From 35878b555b34ba9ef289f7767aa29d02df2cde48 Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Tue, 4 Jan 2011 16:19:23 +0100 Subject: [PATCH] Add hptmv(4), a driver for HighPoint RocketRAID 182x controllers. It was tested with an 1820A card. Thanks to HighPoint and FreeBSD (from which it was ported). --- share/man/man4/Makefile | 1 + share/man/man4/hptiop.4 | 4 +- share/man/man4/hptmv.4 | 102 + sys/conf/files | 5 + sys/config/GENERIC | 1 + sys/config/GENERIC_SMP | 1 + sys/config/LINT | 4 + sys/config/X86_64_GENERIC | 1 + sys/config/X86_64_GENERIC_SMP | 1 + sys/dev/raid/Makefile | 2 +- sys/dev/raid/hptmv/Makefile | 49 + sys/dev/raid/hptmv/access601.h | 62 + sys/dev/raid/hptmv/array.h | 275 ++ sys/dev/raid/hptmv/atapi.h | 388 +++ sys/dev/raid/hptmv/command.h | 267 ++ sys/dev/raid/hptmv/entry.c | 3033 +++++++++++++++++++++++ sys/dev/raid/hptmv/global.h | 202 ++ sys/dev/raid/hptmv/gui_lib.c | 1447 +++++++++++ sys/dev/raid/hptmv/hptintf.h | 1234 +++++++++ sys/dev/raid/hptmv/hptproc.c | 618 +++++ sys/dev/raid/hptmv/i386-elf.raid.o.uu | 1440 +++++++++++ sys/dev/raid/hptmv/ioctl.c | 972 ++++++++ sys/dev/raid/hptmv/mv.c | 115 + sys/dev/raid/hptmv/mvOs.h | 152 ++ sys/dev/raid/hptmv/mvSata.h | 448 ++++ sys/dev/raid/hptmv/mvStorageDev.h | 215 ++ sys/dev/raid/hptmv/osbsd.h | 318 +++ sys/dev/raid/hptmv/raid5n.h | 125 + sys/dev/raid/hptmv/readme.txt | 223 ++ sys/dev/raid/hptmv/vdevice.h | 286 +++ sys/dev/raid/hptmv/x86_64-elf.raid.o.uu | 1934 +++++++++++++++ sys/platform/pc32/conf/files | 5 + sys/platform/pc64/conf/files | 8 +- 33 files changed, 13932 insertions(+), 6 deletions(-) create mode 100644 share/man/man4/hptmv.4 create mode 100644 sys/dev/raid/hptmv/Makefile create mode 100644 sys/dev/raid/hptmv/access601.h create mode 100644 sys/dev/raid/hptmv/array.h create mode 100644 sys/dev/raid/hptmv/atapi.h create mode 100644 sys/dev/raid/hptmv/command.h create mode 100644 sys/dev/raid/hptmv/entry.c create mode 100644 sys/dev/raid/hptmv/global.h create mode 100644 sys/dev/raid/hptmv/gui_lib.c create mode 100644 sys/dev/raid/hptmv/hptintf.h create mode 100644 sys/dev/raid/hptmv/hptproc.c create mode 100644 sys/dev/raid/hptmv/i386-elf.raid.o.uu create mode 100644 sys/dev/raid/hptmv/ioctl.c create mode 100644 sys/dev/raid/hptmv/mv.c create mode 100644 sys/dev/raid/hptmv/mvOs.h create mode 100644 sys/dev/raid/hptmv/mvSata.h create mode 100644 sys/dev/raid/hptmv/mvStorageDev.h create mode 100644 sys/dev/raid/hptmv/osbsd.h create mode 100644 sys/dev/raid/hptmv/raid5n.h create mode 100644 sys/dev/raid/hptmv/readme.txt create mode 100644 sys/dev/raid/hptmv/vdevice.h create mode 100644 sys/dev/raid/hptmv/x86_64-elf.raid.o.uu diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 48f548a0ac..052208d2dc 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -99,6 +99,7 @@ MAN= aac.4 \ gusc.4 \ hifn.4 \ hptiop.4 \ + hptmv.4 \ ichsmb.4 \ icmp.4 \ icmp6.4 \ diff --git a/share/man/man4/hptiop.4 b/share/man/man4/hptiop.4 index 8a76b9572d..d2cba69051 100644 --- a/share/man/man4/hptiop.4 +++ b/share/man/man4/hptiop.4 @@ -89,8 +89,8 @@ The .Nm driver has only been tested on the i386 and amd64 platforms. .Sh SEE ALSO -.Xr cam 4 -.\".Xr hptmv 4 , +.Xr cam 4 , +.Xr hptmv 4 .Sh HISTORY The .Nm diff --git a/share/man/man4/hptmv.4 b/share/man/man4/hptmv.4 new file mode 100644 index 0000000000..acef40dc3d --- /dev/null +++ b/share/man/man4/hptmv.4 @@ -0,0 +1,102 @@ +.\" +.\" Copyright (c) 2004 David E. O'Brien +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD: src/share/man/man4/hptmv.4,v 1.8 2006/09/18 15:24:18 ru Exp $ +.\" +.Dd January 4, 2011 +.Dt HPTMV 4 +.Os +.Sh NAME +.Nm hptmv +.Nd "HighPoint RocketRAID 182x device driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device hptmv" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hptmv_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for HighPoint's RocketRAID 182x based RAID controller. +.Pp +These devices support ATA disk drives +and provide RAID0 (striping), RAID1 (mirroring), and RAID5 functionality. +.Sh HARDWARE +The +.Nm +driver supports the following ATA RAID +controllers: +.Pp +.Bl -bullet -compact +.It +HighPoint's RocketRAID 182x series +.El +.Sh NOTES +The +.Nm +driver only works on the i386 and amd64 platforms as it requires a binary +blob object from the manufacturer which they only supply for these platforms. +.\"The +.\".Nm +.\"driver does +.\".Em not +.\"work on i386 with +.\".Xr pae 4 +.\"enabled. +.Sh SEE ALSO +.Xr hptiop 4 , +.Xr kld 4 , +.Xr kldload 8 , +.Xr loader 8 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 5.3 . +.Sh AUTHORS +.An -nosplit +The +.Nm +device driver was written by +.An HighPoint Technologies, Inc. , +and ported to +.Fx +by +.An Scott Long . +This manual page was written by +.An David E. O'Brien . +.Sh BUGS +The +.Nm +driver does not support manipulating the RAID from the OS, RAIDs need +to be set up from the on-board BIOS. diff --git a/sys/conf/files b/sys/conf/files index 38a4b879fd..3a0ce75f55 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -383,6 +383,11 @@ dev/atm/hfa/fore_timer.c optional hfa dev/atm/hfa/fore_transmit.c optional nowerror hfa dev/atm/hfa/fore_vcm.c optional hfa dev/raid/hptiop/hptiop.c optional hptiop scbus +dev/raid/hptmv/entry.c optional hptmv +dev/raid/hptmv/mv.c optional hptmv +dev/raid/hptmv/gui_lib.c optional hptmv +dev/raid/hptmv/hptproc.c optional hptmv +dev/raid/hptmv/ioctl.c optional hptmv dev/netif/ie/if_ie.c optional nowerror ie isa dev/powermng/ichsmb/ichsmb.c optional ichsmb dev/powermng/ichsmb/ichsmb_pci.c optional ichsmb pci diff --git a/sys/config/GENERIC b/sys/config/GENERIC index dc73e5825c..9d88a80116 100644 --- a/sys/config/GENERIC +++ b/sys/config/GENERIC @@ -158,6 +158,7 @@ device asr # DPT SmartRAID V, VI and Adaptec SCSI RAID device ciss # Compaq SmartRAID 5* series device dpt # DPT Smartcache - See LINT for options! device hptiop # Highpoint RocketRaid 3xxx series +device hptmv # Highpoint RocketRAID 182x device iir # Intel Integrated RAID device mly # Mylex AcceleRAID/eXtremeRAID device twa # 3ware 9000 series PATA/SATA RAID diff --git a/sys/config/GENERIC_SMP b/sys/config/GENERIC_SMP index 57ba282d12..371a30ed39 100644 --- a/sys/config/GENERIC_SMP +++ b/sys/config/GENERIC_SMP @@ -159,6 +159,7 @@ device asr # DPT SmartRAID V, VI and Adaptec SCSI RAID device ciss # Compaq SmartRAID 5* series device dpt # DPT Smartcache - See LINT for options! device hptiop # Highpoint RocketRaid 3xxx series +device hptmv # Highpoint RocketRAID 182x device iir # Intel Integrated RAID device mly # Mylex AcceleRAID/eXtremeRAID device twa # 3ware 9000 series PATA/SATA RAID diff --git a/sys/config/LINT b/sys/config/LINT index bf3654e36c..f7ad2ade6b 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -1269,6 +1269,10 @@ options MFI_DEBUG # device arcmsr # Areca SATA II RAID +# +# Highpoint RocketRAID 182x. +device hptmv + # # Highpoint RocketRaid 3xxx series SATA RAID device hptiop diff --git a/sys/config/X86_64_GENERIC b/sys/config/X86_64_GENERIC index 9c42e01339..e242026dc4 100644 --- a/sys/config/X86_64_GENERIC +++ b/sys/config/X86_64_GENERIC @@ -145,6 +145,7 @@ device asr # DPT SmartRAID V, VI and Adaptec SCSI RAID device ciss # Compaq SmartRAID 5* series device dpt # DPT Smartcache - See LINT for options! device hptiop # Highpoint RocketRaid 3xxx series +device hptmv # Highpoint RocketRAID 182x device iir # Intel Integrated RAID device mly # Mylex AcceleRAID/eXtremeRAID device twa # 3ware 9000 series PATA/SATA RAID diff --git a/sys/config/X86_64_GENERIC_SMP b/sys/config/X86_64_GENERIC_SMP index 04adf518f4..b0cd69a25e 100644 --- a/sys/config/X86_64_GENERIC_SMP +++ b/sys/config/X86_64_GENERIC_SMP @@ -145,6 +145,7 @@ device asr # DPT SmartRAID V, VI and Adaptec SCSI RAID device ciss # Compaq SmartRAID 5* series device dpt # DPT Smartcache - See LINT for options! device hptiop # Highpoint RocketRaid 3xxx series +device hptmv # Highpoint RocketRAID 182x device iir # Intel Integrated RAID device mly # Mylex AcceleRAID/eXtremeRAID device twa # 3ware 9000 series PATA/SATA RAID diff --git a/sys/dev/raid/Makefile b/sys/dev/raid/Makefile index 04e5b180a0..8a343fcd75 100644 --- a/sys/dev/raid/Makefile +++ b/sys/dev/raid/Makefile @@ -1,4 +1,4 @@ -SUBDIR= aac amr arcmsr asr ciss hptiop \ +SUBDIR= aac amr arcmsr asr ciss hptiop hptmv \ iir ips mfi mlx mly pst twa twe vinum .include diff --git a/sys/dev/raid/hptmv/Makefile b/sys/dev/raid/hptmv/Makefile new file mode 100644 index 0000000000..cc8c8ddb1a --- /dev/null +++ b/sys/dev/raid/hptmv/Makefile @@ -0,0 +1,49 @@ +# +# Makefile for RR182x FreeBSD driver +# Copyright (c) 2004-2005 HighPoint Technologies, Inc. All rights reserved +# +# $FreeBSD: src/sys/modules/hptmv/Makefile,v 1.5 2010/08/23 06:13:29 imp Exp $ + +KMOD= hptmv +SRCS= opt_scsi.h opt_cam.h +SRCS+= bus_if.h device_if.h pci_if.h +SRCS+= mv.c entry.c ioctl.c hptproc.c gui_lib.c +OBJS+= hptmvraid.o + +.if $(MACHINE_ARCH) == "x86_64" +HPTMV_RAID_O = x86_64-elf.raid.o.uu +.else +HPTMV_RAID_O = i386-elf.raid.o.uu +.endif + +hptmvraid.o: ${.CURDIR}/$(HPTMV_RAID_O) + uudecode -p < ${.CURDIR}/$(HPTMV_RAID_O) > ${.TARGET} + +# +# Debug Options: +# +# -DDEBUG: include debug code +# -DDEBUG_LEVEL=x: +# 0 - No debug output message +# 1 - print only error messages +# 2 - print error and warning +# 3 - print all messages (info, warning, error) +# +#DEBUGOPT = -O2 + +.if defined(DEBUG) && $(DEBUG) == 1 +DEBUGOPT += -DDEBUG +.if defined(DEBUG_LEVEL) +DEBUGOPT += -DDEBUG_LEVEL=$(DEBUG_LEVEL) +.else +DEBUGOPT += -DDEBUG_LEVEL=1 +.endif +.endif + +.if defined(FOR_DEMO) && $(FOR_DEMO) == 1 +DEBUGOPT += -DFOR_DEMO +.endif + +CFLAGS = ${DEBUGOPT} + +.include diff --git a/sys/dev/raid/hptmv/access601.h b/sys/dev/raid/hptmv/access601.h new file mode 100644 index 0000000000..6c8e458a1b --- /dev/null +++ b/sys/dev/raid/hptmv/access601.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/access601.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef _ACCESS601_H_ +#define _ACCESS601_H_ + +#ifndef FOR_DEMO + +void HPTLIBAPI BeepOn(MV_BUS_ADDR_T BaseAddr); +void HPTLIBAPI BeepOff(MV_BUS_ADDR_T BaseAddr); +UCHAR HPTLIBAPI check_protect_circuit(MV_BUS_ADDR_T BaseAddr); + +#ifdef SUPPORT_FAIL_LED +void HPTLIBAPI set_fail_led(MV_SATA_ADAPTER *pAdapter, UCHAR channel, UCHAR state); +void HPTLIBAPI set_fail_leds(MV_SATA_ADAPTER *pAdapter, UCHAR mask); +#else +#define set_fail_led(pAdapter, channel, state) +#define set_fail_leds(pAdapter, mask) +#endif + +int HPTLIBAPI sx508x_ioctl(MV_SATA_ADAPTER *pSataAdapter, UCHAR *indata, ULONG inlen, + UCHAR *outdata, ULONG maxoutlen, ULONG *poutlen); + +MV_BOOLEAN HPTLIBAPI sx508x_flash_access(MV_SATA_ADAPTER *pSataAdapter, + MV_U32 offset, void *value, int size, int reading); +#else + +#define BeepOn(addr) +#define BeepOff(addr) +#define check_protect_circuit(addr) 1 +#define set_fail_led(pAdapter, channel, state) +#define set_fail_leds(pAdapter, mask) +#define sx508x_ioctl(pSataAdapter, indata, inlen, outdata, maxoutlen, poutlen) 0 +#define sx508x_flash_access(pSataAdapter, offset, value, size, reading) 0 + +#endif + +#endif diff --git a/sys/dev/raid/hptmv/array.h b/sys/dev/raid/hptmv/array.h new file mode 100644 index 0000000000..126e3f88dd --- /dev/null +++ b/sys/dev/raid/hptmv/array.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/array.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ + +#ifndef _ARRAY_H_ +#define _ARRAY_H_ + +/* + * time represented in DWORD format + */ +#pragma pack(1) +#ifdef __BIG_ENDIAN_BITFIELD +typedef DWORD TIME_RECORD; +#else +typedef struct _TIME_RECORD { + UINT seconds:6; /* 0 - 59 */ + UINT minutes:6; /* 0 - 59 */ + UINT month:4; /* 1 - 12 */ + UINT hours:6; /* 0 - 59 */ + UINT day:5; /* 1 - 31 */ + UINT year:5; /* 0=2000, 31=2031 */ +} TIME_RECORD; +#endif +#pragma pack() + +/*************************************************************************** + * Description: Virtual Device Table + ***************************************************************************/ + +typedef struct _RaidArray +{ + /* + * basic information + */ + UCHAR bArnMember; /* the number of members in array */ + UCHAR bArRealnMember; /* real member count */ + UCHAR bArBlockSizeShift; /* the number of shift bit for a block */ + UCHAR reserve1; + + ULONG dArStamp; /* array ID. all disks in a array has same ID */ + ULONG failedStamps[4]; /* stamp for failed members */ + USHORT bStripeWitch; /* = (1 << BlockSizeShift) */ + + USHORT rf_broken: 1; + USHORT rf_need_rebuild: 1; /* one member's data are incorrect. + for R5, if CriticalMembers==0, it means + parity needs to be constructed */ + USHORT rf_need_sync: 1; /* need write array info to disk */ + /* ioctl flags */ + USHORT rf_auto_rebuild: 1; + USHORT rf_newly_created: 1; + USHORT rf_rebuilding: 1; + USHORT rf_verifying: 1; + USHORT rf_initializing: 1; + USHORT rf_abort_rebuild: 1; + USHORT rf_duplicate_and_create: 1; + USHORT rf_duplicate_and_created: 1; + USHORT rf_duplicate_must_done: 1; + USHORT rf_raid15: 1; + + USHORT CriticalMembers; /* tell which member is critial */ + UCHAR last_read; /* for RAID 1 load banlancing */ + UCHAR alreadyBroken; + + LBA_T RebuildSectors; /* how many sectors is OK (LBA on member disk) */ + + PVDevice pMember[MAX_MEMBERS]; + /* + * utility working data + */ + UCHAR ArrayName[MAX_ARRAY_NAME]; /* The Name of the array */ + TIME_RECORD CreateTime; /* when created it */ + UCHAR Description[64]; /* array description */ + UCHAR CreateManager[16]; /* who created it */ +} RaidArray; + +/*************************************************************************** + * Array Descripton on disk + ***************************************************************************/ +#pragma pack(1) +typedef struct _ArrayDescript +{ + ULONG Signature; /* This block is vaild array info block */ + ULONG dArStamp; /* array ID. all disks in a array has same ID */ + + UCHAR bCheckSum; /* check sum of ArrayDescript_3_0_size bytes */ + +#ifdef __BIG_ENDIAN_BITFIELD + UCHAR df_reservedbits: 6; /* put more flags here */ + UCHAR df_user_mode_set: 1;/* user select device mode */ + UCHAR df_bootmark:1; /* user set boot mark on the disk */ +#else + UCHAR df_bootmark:1; /* user set boot mark on the disk */ + UCHAR df_user_mode_set: 1;/* user select device mode */ + UCHAR df_reservedbits: 6; /* put more flags here */ +#endif + + UCHAR bUserDeviceMode; /* see device.h */ + UCHAR ArrayLevel; /* how many level[] is valid */ + + struct { + ULONG Capacity; /* capacity for the array */ + + UCHAR VDeviceType; /* see above & arrayType in array.h */ + UCHAR bMemberCount; /* all disk in the array */ + UCHAR bSerialNumber; /* Serial Number */ + UCHAR bArBlockSizeShift; /* the number of shift bit for a block */ + +#ifdef __BIG_ENDIAN_BITFIELD + USHORT rf_reserved: 14; + USHORT rf_raid15: 1; /* don't remove even you don't use it */ + USHORT rf_need_rebuild:1; /* array is critical */ +#else + USHORT rf_need_rebuild:1; /* array is critical */ + USHORT rf_raid15: 1; /* don't remove even you don't use it */ + USHORT rf_reserved: 14; +#endif + USHORT CriticalMembers; /* record critical members */ + ULONG RebuildSectors; /* how many sectors is OK (LBA on member disk) */ + } level[2]; + + UCHAR ArrayName[MAX_ARRAY_NAME]; /* The Name of the array */ + TIME_RECORD CreateTime; /* when created it */ + UCHAR Description[64]; /* array description */ + UCHAR CreateManager[16]; /* who created it */ + +#define ArrayDescript_3_0_size ((unsigned)(ULONG_PTR)&((struct _ArrayDescript *)0)->bCheckSum31) +#define ArrayDescript_3_1_size 512 + + UCHAR bCheckSum31; /* new check sum */ + UCHAR PrivateFlag1; /* private */ + UCHAR alreadyBroken; /* last stamp has been saved to failedStamps */ + +#ifdef __BIG_ENDIAN_BITFIELD + UCHAR df_read_ahead: 1; /* enable read ahead */ + UCHAR df_read_ahead_set: 1; + UCHAR df_write_cache: 1; /* enable write cache */ + UCHAR df_write_cache_set: 1; + UCHAR df_ncq: 1; /* enable NCQ */ + UCHAR df_ncq_set: 1; + UCHAR df_tcq: 1; /* enable TCQ */ + UCHAR df_tcq_set: 1; +#else + UCHAR df_tcq_set: 1; + UCHAR df_tcq: 1; /* enable TCQ */ + UCHAR df_ncq_set: 1; + UCHAR df_ncq: 1; /* enable NCQ */ + UCHAR df_write_cache_set: 1; + UCHAR df_write_cache: 1; /* enable write cache */ + UCHAR df_read_ahead_set: 1; + UCHAR df_read_ahead: 1; /* enable read ahead */ +#endif + + struct { + ULONG CapacityHi32; + ULONG RebuildSectorsHi32; + } + levelex[2]; + + ULONG failedStamps[4]; /* failed memebrs's stamps */ + +} ArrayDescript; + +/* report an error if ArrayDescript size exceed 512 */ +typedef char ArrayDescript_size_should_not_exceed_512[512-sizeof(ArrayDescript)]; + +#pragma pack() + +/* Signature */ +#define HPT_ARRAY_V3 0x5a7816f3 +#ifdef ARRAY_V2_ONLY +#define SAVE_FOR_RAID_INFO 0 +#else +#define SAVE_FOR_RAID_INFO 10 +#endif + +/*************************************************************************** + * Function protocol for array layer + ***************************************************************************/ + +/* + * array.c + */ +ULONG FASTCALL GetStamp(void); +void HPTLIBAPI SyncArrayInfo(PVDevice pVDev); +void HPTLIBAPI fDeleteArray(_VBUS_ARG PVDevice pVArray, BOOLEAN del_block0); + +/* + * iArray.c + */ +void HPTLIBAPI fCheckArray(PDevice pDevice); +void HPTLIBAPI CheckArrayCritical(_VBUS_ARG0); +PVDevice HPTLIBAPI GetSpareDisk(_VBUS_ARG PVDevice pArray); +#ifdef SUPPORT_OLD_ARRAY +void HPTLIBAPI fFixRAID01Stripe(_VBUS_ARG PVDevice pStripe); +#endif + +/*************************************************************************** + * Macro defination + ***************************************************************************/ +#ifndef MAX_ARRAY_PER_VBUS +#define MAX_ARRAY_PER_VBUS (MAX_VDEVICE_PER_VBUS*2) /* worst case */ +#endif + + +#if defined(MAX_ARRAY_DEVICE) +#if MAX_ARRAY_DEVICE!=MAX_ARRAY_PER_VBUS +#error "remove MAX_ARRAY_DEVICE and use MAX_ARRAY_PER_VBUS instead" +#endif +#endif + +#define _SET_ARRAY_BUS_(pArray) pArray->pVBus = _vbus_p; + +#ifdef ARRAY_V2_ONLY +#define _SET_ARRAY_VER_(pArray) pArray->vf_format_v2 = 1; +#else +#define _SET_ARRAY_VER_(pArray) +#endif + +#define mArGetArrayTable(pVArray) \ + if((pVArray = _vbus_(pFreeArrayLink)) != 0) { \ + _vbus_(pFreeArrayLink) = (PVDevice)_vbus_(pFreeArrayLink)->pVBus; \ + ZeroMemory(pVArray, ARRAY_VDEV_SIZE); \ + _SET_ARRAY_BUS_(pVArray) \ + _SET_ARRAY_VER_(pVArray) \ + } else + +#define mArFreeArrayTable(pVArray) \ + do { \ + pVArray->pVBus = (PVBus)_vbus_(pFreeArrayLink);\ + _vbus_(pFreeArrayLink) = pVArray; \ + pVArray->u.array.dArStamp = 0; \ + } while(0) + +UCHAR CheckSum(UCHAR *p, int size); + +void HPTLIBAPI fRAID0SendCommand(_VBUS_ARG PCommand pCmd); +void HPTLIBAPI fRAID1SendCommand(_VBUS_ARG PCommand pCmd); +void HPTLIBAPI fJBODSendCommand(_VBUS_ARG PCommand pCmd); +void HPTLIBAPI fRAID0MemberFailed(_VBUS_ARG PVDevice pVDev); +void HPTLIBAPI fRAID1MemberFailed(_VBUS_ARG PVDevice pVDev); +void HPTLIBAPI fJBODMemberFailed(_VBUS_ARG PVDevice pVDev); +#if SUPPORT_RAID5 +void HPTLIBAPI fRAID5SendCommand(_VBUS_ARG PCommand pCmd); +void HPTLIBAPI fRAID5MemberFailed(_VBUS_ARG PVDevice pVDev); +#else +#define fRAID5SendCommand 0 +#define fRAID5MemberFailed 0 +#endif + +#endif diff --git a/sys/dev/raid/hptmv/atapi.h b/sys/dev/raid/hptmv/atapi.h new file mode 100644 index 0000000000..5bda30012d --- /dev/null +++ b/sys/dev/raid/hptmv/atapi.h @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/atapi.h,v 1.4 2009/06/24 20:43:51 mav Exp $ + */ + +#ifndef _ATAPI_H_ +#define _ATAPI_H_ + +#pragma pack(1) + +/*************************************************************************** + * IDE IO Register File + ***************************************************************************/ + +/* + * IDE IO Port definition + */ +typedef struct _IDE_REGISTERS_1 { + USHORT Data; /* RW: Data port feature register */ + UCHAR BlockCount; /* RW: Sector count */ + UCHAR BlockNumber; /* RW: Sector number & LBA 0-7 */ + UCHAR CylinderLow; /* RW: Cylinder low & LBA 8-15 */ + UCHAR CylinderHigh; /* RW: Cylinder hign & LBA 16-23 */ + UCHAR DriveSelect; /* RW: Drive/head & LBA 24-27 */ + UCHAR Command; /* RO: Status WR:Command */ +} IDE_REGISTERS_1, *PIDE_REGISTERS_1; + + +/* + * IDE status definitions + */ +#define IDE_STATUS_ERROR 0x01 /* Error Occurred in Execution */ +#define IDE_STATUS_INDEX 0x02 /* is vendor specific */ +#define IDE_STATUS_CORRECTED_ERROR 0x04 /* Corrected Data */ +#define IDE_STATUS_DRQ 0x08 /* Ready to transfer data */ +#define IDE_STATUS_DSC 0x10 /* not defined in ATA-2 */ +#define IDE_STATUS_DWF 0x20 /* Device Fault has been detected */ +#define IDE_STATUS_DRDY 0x40 /* Device Ready to accept command */ +#define IDE_STATUS_IDLE 0x50 /* Device is OK */ +#define IDE_STATUS_BUSY 0x80 /* Device Busy, must wait */ + + +#define IDE_ERROR_BAD_BLOCK 0x80 /* Reserved now */ +#define IDE_ERROR_DATA_ERROR 0x40 /* Uncorreectable Data Error */ +#define IDE_ERROR_MEDIA_CHANGE 0x20 /* Media Changed */ +#define IDE_ERROR_ID_NOT_FOUND 0x10 /* ID Not Found */ +#define IDE_ERROR_MEDIA_CHANGE_REQ 0x08 /* Media Change Requested */ +#define IDE_ERROR_COMMAND_ABORTED 0x04 /* Aborted Command */ +#define IDE_ERROR_TRACK0_NOT_FOUND 0x02 /* Track 0 Not Found */ +#define IDE_ERROR_ADDRESS_NOT_FOUND 0x01 /* Address Mark Not Found */ + + +#define LBA_MODE 0x40 + +/* + * IDE command definitions + */ + +#define IDE_COMMAND_RECALIBRATE 0x10 /* Recalibrate */ +#define IDE_COMMAND_READ 0x20 /* Read Sectors with retry */ +#define IDE_COMMAND_WRITE 0x30 /* Write Sectors with retry */ +#define IDE_COMMAND_VERIFY 0x40 /* Read Verify Sectors with Retry */ +#define IDE_COMMAND_SEEK 0x70 /* Seek */ +#define IDE_COMMAND_SET_DRIVE_PARAMETER 0x91 /* Initialize Device Parmeters */ +#define IDE_COMMAND_GET_MEDIA_STATUS 0xDA +#define IDE_COMMAND_DOOR_LOCK 0xDE /* Door Lock */ +#define IDE_COMMAND_DOOR_UNLOCK 0xDF /* Door Unlock */ +#define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF /* Set Features */ +#define IDE_COMMAND_IDENTIFY 0xEC /* Identify Device */ +#define IDE_COMMAND_MEDIA_EJECT 0xED +#define IDE_COMMAND_SET_FEATURES 0xEF /* IDE set features command */ + +#define IDE_COMMAND_FLUSH_CACHE 0xE7 +#define IDE_COMMAND_STANDBY_IMMEDIATE 0xE0 + +#ifndef NOT_SUPPORT_MULTIPLE +#define IDE_COMMAND_READ_MULTIPLE 0xC4 /* Read Multiple */ +#define IDE_COMMAND_WRITE_MULTIPLE 0xC5 /* Write Multiple */ +#define IDE_COMMAND_SET_MULTIPLE 0xC6 /* Set Multiple Mode */ +#endif + +#ifndef NOT_SUPPORT_DMA +#define IDE_COMMAND_DMA_READ 0xc8 /* IDE DMA read command */ +#define IDE_COMMAND_DMA_WRITE 0xca /* IDE DMA write command */ +#endif + +#define IDE_COMMAND_READ_DMA_QUEUE 0xc7 /* IDE read DMA queue command */ +#define IDE_COMMAND_WRITE_DMA_QUEUE 0xcc /* IDE write DMA queue command */ +#define IDE_COMMAND_SERVICE 0xA2 /* IDE service command command */ +#define IDE_COMMAND_NOP 0x00 /* IDE NOP command */ +#define IDE_STATUS_SRV 0x10 +#define IDE_RELEASE_BUS 4 + +/*#define IDE_COMMAND_FLUSH_CACHE_EXT */ +#define IDE_COMMAND_READ_DMA_EXT 0x25 +#define IDE_COMMAND_READ_QUEUE_EXT 0x26 +#define IDE_COMMAND_READ_MULTIPLE_EXT 0x29 +#define IDE_COMMAND_READ_MAX_ADDR 0x27 +#define IDE_COMMAND_READ_EXT 0x24 +#define IDE_COMMAND_VERIFY_EXT 0x42 +#define IDE_COMMAND_SET_MULTIPLE_EXT 0x37 +#define IDE_COMMAND_WRITE_DMA_EXT 0x35 +#define IDE_COMMAND_WRITE_QUEUE_EXT 0x36 +#define IDE_COMMAND_WRITE_EXT 0x34 +#define IDE_COMMAND_WRITE_MULTIPLE_EXT 0x39 + +/* + * IDE_COMMAND_SET_FEATURES + */ +#define FT_USE_ULTRA 0x40 /* Set feature for Ultra DMA */ +#define FT_USE_MWDMA 0x20 /* Set feature for MW DMA */ +#define FT_USE_SWDMA 0x10 /* Set feature for SW DMA */ +#define FT_USE_PIO 0x8 /* Set feature for PIO */ +#define FT_DISABLE_IORDY 0x10 /* Set feature for disabling IORDY */ + +/* + * S.M.A.R.T. commands + */ +#define IDE_COMMAND_SMART 0xB0 +#define SMART_READ_VALUES 0xd0 +#define SMART_READ_THRESHOLDS 0xd1 +#define SMART_AUTOSAVE 0xd2 +#define SMART_SAVE 0xd3 +#define SMART_IMMEDIATE_OFFLINE 0xd4 +#define SMART_READ_LOG_SECTOR 0xd5 +#define SMART_WRITE_LOG_SECTOR 0xd6 +#define SMART_ENABLE 0xd8 +#define SMART_DISABLE 0xd9 +#define SMART_STATUS 0xda +#define SMART_AUTO_OFFLINE 0xdb + + /*************************************************************************** + * IDE Control Register File + ***************************************************************************/ + +typedef struct _IDE_REGISTERS_2 { + UCHAR AlternateStatus; /* RW: device control port */ +} IDE_REGISTERS_2, *PIDE_REGISTERS_2; + + +/* + * IDE drive control definitions + */ +#define IDE_DC_DISABLE_INTERRUPTS 0x02 +#define IDE_DC_RESET_CONTROLLER 0x04 +#define IDE_DC_REENABLE_CONTROLLER 0x00 + +/*************************************************************************** + * MSNS: Removable device + ***************************************************************************/ +/* + * Media syatus + */ +#define MSNS_NO_MEDIA 2 +#define MSNS_MEDIA_CHANGE_REQUEST 8 +#define MSNS_MIDIA_CHANGE 0x20 +#define MSNS_WRITE_PROTECT 0x40 +#define MSNS_READ_PROTECT 0x80 + +/* + * IDENTIFY data + */ +typedef struct _IDENTIFY_DATA { + USHORT GeneralConfiguration; /* 00 00 */ + USHORT NumberOfCylinders; /* 02 1 */ + USHORT Reserved1; /* 04 2 */ + USHORT NumberOfHeads; /* 06 3 */ + USHORT UnformattedBytesPerTrack; /* 08 4 */ + USHORT UnformattedBytesPerSector; /* 0A 5 */ + USHORT SectorsPerTrack; /* 0C 6 */ + USHORT VendorUnique1[3]; /* 0E 7-9 */ + USHORT SerialNumber[10]; /* 14 10-19 */ + USHORT BufferType; /* 28 20 */ + USHORT BufferSectorSize; /* 2A 21 */ + USHORT NumberOfEccBytes; /* 2C 22 */ + USHORT FirmwareRevision[4]; /* 2E 23-26 */ + USHORT ModelNumber[20]; /* 36 27-46 */ + UCHAR MaximumBlockTransfer; /* 5E 47 */ + UCHAR VendorUnique2; /* 5F */ + USHORT DoubleWordIo; /* 60 48 */ + USHORT Capabilities; /* 62 49 */ + USHORT Reserved2; /* 64 50 */ + UCHAR VendorUnique3; /* 66 51 */ + UCHAR PioCycleTimingMode; /* 67 */ + UCHAR VendorUnique4; /* 68 52 */ + UCHAR DmaCycleTimingMode; /* 69 */ + USHORT TranslationFieldsValid; /* 6A 53 */ + USHORT NumberOfCurrentCylinders; /* 6C 54 */ + USHORT NumberOfCurrentHeads; /* 6E 55 */ + USHORT CurrentSectorsPerTrack; /* 70 56 */ + ULONG CurrentSectorCapacity; /* 72 57-58 */ + USHORT CurrentMultiSectorSetting; /* 76 59 */ + ULONG UserAddressableSectors; /* 78 60-61 */ + UCHAR SingleWordDMASupport; /* 7C 62 */ + UCHAR SingleWordDMAActive; /* 7D */ + UCHAR MultiWordDMASupport; /* 7E 63 */ + UCHAR MultiWordDMAActive; /* 7F */ + UCHAR AdvancedPIOModes; /* 80 64 */ + UCHAR Reserved4; /* 81 */ + USHORT MinimumMWXferCycleTime; /* 82 65 */ + USHORT RecommendedMWXferCycleTime; /* 84 66 */ + USHORT MinimumPIOCycleTime; /* 86 67 */ + USHORT MinimumPIOCycleTimeIORDY; /* 88 68 */ + USHORT Reserved5[2]; /* 8A 69-70 */ + USHORT ReleaseTimeOverlapped; /* 8E 71 */ + USHORT ReleaseTimeServiceCommand; /* 90 72 */ + USHORT MajorRevision; /* 92 73 */ + USHORT MinorRevision; /* 94 74 */ + USHORT MaxQueueDepth; /* 96 75 */ + USHORT SataCapability; /* 76 */ + USHORT Reserved6[9]; /* 98 77-85 */ + USHORT CommandSupport; /* 86 */ + USHORT CommandEnable; /* 87 */ + USHORT UtralDmaMode; /* 88 */ + USHORT Reserved7[11]; /* 89-99 */ + ULONG Lba48BitLow; /* 101-100 */ + ULONG Lba48BitHigh; /* 103-102 */ + USHORT Reserved8[23]; /* 104-126 */ + USHORT SpecialFunctionsEnabled; /* 127 */ + USHORT Reserved9[128]; /* 128-255 */ + +} IDENTIFY_DATA, *PIDENTIFY_DATA; + +typedef struct _CONFIGURATION_IDENTIFY_DATA { + USHORT Revision; + USHORT MWDMAModeSupported; + USHORT UDMAModeSupported; + ULONG MaximumLbaLow; + ULONG MaximumLbaHigh; + USHORT CommandSupport; + USHORT Reserved[247]; + UCHAR Signature; /* 0xA5 */ + UCHAR CheckSum; +} +CONFIGURATION_IDENTIFY_DATA, *PCONFIGURATION_IDENTIFY_DATA; + +/* */ +/* Identify data without the Reserved4. */ +/* */ +typedef struct _IDENTIFY_DATA2 { + USHORT GeneralConfiguration; /* 00 00 */ + USHORT NumberOfCylinders; /* 02 1 */ + USHORT Reserved1; /* 04 2 */ + USHORT NumberOfHeads; /* 06 3 */ + USHORT UnformattedBytesPerTrack; /* 08 4 */ + USHORT UnformattedBytesPerSector; /* 0A 5 */ + USHORT SectorsPerTrack; /* 0C 6 */ + USHORT VendorUnique1[3]; /* 0E 7-9 */ + USHORT SerialNumber[10]; /* 14 10-19 */ + USHORT BufferType; /* 28 20 */ + USHORT BufferSectorSize; /* 2A 21 */ + USHORT NumberOfEccBytes; /* 2C 22 */ + USHORT FirmwareRevision[4]; /* 2E 23-26 */ + USHORT ModelNumber[20]; /* 36 27-46 */ + UCHAR MaximumBlockTransfer; /* 5E 47 */ + UCHAR VendorUnique2; /* 5F */ + USHORT DoubleWordIo; /* 60 48 */ + USHORT Capabilities; /* 62 49 */ + USHORT Reserved2; /* 64 50 */ + UCHAR VendorUnique3; /* 66 51 */ + UCHAR PioCycleTimingMode; /* 67 */ + UCHAR VendorUnique4; /* 68 52 */ + UCHAR DmaCycleTimingMode; /* 69 */ + USHORT TranslationFieldsValid; /* 6A 53 */ + USHORT NumberOfCurrentCylinders; /* 6C 54 */ + USHORT NumberOfCurrentHeads; /* 6E 55 */ + USHORT CurrentSectorsPerTrack; /* 70 56 */ + ULONG CurrentSectorCapacity; /* 72 57-58 */ + USHORT CurrentMultiSectorSetting; /* 59 */ + ULONG UserAddressableSectors; /* 60-61 */ + UCHAR SingleWordDMASupport; /* 62 */ + UCHAR SingleWordDMAActive; + UCHAR MultiWordDMASupport; /* 63 */ + UCHAR MultiWordDMAActive; + UCHAR AdvancedPIOModes; /* 64 */ + UCHAR Reserved4; + USHORT MinimumMWXferCycleTime; /* 65 */ + USHORT RecommendedMWXferCycleTime; /* 66 */ + USHORT MinimumPIOCycleTime; /* 67 */ + USHORT MinimumPIOCycleTimeIORDY; /* 68 */ + USHORT Reserved5[2]; /* 69-70 */ + USHORT ReleaseTimeOverlapped; /* 71 */ + USHORT ReleaseTimeServiceCommand; /* 72 */ + USHORT MajorRevision; /* 73 */ + USHORT MinorRevision; /* 74 */ +/* USHORT Reserved6[14]; // 75-88 */ +} IDENTIFY_DATA2, *PIDENTIFY_DATA2; + +#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA2) + +/* */ +/* IDENTIFY DMA timing cycle modes. */ +/* */ + +#define IDENTIFY_DMA_CYCLES_MODE_0 0x00 +#define IDENTIFY_DMA_CYCLES_MODE_1 0x01 +#define IDENTIFY_DMA_CYCLES_MODE_2 0x02 + +/* + * Mode definitions + */ +typedef enum _DISK_MODE +{ + IDE_PIO_0 = 0, + IDE_PIO_1, + IDE_PIO_2, + IDE_PIO_3, + IDE_PIO_4, + IDE_MWDMA_0, + IDE_MWDMA_1, + IDE_MWDMA_2, + IDE_UDMA_0, + IDE_UDMA_1, + IDE_UDMA_2, + IDE_UDMA_3, + IDE_UDMA_4, + IDE_UDMA_5, + IDE_UDMA_6, + IDE_UDMA_7, +} DISK_MODE; + +/*************************************************************************** + * IDE Macro + ***************************************************************************/ +#ifndef MAX_LBA_T +#define MAX_LBA_T ((LBA_T)-1) +#endif + +#define SECTOR_TO_BYTE_SHIFT 9 +#define SECTOR_TO_BYTE(x) ((ULONG)(x) << SECTOR_TO_BYTE_SHIFT) + +#define mGetStatus(IOPort2) (UCHAR)InPort(&IOPort2->AlternateStatus) +#define mUnitControl(IOPort2, Value) OutPort(&IOPort2->AlternateStatus,(UCHAR)(Value)) + +#define mGetErrorCode(IOPort) (UCHAR)InPort((PUCHAR)&IOPort->Data+1) +#define mSetFeaturePort(IOPort,x) OutPort((PUCHAR)&IOPort->Data+1, x) +#define mSetBlockCount(IOPort,x) OutPort(&IOPort->BlockCount, x) +#define mGetBlockCount(IOPort) (UCHAR)InPort(&IOPort->BlockCount) +#define mGetInterruptReason(IOPort) (UCHAR)InPort(&IOPort->BlockCount) +#define mSetBlockNumber(IOPort,x) OutPort(&IOPort->BlockNumber, x) +#define mGetBlockNumber(IOPort) (UCHAR)InPort((PUCHAR)&IOPort->BlockNumber) +#define mGetByteLow(IOPort) (UCHAR)InPort(&IOPort->CylinderLow) +#define mSetCylinderLow(IOPort,x) OutPort(&IOPort->CylinderLow, x) +#define mGetByteHigh(IOPort) (UCHAR)InPort(&IOPort->CylinderHigh) +#define mSetCylinderHigh(IOPort,x) OutPort(&IOPort->CylinderHigh, x) +#define mGetBaseStatus(IOPort) (UCHAR)InPort(&IOPort->Command) +#ifdef SUPPORT_HPT601 +#define mSelectUnit(IOPort,UnitId) do {\ + OutPort(&IOPort->DriveSelect, (UCHAR)(UnitId));\ + OutPort(&IOPort->DriveSelect, (UCHAR)(UnitId));\ + } while (0) +#else +#define mSelectUnit(IOPort,UnitId) OutPort(&IOPort->DriveSelect, (UCHAR)(UnitId)) +#endif +#define mGetUnitNumber(IOPort) InPort(&IOPort->DriveSelect) +#define mIssueCommand(IOPort,Cmd) OutPort(&IOPort->Command, (UCHAR)(Cmd)) + +/* + * WDC old disk, don't care right now + */ +#define WDC_MW1_FIX_FLAG_OFFSET 129 +#define WDC_MW1_FIX_FLAG_VALUE 0x00005555 + +#pragma pack() +#endif diff --git a/sys/dev/raid/hptmv/command.h b/sys/dev/raid/hptmv/command.h new file mode 100644 index 0000000000..e2d30813a1 --- /dev/null +++ b/sys/dev/raid/hptmv/command.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/command.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef _COMMAND_H_ +#define _COMMAND_H_ + +/*************************************************************************** + * Description: Command + ***************************************************************************/ +typedef struct _AtaCommand +{ + LBA_T Lba; /* Current Logic Disk command: LBA */ + USHORT nSectors; /* sector count. May great than 0x80 */ + UCHAR Command; /* IDE_COMMAND_READ, _WRITE, _VERIFY */ + UCHAR QueueTag; +} AtaComm, *PAtaComm; + +typedef struct _PassthroughCmd { + BYTE bFeaturesReg; /* feature register */ + BYTE bSectorCountReg; /* IDE sector count register. */ + BYTE bLbaLowReg; /* IDE sector number register. */ + BYTE bLbaMidReg; /* IDE low order cylinder value. */ + BYTE bLbaHighReg; /* IDE high order cylinder value. */ + BYTE bDriveHeadReg; /* IDE drive/head register. */ + BYTE bCommandReg; /* Actual IDE command. Checked for validity by driver. */ + BYTE nSectors; /* data transfer */ + ADDRESS pDataBuffer; /* data buffer */ +} +PassthroughCmd; + +/* control commands */ +#define CTRL_CMD_REBUILD 1 +#define CTRL_CMD_VERIFY 2 +#define CTRL_CMD_INIT 3 + +/* + * RAID5 rebuild/verify + * Rebuild/verify one stripe line. + * The caller needn't supply a buffer for rebuild. + * RebuildSectors member will be updated if its previous location is the + * begin of this stripe line. + */ +typedef struct _R5ControlCmd { + LBA_T StripeLine; /* _physical_ stripe line on array */ + USHORT Offset; /* internal use, don't set */ + UCHAR Command; /* CTRL_CMD_XXX */ + UCHAR reserve1; +} +R5ControlCmd, *PR5ControlCmd; + +/* + * RAID1 rebuild/verify + * Rebuild/verify specified sectors. + * The caller must supply a valid buffer and a physical SG table (or a + * pfnBuildSgl routine). + * For rebuild/initialize, the buffer size should be nSectors<<9; + * For verify, the buffer size should be (nSectors*2)<<9. + * RebuildSectors member will be updated if its previous value equals Lba. + */ +typedef struct _R1ControlCmd { + LBA_T Lba; + USHORT nSectors; + UCHAR Command; /* CTRL_CMD_XXX */ + UCHAR reserve1; + ADDRESS Buffer; /* buffer logical address */ +#ifdef _MACOSX_ + ADDRESS PhysicalAddress; +#endif +} +R1ControlCmd, *PR1ControlCmd; + +typedef struct _Command +{ + PVDevice pVDevice; + union{ + /* Ide Command */ + AtaComm Ide; + PassthroughCmd Passthrough; + /* Atapi Command */ + UCHAR Atapi[12]; + /* Control command */ + R5ControlCmd R5Control; + R1ControlCmd R1Control; + } uCmd; + + USHORT cf_physical_sg: 1; + USHORT cf_data_in: 1; + USHORT cf_data_out: 1; + USHORT cf_atapi: 1; + USHORT cf_ide_passthrough: 1; + USHORT cf_control: 1; + + /* return status */ + UCHAR Result; + /* retry count */ + UCHAR RetryCount; + + /* S/G table address, if already prepared */ + FPSCAT_GATH pSgTable; + + /* called if pSgTable is invalid. */ + int (* HPTLIBAPI pfnBuildSgl)(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical); + + /* called when this command is finished */ + void (* HPTLIBAPI pfnCompletion)(_VBUS_ARG PCommand pCmd); + + /* pointer to origional command */ + void *pOrgCommand; + + + /* scratch data area */ + union { + struct { + LBA_T StartLBA; + UCHAR FirstMember; /* the sequence number of the first member */ + UCHAR LastMember; /* the sequence number of the last member */ + USHORT LastSectors; /* the number of sectors for the last member */ + USHORT FirstSectors; /* the number of sectors for the first member */ + USHORT FirstOffset; /* the offset from the StartLBA for the first member */ + USHORT AllMemberBlocks;/* the number of sectors for all member */ + USHORT WaitInterrupt; /* bit map the members who wait interrupt */ + UCHAR InSameLine; /* if the start and end on the same line */ + UCHAR pad1; + } array; + struct { + LBA_T StartLBA; + USHORT FirstSectors; /* the number of sectors for the first member */ + USHORT FirstOffset; /* the offset from the StartLBA for the first member */ + USHORT WaitInterrupt; /* bit map the members who wait interrupt */ + USHORT r5_gap; /* see raid5.c */ + UCHAR ParDiskNo; /* parity for startLba */ + UCHAR BadDiskNo; + UCHAR FirstMember; + UCHAR pad1; + } r5; + struct { + PCommand pCmd1; + PCommand pCmd2; + } r5split; +#ifdef _RAID5N_ + struct { + ULONG dummy[2]; /* uScratch.wait shall be moved out uScratch. + now just fix it thisway */ + struct range_lock *range_lock; + struct stripe *stripes[5]; + UCHAR nstripes; + UCHAR finished_stripes; + USHORT pad2; + /* for direct-read: */ + struct { + UCHAR cmds; + UCHAR finished; + UCHAR first; + UCHAR parity; + LBA_T base; + USHORT firstoffset; + USHORT firstsectors; + } dr; + } r5n2; +#endif + struct { + ULONG WordsLeft; + FPSCAT_GATH pPIOSg; + void (* HPTLIBAPI pfnOrgDone)(_VBUS_ARG PCommand pCmd); +#ifdef SUPPORT_HPT584 + UCHAR cmd; +#endif + } disk; + struct { + PCommand pNext; + void (* HPTLIBAPI WaitEntry)(_VBUS_ARG PCommand pCmd); + } wait; + + struct { + PVOID prdAddr; + ULONG cmd_priv; + USHORT responseFlags; + UCHAR bIdeStatus; + UCHAR errorRegister; + } sata_param; + } uScratch; +} Command; + +/*************************************************************************** + * command return value + ***************************************************************************/ +#define RETURN_PENDING 0 +#define RETURN_SUCCESS 1 +#define RETURN_BAD_DEVICE 2 +#define RETURN_BAD_PARAMETER 3 +#define RETURN_WRITE_NO_DRQ 4 +#define RETURN_DEVICE_BUSY 5 +#define RETURN_INVALID_REQUEST 6 +#define RETURN_SELECTION_TIMEOUT 7 +#define RETURN_IDE_ERROR 8 +#define RETURN_NEED_LOGICAL_SG 9 +#define RETURN_NEED_PHYSICAL_SG 10 +#define RETURN_RETRY 11 +#define RETURN_DATA_ERROR 12 +#define RETURN_BUS_RESET 13 +#define RETURN_BAD_TRANSFER_LENGTH 14 + +typedef void (* HPTLIBAPI DPC_PROC)(_VBUS_ARG void *); +typedef struct _dpc_routine { + DPC_PROC proc; + void *arg; +} +DPC_ROUTINE; + +/* + * MAX_QUEUE_COMM is defined in platform related compiler.h + * to specify the maximum requests allowed (for each VBus) from system. + * + * Maximum command blocks needed for each VBus: + * Each OS command requests 1+MAX_MEMBERS*2 command blocks (RAID1/0 case) + * This space is allocated by platform dependent part, either static or + * dynamic, continuous or non-continous. + * The code only needs _vbus_(pFreeCommands) to be set. + * + * PendingRoutines[] size: + * Each command may invoke CallAfterReturn once. + * + * IdleRoutines[] size: + * Each command may invoke CallWhenIdle once. + */ +#define MAX_COMMAND_BLOCKS_FOR_EACH_VBUS (MAX_QUEUE_COMM * (1+MAX_MEMBERS*2) + 1) +#define MAX_PENDING_ROUTINES (MAX_COMMAND_BLOCKS_FOR_EACH_VBUS+1) +#define MAX_IDLE_ROUTINES (MAX_COMMAND_BLOCKS_FOR_EACH_VBUS+1) + +#define mWaitingForIdle(pVBus) ((pVBus)->IdleRoutinesFirst!=(pVBus)->IdleRoutinesLast) + +PCommand HPTLIBAPI AllocateCommand(_VBUS_ARG0); +void FASTCALL FreeCommand(_VBUS_ARG PCommand pCmd); + +void FASTCALL CallAfterReturn(_VBUS_ARG DPC_PROC proc, void *arg); +void HPTLIBAPI CheckPendingCall(_VBUS_ARG0); +void FASTCALL CallWhenIdle(_VBUS_ARG DPC_PROC proc, void *arg); +void HPTLIBAPI CheckIdleCall(_VBUS_ARG0); + +void HPTLIBAPI AddToWaitingList(PCommand *ppList, PCommand pCmd); +void HPTLIBAPI DoWaitingList(_VBUS_ARG PCommand *ppList); + +#endif diff --git a/sys/dev/raid/hptmv/entry.c b/sys/dev/raid/hptmv/entry.c new file mode 100644 index 0000000000..15aed04ce7 --- /dev/null +++ b/sys/dev/raid/hptmv/entry.c @@ -0,0 +1,3033 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/entry.c,v 1.23 2010/06/19 13:42:14 mav Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include + + +#ifdef DEBUG +#ifdef DEBUG_LEVEL +int hpt_dbg_level = DEBUG_LEVEL; +#else +int hpt_dbg_level = 0; +#endif +#endif + +#define MV_ERROR kprintf + +/* + * CAM SIM entry points + */ +static int hpt_probe (device_t dev); +static void launch_worker_thread(void); +static int hpt_attach(device_t dev); +static int hpt_detach(device_t dev); +static int hpt_shutdown(device_t dev); +static void hpt_poll(struct cam_sim *sim); +static void hpt_intr(void *arg); +static void hpt_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); +static void hpt_action(struct cam_sim *sim, union ccb *ccb); + +static device_method_t driver_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, hpt_probe), + DEVMETHOD(device_attach, hpt_attach), + DEVMETHOD(device_detach, hpt_detach), + + DEVMETHOD(device_shutdown, hpt_shutdown), + { 0, 0 } +}; + +static driver_t hpt_pci_driver = { + __str(PROC_DIR_NAME), + driver_methods, + sizeof(IAL_ADAPTER_T) +}; + +static devclass_t hpt_devclass; + +#define __DRIVER_MODULE(p1, p2, p3, p4, p5, p6) DRIVER_MODULE(p1, p2, p3, p4, p5, p6) +__DRIVER_MODULE(PROC_DIR_NAME, pci, hpt_pci_driver, hpt_devclass, 0, 0); + +#define ccb_ccb_ptr spriv_ptr0 +#define ccb_adapter ccb_h.spriv_ptr1 + +static void SetInquiryData(PINQUIRYDATA inquiryData, PVDevice pVDev); +static void HPTLIBAPI OsSendCommand (_VBUS_ARG union ccb * ccb); +static void HPTLIBAPI fOsCommandDone(_VBUS_ARG PCommand pCmd); +static void ccb_done(union ccb *ccb); +static void hpt_queue_ccb(union ccb **ccb_Q, union ccb *ccb); +static void hpt_free_ccb(union ccb **ccb_Q, union ccb *ccb); +static void hptmv_free_edma_queues(IAL_ADAPTER_T *pAdapter); +static void hptmv_free_channel(IAL_ADAPTER_T *pAdapter, MV_U8 channelNum); +static void handleEdmaError(_VBUS_ARG PCommand pCmd); +static int hptmv_init_channel(IAL_ADAPTER_T *pAdapter, MV_U8 channelNum); +static int fResetActiveCommands(PVBus _vbus_p); +static void fRegisterVdevice(IAL_ADAPTER_T *pAdapter); +static int hptmv_allocate_edma_queues(IAL_ADAPTER_T *pAdapter); +static void hptmv_handle_event_disconnect(void *data); +static void hptmv_handle_event_connect(void *data); +static int start_channel(IAL_ADAPTER_T *pAdapter, MV_U8 channelNum); +static void init_vdev_params(IAL_ADAPTER_T *pAdapter, MV_U8 channel); +static int hptmv_parse_identify_results(MV_SATA_CHANNEL *pMvSataChannel); +static int HPTLIBAPI fOsBuildSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSg, + int logical); +static MV_BOOLEAN CommandCompletionCB(MV_SATA_ADAPTER *pMvSataAdapter, + MV_U8 channelNum, MV_COMPLETION_TYPE comp_type, MV_VOID_PTR commandId, + MV_U16 responseFlags, MV_U32 timeStamp, + MV_STORAGE_DEVICE_REGISTERS *registerStruct); +static MV_BOOLEAN hptmv_event_notify(MV_SATA_ADAPTER *pMvSataAdapter, + MV_EVENT_TYPE eventType, MV_U32 param1, MV_U32 param2); + +#define ccb_ccb_ptr spriv_ptr0 +#define ccb_adapter ccb_h.spriv_ptr1 + +IAL_ADAPTER_T *gIal_Adapter = 0; +IAL_ADAPTER_T *pCurAdapter = 0; +static MV_SATA_CHANNEL gMvSataChannels[MAX_VBUS][MV_SATA_CHANNELS_NUM]; + +typedef struct st_HPT_DPC { + IAL_ADAPTER_T *pAdapter; + void (*dpc)(IAL_ADAPTER_T *, void *, UCHAR); + void *arg; + UCHAR flags; +} ST_HPT_DPC; + +#define MAX_DPC 16 +UCHAR DPC_Request_Nums = 0; +static ST_HPT_DPC DpcQueue[MAX_DPC]; +static int DpcQueue_First=0; +static int DpcQueue_Last = 0; + +char DRIVER_VERSION[] = "v1.16"; + +static struct lock driver_lock; +intrmask_t lock_driver() +{ + + intrmask_t spl = 0; + lockmgr(&driver_lock, LK_EXCLUSIVE); + return spl; +} +void unlock_driver(intrmask_t spl) +{ + lockmgr(&driver_lock, LK_RELEASE); +} + +/******************************************************************************* + * Name: hptmv_free_channel + * + * Description: free allocated queues for the given channel + * + * Parameters: pMvSataAdapter - pointer to the RR18xx controler this + * channel connected to. + * channelNum - channel number. + * + ******************************************************************************/ +static void +hptmv_free_channel(IAL_ADAPTER_T *pAdapter, MV_U8 channelNum) +{ + HPT_ASSERT(channelNum < MV_SATA_CHANNELS_NUM); + pAdapter->mvSataAdapter.sataChannel[channelNum] = NULL; +} + +static void failDevice(PVDevice pVDev) +{ + PVBus _vbus_p = pVDev->pVBus; + IAL_ADAPTER_T *pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt; + + pVDev->u.disk.df_on_line = 0; + pVDev->vf_online = 0; + if (pVDev->pfnDeviceFailed) + CallWhenIdle(_VBUS_P (DPC_PROC)pVDev->pfnDeviceFailed, pVDev); + + fNotifyGUI(ET_DEVICE_REMOVED, pVDev); + +#ifndef FOR_DEMO + if (pAdapter->ver_601==2 && !pAdapter->beeping) { + pAdapter->beeping = 1; + BeepOn(pAdapter->mvSataAdapter.adapterIoBaseAddress); + set_fail_led(&pAdapter->mvSataAdapter, pVDev->u.disk.mv->channelNumber, 1); + } +#endif +} + +int MvSataResetChannel(MV_SATA_ADAPTER *pMvSataAdapter, MV_U8 channel); + +static void +handleEdmaError(_VBUS_ARG PCommand pCmd) +{ + PDevice pDevice = &pCmd->pVDevice->u.disk; + MV_SATA_ADAPTER * pSataAdapter = pDevice->mv->mvSataAdapter; + + if (!pDevice->df_on_line) { + KdPrint(("Device is offline")); + pCmd->Result = RETURN_BAD_DEVICE; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + return; + } + + if (pCmd->RetryCount++>5) { + hpt_printk(("too many retries on channel(%d)\n", pDevice->mv->channelNumber)); +failed: + failDevice(pCmd->pVDevice); + pCmd->Result = RETURN_IDE_ERROR; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + return; + } + + /* reset the channel and retry the command */ + if (MvSataResetChannel(pSataAdapter, pDevice->mv->channelNumber)) + goto failed; + + fNotifyGUI(ET_DEVICE_ERROR, Map2pVDevice(pDevice)); + + hpt_printk(("Retry on channel(%d)\n", pDevice->mv->channelNumber)); + fDeviceSendCommand(_VBUS_P pCmd); +} + +/**************************************************************** + * Name: hptmv_init_channel + * + * Description: allocate request and response queues for the EDMA of the + * given channel and sets other fields. + * + * Parameters: + * pAdapter - pointer to the emulated adapter data structure + * channelNum - channel number. + * Return: 0 on success, otherwise on failure + ****************************************************************/ +static int +hptmv_init_channel(IAL_ADAPTER_T *pAdapter, MV_U8 channelNum) +{ + MV_SATA_CHANNEL *pMvSataChannel; + dma_addr_t req_dma_addr; + dma_addr_t rsp_dma_addr; + + if (channelNum >= MV_SATA_CHANNELS_NUM) + { + MV_ERROR("RR18xx[%d]: Bad channelNum=%d", + pAdapter->mvSataAdapter.adapterId, channelNum); + return -1; + } + + pMvSataChannel = &gMvSataChannels[pAdapter->mvSataAdapter.adapterId][channelNum]; + pAdapter->mvSataAdapter.sataChannel[channelNum] = pMvSataChannel; + pMvSataChannel->channelNumber = channelNum; + pMvSataChannel->lba48Address = MV_FALSE; + pMvSataChannel->maxReadTransfer = MV_FALSE; + + pMvSataChannel->requestQueue = (struct mvDmaRequestQueueEntry *) + (pAdapter->requestsArrayBaseAlignedAddr + (channelNum * MV_EDMA_REQUEST_QUEUE_SIZE)); + req_dma_addr = pAdapter->requestsArrayBaseDmaAlignedAddr + (channelNum * MV_EDMA_REQUEST_QUEUE_SIZE); + + + KdPrint(("requestQueue addr is 0x%llX", (HPT_U64)(ULONG_PTR)req_dma_addr)); + + /* check the 1K alignment of the request queue*/ + if (req_dma_addr & 0x3ff) + { + MV_ERROR("RR18xx[%d]: request queue allocated isn't 1 K aligned," + " dma_addr=%llx channel=%d\n", pAdapter->mvSataAdapter.adapterId, + (HPT_U64)(ULONG_PTR)req_dma_addr, channelNum); + return -1; + } + pMvSataChannel->requestQueuePciLowAddress = req_dma_addr; + pMvSataChannel->requestQueuePciHiAddress = 0; + KdPrint(("RR18xx[%d,%d]: request queue allocated: 0x%p", + pAdapter->mvSataAdapter.adapterId, channelNum, + pMvSataChannel->requestQueue)); + pMvSataChannel->responseQueue = (struct mvDmaResponseQueueEntry *) + (pAdapter->responsesArrayBaseAlignedAddr + (channelNum * MV_EDMA_RESPONSE_QUEUE_SIZE)); + rsp_dma_addr = pAdapter->responsesArrayBaseDmaAlignedAddr + (channelNum * MV_EDMA_RESPONSE_QUEUE_SIZE); + + /* check the 256 alignment of the response queue*/ + if (rsp_dma_addr & 0xff) + { + MV_ERROR("RR18xx[%d,%d]: response queue allocated isn't 256 byte " + "aligned, dma_addr=%llx\n", + pAdapter->mvSataAdapter.adapterId, channelNum, (HPT_U64)(ULONG_PTR)rsp_dma_addr); + return -1; + } + pMvSataChannel->responseQueuePciLowAddress = rsp_dma_addr; + pMvSataChannel->responseQueuePciHiAddress = 0; + KdPrint(("RR18xx[%d,%d]: response queue allocated: 0x%p", + pAdapter->mvSataAdapter.adapterId, channelNum, + pMvSataChannel->responseQueue)); + + pAdapter->mvChannel[channelNum].online = MV_TRUE; + return 0; +} + +/****************************************************************************** + * Name: hptmv_parse_identify_results + * + * Description: this functions parses the identify command results, checks + * that the connected deives can be accesed by RR18xx EDMA, + * and updates the channel stucture accordingly. + * + * Parameters: pMvSataChannel, pointer to the channel data structure. + * + * Returns: =0 ->success, < 0 ->failure. + * + ******************************************************************************/ +static int +hptmv_parse_identify_results(MV_SATA_CHANNEL *pMvSataChannel) +{ + MV_U16 *iden = pMvSataChannel->identifyDevice; + + /*LBA addressing*/ + if (! (iden[IDEN_CAPACITY_1_OFFSET] & 0x200)) + { + KdPrint(("IAL Error in IDENTIFY info: LBA not supported\n")); + return -1; + } + else + { + KdPrint(("%25s - %s\n", "Capabilities", "LBA supported")); + } + /*DMA support*/ + if (! (iden[IDEN_CAPACITY_1_OFFSET] & 0x100)) + { + KdPrint(("IAL Error in IDENTIFY info: DMA not supported\n")); + return -1; + } + else + { + KdPrint(("%25s - %s\n", "Capabilities", "DMA supported")); + } + /* PIO */ + if ((iden[IDEN_VALID] & 2) == 0) + { + KdPrint(("IAL Error in IDENTIFY info: not able to find PIO mode\n")); + return -1; + } + KdPrint(("%25s - 0x%02x\n", "PIO modes supported", + iden[IDEN_PIO_MODE_SPPORTED] & 0xff)); + + /*UDMA*/ + if ((iden[IDEN_VALID] & 4) == 0) + { + KdPrint(("IAL Error in IDENTIFY info: not able to find UDMA mode\n")); + return -1; + } + + /* 48 bit address */ + if ((iden[IDEN_SUPPORTED_COMMANDS2] & 0x400)) + { + KdPrint(("%25s - %s\n", "LBA48 addressing", "supported")); + pMvSataChannel->lba48Address = MV_TRUE; + } + else + { + KdPrint(("%25s - %s\n", "LBA48 addressing", "Not supported")); + pMvSataChannel->lba48Address = MV_FALSE; + } + return 0; +} + +static void +init_vdev_params(IAL_ADAPTER_T *pAdapter, MV_U8 channel) +{ + PVDevice pVDev = &pAdapter->VDevices[channel]; + MV_SATA_CHANNEL *pMvSataChannel = pAdapter->mvSataAdapter.sataChannel[channel]; + MV_U16_PTR IdentifyData = pMvSataChannel->identifyDevice; + + pMvSataChannel->outstandingCommands = 0; + + pVDev->u.disk.mv = pMvSataChannel; + pVDev->u.disk.df_on_line = 1; + pVDev->u.disk.pVBus = &pAdapter->VBus; + pVDev->pVBus = &pAdapter->VBus; + +#ifdef SUPPORT_48BIT_LBA + if (pMvSataChannel->lba48Address == MV_TRUE) + pVDev->u.disk.dDeRealCapacity = ((IdentifyData[101]<<16) | IdentifyData[100]) - 1; + else +#endif + if(IdentifyData[53] & 1) { + pVDev->u.disk.dDeRealCapacity = + (((IdentifyData[58]<<16 | IdentifyData[57]) < (IdentifyData[61]<<16 | IdentifyData[60])) ? + (IdentifyData[61]<<16 | IdentifyData[60]) : + (IdentifyData[58]<<16 | IdentifyData[57])) - 1; + } else + pVDev->u.disk.dDeRealCapacity = + (IdentifyData[61]<<16 | IdentifyData[60]) - 1; + + pVDev->u.disk.bDeUsable_Mode = pVDev->u.disk.bDeModeSetting = + pAdapter->mvChannel[channel].maxPioModeSupported - MV_ATA_TRANSFER_PIO_0; + + if (pAdapter->mvChannel[channel].maxUltraDmaModeSupported!=0xFF) { + pVDev->u.disk.bDeUsable_Mode = pVDev->u.disk.bDeModeSetting = + pAdapter->mvChannel[channel].maxUltraDmaModeSupported - MV_ATA_TRANSFER_UDMA_0 + 8; + } +} + +static void device_change(IAL_ADAPTER_T *pAdapter , MV_U8 channelIndex, int plugged) +{ + PVDevice pVDev; + MV_SATA_ADAPTER *pMvSataAdapter = &pAdapter->mvSataAdapter; + MV_SATA_CHANNEL *pMvSataChannel = pMvSataAdapter->sataChannel[channelIndex]; + + if (!pMvSataChannel) return; + + if (plugged) + { + pVDev = &(pAdapter->VDevices[channelIndex]); + init_vdev_params(pAdapter, channelIndex); + + pVDev->VDeviceType = pVDev->u.disk.df_atapi? VD_ATAPI : + pVDev->u.disk.df_removable_drive? VD_REMOVABLE : VD_SINGLE_DISK; + + pVDev->VDeviceCapacity = pVDev->u.disk.dDeRealCapacity-SAVE_FOR_RAID_INFO; + pVDev->pfnSendCommand = pfnSendCommand[pVDev->VDeviceType]; + pVDev->pfnDeviceFailed = pfnDeviceFailed[pVDev->VDeviceType]; + pVDev->vf_online = 1; + +#ifdef SUPPORT_ARRAY + if(pVDev->pParent) + { + int iMember; + for(iMember = 0; iMember < pVDev->pParent->u.array.bArnMember; iMember++) + if((PVDevice)pVDev->pParent->u.array.pMember[iMember] == pVDev) + pVDev->pParent->u.array.pMember[iMember] = NULL; + pVDev->pParent = NULL; + } +#endif + fNotifyGUI(ET_DEVICE_PLUGGED,pVDev); + fCheckBootable(pVDev); + RegisterVDevice(pVDev); + +#ifndef FOR_DEMO + if (pAdapter->beeping) { + pAdapter->beeping = 0; + BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress); + } +#endif + + } + else + { + pVDev = &(pAdapter->VDevices[channelIndex]); + failDevice(pVDev); + } +} + +static int +start_channel(IAL_ADAPTER_T *pAdapter, MV_U8 channelNum) +{ + MV_SATA_ADAPTER *pMvSataAdapter = &pAdapter->mvSataAdapter; + MV_SATA_CHANNEL *pMvSataChannel = pMvSataAdapter->sataChannel[channelNum]; + MV_CHANNEL *pChannelInfo = &(pAdapter->mvChannel[channelNum]); + MV_U32 udmaMode,pioMode; + + KdPrint(("RR18xx [%d]: start channel (%d)", pMvSataAdapter->adapterId, + channelNum)); + + + /* Software reset channel */ + if (mvStorageDevATASoftResetDevice(pMvSataAdapter, channelNum) == MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d]: failed to perform Software reset\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + + /* Hardware reset channel */ + if (mvSataChannelHardReset(pMvSataAdapter, channelNum) == MV_FALSE) + { + /* If failed, try again - this is when trying to hardreset a channel */ + /* when drive is just spinning up */ + StallExec(5000000); /* wait 5 sec before trying again */ + if (mvSataChannelHardReset(pMvSataAdapter, channelNum) == MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d]: failed to perform Hard reset\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + + /* identify device*/ + if (mvStorageDevATAIdentifyDevice(pMvSataAdapter, channelNum) == MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d]: failed to perform ATA Identify command\n" + , pMvSataAdapter->adapterId, channelNum); + return -1; + } + if (hptmv_parse_identify_results(pMvSataChannel)) + { + MV_ERROR("RR18xx [%d,%d]: Error in parsing ATA Identify message\n" + , pMvSataAdapter->adapterId, channelNum); + return -1; + } + + /* mvStorageDevATASetFeatures */ + /* Disable 8 bit PIO in case CFA enabled */ + if (pMvSataChannel->identifyDevice[86] & 4) + { + KdPrint(("RR18xx [%d]: Disable 8 bit PIO (CFA enabled) \n", + pMvSataAdapter->adapterId)); + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_DISABLE_8_BIT_PIO, 0, + 0, 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d]: channel %d: mvStorageDevATASetFeatures" + " failed\n", pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + /* Write cache */ +#ifdef ENABLE_WRITE_CACHE + if (pMvSataChannel->identifyDevice[82] & 0x20) + { + if (!(pMvSataChannel->identifyDevice[85] & 0x20)) /* if not enabled by default */ + { + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_ENABLE_WCACHE, 0, + 0, 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d]: channel %d: mvStorageDevATASetFeatures failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + KdPrint(("RR18xx [%d]: channel %d, write cache enabled\n", + pMvSataAdapter->adapterId, channelNum)); + } + else + { + KdPrint(("RR18xx [%d]: channel %d, write cache not supported\n", + pMvSataAdapter->adapterId, channelNum)); + } +#else /* disable write cache */ + { + if (pMvSataChannel->identifyDevice[85] & 0x20) + { + KdPrint(("RR18xx [%d]: channel =%d, disable write cache\n", + pMvSataAdapter->adapterId, channelNum)); + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_DISABLE_WCACHE, 0, + 0, 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d]: channel %d: mvStorageDevATASetFeatures failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + KdPrint(("RR18xx [%d]: channel=%d, write cache disabled\n", + pMvSataAdapter->adapterId, channelNum)); + } +#endif + + /* Set transfer mode */ + KdPrint(("RR18xx [%d] Set transfer mode XFER_PIO_SLOW\n", + pMvSataAdapter->adapterId)); + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_TRANSFER, + MV_ATA_TRANSFER_PIO_SLOW, 0, 0, 0) == + MV_FALSE) + { + MV_ERROR("RR18xx [%d] channel %d: Set Features failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + + if (pMvSataChannel->identifyDevice[IDEN_PIO_MODE_SPPORTED] & 1) + { + pioMode = MV_ATA_TRANSFER_PIO_4; + } + else if (pMvSataChannel->identifyDevice[IDEN_PIO_MODE_SPPORTED] & 2) + { + pioMode = MV_ATA_TRANSFER_PIO_3; + } + else + { + MV_ERROR("IAL Error in IDENTIFY info: PIO modes 3 and 4 not supported\n"); + pioMode = MV_ATA_TRANSFER_PIO_SLOW; + } + + KdPrint(("RR18xx [%d] Set transfer mode XFER_PIO_4\n", + pMvSataAdapter->adapterId)); + pAdapter->mvChannel[channelNum].maxPioModeSupported = pioMode; + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_TRANSFER, + pioMode, 0, 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d] channel %d: Set Features failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + + udmaMode = MV_ATA_TRANSFER_UDMA_0; + if (pMvSataChannel->identifyDevice[IDEN_UDMA_MODE] & 0x40) + { + udmaMode = MV_ATA_TRANSFER_UDMA_6; + } + else if (pMvSataChannel->identifyDevice[IDEN_UDMA_MODE] & 0x20) + { + udmaMode = MV_ATA_TRANSFER_UDMA_5; + } + else if (pMvSataChannel->identifyDevice[IDEN_UDMA_MODE] & 0x10) + { + udmaMode = MV_ATA_TRANSFER_UDMA_4; + } + else if (pMvSataChannel->identifyDevice[IDEN_UDMA_MODE] & 8) + { + udmaMode = MV_ATA_TRANSFER_UDMA_3; + } + else if (pMvSataChannel->identifyDevice[IDEN_UDMA_MODE] & 4) + { + udmaMode = MV_ATA_TRANSFER_UDMA_2; + } + + KdPrint(("RR18xx [%d] Set transfer mode XFER_UDMA_%d\n", + pMvSataAdapter->adapterId, udmaMode & 0xf)); + pChannelInfo->maxUltraDmaModeSupported = udmaMode; + + /*if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_TRANSFER, udmaMode, + 0, 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d] channel %d: Set Features failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + }*/ + if (pChannelInfo->maxUltraDmaModeSupported == 0xFF) + return TRUE; + else + do + { + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_TRANSFER, + pChannelInfo->maxUltraDmaModeSupported, + 0, 0, 0) == MV_FALSE) + { + if (pChannelInfo->maxUltraDmaModeSupported > MV_ATA_TRANSFER_UDMA_0) + { + if (mvStorageDevATASoftResetDevice(pMvSataAdapter, channelNum) == MV_FALSE) + { + MV_REG_WRITE_BYTE(pMvSataAdapter->adapterIoBaseAddress, + pMvSataChannel->eDmaRegsOffset + + 0x11c, /* command reg */ + MV_ATA_COMMAND_IDLE_IMMEDIATE); + mvMicroSecondsDelay(10000); + mvSataChannelHardReset(pMvSataAdapter, channelNum); + if (mvStorageDevATASoftResetDevice(pMvSataAdapter, channelNum) == MV_FALSE) + return FALSE; + } + if (mvSataChannelHardReset(pMvSataAdapter, channelNum) == MV_FALSE) + return FALSE; + pChannelInfo->maxUltraDmaModeSupported--; + continue; + } + else return FALSE; + } + break; + }while (1); + + /* Read look ahead */ +#ifdef ENABLE_READ_AHEAD + if (pMvSataChannel->identifyDevice[82] & 0x40) + { + if (!(pMvSataChannel->identifyDevice[85] & 0x40)) /* if not enabled by default */ + { + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_ENABLE_RLA, 0, 0, + 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d] channel %d: Set Features failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + KdPrint(("RR18xx [%d]: channel=%d, read look ahead enabled\n", + pMvSataAdapter->adapterId, channelNum)); + } + else + { + KdPrint(("RR18xx [%d]: channel %d, Read Look Ahead not supported\n", + pMvSataAdapter->adapterId, channelNum)); + } +#else + { + if (pMvSataChannel->identifyDevice[86] & 0x20) + { + KdPrint(("RR18xx [%d]:channel %d, disable read look ahead\n", + pMvSataAdapter->adapterId, channelNum)); + if (mvStorageDevATASetFeatures(pMvSataAdapter, channelNum, + MV_ATA_SET_FEATURES_DISABLE_RLA, 0, 0, + 0, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d]:channel %d: ATA Set Features failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + KdPrint(("RR18xx [%d]:channel %d, read look ahead disabled\n", + pMvSataAdapter->adapterId, channelNum)); + } +#endif + + + { + KdPrint(("RR18xx [%d]: channel %d config EDMA, Non Queued Mode\n", + pMvSataAdapter->adapterId, + channelNum)); + if (mvSataConfigEdmaMode(pMvSataAdapter, channelNum, + MV_EDMA_MODE_NOT_QUEUED, 0) == MV_FALSE) + { + MV_ERROR("RR18xx [%d] channel %d Error: mvSataConfigEdmaMode failed\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + } + /* Enable EDMA */ + if (mvSataEnableChannelDma(pMvSataAdapter, channelNum) == MV_FALSE) + { + MV_ERROR("RR18xx [%d] Failed to enable DMA, channel=%d\n", + pMvSataAdapter->adapterId, channelNum); + return -1; + } + MV_ERROR("RR18xx [%d,%d]: channel started successfully\n", + pMvSataAdapter->adapterId, channelNum); + +#ifndef FOR_DEMO + set_fail_led(pMvSataAdapter, channelNum, 0); +#endif + return 0; +} + +static void +hptmv_handle_event(void * data, int flag) +{ + IAL_ADAPTER_T *pAdapter = (IAL_ADAPTER_T *)data; + MV_SATA_ADAPTER *pMvSataAdapter = &pAdapter->mvSataAdapter; + MV_U8 channelIndex; + +/* mvOsSemTake(&pMvSataAdapter->semaphore); */ + for (channelIndex = 0; channelIndex < MV_SATA_CHANNELS_NUM; channelIndex++) + { + switch(pAdapter->sataEvents[channelIndex]) + { + case SATA_EVENT_CHANNEL_CONNECTED: + /* Handle only connects */ + if (flag == 1) + break; + KdPrint(("RR18xx [%d,%d]: new device connected\n", + pMvSataAdapter->adapterId, channelIndex)); + hptmv_init_channel(pAdapter, channelIndex); + if (mvSataConfigureChannel( pMvSataAdapter, channelIndex) == MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d] Failed to configure\n", + pMvSataAdapter->adapterId, channelIndex); + hptmv_free_channel(pAdapter, channelIndex); + } + else + { + /*mvSataChannelHardReset(pMvSataAdapter, channel);*/ + if (start_channel( pAdapter, channelIndex)) + { + MV_ERROR("RR18xx [%d,%d]Failed to start channel\n", + pMvSataAdapter->adapterId, channelIndex); + hptmv_free_channel(pAdapter, channelIndex); + } + else + { + device_change(pAdapter, channelIndex, TRUE); + } + } + pAdapter->sataEvents[channelIndex] = SATA_EVENT_NO_CHANGE; + break; + + case SATA_EVENT_CHANNEL_DISCONNECTED: + /* Handle only disconnects */ + if (flag == 0) + break; + KdPrint(("RR18xx [%d,%d]: device disconnected\n", + pMvSataAdapter->adapterId, channelIndex)); + /* Flush pending commands */ + if(pMvSataAdapter->sataChannel[channelIndex]) + { + _VBUS_INST(&pAdapter->VBus) + mvSataFlushDmaQueue (pMvSataAdapter, channelIndex, + MV_FLUSH_TYPE_CALLBACK); + CheckPendingCall(_VBUS_P0); + mvSataRemoveChannel(pMvSataAdapter,channelIndex); + hptmv_free_channel(pAdapter, channelIndex); + pMvSataAdapter->sataChannel[channelIndex] = NULL; + KdPrint(("RR18xx [%d,%d]: channel removed\n", + pMvSataAdapter->adapterId, channelIndex)); + if (pAdapter->outstandingCommands==0 && DPC_Request_Nums==0) + Check_Idle_Call(pAdapter); + } + else + { + KdPrint(("RR18xx [%d,%d]: channel already removed!!\n", + pMvSataAdapter->adapterId, channelIndex)); + } + pAdapter->sataEvents[channelIndex] = SATA_EVENT_NO_CHANGE; + break; + + case SATA_EVENT_NO_CHANGE: + break; + + default: + break; + } + } +/* mvOsSemRelease(&pMvSataAdapter->semaphore); */ +} + +#define EVENT_CONNECT 1 +#define EVENT_DISCONNECT 0 + +static void +hptmv_handle_event_connect(void *data) +{ + hptmv_handle_event (data, 0); +} + +static void +hptmv_handle_event_disconnect(void *data) +{ + hptmv_handle_event (data, 1); +} + +static MV_BOOLEAN +hptmv_event_notify(MV_SATA_ADAPTER *pMvSataAdapter, MV_EVENT_TYPE eventType, + MV_U32 param1, MV_U32 param2) +{ + IAL_ADAPTER_T *pAdapter = pMvSataAdapter->IALData; + + switch (eventType) + { + case MV_EVENT_TYPE_SATA_CABLE: + { + MV_U8 channel = param2; + + if (param1 == EVENT_CONNECT) + { + pAdapter->sataEvents[channel] = SATA_EVENT_CHANNEL_CONNECTED; + KdPrint(("RR18xx [%d,%d]: device connected event received\n", + pMvSataAdapter->adapterId, channel)); + /* Delete previous timers (if multiple drives connected in the same time */ + callout_reset(&pAdapter->event_timer_connect, 10*hz, hptmv_handle_event_connect, pAdapter); + } + else if (param1 == EVENT_DISCONNECT) + { + pAdapter->sataEvents[channel] = SATA_EVENT_CHANNEL_DISCONNECTED; + KdPrint(("RR18xx [%d,%d]: device disconnected event received \n", + pMvSataAdapter->adapterId, channel)); + device_change(pAdapter, channel, FALSE); + /* Delete previous timers (if multiple drives disconnected in the same time */ + /* callout_reset(&pAdapter->event_timer_disconnect, 10*hz, hptmv_handle_event_disconnect, pAdapter); */ + /*It is not necessary to wait, handle it directly*/ + hptmv_handle_event_disconnect(pAdapter); + } + else + { + + MV_ERROR("RR18xx: illigal value for param1(%d) at " + "connect/disconect event, host=%d\n", param1, + pMvSataAdapter->adapterId ); + + } + } + break; + case MV_EVENT_TYPE_ADAPTER_ERROR: + KdPrint(("RR18xx: DEVICE error event received, pci cause " + "reg=%x, don't how to handle this\n", param1)); + return MV_TRUE; + default: + MV_ERROR("RR18xx[%d]: unknown event type (%d)\n", + pMvSataAdapter->adapterId, eventType); + return MV_FALSE; + } + return MV_TRUE; +} + +static int +hptmv_allocate_edma_queues(IAL_ADAPTER_T *pAdapter) +{ + pAdapter->requestsArrayBaseAddr = (MV_U8 *)contigmalloc(REQUESTS_ARRAY_SIZE, + M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0ul); + if (pAdapter->requestsArrayBaseAddr == NULL) + { + MV_ERROR("RR18xx[%d]: Failed to allocate memory for EDMA request" + " queues\n", pAdapter->mvSataAdapter.adapterId); + return -1; + } + pAdapter->requestsArrayBaseDmaAddr = fOsPhysicalAddress(pAdapter->requestsArrayBaseAddr); + pAdapter->requestsArrayBaseAlignedAddr = pAdapter->requestsArrayBaseAddr; + pAdapter->requestsArrayBaseAlignedAddr += MV_EDMA_REQUEST_QUEUE_SIZE; + pAdapter->requestsArrayBaseAlignedAddr = (MV_U8 *) + (((ULONG_PTR)pAdapter->requestsArrayBaseAlignedAddr) & ~(ULONG_PTR)(MV_EDMA_REQUEST_QUEUE_SIZE - 1)); + pAdapter->requestsArrayBaseDmaAlignedAddr = pAdapter->requestsArrayBaseDmaAddr; + pAdapter->requestsArrayBaseDmaAlignedAddr += MV_EDMA_REQUEST_QUEUE_SIZE; + pAdapter->requestsArrayBaseDmaAlignedAddr &= ~(ULONG_PTR)(MV_EDMA_REQUEST_QUEUE_SIZE - 1); + + if ((pAdapter->requestsArrayBaseDmaAlignedAddr - pAdapter->requestsArrayBaseDmaAddr) != + (pAdapter->requestsArrayBaseAlignedAddr - pAdapter->requestsArrayBaseAddr)) + { + MV_ERROR("RR18xx[%d]: Error in Request Quueues Alignment\n", + pAdapter->mvSataAdapter.adapterId); + contigfree(pAdapter->requestsArrayBaseAddr, REQUESTS_ARRAY_SIZE, M_DEVBUF); + return -1; + } + /* response queues */ + pAdapter->responsesArrayBaseAddr = (MV_U8 *)contigmalloc(RESPONSES_ARRAY_SIZE, + M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0ul); + if (pAdapter->responsesArrayBaseAddr == NULL) + { + MV_ERROR("RR18xx[%d]: Failed to allocate memory for EDMA response" + " queues\n", pAdapter->mvSataAdapter.adapterId); + contigfree(pAdapter->requestsArrayBaseAddr, RESPONSES_ARRAY_SIZE, M_DEVBUF); + return -1; + } + pAdapter->responsesArrayBaseDmaAddr = fOsPhysicalAddress(pAdapter->responsesArrayBaseAddr); + pAdapter->responsesArrayBaseAlignedAddr = pAdapter->responsesArrayBaseAddr; + pAdapter->responsesArrayBaseAlignedAddr += MV_EDMA_RESPONSE_QUEUE_SIZE; + pAdapter->responsesArrayBaseAlignedAddr = (MV_U8 *) + (((ULONG_PTR)pAdapter->responsesArrayBaseAlignedAddr) & ~(ULONG_PTR)(MV_EDMA_RESPONSE_QUEUE_SIZE - 1)); + pAdapter->responsesArrayBaseDmaAlignedAddr = pAdapter->responsesArrayBaseDmaAddr; + pAdapter->responsesArrayBaseDmaAlignedAddr += MV_EDMA_RESPONSE_QUEUE_SIZE; + pAdapter->responsesArrayBaseDmaAlignedAddr &= ~(ULONG_PTR)(MV_EDMA_RESPONSE_QUEUE_SIZE - 1); + + if ((pAdapter->responsesArrayBaseDmaAlignedAddr - pAdapter->responsesArrayBaseDmaAddr) != + (pAdapter->responsesArrayBaseAlignedAddr - pAdapter->responsesArrayBaseAddr)) + { + MV_ERROR("RR18xx[%d]: Error in Response Quueues Alignment\n", + pAdapter->mvSataAdapter.adapterId); + contigfree(pAdapter->requestsArrayBaseAddr, REQUESTS_ARRAY_SIZE, M_DEVBUF); + contigfree(pAdapter->responsesArrayBaseAddr, RESPONSES_ARRAY_SIZE, M_DEVBUF); + return -1; + } + return 0; +} + +static void +hptmv_free_edma_queues(IAL_ADAPTER_T *pAdapter) +{ + contigfree(pAdapter->requestsArrayBaseAddr, REQUESTS_ARRAY_SIZE, M_DEVBUF); + contigfree(pAdapter->responsesArrayBaseAddr, RESPONSES_ARRAY_SIZE, M_DEVBUF); +} + +static PVOID +AllocatePRDTable(IAL_ADAPTER_T *pAdapter) +{ + PVOID ret; + if (pAdapter->pFreePRDLink) { + KdPrint(("pAdapter->pFreePRDLink:%p\n",pAdapter->pFreePRDLink)); + ret = pAdapter->pFreePRDLink; + pAdapter->pFreePRDLink = *(void**)ret; + return ret; + } + return NULL; +} + +static void +FreePRDTable(IAL_ADAPTER_T *pAdapter, PVOID PRDTable) +{ + *(void**)PRDTable = pAdapter->pFreePRDLink; + pAdapter->pFreePRDLink = PRDTable; +} + +extern PVDevice fGetFirstChild(PVDevice pLogical); +extern void fResetBootMark(PVDevice pLogical); +static void +fRegisterVdevice(IAL_ADAPTER_T *pAdapter) +{ + PVDevice pPhysical, pLogical; + PVBus pVBus; + int i,j; + + for(i=0;iVDevices[i]); + pLogical = pPhysical; + while (pLogical->pParent) pLogical = pLogical->pParent; + if (pLogical->vf_online==0) { + pPhysical->vf_bootmark = pLogical->vf_bootmark = 0; + continue; + } + if (pLogical->VDeviceType==VD_SPARE || pPhysical!=fGetFirstChild(pLogical)) + continue; + + pVBus = &pAdapter->VBus; + if(pVBus) + { + j=0; + while(jpVDevice[j]) j++; + if(jpVDevice[j] = pLogical; + pLogical->pVBus = pVBus; + + if (j>0 && pLogical->vf_bootmark) { + if (pVBus->pVDevice[0]->vf_bootmark) { + fResetBootMark(pLogical); + } + else { + do { pVBus->pVDevice[j] = pVBus->pVDevice[j-1]; } while (--j); + pVBus->pVDevice[0] = pLogical; + } + } + } + } + } +} + +PVDevice +GetSpareDisk(_VBUS_ARG PVDevice pArray) +{ + IAL_ADAPTER_T *pAdapter = (IAL_ADAPTER_T *)pArray->pVBus->OsExt; + LBA_T capacity = LongDiv(pArray->VDeviceCapacity, pArray->u.array.bArnMember-1); + LBA_T thiscap, maxcap = MAX_LBA_T; + PVDevice pVDevice, pFind = NULL; + int i; + + for(i=0;iVDevices[i]; + if(!pVDevice) + continue; + thiscap = pArray->vf_format_v2? pVDevice->u.disk.dDeRealCapacity : pVDevice->VDeviceCapacity; + /* find the smallest usable spare disk */ + if (pVDevice->VDeviceType==VD_SPARE && + pVDevice->u.disk.df_on_line && + thiscap < maxcap && + thiscap >= capacity) + { + maxcap = pVDevice->VDeviceCapacity; + pFind = pVDevice; + } + } + return pFind; +} + +/****************************************************************** + * IO ATA Command + *******************************************************************/ +int HPTLIBAPI +fDeReadWrite(PDevice pDev, ULONG Lba, UCHAR Cmd, void *tmpBuffer) +{ + return mvReadWrite(pDev->mv, Lba, Cmd, tmpBuffer); +} + +void HPTLIBAPI fDeSelectMode(PDevice pDev, UCHAR NewMode) +{ + MV_SATA_CHANNEL *pSataChannel = pDev->mv; + MV_SATA_ADAPTER *pSataAdapter = pSataChannel->mvSataAdapter; + MV_U8 channelIndex = pSataChannel->channelNumber; + UCHAR mvMode; + /* 508x don't use MW-DMA? */ + if (NewMode>4 && NewMode<8) NewMode = 4; + pDev->bDeModeSetting = NewMode; + if (NewMode<=4) + mvMode = MV_ATA_TRANSFER_PIO_0 + NewMode; + else + mvMode = MV_ATA_TRANSFER_UDMA_0 + (NewMode-8); + + /*To fix 88i8030 bug*/ + if (mvMode > MV_ATA_TRANSFER_UDMA_0 && mvMode < MV_ATA_TRANSFER_UDMA_4) + mvMode = MV_ATA_TRANSFER_UDMA_0; + + mvSataDisableChannelDma(pSataAdapter, channelIndex); + /* Flush pending commands */ + mvSataFlushDmaQueue (pSataAdapter, channelIndex, MV_FLUSH_TYPE_NONE); + + if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, + MV_ATA_SET_FEATURES_TRANSFER, + mvMode, 0, 0, 0) == MV_FALSE) + { + KdPrint(("channel %d: Set Features failed\n", channelIndex)); + } + /* Enable EDMA */ + if (mvSataEnableChannelDma(pSataAdapter, channelIndex) == MV_FALSE) + KdPrint(("Failed to enable DMA, channel=%d", channelIndex)); +} + +int HPTLIBAPI fDeSetTCQ(PDevice pDev, int enable, int depth) +{ + MV_SATA_CHANNEL *pSataChannel = pDev->mv; + MV_SATA_ADAPTER *pSataAdapter = pSataChannel->mvSataAdapter; + MV_U8 channelIndex = pSataChannel->channelNumber; + IAL_ADAPTER_T *pAdapter = pSataAdapter->IALData; + MV_CHANNEL *channelInfo = &(pAdapter->mvChannel[channelIndex]); + int dmaActive = pSataChannel->queueCommandsEnabled; + int ret = 0; + + if (dmaActive) { + mvSataDisableChannelDma(pSataAdapter, channelIndex); + mvSataFlushDmaQueue(pSataAdapter,channelIndex,MV_FLUSH_TYPE_CALLBACK); + } + + if (enable) { + if (pSataChannel->queuedDMA == MV_EDMA_MODE_NOT_QUEUED && + (pSataChannel->identifyDevice[IDEN_SUPPORTED_COMMANDS2] & (0x2))) { + UCHAR depth = ((pSataChannel->identifyDevice[IDEN_QUEUE_DEPTH]) & 0x1f) + 1; + channelInfo->queueDepth = (depth==32)? 31 : depth; + mvSataConfigEdmaMode(pSataAdapter, channelIndex, MV_EDMA_MODE_QUEUED, depth); + ret = 1; + } + } + else + { + if (pSataChannel->queuedDMA != MV_EDMA_MODE_NOT_QUEUED) { + channelInfo->queueDepth = 2; + mvSataConfigEdmaMode(pSataAdapter, channelIndex, MV_EDMA_MODE_NOT_QUEUED, 0); + ret = 1; + } + } + + if (dmaActive) + mvSataEnableChannelDma(pSataAdapter,channelIndex); + return ret; +} + +int HPTLIBAPI fDeSetNCQ(PDevice pDev, int enable, int depth) +{ + return 0; +} + +int HPTLIBAPI fDeSetWriteCache(PDevice pDev, int enable) +{ + MV_SATA_CHANNEL *pSataChannel = pDev->mv; + MV_SATA_ADAPTER *pSataAdapter = pSataChannel->mvSataAdapter; + MV_U8 channelIndex = pSataChannel->channelNumber; + IAL_ADAPTER_T *pAdapter = pSataAdapter->IALData; + MV_CHANNEL *channelInfo = &(pAdapter->mvChannel[channelIndex]); + int dmaActive = pSataChannel->queueCommandsEnabled; + int ret = 0; + + if (dmaActive) { + mvSataDisableChannelDma(pSataAdapter, channelIndex); + mvSataFlushDmaQueue(pSataAdapter,channelIndex,MV_FLUSH_TYPE_CALLBACK); + } + + if ((pSataChannel->identifyDevice[82] & (0x20))) { + if (enable) { + if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, + MV_ATA_SET_FEATURES_ENABLE_WCACHE, 0, 0, 0, 0)) + { + channelInfo->writeCacheEnabled = MV_TRUE; + ret = 1; + } + } + else { + if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, + MV_ATA_SET_FEATURES_DISABLE_WCACHE, 0, 0, 0, 0)) + { + channelInfo->writeCacheEnabled = MV_FALSE; + ret = 1; + } + } + } + + if (dmaActive) + mvSataEnableChannelDma(pSataAdapter,channelIndex); + return ret; +} + +int HPTLIBAPI fDeSetReadAhead(PDevice pDev, int enable) +{ + MV_SATA_CHANNEL *pSataChannel = pDev->mv; + MV_SATA_ADAPTER *pSataAdapter = pSataChannel->mvSataAdapter; + MV_U8 channelIndex = pSataChannel->channelNumber; + IAL_ADAPTER_T *pAdapter = pSataAdapter->IALData; + MV_CHANNEL *channelInfo = &(pAdapter->mvChannel[channelIndex]); + int dmaActive = pSataChannel->queueCommandsEnabled; + int ret = 0; + + if (dmaActive) { + mvSataDisableChannelDma(pSataAdapter, channelIndex); + mvSataFlushDmaQueue(pSataAdapter,channelIndex,MV_FLUSH_TYPE_CALLBACK); + } + + if ((pSataChannel->identifyDevice[82] & (0x40))) { + if (enable) { + if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, + MV_ATA_SET_FEATURES_ENABLE_RLA, 0, 0, 0, 0)) + { + channelInfo->readAheadEnabled = MV_TRUE; + ret = 1; + } + } + else { + if (mvStorageDevATASetFeatures(pSataAdapter, channelIndex, + MV_ATA_SET_FEATURES_DISABLE_RLA, 0, 0, 0, 0)) + { + channelInfo->readAheadEnabled = MV_FALSE; + ret = 1; + } + } + } + + if (dmaActive) + mvSataEnableChannelDma(pSataAdapter,channelIndex); + return ret; +} + +#ifdef SUPPORT_ARRAY +#define IdeRegisterVDevice fCheckArray +#else +void +IdeRegisterVDevice(PDevice pDev) +{ + PVDevice pVDev = Map2pVDevice(pDev); + + pVDev->VDeviceType = pDev->df_atapi? VD_ATAPI : + pDev->df_removable_drive? VD_REMOVABLE : VD_SINGLE_DISK; + pVDev->vf_online = 1; + pVDev->VDeviceCapacity = pDev->dDeRealCapacity; + pVDev->pfnSendCommand = pfnSendCommand[pVDev->VDeviceType]; + pVDev->pfnDeviceFailed = pfnDeviceFailed[pVDev->VDeviceType]; +} +#endif + +static __inline PBUS_DMAMAP +dmamap_get(struct IALAdapter * pAdapter) +{ + PBUS_DMAMAP p = pAdapter->pbus_dmamap_list; + if (p) + pAdapter->pbus_dmamap_list = p-> next; + return p; +} + +static __inline void +dmamap_put(PBUS_DMAMAP p) +{ + p->next = p->pAdapter->pbus_dmamap_list; + p->pAdapter->pbus_dmamap_list = p; +} + +/*Since mtx not provide the initialize when declare, so we Final init here to initialize the global mtx*/ +#define override_kernel_driver() + +static void hpt_init(void *dummy) +{ + override_kernel_driver(); + lockinit(&driver_lock, "hptsleeplock", 0, LK_CANRECURSE); +} +SYSINIT(hptinit, SI_SUB_CONFIGURE, SI_ORDER_FIRST, hpt_init, NULL); + +static int num_adapters = 0; +static int +init_adapter(IAL_ADAPTER_T *pAdapter) +{ + PVBus _vbus_p = &pAdapter->VBus; + MV_SATA_ADAPTER *pMvSataAdapter; + int i, channel, rid; + + PVDevice pVDev; + + intrmask_t oldspl = lock_driver(); + + pAdapter->next = 0; + + if(gIal_Adapter == 0){ + gIal_Adapter = pAdapter; + pCurAdapter = gIal_Adapter; + } + else { + pCurAdapter->next = pAdapter; + pCurAdapter = pAdapter; + } + + pAdapter->outstandingCommands = 0; + + pMvSataAdapter = &(pAdapter->mvSataAdapter); + _vbus_p->OsExt = (void *)pAdapter; + pMvSataAdapter->IALData = pAdapter; + + if (bus_dma_tag_create(NULL,/* parent */ + 4, /* alignment */ + BUS_SPACE_MAXADDR_32BIT+1, /* boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + PAGE_SIZE * (MAX_SG_DESCRIPTORS-1), /* maxsize */ + MAX_SG_DESCRIPTORS, /* nsegments */ + 0x10000, /* maxsegsize */ + BUS_DMA_WAITOK, /* flags */ + &pAdapter->io_dma_parent /* tag */)) + { + return ENXIO; + } + + + if (hptmv_allocate_edma_queues(pAdapter)) + { + MV_ERROR("RR18xx: Failed to allocate memory for EDMA queues\n"); + unlock_driver(oldspl); + return ENOMEM; + } + + /* also map EPROM address */ + rid = 0x10; + if (!(pAdapter->mem_res = bus_alloc_resource(pAdapter->hpt_dev, SYS_RES_MEMORY, &rid, + 0, ~0, MV_SATA_PCI_BAR0_SPACE_SIZE+0x40000, RF_ACTIVE)) + || + !(pMvSataAdapter->adapterIoBaseAddress = rman_get_virtual(pAdapter->mem_res))) + { + MV_ERROR("RR18xx: Failed to remap memory space\n"); + hptmv_free_edma_queues(pAdapter); + unlock_driver(oldspl); + return ENXIO; + } + else + { + KdPrint(("RR18xx: io base address 0x%p\n", pMvSataAdapter->adapterIoBaseAddress)); + } + + pMvSataAdapter->adapterId = num_adapters++; + /* get the revision ID */ + pMvSataAdapter->pciConfigRevisionId = pci_read_config(pAdapter->hpt_dev, PCIR_REVID, 1); + pMvSataAdapter->pciConfigDeviceId = pci_get_device(pAdapter->hpt_dev); + + /* init RR18xx */ + pMvSataAdapter->intCoalThre[0]= 1; + pMvSataAdapter->intCoalThre[1]= 1; + pMvSataAdapter->intTimeThre[0] = 1; + pMvSataAdapter->intTimeThre[1] = 1; + pMvSataAdapter->pciCommand = 0x0107E371; + pMvSataAdapter->pciSerrMask = 0xd77fe6ul; + pMvSataAdapter->pciInterruptMask = 0xd77fe6ul; + pMvSataAdapter->mvSataEventNotify = hptmv_event_notify; + + if (mvSataInitAdapter(pMvSataAdapter) == MV_FALSE) + { + MV_ERROR("RR18xx[%d]: core failed to initialize the adapter\n", + pMvSataAdapter->adapterId); +unregister: + bus_release_resource(pAdapter->hpt_dev, SYS_RES_MEMORY, rid, pAdapter->mem_res); + hptmv_free_edma_queues(pAdapter); + unlock_driver(oldspl); + return ENXIO; + } + pAdapter->ver_601 = pMvSataAdapter->pcbVersion; + +#ifndef FOR_DEMO + set_fail_leds(pMvSataAdapter, 0); +#endif + + /* setup command blocks */ + KdPrint(("Allocate command blocks\n")); + _vbus_(pFreeCommands) = 0; + pAdapter->pCommandBlocks = + kmalloc(sizeof(struct _Command) * MAX_COMMAND_BLOCKS_FOR_EACH_VBUS, M_DEVBUF, M_NOWAIT); + KdPrint(("pCommandBlocks:%p\n",pAdapter->pCommandBlocks)); + if (!pAdapter->pCommandBlocks) { + MV_ERROR("insufficient memory\n"); + goto unregister; + } + + for (i=0; ipCommandBlocks[i])); + } + + /*Set up the bus_dmamap*/ + pAdapter->pbus_dmamap = (PBUS_DMAMAP)kmalloc (sizeof(struct _BUS_DMAMAP) * MAX_QUEUE_COMM, M_DEVBUF, M_NOWAIT); + if(!pAdapter->pbus_dmamap) { + MV_ERROR("insufficient memory\n"); + kfree(pAdapter->pCommandBlocks, M_DEVBUF); + goto unregister; + } + + memset((void *)pAdapter->pbus_dmamap, 0, sizeof(struct _BUS_DMAMAP) * MAX_QUEUE_COMM); + pAdapter->pbus_dmamap_list = 0; + for (i=0; i < MAX_QUEUE_COMM; i++) { + PBUS_DMAMAP pmap = &(pAdapter->pbus_dmamap[i]); + pmap->pAdapter = pAdapter; + dmamap_put(pmap); + + if(bus_dmamap_create(pAdapter->io_dma_parent, 0, &pmap->dma_map)) { + MV_ERROR("Can not allocate dma map\n"); + kfree(pAdapter->pCommandBlocks, M_DEVBUF); + kfree(pAdapter->pbus_dmamap, M_DEVBUF); + goto unregister; + } + } + /* setup PRD Tables */ + KdPrint(("Allocate PRD Tables\n")); + pAdapter->pFreePRDLink = 0; + + pAdapter->prdTableAddr = (PUCHAR)contigmalloc( + (PRD_ENTRIES_SIZE*PRD_TABLES_FOR_VBUS + 32), M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0ul); + + KdPrint(("prdTableAddr:%p\n",pAdapter->prdTableAddr)); + if (!pAdapter->prdTableAddr) { + MV_ERROR("insufficient PRD Tables\n"); + goto unregister; + } + pAdapter->prdTableAlignedAddr = (PUCHAR)(((ULONG_PTR)pAdapter->prdTableAddr + 0x1f) & ~(ULONG_PTR)0x1fL); + { + PUCHAR PRDTable = pAdapter->prdTableAlignedAddr; + for (i=0; ipFreePRDLink=%p\n",i,pAdapter->pFreePRDLink)); */ + FreePRDTable(pAdapter, PRDTable); + PRDTable += PRD_ENTRIES_SIZE; + } + } + + /* enable the adapter interrupts */ + + /* configure and start the connected channels*/ + for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++) + { + pAdapter->mvChannel[channel].online = MV_FALSE; + if (mvSataIsStorageDeviceConnected(pMvSataAdapter, channel) + == MV_TRUE) + { + KdPrint(("RR18xx[%d]: channel %d is connected\n", + pMvSataAdapter->adapterId, channel)); + + if (hptmv_init_channel(pAdapter, channel) == 0) + { + if (mvSataConfigureChannel(pMvSataAdapter, channel) == MV_FALSE) + { + MV_ERROR("RR18xx[%d]: Failed to configure channel" + " %d\n",pMvSataAdapter->adapterId, channel); + hptmv_free_channel(pAdapter, channel); + } + else + { + if (start_channel(pAdapter, channel)) + { + MV_ERROR("RR18xx[%d]: Failed to start channel," + " channel=%d\n",pMvSataAdapter->adapterId, + channel); + hptmv_free_channel(pAdapter, channel); + } + pAdapter->mvChannel[channel].online = MV_TRUE; + /* mvSataChannelSetEdmaLoopBackMode(pMvSataAdapter, + channel, + MV_TRUE);*/ + } + } + } + KdPrint(("pAdapter->mvChannel[channel].online:%x, channel:%d\n", + pAdapter->mvChannel[channel].online, channel)); + } + +#ifdef SUPPORT_ARRAY + for(i = MAX_ARRAY_DEVICE - 1; i >= 0; i--) { + pVDev = ArrayTables(i); + mArFreeArrayTable(pVDev); + } +#endif + + KdPrint(("Initialize Devices\n")); + for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++) { + MV_SATA_CHANNEL *pMvSataChannel = pMvSataAdapter->sataChannel[channel]; + if (pMvSataChannel) { + init_vdev_params(pAdapter, channel); + IdeRegisterVDevice(&pAdapter->VDevices[channel].u.disk); + } + } +#ifdef SUPPORT_ARRAY + CheckArrayCritical(_VBUS_P0); +#endif + _vbus_p->nInstances = 1; + fRegisterVdevice(pAdapter); + + for (channel=0;channelpVDevice[channel]; + if (pVDev && pVDev->vf_online) + fCheckBootable(pVDev); + } + +#if defined(SUPPORT_ARRAY) && defined(_RAID5N_) + init_raid5_memory(_VBUS_P0); + _vbus_(r5).enable_write_back = 1; + kprintf("RR18xx: RAID5 write-back %s\n", _vbus_(r5).enable_write_back? "enabled" : "disabled"); +#endif + + mvSataUnmaskAdapterInterrupt(pMvSataAdapter); + unlock_driver(oldspl); + return 0; +} + +int +MvSataResetChannel(MV_SATA_ADAPTER *pMvSataAdapter, MV_U8 channel) +{ + IAL_ADAPTER_T *pAdapter = (IAL_ADAPTER_T *)pMvSataAdapter->IALData; + + mvSataDisableChannelDma(pMvSataAdapter, channel); + /* Flush pending commands */ + mvSataFlushDmaQueue (pMvSataAdapter, channel, MV_FLUSH_TYPE_CALLBACK); + + /* Software reset channel */ + if (mvStorageDevATASoftResetDevice(pMvSataAdapter, channel) == MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d]: failed to perform Software reset\n", + pMvSataAdapter->adapterId, channel); + hptmv_free_channel(pAdapter, channel); + return -1; + } + + /* Hardware reset channel */ + if (mvSataChannelHardReset(pMvSataAdapter, channel)== MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d] Failed to Hard reser the SATA channel\n", + pMvSataAdapter->adapterId, channel); + hptmv_free_channel(pAdapter, channel); + return -1; + } + + if (mvSataIsStorageDeviceConnected(pMvSataAdapter, channel) == MV_FALSE) + { + MV_ERROR("RR18xx [%d,%d] Failed to Connect Device\n", + pMvSataAdapter->adapterId, channel); + hptmv_free_channel(pAdapter, channel); + return -1; + }else + { + MV_ERROR("channel %d: perform recalibrate command", channel); + if (!mvStorageDevATAExecuteNonUDMACommand(pMvSataAdapter, channel, + MV_NON_UDMA_PROTOCOL_NON_DATA, + MV_FALSE, + NULL, /* pBuffer*/ + 0, /* count */ + 0, /*features*/ + /* sectorCount */ + 0, + 0, /* lbaLow */ + 0, /* lbaMid */ + /* lbaHigh */ + 0, + 0, /* device */ + /* command */ + 0x10)) + MV_ERROR("channel %d: recalibrate failed", channel); + + /* Set transfer mode */ + if((mvStorageDevATASetFeatures(pMvSataAdapter, channel, + MV_ATA_SET_FEATURES_TRANSFER, + MV_ATA_TRANSFER_PIO_SLOW, 0, 0, 0) == MV_FALSE) || + (mvStorageDevATASetFeatures(pMvSataAdapter, channel, + MV_ATA_SET_FEATURES_TRANSFER, + pAdapter->mvChannel[channel].maxPioModeSupported, 0, 0, 0) == MV_FALSE) || + (mvStorageDevATASetFeatures(pMvSataAdapter, channel, + MV_ATA_SET_FEATURES_TRANSFER, + pAdapter->mvChannel[channel].maxUltraDmaModeSupported, 0, 0, 0) == MV_FALSE) ) + { + MV_ERROR("channel %d: Set Features failed", channel); + hptmv_free_channel(pAdapter, channel); + return -1; + } + /* Enable EDMA */ + if (mvSataEnableChannelDma(pMvSataAdapter, channel) == MV_FALSE) + { + MV_ERROR("Failed to enable DMA, channel=%d", channel); + hptmv_free_channel(pAdapter, channel); + return -1; + } + } + return 0; +} + +static int +fResetActiveCommands(PVBus _vbus_p) +{ + MV_SATA_ADAPTER *pMvSataAdapter = &((IAL_ADAPTER_T *)_vbus_p->OsExt)->mvSataAdapter; + MV_U8 channel; + for (channel=0;channel< MV_SATA_CHANNELS_NUM;channel++) { + if (pMvSataAdapter->sataChannel[channel] && pMvSataAdapter->sataChannel[channel]->outstandingCommands) + MvSataResetChannel(pMvSataAdapter,channel); + } + return 0; +} + +void fCompleteAllCommandsSynchronously(PVBus _vbus_p) +{ + UINT cont; + ULONG ticks = 0; + MV_U8 channel; + MV_SATA_ADAPTER *pMvSataAdapter = &((IAL_ADAPTER_T *)_vbus_p->OsExt)->mvSataAdapter; + MV_SATA_CHANNEL *pMvSataChannel; + + do { +check_cmds: + cont = 0; + CheckPendingCall(_VBUS_P0); +#ifdef _RAID5N_ + dataxfer_poll(); + xor_poll(); +#endif + for (channel=0;channel< MV_SATA_CHANNELS_NUM;channel++) { + pMvSataChannel = pMvSataAdapter->sataChannel[channel]; + if (pMvSataChannel && pMvSataChannel->outstandingCommands) + { + while (pMvSataChannel->outstandingCommands) { + if (!mvSataInterruptServiceRoutine(pMvSataAdapter)) { + StallExec(1000); + if (ticks++ > 3000) { + MvSataResetChannel(pMvSataAdapter,channel); + goto check_cmds; + } + } + else + ticks = 0; + } + cont = 1; + } + } + } while (cont); +} + +void +fResetVBus(_VBUS_ARG0) +{ + KdPrint(("fMvResetBus(%p)", _vbus_p)); + + /* some commands may already finished. */ + CheckPendingCall(_VBUS_P0); + + fResetActiveCommands(_vbus_p); + /* + * the other pending commands may still be finished successfully. + */ + fCompleteAllCommandsSynchronously(_vbus_p); + + /* Now there should be no pending commands. No more action needed. */ + CheckIdleCall(_VBUS_P0); + + KdPrint(("fMvResetBus() done")); +} + +/*No rescan function*/ +void +fRescanAllDevice(_VBUS_ARG0) +{ +} + +static MV_BOOLEAN +CommandCompletionCB(MV_SATA_ADAPTER *pMvSataAdapter, + MV_U8 channelNum, + MV_COMPLETION_TYPE comp_type, + MV_VOID_PTR commandId, + MV_U16 responseFlags, + MV_U32 timeStamp, + MV_STORAGE_DEVICE_REGISTERS *registerStruct) +{ + PCommand pCmd = (PCommand) commandId; + _VBUS_INST(pCmd->pVDevice->pVBus) + + if (pCmd->uScratch.sata_param.prdAddr) + FreePRDTable(pMvSataAdapter->IALData,pCmd->uScratch.sata_param.prdAddr); + + switch (comp_type) + { + case MV_COMPLETION_TYPE_NORMAL: + pCmd->Result = RETURN_SUCCESS; + break; + case MV_COMPLETION_TYPE_ABORT: + pCmd->Result = RETURN_BUS_RESET; + break; + case MV_COMPLETION_TYPE_ERROR: + MV_ERROR("IAL: COMPLETION ERROR, adapter %d, channel %d, flags=%x\n", + pMvSataAdapter->adapterId, channelNum, responseFlags); + + if (responseFlags & 4) { + MV_ERROR("ATA regs: error %x, sector count %x, LBA low %x, LBA mid %x," + " LBA high %x, device %x, status %x\n", + registerStruct->errorRegister, + registerStruct->sectorCountRegister, + registerStruct->lbaLowRegister, + registerStruct->lbaMidRegister, + registerStruct->lbaHighRegister, + registerStruct->deviceRegister, + registerStruct->statusRegister); + } + /*We can't do handleEdmaError directly here, because CommandCompletionCB is called by + * mv's ISR, if we retry the command, than the internel data structure may be destroyed*/ + pCmd->uScratch.sata_param.responseFlags = responseFlags; + pCmd->uScratch.sata_param.bIdeStatus = registerStruct->statusRegister; + pCmd->uScratch.sata_param.errorRegister = registerStruct->errorRegister; + pCmd->pVDevice->u.disk.QueueLength--; + CallAfterReturn(_VBUS_P (DPC_PROC)handleEdmaError,pCmd); + return TRUE; + + default: + MV_ERROR(" Unknown completion type (%d)\n", comp_type); + return MV_FALSE; + } + + if (pCmd->uCmd.Ide.Command == IDE_COMMAND_VERIFY && pCmd->uScratch.sata_param.cmd_priv > 1) { + pCmd->uScratch.sata_param.cmd_priv --; + return TRUE; + } + pCmd->pVDevice->u.disk.QueueLength--; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + return TRUE; +} + +void +fDeviceSendCommand(_VBUS_ARG PCommand pCmd) +{ + MV_SATA_EDMA_PRD_ENTRY *pPRDTable = 0; + MV_SATA_ADAPTER *pMvSataAdapter; + MV_SATA_CHANNEL *pMvSataChannel; + PVDevice pVDevice = pCmd->pVDevice; + PDevice pDevice = &pVDevice->u.disk; + LBA_T Lba = pCmd->uCmd.Ide.Lba; + USHORT nSector = pCmd->uCmd.Ide.nSectors; + + MV_QUEUE_COMMAND_RESULT result; + MV_QUEUE_COMMAND_INFO commandInfo; + MV_UDMA_COMMAND_PARAMS *pUdmaParams = &commandInfo.commandParams.udmaCommand; + MV_NONE_UDMA_COMMAND_PARAMS *pNoUdmaParams = &commandInfo.commandParams.NoneUdmaCommand; + + MV_BOOLEAN is48bit; + MV_U8 channel; + int i=0; + + DECLARE_BUFFER(FPSCAT_GATH, tmpSg); + + if (!pDevice->df_on_line) { + MV_ERROR("Device is offline"); + pCmd->Result = RETURN_BAD_DEVICE; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + return; + } + + pDevice->HeadPosition = pCmd->uCmd.Ide.Lba + pCmd->uCmd.Ide.nSectors; + pMvSataChannel = pDevice->mv; + pMvSataAdapter = pMvSataChannel->mvSataAdapter; + channel = pMvSataChannel->channelNumber; + + /* old RAID0 has hidden lba. Remember to clear dDeHiddenLba when delete array! */ + Lba += pDevice->dDeHiddenLba; + /* check LBA */ + if (Lba+nSector-1 > pDevice->dDeRealCapacity) { + pCmd->Result = RETURN_INVALID_REQUEST; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + return; + } + + /* + * always use 48bit LBA if drive supports it. + * Some Seagate drives report error if you use a 28-bit command + * to access sector 0xfffffff. + */ + is48bit = pMvSataChannel->lba48Address; + + switch (pCmd->uCmd.Ide.Command) + { + case IDE_COMMAND_READ: + case IDE_COMMAND_WRITE: + if (pDevice->bDeModeSetting<8) goto pio; + + commandInfo.type = MV_QUEUED_COMMAND_TYPE_UDMA; + pUdmaParams->isEXT = is48bit; + pUdmaParams->numOfSectors = nSector; + pUdmaParams->lowLBAAddress = Lba; + pUdmaParams->highLBAAddress = 0; + pUdmaParams->prdHighAddr = 0; + pUdmaParams->callBack = CommandCompletionCB; + pUdmaParams->commandId = (MV_VOID_PTR )pCmd; + if(pCmd->uCmd.Ide.Command == IDE_COMMAND_READ) + pUdmaParams->readWrite = MV_UDMA_TYPE_READ; + else + pUdmaParams->readWrite = MV_UDMA_TYPE_WRITE; + + if (pCmd->pSgTable && pCmd->cf_physical_sg) { + FPSCAT_GATH sg1=tmpSg, sg2=pCmd->pSgTable; + do { *sg1++=*sg2; } while ((sg2++->wSgFlag & SG_FLAG_EOT)==0); + } + else { + if (!pCmd->pfnBuildSgl || !pCmd->pfnBuildSgl(_VBUS_P pCmd, tmpSg, 0)) { +pio: + mvSataDisableChannelDma(pMvSataAdapter, channel); + mvSataFlushDmaQueue(pMvSataAdapter, channel, MV_FLUSH_TYPE_CALLBACK); + + if (pCmd->pSgTable && pCmd->cf_physical_sg==0) { + FPSCAT_GATH sg1=tmpSg, sg2=pCmd->pSgTable; + do { *sg1++=*sg2; } while ((sg2++->wSgFlag & SG_FLAG_EOT)==0); + } + else { + if (!pCmd->pfnBuildSgl || !pCmd->pfnBuildSgl(_VBUS_P pCmd, tmpSg, 1)) { + pCmd->Result = RETURN_NEED_LOGICAL_SG; + goto finish_cmd; + } + } + + do { + ULONG size = tmpSg->wSgSize? tmpSg->wSgSize : 0x10000; + ULONG_PTR addr = tmpSg->dSgAddress; + if (size & 0x1ff) { + pCmd->Result = RETURN_INVALID_REQUEST; + goto finish_cmd; + } + if (mvStorageDevATAExecuteNonUDMACommand(pMvSataAdapter, channel, + (pCmd->cf_data_out)?MV_NON_UDMA_PROTOCOL_PIO_DATA_OUT:MV_NON_UDMA_PROTOCOL_PIO_DATA_IN, + is48bit, + (MV_U16_PTR)addr, + size >> 1, /* count */ + 0, /* features N/A */ + (MV_U16)(size>>9), /*sector count*/ + (MV_U16)( (is48bit? (MV_U16)((Lba >> 16) & 0xFF00) : 0 ) | (UCHAR)(Lba & 0xFF) ), /*lbalow*/ + (MV_U16)((Lba >> 8) & 0xFF), /* lbaMid */ + (MV_U16)((Lba >> 16) & 0xFF),/* lbaHigh */ + (MV_U8)(0x40 | (is48bit ? 0 : (UCHAR)(Lba >> 24) & 0xFF )),/* device */ + (MV_U8)(is48bit ? (pCmd->cf_data_in?IDE_COMMAND_READ_EXT:IDE_COMMAND_WRITE_EXT):pCmd->uCmd.Ide.Command) + )==MV_FALSE) + { + pCmd->Result = RETURN_IDE_ERROR; + goto finish_cmd; + } + Lba += size>>9; + if(Lba & 0xF0000000) is48bit = MV_TRUE; + } + while ((tmpSg++->wSgFlag & SG_FLAG_EOT)==0); + pCmd->Result = RETURN_SUCCESS; +finish_cmd: + mvSataEnableChannelDma(pMvSataAdapter,channel); + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + return; + } + } + + pPRDTable = (MV_SATA_EDMA_PRD_ENTRY *) AllocatePRDTable(pMvSataAdapter->IALData); + KdPrint(("pPRDTable:%p\n",pPRDTable)); + if (!pPRDTable) { + pCmd->Result = RETURN_DEVICE_BUSY; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + HPT_ASSERT(0); + return; + } + + do{ + pPRDTable[i].highBaseAddr = (sizeof(tmpSg->dSgAddress)>4 ? (MV_U32)(tmpSg->dSgAddress>>32) : 0); + pPRDTable[i].flags = (MV_U16)tmpSg->wSgFlag; + pPRDTable[i].byteCount = (MV_U16)tmpSg->wSgSize; + pPRDTable[i].lowBaseAddr = (MV_U32)tmpSg->dSgAddress; + pPRDTable[i].reserved = 0; + i++; + }while((tmpSg++->wSgFlag & SG_FLAG_EOT)==0); + + pUdmaParams->prdLowAddr = (ULONG)fOsPhysicalAddress(pPRDTable); + if ((pUdmaParams->numOfSectors == 256) && (pMvSataChannel->lba48Address == MV_FALSE)) { + pUdmaParams->numOfSectors = 0; + } + + pCmd->uScratch.sata_param.prdAddr = (PVOID)pPRDTable; + + result = mvSataQueueCommand(pMvSataAdapter, channel, &commandInfo); + + if (result != MV_QUEUE_COMMAND_RESULT_OK) + { +queue_failed: + switch (result) + { + case MV_QUEUE_COMMAND_RESULT_BAD_LBA_ADDRESS: + MV_ERROR("IAL Error: Edma Queue command failed. Bad LBA " + "LBA[31:0](0x%08x)\n", pUdmaParams->lowLBAAddress); + pCmd->Result = RETURN_IDE_ERROR; + break; + case MV_QUEUE_COMMAND_RESULT_QUEUED_MODE_DISABLED: + MV_ERROR("IAL Error: Edma Queue command failed. EDMA" + " disabled adapter %d channel %d\n", + pMvSataAdapter->adapterId, channel); + mvSataEnableChannelDma(pMvSataAdapter,channel); + pCmd->Result = RETURN_IDE_ERROR; + break; + case MV_QUEUE_COMMAND_RESULT_FULL: + MV_ERROR("IAL Error: Edma Queue command failed. Queue is" + " Full adapter %d channel %d\n", + pMvSataAdapter->adapterId, channel); + pCmd->Result = RETURN_DEVICE_BUSY; + break; + case MV_QUEUE_COMMAND_RESULT_BAD_PARAMS: + MV_ERROR("IAL Error: Edma Queue command failed. (Bad " + "Params), pMvSataAdapter: %p, pSataChannel: %p.\n", + pMvSataAdapter, pMvSataAdapter->sataChannel[channel]); + pCmd->Result = RETURN_IDE_ERROR; + break; + default: + MV_ERROR("IAL Error: Bad result value (%d) from queue" + " command\n", result); + pCmd->Result = RETURN_IDE_ERROR; + } + if(pPRDTable) + FreePRDTable(pMvSataAdapter->IALData,pPRDTable); + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + } + pDevice->QueueLength++; + return; + + case IDE_COMMAND_VERIFY: + commandInfo.type = MV_QUEUED_COMMAND_TYPE_NONE_UDMA; + pNoUdmaParams->bufPtr = NULL; + pNoUdmaParams->callBack = CommandCompletionCB; + pNoUdmaParams->commandId = (MV_VOID_PTR)pCmd; + pNoUdmaParams->count = 0; + pNoUdmaParams->features = 0; + pNoUdmaParams->protocolType = MV_NON_UDMA_PROTOCOL_NON_DATA; + + pCmd->uScratch.sata_param.cmd_priv = 1; + if (pMvSataChannel->lba48Address == MV_TRUE){ + pNoUdmaParams->command = MV_ATA_COMMAND_READ_VERIFY_SECTORS_EXT; + pNoUdmaParams->isEXT = MV_TRUE; + pNoUdmaParams->lbaHigh = (MV_U16)((Lba & 0xff0000) >> 16); + pNoUdmaParams->lbaMid = (MV_U16)((Lba & 0xff00) >> 8); + pNoUdmaParams->lbaLow = + (MV_U16)(((Lba & 0xff000000) >> 16)| (Lba & 0xff)); + pNoUdmaParams->sectorCount = nSector; + pNoUdmaParams->device = 0x40; + result = mvSataQueueCommand(pMvSataAdapter, channel, &commandInfo); + if (result != MV_QUEUE_COMMAND_RESULT_OK){ + goto queue_failed; + } + return; + } + else{ + pNoUdmaParams->command = MV_ATA_COMMAND_READ_VERIFY_SECTORS; + pNoUdmaParams->isEXT = MV_FALSE; + pNoUdmaParams->lbaHigh = (MV_U16)((Lba & 0xff0000) >> 16); + pNoUdmaParams->lbaMid = (MV_U16)((Lba & 0xff00) >> 8); + pNoUdmaParams->lbaLow = (MV_U16)(Lba & 0xff); + pNoUdmaParams->sectorCount = 0xff & nSector; + pNoUdmaParams->device = (MV_U8)(0x40 | + ((Lba & 0xf000000) >> 24)); + pNoUdmaParams->callBack = CommandCompletionCB; + result = mvSataQueueCommand(pMvSataAdapter, channel, &commandInfo); + /*FIXME: how about the commands already queued? but marvel also forgets to consider this*/ + if (result != MV_QUEUE_COMMAND_RESULT_OK){ + goto queue_failed; + } + } + break; + default: + pCmd->Result = RETURN_INVALID_REQUEST; + CallAfterReturn(_VBUS_P (DPC_PROC)pCmd->pfnCompletion, pCmd); + break; + } +} + +/********************************************************** + * + * Probe the hostadapter. + * + **********************************************************/ +static int +hpt_probe(device_t dev) +{ + if ((pci_get_vendor(dev) == MV_SATA_VENDOR_ID) && + (pci_get_device(dev) == MV_SATA_DEVICE_ID_5081 +#ifdef FOR_DEMO + || pci_get_device(dev) == MV_SATA_DEVICE_ID_5080 +#endif + )) + { + KdPrintI((CONTROLLER_NAME " found\n")); + device_set_desc(dev, CONTROLLER_NAME); + return 0; + } + else + return(ENXIO); +} + +/*********************************************************** + * + * Auto configuration: attach and init a host adapter. + * + ***********************************************************/ +static int +hpt_attach(device_t dev) +{ + IAL_ADAPTER_T * pAdapter = device_get_softc(dev); + int rid; + union ccb *ccb; + struct cam_devq *devq; + struct cam_sim *hpt_vsim; + + kprintf("%s Version %s \n", DRIVER_NAME, DRIVER_VERSION); + + if (!pAdapter) + { + pAdapter = (IAL_ADAPTER_T *)kmalloc(sizeof (IAL_ADAPTER_T), M_DEVBUF, M_NOWAIT); + device_set_softc(dev, (void *)pAdapter); + } + + if (!pAdapter) return (ENOMEM); + bzero(pAdapter, sizeof(IAL_ADAPTER_T)); + + pAdapter->hpt_dev = dev; + + rid = init_adapter(pAdapter); + if (rid) + return rid; + + rid = 0; + if ((pAdapter->hpt_irq = bus_alloc_resource(pAdapter->hpt_dev, SYS_RES_IRQ, &rid, 0, ~0ul, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) + { + hpt_printk(("can't allocate interrupt\n")); + return(ENXIO); + } + + if (bus_setup_intr(pAdapter->hpt_dev, pAdapter->hpt_irq, 0, + hpt_intr, pAdapter, &pAdapter->hpt_intr, NULL)) + { + hpt_printk(("can't set up interrupt\n")); + kfree(pAdapter, M_DEVBUF); + return(ENXIO); + } + + + if((ccb = (union ccb *)kmalloc(sizeof(*ccb), M_DEVBUF, M_WAITOK)) != (union ccb*)NULL) + { + bzero(ccb, sizeof(*ccb)); + ccb->ccb_h.pinfo.priority = 1; + ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX; + } + else + { + return ENOMEM; + } + /* + * Create the device queue for our SIM(s). + */ + if((devq = cam_simq_alloc(8/*MAX_QUEUE_COMM*/)) == NULL) + { + KdPrint(("ENXIO\n")); + return ENOMEM; + } + + /* + * Construct our SIM entry + */ + hpt_vsim = cam_sim_alloc(hpt_action, hpt_poll, __str(PROC_DIR_NAME), + pAdapter, device_get_unit(pAdapter->hpt_dev), &sim_mplock, 1, 8, devq); + cam_simq_release(devq); + if (hpt_vsim == NULL) { + return ENOMEM; + } + + if (xpt_bus_register(hpt_vsim, 0) != CAM_SUCCESS) + { + cam_sim_free(hpt_vsim); + hpt_vsim = NULL; + return ENXIO; + } + + if(xpt_create_path(&pAdapter->path, /*periph */ NULL, + cam_sim_path(hpt_vsim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) + { + xpt_bus_deregister(cam_sim_path(hpt_vsim)); + cam_sim_free(hpt_vsim); + hpt_vsim = NULL; + return ENXIO; + } + + xpt_setup_ccb(&(ccb->ccb_h), pAdapter->path, /*priority*/5); + ccb->ccb_h.func_code = XPT_SASYNC_CB; + ccb->csa.event_enable = AC_LOST_DEVICE; + ccb->csa.callback = hpt_async; + ccb->csa.callback_arg = hpt_vsim; + xpt_action((union ccb *)ccb); + kfree(ccb, M_DEVBUF); + + callout_init(&pAdapter->event_timer_connect); + callout_init(&pAdapter->event_timer_disconnect); + + if (device_get_unit(dev) == 0) { + /* Start the work thread. XXX */ + launch_worker_thread(); + } + + return 0; +} + +static int +hpt_detach(device_t dev) +{ + return (EBUSY); +} + + +/*************************************************************** + * The poll function is used to simulate the interrupt when + * the interrupt subsystem is not functioning. + * + ***************************************************************/ +static void +hpt_poll(struct cam_sim *sim) +{ + hpt_intr((void *)cam_sim_softc(sim)); +} + +/**************************************************************** + * Name: hpt_intr + * Description: Interrupt handler. + ****************************************************************/ +static void +hpt_intr(void *arg) +{ + IAL_ADAPTER_T *pAdapter = (IAL_ADAPTER_T *)arg; + intrmask_t oldspl = lock_driver(); + + /* KdPrintI(("----- Entering Isr() -----\n")); */ + if (mvSataInterruptServiceRoutine(&pAdapter->mvSataAdapter) == MV_TRUE) + { + _VBUS_INST(&pAdapter->VBus) + CheckPendingCall(_VBUS_P0); + } + + /* KdPrintI(("----- Leaving Isr() -----\n")); */ + unlock_driver(oldspl); +} + +/********************************************************** + * Asynchronous Events + *********************************************************/ +#if (!defined(UNREFERENCED_PARAMETER)) +#define UNREFERENCED_PARAMETER(x) (void)(x) +#endif + +static void +hpt_async(void * callback_arg, u_int32_t code, struct cam_path * path, + void * arg) +{ + /* debug XXXX */ + panic("Here"); + UNREFERENCED_PARAMETER(callback_arg); + UNREFERENCED_PARAMETER(code); + UNREFERENCED_PARAMETER(path); + UNREFERENCED_PARAMETER(arg); + +} + +static void +FlushAdapter(IAL_ADAPTER_T *pAdapter) +{ + int i; + + hpt_printk(("flush all devices\n")); + + /* flush all devices */ + for (i=0; iVBus.pVDevice[i]; + if(pVDev) fFlushVDev(pVDev); + } +} + +static int +hpt_shutdown(device_t dev) +{ + IAL_ADAPTER_T *pAdapter; + + pAdapter = device_get_softc(dev); + if (pAdapter == NULL) + return (EINVAL); + + EVENTHANDLER_DEREGISTER(shutdown_final, pAdapter->eh); + FlushAdapter(pAdapter); + /* give the flush some time to happen, + *otherwise "shutdown -p now" will make file system corrupted */ + DELAY(1000 * 1000 * 5); + return 0; +} + +void +Check_Idle_Call(IAL_ADAPTER_T *pAdapter) +{ + _VBUS_INST(&pAdapter->VBus) + + if (mWaitingForIdle(_VBUS_P0)) { + CheckIdleCall(_VBUS_P0); +#ifdef SUPPORT_ARRAY + { + int i; + PVDevice pArray; + for(i = 0; i < MAX_ARRAY_PER_VBUS; i++){ + if ((pArray=ArrayTables(i))->u.array.dArStamp==0) + continue; + else if (pArray->u.array.rf_auto_rebuild) { + KdPrint(("auto rebuild.\n")); + pArray->u.array.rf_auto_rebuild = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE); + } + } + } +#endif + } + /* launch the awaiting commands blocked by mWaitingForIdle */ + while(pAdapter->pending_Q!= NULL) + { + _VBUS_INST(&pAdapter->VBus) + union ccb *ccb = (union ccb *)pAdapter->pending_Q->ccb_h.ccb_ccb_ptr; + hpt_free_ccb(&pAdapter->pending_Q, ccb); + CallAfterReturn(_VBUS_P (DPC_PROC)OsSendCommand, ccb); + } +} + +static void +ccb_done(union ccb *ccb) +{ + PBUS_DMAMAP pmap = (PBUS_DMAMAP)ccb->ccb_adapter; + IAL_ADAPTER_T * pAdapter = pmap->pAdapter; + KdPrintI(("ccb_done: ccb %p status %x\n", ccb, ccb->ccb_h.status)); + + dmamap_put(pmap); + xpt_done(ccb); + + pAdapter->outstandingCommands--; + + if (pAdapter->outstandingCommands == 0) + { + if(DPC_Request_Nums == 0) + Check_Idle_Call(pAdapter); + } +} + +/**************************************************************** + * Name: hpt_action + * Description: Process a queued command from the CAM layer. + * Parameters: sim - Pointer to SIM object + * ccb - Pointer to SCSI command structure. + ****************************************************************/ + +void +hpt_action(struct cam_sim *sim, union ccb *ccb) +{ + intrmask_t oldspl; + IAL_ADAPTER_T * pAdapter = (IAL_ADAPTER_T *) cam_sim_softc(sim); + PBUS_DMAMAP pmap; + _VBUS_INST(&pAdapter->VBus) + + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("hpt_action\n")); + KdPrint(("hpt_action(%lx,%lx{%x})\n", (u_long)sim, (u_long)ccb, ccb->ccb_h.func_code)); + + switch (ccb->ccb_h.func_code) + { + case XPT_SCSI_IO: /* Execute the requested I/O operation */ + { + /* ccb->ccb_h.path_id is not our bus id - don't check it */ + + if (ccb->ccb_h.target_lun) { + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + return; + } + if (ccb->ccb_h.target_id >= MAX_VDEVICE_PER_VBUS || + pAdapter->VBus.pVDevice[ccb->ccb_h.target_id]==0) { + ccb->ccb_h.status = CAM_TID_INVALID; + xpt_done(ccb); + return; + } + + oldspl = lock_driver(); + if (pAdapter->outstandingCommands==0 && DPC_Request_Nums==0) + Check_Idle_Call(pAdapter); + + pmap = dmamap_get(pAdapter); + HPT_ASSERT(pmap); + ccb->ccb_adapter = pmap; + memset((void *)pmap->psg, 0, sizeof(pmap->psg)); + + if (mWaitingForIdle(_VBUS_P0)) + hpt_queue_ccb(&pAdapter->pending_Q, ccb); + else + OsSendCommand(_VBUS_P ccb); + unlock_driver(oldspl); + + /* KdPrint(("leave scsiio\n")); */ + break; + } + + case XPT_RESET_BUS: + KdPrint(("reset bus\n")); + oldspl = lock_driver(); + fResetVBus(_VBUS_P0); + unlock_driver(oldspl); + xpt_done(ccb); + break; + + case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ + case XPT_EN_LUN: /* Enable LUN as a target */ + case XPT_TARGET_IO: /* Execute target I/O request */ + case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ + case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ + case XPT_ABORT: /* Abort the specified CCB */ + case XPT_TERM_IO: /* Terminate the I/O process */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + + case XPT_GET_TRAN_SETTINGS: + case XPT_SET_TRAN_SETTINGS: + /* XXX Implement */ + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + xpt_done(ccb); + break; + + case XPT_CALC_GEOMETRY: + { + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + + ccg = &ccb->ccg; + size_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size); + + if (size_mb > 1024 ) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + + case XPT_PATH_INQ: /* Path routing inquiry */ + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; /* XXX??? */ + cpi->hba_inquiry = PI_SDTR_ABLE; + cpi->target_sprt = 0; + /* Not necessary to reset bus */ + cpi->hba_misc = PIM_NOBUSRESET; + cpi->hba_eng_cnt = 0; + + cpi->max_target = MAX_VDEVICE_PER_VBUS; + cpi->max_lun = 0; + cpi->initiator_id = MAX_VDEVICE_PER_VBUS; + + cpi->bus_id = cam_sim_bus(sim); + cpi->base_transfer_speed = 3300; + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "HPT ", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->transport = XPORT_SPI; + cpi->transport_version = 2; + cpi->protocol = PROTO_SCSI; + cpi->protocol_version = SCSI_REV_2; + cpi->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + + default: + KdPrint(("invalid cmd\n")); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + } + /* KdPrint(("leave hpt_action..............\n")); */ +} + +/* shall be called at lock_driver() */ +static void +hpt_queue_ccb(union ccb **ccb_Q, union ccb *ccb) +{ + if(*ccb_Q == NULL) + ccb->ccb_h.ccb_ccb_ptr = ccb; + else { + ccb->ccb_h.ccb_ccb_ptr = (*ccb_Q)->ccb_h.ccb_ccb_ptr; + (*ccb_Q)->ccb_h.ccb_ccb_ptr = (char *)ccb; + } + + *ccb_Q = ccb; +} + +/* shall be called at lock_driver() */ +static void +hpt_free_ccb(union ccb **ccb_Q, union ccb *ccb) +{ + union ccb *TempCCB; + + TempCCB = *ccb_Q; + + if(ccb->ccb_h.ccb_ccb_ptr == ccb) /*it means SCpnt is the last one in CURRCMDs*/ + *ccb_Q = NULL; + else { + while(TempCCB->ccb_h.ccb_ccb_ptr != (char *)ccb) + TempCCB = (union ccb *)TempCCB->ccb_h.ccb_ccb_ptr; + + TempCCB->ccb_h.ccb_ccb_ptr = ccb->ccb_h.ccb_ccb_ptr; + + if(*ccb_Q == ccb) + *ccb_Q = TempCCB; + } +} + +#ifdef SUPPORT_ARRAY +/*************************************************************************** + * Function: hpt_worker_thread + * Description: Do background rebuilding. Execute in kernel thread context. + * Returns: None + ***************************************************************************/ +static void hpt_worker_thread(void) +{ + intrmask_t oldspl; + + for(;;) { + while (DpcQueue_First!=DpcQueue_Last) { + ST_HPT_DPC p; + oldspl = lock_driver(); + p = DpcQueue[DpcQueue_First]; + DpcQueue_First++; + DpcQueue_First %= MAX_DPC; + DPC_Request_Nums++; + unlock_driver(oldspl); + p.dpc(p.pAdapter, p.arg, p.flags); + + oldspl = lock_driver(); + DPC_Request_Nums--; + /* since we may have prevented Check_Idle_Call, do it here */ + if (DPC_Request_Nums==0) { + if (p.pAdapter->outstandingCommands == 0) { + _VBUS_INST(&p.pAdapter->VBus); + Check_Idle_Call(p.pAdapter); + CheckPendingCall(_VBUS_P0); + } + } + unlock_driver(oldspl); + + /*Schedule out*/ + tsleep((caddr_t)hpt_worker_thread, 0, "sched", 1); + if (SIGISMEMBER(curproc->p_siglist, SIGSTOP)) { + /* abort rebuilding process. */ + IAL_ADAPTER_T *pAdapter; + PVDevice pArray; + PVBus _vbus_p; + int i; + pAdapter = gIal_Adapter; + + while(pAdapter != 0){ + + _vbus_p = &pAdapter->VBus; + + for (i=0;iu.array.dArStamp==0) + continue; + else if (pArray->u.array.rf_rebuilding || + pArray->u.array.rf_verifying || + pArray->u.array.rf_initializing) + { + pArray->u.array.rf_abort_rebuild = 1; + } + } + pAdapter = pAdapter->next; + } + } + } + +/*Remove this debug option*/ +/* +#ifdef DEBUG + if (SIGISMEMBER(curproc->p_siglist, SIGSTOP)) + tsleep((caddr_t)hpt_worker_thread, 0, "hptrdy", 2*hz); +#endif +*/ + kproc_suspend_loop(); + tsleep((caddr_t)hpt_worker_thread, 0, "hptrdy", 2*hz); /* wait for something to do */ + } +} + +static struct thread *hptdaemonproc; +static struct kproc_desc hpt_kp = { + "hpt_wt", + hpt_worker_thread, + &hptdaemonproc +}; + +/*Start this thread in the hpt_attach, to prevent kernel from loading it without our controller.*/ +static void +launch_worker_thread(void) +{ + IAL_ADAPTER_T *pAdapTemp; + + kproc_start(&hpt_kp); + + for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) { + + _VBUS_INST(&pAdapTemp->VBus) + int i; + PVDevice pVDev; + + for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) + if ((pVDev=ArrayTables(i))->u.array.dArStamp==0) + continue; + else{ + if (pVDev->u.array.rf_need_rebuild && !pVDev->u.array.rf_rebuilding) + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapTemp, pVDev, + (UCHAR)((pVDev->u.array.CriticalMembers || pVDev->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY)); + } + } + + /* + * hpt_worker_thread needs to be suspended after shutdown sync, when fs sync finished. + */ + EVENTHANDLER_REGISTER(shutdown_post_sync, shutdown_kproc, hptdaemonproc, SHUTDOWN_PRI_FIRST); +} +/* + *SYSINIT(hptwt, SI_SUB_KTHREAD_IDLE, SI_ORDER_FIRST, launch_worker_thread, NULL); +*/ + +#endif + +/********************************************************************************/ + +int HPTLIBAPI fOsBuildSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSg, int logical) +{ + union ccb *ccb = (union ccb *)pCmd->pOrgCommand; + bus_dma_segment_t *sgList = (bus_dma_segment_t *)ccb->csio.data_ptr; + int idx; + + if(logical) { + if (ccb->ccb_h.flags & CAM_DATA_PHYS) + panic("physical address unsupported"); + + if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { + if (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) + panic("physical address unsupported"); + + for (idx = 0; idx < ccb->csio.sglist_cnt; idx++) { + pSg[idx].dSgAddress = (ULONG_PTR)(UCHAR *)sgList[idx].ds_addr; + pSg[idx].wSgSize = sgList[idx].ds_len; + pSg[idx].wSgFlag = (idx==ccb->csio.sglist_cnt-1)? SG_FLAG_EOT : 0; + } + } + else { + pSg->dSgAddress = (ULONG_PTR)(UCHAR *)ccb->csio.data_ptr; + pSg->wSgSize = ccb->csio.dxfer_len; + pSg->wSgFlag = SG_FLAG_EOT; + } + return TRUE; + } + + /* since we have provided physical sg, nobody will ask us to build physical sg */ + HPT_ASSERT(0); + return FALSE; +} + +/*******************************************************************************/ +ULONG HPTLIBAPI +GetStamp(void) +{ + /* + * the system variable, ticks, can't be used since it hasn't yet been active + * when our driver starts (ticks==0, it's a invalid stamp value) + */ + ULONG stamp; + do { stamp = krandom(); } while (stamp==0); + return stamp; +} + + +static void +SetInquiryData(PINQUIRYDATA inquiryData, PVDevice pVDev) +{ + int i; + IDENTIFY_DATA2 *pIdentify = (IDENTIFY_DATA2*)pVDev->u.disk.mv->identifyDevice; + + inquiryData->DeviceType = T_DIRECT; /*DIRECT_ACCESS_DEVICE*/ + inquiryData->AdditionalLength = (UCHAR)(sizeof(INQUIRYDATA) - 5); +#ifndef SERIAL_CMDS + inquiryData->CommandQueue = 1; +#endif + + switch(pVDev->VDeviceType) { + case VD_SINGLE_DISK: + case VD_ATAPI: + case VD_REMOVABLE: + /* Set the removable bit, if applicable. */ + if ((pVDev->u.disk.df_removable_drive) || (pIdentify->GeneralConfiguration & 0x80)) + inquiryData->RemovableMedia = 1; + + /* Fill in vendor identification fields. */ + for (i = 0; i < 20; i += 2) { + inquiryData->VendorId[i] = ((PUCHAR)pIdentify->ModelNumber)[i + 1]; + inquiryData->VendorId[i+1] = ((PUCHAR)pIdentify->ModelNumber)[i]; + + } + + /* Initialize unused portion of product id. */ + for (i = 0; i < 4; i++) inquiryData->ProductId[12+i] = ' '; + + /* firmware revision */ + for (i = 0; i < 4; i += 2) + { + inquiryData->ProductRevisionLevel[i] = ((PUCHAR)pIdentify->FirmwareRevision)[i+1]; + inquiryData->ProductRevisionLevel[i+1] = ((PUCHAR)pIdentify->FirmwareRevision)[i]; + } + break; + default: + memcpy(&inquiryData->VendorId, "RR18xx ", 8); +#ifdef SUPPORT_ARRAY + switch(pVDev->VDeviceType){ + case VD_RAID_0: + if ((pVDev->u.array.pMember[0] && mIsArray(pVDev->u.array.pMember[0])) || + (pVDev->u.array.pMember[1] && mIsArray(pVDev->u.array.pMember[1]))) + memcpy(&inquiryData->ProductId, "RAID 1/0 Array ", 16); + else + memcpy(&inquiryData->ProductId, "RAID 0 Array ", 16); + break; + case VD_RAID_1: + if ((pVDev->u.array.pMember[0] && mIsArray(pVDev->u.array.pMember[0])) || + (pVDev->u.array.pMember[1] && mIsArray(pVDev->u.array.pMember[1]))) + memcpy(&inquiryData->ProductId, "RAID 0/1 Array ", 16); + else + memcpy(&inquiryData->ProductId, "RAID 1 Array ", 16); + break; + case VD_RAID_5: + memcpy(&inquiryData->ProductId, "RAID 5 Array ", 16); + break; + case VD_JBOD: + memcpy(&inquiryData->ProductId, "JBOD Array ", 16); + break; + } +#endif + memcpy(&inquiryData->ProductRevisionLevel, "3.00", 4); + break; + } +} + +static void +hpt_timeout(void *arg) +{ + _VBUS_INST(&((PBUS_DMAMAP)((union ccb *)arg)->ccb_adapter)->pAdapter->VBus) + intrmask_t oldspl = lock_driver(); + fResetVBus(_VBUS_P0); + unlock_driver(oldspl); +} + +static void +hpt_io_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + PCommand pCmd = (PCommand)arg; + union ccb *ccb = pCmd->pOrgCommand; + struct ccb_hdr *ccb_h = &ccb->ccb_h; + PBUS_DMAMAP pmap = (PBUS_DMAMAP) ccb->ccb_adapter; + IAL_ADAPTER_T *pAdapter = pmap->pAdapter; + PVDevice pVDev = pAdapter->VBus.pVDevice[ccb_h->target_id]; + FPSCAT_GATH psg = pCmd->pSgTable; + int idx; + _VBUS_INST(pVDev->pVBus) + + HPT_ASSERT(pCmd->cf_physical_sg); + + if (error || nsegs == 0) + panic("busdma error"); + + HPT_ASSERT(nsegs<= MAX_SG_DESCRIPTORS); + + for (idx = 0; idx < nsegs; idx++, psg++) { + psg->dSgAddress = (ULONG_PTR)(UCHAR *)segs[idx].ds_addr; + psg->wSgSize = segs[idx].ds_len; + psg->wSgFlag = (idx == nsegs-1)? SG_FLAG_EOT: 0; +/* KdPrint(("psg[%d]:add=%p,size=%x,flag=%x\n", idx, psg->dSgAddress,psg->wSgSize,psg->wSgFlag)); */ + } +/* psg[-1].wSgFlag = SG_FLAG_EOT; */ + + if (pCmd->cf_data_in) { + bus_dmamap_sync(pAdapter->io_dma_parent, pmap->dma_map, BUS_DMASYNC_PREREAD); + } + else if (pCmd->cf_data_out) { + bus_dmamap_sync(pAdapter->io_dma_parent, pmap->dma_map, BUS_DMASYNC_PREWRITE); + } + + callout_reset(&ccb->ccb_h.timeout_ch, 20*hz, hpt_timeout, ccb); + pVDev->pfnSendCommand(_VBUS_P pCmd); + CheckPendingCall(_VBUS_P0); +} + + + +static void HPTLIBAPI +OsSendCommand(_VBUS_ARG union ccb *ccb) +{ + PBUS_DMAMAP pmap = (PBUS_DMAMAP)ccb->ccb_adapter; + IAL_ADAPTER_T *pAdapter = pmap->pAdapter; + struct ccb_hdr *ccb_h = &ccb->ccb_h; + struct ccb_scsiio *csio = &ccb->csio; + PVDevice pVDev = pAdapter->VBus.pVDevice[ccb_h->target_id]; + + KdPrintI(("OsSendCommand: ccb %p cdb %x-%x-%x\n", + ccb, + *(ULONG *)&ccb->csio.cdb_io.cdb_bytes[0], + *(ULONG *)&ccb->csio.cdb_io.cdb_bytes[4], + *(ULONG *)&ccb->csio.cdb_io.cdb_bytes[8] + )); + + pAdapter->outstandingCommands++; + + if (pVDev == NULL || pVDev->vf_online == 0) { + ccb->ccb_h.status = CAM_REQ_INVALID; + ccb_done(ccb); + goto Command_Complished; + } + + switch(ccb->csio.cdb_io.cdb_bytes[0]) + { + case TEST_UNIT_READY: + case START_STOP_UNIT: + case SYNCHRONIZE_CACHE: + /* FALLTHROUGH */ + ccb->ccb_h.status = CAM_REQ_CMP; + break; + + case INQUIRY: + ZeroMemory(ccb->csio.data_ptr, ccb->csio.dxfer_len); + SetInquiryData((PINQUIRYDATA)ccb->csio.data_ptr, pVDev); + ccb_h->status = CAM_REQ_CMP; + break; + + case READ_CAPACITY: + { + UCHAR *rbuf=csio->data_ptr; + unsigned int cap; + + if (pVDev->VDeviceCapacity > 0xfffffffful) { + cap = 0xfffffffful; + } else { + cap = pVDev->VDeviceCapacity - 1; + } + + rbuf[0] = (UCHAR)(cap>>24); + rbuf[1] = (UCHAR)(cap>>16); + rbuf[2] = (UCHAR)(cap>>8); + rbuf[3] = (UCHAR)cap; + /* Claim 512 byte blocks (big-endian). */ + rbuf[4] = 0; + rbuf[5] = 0; + rbuf[6] = 2; + rbuf[7] = 0; + + ccb_h->status = CAM_REQ_CMP; + break; + } + + case 0x9e: /*SERVICE_ACTION_IN*/ + { + UCHAR *rbuf = csio->data_ptr; + LBA_T cap = pVDev->VDeviceCapacity - 1; + + rbuf[0] = (UCHAR)(cap>>56); + rbuf[1] = (UCHAR)(cap>>48); + rbuf[2] = (UCHAR)(cap>>40); + rbuf[3] = (UCHAR)(cap>>32); + rbuf[4] = (UCHAR)(cap>>24); + rbuf[5] = (UCHAR)(cap>>16); + rbuf[6] = (UCHAR)(cap>>8); + rbuf[7] = (UCHAR)cap; + rbuf[8] = 0; + rbuf[9] = 0; + rbuf[10] = 2; + rbuf[11] = 0; + + ccb_h->status = CAM_REQ_CMP; + break; + } + + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case 0x88: /* READ_16 */ + case 0x8a: /* WRITE_16 */ + case 0x13: + case 0x2f: + { + UCHAR Cdb[16]; + UCHAR CdbLength; + _VBUS_INST(pVDev->pVBus) + PCommand pCmd = AllocateCommand(_VBUS_P0); + HPT_ASSERT(pCmd); + + CdbLength = csio->cdb_len; + if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) + { + if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) + { + bcopy(csio->cdb_io.cdb_ptr, Cdb, CdbLength); + } + else + { + KdPrintE(("ERROR!!!\n")); + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + } + } + else + { + bcopy(csio->cdb_io.cdb_bytes, Cdb, CdbLength); + } + + pCmd->pOrgCommand = ccb; + pCmd->pVDevice = pVDev; + pCmd->pfnCompletion = fOsCommandDone; + pCmd->pfnBuildSgl = fOsBuildSgl; + pCmd->pSgTable = pmap->psg; + + switch (Cdb[0]) + { + case READ_6: + case WRITE_6: + case 0x13: + pCmd->uCmd.Ide.Lba = ((ULONG)Cdb[1] << 16) | ((ULONG)Cdb[2] << 8) | (ULONG)Cdb[3]; + pCmd->uCmd.Ide.nSectors = (USHORT) Cdb[4]; + break; + + case 0x88: /* READ_16 */ + case 0x8a: /* WRITE_16 */ + pCmd->uCmd.Ide.Lba = + (HPT_U64)Cdb[2] << 56 | + (HPT_U64)Cdb[3] << 48 | + (HPT_U64)Cdb[4] << 40 | + (HPT_U64)Cdb[5] << 32 | + (HPT_U64)Cdb[6] << 24 | + (HPT_U64)Cdb[7] << 16 | + (HPT_U64)Cdb[8] << 8 | + (HPT_U64)Cdb[9]; + pCmd->uCmd.Ide.nSectors = (USHORT)Cdb[12] << 8 | (USHORT)Cdb[13]; + break; + + default: + pCmd->uCmd.Ide.Lba = (ULONG)Cdb[5] | ((ULONG)Cdb[4] << 8) | ((ULONG)Cdb[3] << 16) | ((ULONG)Cdb[2] << 24); + pCmd->uCmd.Ide.nSectors = (USHORT) Cdb[8] | ((USHORT)Cdb[7]<<8); + break; + } + + switch (Cdb[0]) + { + case READ_6: + case READ_10: + case 0x88: /* READ_16 */ + pCmd->uCmd.Ide.Command = IDE_COMMAND_READ; + pCmd->cf_data_in = 1; + break; + + case WRITE_6: + case WRITE_10: + case 0x8a: /* WRITE_16 */ + pCmd->uCmd.Ide.Command = IDE_COMMAND_WRITE; + pCmd->cf_data_out = 1; + break; + case 0x13: + case 0x2f: + pCmd->uCmd.Ide.Command = IDE_COMMAND_VERIFY; + break; + } +/*///////////////////////// */ + if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { + int idx; + bus_dma_segment_t *sgList = (bus_dma_segment_t *)ccb->csio.data_ptr; + + if (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) + pCmd->cf_physical_sg = 1; + + for (idx = 0; idx < ccb->csio.sglist_cnt; idx++) { + pCmd->pSgTable[idx].dSgAddress = (ULONG_PTR)(UCHAR *)sgList[idx].ds_addr; + pCmd->pSgTable[idx].wSgSize = sgList[idx].ds_len; + pCmd->pSgTable[idx].wSgFlag= (idx==ccb->csio.sglist_cnt-1)?SG_FLAG_EOT: 0; + } + + callout_reset(&ccb->ccb_h.timeout_ch, 20*hz, hpt_timeout, ccb); + pVDev->pfnSendCommand(_VBUS_P pCmd); + } + else { + int error; + pCmd->cf_physical_sg = 1; + error = bus_dmamap_load(pAdapter->io_dma_parent, + pmap->dma_map, + ccb->csio.data_ptr, ccb->csio.dxfer_len, + hpt_io_dmamap_callback, pCmd, + BUS_DMA_WAITOK + ); + KdPrint(("bus_dmamap_load return %d\n", error)); + if (error && error!=EINPROGRESS) { + hpt_printk(("bus_dmamap_load error %d\n", error)); + FreeCommand(_VBUS_P pCmd); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + dmamap_put(pmap); + pAdapter->outstandingCommands--; + xpt_done(ccb); + } + } + goto Command_Complished; + } + + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + } + ccb_done(ccb); +Command_Complished: + CheckPendingCall(_VBUS_P0); + return; +} + +static void HPTLIBAPI +fOsCommandDone(_VBUS_ARG PCommand pCmd) +{ + union ccb *ccb = pCmd->pOrgCommand; + PBUS_DMAMAP pmap = (PBUS_DMAMAP)ccb->ccb_adapter; + IAL_ADAPTER_T *pAdapter = pmap->pAdapter; + + KdPrint(("fOsCommandDone(pcmd=%p, result=%d)\n", pCmd, pCmd->Result)); + + callout_stop(&ccb->ccb_h.timeout_ch); + + switch(pCmd->Result) { + case RETURN_SUCCESS: + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case RETURN_BAD_DEVICE: + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + break; + case RETURN_DEVICE_BUSY: + ccb->ccb_h.status = CAM_BUSY; + break; + case RETURN_INVALID_REQUEST: + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + case RETURN_SELECTION_TIMEOUT: + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + break; + case RETURN_RETRY: + ccb->ccb_h.status = CAM_BUSY; + break; + default: + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + break; + } + + if (pCmd->cf_data_in) { + bus_dmamap_sync(pAdapter->io_dma_parent, pmap->dma_map, BUS_DMASYNC_POSTREAD); + } + else if (pCmd->cf_data_in) { + bus_dmamap_sync(pAdapter->io_dma_parent, pmap->dma_map, BUS_DMASYNC_POSTWRITE); + } + + bus_dmamap_unload(pAdapter->io_dma_parent, pmap->dma_map); + + FreeCommand(_VBUS_P pCmd); + ccb_done(ccb); +} + +int +hpt_queue_dpc(HPT_DPC dpc, IAL_ADAPTER_T * pAdapter, void *arg, UCHAR flags) +{ + int p; + + p = (DpcQueue_Last + 1) % MAX_DPC; + if (p==DpcQueue_First) { + KdPrint(("DPC Queue full!\n")); + return -1; + } + + DpcQueue[DpcQueue_Last].dpc = dpc; + DpcQueue[DpcQueue_Last].pAdapter = pAdapter; + DpcQueue[DpcQueue_Last].arg = arg; + DpcQueue[DpcQueue_Last].flags = flags; + DpcQueue_Last = p; + + return 0; +} + +#ifdef _RAID5N_ +/* + * Allocate memory above 16M, otherwise we may eat all low memory for ISA devices. + * How about the memory for 5081 request/response array and PRD table? + */ +void +*os_alloc_page(_VBUS_ARG0) +{ + return (void *)contigmalloc(0x1000, M_DEVBUF, M_NOWAIT, 0x1000000, 0xffffffff, PAGE_SIZE, 0ul); +} + +void +*os_alloc_dma_page(_VBUS_ARG0) +{ + return (void *)contigmalloc(0x1000, M_DEVBUF, M_NOWAIT, 0x1000000, 0xffffffff, PAGE_SIZE, 0ul); +} + +void +os_free_page(_VBUS_ARG void *p) +{ + contigfree(p, 0x1000, M_DEVBUF); +} + +void +os_free_dma_page(_VBUS_ARG void *p) +{ + contigfree(p, 0x1000, M_DEVBUF); +} + +void +DoXor1(ULONG *p0, ULONG *p1, ULONG *p2, UINT nBytes) +{ + UINT i; + for (i = 0; i < nBytes / 4; i++) *p0++ = *p1++ ^ *p2++; +} + +void +DoXor2(ULONG *p0, ULONG *p2, UINT nBytes) +{ + UINT i; + for (i = 0; i < nBytes / 4; i++) *p0++ ^= *p2++; +} +#endif diff --git a/sys/dev/raid/hptmv/global.h b/sys/dev/raid/hptmv/global.h new file mode 100644 index 0000000000..5f4635ad38 --- /dev/null +++ b/sys/dev/raid/hptmv/global.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/global.h,v 1.5 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ + +#include +#include +#include + +#define COMPANY "HighPoint Technologies, Inc." +#define COPYRIGHT "(c) 2000-2007. HighPoint Technologies, Inc." +#define DRIVER_NAME "RocketRAID 18xx SATA Controller driver" +#define CONTROLLER_NAME "RocketRAID 18xx SATA Controller" +#define PROC_DIR_NAME hptmv + +#define HPT_INTERFACE_VERSION 0x01010000 +#define SUPPORT_48BIT_LBA +#define SUPPORT_ARRAY +#define SUPPORT_RAID5 1 +#define _RAID5N_ +#define MAX_QUEUE_COMM 32 +#define MAX_SG_DESCRIPTORS 17 +#define MAX_VBUS 2 /*one vbus per adapter in mv linux driver, + MAX_VBUS is defined for share code and can not be 1*/ + +#define SET_VBUS_FOR_EACH_CONTROLLER +#define MAX_MEMBERS 8 +#define MAX_ARRAY_NAME 16 +#define MAX_VDEVICE_PER_VBUS 8 +#define MAX_ARRAY_DEVICE MAX_ARRAY_PER_VBUS +#define MAX_CHIP_IN_VBUS 1 + +#define SUPPORT_IOCTL +#define SUPPORT_FAIL_LED + +typedef void * PChipInstance; +typedef void * PChannel; +typedef struct _VDevice *PVDevice; +typedef struct _VBus *PVBus; +typedef struct _ArrayDescript *PArrayDescript; +typedef struct _ArrayDescriptV2 *PArrayDescriptV2; +typedef struct _Command *PCommand; + +typedef struct _Device { + UCHAR df_on_line; + UCHAR df_atapi; + UCHAR df_removable_drive; + UCHAR busyCount; + + UCHAR df_tcq_set: 1; + UCHAR df_tcq: 1; /* enable TCQ */ + UCHAR df_ncq_set: 1; + UCHAR df_ncq: 1; /* enable NCQ */ + UCHAR df_write_cache_set: 1; + UCHAR df_write_cache: 1; /* enable write cache */ + UCHAR df_read_ahead_set: 1; + UCHAR df_read_ahead: 1; /* enable read ahead */ + + UCHAR retryCount; + UCHAR resetCount; + UCHAR pad1; + + UCHAR df_user_mode_set; + UCHAR bDeModeSetting; /* Current Data Transfer mode: 0-4 PIO 0-4 */ + UCHAR bDeUsable_Mode; /* actual maximum data transfer mode */ + UCHAR bDeUserSelectMode; + + PVBus pVBus; + ULONG dDeRealCapacity; + ULONG dDeHiddenLba; + ULONG HeadPosition; + ULONG QueueLength; + MV_SATA_CHANNEL *mv; +} +Device, *PDevice; + +typedef struct _SCAT_GATH +{ + ULONG_PTR dSgAddress; + USHORT wSgSize; + USHORT wSgFlag; +} SCAT_GATH, FAR *FPSCAT_GATH; + +#define OS_VDEV_EXT +typedef struct _VDevice_Ext +{ + UCHAR gui_locked; /* the device is locked by GUI */ + UCHAR reserve[3]; +} VDevice_Ext, *PVDevice_Ext; + + +#define SG_FLAG_SKIP 0x4000 +#define SG_FLAG_EOT 0x8000 + +#define _VBUS_ARG0 PVBus _vbus_p +#define _VBUS_ARG PVBus _vbus_p, +#define _VBUS_P _vbus_p, +#define _VBUS_P0 _vbus_p +#define _VBUS_INST(x) PVBus _vbus_p = x; +#define _vbus_(x) (_vbus_p->x) + +/************************************************************************* + * arithmetic functions + *************************************************************************/ +#define LongRShift(x, y) (x >> y) +#define LongLShift(x, y) (x << y) +#define LongDiv(x, y) (x / (UINT)(y)) +#define LongRem(x, y) (x % (UINT)(y)) +#define LongMul(x, y) (x * y) + +/************************************************************************* + * C library + *************************************************************************/ +int HPTLIBAPI os_memcmp(const void *cs, const void *ct, unsigned len); +void HPTLIBAPI os_memcpy(void *to, const void *from, unsigned len); +void HPTLIBAPI os_memset(void *s, char c, unsigned len); +unsigned HPTLIBAPI os_strlen(const char *s); + +#define ZeroMemory(a, b) memset((char *)a, 0, b) +#define MemoryCopy(a,b,c) memcpy((char *)(a), (char *)(b), (UINT)(c)) +#define farMemoryCopy(a,b,c) memcpy((char *)(a), (char *)(b), (UINT)c) +#define StrLen strlen + +/* + * we don't want whole hptintf.h in shared code... + * some constants must match that in hptintf.h! + */ +enum _driver_events_t +{ + ET_DEVICE=0, + ET_DEVICE_REMOVED, + ET_DEVICE_PLUGGED, + ET_DEVICE_ERROR, + ET_REBUILD_STARTED, + ET_REBUILD_ABORTED, + ET_REBUILD_FINISHED, + ET_SPARE_TOOK_OVER, + ET_REBUILD_FAILED, + ET_VERIFY_STARTED, + ET_VERIFY_ABORTED, + ET_VERIFY_FAILED, + ET_VERIFY_FINISHED, + ET_INITIALIZE_STARTED, + ET_INITIALIZE_ABORTED, + ET_INITIALIZE_FAILED, + ET_INITIALIZE_FINISHED, + ET_VERIFY_DATA_ERROR, +}; + +#define StallExec(x) mvMicroSecondsDelay(x) +extern void HPTLIBAPI ioctl_ReportEvent(UCHAR event, PVOID param); +#define fNotifyGUI(WhatHappen, pVDevice) ioctl_ReportEvent(WhatHappen, pVDevice) +#define DECLARE_BUFFER(type, ptr) UCHAR ptr##__buf[512]; type ptr=(type)ptr##__buf + +int HPTLIBAPI fDeReadWrite(PDevice pDev, ULONG Lba, UCHAR Cmd, void *tmpBuffer); +void HPTLIBAPI fDeSelectMode(PDevice pDev, UCHAR NewMode); +int HPTLIBAPI fDeSetTCQ(PDevice pDev, int enable, int depth); +int HPTLIBAPI fDeSetNCQ(PDevice pDev, int enable, int depth); +int HPTLIBAPI fDeSetWriteCache(PDevice pDev, int enable); +int HPTLIBAPI fDeSetReadAhead(PDevice pDev, int enable); + +#include +#include +#include +#include +#include + +#if defined(__FreeBSD__) && defined(HPTLIBAPI) +#undef HPTLIBAPI +#define HPTLIBAPI +#endif + +#ifdef SUPPORT_ARRAY +#define ArrayTables(i) ((PVDevice)&_vbus_(_ArrayTables)[i*ARRAY_VDEV_SIZE]) +#endif + +#endif diff --git a/sys/dev/raid/hptmv/gui_lib.c b/sys/dev/raid/hptmv/gui_lib.c new file mode 100644 index 0000000000..3a786295b6 --- /dev/null +++ b/sys/dev/raid/hptmv/gui_lib.c @@ -0,0 +1,1447 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/gui_lib.c,v 1.6 2009/04/07 16:38:25 delphij Exp $ + */ +/* + * gui_lib.c + * Copyright (c) 2002-2004 HighPoint Technologies, Inc. All rights reserved. + * + * Platform independent ioctl interface implementation. + * The platform dependent part may reuse this function and/or use it own + * implementation for each ioctl function. + * + * This implementation doesn't use any synchronization; the caller must + * assure the proper context when calling these functions. + */ + +#include +#include +#include +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include + +static int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap); +static int hpt_get_controller_count(void); +static int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo); +static int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo); +static int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount); +static int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo); +static int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo); +static DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam); +static DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam); +static int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk); +static int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk); +static int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo); +static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo); +static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo); + +int +check_VDevice_valid(PVDevice p) +{ + int i; + PVDevice pVDevice; + PVBus _vbus_p; + IAL_ADAPTER_T *pAdapter = gIal_Adapter; + + while(pAdapter != 0) + { + for (i = 0; i < MV_SATA_CHANNELS_NUM; i++) + if(&(pAdapter->VDevices[i]) == p) return 0; + pAdapter = pAdapter->next; + } + +#ifdef SUPPORT_ARRAY + pAdapter = gIal_Adapter; + while(pAdapter != 0) + { + _vbus_p = &pAdapter->VBus; + for (i=0;iu.array.dArStamp != 0) && (pVDevice == p)) + return 0; + } + pAdapter = pAdapter->next; + } +#endif + + return -1; +} + +#ifdef SUPPORT_ARRAY + +static UCHAR get_vdev_type(PVDevice pVDevice) + { + switch (pVDevice->VDeviceType) { + case VD_RAID_0: return AT_RAID0; + case VD_RAID_1: return AT_RAID1; + case VD_JBOD: return AT_JBOD; + case VD_RAID_5: return AT_RAID5; + default: return AT_UNKNOWN; + } + } + +static DWORD get_array_flag(PVDevice pVDevice) +{ + int i; + DWORD f = 0; + + /* The array is disabled */ + if(!pVDevice->vf_online) { + f |= ARRAY_FLAG_DISABLED; + /* Ignore other info */ + return f; + } + + /* array need synchronizing */ + if(pVDevice->u.array.rf_need_rebuild && !pVDevice->u.array.rf_duplicate_and_create) + f |= ARRAY_FLAG_NEEDBUILDING; + + /* array is in rebuilding process */ + if(pVDevice->u.array.rf_rebuilding) + f |= ARRAY_FLAG_REBUILDING; + + /* array is being verified */ + if(pVDevice->u.array.rf_verifying) + f |= ARRAY_FLAG_VERIFYING; + + /* array is being initialized */ + if(pVDevice->u.array.rf_initializing) + f |= ARRAY_FLAG_INITIALIZING; + + /* broken but may still working */ + if(pVDevice->u.array.rf_broken) + f |= ARRAY_FLAG_BROKEN; + + /* array has a active partition */ + if(pVDevice->vf_bootable) + f |= ARRAY_FLAG_BOOTDISK; + + /* a newly created array */ + if(pVDevice->u.array.rf_newly_created) + f |= ARRAY_FLAG_NEWLY_CREATED; + + /* array has boot mark set */ + if(pVDevice->vf_bootmark) + f |= ARRAY_FLAG_BOOTMARK; + + /* auto-rebuild should start */ + if(pVDevice->u.array.rf_auto_rebuild) + f |= ARRAY_FLAG_NEED_AUTOREBUILD; + + for(i = 0; i < pVDevice->u.array.bArnMember; i++) + { + PVDevice pMember = pVDevice->u.array.pMember[i]; + if (!pMember || !pMember->vf_online || (pMember->VDeviceType==VD_SINGLE_DISK)) + continue; + + /* array need synchronizing */ + if(pMember->u.array.rf_need_rebuild && + !pMember->u.array.rf_duplicate_and_create) + f |= ARRAY_FLAG_NEEDBUILDING; + + /* array is in rebuilding process */ + if(pMember->u.array.rf_rebuilding) + f |= ARRAY_FLAG_REBUILDING; + + /* array is being verified */ + if(pMember->u.array.rf_verifying) + f |= ARRAY_FLAG_VERIFYING; + + /* array is being initialized */ + if(pMember->u.array.rf_initializing) + f |= ARRAY_FLAG_INITIALIZING; + + /* broken but may still working */ + if(pMember->u.array.rf_broken) + f |= ARRAY_FLAG_BROKEN; + + /* a newly created array */ + if(pMember->u.array.rf_newly_created) + f |= ARRAY_FLAG_NEWLY_CREATED; + + /* auto-rebuild should start */ + if(pMember->u.array.rf_auto_rebuild) + f |= ARRAY_FLAG_NEED_AUTOREBUILD; + } + + return f; +} + +static DWORD calc_rebuild_progress(PVDevice pVDevice) +{ + int i; + DWORD result = ((ULONG)(pVDevice->u.array.RebuildSectors>>11)*1000 / + (ULONG)(pVDevice->VDeviceCapacity>>11) * (pVDevice->u.array.bArnMember-1)) * 10; + + for(i = 0; i < pVDevice->u.array.bArnMember; i++) + { + PVDevice pMember = pVDevice->u.array.pMember[i]; + if (!pMember || !pMember->vf_online || (pMember->VDeviceType==VD_SINGLE_DISK)) + continue; + + /* for RAID1/0 case */ + if (pMember->u.array.rf_rebuilding || + pMember->u.array.rf_verifying || + pMember->u.array.rf_initializing) + { + DWORD percent = ((ULONG)(pMember->u.array.RebuildSectors>>11)*1000 / + (ULONG)(pMember->VDeviceCapacity>>11) * (pMember->u.array.bArnMember-1)) * 10; + if (result==0 || result>percent) + result = percent; + } + } + + if (result>10000) result = 10000; + return result; + } + +static void get_array_info(PVDevice pVDevice, PHPT_ARRAY_INFO pArrayInfo) +{ + int i; + + memcpy(pArrayInfo->Name, pVDevice->u.array.ArrayName, MAX_ARRAY_NAME); + pArrayInfo->ArrayType = get_vdev_type(pVDevice); + pArrayInfo->BlockSizeShift = pVDevice->u.array.bArBlockSizeShift; + pArrayInfo->RebuiltSectors = pVDevice->u.array.RebuildSectors; + pArrayInfo->Flags = get_array_flag(pVDevice); + pArrayInfo->RebuildingProgress = calc_rebuild_progress(pVDevice); + + pArrayInfo->nDisk = 0; + + for(i = 0; i < pVDevice->u.array.bArnMember; i++) + if(pVDevice->u.array.pMember[i] != NULL) + pArrayInfo->Members[pArrayInfo->nDisk++] = VDEV_TO_ID(pVDevice->u.array.pMember[i]); + + for(i=pArrayInfo->nDisk; iMembers[i] = INVALID_DEVICEID; + } + +static void get_array_info_v2(PVDevice pVDevice, PHPT_ARRAY_INFO_V2 pArrayInfo) +{ + int i; + + memcpy(pArrayInfo->Name, pVDevice->u.array.ArrayName, MAX_ARRAYNAME_LEN); + pArrayInfo->ArrayType = get_vdev_type(pVDevice); + pArrayInfo->BlockSizeShift = pVDevice->u.array.bArBlockSizeShift; + pArrayInfo->RebuiltSectors.lo32 = pVDevice->u.array.RebuildSectors; + pArrayInfo->RebuiltSectors.hi32 = sizeof(LBA_T)>4? (pVDevice->u.array.RebuildSectors>>32) : 0; + pArrayInfo->Flags = get_array_flag(pVDevice); + pArrayInfo->RebuildingProgress = calc_rebuild_progress(pVDevice); + + pArrayInfo->nDisk = 0; + + for(i = 0; i < pVDevice->u.array.bArnMember; i++) + if(pVDevice->u.array.pMember[i] != NULL) + pArrayInfo->Members[pArrayInfo->nDisk++] = VDEV_TO_ID(pVDevice->u.array.pMember[i]); + + for(i=pArrayInfo->nDisk; iMembers[i] = INVALID_DEVICEID; +} +#endif + +static int get_disk_info(PVDevice pVDevice, PDEVICE_INFO pDiskInfo) +{ + MV_SATA_ADAPTER *pSataAdapter; + MV_SATA_CHANNEL *pSataChannel; + IAL_ADAPTER_T *pAdapter; + MV_CHANNEL *channelInfo; + char *p; + int i; + + /* device location */ + pSataChannel = pVDevice->u.disk.mv; + if(pSataChannel == NULL) return -1; + pDiskInfo->TargetId = 0; + pSataAdapter = pSataChannel->mvSataAdapter; + if(pSataAdapter == NULL) return -1; + + pAdapter = pSataAdapter->IALData; + + pDiskInfo->PathId = pSataChannel->channelNumber; + pDiskInfo->ControllerId = (UCHAR)pSataAdapter->adapterId; + +/*GUI uses DeviceModeSetting to display to users +(1) if users select a mode, GUI/BIOS should display that mode. +(2) if SATA/150, GUI/BIOS should display 150 if case (1) isn't satisfied. +(3) display real mode if case (1)&&(2) not satisfied. +*/ + if (pVDevice->u.disk.df_user_mode_set) + pDiskInfo->DeviceModeSetting = pVDevice->u.disk.bDeUserSelectMode; + else if (((((PIDENTIFY_DATA)pVDevice->u.disk.mv->identifyDevice)->SataCapability) & 3)==2) + pDiskInfo->DeviceModeSetting = 15; + else { + p = (char *)&((PIDENTIFY_DATA)pVDevice->u.disk.mv->identifyDevice)->ModelNumber; + if (*(WORD*)p==(0x5354) /*'ST'*/ && + (*(WORD*)(p+8)==(0x4153)/*'AS'*/ || (p[8]=='A' && p[11]=='S'))) + pDiskInfo->DeviceModeSetting = 15; + else + pDiskInfo->DeviceModeSetting = pVDevice->u.disk.bDeModeSetting; + } + + pDiskInfo->UsableMode = pVDevice->u.disk.bDeUsable_Mode; + + pDiskInfo->DeviceType = PDT_HARDDISK; + + pDiskInfo->Flags = 0x0; + + /* device is disabled */ + if(!pVDevice->u.disk.df_on_line) + pDiskInfo->Flags |= DEVICE_FLAG_DISABLED; + + /* disk has a active partition */ + if(pVDevice->vf_bootable) + pDiskInfo->Flags |= DEVICE_FLAG_BOOTDISK; + + /* disk has boot mark set */ + if(pVDevice->vf_bootmark) + pDiskInfo->Flags |= DEVICE_FLAG_BOOTMARK; + + pDiskInfo->Flags |= DEVICE_FLAG_SATA; + + /* is a spare disk */ + if(pVDevice->VDeviceType == VD_SPARE) + pDiskInfo->Flags |= DEVICE_FLAG_IS_SPARE; + + memcpy(&(pDiskInfo->IdentifyData), (pSataChannel->identifyDevice), sizeof(IDENTIFY_DATA2)); + p = (char *)&pDiskInfo->IdentifyData.ModelNumber; + for (i = 0; i < 20; i++) + ((WORD*)p)[i] = shortswap(pSataChannel->identifyDevice[IDEN_MODEL_OFFSET+i]); + p[39] = '\0'; + + channelInfo = &pAdapter->mvChannel[pSataChannel->channelNumber]; + pDiskInfo->ReadAheadSupported = channelInfo->readAheadSupported; + pDiskInfo->ReadAheadEnabled = channelInfo->readAheadEnabled; + pDiskInfo->WriteCacheSupported = channelInfo->writeCacheSupported; + pDiskInfo->WriteCacheEnabled = channelInfo->writeCacheEnabled; + pDiskInfo->TCQSupported = (pSataChannel->identifyDevice[IDEN_SUPPORTED_COMMANDS2] & (0x2))!=0; + pDiskInfo->TCQEnabled = pSataChannel->queuedDMA==MV_EDMA_MODE_QUEUED; + pDiskInfo->NCQSupported = MV_SATA_GEN_2(pSataAdapter) && + (pSataChannel->identifyDevice[IDEN_SATA_CAPABILITIES] & (0x0100)); + pDiskInfo->NCQEnabled = pSataChannel->queuedDMA==MV_EDMA_MODE_NATIVE_QUEUING; + return 0; +} + +int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap) +{ + ZeroMemory(cap, sizeof(DRIVER_CAPABILITIES)); + cap->dwSize = sizeof(DRIVER_CAPABILITIES); + cap->MaximumControllers = MAX_VBUS; + + /* cap->SupportCrossControllerRAID = 0; */ + /* take care for various OSes! */ + cap->SupportCrossControllerRAID = 0; + + + cap->MinimumBlockSizeShift = MinBlockSizeShift; + cap->MaximumBlockSizeShift = MaxBlockSizeShift; + cap->SupportDiskModeSetting = 0; + cap->SupportSparePool = 1; + cap->MaximumArrayNameLength = MAX_ARRAY_NAME - 1; + cap->SupportDedicatedSpare = 0; + + +#ifdef SUPPORT_ARRAY + /* Stripe */ + cap->SupportedRAIDTypes[0] = AT_RAID0; + cap->MaximumArrayMembers[0] = MAX_MEMBERS; + /* Mirror */ + cap->SupportedRAIDTypes[1] = AT_RAID1; + cap->MaximumArrayMembers[1] = 2; + /* Mirror + Stripe */ +#ifdef ARRAY_V2_ONLY + cap->SupportedRAIDTypes[2] = (AT_RAID1<<4)|AT_RAID0; /* RAID0/1 */ +#else + cap->SupportedRAIDTypes[2] = (AT_RAID0<<4)|AT_RAID1; /* RAID1/0 */ +#endif + cap->MaximumArrayMembers[2] = MAX_MEMBERS; + /* Jbod */ + cap->SupportedRAIDTypes[3] = AT_JBOD; + cap->MaximumArrayMembers[3] = MAX_MEMBERS; + /* RAID5 */ +#if SUPPORT_RAID5 + cap->SupportedRAIDTypes[4] = AT_RAID5; + cap->MaximumArrayMembers[4] = MAX_MEMBERS; +#endif +#endif + return 0; +} + +int hpt_get_controller_count(void) +{ + IAL_ADAPTER_T *pAdapTemp = gIal_Adapter; + int iControllerCount = 0; + + while(pAdapTemp != 0) + { + iControllerCount++; + pAdapTemp = pAdapTemp->next; + } + + return iControllerCount; +} + +int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo) +{ + IAL_ADAPTER_T *pAdapTemp; + int iControllerCount = 0; + + for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) { + if (iControllerCount++==id) { + pInfo->InterruptLevel = 0; + pInfo->ChipType = 0; + pInfo->ChipFlags = CHIP_SUPPORT_ULTRA_100; + strcpy( pInfo->szVendorID, "HighPoint Technologies, Inc."); +#ifdef GUI_CONTROLLER_NAME +#ifdef FORCE_ATA150_DISPLAY + /* show "Bus Type: ATA/150" in GUI for SATA controllers */ + pInfo->ChipFlags = CHIP_SUPPORT_ULTRA_150; +#endif + strcpy(pInfo->szProductID, GUI_CONTROLLER_NAME); +#define _set_product_id(x) +#else +#define _set_product_id(x) strcpy(pInfo->szProductID, x) +#endif + _set_product_id("RocketRAID 18xx SATA Controller"); + pInfo->NumBuses = 8; + pInfo->ChipFlags |= CHIP_SUPPORT_ULTRA_133|CHIP_SUPPORT_ULTRA_150; + return 0; + } + } + return -1; +} + + +int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo) +{ + IAL_ADAPTER_T *pAdapTemp = gIal_Adapter; + int i,iControllerCount = 0; + + while(pAdapTemp != 0) + { + if (iControllerCount++==id) + goto found; + pAdapTemp = pAdapTemp->next; + } + return -1; + +found: + + pInfo->IoPort = 0; + pInfo->ControlPort = 0; + + for (i=0; i<2 ;i++) + { + pInfo->Devices[i] = (DEVICEID)INVALID_DEVICEID; + } + + if (pAdapTemp->mvChannel[bus].online == MV_TRUE) + pInfo->Devices[0] = VDEV_TO_ID(&pAdapTemp->VDevices[bus]); + else + pInfo->Devices[0] = (DEVICEID)INVALID_DEVICEID; + + return 0; + + +} + +int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount) +{ + int count = 0; + int i,j; + PVDevice pPhysical, pLogical; + IAL_ADAPTER_T *pAdapTemp; + + for(i = 0; i < nMaxCount; i++) + pIds[i] = INVALID_DEVICEID; + + /* append the arrays not registered on VBus */ + for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) { + for(i = 0; i < MV_SATA_CHANNELS_NUM; i++) + { + pPhysical = &pAdapTemp->VDevices[i]; + pLogical = pPhysical; + + while (pLogical->pParent) pLogical = pLogical->pParent; + if (pLogical->VDeviceType==VD_SPARE) + continue; + + for (j=0; j=nMaxCount) goto done; + next:; + } + } + +done: + return count; +} + +int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo) +{ + PVDevice pVDevice = ID_TO_VDEV(id); + + if((id == 0) || check_VDevice_valid(pVDevice)) + return -1; + +#ifdef SUPPORT_ARRAY + if (mIsArray(pVDevice)) { + pInfo->Type = LDT_ARRAY; + pInfo->Capacity = pVDevice->VDeviceCapacity; + pInfo->ParentArray = VDEV_TO_ID(pVDevice->pParent); + get_array_info(pVDevice, &pInfo->u.array); + return 0; + } +#endif + + pInfo->Type = LDT_DEVICE; + pInfo->ParentArray = pVDevice->pParent? VDEV_TO_ID(pVDevice->pParent) : INVALID_DEVICEID; + /* report real capacity to be compatible with old arrays */ + pInfo->Capacity = pVDevice->u.disk.dDeRealCapacity; + return get_disk_info(pVDevice, &pInfo->u.device); +} + +int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo) +{ + PVDevice pVDevice = ID_TO_VDEV(id); + + if((id == 0) || check_VDevice_valid(pVDevice)) + return -1; + +#ifdef SUPPORT_ARRAY + if (mIsArray(pVDevice)) { + pInfo->Type = LDT_ARRAY; + pInfo->Capacity.lo32 = pVDevice->VDeviceCapacity; + pInfo->Capacity.hi32 = sizeof(LBA_T)>4? (pVDevice->VDeviceCapacity>>32) : 0; + pInfo->ParentArray = VDEV_TO_ID(pVDevice->pParent); + get_array_info_v2(pVDevice, &pInfo->u.array); + return 0; +} +#endif + + pInfo->Type = LDT_DEVICE; + pInfo->ParentArray = pVDevice->pParent? VDEV_TO_ID(pVDevice->pParent) : INVALID_DEVICEID; + /* report real capacity to be compatible with old arrays */ + pInfo->Capacity.lo32 = pVDevice->u.disk.dDeRealCapacity; + pInfo->Capacity.hi32 = 0; + return get_disk_info(pVDevice, &pInfo->u.device); +} + +#ifdef SUPPORT_ARRAY +DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam) +{ + ULONG Stamp = GetStamp(); + int i,j; + LBA_T capacity = MAX_LBA_T; + PVDevice pArray,pChild; + int Loca = -1; + + if (pParam->nDisk > MAX_MEMBERS) + return INVALID_DEVICEID; +/* check in verify_vd + for(i = 0; i < pParam->nDisk; i++) + { + PVDevice pVDev = ID_TO_VDEV(pParam->Members[i]); + if (check_VDevice_valid(pVDev)) return INVALID_DEVICEID; + if (mIsArray(pVDev)) return INVALID_DEVICEID; + if (!pVDev->vf_online) return INVALID_DEVICEID; + if (!_vbus_p) + _vbus_p = pVDev->u.disk.pVBus; + else if (_vbus_p != pVDev->u.disk.pVBus) + return INVALID_DEVICEID; + } +*/ + _vbus_p = (ID_TO_VDEV(pParam->Members[0]))->u.disk.pVBus; + if (!_vbus_p) return INVALID_DEVICEID; + + mArGetArrayTable(pArray); + if(!pArray) return INVALID_DEVICEID; + + switch (pParam->ArrayType) + { + case AT_JBOD: + pArray->VDeviceType = VD_JBOD; + goto simple; + + case AT_RAID0: + if((pParam->BlockSizeShift < MinBlockSizeShift) || (pParam->BlockSizeShift > MaxBlockSizeShift)) + goto error; + pArray->VDeviceType = VD_RAID_0; + goto simple; + + case AT_RAID5: + if((pParam->BlockSizeShift < MinBlockSizeShift) || (pParam->BlockSizeShift > MaxBlockSizeShift)) + goto error; + pArray->VDeviceType = VD_RAID_5; + /* only "no build" R5 is not critical after creation. */ + if ((pParam->CreateFlags & CAF_CREATE_R5_NO_BUILD)==0) + pArray->u.array.rf_need_rebuild = 1; + goto simple; + + case AT_RAID1: + if(pParam->nDisk <= 2) + { + pArray->VDeviceType = VD_RAID_1; +simple: + pArray->u.array.bArnMember = pParam->nDisk; + pArray->u.array.bArRealnMember = pParam->nDisk; + pArray->u.array.bArBlockSizeShift = pParam->BlockSizeShift; + pArray->u.array.bStripeWitch = (1 << pParam->BlockSizeShift); + pArray->u.array.dArStamp = Stamp; + + pArray->u.array.rf_need_sync = 1; + pArray->u.array.rf_newly_created = 1; + + if ((pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE) && + (pArray->VDeviceType == VD_RAID_1)) + { + pArray->u.array.rf_newly_created = 0; /* R1 shall still be accessible */ + pArray->u.array.rf_need_rebuild = 1; + pArray->u.array.rf_auto_rebuild = 1; + pArray->u.array.rf_duplicate_and_create = 1; + + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) + if (_vbus_p->pVDevice[i] == ID_TO_VDEV(pParam->Members[0])) + Loca = i; + } + + pArray->u.array.RebuildSectors = pArray->u.array.rf_need_rebuild? 0 : MAX_LBA_T; + + memcpy(pArray->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME); + + for(i = 0; i < pParam->nDisk; i++) + { + pArray->u.array.pMember[i] = ID_TO_VDEV(pParam->Members[i]); + pArray->u.array.pMember[i]->bSerialNumber = i; + pArray->u.array.pMember[i]->pParent = pArray; + + /* don't unregister source disk for duplicate RAID1 */ + if (i || + pArray->VDeviceType!=VD_RAID_1 || + (pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE)==0) + UnregisterVDevice(pArray->u.array.pMember[i]); + + if(pArray->VDeviceType == VD_RAID_5) + pArray->u.array.pMember[i]->vf_cache_disk = 1; + } + } + else + { + for(i = 0; i < (pParam->nDisk / 2); i++) + { + mArGetArrayTable(pChild); + pChild->VDeviceType = VD_RAID_1; + + pChild->u.array.bArnMember = 2; + pChild->u.array.bArRealnMember = 2; + pChild->u.array.bArBlockSizeShift = pParam->BlockSizeShift; + pChild->u.array.bStripeWitch = (1 << pParam->BlockSizeShift); + pChild->u.array.dArStamp = Stamp; + + pChild->u.array.rf_need_sync = 1; + pChild->u.array.rf_newly_created = 1; + + pChild->u.array.RebuildSectors = MAX_LBA_T; + + memcpy(pChild->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME); + + for(j = 0; j < 2; j++) + { + pChild->u.array.pMember[j] = ID_TO_VDEV(pParam->Members[i*2 + j]); + pChild->u.array.pMember[j]->bSerialNumber = j; + pChild->u.array.pMember[j]->pParent = pChild; + pChild->u.array.pMember[j]->pfnDeviceFailed = pfnDeviceFailed[pChild->VDeviceType]; + UnregisterVDevice(pChild->u.array.pMember[j]); + } + + pArray->u.array.pMember[i] = pChild; + + pChild->vf_online = 1; + pChild->bSerialNumber = i; + pChild->pParent = pArray; + pChild->VDeviceCapacity = MIN(pChild->u.array.pMember[0]->VDeviceCapacity, + pChild->u.array.pMember[1]->VDeviceCapacity); + + pChild->pfnSendCommand = pfnSendCommand[pChild->VDeviceType]; + pChild->pfnDeviceFailed = pfnDeviceFailed[VD_RAID_0]; + } + + pArray->VDeviceType = VD_RAID_0; + + pArray->u.array.bArnMember = pParam->nDisk / 2; + pArray->u.array.bArRealnMember = pParam->nDisk / 2; + pArray->u.array.bArBlockSizeShift = pParam->BlockSizeShift; + pArray->u.array.bStripeWitch = (1 << pParam->BlockSizeShift); + pArray->u.array.dArStamp = Stamp; + + pArray->u.array.rf_need_sync = 1; + pArray->u.array.rf_newly_created = 1; + + memcpy(pArray->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME); + } + break; + + default: + goto error; + } + + for(i = 0; i < pArray->u.array.bArnMember; i++) + pArray->u.array.pMember[i]->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType]; + + if ((pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE) && + (pArray->VDeviceType == VD_RAID_1)) + { + pArray->vf_bootmark = pArray->u.array.pMember[0]->vf_bootmark; + pArray->vf_bootable = pArray->u.array.pMember[0]->vf_bootable; + pArray->u.array.pMember[0]->vf_bootable = 0; + pArray->u.array.pMember[0]->vf_bootmark = 0; + if (Loca>=0) { + _vbus_p->pVDevice[Loca] = pArray; + /* to comfort OS */ + pArray->u.array.rf_duplicate_and_created = 1; + pArray->pVBus = _vbus_p; + } + } + else { + UCHAR TempBuffer[512]; + ZeroMemory(TempBuffer, 512); + for(i = 0; i < pParam->nDisk; i++) + { + PVDevice pDisk = ID_TO_VDEV(pParam->Members[i]); + pDisk->vf_bootmark = pDisk->vf_bootable = 0; + fDeReadWrite(&pDisk->u.disk, 0, IDE_COMMAND_WRITE, TempBuffer); + } + } + + pArray->vf_online = 1; + pArray->pParent = NULL; + + switch(pArray->VDeviceType) + { + case VD_RAID_0: + for(i = 0; i < pArray->u.array.bArnMember; i++) + if(pArray->u.array.pMember[i]->VDeviceCapacity < capacity) + capacity = pArray->u.array.pMember[i]->VDeviceCapacity; +#ifdef ARRAY_V2_ONLY + capacity -= 10; +#endif + capacity &= ~(pArray->u.array.bStripeWitch - 1); + /* shrink member capacity for RAID 1/0 */ + for(i = 0; i < pArray->u.array.bArnMember; i++) + if (mIsArray(pArray->u.array.pMember[i])) + pArray->u.array.pMember[i]->VDeviceCapacity = capacity; + pArray->VDeviceCapacity = capacity * pArray->u.array.bArnMember; + break; + + case VD_RAID_1: + pArray->VDeviceCapacity = MIN(pArray->u.array.pMember[0]->VDeviceCapacity, + pArray->u.array.pMember[1]->VDeviceCapacity); + break; + + case VD_JBOD: + for(i = 0; i < pArray->u.array.bArnMember; i++) + pArray->VDeviceCapacity += pArray->u.array.pMember[i]->VDeviceCapacity +#ifdef ARRAY_V2_ONLY + -10 +#endif + ; + break; + + case VD_RAID_5: + for(i = 0; i < pArray->u.array.bArnMember; i++) + if(pArray->u.array.pMember[i]->VDeviceCapacity < capacity) + capacity = pArray->u.array.pMember[i]->VDeviceCapacity; + pArray->VDeviceCapacity = (capacity & ~(pArray->u.array.bStripeWitch - 1)) + * (pArray->u.array.bArnMember - 1); + break; + + default: + goto error; + } + + pArray->pfnSendCommand = pfnSendCommand[pArray->VDeviceType]; + pArray->pfnDeviceFailed = fOsDiskFailed; + SyncArrayInfo(pArray); + + if (!pArray->u.array.rf_duplicate_and_created) + RegisterVDevice(pArray); + return VDEV_TO_ID(pArray); + +error: + for(i = 0; i < pArray->u.array.bArnMember; i++) + { + pChild = pArray->u.array.pMember[i]; + if((pChild != NULL) && (pChild->VDeviceType != VD_SINGLE_DISK)) + mArFreeArrayTable(pChild); + } + mArFreeArrayTable(pArray); + return INVALID_DEVICEID; +} + +DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam) +{ + CREATE_ARRAY_PARAMS_V2 param2; + param2.ArrayType = pParam->ArrayType; + param2.nDisk = pParam->nDisk; + param2.BlockSizeShift = pParam->BlockSizeShift; + param2.CreateFlags = pParam->CreateFlags; + param2.CreateTime = pParam->CreateTime; + memcpy(param2.ArrayName, pParam->ArrayName, sizeof(param2.ArrayName)); + memcpy(param2.Description, pParam->Description, sizeof(param2.Description)); + memcpy(param2.CreateManager, pParam->CreateManager, sizeof(param2.CreateManager)); + param2.Capacity.lo32 = param2.Capacity.hi32 = 0; + memcpy(param2.Members, pParam->Members, sizeof(pParam->Members)); + return hpt_create_array_v2(_VBUS_P ¶m2); +} + +#ifdef SUPPORT_OLD_ARRAY +/* this is only for old RAID 0/1 */ +int old_add_disk_to_raid01(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk) +{ + PVDevice pArray1 = ID_TO_VDEV(idArray); + PVDevice pArray2 = 0; + PVDevice pDisk = ID_TO_VDEV(idDisk); + int i; + IAL_ADAPTER_T *pAdapter = gIal_Adapter; + + if (pArray1->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;} + + if(pDisk->u.disk.dDeRealCapacity < (pArray1->VDeviceCapacity / 2)) + return -1; + + pArray2 = pArray1->u.array.pMember[1]; + if(pArray2 == NULL) { + /* create a Stripe */ + mArGetArrayTable(pArray2); + pArray2->VDeviceType = VD_RAID_0; + pArray2->u.array.dArStamp = GetStamp(); + pArray2->vf_format_v2 = 1; + pArray2->u.array.rf_broken = 1; + pArray2->u.array.bArBlockSizeShift = pArray1->u.array.bArBlockSizeShift; + pArray2->u.array.bStripeWitch = (1 << pArray2->u.array.bArBlockSizeShift); + pArray2->u.array.bArnMember = 2; + pArray2->VDeviceCapacity = pArray1->VDeviceCapacity; + pArray2->pfnSendCommand = pfnSendCommand[pArray2->VDeviceType]; + pArray2->pfnDeviceFailed = pfnDeviceFailed[pArray1->VDeviceType]; + memcpy(pArray2->u.array.ArrayName, pArray1->u.array.ArrayName, MAX_ARRAY_NAME); + pArray2->pParent = pArray1; + pArray2->bSerialNumber = 1; + pArray1->u.array.pMember[1] = pArray2; + pArray1->u.array.bArRealnMember++; + } + + for(i = 0; i < pArray2->u.array.bArnMember; i++) + if((pArray2->u.array.pMember[i] == NULL) || !pArray2->u.array.pMember[i]->vf_online) + { + if(pArray2->u.array.pMember[i] != NULL) + pArray2->u.array.pMember[i]->pParent = NULL; + pArray2->u.array.pMember[i] = pDisk; + goto find; + } + return -1; + +find: + UnregisterVDevice(pDisk); + pDisk->VDeviceType = VD_SINGLE_DISK; + pDisk->bSerialNumber = i; + pDisk->pParent = pArray2; + pDisk->vf_format_v2 = 1; + pDisk->u.disk.dDeHiddenLba = i? 10 : 0; + pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity; + pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray2->VDeviceType]; + + pArray2->u.array.bArRealnMember++; + if(pArray2->u.array.bArnMember == pArray2->u.array.bArRealnMember){ + pArray2->vf_online = 1; + pArray2->u.array.rf_broken = 0; + } + + if(pArray1->u.array.pMember[0]->vf_online && pArray1->u.array.pMember[1]->vf_online){ + pArray1->u.array.bArRealnMember = pArray1->u.array.bArnMember; + pArray1->u.array.rf_broken = 0; + pArray1->u.array.rf_need_rebuild = 1; + pArray1->u.array.rf_auto_rebuild = 1; + + } + pArray1->u.array.RebuildSectors = 0; + pArray1->u.array.dArStamp = GetStamp(); + SyncArrayInfo(pArray1); + return 1; +} +#endif + +int hpt_add_disk_to_array(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk) +{ + int i; + + LBA_T Capacity; + PVDevice pArray = ID_TO_VDEV(idArray); + PVDevice pDisk = ID_TO_VDEV(idDisk); + + if((idArray == 0) || (idDisk == 0)) return -1; + if(check_VDevice_valid(pArray) || check_VDevice_valid(pDisk)) return -1; + if(!pArray->u.array.rf_broken) return -1; + + if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5) + return -1; + if((pDisk->VDeviceType != VD_SINGLE_DISK) && (pDisk->VDeviceType != VD_SPARE)) + return -1; + +#ifdef SUPPORT_OLD_ARRAY + /* RAID 0 + 1 */ + if (pArray->vf_format_v2 && pArray->VDeviceType==VD_RAID_1 && + pArray->u.array.pMember[0] && + mIsArray(pArray->u.array.pMember[0])) + { + if(old_add_disk_to_raid01(_VBUS_P idArray, idDisk)) + return 0; + else + return -1; + } +#endif + + Capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember - 1); + + if (pArray->vf_format_v2) { + if(pDisk->u.disk.dDeRealCapacity < Capacity) return -1; + } + else + if(pDisk->VDeviceCapacity < Capacity) return -1; + + if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;} + + for(i = 0; i < pArray->u.array.bArnMember; i++) + if((pArray->u.array.pMember[i] == 0) || !pArray->u.array.pMember[i]->vf_online) + { + if(pArray->u.array.pMember[i] != NULL) + pArray->u.array.pMember[i]->pParent = NULL; + pArray->u.array.pMember[i] = pDisk; + goto find; + } + return -1; + +find: + UnregisterVDevice(pDisk); + pDisk->VDeviceType = VD_SINGLE_DISK; + pDisk->bSerialNumber = i; + pDisk->pParent = pArray; + if (pArray->VDeviceType==VD_RAID_5) pDisk->vf_cache_disk = 1; + pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType]; + if (pArray->vf_format_v2) { + pDisk->vf_format_v2 = 1; + pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity; + } + + pArray->u.array.bArRealnMember++; + if(pArray->u.array.bArnMember == pArray->u.array.bArRealnMember) + { + pArray->u.array.rf_need_rebuild = 1; + pArray->u.array.RebuildSectors = 0; + pArray->u.array.rf_auto_rebuild = 1; + pArray->u.array.rf_broken = 0; + } + pArray->u.array.RebuildSectors = 0; + + /* sync the whole array */ + while (pArray->pParent) pArray = pArray->pParent; + pArray->u.array.dArStamp = GetStamp(); + SyncArrayInfo(pArray); + return 0; +} + +int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk) +{ + PVDevice pVDevice = ID_TO_VDEV(idDisk); + DECLARE_BUFFER(PUCHAR, pbuffer); + + if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1; + if (pVDevice->VDeviceType != VD_SINGLE_DISK || pVDevice->pParent) + return -1; + + if (pVDevice->u.disk.pVBus!=_vbus_p) return -1; + + UnregisterVDevice(pVDevice); + pVDevice->VDeviceType = VD_SPARE; + pVDevice->vf_bootmark = 0; + + ZeroMemory((char *)pbuffer, 512); + fDeReadWrite(&pVDevice->u.disk, 0, IDE_COMMAND_WRITE, pbuffer); + SyncArrayInfo(pVDevice); + return 0; +} + +int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk) +{ + PVDevice pVDevice = ID_TO_VDEV(idDisk); + + if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1; + + if (pVDevice->u.disk.pVBus!=_vbus_p) return -1; + + pVDevice->VDeviceType = VD_SINGLE_DISK; + + SyncArrayInfo(pVDevice); + RegisterVDevice(pVDevice); + return 0; +} + +int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo) +{ + PVDevice pVDevice = ID_TO_VDEV(idArray); + + if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1; + if (!mIsArray(pVDevice)) return -1; + + /* if the pVDevice isn't a top level, return -1; */ + if(pVDevice->pParent != NULL) return -1; + + if (pVDevice->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;} + + if (pInfo->ValidFields & AAIF_NAME) { + memset(pVDevice->u.array.ArrayName, 0, MAX_ARRAY_NAME); + memcpy(pVDevice->u.array.ArrayName, pInfo->Name, sizeof(pInfo->Name)); + pVDevice->u.array.rf_need_sync = 1; + } + + if (pInfo->ValidFields & AAIF_DESCRIPTION) { + memcpy(pVDevice->u.array.Description, pInfo->Description, sizeof(pInfo->Description)); + pVDevice->u.array.rf_need_sync = 1; + } + + if (pVDevice->u.array.rf_need_sync) + SyncArrayInfo(pVDevice); + return 0; +} + +static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo) +{ + PVDevice pVDevice = ID_TO_VDEV(idDisk); + + if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1; + if (mIsArray(pVDevice)) + return -1; + + if (pVDevice->u.disk.pVBus!=_vbus_p) return -1; + + /* TODO */ + return 0; + } + +static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo) +{ + PVDevice pVDevice = ID_TO_VDEV(idDisk); + int sync = 0; + + if(idDisk==0 || check_VDevice_valid(pVDevice)) return -1; + if (mIsArray(pVDevice)) + return -1; + + if (pVDevice->u.disk.pVBus!=_vbus_p) return -1; + + if (pInfo->ValidFields & ADIF_MODE) { + pVDevice->u.disk.bDeModeSetting = pInfo->DeviceModeSetting; + pVDevice->u.disk.bDeUserSelectMode = pInfo->DeviceModeSetting; + pVDevice->u.disk.df_user_mode_set = 1; + fDeSelectMode((PDevice)&(pVDevice->u.disk), (UCHAR)pInfo->DeviceModeSetting); + sync = 1; +} + + if (pInfo->ValidFields & ADIF_TCQ) { + if (fDeSetTCQ(&pVDevice->u.disk, pInfo->TCQEnabled, 0)) { + pVDevice->u.disk.df_tcq_set = 1; + pVDevice->u.disk.df_tcq = pInfo->TCQEnabled!=0; + sync = 1; +} + } + + if (pInfo->ValidFields & ADIF_NCQ) { + if (fDeSetNCQ(&pVDevice->u.disk, pInfo->NCQEnabled, 0)) { + pVDevice->u.disk.df_ncq_set = 1; + pVDevice->u.disk.df_ncq = pInfo->NCQEnabled!=0; + sync = 1; + } + } + + if (pInfo->ValidFields & ADIF_WRITE_CACHE) { + if (fDeSetWriteCache(&pVDevice->u.disk, pInfo->WriteCacheEnabled)) { + pVDevice->u.disk.df_write_cache_set = 1; + pVDevice->u.disk.df_write_cache = pInfo->WriteCacheEnabled!=0; + sync = 1; + } + } + + if (pInfo->ValidFields & ADIF_READ_AHEAD) { + if (fDeSetReadAhead(&pVDevice->u.disk, pInfo->ReadAheadEnabled)) { + pVDevice->u.disk.df_read_ahead_set = 1; + pVDevice->u.disk.df_read_ahead = pInfo->ReadAheadEnabled!=0; + sync = 1; + } + } + + if (sync) + SyncArrayInfo(pVDevice); + return 0; +} + +#endif + +/* hpt_default_ioctl() + * This is a default implementation. The platform dependent part + * may reuse this function and/or use it own implementation for + * each ioctl function. + */ +int hpt_default_ioctl(_VBUS_ARG + DWORD dwIoControlCode, /* operation control code */ + PVOID lpInBuffer, /* input data buffer */ + DWORD nInBufferSize, /* size of input data buffer */ + PVOID lpOutBuffer, /* output data buffer */ + DWORD nOutBufferSize, /* size of output data buffer */ + PDWORD lpBytesReturned /* byte count */ + ) +{ + switch(dwIoControlCode) { + + case HPT_IOCTL_GET_VERSION: + + if (nInBufferSize != 0) return -1; + if (nOutBufferSize != sizeof(DWORD)) return -1; + *((DWORD*)lpOutBuffer) = HPT_INTERFACE_VERSION; + break; + + case HPT_IOCTL_GET_CONTROLLER_COUNT: + + if (nOutBufferSize!=sizeof(DWORD)) return -1; + *(PDWORD)lpOutBuffer = hpt_get_controller_count(); + break; + + case HPT_IOCTL_GET_CONTROLLER_INFO: + { + int id; + PCONTROLLER_INFO pInfo; + + if (nInBufferSize!=sizeof(DWORD)) return -1; + if (nOutBufferSize!=sizeof(CONTROLLER_INFO)) return -1; + + id = *(DWORD *)lpInBuffer; + pInfo = (PCONTROLLER_INFO)lpOutBuffer; + if (hpt_get_controller_info(id, pInfo)!=0) + return -1; + } + break; + + case HPT_IOCTL_GET_CHANNEL_INFO: + { + int id, bus; + PCHANNEL_INFO pInfo; + + if (nInBufferSize!=8) return -1; + if (nOutBufferSize!=sizeof(CHANNEL_INFO)) return -1; + + id = *(DWORD *)lpInBuffer; + bus = ((DWORD *)lpInBuffer)[1]; + pInfo = (PCHANNEL_INFO)lpOutBuffer; + + if (hpt_get_channel_info(id, bus, pInfo)!=0) + return -1; + } + break; + + case HPT_IOCTL_GET_LOGICAL_DEVICES: + { + DWORD nMax; + DEVICEID *pIds; + + if (nInBufferSize!=sizeof(DWORD)) return -1; + nMax = *(DWORD *)lpInBuffer; + if (nOutBufferSize < sizeof(DWORD)+sizeof(DWORD)*nMax) return -1; + + pIds = ((DEVICEID *)lpOutBuffer)+1; + *(DWORD*)lpOutBuffer = hpt_get_logical_devices(pIds, nMax); + } + break; + + case HPT_IOCTL_GET_DEVICE_INFO: + { + DEVICEID id; + PLOGICAL_DEVICE_INFO pInfo; + + if (nInBufferSize!=sizeof(DEVICEID)) return -1; + if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO)) return -1; + + id = *(DWORD *)lpInBuffer; + if (id == INVALID_DEVICEID) return -1; + + pInfo = (PLOGICAL_DEVICE_INFO)lpOutBuffer; + memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO)); + + if (hpt_get_device_info(id, pInfo)!=0) + return -1; + } + break; + + case HPT_IOCTL_GET_DEVICE_INFO_V2: + { + DEVICEID id; + PLOGICAL_DEVICE_INFO_V2 pInfo; + + if (nInBufferSize!=sizeof(DEVICEID)) return -1; + if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO_V2)) return -1; + + id = *(DWORD *)lpInBuffer; + if (id == INVALID_DEVICEID) return -1; + + pInfo = (PLOGICAL_DEVICE_INFO_V2)lpOutBuffer; + memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO_V2)); + + if (hpt_get_device_info_v2(id, pInfo)!=0) + return -1; + } + break; + +#ifdef SUPPORT_ARRAY + case HPT_IOCTL_CREATE_ARRAY: + { + if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS)) return -1; + if (nOutBufferSize!=sizeof(DEVICEID)) return -1; + + *(DEVICEID *)lpOutBuffer = hpt_create_array(_VBUS_P (PCREATE_ARRAY_PARAMS)lpInBuffer); + + if(*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID) + return -1; + } + break; + + case HPT_IOCTL_CREATE_ARRAY_V2: + { + if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS_V2)) return -1; + if (nOutBufferSize!=sizeof(DEVICEID)) return -1; + + *(DEVICEID *)lpOutBuffer = hpt_create_array_v2(_VBUS_P (PCREATE_ARRAY_PARAMS_V2)lpInBuffer); + + if (*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID) + return -1; + } + break; + + case HPT_IOCTL_SET_ARRAY_INFO: + { + DEVICEID idArray; + PALTERABLE_ARRAY_INFO pInfo; + + if (nInBufferSize!=sizeof(HPT_SET_ARRAY_INFO)) return -1; + if (nOutBufferSize!=0) return -1; + + idArray = ((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray; + pInfo = &((PHPT_SET_ARRAY_INFO)lpInBuffer)->Info; + + if(hpt_set_array_info(_VBUS_P idArray, pInfo)) + return -1; + } + break; + + case HPT_IOCTL_SET_DEVICE_INFO: + { + DEVICEID idDisk; + PALTERABLE_DEVICE_INFO pInfo; + + if (nInBufferSize!=sizeof(HPT_SET_DEVICE_INFO)) return -1; + if (nOutBufferSize!=0) return -1; + + idDisk = ((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk; + pInfo = &((PHPT_SET_DEVICE_INFO)lpInBuffer)->Info; + if(hpt_set_device_info(_VBUS_P idDisk, pInfo) != 0) + return -1; + } + break; + + case HPT_IOCTL_SET_DEVICE_INFO_V2: + { + DEVICEID idDisk; + PALTERABLE_DEVICE_INFO_V2 pInfo; + + if (nInBufferSize < sizeof(HPT_SET_DEVICE_INFO_V2)) return -1; + if (nOutBufferSize!=0) return -1; + + idDisk = ((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk; + pInfo = &((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->Info; + if(hpt_set_device_info_v2(_VBUS_P idDisk, pInfo) != 0) + return -1; + } + break; + + case HPT_IOCTL_SET_BOOT_MARK: + { + DEVICEID id; + PVDevice pTop; + int i; + IAL_ADAPTER_T *pAdapter = gIal_Adapter; + PVBus pVBus; + + if (nInBufferSize!=sizeof(DEVICEID)) return -1; + id = *(DEVICEID *)lpInBuffer; + while(pAdapter != 0) + { + pVBus = &pAdapter->VBus; + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) + { + if(!(pTop = pVBus->pVDevice[i])) continue; + if (pTop->pVBus!=_vbus_p) return -1; + while (pTop->pParent) pTop = pTop->pParent; + if (id==0 && pTop->vf_bootmark) + pTop->vf_bootmark = 0; + else if (pTop==ID_TO_VDEV(id) && !pTop->vf_bootmark) + pTop->vf_bootmark = 1; + else + continue; + SyncArrayInfo(pTop); + break; + } + pAdapter = pAdapter->next; + } + } + break; + + case HPT_IOCTL_ADD_SPARE_DISK: + { + DEVICEID id; + + if (nInBufferSize!=sizeof(DEVICEID)) return -1; + if (nOutBufferSize!=0) return -1; + + id = *(DEVICEID *)lpInBuffer; + + if(hpt_add_spare_disk(_VBUS_P id)) + return -1; + } + break; + + case HPT_IOCTL_REMOVE_SPARE_DISK: + { + DEVICEID id; + + if (nInBufferSize!=sizeof(DEVICEID)) return -1; + if (nOutBufferSize!=0) return -1; + + id = *(DEVICEID *)lpInBuffer; + + if(hpt_remove_spare_disk(_VBUS_P id)) + return -1; + } + break; + + case HPT_IOCTL_ADD_DISK_TO_ARRAY: + { + DEVICEID id1,id2; + id1 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray; + id2 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idDisk; + + if (nInBufferSize != sizeof(HPT_ADD_DISK_TO_ARRAY)) return -1; + if (nOutBufferSize != 0) return -1; + + if(hpt_add_disk_to_array(_VBUS_P id1, id2)) + return -1; + } + break; +#endif + case HPT_IOCTL_GET_DRIVER_CAPABILITIES: + { + PDRIVER_CAPABILITIES cap; + if (nOutBufferSizenext) + if (iControllerCount++==id) + break; + + if (!pAdapTemp) + return -1; + + if (nOutBufferSize < 4) + return -1; + + *(DWORD*)lpOutBuffer = ((DWORD)pAdapTemp->mvSataAdapter.pciConfigDeviceId << 16) | 0x11AB; + return 0; + } + + case HPT_IOCTL_EPROM_IO: + { + DWORD id = ((DWORD*)lpInBuffer)[0]; + DWORD offset = ((DWORD*)lpInBuffer)[1]; + DWORD direction = ((DWORD*)lpInBuffer)[2]; + DWORD length = ((DWORD*)lpInBuffer)[3]; + IAL_ADAPTER_T *pAdapTemp; + int iControllerCount = 0; + + for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) + if (iControllerCount++==id) + break; + + if (!pAdapTemp) + return -1; + + if (nInBufferSize < sizeof(DWORD) * 4 + (direction? length : 0) || + nOutBufferSize < (direction? 0 : length)) + return -1; + + if (direction == 0) /* read */ + sx508x_flash_access(&pAdapTemp->mvSataAdapter, + offset, lpOutBuffer, length, 1); + else + sx508x_flash_access(&pAdapTemp->mvSataAdapter, + offset, (char *)lpInBuffer + 16, length, 0); + + return 0; + } + break; + + default: + return -1; + } + + if (lpBytesReturned) + *lpBytesReturned = nOutBufferSize; + return 0; +} diff --git a/sys/dev/raid/hptmv/hptintf.h b/sys/dev/raid/hptmv/hptintf.h new file mode 100644 index 0000000000..4eec0a57b7 --- /dev/null +++ b/sys/dev/raid/hptmv/hptintf.h @@ -0,0 +1,1234 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/hptintf.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ + +#ifndef HPT_INTF_H +#define HPT_INTF_H +#pragma pack(1) + +/* + * Version of this interface. + * The user mode application must first issue a hpt_get_version() call to + * check HPT_INTERFACE_VERSION. When an utility using newer version interface + * is used with old version drivers, it must call only the functions that + * driver supported. + * A new version interface should only add ioctl functions; it should implement + * all old version functions without change their definition. + */ +#define __this_HPT_INTERFACE_VERSION 0x01010000 + +#ifndef HPT_INTERFACE_VERSION +#error "You must define HPT_INTERFACE_VERSION you implemented" +#endif + +#if HPT_INTERFACE_VERSION > __this_HPT_INTERFACE_VERSION +#error "HPT_INTERFACE_VERSION is invalid" +#endif + +/* + * DEFINITION + * Logical device --- a device that can be accessed by OS. + * Physical device --- device attached to the controller. + * A logical device can be simply a physical device. + * + * Each logical and physical device has a 32bit ID. GUI will use this ID + * to identify devices. + * 1. The ID must be unique. + * 2. The ID must be immutable. Once an ID is assigned to a device, it + * must not change when system is running and the device exists. + * 3. The ID of logical device must be NOT reusable. If a device is + * removed, other newly created logical device must not use the same ID. + * 4. The ID must not be zero or 0xFFFFFFFF. + */ +typedef DWORD DEVICEID; + +/* + * logical device type. + * Identify array (logical device) and physical device. + */ +#define LDT_ARRAY 1 +#define LDT_DEVICE 2 + +/* + * Array types + * GUI will treat all array as 1-level RAID. No RAID0/1 or RAID1/0. + * A RAID0/1 device is type AT_RAID1. A RAID1/0 device is type AT_RAID0. + * Their members may be another array of type RAID0 or RAID1. + */ +#define AT_UNKNOWN 0 +#define AT_RAID0 1 +#define AT_RAID1 2 +#define AT_RAID5 3 +#define AT_JBOD 7 + +/* + * physical device type + */ +#define PDT_UNKNOWN 0 +#define PDT_HARDDISK 1 +#define PDT_CDROM 2 +#define PDT_TAPE 3 + +/* + * Some constants. + */ +#define MAX_NAME_LENGTH 36 +#define MAX_ARRAYNAME_LEN 16 + +#define MAX_ARRAY_MEMBERS_V1 8 +#define MAX_ARRAY_MEMBERS_V2 16 +/* keep definition for source code compatiblity */ +#define MAX_ARRAY_MEMBERS MAX_ARRAY_MEMBERS_V1 + +/* + * io commands + * GUI use these commands to do IO on logical/physical devices. + */ +#define IO_COMMAND_READ 1 +#define IO_COMMAND_WRITE 2 + +/* + * array flags + */ +#define ARRAY_FLAG_DISABLED 0x00000001 /* The array is disabled */ +#define ARRAY_FLAG_NEEDBUILDING 0x00000002 /* array need synchronizing */ +#define ARRAY_FLAG_REBUILDING 0x00000004 /* array is in rebuilding process */ +#define ARRAY_FLAG_BROKEN 0x00000008 /* broken but may still working */ +#define ARRAY_FLAG_BOOTDISK 0x00000010 /* array has a active partition */ +#define ARRAY_FLAG_NEWLY_CREATED 0x00000020 /* a newly created array */ +#define ARRAY_FLAG_BOOTMARK 0x00000040 /* array has boot mark set */ +#define ARRAY_FLAG_NEED_AUTOREBUILD 0x00000080 /* auto-rebuild should start */ +#define ARRAY_FLAG_VERIFYING 0x00000100 /* is being verified */ +#define ARRAY_FLAG_INITIALIZING 0x00000200 /* is being initialized */ +#define ARRAY_FLAG_RAID15PLUS 0x80000000 /* display this RAID 1 as RAID 1.5 */ + +/* + * device flags + */ +#define DEVICE_FLAG_DISABLED 0x00000001 /* device is disabled */ +#define DEVICE_FLAG_BOOTDISK 0x00000002 /* disk has a active partition */ +#define DEVICE_FLAG_BOOTMARK 0x00000004 /* disk has boot mark set */ +#define DEVICE_FLAG_WITH_601 0x00000008 /* has HPT601 connected */ +#define DEVICE_FLAG_SATA 0x00000010 /* S-ATA device */ +#define DEVICE_FLAG_IS_SPARE 0x80000000 /* is a spare disk */ + +/* + * array states used by hpt_set_array_state() + */ +/* old defines */ +#define MIRROR_REBUILD_START 1 +#define MIRROR_REBUILD_ABORT 2 +#define MIRROR_REBUILD_COMPLETE 3 +/* new defines */ +#define AS_REBUILD_START 1 +#define AS_REBUILD_ABORT 2 +#define AS_REBUILD_PAUSE AS_REBUILD_ABORT +#define AS_REBUILD_COMPLETE 3 +#define AS_VERIFY_START 4 +#define AS_VERIFY_ABORT 5 +#define AS_VERIFY_COMPLETE 6 +#define AS_INITIALIZE_START 7 +#define AS_INITIALIZE_ABORT 8 +#define AS_INITIALIZE_COMPLETE 9 +#define AS_VERIFY_FAILED 10 +#define AS_REBUILD_STOP 11 +#define AS_SAVE_STATE 12 +/************************************************************************ + * ioctl code + * It would be better if ioctl code are the same on different platforms, + * but we must not conflict with system defined ioctl code. + ************************************************************************/ +#if defined(LINUX) || defined(__DragonFly_version) +#define HPT_CTL_CODE(x) (x+0xFF00) +#elif defined(_MS_WIN32_) || defined(WIN32) + +#ifndef CTL_CODE +#define CTL_CODE( DeviceType, Function, Method, Access ) \ + (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#endif +#define HPT_CTL_CODE(x) CTL_CODE(0x370, 0x900+(x), 0, 0) +#define HPT_CTL_CODE_WIN32_TO_I960(x) ((((x) & 0xffff)>>2)-0x900) + +#else +#define HPT_CTL_CODE(x) (x) +#endif + +#define HPT_IOCTL_GET_VERSION HPT_CTL_CODE(0) +#define HPT_IOCTL_GET_CONTROLLER_COUNT HPT_CTL_CODE(1) +#define HPT_IOCTL_GET_CONTROLLER_INFO HPT_CTL_CODE(2) +#define HPT_IOCTL_GET_CHANNEL_INFO HPT_CTL_CODE(3) +#define HPT_IOCTL_GET_LOGICAL_DEVICES HPT_CTL_CODE(4) +#define HPT_IOCTL_GET_DEVICE_INFO HPT_CTL_CODE(5) +#define HPT_IOCTL_CREATE_ARRAY HPT_CTL_CODE(6) +#define HPT_IOCTL_DELETE_ARRAY HPT_CTL_CODE(7) +#define HPT_IOCTL_ARRAY_IO HPT_CTL_CODE(8) +#define HPT_IOCTL_DEVICE_IO HPT_CTL_CODE(9) +#define HPT_IOCTL_GET_EVENT HPT_CTL_CODE(10) +#define HPT_IOCTL_REBUILD_MIRROR HPT_CTL_CODE(11) +/* use HPT_IOCTL_REBUILD_DATA_BLOCK from now on */ +#define HPT_IOCTL_REBUILD_DATA_BLOCK HPT_IOCTL_REBUILD_MIRROR +#define HPT_IOCTL_ADD_SPARE_DISK HPT_CTL_CODE(12) +#define HPT_IOCTL_REMOVE_SPARE_DISK HPT_CTL_CODE(13) +#define HPT_IOCTL_ADD_DISK_TO_ARRAY HPT_CTL_CODE(14) +#define HPT_IOCTL_SET_ARRAY_STATE HPT_CTL_CODE(15) +#define HPT_IOCTL_SET_ARRAY_INFO HPT_CTL_CODE(16) +#define HPT_IOCTL_SET_DEVICE_INFO HPT_CTL_CODE(17) +#define HPT_IOCTL_RESCAN_DEVICES HPT_CTL_CODE(18) +#define HPT_IOCTL_GET_DRIVER_CAPABILITIES HPT_CTL_CODE(19) +#define HPT_IOCTL_GET_601_INFO HPT_CTL_CODE(20) +#define HPT_IOCTL_SET_601_INFO HPT_CTL_CODE(21) +#define HPT_IOCTL_LOCK_DEVICE HPT_CTL_CODE(22) +#define HPT_IOCTL_UNLOCK_DEVICE HPT_CTL_CODE(23) +#define HPT_IOCTL_IDE_PASS_THROUGH HPT_CTL_CODE(24) +#define HPT_IOCTL_VERIFY_DATA_BLOCK HPT_CTL_CODE(25) +#define HPT_IOCTL_INITIALIZE_DATA_BLOCK HPT_CTL_CODE(26) +#define HPT_IOCTL_ADD_DEDICATED_SPARE HPT_CTL_CODE(27) +#define HPT_IOCTL_DEVICE_IO_EX HPT_CTL_CODE(28) +#define HPT_IOCTL_SET_BOOT_MARK HPT_CTL_CODE(29) +#define HPT_IOCTL_QUERY_REMOVE HPT_CTL_CODE(30) +#define HPT_IOCTL_REMOVE_DEVICES HPT_CTL_CODE(31) +#define HPT_IOCTL_CREATE_ARRAY_V2 HPT_CTL_CODE(32) +#define HPT_IOCTL_GET_DEVICE_INFO_V2 HPT_CTL_CODE(33) +#define HPT_IOCTL_SET_DEVICE_INFO_V2 HPT_CTL_CODE(34) +#define HPT_IOCTL_REBUILD_DATA_BLOCK_V2 HPT_CTL_CODE(35) +#define HPT_IOCTL_VERIFY_DATA_BLOCK_V2 HPT_CTL_CODE(36) +#define HPT_IOCTL_INITIALIZE_DATA_BLOCK_V2 HPT_CTL_CODE(37) +#define HPT_IOCTL_LOCK_DEVICE_V2 HPT_CTL_CODE(38) +#define HPT_IOCTL_DEVICE_IO_V2 HPT_CTL_CODE(39) +#define HPT_IOCTL_DEVICE_IO_EX_V2 HPT_CTL_CODE(40) + +#define HPT_IOCTL_I2C_TRANSACTION HPT_CTL_CODE(48) +#define HPT_IOCTL_GET_PARAMETER_LIST HPT_CTL_CODE(49) +#define HPT_IOCTL_GET_PARAMETER HPT_CTL_CODE(50) +#define HPT_IOCTL_SET_PARAMETER HPT_CTL_CODE(51) + +/* Windows only */ +#define HPT_IOCTL_GET_CONTROLLER_IDS HPT_CTL_CODE(100) +#define HPT_IOCTL_GET_DCB HPT_CTL_CODE(101) +#define HPT_IOCTL_EPROM_IO HPT_CTL_CODE(102) +#define HPT_IOCTL_GET_CONTROLLER_VENID HPT_CTL_CODE(103) + +/************************************************************************ + * shared data structures + ************************************************************************/ + +/* + * Chip Type + */ +#define CHIP_TYPE_HPT366 1 +#define CHIP_TYPE_HPT368 2 +#define CHIP_TYPE_HPT370 3 +#define CHIP_TYPE_HPT370A 4 +#define CHIP_TYPE_HPT370B 5 +#define CHIP_TYPE_HPT374 6 +#define CHIP_TYPE_HPT372 7 +#define CHIP_TYPE_HPT372A 8 +#define CHIP_TYPE_HPT302 9 +#define CHIP_TYPE_HPT371 10 +#define CHIP_TYPE_HPT372N 11 +#define CHIP_TYPE_HPT302N 12 +#define CHIP_TYPE_HPT371N 13 +#define CHIP_TYPE_SI3112A 14 +#define CHIP_TYPE_ICH5 15 +#define CHIP_TYPE_ICH5R 16 + +/* + * Chip Flags + */ +#define CHIP_SUPPORT_ULTRA_66 0x20 +#define CHIP_SUPPORT_ULTRA_100 0x40 +#define CHIP_HPT3XX_DPLL_MODE 0x80 +#define CHIP_SUPPORT_ULTRA_133 0x01 +#define CHIP_SUPPORT_ULTRA_150 0x02 + +typedef struct _DRIVER_CAPABILITIES { + DWORD dwSize; + + UCHAR MaximumControllers; /* maximum controllers the driver can support */ + UCHAR SupportCrossControllerRAID; /* 1-support, 0-not support */ + UCHAR MinimumBlockSizeShift; /* minimum block size shift */ + UCHAR MaximumBlockSizeShift; /* maximum block size shift */ + + UCHAR SupportDiskModeSetting; + UCHAR SupportSparePool; + UCHAR MaximumArrayNameLength; + /* only one byte left here! */ +#ifdef __BIG_ENDIAN_BITFIELD + UCHAR reserved: 4; + UCHAR SupportHotSwap: 1; + UCHAR HighPerformanceRAID1: 1; + UCHAR RebuildProcessInDriver: 1; + UCHAR SupportDedicatedSpare: 1; +#else + UCHAR SupportDedicatedSpare: 1; /* call hpt_add_dedicated_spare() for dedicated spare. */ + UCHAR RebuildProcessInDriver: 1; /* Windows only. used by mid layer for rebuild control. */ + UCHAR HighPerformanceRAID1: 1; /* Support RAID1.5 */ + UCHAR SupportHotSwap: 1; + UCHAR reserved: 4; +#endif + + /* SupportedRAIDTypes is an array of bytes, one of each is an array type. + * Only non-zero values is valid. Bit0-3 represents the lower(child) level RAID type; + * bit4-7 represents the top level. i.e. + * RAID 0/1 is (AT_RAID1<<4) | AT_RAID0 + * RAID 5/0 is (AT_RAID0<<4) | AT_RAID5 + */ + UCHAR SupportedRAIDTypes[16]; + /* maximum members in an array corresponding to SupportedRAIDTypes */ + UCHAR MaximumArrayMembers[16]; +} +DRIVER_CAPABILITIES, *PDRIVER_CAPABILITIES; + +/* + * Controller information. + */ +typedef struct _CONTROLLER_INFO { + UCHAR ChipType; /* chip type */ + UCHAR InterruptLevel; /* IRQ level */ + UCHAR NumBuses; /* bus count */ + UCHAR ChipFlags; + + UCHAR szProductID[MAX_NAME_LENGTH]; /* product name */ + UCHAR szVendorID[MAX_NAME_LENGTH]; /* vender name */ + +} CONTROLLER_INFO, *PCONTROLLER_INFO; + +/* + * Channel information. + */ +typedef struct _CHANNEL_INFO { + ULONG IoPort; /* IDE Base Port Address */ + ULONG ControlPort; /* IDE Control Port Address */ + + DEVICEID Devices[2]; /* device connected to this channel */ + +} CHANNEL_INFO, *PCHANNEL_INFO; + +/* + * time represented in DWORD format + */ +#ifndef __KERNEL__ +typedef struct _TIME_RECORD { + UINT seconds:6; /* 0 - 59 */ + UINT minutes:6; /* 0 - 59 */ + UINT month:4; /* 1 - 12 */ + UINT hours:6; /* 0 - 59 */ + UINT day:5; /* 1 - 31 */ + UINT year:5; /* 0=2000, 31=2031 */ +} TIME_RECORD; +#endif + +/* + * Array information. + */ +typedef struct _HPT_ARRAY_INFO { + UCHAR Name[MAX_ARRAYNAME_LEN];/* array name */ + UCHAR Description[64]; /* array description */ + UCHAR CreateManager[16]; /* who created it */ + TIME_RECORD CreateTime; /* when created it */ + + UCHAR ArrayType; /* array type */ + UCHAR BlockSizeShift; /* stripe size */ + UCHAR nDisk; /* member count: Number of ID in Members[] */ + UCHAR reserved; + + DWORD Flags; /* working flags, see ARRAY_FLAG_XXX */ + DWORD Members[MAX_ARRAY_MEMBERS_V1]; /* member array/disks */ + + /* + * rebuilding progress, xx.xx% = sprintf(s, "%.2f%%", RebuildingProgress/100.0); + * only valid if rebuilding is done by driver code. + * Member Flags will have ARRAY_FLAG_REBUILDING set at this case. + * Verify operation use same fields below, the only difference is + * ARRAY_FLAG_VERIFYING is set. + */ + DWORD RebuildingProgress; + DWORD RebuiltSectors; /* rebuilding point (LBA) for single member */ + +} HPT_ARRAY_INFO, *PHPT_ARRAY_INFO; /*LDX modify ARRAY_INFO TO HPT_ARRAY_INFO to avoid compiling error in Windows*/ + +#if HPT_INTERFACE_VERSION>=0x01010000 +typedef struct _LBA64 { +#ifdef __BIG_ENDIAN_BITFIELD + DWORD hi32; + DWORD lo32; +#else + DWORD lo32; + DWORD hi32; +#endif +} +LBA64; +typedef struct _HPT_ARRAY_INFO_V2 { + UCHAR Name[MAX_ARRAYNAME_LEN];/* array name */ + UCHAR Description[64]; /* array description */ + UCHAR CreateManager[16]; /* who created it */ + TIME_RECORD CreateTime; /* when created it */ + + UCHAR ArrayType; /* array type */ + UCHAR BlockSizeShift; /* stripe size */ + UCHAR nDisk; /* member count: Number of ID in Members[] */ + UCHAR reserved; + + DWORD Flags; /* working flags, see ARRAY_FLAG_XXX */ + DWORD Members[MAX_ARRAY_MEMBERS_V2]; /* member array/disks */ + + DWORD RebuildingProgress; + LBA64 RebuiltSectors; /* rebuilding point (LBA) for single member */ + + DWORD reserve4[4]; + +} HPT_ARRAY_INFO_V2, *PHPT_ARRAY_INFO_V2; +#endif + +/* + * ATA/ATAPI Device identify data without the Reserved4. + */ +#ifndef __KERNEL__ +typedef struct _IDENTIFY_DATA2 { + USHORT GeneralConfiguration; /* 00 00 */ + USHORT NumberOfCylinders; /* 02 1 */ + USHORT Reserved1; /* 04 2 */ + USHORT NumberOfHeads; /* 06 3 */ + USHORT UnformattedBytesPerTrack; /* 08 4 */ + USHORT UnformattedBytesPerSector; /* 0A 5 */ + USHORT SectorsPerTrack; /* 0C 6 */ + USHORT VendorUnique1[3]; /* 0E 7-9 */ + USHORT SerialNumber[10]; /* 14 10-19 */ + USHORT BufferType; /* 28 20 */ + USHORT BufferSectorSize; /* 2A 21 */ + USHORT NumberOfEccBytes; /* 2C 22 */ + USHORT FirmwareRevision[4]; /* 2E 23-26 */ + USHORT ModelNumber[20]; /* 36 27-46 */ + UCHAR MaximumBlockTransfer; /* 5E 47 */ + UCHAR VendorUnique2; /* 5F */ + USHORT DoubleWordIo; /* 60 48 */ + USHORT Capabilities; /* 62 49 */ + USHORT Reserved2; /* 64 50 */ + UCHAR VendorUnique3; /* 66 51 */ + UCHAR PioCycleTimingMode; /* 67 */ + UCHAR VendorUnique4; /* 68 52 */ + UCHAR DmaCycleTimingMode; /* 69 */ + USHORT TranslationFieldsValid:1; /* 6A 53 */ + USHORT Reserved3:15; + USHORT NumberOfCurrentCylinders; /* 6C 54 */ + USHORT NumberOfCurrentHeads; /* 6E 55 */ + USHORT CurrentSectorsPerTrack; /* 70 56 */ + ULONG CurrentSectorCapacity; /* 72 57-58 */ + USHORT CurrentMultiSectorSetting; /* 59 */ + ULONG UserAddressableSectors; /* 60-61 */ + USHORT SingleWordDMASupport : 8; /* 62 */ + USHORT SingleWordDMAActive : 8; + USHORT MultiWordDMASupport : 8; /* 63 */ + USHORT MultiWordDMAActive : 8; + USHORT AdvancedPIOModes : 8; /* 64 */ + USHORT Reserved4 : 8; + USHORT MinimumMWXferCycleTime; /* 65 */ + USHORT RecommendedMWXferCycleTime; /* 66 */ + USHORT MinimumPIOCycleTime; /* 67 */ + USHORT MinimumPIOCycleTimeIORDY; /* 68 */ + USHORT Reserved5[2]; /* 69-70 */ + USHORT ReleaseTimeOverlapped; /* 71 */ + USHORT ReleaseTimeServiceCommand; /* 72 */ + USHORT MajorRevision; /* 73 */ + USHORT MinorRevision; /* 74 */ +/* USHORT Reserved6[14]; // 75-88 */ +} IDENTIFY_DATA2, *PIDENTIFY_DATA2; +#endif + +/* + * physical device information. + * IdentifyData.ModelNumber[] is byte-swapped from the original identify data. + */ +typedef struct _DEVICE_INFO { + UCHAR ControllerId; /* controller id */ + UCHAR PathId; /* bus */ + UCHAR TargetId; /* id */ + UCHAR DeviceModeSetting; /* Current Data Transfer mode: 0-4 PIO 0-4 */ + /* 5-7 MW DMA0-2, 8-13 UDMA0-5 */ + UCHAR DeviceType; /* device type */ + UCHAR UsableMode; /* highest usable mode */ + + UCHAR ReadAheadSupported: 1; + UCHAR ReadAheadEnabled: 1; + UCHAR WriteCacheSupported: 1; + UCHAR WriteCacheEnabled: 1; + UCHAR TCQSupported: 1; + UCHAR TCQEnabled: 1; + UCHAR NCQSupported: 1; + UCHAR NCQEnabled: 1; + UCHAR reserved; + + DWORD Flags; /* working flags, see DEVICE_FLAG_XXX */ + + IDENTIFY_DATA2 IdentifyData; /* Identify Data of this device */ + +} DEVICE_INFO, *PDEVICE_INFO; + +/* + * HPT601 information + */ +#define HPT601_INFO_DEVICEID 1 +#define HPT601_INFO_TEMPERATURE 2 +#define HPT601_INFO_FANSTATUS 4 +#define HPT601_INFO_BEEPERCONTROL 8 +#define HPT601_INFO_LED1CONTROL 0x10 +#define HPT601_INFO_LED2CONTROL 0x20 +#define HPT601_INFO_POWERSTATUS 0x40 + +typedef struct _HPT601_INFO { + WORD ValidFields; /* mark valid fields below */ + WORD DeviceId; /* 0x5A3E */ + WORD Temperature; /* Read: temperature sensor value. Write: temperature limit */ + WORD FanStatus; /* Fan status */ + WORD BeeperControl; /* bit4: beeper control bit. bit0-3: frequency bits */ + WORD LED1Control; /* bit4: twinkling control bit. bit0-3: frequency bits */ + WORD LED2Control; /* bit4: twinkling control bit. bit0-3: frequency bits */ + WORD PowerStatus; /* 1: has power 2: no power */ +} HPT601_INFO, *PHPT601_INFO; + +/* + * Logical device information. + * Union of ArrayInfo and DeviceInfo. + * Common properties will be put in logical device information. + */ +typedef struct _LOGICAL_DEVICE_INFO { + UCHAR Type; /* LDT_ARRAY or LDT_DEVICE */ + UCHAR reserved[3]; + + DWORD Capacity; /* array capacity */ + DEVICEID ParentArray; + + union { + HPT_ARRAY_INFO array; + DEVICE_INFO device; + } u; + +} LOGICAL_DEVICE_INFO, *PLOGICAL_DEVICE_INFO; + +#if HPT_INTERFACE_VERSION>=0x01010000 +typedef struct _LOGICAL_DEVICE_INFO_V2 { + UCHAR Type; /* LDT_ARRAY or LDT_DEVICE */ + UCHAR reserved[3]; + + LBA64 Capacity; /* array capacity */ + DEVICEID ParentArray; + + union { + HPT_ARRAY_INFO_V2 array; + DEVICE_INFO device; + } u; + +} LOGICAL_DEVICE_INFO_V2, *PLOGICAL_DEVICE_INFO_V2; +#endif + +/* + * ALTERABLE_ARRAY_INFO and ALTERABLE_DEVICE_INFO, used in set_array_info() + * and set_device_info(). + * When set_xxx_info() is called, the ValidFields member indicates which + * fields in the structure are valid. + */ +/* field masks */ +#define AAIF_NAME 1 +#define AAIF_DESCRIPTION 2 +#define ADIF_MODE 1 +#define ADIF_TCQ 2 +#define ADIF_NCQ 4 +#define ADIF_WRITE_CACHE 8 +#define ADIF_READ_AHEAD 0x10 + +typedef struct _ALTERABLE_ARRAY_INFO { + DWORD ValidFields; /* mark valid fields below */ + UCHAR Name[MAX_ARRAYNAME_LEN]; /* array name */ + UCHAR Description[64]; /* array description */ +} +ALTERABLE_ARRAY_INFO, *PALTERABLE_ARRAY_INFO; + +typedef struct _ALTERABLE_DEVICE_INFO { + DWORD ValidFields; /* mark valid fields below */ + UCHAR DeviceModeSetting; /* 0-4 PIO 0-4, 5-7 MW DMA0-2, 8-13 UDMA0-5 */ +} +ALTERABLE_DEVICE_INFO, *PALTERABLE_DEVICE_INFO; + +typedef struct _ALTERABLE_DEVICE_INFO_V2 { + DWORD ValidFields; /* mark valid fields below */ + UCHAR DeviceModeSetting; /* 0-4 PIO 0-4, 5-7 MW DMA0-2, 8-13 UDMA0-5 */ + UCHAR TCQEnabled; + UCHAR NCQEnabled; + UCHAR WriteCacheEnabled; + UCHAR ReadAheadEnabled; + UCHAR reserve[3]; + ULONG reserve2[13]; /* pad to 64 bytes */ +} +ALTERABLE_DEVICE_INFO_V2, *PALTERABLE_DEVICE_INFO_V2; + +/* + * CREATE_ARRAY_PARAMS + * Param structure used to create an array. + */ +typedef struct _CREATE_ARRAY_PARAMS { + UCHAR ArrayType; /* 1-level array type */ + UCHAR nDisk; /* number of elements in Members[] array */ + UCHAR BlockSizeShift; /* Stripe size if ArrayType==AT_RAID0 / AT_RAID5 */ + UCHAR CreateFlags; /* See CAF_xxx */ + + UCHAR ArrayName[MAX_ARRAYNAME_LEN]; /* Array name */ + UCHAR Description[64]; /* array description */ + UCHAR CreateManager[16]; /* who created it */ + TIME_RECORD CreateTime; /* when created it */ + + DWORD Members[MAX_ARRAY_MEMBERS_V1];/* ID of array members, a member can be an array */ + +} CREATE_ARRAY_PARAMS, *PCREATE_ARRAY_PARAMS; + +#if HPT_INTERFACE_VERSION>=0x01010000 +typedef struct _CREATE_ARRAY_PARAMS_V2 { + UCHAR ArrayType; /* 1-level array type */ + UCHAR nDisk; /* number of elements in Members[] array */ + UCHAR BlockSizeShift; /* Stripe size if ArrayType==AT_RAID0 / AT_RAID5 */ + UCHAR CreateFlags; /* See CAF_xxx */ + + UCHAR ArrayName[MAX_ARRAYNAME_LEN]; /* Array name */ + UCHAR Description[64]; /* array description */ + UCHAR CreateManager[16]; /* who created it */ + TIME_RECORD CreateTime; /* when created it */ + LBA64 Capacity; /* specify array capacity (0 for default) */ + + DWORD Members[MAX_ARRAY_MEMBERS_V2];/* ID of array members, a member can be an array */ + +} CREATE_ARRAY_PARAMS_V2, *PCREATE_ARRAY_PARAMS_V2; +#endif + +/* + * Flags used for creating an RAID 1 array + * + * CAF_CREATE_AND_DUPLICATE + * Copy source disk contents to target for RAID 1. If user choose "create and duplicate" + * to create an array, GUI will call CreateArray() with this flag set. Then GUI should + * call hpt_get_device_info() with the returned array ID and check returned flags to + * see if ARRAY_FLAG_REBUILDING is set. If not set, driver does not support rebuilding + * and GUI must do duplication itself. + * CAF_DUPLICATE_MUST_DONE + * If the duplication is aborted or fails, do not create the array. + */ +#define CAF_CREATE_AND_DUPLICATE 1 +#define CAF_DUPLICATE_MUST_DONE 2 +#define CAF_CREATE_AS_RAID15 4 +/* + * Flags used for creating an RAID 5 array + */ +#define CAF_CREATE_R5_NO_BUILD 1 +#define CAF_CREATE_R5_ZERO_INIT 2 +#define CAF_CREATE_R5_BUILD_PARITY 4 + +/* + * Flags used for deleting an array + * + * DAF_KEEP_DATA_IF_POSSIBLE + * If this flag is set, deleting a RAID 1 array will not destroy the data on both disks. + * Deleting a JBOD should keep partitions on first disk ( not implement now ). + * Deleting a RAID 0/1 should result as two RAID 0 array ( not implement now ). + */ +#define DAF_KEEP_DATA_IF_POSSIBLE 1 + +/* + * event types + */ +#define ET_DEVICE_REMOVED 1 /* device removed */ +#define ET_DEVICE_PLUGGED 2 /* device plugged */ +#define ET_DEVICE_ERROR 3 /* device I/O error */ +#define ET_REBUILD_STARTED 4 +#define ET_REBUILD_ABORTED 5 +#define ET_REBUILD_FINISHED 6 +#define ET_SPARE_TOOK_OVER 7 +#define ET_REBUILD_FAILED 8 +#define ET_VERIFY_STARTED 9 +#define ET_VERIFY_ABORTED 10 +#define ET_VERIFY_FAILED 11 +#define ET_VERIFY_FINISHED 12 +#define ET_INITIALIZE_STARTED 13 +#define ET_INITIALIZE_ABORTED 14 +#define ET_INITIALIZE_FAILED 15 +#define ET_INITIALIZE_FINISHED 16 +#define ET_VERIFY_DATA_ERROR 17 + +/* + * event structure + */ +typedef struct _HPT_EVENT { + TIME_RECORD Time; + DEVICEID DeviceID; + UCHAR EventType; + UCHAR reserved[3]; + + UCHAR Data[32]; /* various data depend on EventType */ +} HPT_EVENT, *PHPT_EVENT; + +/* + * IDE pass-through command. Use it at your own risk! + */ +#ifdef _MSC_VER +#pragma warning(disable:4200) +#endif +typedef struct _IDE_PASS_THROUGH_HEADER { + DEVICEID idDisk; /* disk ID */ + BYTE bFeaturesReg; /* feature register */ + BYTE bSectorCountReg; /* IDE sector count register. */ + BYTE bLbaLowReg; /* IDE sector number register. */ + BYTE bLbaMidReg; /* IDE low order cylinder value. */ + BYTE bLbaHighReg; /* IDE high order cylinder value. */ + BYTE bDriveHeadReg; /* IDE drive/head register. */ + BYTE bCommandReg; /* Actual IDE command. Checked for validity by driver. */ + BYTE nSectors; /* data sze in sectors, if the command has data transfer */ + BYTE protocol; /* IO_COMMAND_(READ,WRITE) or zero for non-DATA */ + BYTE reserve[3]; +#define IDE_PASS_THROUGH_buffer(p) ((unsigned char *)(p) + sizeof(IDE_PASS_THROUGH_HEADER)) +} +IDE_PASS_THROUGH_HEADER, *PIDE_PASS_THROUGH_HEADER; + +/* + * device io packet format + */ +typedef struct _DEVICE_IO_EX_PARAMS { + DEVICEID idDisk; + ULONG Lba; + USHORT nSectors; + UCHAR Command; /* IO_COMMAD_xxx */ + UCHAR BufferType; /* BUFFER_TYPE_xxx, see below */ + ULONG BufferPtr; +} +DEVICE_IO_EX_PARAMS, *PDEVICE_IO_EX_PARAMS; + +#define BUFFER_TYPE_LOGICAL 1 /* logical pointer to buffer */ +#define BUFFER_TYPE_PHYSICAL 2 /* physical address of buffer */ +#define BUFFER_TYPE_LOGICAL_LOGICAL_SG 3 /* logical pointer to logical S/G table */ +#define BUFFER_TYPE_LOGICAL_PHYSICAL_SG 4 /* logical pointer to physical S/G table */ +#define BUFFER_TYPE_PHYSICAL_LOGICAL_SG 5 /* physical address to logical S/G table */ +#define BUFFER_TYPE_PHYSICAL_PHYSICAL_SG 6 /* physical address of physical S/G table */ +#define BUFFER_TYPE_PHYSICAL_PHYSICAL_SG_PIO 7 /* non DMA capable physical address of physical S/G table */ + +/* + * all ioctl functions should use far pointers. It's not a problem on + * 32bit platforms, however, BIOS needs care. + */ + +/* + * ioctl structure + */ +#define HPT_IOCTL_MAGIC32 0x1A2B3C4D +#define HPT_IOCTL_MAGIC 0xA1B2C3D4 + +typedef struct _HPT_IOCTL_PARAM { + DWORD Magic; /* used to check if it's a valid ioctl packet */ + DWORD dwIoControlCode; /* operation control code */ + LPVOID lpInBuffer; /* input data buffer */ + DWORD nInBufferSize; /* size of input data buffer */ + LPVOID lpOutBuffer; /* output data buffer */ + DWORD nOutBufferSize; /* size of output data buffer */ + LPDWORD lpBytesReturned; /* count of bytes returned */ +} +HPT_IOCTL_PARAM, *PHPT_IOCTL_PARAM; + +/* for 32-bit app running on 64-bit system */ +typedef struct _HPT_IOCTL_PARAM32 { + DWORD Magic; + DWORD dwIoControlCode; + DWORD lpInBuffer; + DWORD nInBufferSize; + DWORD lpOutBuffer; + DWORD nOutBufferSize; + DWORD lpBytesReturned; +} +HPT_IOCTL_PARAM32, *PHPT_IOCTL_PARAM32; + +/* + * User-mode ioctl parameter passing conventions: + * The ioctl function implementation is platform specific, so we don't + * have forced rules for it. However, it's suggested to use a parameter + * passing method as below + * 1) Put all input data continuously in an input buffer. + * 2) Prepare an output buffer with enough size if needed. + * 3) Fill a HPT_IOCTL_PARAM structure. + * 4) Pass the structure to driver through a platform-specific method. + * This is implemented in the mid-layer user-mode library. The UI + * programmer needn't care about it. + */ + +/************************************************************************ + * User mode functions + ************************************************************************/ +#ifndef __KERNEL__ +/* + * hpt_get_version + * Version compatibility: all versions + * Parameters: + * None + * Returns: + * interface version. 0 when fail. + */ +DWORD hpt_get_version(); + +/*-------------------------------------------------------------------------- */ + +/* + * hpt_get_driver_capabilities + * Version compatibility: v1.0.0.2 or later + * Parameters: + * Pointer to receive a DRIVE_CAPABILITIES structure. The caller must set + * dwSize member to sizeof(DRIVER_CAPABILITIES). The callee must check this + * member to see if it's correct. + * Returns: + * 0 - Success + */ +int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap); + +/*-------------------------------------------------------------------------- */ + +/* + * hpt_get_controller_count + * Version compatibility: v1.0.0.1 or later + * Parameters: + * None + * Returns: + * number of controllers + */ +int hpt_get_controller_count(); + +/*-------------------------------------------------------------------------- */ + +/* hpt_get_controller_info + * Version compatibility: v1.0.0.1 or later + * Parameters: + * id Controller id + * pInfo pointer to CONTROLLER_INFO buffer + * Returns: + * 0 Success, controller info is put into (*pInfo ). + */ +int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo); + +/*-------------------------------------------------------------------------- */ + +/* hpt_get_channel_info + * Version compatibility: v1.0.0.1 or later + * Parameters: + * id Controller id + * bus bus number + * pInfo pointer to CHANNEL_INFO buffer + * Returns: + * 0 Success, channel info is put into (*pInfo ). + */ +int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo); + +/*-------------------------------------------------------------------------- */ + +/* hpt_get_logical_devices + * Version compatibility: v1.0.0.1 or later + * Parameters: + * pIds pointer to a DEVICEID array + * nMaxCount array size + * Returns: + * Number of ID returned. All logical device IDs are put into pIds array. + * Note: A spare disk is not a logical device. + */ +int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount); + +/*-------------------------------------------------------------------------- */ + +/* hpt_get_device_info + * Version compatibility: v1.0.0.1 or later + * Parameters: + * id logical device id + * pInfo pointer to HPT_ARRAY_INFO structure + * Returns: + * 0 - Success + */ +int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo); + +#if HPT_INTERFACE_VERSION>=0x01010000 +int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo); +#endif + +/*-------------------------------------------------------------------------- */ + +/* hpt_create_array + * Version compatibility: v1.0.0.1 or later + * Parameters: + * pParam pointer to CREATE_ARRAY_PARAMS structure + * Returns: + * 0 failed + * else return array id + */ +DEVICEID hpt_create_array(PCREATE_ARRAY_PARAMS pParam); + +#if HPT_INTERFACE_VERSION>=0x01010000 +DEVICEID hpt_create_array_v2(PCREATE_ARRAY_PARAMS_V2 pParam); +#endif + +/*-------------------------------------------------------------------------- */ + +/* hpt_delete_array + * Version compatibility: v1.0.0.1 or later + * Parameters: + * id array id + * Returns: + * 0 Success + */ +int hpt_delete_array(DEVICEID id, DWORD options); + +/*-------------------------------------------------------------------------- */ + +/* hpt_device_io + * Read/write data on array and physcal device. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * id device id. If it's an array ID, IO will be performed on the array. + * If it's a physical device ID, IO will be performed on the device. + * cmd IO_COMMAND_READ or IO_COMMAND_WRITE + * buffer data buffer + * length data size + * Returns: + * 0 Success + */ +int hpt_device_io(DEVICEID id, int cmd, ULONG lba, DWORD nSector, LPVOID buffer); + +#if HPT_INTERFACE_VERSION >= 0x01010000 +int hpt_device_io_v2(DEVICEID id, int cmd, LBA64 lba, DWORD nSector, LPVOID buffer); +#endif + +/* hpt_add_disk_to_array + * Used to dynamicly add a disk to an RAID1, RAID0/1, RAID1/0 or RAID5 array. + * Auto-rebuild will start. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * idArray array id + * idDisk disk id + * Returns: + * 0 Success + */ +int hpt_add_disk_to_array(DEVICEID idArray, DEVICEID idDisk); +/*-------------------------------------------------------------------------- */ + +/* hpt_add_spare_disk + * Version compatibility: v1.0.0.1 or later + * Add a disk to spare pool. + * Parameters: + * idDisk disk id + * Returns: + * 0 Success + */ +int hpt_add_spare_disk(DEVICEID idDisk); +/*-------------------------------------------------------------------------- */ + +/* hpt_add_dedicated_spare + * Version compatibility: v1.0.0.3 or later + * Add a spare disk to an array + * Parameters: + * idDisk disk id + * idArray array id + * Returns: + * 0 Success + */ +int hpt_add_dedicated_spare(DEVICEID idDisk, DEVICEID idArray); +/*-------------------------------------------------------------------------- */ + +/* hpt_remove_spare_disk + * remove a disk from spare pool. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * idDisk disk id + * Returns: + * 0 Success + */ +int hpt_remove_spare_disk(DEVICEID idDisk); +/*-------------------------------------------------------------------------- */ + +/* hpt_get_event + * Used to poll events from driver. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * pEvent pointer to HPT_EVENT structure + * Returns: + * 0 Success, event info is filled in *pEvent + */ +int hpt_get_event(PHPT_EVENT pEvent); +/*-------------------------------------------------------------------------- */ + +/* hpt_rebuild_data_block + * Used to copy data from source disk and mirror disk. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * idArray Array ID (RAID1, 0/1 or RAID5) + * Lba Start LBA for each array member + * nSector Number of sectors for each array member (RAID 5 will ignore this parameter) + * + * Returns: + * 0 Success, event info is filled in *pEvent + */ +int hpt_rebuild_data_block(DEVICEID idMirror, DWORD Lba, UCHAR nSector); +#define hpt_rebuild_mirror(p1, p2, p3) hpt_rebuild_data_block(p1, p2, p3) + +#if HPT_INTERFACE_VERSION >= 0x01010000 +int hpt_rebuild_data_block_v2(DEVICEID idArray, LBA64 Lba, USHORT nSector); +#endif +/*-------------------------------------------------------------------------- */ + +/* hpt_set_array_state + * set array state. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * idArray Array ID + * state See above 'array states' constants, possible values are: + * MIRROR_REBUILD_START + * Indicate that GUI wants to rebuild a mirror array + * MIRROR_REBUILD_ABORT + * GUI wants to abort rebuilding an array + * MIRROR_REBUILD_COMPLETE + * GUI finished to rebuild an array. If rebuild is done by driver this + * state has no use + * + * Returns: + * 0 Success + */ +int hpt_set_array_state(DEVICEID idArray, DWORD state); +/*-------------------------------------------------------------------------- */ + +/* hpt_set_array_info + * set array info. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * idArray Array ID + * pInfo pointer to new info + * + * Returns: + * 0 Success + */ +int hpt_set_array_info(DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo); +/*-------------------------------------------------------------------------- */ + +/* hpt_set_device_info + * set device info. + * Version compatibility: v1.0.0.1 or later + * Parameters: + * idDisk device ID + * pInfo pointer to new info + * + * Returns: + * 0 Success + * Additional notes: + * If idDisk==0, call to this function will stop buzzer on the adapter + * (if supported by driver). + */ +int hpt_set_device_info(DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo); + +#if HPT_INTERFACE_VERSION >= 0x01000004 +int hpt_set_device_info_v2(DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo); +#endif + +/*-------------------------------------------------------------------------- */ + +/* hpt_rescan_devices + * rescan devices + * Version compatibility: v1.0.0.1 or later + * Parameters: + * None + * Returns: + * 0 Success + */ +int hpt_rescan_devices(); +/*-------------------------------------------------------------------------- */ + +/* hpt_get_601_info + * Get HPT601 status + * Version compatibiilty: v1.0.0.3 or later + * Parameters: + * idDisk - Disk handle + * PHPT601_INFO - pointer to HPT601 info buffer + * Returns: + * 0 Success + */ +int hpt_get_601_info(DEVICEID idDisk, PHPT601_INFO pInfo); +/*-------------------------------------------------------------------------- */ + +/* hpt_set_601_info + * HPT601 function control + * Version compatibiilty: v1.0.0.3 or later + * Parameters: + * idDisk - Disk handle + * PHPT601_INFO - pointer to HPT601 info buffer + * Returns: + * 0 Success + */ +int hpt_set_601_info(DEVICEID idDisk, PHPT601_INFO pInfo); +/*-------------------------------------------------------------------------- */ + +/* hpt_lock_device + * Lock a block on a device (prevent OS accessing it) + * Version compatibiilty: v1.0.0.3 or later + * Parameters: + * idDisk - Disk handle + * Lba - Start LBA + * nSectors - number of sectors + * Returns: + * 0 Success + */ +int hpt_lock_device(DEVICEID idDisk, ULONG Lba, UCHAR nSectors); + +#if HPT_INTERFACE_VERSION >= 0x01010000 +int hpt_lock_device_v2(DEVICEID idDisk, LBA64 Lba, USHORT nSectors); +#endif +/*-------------------------------------------------------------------------- */ + +/* hpt_lock_device + * Unlock a device + * Version compatibiilty: v1.0.0.3 or later + * Parameters: + * idDisk - Disk handle + * Returns: + * 0 Success + */ +int hpt_unlock_device(DEVICEID idDisk); +/*-------------------------------------------------------------------------- */ + +/* hpt_ide_pass_through + * directly access controller's command and control registers. + * Can only call it on physical devices. + * Version compatibility: v1.0.0.3 or later + * Parameters: + * p - IDE_PASS_THROUGH header pointer + * Returns: + * 0 Success + */ +int hpt_ide_pass_through(PIDE_PASS_THROUGH_HEADER p); +/*-------------------------------------------------------------------------- */ + +/* hpt_verify_data_block + * verify data block on RAID1 or RAID5. + * Version compatibility: v1.0.0.3 or later + * Parameters: + * idArray - Array ID + * Lba - block number (on each array member, not logical block!) + * nSectors - Sectors for each member (RAID 5 will ignore this parameter) + * Returns: + * 0 Success + * 1 Data compare error + * 2 I/O error + */ +int hpt_verify_data_block(DEVICEID idArray, ULONG Lba, UCHAR nSectors); + +#if HPT_INTERFACE_VERSION >= 0x01010000 +int hpt_verify_data_block_v2(DEVICEID idArray, LBA64 Lba, USHORT nSectors); +#endif +/*-------------------------------------------------------------------------- */ + +/* hpt_initialize_data_block + * initialize data block (fill with zero) on RAID5 + * Version compatibility: v1.0.0.3 or later + * Parameters: + * idArray - Array ID + * Lba - block number (on each array member, not logical block!) + * nSectors - Sectors for each member (RAID 5 will ignore this parameter) + * Returns: + * 0 Success + */ +int hpt_initialize_data_block(DEVICEID idArray, ULONG Lba, UCHAR nSectors); + +#if HPT_INTERFACE_VERSION >= 0x01010000 +int hpt_initialize_data_block_v2(DEVICEID idArray, LBA64 Lba, USHORT nSectors); +#endif +/*-------------------------------------------------------------------------- */ + +/* hpt_device_io_ex + * extended device I/O function + * Version compatibility: v1.0.0.3 or later + * Parameters: + * idArray - Array ID + * Lba - block number (on each array member, not logical block!) + * nSectors - Sectors for each member + * buffer - I/O buffer or s/g address + * Returns: + * 0 Success + */ +int hpt_device_io_ex(PDEVICE_IO_EX_PARAMS param); +#if HPT_INTERFACE_VERSION >= 0x01010000 +int hpt_device_io_ex_v2(void * param); /* NOT IMPLEMENTED */ +#endif +/*-------------------------------------------------------------------------- */ + +/* hpt_set_boot_mark + * select boot device + * Version compatibility: v1.0.0.3 or later + * Parameters: + * id - logical device ID. If id is 0 the boot mark will be removed. + * Returns: + * 0 Success + */ +int hpt_set_boot_mark(DEVICEID id); +/*-------------------------------------------------------------------------- */ + +/* hpt_query_remove + * check if device can be removed safely + * Version compatibility: v1.0.0.4 or later + * Parameters: + * ndev - number of devices + * pIds - device ID list + * Returns: + * 0 - Success + * -1 - unknown error + * n - the n-th device that can't be removed + */ +int hpt_query_remove(DWORD ndev, DEVICEID *pIds); +/*-------------------------------------------------------------------------- */ + +/* hpt_remove_devices + * remove a list of devices + * Version compatibility: v1.0.0.4 or later + * Parameters: + * ndev - number of devices + * pIds - device ID list + * Returns: + * 0 - Success + * -1 - unknown error + * n - the n-th device that can't be removed + */ +int hpt_remove_devices(DWORD ndev, DEVICEID *pIds); +/*-------------------------------------------------------------------------- */ + +/* hpt_ide_pass_through + * directly access controller's command and control registers. + * Can only call it on physical devices. + * Version compatibility: v1.0.0.3 or later + * Parameters: + * p - IDE_PASS_THROUGH header pointer + * Returns: + * 0 Success + */ +int hpt_ide_pass_through(PIDE_PASS_THROUGH_HEADER p); +/*-------------------------------------------------------------------------- */ + +#endif + +#pragma pack() +#endif diff --git a/sys/dev/raid/hptmv/hptproc.c b/sys/dev/raid/hptmv/hptproc.c new file mode 100644 index 0000000000..87f1da9f7a --- /dev/null +++ b/sys/dev/raid/hptmv/hptproc.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/hptproc.c,v 1.8 2009/04/07 16:38:25 delphij Exp $ + */ +/* + * hptproc.c sysctl support + */ +#include +#include +#include +#include +#include +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include + +int hpt_rescan_all(void); + +/***************************************************************************/ + +static char hptproc_buffer[256]; +extern char DRIVER_VERSION[]; + +#define FORMAL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, int arg2, \ + struct sysctl_req *req +#define REAL_HANDLER_ARGS oidp, arg1, arg2, req +typedef struct sysctl_req HPT_GET_INFO; + +static int +hpt_set_asc_info(IAL_ADAPTER_T *pAdapter, char *buffer,int length) +{ + int orig_length = length+4; + PVBus _vbus_p = &pAdapter->VBus; + PVDevice pArray; + PVDevice pSubArray, pVDev; + UINT i, iarray, ichan; + struct cam_periph *periph = NULL; + intrmask_t oldspl; + +#ifdef SUPPORT_ARRAY + if (length>=8 && strncmp(buffer, "rebuild ", 8)==0) + { + buffer+=8; + length-=8; + if (length>=5 && strncmp(buffer, "start", 5)==0) + { + oldspl = lock_driver(); + for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) + if ((pArray=ArrayTables(i))->u.array.dArStamp==0) + continue; + else{ + if (pArray->u.array.rf_need_rebuild && !pArray->u.array.rf_rebuilding) + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, + (UCHAR)((pArray->u.array.CriticalMembers || pArray->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY)); + } + unlock_driver(oldspl); + return orig_length; + } + else if (length>=4 && strncmp(buffer, "stop", 4)==0) + { + oldspl = lock_driver(); + for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) + if ((pArray=ArrayTables(i))->u.array.dArStamp==0) + continue; + else{ + if (pArray->u.array.rf_rebuilding) + pArray->u.array.rf_abort_rebuild = 1; + } + unlock_driver(oldspl); + return orig_length; + } + else if (length>=3 && buffer[1]==','&& buffer[0]>='1'&& buffer[2]>='1') + { + iarray = buffer[0]-'1'; + ichan = buffer[2]-'1'; + + if(iarray >= MAX_VDEVICE_PER_VBUS || ichan >= MV_SATA_CHANNELS_NUM) return -EINVAL; + + pArray = _vbus_p->pVDevice[iarray]; + if (!pArray || (pArray->vf_online == 0)) return -EINVAL; + + for (i=0;iVDevices[ichan]; + if(!pVDev->u.disk.df_on_line || pVDev->pParent) return -EINVAL; + + /* Not allow to use a mounted disk ??? test*/ + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) + if(pVDev == _vbus_p->pVDevice[i]) + { + periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId,i); + if (periph != NULL && periph->refcount >= 1) + { + hpt_printk(("Can not use disk used by OS!\n")); + return -EINVAL; + } + /* the Mounted Disk isn't delete */ + } + + switch(pArray->VDeviceType) + { + case VD_RAID_1: + case VD_RAID_5: + { + pSubArray = pArray; +loop: + oldspl = lock_driver(); + if(hpt_add_disk_to_array(_VBUS_P VDEV_TO_ID(pSubArray), VDEV_TO_ID(pVDev)) == -1) { + unlock_driver(oldspl); + return -EINVAL; + } + pSubArray->u.array.rf_auto_rebuild = 0; + pSubArray->u.array.rf_abort_rebuild = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pSubArray, DUPLICATE); + unlock_driver(oldspl); + break; + } + case VD_RAID_0: + for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) + if(pArray->u.array.pMember[i] && mIsArray(pArray->u.array.pMember[i]) && + (pArray->u.array.pMember[i]->u.array.rf_broken == 1)) + { + pSubArray = pArray->u.array.pMember[i]; + goto loop; + } + default: + return -EINVAL; + } + return orig_length; + } + } + else if (length>=7 && strncmp(buffer, "verify ", 7)==0) + { + buffer+=7; + length-=7; + if (length>=6 && strncmp(buffer, "start ", 6)==0) + { + buffer+=6; + length-=6; + if (length>=1 && *buffer>='1') + { + iarray = *buffer-'1'; + if(iarray >= MAX_VDEVICE_PER_VBUS) return -EINVAL; + + pArray = _vbus_p->pVDevice[iarray]; + if (!pArray || (pArray->vf_online == 0)) return -EINVAL; + + if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5) + return -EINVAL; + + if (!(pArray->u.array.rf_need_rebuild || + pArray->u.array.rf_rebuilding || + pArray->u.array.rf_verifying || + pArray->u.array.rf_initializing)) + { + oldspl = lock_driver(); + pArray->u.array.RebuildSectors = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, VERIFY); + unlock_driver(oldspl); + } + return orig_length; + } + } + else if (length>=5 && strncmp(buffer, "stop ", 5)==0) + { + buffer+=5; + length-=5; + if (length>=1 && *buffer>='1') + { + iarray = *buffer-'1'; + if(iarray >= MAX_VDEVICE_PER_VBUS) return -EINVAL; + + pArray = _vbus_p->pVDevice[iarray]; + if (!pArray || (pArray->vf_online == 0)) return -EINVAL; + if(pArray->u.array.rf_verifying) + { + oldspl = lock_driver(); + pArray->u.array.rf_abort_rebuild = 1; + unlock_driver(oldspl); + } + return orig_length; + } + } + } + else +#ifdef _RAID5N_ + if (length>=10 && strncmp(buffer, "writeback ", 10)==0) { + buffer+=10; + length-=10; + if (length>=1 && *buffer>='0' && *buffer<='1') { + _vbus_(r5.enable_write_back) = *buffer-'0'; + if (_vbus_(r5.enable_write_back)) + hpt_printk(("RAID5 write back enabled")); + return orig_length; + } + } + else +#endif +#endif + if (0) {} /* just to compile */ +#ifdef DEBUG + else if (length>=9 && strncmp(buffer, "dbglevel ", 9)==0) { + buffer+=9; + length-=9; + if (length>=1 && *buffer>='0' && *buffer<='3') { + hpt_dbg_level = *buffer-'0'; + return orig_length; + } + } + else if (length>=8 && strncmp(buffer, "disable ", 8)==0) { + /* TO DO */ + } +#endif + + return -EINVAL; +} + +/* + * Since we have only one sysctl node, add adapter ID in the command + * line string: e.g. "hpt 0 rebuild start" + */ +static int +hpt_set_info(int length) +{ + int retval; + +#ifdef SUPPORT_IOCTL + PUCHAR ke_area; + int err; + DWORD dwRet; + PHPT_IOCTL_PARAM piop; +#endif + char *buffer = hptproc_buffer; + if (length >= 6) { + if (strncmp(buffer,"hpt ",4) == 0) { + IAL_ADAPTER_T *pAdapter; + retval = buffer[4]-'0'; + for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { + if (pAdapter->mvSataAdapter.adapterId==retval) + return (retval = hpt_set_asc_info(pAdapter, buffer+6, length-6)) >= 0? retval : -EINVAL; + } + return -EINVAL; + } +#ifdef SUPPORT_IOCTL + piop = (PHPT_IOCTL_PARAM)buffer; + if (piop->Magic == HPT_IOCTL_MAGIC || + piop->Magic == HPT_IOCTL_MAGIC32) { + KdPrintE(("ioctl=%d in=%p len=%d out=%p len=%d\n", + piop->dwIoControlCode, + piop->lpInBuffer, + piop->nInBufferSize, + piop->lpOutBuffer, + piop->nOutBufferSize)); + + /* + * map buffer to kernel. + */ + if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) { + KdPrintE(("User buffer too large\n")); + return -EINVAL; + } + + ke_area = kmalloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT); + if (ke_area == NULL) { + KdPrintE(("Couldn't allocate kernel mem.\n")); + return -EINVAL; + } + + if (piop->nInBufferSize) + copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize); + + /* + * call kernel handler. + */ + err = Kernel_DeviceIoControl(&gIal_Adapter->VBus, + piop->dwIoControlCode, ke_area, piop->nInBufferSize, + ke_area + piop->nInBufferSize, piop->nOutBufferSize, &dwRet); + + if (err==0) { + if (piop->nOutBufferSize) + copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize); + + if (piop->lpBytesReturned) + copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD)); + + kfree(ke_area, M_DEVBUF); + return length; + } + else KdPrintW(("Kernel_ioctl(): return %d\n", err)); + + kfree(ke_area, M_DEVBUF); + return -EINVAL; + } else { + KdPrintW(("Wrong signature: %x\n", piop->Magic)); + return -EINVAL; + } +#endif + } + + return -EINVAL; +} + +#define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8)) + +static void +get_disk_name(char *name, PDevice pDev) +{ + int i; + MV_SATA_CHANNEL *pMvSataChannel = pDev->mv; + IDENTIFY_DATA2 *pIdentifyData = (IDENTIFY_DATA2 *)pMvSataChannel->identifyDevice; + + for (i = 0; i < 10; i++) + ((WORD*)name)[i] = shortswap(pIdentifyData->ModelNumber[i]); + name[20] = '\0'; +} + +static int +hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...) +{ + int printfretval; + __va_list ap; + + if(fmt == NULL) { + *hptproc_buffer = 0; + return (SYSCTL_OUT(pinfo, hptproc_buffer, 1)); + } + else + { + __va_start(ap, fmt); + printfretval = kvsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap); + __va_end(ap); + return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer))); + } +} + +static void +hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan) +{ + char name[32], arrayname[16], *status; + + get_disk_name(name, &pVDev->u.disk); + + if (!pVDev->u.disk.df_on_line) + status = "Disabled"; + else if (pVDev->VDeviceType==VD_SPARE) + status = "Spare "; + else + status = "Normal "; + +#ifdef SUPPORT_ARRAY + if(pVDev->pParent) { + memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME); + if (pVDev->pParent->u.array.CriticalMembers & (1<bSerialNumber)) + status = "Degraded"; + } + else +#endif + arrayname[0]=0; + + hpt_copy_info(pinfo, "Channel %d %s %5dMB %s %s\n", + iChan+1, + name, pVDev->VDeviceCapacity>>11, status, arrayname); +} + +#ifdef SUPPORT_ARRAY +static void +hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray) +{ + int i; + char *sType=0, *sStatus=0; + char buf[32]; + PVDevice pTmpArray; + + switch (pArray->VDeviceType) { + case VD_RAID_0: + for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) + if(pArray->u.array.pMember[i]) { + if(mIsArray(pArray->u.array.pMember[i])) + sType = "RAID 1/0 "; + /* TO DO */ + else + sType = "RAID 0 "; + break; + } + break; + + case VD_RAID_1: + sType = "RAID 1 "; + break; + + case VD_JBOD: + sType = "JBOD "; + break; + + case VD_RAID_5: + sType = "RAID 5 "; + break; + + default: + sType = "N/A "; + break; + } + + if (pArray->vf_online == 0) + sStatus = "Disabled"; + else if (pArray->u.array.rf_broken) + sStatus = "Critical"; + for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) + { + if (!sStatus) + { + if(mIsArray(pArray->u.array.pMember[i])) + pTmpArray = pArray->u.array.pMember[i]; + else + pTmpArray = pArray; + + if (pTmpArray->u.array.rf_rebuilding) { +#ifdef DEBUG + ksprintf(buf, "Rebuilding %lldMB", (pTmpArray->u.array.RebuildSectors>>11)); +#else + ksprintf(buf, "Rebuilding %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11))); +#endif + sStatus = buf; + } + else if (pTmpArray->u.array.rf_verifying) { + ksprintf(buf, "Verifying %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11))); + sStatus = buf; + } + else if (pTmpArray->u.array.rf_need_rebuild) + sStatus = "Critical"; + else if (pTmpArray->u.array.rf_broken) + sStatus = "Critical"; + + if(pTmpArray == pArray) goto out; + } + else + goto out; + } +out: + if (!sStatus) sStatus = "Normal"; + hpt_copy_info(pinfo, "%2d %11s %-20s %5lldMB %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus); +} +#endif + +static int +hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo) +{ + PVBus _vbus_p = &pAdapter->VBus; + struct cam_periph *periph = NULL; + UINT channel,j,i; + PVDevice pVDev; + +#ifndef FOR_DEMO + if (pAdapter->beeping) { + intrmask_t oldspl = lock_driver(); + pAdapter->beeping = 0; + BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress); + unlock_driver(oldspl); + } +#endif + + hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId); + + hpt_copy_info(pinfo, "Physical device list\n"); + hpt_copy_info(pinfo, "Channel Model Capacity Status Array\n"); + hpt_copy_info(pinfo, "-------------------------------------------------------------------\n"); + + for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++) + { + pVDev = &(pAdapter->VDevices[channel]); + if(pVDev->u.disk.df_on_line) + hpt_copy_disk_info(pinfo, pVDev, channel); + } + + hpt_copy_info(pinfo, "\nLogical device list\n"); + hpt_copy_info(pinfo, "No. Type Name Capacity Status OsDisk\n"); + hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n"); + + j=1; + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){ + pVDev = _vbus_p->pVDevice[i]; + if(pVDev){ + j=i+1; +#ifdef SUPPORT_ARRAY + if (mIsArray(pVDev)) + { + is_array: + hpt_copy_array_info(pinfo, j, pVDev); + } + else +#endif + { + char name[32]; + /* it may be add to an array after driver loaded, check it */ +#ifdef SUPPORT_ARRAY + if (pVDev->pParent) + /* in this case, pVDev can only be a RAID 1 source disk. */ + if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0]) + goto is_array; +#endif + get_disk_name(name, &pVDev->u.disk); + + hpt_copy_info(pinfo, "%2d %s %s %5dMB %-16s", + j, "Single disk", name, pVDev->VDeviceCapacity>>11, + /* gmm 2001-6-19: Check if pDev has been added to an array. */ + ((pVDev->pParent) ? "Unavailable" : "Normal")); + } + periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i); + if (periph == NULL) + hpt_copy_info(pinfo," %s\n","not registered"); + else + hpt_copy_info(pinfo," %s%d\n", periph->periph_name, periph->unit_number); + } + } + return 0; +} + +static __inline int +hpt_proc_in(FORMAL_HANDLER_ARGS, int *len) +{ + int i, error=0; + + *len = 0; + if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) { + error = EINVAL; + } else { + i = (req->newlen - req->newidx); + error = SYSCTL_IN(req, hptproc_buffer, i); + if (!error) + *len = i; + (hptproc_buffer)[i] = '\0'; + } + return (error); +} + +static int +hpt_status(FORMAL_HANDLER_ARGS) +{ + int length, error=0, retval=0; + IAL_ADAPTER_T *pAdapter; + + error = hpt_proc_in(REAL_HANDLER_ARGS, &length); + + if (req->newptr != NULL) + { + if (error || length == 0) + { + KdPrint(("error!\n")); + retval = EINVAL; + goto out; + } + + if (hpt_set_info(length) >= 0) + retval = 0; + else + retval = EINVAL; + goto out; + } + + hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION); + for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { + if (hpt_get_info(pAdapter, req) < 0) { + retval = EINVAL; + break; + } + } + + hpt_copy_info(req, NULL); + goto out; + +out: + return (retval); +} + + +#define xhptregister_node(name) hptregister_node(name) + +#define hptregister_node(name) \ + SYSCTL_NODE(, OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \ + SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \ + NULL, 0, hpt_status, "A", "Get/Set " #name " state"); + +xhptregister_node(PROC_DIR_NAME); diff --git a/sys/dev/raid/hptmv/i386-elf.raid.o.uu b/sys/dev/raid/hptmv/i386-elf.raid.o.uu new file mode 100644 index 0000000000..30547940d6 --- /dev/null +++ b/sys/dev/raid/hptmv/i386-elf.raid.o.uu @@ -0,0 +1,1440 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/i386-elf.raid.o.uu,v 1.6 2009/04/07 16:38:25 delphij Exp $ + */ +begin 644 hptmvraid.o +M?T5,1@$!`0D```````````$``P`!``````````````#LQP```````#0````` +M`"@`#``)`%6)Y5=64X'L+`(``(M]"(M'#(F%Y/W__XUWO+`"@'\!`'4*@'\" +M`1G`@^`"0(@&QT8$`````(!.`02+1PR)1@B+5Q"Y`````(E6#(E.$`^V!HL$ +MA0````")1CR`/@-U.(G0BC]__]2:B"+1Q"#Z`I0 +M5^C\____@\00@;WH_?__\Q9X6G09C78`#[8&BP2%`````(E&0(!.`03I>@8` +M`(/L"&B0````C8WH_?__4>C\____@\00A,!US_:%\?W__P)T(L9'"`&*A?+] +M__^(1PLZ1PES$(/L"`^VP%!7Z/S___^#Q!"#[`AH``(``(V%Z/W__U#H_/__ +M_X/$$(3`=!Z#[`1H<`$``&H`C87H_?__!9````!0Z/S___^#Q!"*E7O^__^( +MTX/C`8I'!(/@_(C1@^$""=@)R(C3@^,$@^#SB-�@)V`G(B-.#XQ"#X,^( +MT8/A(`G8"S]__\`#X1N_O__N@`````/MH7S_?__B<&#^`!^+[L````` +MB=#!X`2-O>C]__\!^(!X$`@/AS_^__\/MD`0@SR#``^$,?[__T(YT7_6BX4` +M_O__N@````")A=C]__^)E=S]__^+C8#^__^)R[D`````BX78_?__"`$BXWD_?__C;P(<"(``(-_ +M!`!U#XM'2#N%[/W__P^$60$``$*#^@]^SXN%Y/W__XNX;"(``(7_="N+1PB+ +ME>3]__^)@FPB``"#[`1H\````&H`5^C\____BXWD_?__B4\(@\00BX7L_?__ +MB4=(BE=>@\H!B%=>9@^VA?S]__^#X`'1X(/B_0G"B%=>9HN%_OW__V:)1V"+ +MA=C]__^+E=S]__^)1V2)5VB*A?C]__^(!XJ%^_W__XA'1@^VR+@!````T^!F +MB4=/]__^`O?/]__\!#X9U`@``#[;"BT2' +M;(F%U/W__XN%$/[__[H`````B878_?__B97<_?__BXV(_O__B`0``BY7D_?__ +MBY)L(@``B974_?__A=)T,8M""(N-Y/W__XF!;"(``(/L!&CP````:@!2Z/S_ +M__^+E>3]__^+A=3]__^)4`B#Q!"+A>S]__^+C=3]__^)04B*45Z#R@&(45YF +M#[:%#/[__X/@`='@@^+]"<*(45YFBX4._O__9HE!8(N%V/W__XN5W/W__XN- +MU/W__XE!9(E1:(J%"?[__XA!1(J%"/[__X@!B7D$BX4$_O__B4$,QT$0```` +M`(N%A/[__XG"N``````+00P+41")00R)41"*A0O^__^(04:+E=3]__\/MDI& +MN`$```#3X&:)0EP/M@*+!(4`````B4(\#[8'BP2%`````(E"0(J-X_W__XA* +M`P^VP8E4AVS^1T6#[`1J$(V%Z/W__X/`+%")T`6,````4.C\____@\0,:@2- +MA>C]__^#P#Q0BX74_?__!9P```!0Z/S___^#Q`QJ$(V%Z/W__X/H@%"+A=3] +M__\%X````%#H_/___X/$#&I`C87H_?__@\!`4(N%U/W__P6@````4.C\____ +M@\00]H7Q_?__`70*B[W4_?__@$\!`0^VA0K^__^+E=3]__^#?()L``^%@``` +M`(ET@FR*A0K^__^(1@/^0D6)5@0/M@*+!(4`````B49`BXW<_?__.4IH/]__^(1@,/M@>+!(4`````B49`C67T6UY? +MR<-5B>564XMU#+L`````#[9&1(G"@_@`#XZX````@WR>;`!T"D,YVG_TZ:<` +M``"X`0```(C9T^!F"49@@^P(5O]U".C\____B<*#Q!"%P`^$@0```,8``XA8 +M`XEP!(`^"`^4P,'@`XI*`8/A]PG!B$H!H0P```")0CP/M@:+!(4`````B4)` +M]D8!$'05B,B#R!"(0@&+0E2)0@S'0A``````B52>;(I&7H/@_H/("HA&7L=& +M9`````#'1F@`````_D9%@^P(4FH'Z/S___^`3EX$@\00D(UE^%M>R<.058GE +M5U93@^P,BW4,#[8&@_@&='R#^`9_"X/X!`^,<@$``.L0@_@(#X3#````Z6(! +M``")]HI&13I&1`^%5`$``(!.`02`9E[^OP````"`?D0`#X0]`0``D(M!,=&9`````#' +M1F@`````Z:4```"0BD9%.D9$=1R`3@$$BD9>@^#^B$9>9H-^8`!T:(/(`HA& +M7NM@#[9&14`/ME9$.=!U4V:#?F``="&Y``````^W1F")PJ@!=0E!B=#3^*@! +M=/>#?(YL`'4?ZP;V1EX"=1>`3@$$@$Y>!(/L"%;_=0CH_/___X/$$,=&9``` +M``#'1F@`````#[=&7+H`````@\#_@]+_]]#WTB-&9"-6:(E&9(E6:)"#?@0` +M=1KV1EX$=!3H_/___XE&2(/L#%;H_/___X/$$(UE]%M>7\G#58GE5U93@^P, +MBWT(O@````"-=@"-!':-!(#!X`2-G#AP(@``@WM(`'0B@WL$`'4<@^P(4U?H +M_/___X/$$/9#`01T"<=#0`````")]D:#_@]^PHUE]%M>7\G#B?95B>575E.! +M["@"``"+?0R*11"(A>?]__]7Z/S___^#Q!"`/PAU$H/L"%?_=0CH_/___X/$ +M$(UV`+X`````@']$``^&Q0```)"#?+=L``^$K0```(M$MVR`.`-V((/L!`^V +MA>?]__]0_W2W;/]U".C\____@\00Z84```"0BURW;,9#`P#'0P0`````QT-8 +M`````(!C`?['0T``````@+WG_?__`'4.@#\&=0F#?P0`=#*-=@"#[`1H``(` +M`&H`C97H_?__4NC\____C87H_?__4&HP:@"-0T10Z/S___^#Q"#K$8I7`8/B +M`8I#`8/@_@G0B$,!@^P,4^C\____@\001HGR.%=$#X<\____@^P$:/````!J +M`%?H_/___XM5"(N";"(``(E'"(FZ;"(``,='2`````"#Q!"-9?1;7E_)PU6) +MY5=64X'L'`(``(M5#(M]$(M-%(L"BU@$B9WD_?__BUHDBU,8B97@_?__#[9` +M`XF%W/W__XV5Z/W__X.]X/W__P!T#&8/MD,4@^`!.#]___K@F;'1_X`@+@!````C67T +M6UY?R<.-=@!5B>575E.#[`R+10B+70R+>`2+4RB+2RR)5>B)3>R*2`-FBW,X +M.$LP=1(/MT,VN@`````!1>@15>SK%9`X2S!V#P^W1URZ``````%%Z!%5[#A+ +M,'4'9@-S-(UV`#A+,74'9@-S,HUV`(![/`!T#CA+,',=.$LQ=Q+K%HGV.$LP +MB)5>QFQT8X``#&1CP!#[9#1+H`````4E#_=>S_=>CH +M_/___X/$$`^V2T8/I<+3X/;!('0'B<*X`````(E&*(E6+`^V0T2Z`````%)0 +M_W7L_W7HZ/S___^#Q!"(1C"(P6:+0UQ(9B-&!&:)1C9FBU-<9BG"9CGZ<@MF +MB7XTOP````#K1F:)5C1F*==FQT7F`0"Z`0```(G0T^!F"48Z03A+1'4:L0"` +M?CP`=`;&1CP`ZPQFBT8X9@-#7&:)1CAF.7M<A4!=`:*0A6(0Q6#[`A25NC\____@\009H-[.@!U&H![%0!U +M!,9#%0&#[`13_W,@5NC\____@\00C67X6U[)PU6)Y5=64X/L#(M]#(L'B47P +M]D`!!'49QD<5`H/L!%?_=R#_=0CH_/___^G-````D(/L"%?_=?#H1/[__X/$ +M$&:#?SH`=1K&1Q4"@^P$5_]W(/]U".C\____Z9X```")]KX`````BU7P@'I$ +M``^$B@```(GV#[='.HGQT_BH`71L@^P,_W4(Z/S___^)PXM%\(M$L&R)1>R) +M`XE[)(I7%(/B`HI#%(/@_0G0B$,4BE<4@^($@^#["="(0Q2*1PZ(0PY35_]U +M[.@%_?__QT,@`````,=#'`````"#Q!13_W4(BU7L_U(\@\00C78`1HM-\`^V +M040Y\`^/>/___XUE]%M>7\G#58GE@^P(BU4,BTH$BD$!P.@"@_`!@^`!@&(! +M^X!A`?O^246`25X!@WE``'03A56 +M4XM=$(MU%(M%#(M0)(M*&(7)=`QF#[9"%(/@`3GP=22#>AP`=!564U+_=0C_ +M4AR#Q!"Z`0```(7`=2>Z`````.L@B?:+`8M1!(D#B5,$@\,(C4$&@\$(9H,X +M`'GGN@$```")T(UE^%M>R<.058GE5E.+=0@/M@:#Z`2#^`%W0;L`````@'Y$ +M`'0OB?:#?)YL`'03@^P,_W2>;.C-____@\00A)(L[ +MBP:)1?"`?A4!#X30````]D,4`G1V@'L6``^%P````/9'7@(/A;8```#&0Q8! +M@'@#`1G`@^`$BT0X;(E%\(7`=$-0Z$3___^#Q`2%P'0V@^P$:C1J`(U&*%#H +M_/___XM%\`^V2`.X`0```-/@9HE#.HM%\(D&@\0(5O]U"/]0/.G'````BP:) +M1?#K5/9#%`1T3O]U\.CR_O__@\0$AQ4!=!T/MU,ZBT7P#[9(`[@!````T^`YPG4'D(I& +M%8A#%8/L"%;_=0CH_/___XM%\`^V2`.X_O___]/`9B%#.H/$$&:#>SH`=3Z` +M>Q4`=03&0Q4!@^P$4_]S(/]U".C\____9O]/'H/$$&:#?QX`=1>+1R2%P'00 +M@^P(_W7\G#58GE4X/L!(M5#(M=$(M-%(M")(7) +M=!F+0!")`V:+0@S!X`EFB4,$9L=#!@"`ZT60@W@8`'0F]D`4`70@BT@8D(L! +MBU$$B0.)4P2#PPB-00:#P0AF@S@`>>?K&9"Z`````(-X'`!T$E%34/]U"/]0 +M'(G"ZP6Z`0```(G0BUW\R<-5B>575E.#[`R+10R+6"2)PHL`#[9(`[C^____ +MT\!F(4,Z@'H5`70&BD(5B$,5@^P(_W4,_W4(Z/S___^#Q!!F@WLZ`'5N@'L5 +M`'4XQD,5`8L+B4WPBW%DBWEHBTT,BU$(,?J+000Q\`G"=1@/MT$,N@`````! +M\!'ZBTWPB4%DB5%HB?:#[`13_W,@_W4(Z/S___^+`V;'0!P``(/$#(L#@\`@ +M4&@`````_W4(Z/S___^#Q!"-9?1;7E_)PU6)Y5=64X/L#(M]#(MW)(!_%0%T +M"XI'%8A&%>M[C78`@'\.('4^QD<5`(L&BT!PB0>#[`1J-&H`C4575E.#[`R+?1"+312+50R+0B2%R71# +MBU`0B1>+30QFBT$,P>`)9HE'!&;'1P8`@(L!@'@#``^$\@```(V"```!`&:# +M?P0`=`!P`#X22 +M````45=0_W4(_U`<@\00N@````"%P'1]ZPYFB7$$9L=!!@"`ZSV)]HGYB?:Z +M```!`&:#>00`=`0/MU$$BUT,BP.`>`,`=!$Y\G81`3&)T&8I\&:)003K"SGR +M<[Z#P0@IUG7)BU4,BP*`>`,`="(YSW0>B?:+`8M1!(D'B5<$@\<(C4$&@\$( +M9H,X`'GGC78`N@$```")T(UE]%M>7\G#D%6)Y5=64X/L#(M]"(MU#(M>)(!^ +M%0%T#(I&%8A#%>F5````D(L&@'@#`'4PQD85`(L#BT!PB0:#[`1J-&H`C48H +M4.C\____QD86`(/$"(L&5E?_4#SID0```(GV@^P$#[=&#,'@"5`#0Q!0_W,0 +MZ/S___^#Q!"%P'0&QD,5#.LXQD,5`8L+BT%DBU%HB47HB57LBU7L,U8(BT7H +M,T8$"<)U%@^W1@RZ``````-%Z!-5[(E!9(E1:)"#[`A65^C\____@\0,4_]S +M(%?H_/___XL#9L=`'```@\0,BP.#P"!0:`````!7Z/S___^-9?1;7E_)PY!5 +MB>575E.#[`R+?0B+70R+,\=&)`````#V1EX!#X5^`0``#[9##H/X`@^$$0$` +M`(/X`G\0@_@!#X2C````Z5X!``")]H/X`P^%4P$``(M#!(M3"(E&%(E6&&:+ +M0PQFB48<@^P$#[=##,'@"5!J`/]S$.C\____9L=#.@,`QT7P`````(/$$(/L +M#%?H_/___XG!QD`.,(M#!(M3"(E!!(E1"&:+0PQFB4$,@$D4!(E9),=!(``` +M``#'01P`````BU7PBT26;(D!@\0(45?_4#R#Q!#_1?"#??`!?JOIU````(M# +M!(M3"(E&%(E6&&:+0PQFB48<@^P,5^C\____B<'&0`X@BT,$BU,(B4$$B5$( +M9HM##&:)00R`210"B5DDQT$@`````,=!'`````"+1FR)`8/$"%%7_U`\@\00 +MZW:)]HM#!(M3"(E&%(E6&&:+0PQFB48<@^P,5^C\____B<'&0`X@BT,$BU,( +MB4$$B5$(9HM##&:)00R`210"B5DDQT$@`````,=!'`````"+1FR)`8/$"%%7 +M_U`\@\00ZQ:)]L9#%0:#[`13_W,@5^C\____@\00@^P$C48@4&@`````5^C\ +M____C67T6UY?R<.)]E6)Y5=64X/L'(M]#(LW]D8!!'48QD<5`H/L!%?_=R#_ +M=0CH_/___^F8`0``]D<4('0JQT8D>!8``(E^*&:#?AX`#X5]`0``@^P(5_]U +M".C=_?__@\00Z6D!``"0@WXD`'4^9H-^'`!T4P^W1ARZ``````-&%!-6&#M7 +M"'(_=P4[1P1V.`^W1PRZ``````-'!!-7"#E6&'((=R(Y1A1S'9#'1RP````` +M@^P(5XU&(%#H_/___^D+`0``C78`9O]&'O9&7@-U>O9'%`)T=(M&;(M6<(`X +M`W59@#H#=52+7P2)7>2+2EPI3>2+2&")3>B+4F`K6%QY`O?;@WWD`'D#]UWD +M.UWD?13&1?,`A=)U-H-]Z`5V,,9%\P'K*L9%\P"#?>@`=06#^@5W&\9%\P'K +M%9"`?F(`#Y1%\XI%\XA&8NL$QD7S`&;'1SH``+,`#[;#@WR&;`!T9HM$AFSV +M0`$$=%SV1Q0$=04X7?-U48/L#/]U".C\____B47L@\0,:BA74.C\____#[;+ +MN`$```#3X&8)1SJ+5>R)>B3'0B``````QT(<`````(M$CFR)`H/$"%+_=0C_ +M4#R#Q!")]D.`^P%VBHGVC67T6UY?R<-5B>564XM-"(MU#(M>!`^V5@.`9@'[ +M@$M>`<=#9`````#'0V@`````_DM%@'M%`'4'@&,!^^L9D(I#7J@"=!&#X->( +M0UZ%TG4'@&,!^XUV`/9#`01U&H-[0``/A.H```"#[`A34?]30(/$$.G:```` +MA=)U%(M3;,9"`P&+0W#&0`,`B4-LB5-P@WL$`'0)BT,$]D`!!'1UBT-L@#@# +M=6V#[`A34>C\____B<*#Q!"%P'1:Q@`#QD`#`8E8!*$,````B4(\H1@```") +M0D#V0P$0=!&`2@$0BT)4B4(,QT(0`````,=&!`````")4W"*0UZ#X/Z#R`J( +M0U[^0T6#[`A2:@?H_/___X/$$(GV@WL$`'0+B?:+6P2#>P0`=?>+0U2)0UB+ +M0U")0U2+0TR)0U"+0TB)0TSH_/___XE#2,9#8P&#[`Q3Z/S___^-9?A;7LG# +MC78`58GE5U93@>PL`@``BT4,BTT4BQ")E>3]__^+0"2)A=3]__^+6!C'A>#] +M__\1````C97H_?__A=MT#&8/MD`4@^`!.$)O@```0!F@WL$`'0$#[=S!#GQ=DB0BY7D_?__BD(#B[W4_?__.D3]__^*0@.+O=3]__\Z1S!U&8L#BU40B0)FB4H$9L="!@"`N`$` +M``#K7Y`Y\7,VB<@#`XM]$(D'B?!F*`#4%/_=1#H +M_/___[@!````C67T6UY?R<.)]E6)Y8M5#(M-$(M%"(I``SI",'489HM"-&:) +M00R+0BB+4BR)002)40CK&(GV9HM",F:)00S'000`````QT$(`````,G#58GE +M5U93@^P(BU4(BT4,BU@$BW`(9HM`#&:)1?+'1>P`````N0````"`>D0`#X2< +M````D(M\BFPY=Q!W!W)].5\,=GB+50R)6BB)P!````C4$!BU4,B$(Q08M%[-/@ +M9@E".F:+1PQF*=AFB4(T9HM5\F8IPHG0BU4,9HE",NLDBT4,QD`Q_V:+5?)F +MB5`TZQ,K7PP;=Q!!#[9"1#G(#X=E____BT7L@\0(6UY?R<.)]E6)Y593BW4( +MBU4,BUHDBP(/MD@#N/[____3P&8A0SJ`>A4!=`:*0A6(0Q6#[`A25NC\____ +M@\009H-[.@!U&H![%0!U!,9#%0&#[`13_W,@5NC\____@\00C67X6U[)PU6) +MY5=64X/L#(M]#(L'B47P]D`!!'49QD<5`H/L!%?_=R#_=0CH_/___^G)```` +MD%?_=?#HB_[__X/$"&:#?SH`=1G&1Q4"@^P$5_]W(/]U".C\____Z9T```"0 +MO@````"+5?"`>D0`#X2*````B?8/MT6#[`B+10R+4`2`8`'[ +M@&(!^_Y*18!*7@&#>D``=`^#[`A2_W4(_U)`@\00B?;)PXGV58GE4XM="(M- +M#(N4BXPQ``"%TG0)BP*)A(N,,0``B=!;R<.058GE4XM="(M-#(M5$(N$DXPQ +M``")`8F,DXPQ``!;R<-5B>575E.#[`R+10R[`(```#T`0```=V%FNP!`/0`@ +M``!W5F:[`"`]`!```'=+9KL`$#T`"```=T!FNP`(/0`$``!W-6:[``0]``(` +M`'P`````N`````"!^P`0```/A]8```#_3?"# +M??#_#X3&````D(/L#/]U".C\____B<;_1>R_`````(/$$+@`$```N@````#W +M\X/X``^&BP```(UV`+@*````@?L`0```=U>P"8'[`"```'=-L`B!^P`0``!W +M0[`'@?L`"```=SFP!H'[``0``'564XMU +M"(M=#+@`````.9ZX,0``R<.-=@!5B>564XM="(MU#(L.28/Y_W0?D(M4C@2+@[0Q``")`HF3 +MM#$``/^#N#$``$F#^?]UXFH"5E/HN?W__XUE^%M>R<.)]E6)Y593BW4(BQY+ +M@_O_=!R#[`1H`!```&H`_W2>!.C\____@\002X/[_W7DC67X6U[)PY!5B>53 +MBUT(BPM)@_G_=">+1(L$N@````"#.`!T![@`````ZQ="@\`$@?K_`P``=NA) +M@_G_==FX`0```%O)PXGV58GE@^P,:A!J`/]U".C\____R<-5B>6+30R#>10` +M=`F+412+01")0A"+41"+012)`L=!$`````!J`%'_=0CH^?S__\G#C78`58GE +M4XM5"(M-#(U:.(M".(E!%(7`=`F+4CB-012)0A")61")"UO)PU6)Y5=64XMU +M&(M]'(M%#(M8.(7;="V)]CE[!'575E.#[!R*10R(1?.+51AFB57P +MBT4(BYBX,0``P>,##[?*#[95\XU"_='X`<(/K\HYRP^#X0````^V5?.)5>2) +MT(E5X`^W5?"-0/W1^`-%Y(G3#Z_8BT4(!70Q``"+50@Y@G0Q```/A,L```"+ +MLG0Q``"+5@2+!HE0!(D"B3:)=@2#?A``=!Z#?A0`=`F+5A2+1A")0A"+5A"+ +M1A2)`L=&$`````"+1?!F.48H=4N*5?,X5BIU0XDVB78$BT40BU44B48@B58D +MOP````"#?>0`?B"+7>"#[`R)^,'@!(V$,%@(``!0Z*/]__^#Q!!'.?M_XXGP +MZ1L!``!6_W4(Z*/^__^#Q`B+50B+@K@Q``#!X`,YV`^"//___VH'_W4(Z(+Z +M__^)QH/$"+@`````A?8/A-\```#K"K@`````Z=,```")-HEV!(M%$(M5%(E& +M((E6)(M5\&:)5BB*1?.(1BK'1A@`````OP`````/MM"-0OW1^`'"@_H`#XZ4 +M````BT7P9L'H`P^WP(E%Z`^V5?.-0OW1^`'"B57L_W7H_W4(Z,7[__^)A+ZP +M!P``@\0(AAJ!U;_ +M=0CH[?G__[@`````ZS&)]H/L#(G[P>,$`?.-@]@'``!0Z)+\__^!PU@(``") +M'"3HA/S__X/$$$Q_AXGPC67T6UY?R<.058GE5U93@^P,BW48BT4,#[9( +M1HM%$-/H)?\#``"+30R+432-'(*+.X7_="^+510S5R2+11`S1R`)PG48BU<$ +MBP>)4`2)`HD_B7\$B?CIF0```(GVBW\4A?]UT8/L#`^WQE#_=13_=1"+50P/ +MMD)$4/]U".AH_?__B<>#Q""%P'1HBTT,B4@7\G# +MD%6)Y5=64X'LS````(M%#(I0%(C0T.B#\`&)P8/A`8F-5/___XM%#(-X&`!T +M!?;"`70@C958____B950____:@%2_W4,_W4(BTT,_U$<@\00ZPR+10R+0!B) +MA5#____'A3C___\```$`BY50____9H-Z!`!T"@^W2@2)C3C____'A4#___\` +M````QX5,____`````(M%#(!X2``/A-P!``"+E4S___^+30R+5)$TB95$____ +MBHHP"0``B(U+____.(HQ"0``#X*8`0``BH5+____BY5$____.$(K#X1E`0`` +M#[;`B=%FBY2"$`D``&:+A($2"0``9HF%/O___XG09L'H`P^WP(F%-/___X/B +M!V:)E3S___\/M\*)PL'B";@(````9BN%//___V:)A3S___]FBX4^____9CF% +M//___W8'9HF%//___P^WA3S___^)QL'F"0^VA4O___^+C43___^+A(&P!P`` +MB=>+C33___\#?(@$D(N%./___SF%0/___W4R@X50____",>%./___P```0"+ +ME5#___]F@WH$`'0*#[=*!(F-./___\>%0/___P````"+G3C___\KG4#___\Y +M\W8"B?.#O53___\`="&#[`13BX5`____BY50____`P)05^C\____@\00ZQ^- +M=@"#[`135XN%0/___XN-4/___P,!4.C\____@\00`9U`____*=YT!P'?Z5?_ +M__^+A3S___]F*84^____=!G_A33___^Z`````&;'A3S___\(`.GK_O___H5+ +M____BI5+____BXU$____.)$Q"0``#X-H_O___X5,____BU4,#[9"2#N%3/__ +M_P^/)/[__X/L!&H`_W4,_W4(_U40C67T6UY?R<.)]E6)Y5=64X/L#(-]$`!T +M!XM%#,9`%0O'1?``````BU4,@'I(``^$P0```(M%"`5\,0``B47LBU4(@<)T +M,0``B57HC78`BT7PBU4,BUR"-,>#"`D```````")W[$`@'LJ`'9!B?8/ML'! +MX`0!^(V0V`<``+X`````@[C8!P```'44@WH$`'4.@WH(`'4(@WH,`'0'B?:^ +M`0```(7V=2%!.$\J=\&X`````(7`=!R+5>R+0@2)6@2)$XE#!(D8ZQJX`0`` +M`.OCC78`BU7HBT($B5H$B1.)0P2)&/]%\(M5#`^V0D@[1?`/CUG___^#[`C_ +M=0S_=0CH0T```(UE]%M>7\G#C78`58GE5U93@^P\BW4,B[X("0``BT4(_XB\ +M,0``C48(BT@$BU8(B4H$B1&)1@B)0`2%_P^$Y0(``/9'%"`/A)QX8("0```````(M%"`5T +M,0``BU`$B7`$B0:)5@2),H"^,@D```%U@/MT)<]]B9BTX@(<&+7B0ATXM% +MZ#E8:'(B=P4Y2&1V&XM5Z`^W0ESWV)DC1B`C5B2+3>B)062)46B)]H"^,@D` +M``%T&HJ&,@D``(A'%8/L"%?_=0CH)C\``.FI`P``BT7H#[=`7(E%N,=%O``` +M``"+3P2+7PB#P0&#TP"+1;CWX8E%T(E5U(M5N`^OTXMUU`'6BT6\#Z_!C00& +MB474BTWD.4/]UY/]UX/]UZ/]U".CT^?__ +MB;@("0``B4@/MT%0QT3-%X`G!=0^+1>"+5>2+3>B)062)46B#[`A7_W4(Z&4^``#IZ`(``(I' +M24"(1TDZ1T@/A60"``#V1Q0$#X3"````QD7O`(!_2``/AJ````"+10@%=#$` +M`(E%Q(M5"('"?#$``(E5P)`/MD7OBW2'-,>&"`D```````"`OC()```!=46) +M=`$BTW(C80(V`<``%#HB_7__X/$$$.+1<@X +M6"IWVXM5Q(M"!(ER!(D6B48$B3#K&I"*AC()``"(1Q6+3<"+002)<02)#HE& +M!(DP_D7OBD7O.$=(#X=X____@^P(5_]U".B,/0``@\00Z9@!``#&1>\`@']( +M`'8GB?8/MD7OBW2'-("^,@D```%T"8J&,@D``(A'%?Y%[XI5[SA72'?;@'\5 +M`'49@^P$:)0I``!7_W4(Z&SY__^#Q!#I2`$``(/L!&H`5_]U".CJ^___@\00 +MZ3(!``")]H"^,@D```%U=XGWLP"`?BH`=B"0@^P,#[;#P>`$C80XV`<``%#H +MGO3__X/$$$,X7RIWX8.^#`D```!T*HN&#`D``(F&"`D``,>&#`D```````"# +M[`A6_W4(Z-H-``"#Q!#IR@```(M%"`5T,0``BU`$B7`$B0:)5@2),NM7C78` +MBT4(!7PQ``"+4`2)<`2)!HE6!(DR@[X,"0```'0VBY8,"0``BH8R"0``B$(5 +M@^P$_[8,"0``:-!J``#_=0CH_/___\>&#`D```````#IT@```(GV_W88_W4( +MZ/WS___'1A@`````BT8<@\0(@W@@`'09@^P$@\`@4&@`````_W4(Z/S___^# +MQ!#K)8M-"(.YQ#$```!T&8/L!(G(!<0Q``!0:`````!1Z/S___^#Q!"+10B# +MN,`Q````=&B`OC()```!=5^+1AR#>"P`=#V#[`Q0Z#$Z``"#Q!"%P'4M@^P$ +MBT8<_W`PBT8<_W`L_W4(Z/S___^+1AS'0"P`````BU4(_XK`,0``@\00BTT( +M@[G`,0```'0-@^P,4>C\____@\00D(UE]%M>7\G#58GE@^P(BT4,BP"`>"X` +M=!O&0"X`@^P$4&B(.0``_W4(Z/S___^#Q!"-=@#)PXGV58GE5U93@^P,BU4, +MBWT0BT(DBP@/MD`)BX2!L`<``(E%\(M"!"M!(,'@"0^W<@S!Y@F)PH'B_P\` +M`,'H#(E%[+@`$```B<,ITSGS=@*)\X-]%`!T#XM%[(M-\`-4@03K&XUV`(/L +M#(M%[(M-\`-4@012Z/S___^#Q!")PHD79HE?!#GS=!5FQT<&``"#QPC_1>PI +MWKH`````ZZ5FQT<&`("X`0```(UE]%M>7\G#B?95B>575E.+50B*0@H"0@N( +M0@J-6@R^`0```.L3@'H*`'D*N`````#I\@```/Y""@^V2@J#^1]W$(GPT^"% +M0@P/E<`/ML#K39"#^3]W$X/I((GPT^"%0P0/E<`/ML#K-9"#^5]W$X/I0(GP +MT^"%0P@/E<`/ML#K'9"X`````(/Y?W<2@^E@B?#3X(5##`^5P`^VP(GVA@P/MEH*O@$```#K!8GV_D(+#[9""XT,`X/Y'W<1B?#3X(5"#`^5 +MP`^VP.M.B?:#^3]W$X/I((GPT^"%1P0/E<`/ML#K-9"#^5]W$H/I0(GPT^"% +M1P@/E<`/ML#K';@`````@_E_=Q.#Z6")\-/@A4<,#Y7`#[;`C78`A0@'L$`75"BD,(.$8K +M=#HX0PEU-0^VR(G(P>`$C8PP6`@``(US#(L!"T,,B0&+000+1@2)002+00@+ +M1@B)00B+00P+1@R)00R0QD,%`H/L"%-7Z%[]__^-9?1;7E_)PXGV58GE4X/L +M!(M=#,9#"P#&0PH`4^@<_O__@^P$4_]U".@(````BUW\R<.-=@!5B>575E.# +M[!B+70R+,XM6'`^V0PB+?()L_W4(Z/S___^)P8DX@\00@'L$`74*@$@4`L9` +M#B#K"(!(%`3&0`XP#[9#"KH``````T8@$U8DB4$$B5$(9@^V0PMFB4$,QT$< +MD"\``(E9),=!(&0Q``"#[`A1_W4(_U<\C67T6UY?R<.-=@!5B>575E.#[`B+ +M?0R^`````,=%\`````"+10B)1>SK$X-]\']V"HGPZ4R%0@@/E<`/ML#K(+@````` +M@_I_=Q:-2J"P`=/@BU7LA4(,#Y7`#[;`C78`A<`/A&S___^[`0```(M5".L# +MB?9#BTWP`=F#^1]W$;@!````T^"%`@^5P`^VP.M4@_D_=Q>#Z2"X`0```-/@ +MA4($#Y7`#[;`ZSJ)]H/Y7W<7@^E`N`$```#3X(5""`^5P`^VP.L>B?:X```` +M`(/Y?W<2@^E@L`'3X(5"#`^5P`^VP(GVA( +MT(/@!XA$MP&Q""C!B$RW`@^VP3G88) +MBH2=Z/[__XB%T_[__P^VT(G(B[W8_O__`T27!(F%X/[__XN%U/[__XM\D`0! +MSXF]M/[__XF]Y/[__XN%W/[__XM\D`0!SSF]X/[__W4D@^P$5O^UM/[__XG( +MB[7<_O__`T26!%#H_/___X/$$.LJC78`5O^UY/[___^UX/[__P^VA=/^__^+ +MO=S^__\#3(<$4>C\____@\000SN=S/[__P^,0/___^FM````C78`C87H_O__ +M4%/H'_W__XF%S/[__P^V0Q2+A(:P!P``B87<_O__BU4,#[9"#(N$AK`'``") +MA=C^__^[`````(/$"#N=S/[__WUB#[:$G>G^__^)P<'A"0^VA)WJ_O__B<;! +MY@D/MI2=Z/[__XG(B[W<_O__`T27!(F%X/[__XG(B[W8_O__`T27!(F%Y/[_ +M_X/L!%90_[7@_O__Z/S___^#Q!!#.YW,_O__?)Z#[`1J`/]U#/]U".AJ`@`` +MC67T6UY?R<.)]E6)Y5=64X'L+`$``(M%#(L8C87H_O__4(M%#(/`"%#H1/S_ +M_XF%V/[__XM5#`^V0AB+A(.P!P``B87<_O__#[9"&8N$@[`'``")A=3^__^^ +M`````(/$"#NUV/[__WU=D`^VA+7I_O__P>`)#[:,M>K^___!X0D/MIRUZ/[_ +M_XG"B[W<_O__`U2?!(F5X/[__XN5U/[__P-$F@2)A>3^__^#[`114/^UX/[_ +M_^C\____@\001CNUV/[__WRD@^P$:@#_=0S_=0CHE`$``(UE]%M>7\G#58GE +M5U93@>Q\`0``BT4,BS"+6`B-A>C^__]04^AS^___B864_O__#[9#%(N$AK`' +M``")A:3^__^Q`(/$"(M5#(!Z%`!V)(I:%(UV``^VP8M]#`^V5`<,BY26L`<` +M`(F4A%F/[__P````"+A93^__\YA9C^__\/C>X```")]HN5 +MF/[__P^VA)7I_O__BC^__^(C9_^ +M__^Q`(M=#(![%`!V,0^VM9_^__^*0Q2(A8?^__\/ML&+E(7(_O__BURR!(T4 +M'XF4A:C^__]!.(V'_O__=]\/MI6?_O__B?B+C:3^__\#1)$$.86H_O__=2"# +M[`3_M:#^____M:S^__^)^`-$D010Z/S___^#Q!#K+/^UH/[___^UK/[___^U +MJ/[__P^VA9_^__^+G:3^__\#?(,$5^C\____@\00_X68_O__B[V4_O__.;V8 +M_O__#XP4____@^P$:@#_=0S_=0CH"````(UE]%M>7\G#58GE5U93@^P4BWT( +MBUT,BW40QD,%`H/^`1G`@^#U@\`,B$,&4U?H@?;__X/$$(![!`-U,(M#"(M0 +M$(72=";'0!``````QD(%`H/^`1G`@^#U@\`,B$(&@^P(4E?H2_;__X/$$(UE +M]%M>7\G#58GE5E.+70B+=0P/MDX'A`4"=`FX`````.LKB?:`>`8!=!+&1@4"BD`&B$8&N`````#K$I`/MHQ+ +MP08``(7)=;BX`0```%M>R<.-=@!5B>575E.#[!R+?0S&1RX`@+\S"0```'1[ +MO@````"-7S"`?RT`=$F0@'L%`74V@'L$`W4EBT,(@'@5`'0<@W@0`'06QT`0 +M`````,9#!0**AS()``"(0P;K"\9'+@'I]P$``(GV1H/#'`^V1RTY\'^X@^P( +M5_]U".B4\/__Z=@!``"*0P:(AS()``#&AS,)```!ZX:0QT7P`````,=%[`$` +M``"^`````(U?,(!_+0`/A'P!``"`>P4`#X66````4U?HT_[__X/$"(7`='S& +M0P4!BT4(B47HB=H/MD,$@_@&=V?_)(4`````@^P(4_]UZ.B0]___@\00ZT^# +M[`A3_W7HZ*OY__^#Q!#K/H/L"%/_=>CHMOO__X/$$.LM@^P(4_]UZ.AY_/__ +M@\00ZQS&1R\!QD(%`L9"!@&#[`A2_W7HZ)3T__^#Q!"0@'L%`G4,_T7PC78` +M@'L%`G0.QT7L`````.FZ````B?:`>P8!#X2N````@'\O``^$!?___XM''`^V +M4PB+1)!L]D`!!`^$B````,=%[`````#&0P4!QD,&`(M%"(E%Y(G:#[9#!(/X +M!G=O_R2%'````(/L"%/_=>3HP/;__X/$$.M7@^P(4_]UY.C;^/__@\00ZT:# +M[`A3_W7DZ.;Z__^#Q!#K-8/L"%/_=>3HJ?O__X/$$.LDQDP`=!7&AS()```!@^P(5_]U".B][O__ZP3&1RX!C67T6UY?R<.- +M=@!5B>575E.![&P!``"+10R+>!R+D`@)``")E<3^___&A:W^__\`A=)U.XG! +M#[=`*+H`````B`742BT=DBU=H.U,D<@=W*CM#(' +M`G0BBT=DBU=HBTT,.U$D=Q1R!3M!('<-BUT,BD,KB$,LZPF)]HMU#,9&+`B+ +M?0S&1RT`QH?`!@```,9'+P#&AS()````QH'#`D```````"#O<3^ +M__\`#X1^$P``BX7$_O__]D`4(`^$=@D```^V0`Z#^`(/A(P%``"#^`)_#H/X +M`0^$1`$``.DN*@``@_@##X4E*@``@^P,C9W8_O__4^@&Y?__@\00OP````"+ +M50P/MW(HLP"#_Q]W4@^VPXV4A=C^__^)O:C^__^Y(````"GY.?%V`HGQ@_D@ +M=0C'`O_____K$K@!````T^!(BHVH_O__T^`)`K@@````*?@Y\',4C70^X+\` +M````ZP.#[R!#@/L#=J"#[`R+70S_L[`'``#H$.3__\:%K_[__P"#Q!"`>RH` +M#X:`*0``@^P,#[:=K_[__\'C!`-=#(V#V`<``%#H5.3__X'#6`@``(D<).A& +MY/__@\00_W4,Z!_E__^#Q`3&0`0"BI6O_O__B%`(QD`)`(N5V/[__XE0#(N5 +MW/[__XE0$(N5X/[__XE0%(N5Y/[__XE0&/Z%K_[__XJ-K_[__XM=##A+*@^' +M>____^GV*```N`$```#K38MU#+$`@'XJ`'8]#[;!P>`$`?"-D-@'``"[```` +M`(.XV`<```!U$H-Z!`!U#(-Z"`!U!H-Z#`!T!;L!````A=MUMT$X3BIWP[@` +M````A&"`D```````#IH!$``(/L#(V=V/[_ +M_U/H8>/__X/$$+\`````BT4,#[=P*+,`@_\?=U(/ML.-E(78_O__B;VD_O__ +MN2`````I^3GQ=@*)\8/Y('4(QP+_____ZQ*X`0```-/@2(J-I/[__]/@"0*X +M(````"GX.?!S%(UT/N"_`````.L#@^\@0X#[`W:@BUT,@'LL"'4&BD,KB$,L +MBW4,BEXLB)[L"```QH;M"````8N%V/[__XF&V`@``(N%W/[__XF&W`@``(N% +MX/[__XF&X`@``(N%Y/[__XF&Y`@``,>&Z`@```````!6Z'+C__^#Q`3&0`0" +MB%@(B%@)BY78_O__B5`,BY7<_O__B5`0BY7@_O__B5`4BY7D_O__B5`8B<>` +M?BH"#X=4`0``B?.!P]@(``!6Z"?C__^#Q`3&0`0%B5@(QD`4`(F%O/[__XL? +M_H/`!@``#[:SP`8``(G"*=J#ZC#!^@*-!-*-!,*-!,*-!,*)P<'A#P'(C03" +M]]B(A'/`!@``BD<'B(1SP08``(GPB$<'QH6O_O__`(M5#(!Z*@`/AN0F``"* +MC:_^__^+70PX2RP/A*@```!3Z*#B__^#Q`3&0`0!BI6O_O__B%`(B%`)BY78 +M_O__B5`,BY7<_O__B5`0BY7@_O__B5`4BY7D_O__B5`8BXV\_O__BE$4#[;* +MBIVO_O__B[6\_O__B%P.#$*(5A2+'OZ#P`8```^VL\`&```IV(/H,,'X`HT4 +MP(T4T(T4T(T4T(G1P>$/`(A'/!!@`` +MB?"(1P?^A:_^__^*E:_^__^+30PX42H/AR[____I#28``,:%K_[__P"+70R` +M>RH`#X;Y)0``@@0`=0Z#>@@`=0B#>@P`=`>)]KL!````A=MULT$X +M3BIWP;@`````A#"`D```````#I8@T``(/L +M#(V=V/[__U/H(]___X/$$+\`````BT4,#[=P*+,`@_\?=U(/ML.-E(78_O__ +MB;V<_O__N2`````I^3GQ=@*)\8/Y('4(QP+_____ZQ*X`0```-/@2(J-G/[_ +M_]/@"0*X(````"GX.?!S%(UT/N"_`````.L#@^\@0X#[`W:@BUT,BD,KB(/L +M"```QH/M"````(N%V/[__XF#V`@``(N%W/[__XF#W`@``(N%X/[__XF#X`@` +M`(N%Y/[__XF#Y`@``,>#Z`@```````"`>RH"#X<``0``BUT,@__^#Q`3&0`0!BI6O_O__B%`(B%`)BY78_O__B5`,BY7<_O__B5`0 +MBY7@_O__B5`4BY7D_O__B5`8BXV\_O__BE$4#[;*BIVO_O__B[6\_O__B%P. +M#$*(5A2+'OZ#P`8```^VL\`&```IV(/H,,'X`HT4P(T4T(T4T(T4T(G1P>$/ +M`(A'/!!@``B?"(1P?^A:_^__^*E:_^ +M__^+30PX42H/AS[____I:R(``(MU#(I>*U;H,][__X/$!,9`!`&(6`B(6`F+ +ME=C^__^)4`R+E=S^__^)4!"+E>#^__^)4!2+E>3^__^)4!B)A;C^___&A:_^ +M__\`@'XJ``^&%R(``(GW@*@^'T/[__^G:(```B?:#O<3^__\`#X3K"0``B[W$_O__]D<4`@^$VPD` +M`(M%#(J`,`D``(B%K_[__XM5##B",0D```^"B`$``)"*C:_^__^+70PX2RL/ +MA%H!``"#[`P/MMF)V,'@!(VT!6C___]6Z&+;__^#Q!")M9C^__^+=0P/MY2> +M$`D```^WO)X2"0``O@````"0@_H?=U>)\0^VP8N-F/[__XT<@8F5E/[__[D@ +M````*=$Y^78"B?F#^2!U"<<#_____^L3D+@!````T^!(BHV4_O__T^`)`[@@ +M````*=`Y^',6C7P7X+H`````ZP.#ZB!&B?.`^P-VF0^VG:_^__^)VHG8P>`$ +MBW4,C9PP6`@``(L+]]&)C=C^__^+0P3WT(F%W/[__XM#"/?0B87@_O__BT,, +M]]")A>3^__^)UL'F!(V<->C^__^-E#5H____(PJ)"XM"!".%W/[__XE#!(M" +M"".%X/[__XE#"(M"#".%Y/[__XE##(J%K_[__XM5##A"+'4MN@````"#.P!U +M$H-[!`!U#(-["`!U!H-[#`!T!;H!````A=)T",:%K?[__P&0_H6O_O__BHVO +M_O__BUT,.(LQ"0``#X-Y_O__@+VM_O__``^$9`<``(/L#(V%V/[__U#HZ=G_ +M_\:%K_[__P"#Q!"+=0R`?BH`=G>)]HJ%K_[__XM5##A"+'13.$(K=$X/MM#! +MX@0#50R-BM@'``"+A=C^__\+@M@'``")A=C^__^+A=S^__\+002)A=S^__^+ +MA>#^__\+00B)A>#^__^+A>3^__\+00R)A>3^___^A:_^__^*C:_^__^+70PX +M2RIWBXMU#`^V?BS!YP2-G#WH_O__B[78_O__(S.)M#^__\C4PB)E=#^__^+A>3^__\C0PR)A=3^___WUHFUV/[___?1 +MB8W<_O__]]*)E>#^___WT(F%Y/[__R,SB;78_O__(TL$B8W<_O__(U,(B97@ +M_O__(T,,B87D_O___W4,Z*S9__^#Q`3&0`0`B86P_O__N`````"#O=C^__\` +M=1N#O=S^__\`=1*#O>#^__\`=0F#O>3^__\`=`6X`0```(7`#X0\`@``BWT, +MBD'Z`@```````#&A:_^__\`@'\J``^&I@(` +M`(J%K_[__XM5##A"+`^$KP$``#B",`D``'<-.((Q"0``<@4X0BMU1_]U#.C< +MV/__@\0$QD`$`8J-K_[__XA("(A("8N5V/[__XE0#(N5W/[__XE0$(N5X/[_ +M_XE0%(N5Y/[__XE0&(F%P/[__^MW#[:-K_[__\'A!(V<#>C^__^+A=C^__\+ +M`XD#BX7<_O__"T,$B4,$BX7@_O__"T,(B4,(BX7D_O__"T,,B4,,_W4,Z%;8 +M__^#Q`3&0`0!BI6O_O__B%`(B%`)BQ.)4`R+4P2)4!"+4PB)4!2+4PR)4!B) +MA<#^__^+70R!P]@(``#_=0SH%=C__X/$!,9`!`.)6`B*C:_^__^(2`R)A;S^ +M__^+&/Z#P`8```^VL\`&``"+E<#^__\IVH/J,,'Z`HT$THT$PHT$PHT$PHG! +MP>$/`(A'/!!@``B?"(1P>*E:_^__^+ +M30PX42MU4XNUL/[__XL>_H/`!@``#[:SP`8``(GZ*=J#ZC#!^@*-!-*-!,*- +M!,*-!,*)P<'A#P'(C03"]]B(A'/`!@``B[VP_O__BD<'B(1SP08``(GPB$<' +M_H6O_O__BI6O_O__BTT,.%$J#XC^__^Z`````(,X`'42@W@$`'4,@W@(`'4&@W@,`'0%N@$```"% +MTG1##[:%K_[__\'@!(VC^____=0SHI];__X/$!,9`!`&*C:_^__^(2`B( +M2`F+$XE0#(M3!(E0$(M3"(E0%(M3#(E0&/Z%K_[__XJ=K_[__XMU##A>*@^' +M3/___[@`````@[W(_O__`'4;@[W,_O__`'42@[W0_O__`'4)@[W4_O__`'0% +MN`$```"%P`^$6QH``(M%#(I`+(B%D_[__XM5#(B"!`D``(N%R/[__XF"\`@` +M`(N%S/[__XF"]`@``(N%T/[__XF"^`@``(N%U/[__XF"_`@``,:"!0D```#' +M@@`)````````BEHK4NC0U?__@\0$QD`$`8A8"(J-D_[__XA("8N5R/[__XE0 +M#(N5S/[__XE0$(N5T/[__XE0%(N5U/[__XE0&(F%N/[__\>%M/[__P````#& +MA:_^__\`BUT,@'LJ``^&H1D``(J%K_[__XM5##A"+`^$S`$``#A"*P^$PP$` +M`(I:*U+H4=7__X/$!,9`!`&*C:_^__^(2`B(6`F+E$/`(A'/!!@``B?"(1P>#O;3^__\`=$N+'_Z#P`8```^VL\`&``"+E;3^ +M__\IVH/J,,'Z`HT$THT$PHT$PHT$PHG!P>$/`( +MA'/!!@``B?*(5P>+70R!P_`(``"+30R*22N(C9+^____=0SH4M3__X/$!,9` +M!`.)6`B*G9+^__^(6`R)A;S^__^)A;3^__^+&/Z#P`8```^VL\`&``"+E<#^ +M__\IVH/J,,'Z`HT$THT$PHT$PHT$PHG!P>$/`(A'/!!@``B?"(1P>+'_Z#P`8```^VL\`&``"+E;C^__\IVH/J,,'Z +M`HT$THT$PHT$PHT$PHG!P>$/`(A'/!!@``B?*( +M5P?^A:_^__^*C:_^__^+70PX2RH/APK^___IIA<``(GVBT4,BH`P"0``B(6O +M_O__BU4,.((Q"0``#X*&%P``B?:*C:_^__^+70PX2RMT=@^VP<'@!(V$!>C^ +M__^Z`````(,X`'43@W@$`'4-@W@(`'4'@W@,`'0&D+H!````A=)T0P^VA:_^ +M___!X`2-G`7H_O___W4,Z/[2__^#Q`3&0`0!BI6O_O__B%`(B%`)BQ.)4`R+ +M4P2)4!"+4PB)4!2+4PR)4!C^A:_^__^*C:_^__^+70PXBS$)```/@V'____I +MX!8``(MU#(!^+``$`="-D-@' +M``"Y`````(.XV`<```!U$H-Z!`!U#(-Z"`!U!H-Z#`!T!;D!````A*@^'2/___P^VE:[^__^+?0P/MD$/`(A'/!!@``B?"(1P>+ +M50R`>BH"#X?6`@``B=.!P]@(``!2Z*_0__^#Q`3&0`0%B5@(QD`4`(F%O/[_ +M_XN-L/[__XL9_H/`!@``#[:SP`8``(G"*=J#ZC#!^@*-!-*-!,*-!,*-!,*) +MP<'A#P'(C03"]]B(A'/`!@``B[VP_O__BD<'B(1SP08``(GPB$<'QH6O_O__ +M`(M5#(!Z*@`/AF`4``"*C:_^__^+70PX2RL/A!X"``"+M;S^__^*1A0/MM"( +M3!8,0(A&%`^VV<'C!(M]#(T$.XV(6`@``(N06`@``/?2B97(_O__BT$$]]") +MA`$C9P%Z/[___]U#.A/S___@\0$QD`$`8J5K_[__XA0"(A0"8L3B5`,BU,$ +MB5`0BU,(B5`4BU,,B5`8BXV\_O__BQG^@\`&```/MK/`!@``*=B#Z##!^`*- +M%,"-%-"-%-"-%-")T<'A#P'*C130]]J(E'/`!@``B[V\_O__BD<'B(1SP08` +M`(GPB$<'#[:%K_[__\'@!(M5#(V$$-@'``"Z`````(,X`'42@W@$`'4,@W@( +M`'4&@W@,`'0%N@$```"%T@^$DP````^VG:_^__^)V,'@!(M-#(V<"-@'``!1 +MZ'O.__^#Q`3&0`0"BI6O_O__B%`(B%`)BQ.)4`R+4P2)4!"+4PB)4!2+4PR) +M4!B)QXL8_H/`!@``#[:SP`8``(N5L/[__RG:@^HPP?H"C032C03"C03"C03" +MB<'!X0\!R(T$PO?8B(1SP`8``(I'!XB$<\$&``")\8A/!_Z%K_[__XJ=K_[_ +M_XMU##A>*@^'N/W__^D3$@``QH6O_O__`(M]#(!_*@`/AO\1``"-=@"*A:_^ +M__^+50PX0BL/A(X"```/MOC!YP2-!!>-B%@(``"+D%@(``#WTHF5R/[__XM! +M!/?0B87,_O__BT$(]]")A=#^__^+00SWT(F%U/[__XV,/>C^__\CE=C^__^) +M$8N%W/[__R.%S/[__XE!!(N%X/[__R.%T/[__XE!"(N%Y/[__R.%U/[__XE! +M#(M=#('#V`@``/]U#.@SS?__@\0$QD`$`XE8"(J-K_[__XA(#(F%O/[__XNU +ML/[__XL>_H/`!@``#[:SP`8``(G"*=J#ZC#!^@*-!-*-!,*-!,*-!,*)P<'A +M#P'(C03"]]B(A'/`!@``BY6P_O__BD('B(1SP08``(GQB$H'C80]Z/[__[H` +M````@S@`=1*#>`0`=0R#>`@`=0:#>`P`=`6Z`0```(72#X24````#[:%K_[_ +M_\'@!(VC^____=0SH?LS__X/$!,9`!`&*E:_^__^(4`B(4`F+$XE0#(M3 +M!(E0$(M3"(E0%(M3#(E0&(N-O/[__XL9_H/`!@``#[:SP`8``"G8@^@PP?@" +MC13`C130C130C130B='!X0\!RHT4T/?:B)1SP`8``(N]O/[__XI'!XB$<\$& +M``")\(A'!P^VA:_^___!X`2+50R-A!#8!P``N@````"#.`!U$H-X!`!U#(-X +M"`!U!H-X#`!T!;H!````A=(/A)8````/MIVO_O__B=C!X`2+30R-G`C8!P`` +M4>BJR___@\0$QD`$`HJ5K_[__XA0"(A0"8L3B5`,BU,$B5`0BU,(B5`4BU,, +MB5`8B<>+&/Z#P`8```^VL\`&``"+E;#^__\IVH/J,,'Z`HT$THT$PHT$PHT$ +MPHG!P>$/`(A'/!!@``B?&(3P>-=@#^A:_^__^* +MG:_^__^+=0PX7BH/ATC]___I/P\``(M]#(I?*U?H!\O__\9`!`&(6`B(6`F+ +ME=C^__^)4`R+E=S^__^)4!"+E>#^__^)4!2+E>3^__^)4!B)A;C^__^*7RN) +M/"3HR,K__X/$!,9`!`*(6`B(6`F+E=C^__^)4`R+E=S^__^)4!"+E>#^__^) +M4!2+E>3^__^)4!B)Q_]U#.B-RO__@\0$QD`$!HF%L/[__XL?_H/`!@``#[:S +MP`8``(G"*=J#ZC#!^@*-!-*-!,*-!,*-!,*)P<'A#P'(C03"]]B(A'/`!@`` +MBD<'B(1SP08``(GPB$<'QH6O_O__`(M5#(!Z*@`/AE$.``"0BHVO_O__BUT, +M.$LK#X1J`P``#[;!P>`$`=B-D-@'``"Y`````(.XV`<```!U$H-Z!`!U#(-Z +M"`!U!H-Z#`!T!;D!````A+&/Z# +MP`8```^VL\`&``"+E;#^__\IVH/J,,'Z`HT$THT$PHT$PHT$PHG!P>$/`(A'/!!@``B?&(3P>)]OZ%K_[__XJ=K_[__XMU##A> +M*@^';/S__^FW"@``C78`BWT,BD@0`=0R#>@@`=0:#>@P`=`6Y`0```(7)=$@'QO__@\0$QD`$`HJ5K_[__XA0"(A0"8L3B5`,BU,$B5`0BU,(B5`4 +MBU,,B5`8D/Z%K_[__XJ-K_[__XM=##A+*@^'7/___^GK"0``@^P,C878_O__ +M4.C,Q/__@\00_W4,Z*7%__^#Q`3&0`0&B86P_O__QH6O_O__`(MU#(!^*@`/ +MAE0!``"*A:_^__^+50PX0BL/A"H!```/ML#!X`0!T(V0V`<``+D`````@[C8 +M!P```'42@WH$`'4,@WH(`'4&@WH,`'0%N0$```"%R0^$[P````^VE:_^__^) +MT8G0P>`$BUT,C908V`<``(N%V/[__PL"B878_O__BX7<_O__"T($B87<_O__ +MBX7@_O__"T((B87@_O__BX7D_O__"T(,B87D_O__BH6O_O__.$,L#X2-```` +MB+&/Z#P`8```^VL\`&``"+E;#^__\IVH/J +M,,'Z`HT$THT$PHT$PHT$PHG!P>$/`(A'/!!@`` +MB?.(7P>0_H6O_O__BH6O_O__BU4,.$(J#X>L_O__BTT,BEDK4>@DQ/__@\0$ +MQD`$`HA8"(A8"8N5V/[__XE0#(N5W/[__XE0$(N5X/[__XE0%(N5Y/[__XE0 +M&(G'BQC^@\`&```/MK/`!@``BY6P_O__*=J#ZC#!^@*-!-*-!,*-!,*-!,*) +MP<'A#P'(C03"]]B(A'/`!@``BD<'B(1SP08``(GSB%\'BW4,#[9>+(G>B=C! +MX`2+?0R-G#A8"```BP/WT(F%R/[__XM3!/?2B97,_O__BTL(]]&)C=#^__^+ +M6PSWTR.%V/[__XF%R/[__XN]W/[__R'ZB97,_O__BY7@_O__(=&)C=#^__^+ +MA>3^__\APXF=U/[__\'F!(M-#(VT#E@(``"+C=C^__\C#HF-V/[__R-^!(F] +MW/[__R-6"(F5X/[__R-&#(F%Y/[__[@`````A$/`(A'/!!@``B?"(1P?IM0$``)"*E:_^__^+30PX42L/A*(! +M```/MOK!YP2-C#WH_O__BUT,C90?6`@``(L"]]")`8M"!/?0B4$$BT((]]") +M00B+0@SWT(E!#(L!(X78_O__B0&+000CA=S^__^)002+00@CA>#^__^)00B+ +M00PCA>3^__^)00Q3Z&W!__^#Q`3&0`0#B[6,_O__B7`(BI6O_O__B%`,B86\ +M_O__BXVP_O__BQG^@\`&```/MK/`!@``B<(IVH/J,,'Z`HT$THT$PHT$PHT$ +MPHG!P>$/`(A'/!!@``B?&(2@>-A#WH +M_O__N@````"#.`!U$H-X!`!U#(-X"`!U!H-X#`!T!;H!````A=(/A)<````/ +MMH6O_O__P>`$C9P%Z/[___]U#.BRP/__@\0$QD`$`8J5K_[__XA0"(A0"8L3 +MB5`,BU,$B5`0BU,(B5`4BU,,B5`8BXV\_O__BQG^@\`&```/MK/`!@``*=B# +MZ##!^`*-%,"-%-"-%-"-%-")T<'A#P'*C130]]J(E'/`!@``B[V\_O__BD<' +MB(1SP08``(GPB$<'C78`_H6O_O__BI6O_O__BTT,.%$J#X>P_?__N`````"# +MO%M/[__P````#&A:_^__\`@'XJ +M``^&M`,``(J%K_[__XM5##A"+`^$B@,``#A"*P^$@0,```^VP,'@!(VC^ +M__\!T(V(V`<``(N5R/[__R.0V`<``(D3BX7,_O__(T$$B4,$BX70_O__(T$( +MB4,(BX74_O__(T$,B4,,N`````"#.P!U$H-[!`!U#(-["`!U!H-[#`!T!;@! +M````A<`/A!$#``"+30R*22R(C8O^__\/MH6O_O__P>`$C9P%Z/[___]U#.C8 +MOO__@\0$QD`$`8J5K_[__XA0"(J-B_[__XA("8L3B5`,BU,$B5`0BU,(B5`4 +MBU,,B5`8B87`_O__@[VT_O__`'11BQC^@\`&```/MK/`!@``BY6T_O__*=J# +MZC#!^@*-!-*-!,*-!,*-!,*)P<'A#P'(C03"]]B(A'/`!@``B[W`_O__BD<' +MB(1SP08``(GPB$<'BU4,BE(KB)6*_O__BTT,BDDLB(V)_O__#[:]K_[__\'G +M!(VC^____=0SH%[[__X/$!,9`!`2*E8K^__^(4!B*C8G^__^(2!F+$XE0 +M"(M3!(E0#(M3"(E0$(M3#(E0%(F%O/[__XF%M/[__XL8_H/`!@``#[:SP`8` +M`(N5N/[__RG:@^HPP?H"C032C03"C03"C03"B<'!X0\!R(T$PO?8B(1SP`8` +M`(N5O/[__XI"!XB$<\$&``")\8A*!XL:_H/`!@``#[:SP`8``(N5P/[__RG: +M@^HPP?H"C032C03"C03"C03"B<'!X0\!R(T$PO?8B(1SP`8``(N5O/[__XI" +M!XB$<\$&``")\8A*!XNUL/[__XL>_H/`!@``#[:SP`8``(N5O/[__RG:@^HP +MP?H"C032C03"C03"C03"B<'!X0\!R(T$PO?8B(1SP`8``(N5L/[__XI"!XB$ +M<\$&``")\8A*!XM=#(I;*XB=B/[__XVC^____=0SHQ[S__X/$!,9`!`2* +ME8C^__^(4!B*C:_^__^(2!F+$XE0"(M3!(E0#(M3"(E0$(M3#(E0%(F%O/[_ +M_XL8_H/`!@``#[:SP`8``(N5N/[__RG:@^HPP?H"C032C03"C03"C03"B<'! +MX0\!R(T$PO?8B(1SP`8``(N]O/[__XI'!XB$<\$&``")\(A'!XN5L/[__XL: +M_H/`!@``#[:SP`8``(GZ*=J#ZC#!^@*-!-*-!,*-!,*-!,*)P<'A#P'(C03" +M]]B(A'/`!@``BXVP_O__BD$'B(1SP08``(GSB%D'D/Z%K_[__XJ%K_[__XM5 +M##A"*@^'3/S__X/L"/]U#/]U".CNT?__N`````"-9?1;7E_)PY!5B>575E.# +M[`R+10B#N+PQ```##XR+BGPQ +M``")3?"-=@"+7?"+`XE%\(M3!(L#B5`$B0*)&XE;!(M#'/9``00/A8@```") +MW[X`````@'LJ`'8FC78`@^P,B?(/ML+!X`2-A#C8!P``4.A,NO__@\001HGQ +M.$\J=]V+50B!PG0Q``"+30B+@70Q``")6`2)`XE3!(F9=#$``(M#'(-X+`!T +M8(/L!/]P,(M#'/]P+%'H_/___XM#',=`+`````"+10C_B,`Q``"#Q!#K-HGV +M@^P(4_]U".A0T___@\00A7\G#58GE4X/L!(M%"(M8"(.[O#$` +M``!U#HV#?#$``#F#?#$``'0S@^P,4^C\____B1PDZ/S___^)'"3H_/___X/$ +M$(.[O#$```!UVXV#?#$``#F#?#$``'7-N`````"+7?S)PXUV`%6)Y5=64X/L +M!(M%"(M`"(E%\(N(?#$```5\,0``.<@/A($```"-=@"+50@Y41QU:(G/LP"` +M>2H`=D&)]@^VP\'@!`'XC9#8!P``O@````"#N-@'````=12#>@0`=0Z#>@@` +M=0B#>@P`=`>)]KX!````A?9U&4,X7RIWP;@`````A"H`=D&)\@^VPL'@!`'8C9#8!P``OP````"#N-@' +M````=1*#>@0`=0R#>@@`=0:#>@P`=`6_`0```(7_=1A&B?`X0RIWO[@````` +MA7\G# +MD%6)Y5=64X/L#(M="(M]$(MS"(-[+`!U#5/HGO[__X/$!(7`=0N#[`A75O]5 +M#.L9D(M%#(E#+(E[,/^&P#$``(/L#%;H_/___XUE]%M>7\G#58GE5E.+=0B+ +M70R`>Q4`=03&0Q4!@'L5`709@'L5!G03@'L5`W0-]D,4('4'QD,5"XUV`/]S +M,%;H@[?__XD<)/]S(%;H_/___XL#@\00@W@@`'08@^P$@\`@4&@`````5NC\ +M____@\00ZUV0@[[$,0```'0KC89T,0``.89T,0``=!V#[`2-AL0Q``!0:``` +M``!6Z/S___^#Q!#K*XUV`(&^N#$``/\```!W'(V&=#$``#F&=#$``'4.@^P, +M5NC\____@\00B?:-9?A;7LG#D%6)Y5=64X'LW````(M]$(M%#(M0)(L*B8T@ +M____#[991$N)G33___]FBT(,9HF%5O___XM*4(M:5(F-2/___XF=3/___P^V +M6DZ)G3#___\/MD)/B84L____9HM*6F:)C53___]FBUI8@WH8`'0-9@^V0A2# +MX`$[111U.+D`````@WH<``^$[@(``(V%6/___XF%)/____]U%%!2_W4(_U(< +M@\00N0````"%P`^$QP(``.L)BU(8B94D____O@````"+50R+`@^V0`.)A2C_ +M___'A3C___\`````QX4\____``````^WP[H``````X5(____$Y5,____B85` +M____B95$____BXTH____.8TP____#X5:`0``BYT\____"YTX____=%:+A4#_ +M__\KA3C___^)P\'C"71#@WT4`'0'H0````#K$8/L#/\U`````.C\____@\00 +MB0=FQT<&``"!^P`0```/AO0```!FQT<$`!"#QPB!ZP`0``!UO0^WG53____! +MXPF+A23___\/MU`$A=)U!;H```$`B=`I\#G8Q4!=!"`>Q4& +M=`J`>Q4#=`3&0Q4+@^P(4U;_4R"#Q!")]HUE^%M>R<.058GE5U93@^P\BT4, +MBP")1>B+50SV0A0$#X3]`0``QT7L`````(!Z2``/A'L!``"+3>R+70R+3(LT +MB4WDBIDP"0``B%WC.)DQ"0``#X)&`0``C78`BD7CBU7D.$(K#X0?`0``#[;` +MB<+!X@2+3>2-E`K8!P``B57<#[>4@1`)```/M[2!$@D``+\`````C78`@_H? +M=U.)^P^VPXM-W(T<@8E5V+D@````*=$Y\78"B?&#^2!U"\<#_____^L2C78` +MN`$```#3X$B*3=C3X`D#N"`````IT#GP) +M^X#[`W:=#[9UXXGPP>`$BWWDC80X6`@``(E%U`^WG+<0"0``#[>TMQ()``"_ +M`````(GV@_L?=U.)^@^VPHM-U(T4@8E=T+D@````*=DY\78"B?&#^2!U"\<" +M_____^L2C78`N`$```#3X$B*3=#3X`D"N"`````IV#GP)^#P#=I[^1>.*5>.+3>0XD3$)```/@[W^____1>R+70P/MD-( +M.T7L#X^%_O__BW4(@[YP,0````^$H@,``,=%[`````"+?0R`?T@`=#Z)\H'" +M?#$``(M%[(M-#(M$@32)1>3'@`@)````````BT($BTWDB4H$B1&)002)"/]% +M[(M=#`^V0T@[1>Q_RH/L"/]U#/]U".@N^?__Z7@#``"+=0SV1A0"#X0T`P`` +MBWT(@CV0EX##X40`P``@^P$:A!J`%#H +M_/___\=%[`````"#Q!"`?D@`#X03`0``BTWLBUT,BTR+-(E-Y(G.L0"`?BH` +M=D8/ML'!X`0!\(V0V`<``+L`````@[C8!P```'42@WH$`'4,@WH(`'4&@WH, +M`'0%NP$```"%VW0)N`$```#K#8GV03A.*G>ZN`````"%P`^%A0(``(M%Y(J` +M,`D``(A%XXM5Y#B",0D``')_BDWCBUWD.$LK=&,/MLF+=$ +MBQ`)``"Z`````(G?`T,@$U,DBUW,B03+B53+!&:+A(\2"0``9HD$3NLI#[95 +MXXMUY&:+1B!F`X26$`D``&8#A)82"0``BWW,9BL$UXM-R&:)!%'^1>.*7>.+ +M=>0XGC$)``!S@?]%[(M]#`^V1T@[1>P/C^W^__^+10S_<##_=0CH=J___\=% +M[`````"#Q`B+50R`>D@`#X0$`0``BTT(@<%T,0``B4W$BUWLBW4,BUR>-(E= +MY(-][`!U3HM#((M3)(M]#(E'4(E75(J#,`D``(A'3HI#*XA'3P^V@S`)``!F +MBX2#$`D``&:)1U@/MH,P"0``9HN$@Q()``!FB4=:QD=,`,9'30#K<8M-Y(M! +M((M1)(M=##M35')@=P4[0U!V68MUZ`^W1ESWV(E%N(G'P?\?B7V\BTVXBT7D +M(T@@BUV\(U@DBT6XBW4,(T90BU6\(U94B=XQUC'("<9U'8M]Y`^VES`)``"+ +M30QFBT%:9@.$EQ()``!FB4%:BUW$BT,$BW7DB7,$B1Z)1@2),/]%[(M]#`^V +M1T@[1>P/CPC___^+10B#N,0Q````=!F#[`0%Q#$``%!H`````/]U".C\____ +M@\00QD7C`(M5Z(!Z1``/AK0````/MG7CBTW(9H,\<0!T7HM]Z(M.*3>.+ +M7>@X2T1WANLXD,=%[`````"+=0R`?D@`=">#[`B+?>R+10S_=+@T_W4(Z-_& +M__^#Q!!'B7WLBU4,#[9"2#GX?]F-9?1;7E_)PY!5B>575E.#[%R+10R+`(E% +M[,=%V`````!FBU!<9HE5WF:!^H``=@9FQT7>@`"+30SV010@=$Z#[`P/MT7> +M4(M=$/]S%/]S$/]U[/]U".B2L/__B478@\0@N/____^#?=@`#X2.`P``BT4, +MQD!(`8M5V(E0-(F""`D``+@`````Z7$#``"+31`/MD$BN@````!24(G+_W$$ +M_S'H_/___X/$$(A%UXM-[`^V042Z`````%)0_W,,_W,(Z/S___^#Q!"*2R(H +MP8A-UCA-UX!=U_^+1>QFBU!!FBWW>9BG'9CM]W'8#BWWBT7L9CE07'8^N0````"+50P/MD)(B46\@_@`?BJ)]HM%#(M$ +MB#2)1=B+4"0Q\HE5J(M0(#':BT6H"=`/A"8!``!!.4V\?]B#[`S_=DC_#X2O````BTVTB4VX +MBWVPBUT,#[9#2(M$@S2)1=C'@`@)````````B<:Q`(!X*@!V/P^VP<'@!`'P +MC9#8!P``NP````"#N-@'````=12#>@0`=0Z#>@@`=0B#>@P`=`>)]KL!```` +MA=MU)$$X3BIWP;@`````A`15>3'1=`!````Z??]__^+11!F@W@@``^$D0```+D`````_D77 +MBE76.%77=0/^1=>*7=>+1>PX6$1U.H!]U@!T!?Y-UNL)BU40BE(BB%76@'W6 +M``^41=>+7>P/MT-BT7L9CE0 +M7'8'QT70`0```(M=$&:+6R!FB5W7\G#C78`58GE@^P(BU4(BT4,@WT0`'0:QD`5"X/L!%!H +MT&H``%+H_/___X/$$.L/B?:#[`A04N@N]O__@\00R<.058GE5U93@>S,```` +MBT4,BP")1;3V0`$$=1Z+50S&0A4"@^P$4O]R(/]U".C\____Z0\$``"-=@"+ +M3;2#>30`=2=J!_]U".CEI?__BUVTB4,TQP0D`!```&H`_W,TZ/S___^#Q!"- +M=@"+50R*0A2H(`^%$@(``*@&=1K&0A4!@^P$4O]R(/]U".C\____Z;(#``") +M]HM-#/9!%`1T+XM=M(-[+`!T)H/L!/]S,/]S+/]U".C\____QT,L`````(M% +M"/^(P#$``(/$$(GVBTT,BU$$BTD(B95`____B8U$____B570B4W4BUT,9HM# +M#&:)1=B+5;2*0D1(B$7:#[9*1HN%0/___XN51/___P^MT-/J]L$@=`>)T+H` +M````B46@B56DB46XB56\#[9%VKH`````4E#_=:3_=:#H_/___X/$$(E%P(E5 +MQ(M=M`^V2T8/I<+3X/;!('0'B<*X`````(E%R(E5S`^W0UP/ME7:B56<#Z_" +MB46P#[=-V(E-D,=%E`````"+19"+590#A4#___\3E43___^)18B)58R+59R) +ME3#____'A33___\`````BT7(]Z4P____B46`B56$BY4P____#Z]5S(M]A`'7 +MBT7(#Z^%-/___XT$!XE%A(MUB(M]C"MU@!M]A(M%L+H``````<81UXFU`70;BT4,QD`5!H/L!%#_<"#_=0CH_/___^F8`0``BU6T +M#[=27(E5K(F54/___\>%5/___P````"+30R+202)C3S___^+A5#____WX8F% +M,/___XF5-/___XN-4/___XM5#`^O2@B+G33___\!RXN-//___P^OC53___^- +M#`N)C33___^+A3#___^+E33___^)153@^P$BUT,@WLT`'1.@^P,4^C\____N@````"#Q!"-=@"+ +M0S2+!)"%P'00B?;'0!``````BT`4A#$``(V'?#$``(F'?#$``(F'@#$``(V'A#$``(F'A#$``(F' +MB#$``*$`````P>`,NJNJJJKWXHG3P>L/4V@T"0``5^A8H?__B<:#Q`R#PR!3 +M:AA7Z$>A__\!QH/$#*$`````P>`,P>@.4&I$5^@NH?__`<:#Q`QJ"&@`$``` +M5^@T,0``_X>X,0``1CLU`````'+1D(UE]%M>7\G# +M58GE5U93@^P,BWT(BW4,BUX$#[9.`[@!````B<+3XH!F`?O'0V0`````QT-H +M`````/9#7@)T"6:#>V``=`_K!V:#>V``="UFA5-@=2=F"5-@@&,!^X-[0`!T +M#8/L"%-7_U-`@\00B?:`8UX?Z;L```"-=@"*0UYFB5-@_DM%QT-D`````,=# +M:`````"#R`6(0UZ$P'D.@^!_B$->Z8L```"-=@"`8UZ?@^P(4U?H_/___XG" +M@\00A@^#^@\@*B$->_D-%@^P(4FH'Z/S___^#Q!"#>P0`=`R- +M=@"+6P2#>P0`=??H_/___XE#2(/L#%/H_/___XGVC67T6UY?R<-5B>53BTT( +MNP````"+50Q*@_K_=`^-=@`/M@$!PT%*@_K_=?0/ML-;R<.)]E6)Y593BW4( +M@#X#=D:[`````(!^1`!T-8-\GFP`="6+3)YLBE8!@^(!BD$!@^#^"="(00&# +M[`S_=)YLZ/S___^#Q!"00P^V1D0YV'_+@&9>^^L)@^P,5N@(````C67X6U[) +MPY!5B>575E.![!P"``#'A>3]__\`````C;7H_?__BT4(@'A$``^$-@(``(MX +M!(7_=`^#?P0`=`F)O>3]__^+?P2#[`1H``(``&H`5NC\____QP;S%GA:@\00 +MN`````"%_W0#BT=(B48$BU4(@'I,`'0*@$X)`HI"3XA&"HM-"(I12(C3@^,! +MBH:3````@^#\B-�()V`G(B-.#XP2#X/.(T8/A"`G8"3]__\!&<"#P`*(1@N%_P^$N````(M'#(E&#(M'$(F&E````(H'B$80 +MBD=$B$81@[WD_?__`'0+BY7D_?__BD(#ZP:+30B*00.(1A**1T:(1A/V1UX" +M=`2`3A0!9HM'8&:)1A:+1V2)1AB+1VB)AI@```"#[`1J$(V'C````%"-1BQ0 +MZ/S___^#Q`QJ!(V'G````%"-1CQ0Z/S___^#Q`QJ$(V'X````%"-AH````!0 +MZ/S___^#Q`QJ0(V'H````%"-1D!0Z/S___^#Q!"#O>3]__\`=%R+E>3]__^+ +M0@R)1AR+C>3]__^+01")AIP```"*`8A&((I!1(A&(8M5"(I"`XA&(HI!1HA& +M(_9!7@)T!(!.)`&+C>3]__]FBT%@9HE&)HM!9(E&*(M!:(F&H````(7_=0N+ +M50B*`HA&$(UV`&B0````5NC\____]]B(1@AH``(``%;H_/____?8B(:0```` +M5FHPBTT(BT%4@^@*4(G(@\!$4.C\____C67T6UY?R<.058GEBTT(B6+10R`8`'[4.C\____ +MR<.)]E6)Y5=64X'L'`0``(M]"(VUZ/W__XG[BDC[__^0BUML@#\( +M=62%VW0'9H-_8`%U68G#QX7D^___`0````^V1T2#^`%^6E-J(&H`BY7D^___ +MBT27;(/`1%#H_/___[H`````@\00BP26,P23B0260H/Z?W[Q_X7D^___#[9' +M1#N%Y/O__W^_ZQ>0@#L#=8]6:B!J`(U#1%#H_/___X/$$&:!OOX!``!5JG5> +M@[[*`0```'0;@7X&3$E,3W0,@;YV`0``1U)50G4&@$\!`NLZQX7D^___```` +M`(N%Y/O__\'@!`'P@+B^`0``@'4-@[C*`0```'0$@$\!`O^%Y/O__X.]Y/O_ +M_P-^T(UE]%M>7\G#D%6)Y593BTT(BYE0$0``C4,!OB("``"9]_Z)UHM%#(E$ +MV3R+D5`1``"+11")1-%`B;%0$0``6U[)PXUV`%6)Y5=64X/L#(MU"(N&3!$` +M`#N&4!$``'0VOR("``"0BX9,$0``BTS&/(M564XM-"(N9:"(``(U#`;XB +M`@``F??^B=:+10R)A-E4$0``BY%H(@``BT40B8316!$``(FQ:"(``%M>R<.0 +M58GE5U93@^P,BUT(BX-D(@``.X-H(@``=%:)]HN#9"(``(NTPU01``"+O,-8 +M$0``0+HB`@``B=&9]_F)DV0B``"#N[PQ````=`Z#[`Q3Z/S___^#Q!")]H/L +M"%=3_]:#Q!"+@V0B```[@V@B``!UK(UE]%M>7\G#58GE4X/L!(M5"+@````` +M@WHX`'07BUHXBP.)0CB#[`1J7&H`4^C\____B=B+7?S)PXUV`%6)Y8M-"(M5 +M#(M!.(D"B5$XR<.058GEBTT(BU4,@SD`=!*+`8M`*(E"*(L!B5`HZP:-=@") +M4BB)$53@^P$BT4(BUT,BTT0 +MBU`(@#@(=1"#[`114U#H_/___^L*C78`@^P(45+_TXM=_,G#58GE5U93@^P4 +MBT4(BE44B%7SBW@HB@"(1?(/MMA35^C\____@\0,:@!35^C\____@\0,:@!J +M`&H`:@!J`U-7Z/S___^#Q""Z`````(7`#X2M````]T4,````\`^5P`^VR(/L +M#(7)=!2X)````(!]\R!T#;@T````ZP:)]@^V1?-0N$````"%R740BT4,BU40 +M#ZS0&(/(0`^VP%"+10R+51`/K-`0#[?8#[;#4(M%#(M5$`^LT`@/ML!0#[95 +M#`^WPH7)=`F)V"4`_P``"=!0:@%J`&@``0``_W4848!]\S`/E,`/ML!`4`^V +M7?)35^C\____B<:#Q#A35^C\____B?*)T(UE]%M>7\G#D%6)Y8I%"(G"@^(# +MB='!X0V-D0`@``"H!'0*C8$`(`,`ZPB)]HV"```"`,G#58GE5E.#[!R+=0B* +M10R(1?=H(*$'`.C\____NR"A!P"#Q!"0@^P(#[9%]U#HH____P4<`0``B00D +M_W8,Z/S___^#Q!"$P'@(N`$```#K))"#[`QH$"<``.C\____@\00@<,0)P`` +M@?L_2TP`=K:X`````(UE^%M>R<.)]E6)Y593BUT(@^P$:@`/MD4,4.A!____ +MB<:-0`B)!"3_575E.+70B+?1"+=12Y`````(U3"HM&$(D#BT84B4,$@SX`=0*Q`0^V1P31 +MX`G!9HE+"(M%#(.X.`(```!T#X.X.`(```(/A48!``")]H-^!`$/A<8```!F +M#[9&#X#,$6:)`H/"`F8/MD8.@,P19HD"@\("#[9'!,'@`R7X````@,P29HD" +M@\("9@^V1@N`S!-FB0*#P@)F#[9&"(#,$V:)`H/"`F8/MD8,@,P49HD"@\(" +M9@^V1@F`S!1FB0*#P@)F#[9#,%6:)`H/"`F8/MD8*@,P59HD"@\("9L<" +M0!:#P@*#/@!U&;!@BTT,@[DX`@```@^$@@$``+`FZ7L!``"P88M-#(.Y.`(` +M``(/A&D!``"P-NEB`0``B?9F#[9&#H#,$6:)`H/"`@^V1P3!X`,E^````(#, +M$F:)`H/"`F8/MD8(@,P39HD"@\("9@^V1@F`S!1FB0*#P@)F#[9&"H#,%6:) +M`H/"`HM&""4````/P>@8#4`6``!FB0*#P@*#/@$9P(/@^X/H-.GM````D(-^ +M!`$/A88```!F#[9&#X#,$F:)`H/"`F8/MD8.@,P29HD"@\("9@^V1@N`S!-F +MB0*#P@)F#[9&"(#,$V:)`H/"`F8/MD8,@,P49HD"@\("9@^V1@F`S!1FB0*# +MP@)F#[9#,%6:)`H/"`F8/MD8*@,P59HD"@\("9L<"0!:#P@*#/@$9P(/@ +M\(/`->M=D&8/MD8.@,P29HD"@\("9@^V1@B`S!-FB0*#P@)F#[9&"8#,%&:) +M`H/"`F8/MD8*@,P59HD"@\("BT8()0````_!Z!@-0!8``&:)`H/"`H,^`1G` +M@^#^@^@VC78`9@^VP`T`E___9HD"6UY?R<.-=@!5B>575E.#[""+50B+?12+ +M6@P/MD4,BT2")(MP,&H`C88@`0``B47P4%/H_/___X/$"(V&!`$``%!3Z/S_ +M__^(!X/$"(V&"`$``(E%[%!3Z/S___]F#[;`9HE'`H/$"(V&#`$``(E%Z%!3 +MZ/S___]F#[;`9HE'!(/$"(V&$`$``(E%Y%!3Z/S___]F#[;`9HE'!H/$"(V& +M%`$``(E%X%!3Z/S___]F#[;`9HE'"(/$$(-]$`%U;H/L!&B`````_W7P4^C\ +M____@\0(_W7L4^C\____P>`(9@E'`H/$"/]UZ%/H_/___\'@"&8)1P2#Q`C_ +M=>13Z/S____!X`AF"4<&@\0(_W7@4^C\____P>`(9@E'"(/$#&H`_W7P4^C\ +M____@\00@^P(C888`0``4%/H_/___XA'"H/$"(V&'`$``%!3Z/S___^(1PN- +M9?1;7E_)PXGV58GE5U93@^PTBT409HE%U@^V50R)5="+10B+?)`DBTR<.-=@!5B>575E.#[!R+10B+0`R)1>S'1>@` +M````#[9%#(T,A0````"(3?.*11`(1?,/MD7SBU4(BW2")(-]&`!T:X7V#X3- +M````BY[<"0``@^P$BT44P>`#"T8D4(M&,(/`)%#_=>SH_/___X/$$#M=%'0C +M#[9]\X/L!(M&%(T$V%!7_W4(Z(G]__]#@^,?@\00.UT4=>&#ODP)````=0?' +M1>@!````B9[<"0``@WT<`'4*@WWH``^$_P$``(/L"`^V1?-0Z+;W__^#P`B) +M1>2)!"3_=>SH_/___XG'@\0,#[?8B=CWT%#_=>3_=>SH_/___X/$$/;#"`^$ +M%@$``(7V=!3'ADP)````````QX8T`@```````(M-"(-Y9`%T!H-Y:`%U&H/L +M!+@``0``BDWST^!04/]U".@S_O__@\00BT4(@WA@`70,@WAD`70&@WAH`745 +M@^P(#[9%\U#_=0CH:PD``(/$$.MZBU4(@WI<`70&@WI@`75K@^P$:@0/MEWS +M4^CX]O__C7`HB30D_W7LZ/S___^#Q`A6_W7LZ/S____'!"09````Z/S___^# +MQ`QJ`%;_=>SH_/___X/$"%;_=>SH_/___\<$)-`'``#H_/___X/$"%/_=0CH +MM`<``(/$$)"#[`@/MEWS4_]U".C\____@\00A<`/A;T```!3:@!J`?]U"(M- +M"/]1((/$$.FG````]\<0````=%&#[`@/MD7S4/]U".AG!P``@\00BT4(@WAD +M`70&@WAH`74;@^P$:@"X``$``(I-\]/@4/]U".@9_?__@\00#[9%\U!J`6H! +M_W4(BU4(_U(@ZTX/M\?VQ`%T1H.^-`(```%U*,>&3`D```````#'AC0"```` +M````@^P$4`^V1?-0_W4(Z-SZ__^#Q!"#/0`````!=0R#[`Q6Z$L0``"#Q!"- +M9?1;7E_)PU6)Y5.#[`2+70@/MD4,P>`""T40#[;0BTR3)(7)=0V#[`A24^@' +M#@``ZT60BY%$"0``A=)U$H/L"`^VP%!3Z.T-``#K*XUV`(,Z`70&@WH0`701 +M@^P(#[;`4%/HT`T``.L.B?:#[`A24>@*````B?:+7?S)PXUV`%6)Y5=64X/L +M)(M5"(M"*(MP#(M:,(H*@^$#B<\/M@*#X`3!Z`*(1=B-@R`!``!05NC\____ +M@\0(@<,<`0``4U;H_/___XC#@\0,N``!``")^=/@]]!0@'W8`1G`)0``__\% +M%``#`%!6Z/S___^#Q!"$VP^(*`$``/;#`707@^P$:@'_=0S_=0CHWP$``.D. +M`0``B?:+50R+0A2#^`%T+8/X`7(0@_@"#X2(````Z>X```")]H/L!&H`_W4, +M_W4(Z*@!``"#Q!#IU````/;#0'12@^P(BT4,@\`44/]U".C%````@\00@_@! +M=2.+30R#>2``#X6H````@^P$:@!1_W4(Z&8!``"#Q!#ID@```(/L!&H!_W4, +M_W4(Z$X!``"#Q!#K?8/L!&H!_W4,_W4(Z#D!``#K:P^VPZA`=%"H('5,BT4, +M@W@@`'43@^P$:@!0_W4(Z!4!``"#Q!#K1(/L"(M%#(/`%%#_=0CH.@```(/$ +M$(7`=2N#[`1J`?]U#/]U".CG````@\00ZQ:)]H/L!&H!_W4,_W4(Z-````"# +MQ!"0C67T6UY?R<-5B>575E.#[`R+?0B+=0RX`````(%^#/\````/AI@```"+ +M%H/Z`711N`````"#^@$/@H,```"#^@)U>;L`````@^P$BT8(#[<04H/``HE& +M"(M',`4``0``4(M'*/]P#.C\____@\000X'[_P```';0@6X,``$``.L[NP`` +M``")]H/L"(M',`4``0``4(M'*/]P#.C\____BU8(9HD"@T8(`H/$$$.!^_\` +M``!VTX%N#``!``"X`0```(UE]%M>7\G#C78`58GE5U93@^P&3`D````` +M``"-=@"#[`2-1=A0:@!J`/]S(%!`!=2^#[`A05N@%#0``@\00A<`/A9H```"#[`1J`?^V1`D``%;H.?__ +M_X/$$.F!````D(.^.`(```!U,X/L"`^V!E#_=BCH9`H``(/$"(M&,(/`*%"+ +M1BC_<`SH_/___\<$)`$```#H_/___X/$$(/L"`^V!E#_=BCHA0H``(N>1`D` +M`(/$$(7;="B#>Q``=2*)]H/L!(U#%%!35NBZ"P``BUL(@\00A=MT"(-[$`!T +MXHGVC67T6UY?R<-5B>575E.#[!2+70B+0RB+>`R+0S")1?")QH/&*%97Z/S_ +M__^#Q!"H!'0V@^P$:@)65^C\____@\0(5E?H_/___\<$)-`'``#H_/___X/$ +M"`^V`U#_#W`D```````#'@S0"```````` +MQX/4"0``(````+H`````B9235`D``$*#^A]^\[H`````B?:-!-4`````*=#' +MA,-$`@```0```$*#^A]^YL>#1`D```````#'@T@)````````QX-,"0`````` +M`(/L!&H`BT7P@\`(4%?H_/___X/$#&@8`0``BT7P@\`,4%?H_/___X/$#/]S +M&(M%\(/`$%!7Z/S___^#Q`R+0QPE`/S__U"+1?"#P!105^C\____@\0,BT,H +MN@````"#>'@`=`.+4QQ2BT7P@\`84%?H_/___X/$#/]S((M%\(/`'%!7Z/S_ +M__^#Q`R+0RBZ`````(-X>`!T`XM3'%*+1?"#P"!05^C\____@\0,BT,DL`!0 +MBT7P@\`D4%?H_/___[@!````C67T6UY?R<.-=@!5B>575E.#["R+=0B+111F +MB476@WT,``^%F@```+L`````B?:-!-T`````*=B-!,:#N$0"````=72#N%0" +M```!=1J+D%P"``"+N'@"``"+@'0"``")1=#K)(UV`(T$W0`````IV(T$QHN0 +M7`(``(NX=`(``(N`<`(``(E%T(U%V%!2#[8&4/]V*.C*\O__@\0,C4784&H` +M#[=%UE!7_W40#[8&4/]V*/]5T(/$($.#^Q\/CFW___^-9?1;7E_)PY!5B>57 +M5E.#[!R+70@/MG4,B?"#X`3!Z`*(1=B_`P```"'W@WM<`70&@WM@`75K@^P( +MB?H/ML*)PL'B"(V"#`$``(!]V`!T"8V"#`$#`.L&D`4```(`4/]S#.C\____ +MB<&#X?R#R0&#Q`Q1B?H/ML*)PL'B"(V"#`$``(!]V`!T"(V"#`$#`.L%!0`` +M`@!0_W,,Z/S___^#Q!"#[`B)^@^VPHG"P>((C8)T`0``@'W8`'0*C8)T`0,` +MZP>)]@4```(`4/]S#.C\____B<&`X1^)\@^VP@^VE!B)````P>(%@>+@```` +M"=&`Y>7\G#C78`58GE +M5U93@^P,BUT(#[9U#%;HFNW__X/L!(UX*%93Z'WN__^#Q`QJ!%?_575E.#[`S& +M1?(`QD7S`(UV`(I%\HI5\XT<@@^VVU/H"NW__XG':@*-<"A6BT4(_W`,Z/S_ +M__^#Q`A6BU4(_W(,Z/S___^#Q`A3_W4(Z"S___^#Q`QJ`%:+10C_<`SH_/__ +M_X/$#&@?`0``5XM5"/]R#.C\____@\0,:@"-1P10BT4(_W`,Z/S___^#Q`QJ +M`(U'"%"+50C_<@SH_/___X/$#&H`C4<,4(M%"/]P#.C\____@\0,:@"-1Q!0 +MBU4(_W(,Z/S___^#Q`QJ`(U'%%"+10C_<`SH_/___X/$#&H`C4<84(M5"/]R +M#.C\____@\0,:@"-1QQ0BT4(_W`,Z/S___^#Q`QJ`(U')%"+50C_<@SH_/__ +M_X/$#&H`C4<@4(M%"/]P#.C\____@\0,:@"-1RQ0BU4(_W(,Z/S___^#Q`QH +MO````(U'-%"+10C_<`SH_/___X/$$/Y%\X!]\P,/AJS^__^`??(!&=N!XP`` +M__^!PP```P"#[`1J`(U##%"+50C_<@SH_/___X/$#&H`C4,04(M%"/]P#.C\ +M____@\0,:@"-0Q10BU4(_W(,Z/S___^#Q`QJ`(U#&%"+10C_<`SH_/___X/$ +M"(/#(%.+50C_<@SH_/___R4<'!P<#0,#`P.#Q`Q04XM%"/]P#.C\____@\00 +M_D7R@'WR`0^&!_[__XUE]%M>7\G#B?95B>6#[`QH___/#VAL!`$`BT4(_W`, +MZ/S____)PXUV`%6)Y5.#[`2+70B+0P2P`#T``(!0=">#[`AH+`T``/]S#.C\ +M____@\@!@\0,4&@L#0``_W,,Z/S___^#Q!"#[`AH``T``/]S#.C\____)?__ +M`/^#Q`Q0:``-``#_53BUT(BTT,@WD(`'48BT$, +MB8-("0``A575E.#[`R+?0B+=0R+71"#.P!U&8/L!&H@C4,$4(U&%%#H_/___X/$$.L= +MB?:#[`1J)(U#!%"-1A10Z/S____^AU`)``"#Q!"+`XE&$%97Z/G^___'!@`` +M``#^ASP"``"-9?1;7E_)PY!5B>564XM="(MU#(-^$`!T!OZ+4`D``%93Z`K_ +M__^+@]0)```/ME8$B92#5`D``$")@]0)``#'!@$```#^BSP"``"-9?A;7LG# +MC78`58GEBD4(/`-V$@^VR(U,"0*X`0```-/@ZQ")]@^VR(U,"0&X`0```-/@ +MR<-5B>575E.#[`R+?0B+=U0/MET,4^B[____@^P$"?")1U13Z!'H__\%'`$` +M`(D$)/]W#.C\____@\0,B=F#X0.X``$``-/@]]!0@^,$P?L"@_L!&<`E``#_ +M_P44``,`4/]W#.C\____@\0(:&0=``#_=PSH_/___X/$$#GP=2:#[`3_=U1H +M9!T``/]W#.C\____@\0(:&0=``#_=PSH_/___X/$$(UE]%M>7\G#58GE5E.+ +M=0B+7E0/MD4,4.@3____@^P$]]`AV(E&5&AD'0``_W8,Z/S___^#Q!`YV'49 +M@^P$_W94:&0=``#_=@SH_/___X/$$(UV`(UE^%M>R<.058GE5U93@^P0BET, +MBT4(BT`,B47P#[;3BT4(BW20)(M^,,>&-`(```$```"#X@3!Z@*)V8/A`[@! +M`0``T^#WT%"`^@$9P"4``/__!10``P!0_W7PZ/S___^#Q`QJ`(M&,(/`"%#_ +M=?#H_/___X/$"`^VVU/_=0CH,/___X/$"(V''`$``%#_=?#H_/___\>&0`(` +M``$```"#Q`QJ`8/'*%?_=?#H_/___XUE]%M>7\G#C78`58GE5U93@^P0BD4, +MB$7SNP````"+50B+>@P/ML"+1((DBW`PQX`T`@```````&H"C48H4%?H_/__ +M_X/$$(UV`(/L"(U&*%!7Z/S___^#Q!"H`70<@^P,:.@#``#H_/___X/$$$.! +M^^<#``!VT^L)D('[YP,``'83@^P(#[9%\U#_=0CH3/C__X/$$(/L"`^V1?-0 +M_W4(Z+']__^-9?1;7E_)PY!5B>564XM="(M#*(MP#/]U$/]U#%.+@]@)``#! +MX`4#0Q!0Z-'F__^+D]@)``!"@^(?B9/8"0``_H-1"0``@\0,BT,<)0#\___! +MX@4)T%"+0S"#P!105NC\____C67X6U[)PXGV58GE4X/L!(M="&H`:@)J`%/H +MNO7__XD<).C>\___B1PDZ/S___^#Q!"#^`%U'L>#3`D```$```"#[`@/M@-0 +M_W,HZ/W\__^#Q!")]HM=_,G#C78`58GE5U93@^P4BWT,@\<4BU4(BT(HBW`, +MBUHPC8,<`0``4%;H_/___R7!````@\00N@````"#^$`/A=X!``"#?P0!=7"# +M[`0/MD<14(V#!`$``%!6Z/S___^#Q`P/MD<34(V#"`$``%!6Z/S___^#Q`P/ +MMD<54(V##`$``%!6Z/S___^#Q`P/MD<74(V#$`$``%!6Z/S___^#Q`P/MD<9 +M4(V#%`$``%!6Z/S___^#Q!#K-(GV9O='$`#_=2!F]T<2`/]U&&;W1Q0`_W40 +M9O='%@#_=0AF]T<8`/]T"KH`````Z38!``"#[`0/MD<04(V#!`$``%!6Z/S_ +M__^#Q`P/MD<24(V#"`$``%!6Z/S___^#Q`P/MD<44(V##`$``%!6Z/S___^# +MQ`P/MD<64(V#$`$``%!6Z/S___^#Q`P/MD<84(V#%`$``%!6Z/S___^#Q`P/ +MMD<:4(V#&`$``%!6Z/S___^#Q`P/MD<;4(V#'`$``%!6Z/S___^#Q!"#/P(/ +MA9````"#[`B-@R`!``!05NC\____QP0DR````&@0)P``:@%J`/]U".C\____ +M@\0@N@````"%P'1C@^P(C8,<`0``4%;H_/___R6)````@\00N@````"#^`AU +M0<=%\`````"!PP`!``"#[`2+1P@/MQ!2@\`"B4<(4U;H_/___X/$$/]%\(%] +M\/\```!VVH%O#``!``"Z`0```(GVB="-9?1;7E_)PXGV58GE5U93@^P0BW4( +MQT94`````&H`:&0=``#_=@SH_/___X/$!/]V#.C\____B$8$@\00N`````"` +M?@0`#X32`@``QT9<`````,=&8`````#'1F0`````QT9H`````,=&;`````#' +M1G``````QT9T`````,:&@`````&X`````(-^(``/A(L"``"X`````&:!?@:! +M4`^%>@(```^V5@6#^@$/A&T"``"#^@%_!H72=`GK&8/Z`G0+ZQ+'1F`!```` +MZQ#'1F0!````ZP?'1F@!````LP"#[`@/MM.)T(/@`\'@"(V(=`$``/;"!'0' +M!70!`P#K!HV!```"`%#_=@SH_/___P^VRXG"@>+@````P>H%B)0QB0```"4` +M&```P>@+B(0QD0```(/$$$.`^P=VI(/L#%;HE_3__XDT).B?]O__B30DZ+?V +M__^#Q`QJ`&CP!`$`_W8,Z/S___^#Q`AH+`T``/]V#.C\____B47P@V7P_H/$ +M#/]U\&@L#0``_W8,Z/S___^#Q!"#OH0`````=5>#[`AH``T``/]V#.C\____ +MB47P@\00J#!T.8M&1*G@`P"`=`@E'_S_?XE&1(-^7`%T$H-^8`%T#(-^9`%T +M!H-^:`%U$XM&1*@0=`R#X.^)1D3K!(-F1,^S`(GV@^P(#[;#4%;H&_+__X/$ +M$$.`^P=VZH/L!/]V1&@`#```_W8,Z/S___^#Q`S_=DAH*`P``/]V#.C\____ +M@\0,_W9,:%P=``#_=@SH_/___[,`@\00@^P$#[;#_W2&$(#[`1G`)0``__\% +M#``#`%#_=@SH_/___X/$#`^VP_]TAAB`^P$9P"4``/__!1```P!0_W8,Z/S_ +M__^#Q!!#@/L!=K/'1E15JP8`LP")]H/L"`^VPU!6Z`/A__^#Q!!#@/L'=NJ# +M[`QH4,,``.C\____@\00@WYD`70&@WYH`75#QT7P`````+,`D(/L"`^V^U=6 +MZ/S___^#Q!"%P'4+9K@``8GYT^`)1?!#@/L'=MN#[`3_=?!H`/\``%;HYN;_ +M_X/$$+@!````B?:-9?1;7E_)PU6)Y8/L#&H`:&0=``"+10C_<`SH_/___[@! +M````R<.058GEQP4``````0```,G#D%6)Y<<%``````````#)PY!5B>564XMU +M"(I5#`^VPHMW__XUE^%M>R<.)]E6)Y0^V50R+10B+5)`DN``` +M``"%TG0-@[I,"0```0^5P`^VP,G#B?95B>564XMU"(I%#(G"@^(#B='!X0B- +MD0`!``"H!'0)C9D``0,`ZP>0C9H```(`@^P(4_]V#.C\____@^`/@\00@_@! +M=`^#^`%R0H/X`W0UZSN-=@"#[`A3_W8,Z/S____'!"1`#0,`Z/S___^#Q`A3 +M_W8,Z/S___^#X`^#Q!"#^`-U"9"X`0```.L&D+@`````C67X6U[)PU6)Y5=6 +M4X/L+(M]"(I%#(A%\P^VP(M4AR2+3PR)3>RX`````(72#X0``@``BT(PB47H +MN`````"#NDP)```!#X3H`0``QT7D`````)#_1>2#?>0*=@NX`````.G-`0`` +MD(/L"`^V7?-35^AV\/__@\0(4U?H#-___XI5\X/B`XA5XX/C!(G>P>X"QT7< +M`````(/$$`^VPHG!P>$(B4W4@<$(`0``B4W8P>`(B470@^P(BU74C8((`0,` +MB?&$R74)BU78C8(```(`4/]W#.C\____B<.#X_"#RP&#Q`Q3BT70C9`(`0`` +MC8`(`0,`B?&$R74&C8(```(`4/]W#.C\____@\0(#[9%XXG"P>((C8((`0`` +MB?&$R70+C8((`0,`ZPB-=@`%```"`%#_=PSH_/___\<$)!D```#H_/___X/C +M\(/$#%,/MD7CB<+!X@B-@@@!``")\83)=`J-@@@!`P#K!XGV!0```@!0_W<, +MZ/S___^#Q`@/MD7CB<+!X@B-@@@!``")\83)=`J-@@@!`P#K!XGV!0```@!0 +M_W<,Z/S____'!"30!P``Z/S___^#Q`@/MEWS4U?H_/___X/$$(7`=1__1=R# +M?=P"#X;=_O__@^P(4U?H8MW__X/$$.EJ_O__@^P(BT7H!1P!``!0_W7LZ/S_ +M__\EP````(/$$(/X0'05@^P(#[9%\U!7Z"O=__^X`````.L4@^P(#[9%\U!7 +MZ!;=__^X`0```)"-9?1;7E_)PU6)Y5=64X/L#(M5"(I%%(A%\P^V10R+7((D +MN0````"%VW1UBWH,BW,PN0````"#NTP)```!=&&#[`A65^C\____B<*#Q!"# +M?1``=2B*1?-(N0`````\'W<_QX,X`@```````(/BP`^V1?-("<*`S@+K$HGV +MQX,X`@```0```('BP/W__X#.`8/L!%)65^C\____N0$```"0B"3`D```$```"#[`@/ML%04^A"]/__N`$```"+7?S)PU6)Y5.#[`2+70B* +M50P/ML*Y`````(-\@R0`="`/MM*+1),DQX!,"0```````(/L"%)3Z+7T__^Y +M`0```(G(BUW\R<.058GE4X/L!`^V50R+10B+7)`DN`````"%VW0HN`````"# +MNTP)```!=!IJ`&H"_W404^A*Z___B1PDZ&[I__^X`0```(M=_,G#58GE#[95 +M#(M%"(M4D"2X_P```(72=`575E.#[`R*70P/MG40#[9] +M%(C:@^(#B=B#X`3!Z`+WQO@```!U"/?'_````'0+N`````#IC0```)`/MM*) +MT<'A"(V1=`$``(3`=`Z!P70!`P")3?#K#(UV`('"```"`(E5\(/L"/]U\(M% +M"/]P#.C\____)!^)\L'B!8'BX`````G0@.3GB?K!X@N!X@`8```)T(/$#%#_ +M=?"+50C_<@SH_/___P^VPXGYBU4(B(P0D0```(GQB(P0B0```(/$$+@!```` +MD(UE]%M>7\G#58GE5U93@^P4BW4(BET,OP,````AWX/C!,'K`H#[`1G`)0`` +M__\%&``#`%#_=@SH_/___XGY#[;1C4H8N@$```#3X@G0@\0,4(#[`1G`)0`` +M__\%&``#`%#_=@SH_/___X/$"(#[`1G`)0``__\%&``#`%#_=@SH_/___X/$ +M$+@!````C67T6UY?R<-5B>575E.#[!2+=0@/MGT,B?B#X`.(1?.)^`^VT(G0 +M@^`$B)]@4```(`4/]V#.C\____@^#P@\@!@\0,4`^V1?.)PL'B"(V" +M"`$``(3;=`F-@@@!`P#K!I`%```"`%#_=@SH_/___X/$"(GZ#[;"4%;H>^G_ +M_X/$$+@!````C67T6UY?R<.-=@!5B>575E.#[!2+?0B+=1"*10R(1?.+1PR) +M1>P/MD7SBUR')(G"@^(#B='!X0B-D70!``"H!'0(C8%T`0,`ZP:-@@```@!0 +M_W<,Z/S___^)1EB#Q!"%VW40QP8`````N`$```#I_P```(M#,(E%Z(/L"`^V +M1?-05^C\____B0:#Q!"X`0```(,^``^$V````(N#3`D``(E&+(N#.`(``(E& +M,(J#/`(``(A&-+H`````D(I$$VJ(1!8$0H/Z)W;R@^P(_W7H_W7LZ/S___^) +M1CB#Q`B+1>B#P!!0_W7LZ/S___^)1CR#Q`B+1>B#P!10_W7LZ/S___^)1D"# +MQ`B+1>B#P!A0_W7LZ/S___^)1D2#Q`B+1>B#P!Q0_W7LZ/S___^)1DB#Q`B+ +M1>B#P"!0_W7LZ/S___^)1DR#Q`B+1>B#P"10_W7LZ/S___^)1E"#Q`B+1>B# +MP"A0_W7LZ/S___^)1E2X`0```(UE]%M>7\G#D%6)Y5=64X/L#(I=#`^VPXM5 +M"(MT@B2X`0```(.^3`D````/A$D!``"X`@```("^/`(``!\/A#@^P( +M#[;;4_]U".B'[O__@\0(4_]U".C/[O__@\00@^P$_W405U;HV^S__X/$#(M% +M$(/`!%!75N@&\/__@\00ZVF0@^P$_W405U;HM^S__X/$$.M6B?:#[`3_=1!7 +M5NBC[/__@\00@+X\`@```74[@[XT`@```742@^P(#[;#4/]U".@7[___@\00 +M@^P(5U;H9O#__X/$$(7`=0]75NC0[/__N`$```#K!I"X`````(UE]%M>7\G# +MC78`58GE5U93@^PDBT4(BT`,B47D:&`=``!0Z/S___^)QHM5"(M25(E5\(/$ +M$+@`````A=8/A(L!``#WQ@``!`!T6H/L"(M%"(.XA`````$9P"58!```!0`9 +M``!0_W7DZ/S___^)PX/$#/?04(M5"(.ZA`````$9P"58!```!0`9``!0_W7D +MZ/S___]J`%-J`/]U"(M5"/]2((/$(,9%ZP#WQO\!```/A`(!``"`?>L!&=N! +MXP``__^!PQ0``P"#[`1J[U/_=>3H_/___X/$"%/_=>3H_/___XG'@\0,]]"# +MR!!04_]UY.C\____@\0(@'WK`1G`)0``__\%"``#`%#_=>3H_/___XE%X+,` +M@\00#[9%ZXE%V(UV``^VR[@``0``T^`A^(E%[+@!````T^")\H/B`2'X=02% +MTG0A@^P$5U)0BT7@@^`?4`^VPU`/MD7K4/]U".B3V___@\0@@WWL`'0VBU78 +MB57X"P6W@"$.`^P,/AF_____K!)#![@C1[OY%ZX!]ZP$/AN#^__^X +M`0```(UE]%M>7\G#D%6)Y8/L#&H`:&0=``"+10C_<`SH_/___[@!````R<.0 +M58GE@^P,BT4(_W!4:&0=``#_<`SH_/___[@!````R<-5B>575E.#[`R+70B+ +M?12*10R(1?.*11"(1?*^`````#G^53 +M@^P(BUT(:@"+0S`%(`$``%"+0RC_<`SH_/___X/$"(M#,`4@`0``4(M#*/]P +M#.C\____BUW\R<-5B>53@^P(BUT(:@*+0S`%(`$``%"+0RC_<`SH_/___X/$ +M"(M#,`4<`0``4(M#*/]P#.C\____BUW\R<-5B>575E.#[`R+50@/MD4,BUR" +M)+@`````A=MT;XMZ#(MS,+@`````@[M,"0```71;@^P,4^C\____@\0,:.$` +M``"-AAP!``!05^C\____QP0D9````&@0)P``:@%J`%/H_/___X/$((7`=1"# +M[`Q3Z/S___^X`````.L0@^P,4^C\____N`$```")]HUE]%M>7\G#58GE5U93 +M@^P,BWT(BD4,B$7S#[;`BW2')+@`````A?8/A*8```"-7C2-=@"#[`QH[``` +M`&H`:@!J`&H`:@!J`&@``0``C48T4&H`:@$/MD7S4%?H_/___X/$0(7`=&WV +M`P1T+F:!>P3(-W4F@^P$:@!J`&H`:@!J!P^V1?-05^C\____@\0@A6#[`@/ME4,BT4(BU20)+@` +M````A=)T%[@`````@[I,"0```70)@^P,4NC\____R<.058GE@^P4:.\```!J +M``^V12!0#[9%'%`/MD484`^V1110#[9%$%!J`&H`:@!J``^V10Q0_W4(Z/S_ +M___)PXUV`%6)Y5=64X/L#(I%#(A%\XM-(&:)3?"+121FB47NBTTH9HE-[(M] +M+(MU,(I=-(I%.(A%ZP^V1?.Z`````(M-"(-\@20`=#Z#[`P/MD7K4`^VPU`/ +MM\90#[?'4`^W1>Q0#[=%[E`/MT7P4/]U'/]U&/]U%/]U$`^V1?-0_W4(Z`X` +M``")PHG0C67T6UY?R<.)]E6)Y5=64X/L7(M5"(M]((M%)&:)1=B+12AFB47( +MBT4L9HE%N(M%,&:)1:B*132(1:>*13B(1:8/MD4,BUR")(MR#(M3,(E5H(.[ +M-`(```%T"8.[3`D```%U"KH`````Z00#``"#[`QHZ`,``&BX"P``:@!J0%/H +M_/___X/$(+H`````A<`/A-T"``"#[`Q3Z/S___^#Q!"#?10!#X6!````@^P$ +MB?H/ML90BT6@!00!``!05NC\____@\0,BU78#[;&4(M%H`4(`0``4%;H_/__ +M_X/$#(M5R`^VQE"+1:`%#`$``%!6Z/S___^#Q`R+5;@/ML90BT6@!1`!``!0 +M5NC\____@\0,BU6H#[;&4(M%H`44`0``4%;H_/___X/$$.L_]\<`_P``=23W +M1=@`_P``=1OW1<@`_P``=1+W1;@`_P``=0GW1:@`_P``=!.#[`Q3Z/S___^Z +M`````.D'`@``@^P$B?H/ML)0BT6@!00!``!05NC\____@\0,#[9%V%"+1:`% +M"`$``%!6Z/S___^#Q`P/MD7(4(M%H`4,`0``4%;H_/___X/$#`^V1;A0BT6@ +M!1`!``!05NC\____@\0,#[9%J%"+1:`%%`$``%!6Z/S___^#Q`P/MD6G4(M% +MH`48`0``4%;H_/___X/$#`^V1:90BT6@!1P!``!05NC\____@\00@WT0`'5$ +M@^P,:!`G``!H'`P``&H!:@!3Z/S___^#Q""%P'43@^P,4^C\____N@````#I +M*P$``(/L#%/H_/___[H!````Z1@!``"#[`QH$"<``&@<#```:@%J`%/H_/__ +M_X/$((7`=1.#[`Q3Z/S___^Z`````.GG````@^P(BT6@!1P!``!05NC\____ +M@\00J`AU$X/L#%/H_/___[H`````Z;L```"_`````#M]''-GBT6@!0`!``") +M19R)^H32=1N#[`QJ9&A0PP``:@%J`%/H_/___X/$((7`=&:#?1`!=1B#[`C_ +M=9Q6Z/S___^+51AFB01Z@\00ZQ>#[`2+51@/MP1Z4/]UG%;H_/___X/$$$<[ +M?1QRI(/L#&ID:%##``!J`6H`4^C\____@\0@A`FX`0```.L@B?:#[`QH]`$``.C\____@\00 +M0X'[#R<``';'N`````"-9?1;7E_)PXGV58GE4X/L$(M="%/H)/___X/$$+H! +M````@_@!=!>#[`QH]`$``.C\____B1PDZ`+___^)PHG0BUW\R<.058GE5E.+ +M=0B#[`1HH````*'@````BT`8!0``!`!05NC\____NP````"#Q!"#[`BAX``` +M`(M`$`4```0`4%;H_/___X/$$$.#^P1^X+L`````C78`@^P(H>````"+0!0% +M```$`%!6Z/S___^#Q!!#@_L%?N"[`````(UV`(/L"*'@````BT`0!0``!`!0 +M5NC\____@\000X/[!'[@C67X6U[)PY!5B>53@^P(BUT(:(````"AX````(M` +M#`4```0`4%/H_/___X/$#&BP````H>````"+0!@%```$`%!3Z/S___^+7?S) +MPU6)Y593BW4(@^P,5N@'____@\0,:@"AX````(M`"`4```0`4%;H_/___X/$ +M"*'@````BP`%```$`%!6Z/S___^(PXDT).AR____#[;;B=B-9?A;7LG#B?95 +MB>575E.#[`R+70B#/00`````#X4'`0``@^P(:"P-``!3Z/S___^)QX/$#(/( +M`5!H+`T``%/H_/___X/$"&CP!`$`4^C\____B<:#X&*#Q!"#^&)T&H/L!(GP +M@\AB#[;`4&CP!`$`4^C\____@\00@^P(:```!`!3Z/S___^)'"3H.O[__X/$ +M#&H'H>````"+0`@%```$`%!3Z/S___^#Q`QJ$:'@````BP`%```$`%!3Z/S_ +M__^#Q`QJ!:'@````BT`(!0``!`!04^C\____@\0,:A&AX````(L`!0``!`!0 +M4^C\____B1PDZ'3^__^#Q`Q6:/`$`0!3Z/S___^#Q`AH\`0!`%/H_/___X/$ +M#%=H+`T``%/H_/___X/$$)"-9?1;7E_)PU6)Y5=64X/L%(M="&@L#0``4^C\ +M____B<>#Q`R#R`%0:"P-``!3Z/S___^#Q`AH\`0!`%/H_/___XG&@^!B@\00 +M@_AB=!J#[`2)\(/(8@^VP%!H\`0!`%/H_/___X/$$(/L"&@```0`4^C\____ +MB1PDZ"+]__^#Q`QJ!Z'@````BT`(!0``!`!04^C\____@\0,:@"AX````(L` +M!0``!`!04^C\____@\0,:@6AX````(M`"`4```0`4%/H_/___X/$#&H`H>`` +M``"+``4```0`4%/H_/___XD<).A<_?__@\0,5FCP!`$`4^C\____@\0(:/`$ +M`0!3Z/S___^#Q`Q7:"P-``!3Z/S___^#Q!"-9?1;7E_)PY!5B>53@^P0BUT( +M4^AP_/__@\0,:@JAX````(M`"`4```0`4%/H_/___X/$#&H`H>````"+``4` +M``0`4%/H_/___XD<).C;_/__@\0(:`$`!`!3Z/S___^#Q!"Z_____Z@"=5"# +M[`Q3Z!3\__^#Q`QJ`:'@````BP`%```$`%!3Z/S___^)'"3HF/S__\<$)&0` +M``#H_/___X/$"&@!``0`4^C\____T>B#X`&#Q!"#^`$9THG0BUW\R<.)]E6) +MY5=64X/L%(M]"(I%#(A%\XM?#&@L#0``4^C\____B47L@\0,@\@!4&@L#0`` +M4^C\____@\0(:/`$`0!3Z/S___^)QH/@8H/$$(/X8G0:@^P$B?"#R&(/ML!0 +M:/`$`0!3Z/S___^#Q!"#[`AH```$`%/H_/___X/$#(I%\XB'B`````^VP%"A +MX````(M`'`4```0`4%/H_/___X/$#%9H\`0!`%/H_/___X/$"&CP!`$`4^C\ +M____@\0,_W7L:"P-``!3Z/S___^#Q!"-9?1;7E_)PXUV`%6)Y8/L"(M5"(I- +M#(!]$`!T$K@!````T^`(@H@```#K$(UV`+C^____T\`@@H@```"#[`@/MH*( +M````4%+H_/___\G#58GE5U93@^P4BWT(QD7S`&@L#0``5^C\____B47H@\0, +M@\@!4&@L#0``5^C\____@\0(:/`$`0!7Z/S___^)1>R#X&*#Q!"#^&)T&X/L +M!(I%[(/(8@^VP%!H\`0!`%?H_/___X/$$(/L"&@```0`5^C\____@\0(:``` +M!`!7Z/S___^#Q!!F/56J#X7U````O@````"-=@"[`````#GS?R>-=@"#[`1H +MH````*'@````BT`8!0``!`!05^C\____@\000SGS?MR!_L@```!^$(/L#&H! +MZ/S___^#Q!"-=@"#[`AH```$`%?H_/___XG#@\0,:+````"AX````(M`&`4` +M``0`4%?H_/___X/$$&:!^U6J=11&@?['````#XYU____9H'[5:IT6X/L!&BP +M````H>````"+0!@%```$`%!7Z/S___^#Q`AH```$`%?H_/___X/$$&8]5:IU +M*,9%\P&#[`Q7Z";Z__^#Q!`\/G44@^P,5^BN_/__@\00A7\G#58GE +M5E.+=0B[`````(UV`,<%X````*````"#[`Q6Z/W]__^#Q!"$P'4CQP7@```` +MP````(/L#%;HX_W__X/$$(3`=0E#@?OG`P``?L,/ML"-9?A;7LG#D%6)Y8M% +M#(!X`0)U&(!X`@%U$@^V0`.C!````+@`````ZP>)]KC_____R<.058GE5U93 +M@^P4BT4(BW`,BWT0:"P-``!6Z/S___^)1>R#Q`R#R`%0:"P-``!6Z/S___^# +MQ`AH\`0!`%;H_/___XE%\(/@8H/$$(/X8G0;@^P$BD7P@\AB#[;`4&CP!`$` +M5NC\____@\00@^P(:```!`!6Z/S___^#Q!"#?1@`=#"[`````#M=%'U6B?:# +M[`B+50R-A!H```0`4%;H_/___X@'@\000T<[711\X.LRB?:[`````#M=%'TF +MB?:#[`0/M@=0BU4,C80:```$`%!6Z/S___^#Q!!#1SM=%'S>B?:#[`3_=?!H +M\`0!`%;H_/___X/$"&CP!`$`5NC\____@\0,_W7L:"P-``!6Z/S___^#Q!"X +M`0```(UE]%M>7\G#``````````````````0````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````````````````0`````````````````````````````` +M`````````0`!``$``@`!``,``0`$``$`!0`!``8``0`'``$````!```@`0`` +M0`$``&`!``"``0``H`$``,`!``#@`0#`````N#H``'`Z``!P.@``@3H``)(Z +M``"C.@``M#H``(@[``!`.P``0#L``%$[``!B.P``6UT86(`+G-T`0```@`!`"P```!D$```9`````(``0`Y````>!8` +M`,X!```"``$`1@```.`<``!$`````@`!`%4````D'0``V@````(``0!F```` +ME!\``",````"``$`<@```+@?```@`````@`!`'T`````````!`````$`!0"* +M````V!\``(`!```"``$`F@```%@A``!I`````@`!`*,```#$(0``0@````(` +M`0"K````""(``#,````"``$`LP```#PB```^`````@`!`+X```!\(@``%``` +M``(``0#&````D"(``#$````"``$`V````,0B```H`````@`!`.<```#L(@`` +M`@``H&L``((#```" +M``$`+@(``"1O``!G`````@`!`$4"``",;P``FP4```(``0!0`@``*'4``/T# +M```"``$`7`(``"AY```[`````@`!`&P"``#4@```9P(```(``0!Y`@``L(@` +M`"P````"``$`B@(``%B)``!%`````@`!`)\"``"@B0``)0````(``0"R`@`` +MR(D``)$"```"``$`R`(``%R,``!2`0```@`!`-\"``"PC0``E`````(``0#W +M`@```*```$D````"``$`!0,``$2.``!<`0```@`!`!@#```LH@``HP````(` +M`0`G`P``B*,``"8"```"``$`.P,``-B5``!8`0```@`!`$X#``"@CP``D0`` +M``(``0!=`P``-)```,`"```"``$`<0,```";``!_`````@`!`(,#``#$F0`` +M.0$```(``0"1`P``-*,``%$````"``$`G@,``/22``!U`````@`!`+0#```D +MH0``4P````(``0#+`P``;),``*@!```"``$`W@,``!25``#!`````@`!`.X# +M``!XH0``L0````(``0#[`P``T*(``&(````"``$`#@0``#"7``#1`0```@`! +M`!\$```$F0``OP````(``0`M!```@)L```X"```"``$`/@0``)"=```=```` +M`@`!`%<$``"PG0``,0$```(``0!N!```Y)X``$(````"``$`@P0``"B?``!J +M`````@`!`)<$``"4GP``:P````(``0"B!```3*```"P````"``$`M`0``'B@ +M``"L`````@`!`,H$``#(N```<@,```(``0#@!```/+P``,H````"``$`[00` +M`*`````@`````0`#`/<$``#`````(`````$``P`!!0``X`````0````!``,` +M"04```0````$`````0`%`!@%``!$O0``HP````(``0`A!0``Z+T``$0````" +M``$`*04``"R^``!6`````@`!`#0%``#$P```N@````(``0`\!0``G,(``.`! +M```"``$``````````````````P`(`%0%````````,`<``!(``0!@!0``(``` +M`"0````1``,`;P4`````````````$````'P%``!@````)````!$``P",!0`` +M1(```"H````2``$`E04`````````````$````*,%`````````````!````"M +M!0`````````````0````MP4`````````````$````,$%`````````````!`` +M``#2!0`````````````0````X@4`````````````$````.P%```P!P``VP`` +M`!(``0#V!0`````````````0`````P8`````````````$````!4&```,"``` +MO`$``!(``0`E!@`````````````0````+@8``'"```!C````$@`!`#P&``#( +M"0``6@```!(``0!/!@``[(,``!(````2``$`708``"0*``!``0``$@`!`&H& +M``#$@P``*````!(``0!\!@``L'T``&,````2``$`AP8``&0+```5`0``$@`! +M`)H&`````````````!````"D!@`````````````0````K@8``$P.``!@```` +M$@`!`+\&``#$A@``$P```!(``0#+!@``1(4``#D````2``$`VP8``*P.```$ +M`0``$@`!`.T&``"0A@``,0```!(``0#]!@``L`\``$(````2``$`$`<``/0/ +M``!O````$@`!`"('``#($```9`$``!(``0`X!P``+!(``(`````2``$`50<` +M`*P2``"\````$@`!`&D'````AP``3@```!(``0!W!P``:!,``-D````2``$` +MC@<``$04```_`0``$@`!`*8'``"$%0``\P```!(``0"\!P`````````````0 +M````Q@<``$@8``#,`0``$@`!`-@'``#8A@``)P```!(``0#I!P``%!H``%$! +M```2``$`_`<``&@;``!V`0``$@`!``T(````'@``8````!(``0`="```8!X` +M```!```2``$`+@@``&`?```R````$@`!`$`(````````!````!$``P!0"``` +M```````````0````7@@``*AG```P`0``$@`!`'$(`````````````!````"$ +M"``````````````0````BP@`````````````$````)((``#8:```80```!(` +M`0">"``````````````0````P`@``!B&``!X````$@`!`,X(``"`:@``4``` +M`!(``0#@"```9'D``$P$```2``$`\@@``!!_```T`0``$@`!``4)```4?@`` +M_````!(``0`7"0`````````````0````*0D`````````````$````#P)```\ +M@P``/@```!(``0!+"0``?(,``$<````2``$`6@D```"$``!#`0``$@`!`&D) +M``"`A0``6````!(``0!Z"0``V(4``#\````2``$`APD``%"'```>````$@`! +M`)()``!PAP``-````!(``0"B"0``I(<```L!```2``$`K@D``$"M``!#```` +M$@`!`,8)``"$K0``2````!(``0#:"0``^+<``#T````2``$`]0D``#BX``". +M````$@`!`!H*``#TK```3````!(``0`Q"@``W(@``'H````2``$`2`H````` +M````````$````%P*`````````````!````!M"@`````````````0````@`H` +M`(0````$````$0`#`),*`````````````!````"E"@`````````````0```` +MMPH``(2I``"8````$@`!`-8*`````````````!````#H"@`````````````0 +M````^0H```B]```[````$@`!``@+``!4M0``C0```!(``0`="P``L*4``!P# +M```2``$`+PL``'S$``!7````$@`!`$4+``#,J```'P```!(``0!;"P``[*@` +M``\````2``$`;0L``/RH```/````$@`!`(`+```,J0``3@```!(``0"7"P`` +M7*D``"8````2``$`JPL``!RJ```T`@``$@`!`,(+``!0K```H@```!(``0#7 +M"P``S*T``"`````2``$`[@L``.RM``#0````$@`!``@,``"\K@``C````!(` +M`0`A#```2*\``!$!```2``$`.0P``%RP``!O`0``$@`!`%`,``#,L0``>0$` +M`!(``0!C#```2+,``,L!```2``$`@0P``!2U```?````$@`!`)P,```TM0`` +M(````!(``0"Y#```Y+4``#P````2``$`TPP``""V```\````$@`!`.X,``!< +MM@``E````!(``0`+#0``\+8``-0````2``$`*0T``,2W```S````$@`!`$@- +M``"$O@``*`$``!(``0!/#0``K+\``!F5R;P!C9E]I;FET`')E;6]V95]R86YG95]L;V-K`&%D9%]R +M86YG95]L;V-K`&QO8VM?&9E +M0!T87-K7V1O;F4`&]R7W1A&]R7W1A +M&]R;E]T87-K`&-H96-K7V1E<&5N +M9&5N8WD`9&ER96-T7W)E861?0!D=6UP +M071A1&5V:6-E4F5G:7-T97)S`&AA;F1L945D;6%&86EL961#;VUM86YD`')E +M;6]V94-O;6UA;F0`:&%N9&QE161M85)E%!H>5!A0!F061D4W!A'5P07)R87E3=&%T +M90!'9713=&%M<`!3>6YC07)R87E);F9O`$-H96-K07)R87E#0!5;G)E9VES=&5R5D1E=FEC90!R +M86ED-5]F6YC`&UV4F5A +M9%=R:71E`&UV4V%T841I5-H=71D +M;W=N`&UV4V%T84-H86YN96Q0:'E0;W=E#4P.'A?:6]C=&P`0``M@T```)Z +M``!]#@```GP``)X.```"?0``T@X```)]```!#P```GT``#,/```"?P``>@\` +M``%[``"!#P```7@``#,1```"9P``A1$```)G``#&$0```GP``/L1```"?0`` +MY!(```)\```[$P```GT``%$3```!A0``61,```)]``"E$P```F<```@4```" +M?```%Q0```)]```M%````84``#44```"?0``QQ4```)G``#S%0```HD``$(6 +M```"?```3Q8```)]``!E%@```84``&L6```"?0``ZA8```)G```#%P```G\` +M`"L7```!A```,A<```&#``!Q%P```G\``)D7```!A@``H!<```&#``#1%P`` +M`G\``/D7```!B````!@```&'```E&````GT``#08```!A0``.A@```)]``!K +M&````GT``'T8```!`@``ZQ@```&*``#X&````HL``+H9```"?P``R1D```)L +M``#D&0```8(``.L9```!@0``N1H```)N``#1&@```6(``-D:```!9```%QL` +M``)O``!*&P```G$``%H;```"<@``S1P```)L```Q'@```GP``%(>```"?0`` +MAAX```)]``"R'@```GT``.,>```"?P``*A\```&.```Q'P```8T``(\@```" +MD@``)R(```)G``"*(@```F<``.@F```">@``Y"@```)L```%*0```FP``(:P```84``&1K```"?0`` +MCVL```*3``#>;````00``.EL```!!```[FP```*4``!$;P```GP``.%Q```" +M9P``2W0```&%``!3=````GT``(=T```"?P``MW0```$"``"^=````0(``,)U +M```">@``X74```)Z``!#>0```0(``$EY```"?0``D'D```)]``#">0```F<` +M`.UY```"?0``%WH```)]``"?>@```GD``'%[```">0``!WP```)]``"X?``` +M`9L``,A\```"BP``'GT```&<```[?0```9L``$U]```"BP``6'T```*3``!M +M?0```0(``)%]```"?0``Q7T```*7``!A?@```9$``)=^```!D0``PGX```*> +M``#'?@```00``-%^```!D0``W7X```*>```!?P```9$``+Y_```";@``W'\` +M``%B``#D?P```60``!"````";P``*H````)Q```V@````G(``*R````"<@`` +M'X$```)G```[@@```FP``%""```";```:((```)L``!]@@```FP``/^"```" +M90``#X,```)E```O@P```F,``'.#```"H```HX,```*A``#X@P```G8``#V$ +M```"9P``C(0```)C``#+A````F,``&>&```"F```MH8```)G``!CAP```I<` +M`(^'```"F@``Q(<```*H``#0AP```JD``.2'```"J@``DX@```*K``"?B``` +M`JP``/.(```"K@``&8D```*O```UB0```JX``'N)```"L```CXD```*P``"_ +MB0```K```(>,```"L@``EXP```*O``"LC````J\``,>,```"KP``XHP```*O +M``#]C````J\``!^-```"L@``*XT```*O```^C0```J\``%&-```"KP``9(T` +M``*O``!YC0```K(``(R-```"KP``GXT```*O``#=```"L```TIT```*S``#FG0```K```/F=```"LP``#YX```*P```A +MG@```K```#.>```"L```2)X```*P``!:G@```K```&R>```"L```?IX```*P +M``"0G@```K```**>```"L```M)X```*P``#&G@```K```-B>```"L```N9\` +M``)L``#2GP```FP``*N@```"KP``VZ````*P``#KH````K,```6A```"L``` +M%:$```*S``!,H0```K,``&:A```"L```S:$```*P``#AH0```K````*B```" +MKP``':(```*P``!BH@```K```'6B```"LP``B:(```*N```GHP```K```%:C +M```"MP``K*,```*O``#=HP```K(``/*C```"L@``!Z0```*R```G```"L```%Z<```*S +M```QIP```K```$VG```"LP``P:<```*P``#4IP```K```.>G```"L```#J@` +M``*P```PJ````K```&>H```"K@``C:@```*T``#@J````K```/&H```!L0`` +M`:D```&Q``"ZJ0```K,``."I```"LP``[*D```*N``#XJ0```K,``.FJ```" +MLP``&:L```*P``!*JP```K,``%:K```"K@``BJL```*P``"ZJP```K,``,:K +M```"K@``U*L```*M```.K````J\``(VL```"LP``WJP```*P``!>K@```K,` +M`(^N```"L```[*X```*S```9KP```K```#2O```"LP``C:\```*S``"YKP`` +M`K```-2O```"LP```K````*S```VL````K```*:P```"LP``U+````*T```D +ML0```K,``#FQ```"LP``3K$```*S``!CL0```K,``'BQ```"LP``C;$```*S +M``"BL0```K,``+>Q```"LP``8;,```*S``"FLP```K,``,VS```"L```#K0` +M``*P```:M````K,``"ZT```"L```2K0```*S```HM0```K```$FU```"L``` +MB[4```*O``"SM0```JX``,*U```"M````+8```*R```7M@```J\``#RV```" +ML@``4[8```*O``"2M@```LP``*>V```"L@``O;8```*X``#-M@```LL``-VV +M```"RP``1+<```*K``!PMP```JH``/&W```"MP``+[@```*K```_N0```K@` +M`%BY```"S```?;D```*R``"6N0```K(``*^Y```"L@``R+D```*R``#AN0`` +M`K(``!NZ```"RP``/;H```*R``!4N@```K(``&NZ```"L@``@KH```*R``"9 +MN@```K(``+"Z```"L@``Q[H```*R``#GN@```K@``/>Z```"RP``"KL```++ +M```KNP```K@``#N[```"RP``5[L```*O``!GNP```LL``*"[```"N```N;L` +M``*V``#9NP```K4``/:[```"N```!KP```++```6O````LL``":\```"RP`` +M7+P```*R``!NO````J\``'J\```"K@``@KP```++``".O````JX``)J\```" +MK@``IKP```*N``"RO````JX``,R\```"KP``Z;P```*N```NO0```JX``%6] +M```!`P``9+T```*R``!TO0```0,``(.]```"KP``G+T```$#``"KO0```J\` +M`,2]```!`P``T[T```*O``#XO0```0,```>^```"L@``%+X```$#```CO@`` +M`K(``$.^```!`P``4KX```*R``!:O@```0,``&B^```"KP``DKX```$$``"G +MO@```K,``+N^```"L```R;X```*S``#MO@```K4``/Z^```"LP``$+\```$# +M```?OP```K(``"F_```!`P``-[\```*R``!!OP```0,``%"_```"L@``6K\` +M``$#``!HOP```K(``'^_```"L```C;\```*S``"``` +M``&,``"``````9P``.`````!`P````````$"```$`````0(```@````!`@`` +M#`````$"```0`````0(``!0````!`@``&`````$"```<`````0(``"`````! +K`@``)`````$"```H`````0(``"P````!`@``,`````$"```T`````0(````` +` +end diff --git a/sys/dev/raid/hptmv/ioctl.c b/sys/dev/raid/hptmv/ioctl.c new file mode 100644 index 0000000000..7e6482a09c --- /dev/null +++ b/sys/dev/raid/hptmv/ioctl.c @@ -0,0 +1,972 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/ioctl.c,v 1.9 2009/04/07 16:38:25 delphij Exp $ + */ +/* + * ioctl.c ioctl interface implementation + */ +#include +#include +#include +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include + +#pragma pack(1) + +typedef struct _HPT_REBUILD_PARAM +{ + DEVICEID idMirror; + DWORD Lba; + UCHAR nSector; +} HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM; + +#pragma pack() + +#define MAX_EVENTS 10 +static HPT_EVENT hpt_event_queue[MAX_EVENTS]; +static int event_queue_head=0, event_queue_tail=0; + +static int hpt_get_event(PHPT_EVENT pEvent); +static int hpt_set_array_state(DEVICEID idArray, DWORD state); +static intrmask_t lock_driver_idle(IAL_ADAPTER_T *pAdapter); +static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd); +static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd, + FPSCAT_GATH pSgTable, int logical); + +static void +get_disk_location(PDevice pDev, int *controller, int *channel) +{ + IAL_ADAPTER_T *pAdapTemp; + int i, j; + + *controller = *channel = 0; + + for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) { + for (j=0; jVDevices[j].u.disk) { + *controller = i; + *channel = j; + return; + } + } + } +} + +static int +event_queue_add(PHPT_EVENT pEvent) +{ + int p; + p = (event_queue_tail + 1) % MAX_EVENTS; + if (p==event_queue_head) + { + return -1; + } + hpt_event_queue[event_queue_tail] = *pEvent; + event_queue_tail = p; + return 0; +} + +static int +event_queue_remove(PHPT_EVENT pEvent) +{ + if (event_queue_head != event_queue_tail) + { + *pEvent = hpt_event_queue[event_queue_head]; + event_queue_head++; + event_queue_head %= MAX_EVENTS; + return 0; + } + return -1; +} + +void HPTLIBAPI +ioctl_ReportEvent(UCHAR event, PVOID param) +{ + HPT_EVENT e; + ZeroMemory(&e, sizeof(e)); + e.EventType = event; + switch(event) + { + case ET_INITIALIZE_ABORTED: + case ET_INITIALIZE_FAILED: + memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME); + case ET_INITIALIZE_STARTED: + case ET_INITIALIZE_FINISHED: + + case ET_REBUILD_STARTED: + case ET_REBUILD_ABORTED: + case ET_REBUILD_FAILED: + case ET_REBUILD_FINISHED: + + case ET_VERIFY_STARTED: + case ET_VERIFY_ABORTED: + case ET_VERIFY_FAILED: + case ET_VERIFY_FINISHED: + case ET_VERIFY_DATA_ERROR: + + case ET_SPARE_TOOK_OVER: + case ET_DEVICE_REMOVED: + case ET_DEVICE_PLUGGED: + case ET_DEVICE_ERROR: + e.DeviceID = VDEV_TO_ID((PVDevice)param); + break; + + default: + break; + } + event_queue_add(&e); + if (event==ET_DEVICE_REMOVED) { + int controller, channel; + get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel); + hpt_printk(("Device removed: controller %d channel %d\n", controller, channel)); + } +} + +static int +hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options) +{ + PVDevice pArray = ID_TO_VDEV(id); + BOOLEAN del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1; + int i; + PVDevice pa; + + if ((id==0) || check_VDevice_valid(pArray)) + return -1; + + if(!mIsArray(pArray)) return -1; + + if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying || + pArray->u.array.rf_initializing) + return -1; + + for(i=0; iu.array.bArnMember; i++) { + pa = pArray->u.array.pMember[i]; + if (pa && mIsArray(pa)) { + if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying || + pa->u.array.rf_initializing) + return -1; + } + } + + if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;} + fDeleteArray(_VBUS_P pArray, del_block0); + return 0; + +} + +/* just to prevent driver from sending more commands */ +static void HPTLIBAPI nothing(_VBUS_ARG void *notused){} + +intrmask_t +lock_driver_idle(IAL_ADAPTER_T *pAdapter) +{ + intrmask_t oldspl; + _VBUS_INST(&pAdapter->VBus) + oldspl = lock_driver(); + while (pAdapter->outstandingCommands) { + KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands)); + if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0); + unlock_driver(oldspl); +/*Schedule out*/ + tsleep(lock_driver_idle, 0, "switch", 1); + oldspl = lock_driver(); + } + CheckIdleCall(_VBUS_P0); + return oldspl; +} + +int Kernel_DeviceIoControl(_VBUS_ARG + DWORD dwIoControlCode, /* operation control code */ + PVOID lpInBuffer, /* input data buffer */ + DWORD nInBufferSize, /* size of input data buffer */ + PVOID lpOutBuffer, /* output data buffer */ + DWORD nOutBufferSize, /* size of output data buffer */ + PDWORD lpBytesReturned /* byte count */ + ) +{ + IAL_ADAPTER_T *pAdapter; + + switch(dwIoControlCode) { + case HPT_IOCTL_DELETE_ARRAY: + { + DEVICEID idArray; + int iSuccess; + int i; + PVDevice pArray; + PVBus _vbus_p; + struct cam_periph *periph = NULL; + + if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1; + if (nOutBufferSize!=sizeof(int)) return -1; + idArray = *(DEVICEID *)lpInBuffer; + + pArray = ID_TO_VDEV(idArray); + + if((idArray == 0) || check_VDevice_valid(pArray)) + return -1; + + if(!mIsArray(pArray)) + return -1; + + _vbus_p=pArray->pVBus; + pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt; + + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) { + if(pArray == _vbus_p->pVDevice[i]) + { + periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i); + if (periph != NULL && periph->refcount >= 1) + { + hpt_printk(("Can not delete a mounted device.\n")); + return -1; + } + } + /* the Mounted Disk isn't delete */ + } + + iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1)); + + *(int*)lpOutBuffer = iSuccess; + + if(iSuccess != 0) + return -1; + break; + } + + case HPT_IOCTL_GET_EVENT: + { + PHPT_EVENT pInfo; + + if (nInBufferSize!=0) return -1; + if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1; + + pInfo = (PHPT_EVENT)lpOutBuffer; + + if (hpt_get_event(pInfo)!=0) + return -1; + } + break; + + case HPT_IOCTL_SET_ARRAY_STATE: + { + DEVICEID idArray; + DWORD state; + + if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1; + if (nOutBufferSize!=0) return -1; + + idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray; + state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state; + + if(hpt_set_array_state(idArray, state)!=0) + return -1; + } + break; + + case HPT_IOCTL_RESCAN_DEVICES: + { + if (nInBufferSize!=0) return -1; + if (nOutBufferSize!=0) return -1; + +#ifndef FOR_DEMO + /* stop buzzer if user perform rescan */ + for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { + if (pAdapter->beeping) { + pAdapter->beeping = 0; + BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress); + } + } +#endif + } + break; + + default: + { + PVDevice pVDev; +#ifdef SUPPORT_ARRAY + intrmask_t oldspl; +#endif + switch(dwIoControlCode) { + /* read-only ioctl functions can be called directly. */ + case HPT_IOCTL_GET_VERSION: + case HPT_IOCTL_GET_CONTROLLER_IDS: + case HPT_IOCTL_GET_CONTROLLER_COUNT: + case HPT_IOCTL_GET_CONTROLLER_INFO: + case HPT_IOCTL_GET_CHANNEL_INFO: + case HPT_IOCTL_GET_LOGICAL_DEVICES: + case HPT_IOCTL_GET_DEVICE_INFO: + case HPT_IOCTL_GET_DEVICE_INFO_V2: + case HPT_IOCTL_GET_EVENT: + case HPT_IOCTL_GET_DRIVER_CAPABILITIES: + if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1; + break; + + default: + /* + * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be + * wrong for second controller. + */ + switch(dwIoControlCode) { + case HPT_IOCTL_CREATE_ARRAY: + pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break; + case HPT_IOCTL_CREATE_ARRAY_V2: + pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break; + case HPT_IOCTL_SET_ARRAY_INFO: + pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break; + case HPT_IOCTL_SET_DEVICE_INFO: + pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break; + case HPT_IOCTL_SET_DEVICE_INFO_V2: + pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break; + case HPT_IOCTL_SET_BOOT_MARK: + case HPT_IOCTL_ADD_SPARE_DISK: + case HPT_IOCTL_REMOVE_SPARE_DISK: + pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break; + case HPT_IOCTL_ADD_DISK_TO_ARRAY: + pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break; + default: + pVDev = 0; + } + + if (pVDev && !check_VDevice_valid(pVDev)){ + _vbus_p = pVDev->pVBus; + + pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt; + /* + * create_array, and other functions can't be executed while channel is + * perform I/O commands. Wait until driver is idle. + */ + oldspl = lock_driver_idle(pAdapter); + if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) { + unlock_driver(oldspl); + return -1; + } + unlock_driver(oldspl); + } + else + return -1; + break; + } + +#ifdef SUPPORT_ARRAY + switch(dwIoControlCode) + { + case HPT_IOCTL_CREATE_ARRAY: + { + pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt; + oldspl = lock_driver(); + if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) + { + (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE); + } + else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) + { + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE); + } + else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) + { + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY); + } + unlock_driver(oldspl); + break; + } + + + case HPT_IOCTL_CREATE_ARRAY_V2: + { + pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt; + oldspl = lock_driver(); + if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) { + (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE); + } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) { + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE); + } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) { + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY); + } + unlock_driver(oldspl); + break; + } + case HPT_IOCTL_ADD_DISK_TO_ARRAY: + { + PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); + pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt; + if(pArray->u.array.rf_rebuilding == 0) + { + DWORD timeout = 0; + oldspl = lock_driver(); + pArray->u.array.rf_auto_rebuild = 0; + pArray->u.array.rf_abort_rebuild = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE); + unlock_driver(oldspl); + while (!pArray->u.array.rf_rebuilding) + { + tsleep((caddr_t)Kernel_DeviceIoControl, 0, "pause", 1); + if ( timeout >= hz*3) + break; + timeout ++; + } + } + break; + } + } +#endif + return 0; + } + } + + if (lpBytesReturned) + *lpBytesReturned = nOutBufferSize; + return 0; +} + +static int +hpt_get_event(PHPT_EVENT pEvent) +{ + intrmask_t oldspl = lock_driver(); + int ret = event_queue_remove(pEvent); + unlock_driver(oldspl); + return ret; +} + +static int +hpt_set_array_state(DEVICEID idArray, DWORD state) +{ + IAL_ADAPTER_T *pAdapter; + PVDevice pVDevice = ID_TO_VDEV(idArray); + int i; + DWORD timeout = 0; + intrmask_t oldspl; + + if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1; + if(!mIsArray(pVDevice)) + return -1; + if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1; + + pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt; + + switch(state) + { + case MIRROR_REBUILD_START: + { + if (pVDevice->u.array.rf_rebuilding || + pVDevice->u.array.rf_verifying || + pVDevice->u.array.rf_initializing) + return -1; + + oldspl = lock_driver(); + + pVDevice->u.array.rf_auto_rebuild = 0; + pVDevice->u.array.rf_abort_rebuild = 0; + + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, + (UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY)); + + unlock_driver(oldspl); + + while (!pVDevice->u.array.rf_rebuilding) + { + tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); + if ( timeout >= hz*20) + break; + timeout ++; + } + } + + break; + + case MIRROR_REBUILD_ABORT: + { + for(i = 0; i < pVDevice->u.array.bArnMember; i++) { + if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1) + hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state); + } + + if(pVDevice->u.array.rf_rebuilding != 1) + return -1; + + oldspl = lock_driver(); + pVDevice->u.array.rf_abort_rebuild = 1; + unlock_driver(oldspl); + + while (pVDevice->u.array.rf_abort_rebuild) + { + tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); + if ( timeout >= hz*20) + break; + timeout ++; + } + } + break; + + case AS_VERIFY_START: + { + /*if(pVDevice->u.array.rf_verifying) + return -1;*/ + if (pVDevice->u.array.rf_rebuilding || + pVDevice->u.array.rf_verifying || + pVDevice->u.array.rf_initializing) + return -1; + + oldspl = lock_driver(); + pVDevice->u.array.RebuildSectors = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY); + unlock_driver(oldspl); + + while (!pVDevice->u.array.rf_verifying) + { + tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); + if ( timeout >= hz*20) + break; + timeout ++; + } + } + break; + + case AS_VERIFY_ABORT: + { + if(pVDevice->u.array.rf_verifying != 1) + return -1; + + oldspl = lock_driver(); + pVDevice->u.array.rf_abort_rebuild = 1; + unlock_driver(oldspl); + + while (pVDevice->u.array.rf_abort_rebuild) + { + tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); + if ( timeout >= hz*80) + break; + timeout ++; + } + } + break; + + case AS_INITIALIZE_START: + { + if (pVDevice->u.array.rf_rebuilding || + pVDevice->u.array.rf_verifying || + pVDevice->u.array.rf_initializing) + return -1; + + oldspl = lock_driver(); + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY); + unlock_driver(oldspl); + + while (!pVDevice->u.array.rf_initializing) + { + tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); + if ( timeout >= hz*80) + break; + timeout ++; + } + } + break; + + case AS_INITIALIZE_ABORT: + { + if(pVDevice->u.array.rf_initializing != 1) + return -1; + + oldspl = lock_driver(); + pVDevice->u.array.rf_abort_rebuild = 1; + unlock_driver(oldspl); + + while (pVDevice->u.array.rf_abort_rebuild) + { + tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); + if ( timeout >= hz*80) + break; + timeout ++; + } + } + break; + + default: + return -1; + } + + return 0; +} + +int HPTLIBAPI +R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical) +{ + ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors); + if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY) + bufferSize<<=1; + if (logical) { + pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer; + pSgTable->wSgSize = (USHORT)bufferSize; + pSgTable->wSgFlag = SG_FLAG_EOT; + } + else { + /* build physical SG table for pCmd->uCmd.R1Control.Buffer */ + ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage; + ULONG length; + int idx = 0; + + v = pCmd->uCmd.R1Control.Buffer; + dataPointer = (ADDRESS)fOsPhysicalAddress(v); + + if ((ULONG_PTR)dataPointer & 0x1) + return FALSE; + + #define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0) + #define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE) + + do { + if (idx >= MAX_SG_DESCRIPTORS) return FALSE; + + pSgTable[idx].dSgAddress = fOsPhysicalAddress(v); + currvaddr = v; + currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr)); + + + do { + nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE)); + nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage)); + + if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break; + nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage); + + if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) { + nextvaddr = nextpage; + break; + } + + currvaddr = nextvaddr; + currphypage = nextphypage; + }while (1); + + length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v; + v = nextvaddr; + bufferSize -= length; + + pSgTable[idx].wSgSize = (USHORT)length; + pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT; + idx++; + + }while (bufferSize); + } + return 1; +} + +static int End_Job=0; +void HPTLIBAPI +thread_io_done(_VBUS_ARG PCommand pCmd) +{ + End_Job = 1; + wakeup((caddr_t)pCmd); +} + +void +hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags) +{ + DWORD timeout = 0; + ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1); + PCommand pCmd; + UINT result; + int needsync=0, retry=0, needdelete=0; + void *buffer = 0; + intrmask_t oldspl; + + _VBUS_INST(&pAdapter->VBus) + + if (pArray->u.array.rf_broken==1 || + pArray->u.array.RebuildSectors>=capacity) + return; + + oldspl = lock_driver(); + + switch(flags) + { + case DUPLICATE: + case REBUILD_PARITY: + if(pArray->u.array.rf_rebuilding == 0) + { + pArray->u.array.rf_rebuilding = 1; + hpt_printk(("Rebuilding started.\n")); + ioctl_ReportEvent(ET_REBUILD_STARTED, pArray); + } + break; + + case INITIALIZE: + if(pArray->u.array.rf_initializing == 0) + { + pArray->u.array.rf_initializing = 1; + hpt_printk(("Initializing started.\n")); + ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray); + } + break; + + case VERIFY: + if(pArray->u.array.rf_verifying == 0) + { + pArray->u.array.rf_verifying = 1; + hpt_printk(("Verifying started.\n")); + ioctl_ReportEvent(ET_VERIFY_STARTED, pArray); + } + break; + } + +retry_cmd: + pCmd = AllocateCommand(_VBUS_P0); + HPT_ASSERT(pCmd); + pCmd->cf_control = 1; + End_Job = 0; + + if (pArray->VDeviceType==VD_RAID_1) + { + #define MAX_REBUILD_SECTORS 0x40 + + /* take care for discontinuous buffer in R1ControlSgl */ + unlock_driver(oldspl); + buffer = kmalloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT); + oldspl = lock_driver(); + if(!buffer) { + FreeCommand(_VBUS_P pCmd); + hpt_printk(("can't allocate rebuild buffer\n")); + goto fail; + } + switch(flags) + { + case DUPLICATE: + pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD; + pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS; + break; + + case VERIFY: + pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY; + pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2; + break; + + case INITIALIZE: + pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD; + pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS; + break; + } + + pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors; + + if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors) + pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors; + + pCmd->uCmd.R1Control.Buffer = buffer; + pCmd->pfnBuildSgl = R1ControlSgl; + } + else if (pArray->VDeviceType==VD_RAID_5) + { + switch(flags) + { + case DUPLICATE: + case REBUILD_PARITY: + pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break; + case VERIFY: + pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break; + case INITIALIZE: + pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break; + } + pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift; + } + else + HPT_ASSERT(0); + + pCmd->pVDevice = pArray; + pCmd->pfnCompletion = thread_io_done; + pArray->pfnSendCommand(_VBUS_P pCmd); + CheckPendingCall(_VBUS_P0); + + if (!End_Job) { + unlock_driver(oldspl); + while (!End_Job) { + tsleep((caddr_t)pCmd, 0, "pause", hz); + if (timeout++>60) break; + } + oldspl = lock_driver(); + if (!End_Job) { + hpt_printk(("timeout, reset\n")); + fResetVBus(_VBUS_P0); + } + } + + result = pCmd->Result; + FreeCommand(_VBUS_P pCmd); + unlock_driver(oldspl); + if (buffer) kfree(buffer, M_DEVBUF); + oldspl = lock_driver(); + KdPrintI(("cmd finished %d", result)); + + switch(result) + { + case RETURN_SUCCESS: + if (!pArray->u.array.rf_abort_rebuild) + { + if(pArray->u.array.RebuildSectors < capacity) + { + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags); + } + else + { + switch (flags) + { + case DUPLICATE: + case REBUILD_PARITY: + needsync = 1; + pArray->u.array.rf_rebuilding = 0; + pArray->u.array.rf_need_rebuild = 0; + pArray->u.array.CriticalMembers = 0; + pArray->u.array.RebuildSectors = MAX_LBA_T; + pArray->u.array.rf_duplicate_and_create = 0; + hpt_printk(("Rebuilding finished.\n")); + ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray); + break; + case INITIALIZE: + needsync = 1; + pArray->u.array.rf_initializing = 0; + pArray->u.array.rf_need_rebuild = 0; + pArray->u.array.RebuildSectors = MAX_LBA_T; + hpt_printk(("Initializing finished.\n")); + ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray); + break; + case VERIFY: + pArray->u.array.rf_verifying = 0; + hpt_printk(("Verifying finished.\n")); + ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray); + break; + } + } + } + else + { + pArray->u.array.rf_abort_rebuild = 0; + if (pArray->u.array.rf_rebuilding) + { + hpt_printk(("Abort rebuilding.\n")); + pArray->u.array.rf_rebuilding = 0; + pArray->u.array.rf_duplicate_and_create = 0; + ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray); + } + else if (pArray->u.array.rf_verifying) + { + hpt_printk(("Abort verifying.\n")); + pArray->u.array.rf_verifying = 0; + ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray); + } + else if (pArray->u.array.rf_initializing) + { + hpt_printk(("Abort initializing.\n")); + pArray->u.array.rf_initializing = 0; + ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray); + } + needdelete=1; + } + break; + + case RETURN_DATA_ERROR: + if (flags==VERIFY) + { + needsync = 1; + pArray->u.array.rf_verifying = 0; + pArray->u.array.rf_need_rebuild = 1; + hpt_printk(("Verifying failed: found inconsistency\n")); + ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray); + ioctl_ReportEvent(ET_VERIFY_FAILED, pArray); + + if (!pArray->vf_online || pArray->u.array.rf_broken) break; + + pArray->u.array.rf_auto_rebuild = 0; + pArray->u.array.rf_abort_rebuild = 0; + hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, + (pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY); + } + break; + + default: + hpt_printk(("command failed with error %d\n", result)); + if (++retry<3) + { + hpt_printk(("retry (%d)\n", retry)); + goto retry_cmd; + } +fail: + pArray->u.array.rf_abort_rebuild = 0; + switch (flags) + { + case DUPLICATE: + case REBUILD_PARITY: + needsync = 1; + pArray->u.array.rf_rebuilding = 0; + pArray->u.array.rf_duplicate_and_create = 0; + hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n")); + ioctl_ReportEvent(ET_REBUILD_FAILED, pArray); + break; + + case INITIALIZE: + needsync = 1; + pArray->u.array.rf_initializing = 0; + hpt_printk(("Initializing failed.\n")); + ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray); + break; + + case VERIFY: + needsync = 1; + pArray->u.array.rf_verifying = 0; + hpt_printk(("Verifying failed.\n")); + ioctl_ReportEvent(ET_VERIFY_FAILED, pArray); + break; + } + needdelete=1; + } + + while (pAdapter->outstandingCommands) + { + KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands)); + /* put this to have driver stop processing system commands quickly */ + if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0); + unlock_driver(oldspl); + /*Schedule out*/ + tsleep(hpt_rebuild_data_block, 0, "switch", 1); + oldspl = lock_driver(); + } + + if (needsync) SyncArrayInfo(pArray); + if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE))) + fDeleteArray(_VBUS_P pArray, TRUE); + + Check_Idle_Call(pAdapter); + unlock_driver(oldspl); +} diff --git a/sys/dev/raid/hptmv/mv.c b/sys/dev/raid/hptmv/mv.c new file mode 100644 index 0000000000..77cda6725b --- /dev/null +++ b/sys/dev/raid/hptmv/mv.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/mv.c,v 1.3 2005/09/07 23:33:26 scottl Exp $ + */ +#include +#include + +#include +#include +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include + + +void HPTLIBAPI +MV_REG_WRITE_BYTE(MV_BUS_ADDR_T base, MV_U32 offset, MV_U8 val) +{ + writeb((void *)((ULONG_PTR)base + offset), val); +} + +void HPTLIBAPI +MV_REG_WRITE_WORD(MV_BUS_ADDR_T base, MV_U32 offset, MV_U16 val) +{ + writew((void *)((ULONG_PTR)base + offset), val); +} + +void HPTLIBAPI +MV_REG_WRITE_DWORD(MV_BUS_ADDR_T base, MV_U32 offset, MV_U32 val) +{ + writel((void *)((ULONG_PTR)base + offset), val); +} + +MV_U8 HPTLIBAPI +MV_REG_READ_BYTE(MV_BUS_ADDR_T base, MV_U32 offset) +{ + return readb((void *)((ULONG_PTR)base + offset)); +} + +MV_U16 HPTLIBAPI +MV_REG_READ_WORD(MV_BUS_ADDR_T base, MV_U32 offset) +{ + return readw((void *)((ULONG_PTR)base + offset)); +} + +MV_U32 HPTLIBAPI +MV_REG_READ_DWORD(MV_BUS_ADDR_T base, MV_U32 offset) +{ + return readl((void *)((ULONG_PTR)base + offset)); +} + +int HPTLIBAPI +os_memcmp(const void *cs, const void *ct, unsigned len) +{ + return memcmp(cs, ct, len); +} + +void HPTLIBAPI +os_memcpy(void *to, const void *from, unsigned len) +{ + memcpy(to, from, len); +} + +void HPTLIBAPI +os_memset(void *s, char c, unsigned len) +{ + memset(s, c, len); +} + +unsigned HPTLIBAPI +os_strlen(const char *s) +{ + return strlen(s); +} + +void HPTLIBAPI +mvMicroSecondsDelay(MV_U32 msecs) +{ + DELAY(msecs); +} + +ULONG_PTR HPTLIBAPI +fOsPhysicalAddress(void *addr) +{ + return (ULONG_PTR)(vtophys(addr)); +} diff --git a/sys/dev/raid/hptmv/mvOs.h b/sys/dev/raid/hptmv/mvOs.h new file mode 100644 index 0000000000..8a1723e42d --- /dev/null +++ b/sys/dev/raid/hptmv/mvOs.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/mvOs.h,v 1.6 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef __INCmvOsBsdh +#define __INCmvOsBsdh + +#ifdef DEBUG +#define MV_DEBUG_LOG +#endif + +#define ENABLE_READ_AHEAD +#define ENABLE_WRITE_CACHE + +/* Typedefs */ +/*#define HPTLIBAPI __attribute__((regparm(0))) */ +#define HPTLIBAPI +#define FAR +#define SS_SEG +#ifdef FASTCALL +#undef FASTCALL +#endif +#define FASTCALL HPTLIBAPI +#define PASCAL HPTLIBAPI + +typedef unsigned short USHORT; +typedef unsigned char UCHAR; +typedef unsigned char *PUCHAR; +typedef unsigned short *PUSHORT; +typedef unsigned char BOOLEAN; +typedef unsigned short WORD; +typedef unsigned int UINT, BOOL; +typedef unsigned char BYTE; +typedef void *PVOID, *LPVOID; +typedef void *ADDRESS; + +typedef int LONG; +typedef unsigned int ULONG, *PULONG; +typedef unsigned int DWORD, *LPDWORD, *PDWORD; +typedef unsigned long ULONG_PTR, UINT_PTR, BUS_ADDR; +typedef unsigned long long HPT_U64, LBA_T; + +typedef enum mvBoolean{MV_FALSE, MV_TRUE} MV_BOOLEAN; + +#define FALSE 0 +#define TRUE 1 + +#ifndef NULL +#define NULL 0 +#endif + +/* System dependant typedefs */ +typedef void MV_VOID; +typedef unsigned int MV_U32; +typedef unsigned short MV_U16; +typedef unsigned char MV_U8; +typedef void *MV_VOID_PTR; +typedef MV_U32 *MV_U32_PTR; +typedef MV_U16 *MV_U16_PTR; +typedef MV_U8 *MV_U8_PTR; +typedef char *MV_CHAR_PTR; +typedef void *MV_BUS_ADDR_T; + +/* System dependent macro for flushing CPU write cache */ +#define MV_CPU_WRITE_BUFFER_FLUSH() + +/* System dependent little endian from / to CPU conversions */ +#define MV_CPU_TO_LE16(x) (x) +#define MV_CPU_TO_LE32(x) (x) + +#define MV_LE16_TO_CPU(x) (x) +#define MV_LE32_TO_CPU(x) (x) + +/* System dependent register read / write in byte/word/dword variants */ +extern void HPTLIBAPI MV_REG_WRITE_BYTE(MV_BUS_ADDR_T base, MV_U32 offset, MV_U8 val); +extern void HPTLIBAPI MV_REG_WRITE_WORD(MV_BUS_ADDR_T base, MV_U32 offset, MV_U16 val); +extern void HPTLIBAPI MV_REG_WRITE_DWORD(MV_BUS_ADDR_T base, MV_U32 offset, MV_U32 val); +extern MV_U8 HPTLIBAPI MV_REG_READ_BYTE(MV_BUS_ADDR_T base, MV_U32 offset); +extern MV_U16 HPTLIBAPI MV_REG_READ_WORD(MV_BUS_ADDR_T base, MV_U32 offset); +extern MV_U32 HPTLIBAPI MV_REG_READ_DWORD(MV_BUS_ADDR_T base, MV_U32 offset); + +/* System dependent structure */ +typedef struct mvOsSemaphore +{ + int notused; +} MV_OS_SEMAPHORE; + +/* Functions (User implemented)*/ +ULONG_PTR HPTLIBAPI fOsPhysicalAddress(void *addr); + +/* Semaphore init, take and release */ +#define mvOsSemInit(p) (MV_TRUE) +#define mvOsSemTake(p) (MV_TRUE) +#define mvOsSemRelease(p) (MV_TRUE) + +/* Delay function in micro seconds resolution */ +void HPTLIBAPI mvMicroSecondsDelay(MV_U32); + +/* System logging function */ +#ifdef MV_DEBUG_LOG +int mvLogMsg(MV_U8, MV_CHAR_PTR, ...); +#define _mvLogMsg(x) mvLogMsg x +#else +#define mvLogMsg(x...) +#define _mvLogMsg(x) +#endif + +/************************************************************************* + * Debug support + *************************************************************************/ +#ifdef DEBUG +#define HPT_ASSERT(x) do { if (!(x)) { \ + kprintf("ASSERT fail at %s line %d", __FILE__, __LINE__); \ + while (1); \ + }} while (0) +extern int hpt_dbg_level; +#define KdPrintI(_x_) do{ if (hpt_dbg_level>2) kprintf _x_; }while(0) +#define KdPrintW(_x_) do{ if (hpt_dbg_level>1) kprintf _x_; }while(0) +#define KdPrintE(_x_) do{ if (hpt_dbg_level>0) kprintf _x_; }while(0) +#define KdPrint(x) KdPrintI(x) +#else +#define HPT_ASSERT(x) +#define KdPrint(x) +#define KdPrintI(x) +#define KdPrintW(x) +#define KdPrintE(x) +#endif + +#endif diff --git a/sys/dev/raid/hptmv/mvSata.h b/sys/dev/raid/hptmv/mvSata.h new file mode 100644 index 0000000000..27f2c99f84 --- /dev/null +++ b/sys/dev/raid/hptmv/mvSata.h @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2004-2005 MARVELL SEMICONDUCTOR ISRAEL, LTD. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/mvSata.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef __INCmvSatah +#define __INCmvSatah + +#ifndef SUPPORT_MV_SATA_GEN_1 +#define SUPPORT_MV_SATA_GEN_1 1 +#endif + +#ifndef SUPPORT_MV_SATA_GEN_2 +#define SUPPORT_MV_SATA_GEN_2 0 +#endif + +#ifndef SUPPORT_MV_SATA_GEN_2E +#define SUPPORT_MV_SATA_GEN_2E 0 +#endif + +#if (SUPPORT_MV_SATA_GEN_1 + SUPPORT_MV_SATA_GEN_2 + SUPPORT_MV_SATA_GEN_2E) > 1 + +#define MV_SATA_GEN_1(x) ((x)->sataAdapterGeneration==1) +#define MV_SATA_GEN_2(x) ((x)->sataAdapterGeneration>=2) +#define MV_SATA_GEN_2E(x) ((x)->sataAdapterGeneration==3) + +#elif SUPPORT_MV_SATA_GEN_1==1 + +#define MV_SATA_GEN_1(x) 1 +#define MV_SATA_GEN_2(x) 0 +#define MV_SATA_GEN_2E(x) 0 + +#elif SUPPORT_MV_SATA_GEN_2==1 + +#define MV_SATA_GEN_1(x) 0 +#define MV_SATA_GEN_2(x) 1 +#define MV_SATA_GEN_2E(x) 0 + +#elif SUPPORT_MV_SATA_GEN_2E==1 + +#define MV_SATA_GEN_1(x) 0 +#define MV_SATA_GEN_2(x) 1 /* gen2E impiles gen2 */ +#define MV_SATA_GEN_2E(x) 1 + +#else +#error "Which IC do you support?" +#endif + +/* Definitions */ +/* MV88SX50XX specific defines */ +#define MV_SATA_VENDOR_ID 0x11AB +#define MV_SATA_DEVICE_ID_5080 0x5080 +#define MV_SATA_DEVICE_ID_5081 0x5081 +#define MV_SATA_DEVICE_ID_6080 0x6080 +#define MV_SATA_DEVICE_ID_6081 0x6081 + +#if defined(RR2310) || defined(RR1740) || defined(RR2210) || defined (RR2522) +#define MV_SATA_CHANNELS_NUM 4 +#define MV_SATA_UNITS_NUM 1 +#else +#define MV_SATA_CHANNELS_NUM 8 +#define MV_SATA_UNITS_NUM 2 +#endif + +#define MV_SATA_PCI_BAR0_SPACE_SIZE (1<<18) /* 256 Kb*/ + +#define CHANNEL_QUEUE_LENGTH 32 +#define CHANNEL_QUEUE_MASK 0x1F + +#define MV_EDMA_QUEUE_LENGTH 32 /* Up to 32 outstanding */ + /* commands per SATA channel*/ +#define MV_EDMA_QUEUE_MASK 0x1F +#define MV_EDMA_REQUEST_QUEUE_SIZE 1024 /* 32*32 = 1KBytes */ +#define MV_EDMA_RESPONSE_QUEUE_SIZE 256 /* 32*8 = 256 Bytes */ + +#define MV_EDMA_REQUEST_ENTRY_SIZE 32 +#define MV_EDMA_RESPONSE_ENTRY_SIZE 8 + +#define MV_EDMA_PRD_ENTRY_SIZE 16 /* 16Bytes*/ +#define MV_EDMA_PRD_NO_SNOOP_FLAG 0x00000001 /* MV_BIT0 */ +#define MV_EDMA_PRD_EOT_FLAG 0x00008000 /* MV_BIT15 */ + +#define MV_ATA_IDENTIFY_DEV_DATA_LENGTH 256 /* number of words(2 byte)*/ +#define MV_ATA_MODEL_NUMBER_LEN 40 +#define ATA_SECTOR_SIZE 512 +/* Log messages level defines */ +#define MV_DEBUG 0x1 +#define MV_DEBUG_INIT 0x2 +#define MV_DEBUG_INTERRUPTS 0x4 +#define MV_DEBUG_SATA_LINK 0x8 +#define MV_DEBUG_UDMA_COMMAND 0x10 +#define MV_DEBUG_NON_UDMA_COMMAND 0x20 +#define MV_DEBUG_ERROR 0x40 + + +/* Typedefs */ +typedef enum mvUdmaType +{ + MV_UDMA_TYPE_READ, MV_UDMA_TYPE_WRITE +} MV_UDMA_TYPE; + +typedef enum mvFlushType +{ + MV_FLUSH_TYPE_CALLBACK, MV_FLUSH_TYPE_NONE +} MV_FLUSH_TYPE; + +typedef enum mvCompletionType +{ + MV_COMPLETION_TYPE_NORMAL, MV_COMPLETION_TYPE_ERROR, + MV_COMPLETION_TYPE_ABORT +} MV_COMPLETION_TYPE; + +typedef enum mvEventType +{ + MV_EVENT_TYPE_ADAPTER_ERROR, MV_EVENT_TYPE_SATA_CABLE +} MV_EVENT_TYPE; + +typedef enum mvEdmaMode +{ + MV_EDMA_MODE_QUEUED, + MV_EDMA_MODE_NOT_QUEUED, + MV_EDMA_MODE_NATIVE_QUEUING +} MV_EDMA_MODE; + +typedef enum mvEdmaQueueResult +{ + MV_EDMA_QUEUE_RESULT_OK = 0, + MV_EDMA_QUEUE_RESULT_EDMA_DISABLED, + MV_EDMA_QUEUE_RESULT_FULL, + MV_EDMA_QUEUE_RESULT_BAD_LBA_ADDRESS, + MV_EDMA_QUEUE_RESULT_BAD_PARAMS +} MV_EDMA_QUEUE_RESULT; + +typedef enum mvQueueCommandResult +{ + MV_QUEUE_COMMAND_RESULT_OK = 0, + MV_QUEUE_COMMAND_RESULT_QUEUED_MODE_DISABLED, + MV_QUEUE_COMMAND_RESULT_FULL, + MV_QUEUE_COMMAND_RESULT_BAD_LBA_ADDRESS, + MV_QUEUE_COMMAND_RESULT_BAD_PARAMS +} MV_QUEUE_COMMAND_RESULT; + +typedef enum mvNonUdmaProtocol +{ + MV_NON_UDMA_PROTOCOL_NON_DATA, + MV_NON_UDMA_PROTOCOL_PIO_DATA_IN, + MV_NON_UDMA_PROTOCOL_PIO_DATA_OUT +} MV_NON_UDMA_PROTOCOL; + + +struct mvDmaRequestQueueEntry; +struct mvDmaResponseQueueEntry; +struct mvDmaCommandEntry; + +struct mvSataAdapter; +struct mvStorageDevRegisters; + +typedef MV_BOOLEAN (* HPTLIBAPI mvSataCommandCompletionCallBack_t)(struct mvSataAdapter *, + MV_U8, + MV_COMPLETION_TYPE, + MV_VOID_PTR, MV_U16, + MV_U32, + struct mvStorageDevRegisters SS_SEG*); + +typedef enum mvQueuedCommandType +{ + MV_QUEUED_COMMAND_TYPE_UDMA, + MV_QUEUED_COMMAND_TYPE_NONE_UDMA +} MV_QUEUED_COMMAND_TYPE; + +typedef struct mvUdmaCommandParams +{ + MV_UDMA_TYPE readWrite; + MV_BOOLEAN isEXT; + MV_U32 lowLBAAddress; + MV_U16 highLBAAddress; + MV_U16 numOfSectors; + MV_U32 prdLowAddr; + MV_U32 prdHighAddr; + mvSataCommandCompletionCallBack_t callBack; + MV_VOID_PTR commandId; +} MV_UDMA_COMMAND_PARAMS; + +typedef struct mvNoneUdmaCommandParams +{ + MV_NON_UDMA_PROTOCOL protocolType; + MV_BOOLEAN isEXT; + MV_U16_PTR bufPtr; + MV_U32 count; + MV_U16 features; + MV_U16 sectorCount; + MV_U16 lbaLow; + MV_U16 lbaMid; + MV_U16 lbaHigh; + MV_U8 device; + MV_U8 command; + mvSataCommandCompletionCallBack_t callBack; + MV_VOID_PTR commandId; +} MV_NONE_UDMA_COMMAND_PARAMS; + +typedef struct mvQueueCommandInfo +{ + MV_QUEUED_COMMAND_TYPE type; + union + { + MV_UDMA_COMMAND_PARAMS udmaCommand; + MV_NONE_UDMA_COMMAND_PARAMS NoneUdmaCommand; + } commandParams; +} MV_QUEUE_COMMAND_INFO; + +/* The following structure is for the Core Driver internal usage */ +typedef struct mvQueuedCommandEntry +{ + MV_BOOLEAN isFreeEntry; + MV_U8 commandTag; + struct mvQueuedCommandEntry *next; + struct mvQueuedCommandEntry *prev; + MV_QUEUE_COMMAND_INFO commandInfo; +} MV_QUEUED_COMMAND_ENTRY; + +/* The following structures are part of the Core Driver API */ +typedef struct mvSataChannel +{ + /* Fields set by Intermediate Application Layer */ + MV_U8 channelNumber; + MV_BOOLEAN waitingForInterrupt; + MV_BOOLEAN lba48Address; + MV_BOOLEAN maxReadTransfer; + struct mvDmaRequestQueueEntry SS_SEG *requestQueue; + struct mvDmaResponseQueueEntry SS_SEG *responseQueue; + MV_U32 requestQueuePciHiAddress; + MV_U32 requestQueuePciLowAddress; + MV_U32 responseQueuePciHiAddress; + MV_U32 responseQueuePciLowAddress; + /* Fields set by CORE driver */ + struct mvSataAdapter *mvSataAdapter; + MV_OS_SEMAPHORE semaphore; + MV_U32 eDmaRegsOffset; + MV_U16 identifyDevice[MV_ATA_IDENTIFY_DEV_DATA_LENGTH]; + MV_BOOLEAN EdmaActive; + MV_EDMA_MODE queuedDMA; + MV_U8 outstandingCommands; + MV_BOOLEAN workAroundDone; + struct mvQueuedCommandEntry commandsQueue[CHANNEL_QUEUE_LENGTH]; + struct mvQueuedCommandEntry *commandsQueueHead; + struct mvQueuedCommandEntry *commandsQueueTail; + MV_BOOLEAN queueCommandsEnabled; + MV_U8 noneUdmaOutstandingCommands; + MV_U8 EdmaQueuedCommands; + MV_U32 freeIDsStack[CHANNEL_QUEUE_LENGTH]; + MV_U32 freeIDsNum; + MV_U32 reqInPtr; + MV_U32 rspOutPtr; +} MV_SATA_CHANNEL; + +typedef struct mvSataAdapter +{ + /* Fields set by Intermediate Application Layer */ + MV_U32 adapterId; + MV_U8 pcbVersion; + MV_U8 pciConfigRevisionId; + MV_U16 pciConfigDeviceId; + MV_VOID_PTR IALData; + MV_BUS_ADDR_T adapterIoBaseAddress; + MV_U32 intCoalThre[MV_SATA_UNITS_NUM]; + MV_U32 intTimeThre[MV_SATA_UNITS_NUM]; + MV_BOOLEAN (* HPTLIBAPI mvSataEventNotify)(struct mvSataAdapter *, + MV_EVENT_TYPE, + MV_U32, MV_U32); + MV_SATA_CHANNEL *sataChannel[MV_SATA_CHANNELS_NUM]; + MV_U32 pciCommand; + MV_U32 pciSerrMask; + MV_U32 pciInterruptMask; + + /* Fields set by CORE driver */ + MV_OS_SEMAPHORE semaphore; + MV_U32 mainMask; + MV_OS_SEMAPHORE interruptsMaskSem; + MV_BOOLEAN implementA0Workarounds; + MV_BOOLEAN implement50XXB0Workarounds; + MV_BOOLEAN implement50XXB1Workarounds; + MV_BOOLEAN implement50XXB2Workarounds; + MV_BOOLEAN implement60X1A0Workarounds; + MV_BOOLEAN implement60X1A1Workarounds; + MV_BOOLEAN implement60X1B0Workarounds; + MV_BOOLEAN implement7042A0Workarounds; + MV_BOOLEAN implement7042A1Workarounds; + MV_U8 sataAdapterGeneration; + MV_BOOLEAN isPEX; + MV_U8 failLEDMask; + MV_U8 signalAmps[MV_SATA_CHANNELS_NUM]; + MV_U8 pre[MV_SATA_CHANNELS_NUM]; + MV_BOOLEAN staggaredSpinup[MV_SATA_CHANNELS_NUM]; /* For 60x1 only */ +} MV_SATA_ADAPTER; + +typedef struct mvSataAdapterStatus +{ + /* Fields set by CORE driver */ + MV_BOOLEAN channelConnected[MV_SATA_CHANNELS_NUM]; + MV_U32 pciDLLStatusAndControlRegister; + MV_U32 pciCommandRegister; + MV_U32 pciModeRegister; + MV_U32 pciSERRMaskRegister; + MV_U32 intCoalThre[MV_SATA_UNITS_NUM]; + MV_U32 intTimeThre[MV_SATA_UNITS_NUM]; + MV_U32 R00StatusBridgePortRegister[MV_SATA_CHANNELS_NUM]; +}MV_SATA_ADAPTER_STATUS; + + +typedef struct mvSataChannelStatus +{ + /* Fields set by CORE driver */ + MV_BOOLEAN isConnected; + MV_U8 modelNumber[MV_ATA_MODEL_NUMBER_LEN]; + MV_BOOLEAN DMAEnabled; + MV_EDMA_MODE queuedDMA; + MV_U8 outstandingCommands; + MV_U32 EdmaConfigurationRegister; + MV_U32 EdmaRequestQueueBaseAddressHighRegister; + MV_U32 EdmaRequestQueueInPointerRegister; + MV_U32 EdmaRequestQueueOutPointerRegister; + MV_U32 EdmaResponseQueueBaseAddressHighRegister; + MV_U32 EdmaResponseQueueInPointerRegister; + MV_U32 EdmaResponseQueueOutPointerRegister; + MV_U32 EdmaCommandRegister; + MV_U32 PHYModeRegister; +}MV_SATA_CHANNEL_STATUS; + +/* this structure used by the IAL defines the PRD entries used by the EDMA HW */ +typedef struct mvSataEdmaPRDEntry +{ + volatile MV_U32 lowBaseAddr; + volatile MV_U16 byteCount; + volatile MV_U16 flags; + volatile MV_U32 highBaseAddr; + volatile MV_U32 reserved; +}MV_SATA_EDMA_PRD_ENTRY; + +/* API Functions */ + +/* CORE driver Adapter Management */ +MV_BOOLEAN HPTLIBAPI mvSataInitAdapter(MV_SATA_ADAPTER *pAdapter); + +MV_BOOLEAN HPTLIBAPI mvSataShutdownAdapter(MV_SATA_ADAPTER *pAdapter); + +MV_BOOLEAN HPTLIBAPI mvSataGetAdapterStatus(MV_SATA_ADAPTER *pAdapter, + MV_SATA_ADAPTER_STATUS *pAdapterStatus); + +MV_U32 HPTLIBAPI mvSataReadReg(MV_SATA_ADAPTER *pAdapter, MV_U32 regOffset); + +MV_VOID HPTLIBAPI mvSataWriteReg(MV_SATA_ADAPTER *pAdapter, MV_U32 regOffset, + MV_U32 regValue); + +MV_VOID HPTLIBAPI mvEnableAutoFlush(MV_VOID); +MV_VOID HPTLIBAPI mvDisableAutoFlush(MV_VOID); + + +/* CORE driver SATA Channel Management */ +MV_BOOLEAN HPTLIBAPI mvSataConfigureChannel(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataRemoveChannel(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataIsStorageDeviceConnected(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataChannelHardReset(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataConfigEdmaMode(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex, + MV_EDMA_MODE eDmaMode, MV_U8 maxQueueDepth); + +MV_BOOLEAN HPTLIBAPI mvSataEnableChannelDma(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataDisableChannelDma(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataFlushDmaQueue(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex, + MV_FLUSH_TYPE flushType); + +MV_U8 HPTLIBAPI mvSataNumOfDmaCommands(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataSetIntCoalParams (MV_SATA_ADAPTER *pAdapter, MV_U8 sataUnit, + MV_U32 intCoalThre, MV_U32 intTimeThre); + +MV_BOOLEAN HPTLIBAPI mvSataSetChannelPhyParams(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex, + MV_U8 signalAmps, MV_U8 pre); + +MV_BOOLEAN HPTLIBAPI mvSataChannelPhyShutdown(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataChannelPhyPowerOn(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvSataChannelSetEdmaLoopBackMode(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex, + MV_BOOLEAN loopBackOn); + +MV_BOOLEAN HPTLIBAPI mvSataGetChannelStatus(MV_SATA_ADAPTER *pAdapter, MV_U8 channelIndex, + MV_SATA_CHANNEL_STATUS *pChannelStatus); + +MV_QUEUE_COMMAND_RESULT HPTLIBAPI mvSataQueueCommand(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex, + MV_QUEUE_COMMAND_INFO SS_SEG *pCommandParams); + +/* Interrupt Service Routine */ +MV_BOOLEAN HPTLIBAPI mvSataInterruptServiceRoutine(MV_SATA_ADAPTER *pAdapter); + +MV_BOOLEAN HPTLIBAPI mvSataMaskAdapterInterrupt(MV_SATA_ADAPTER *pAdapter); + +MV_BOOLEAN HPTLIBAPI mvSataUnmaskAdapterInterrupt(MV_SATA_ADAPTER *pAdapter); + +/* Command Completion and Event Notification (user implemented) */ +MV_BOOLEAN HPTLIBAPI mvSataEventNotify(MV_SATA_ADAPTER *, MV_EVENT_TYPE , + MV_U32, MV_U32); + +/* + * Staggered spin-ip support and SATA interface speed control + * (relevant for 60x1 adapters) + */ +MV_BOOLEAN HPTLIBAPI mvSataEnableStaggeredSpinUpAll (MV_SATA_ADAPTER *pAdapter); +MV_BOOLEAN HPTLIBAPI mvSataDisableStaggeredSpinUpAll (MV_SATA_ADAPTER *pAdapter); + +#endif diff --git a/sys/dev/raid/hptmv/mvStorageDev.h b/sys/dev/raid/hptmv/mvStorageDev.h new file mode 100644 index 0000000000..4f0b640dd4 --- /dev/null +++ b/sys/dev/raid/hptmv/mvStorageDev.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2004-2005 MARVELL SEMICONDUCTOR ISRAEL, LTD. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/mvStorageDev.h,v 1.5 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef __INCmvStorageDevh +#define __INCmvStorageDevh + +/* Definitions */ + +/* ATA register on the ATA drive*/ + +#define MV_EDMA_ATA_FEATURES_ADDR 0x11 +#define MV_EDMA_ATA_SECTOR_COUNT_ADDR 0x12 +#define MV_EDMA_ATA_LBA_LOW_ADDR 0x13 +#define MV_EDMA_ATA_LBA_MID_ADDR 0x14 +#define MV_EDMA_ATA_LBA_HIGH_ADDR 0x15 +#define MV_EDMA_ATA_DEVICE_ADDR 0x16 +#define MV_EDMA_ATA_COMMAND_ADDR 0x17 + +#define MV_ATA_ERROR_STATUS 0x00000001 /* MV_BIT0 */ +#define MV_ATA_DATA_REQUEST_STATUS 0x00000008 /* MV_BIT3 */ +#define MV_ATA_SERVICE_STATUS 0x00000010 /* MV_BIT4 */ +#define MV_ATA_DEVICE_FAULT_STATUS 0x00000020 /* MV_BIT5 */ +#define MV_ATA_READY_STATUS 0x00000040 /* MV_BIT6 */ +#define MV_ATA_BUSY_STATUS 0x00000080 /* MV_BIT7 */ + + +#define MV_ATA_COMMAND_READ_SECTORS 0x20 +#define MV_ATA_COMMAND_READ_SECTORS_EXT 0x24 +#define MV_ATA_COMMAND_READ_VERIFY_SECTORS 0x40 +#define MV_ATA_COMMAND_READ_VERIFY_SECTORS_EXT 0x42 +#define MV_ATA_COMMAND_READ_BUFFER 0xE4 +#define MV_ATA_COMMAND_WRITE_BUFFER 0xE8 +#define MV_ATA_COMMAND_WRITE_SECTORS 0x30 +#define MV_ATA_COMMAND_WRITE_SECTORS_EXT 0x34 +#define MV_ATA_COMMAND_DIAGNOSTIC 0x90 +#define MV_ATA_COMMAND_SMART 0xb0 +#define MV_ATA_COMMAND_READ_MULTIPLE 0xc4 +#define MV_ATA_COMMAND_WRITE_MULTIPLE 0xc5 +#define MV_ATA_COMMAND_STANDBY_IMMEDIATE 0xe0 +#define MV_ATA_COMMAND_IDLE_IMMEDIATE 0xe1 +#define MV_ATA_COMMAND_STANDBY 0xe2 +#define MV_ATA_COMMAND_IDLE 0xe3 +#define MV_ATA_COMMAND_SLEEP 0xe6 +#define MV_ATA_COMMAND_IDENTIFY 0xec +#define MV_ATA_COMMAND_DEVICE_CONFIG 0xb1 +#define MV_ATA_COMMAND_SET_FEATURES 0xef +#define MV_ATA_COMMAND_WRITE_DMA 0xca +#define MV_ATA_COMMAND_WRITE_DMA_EXT 0x35 +#define MV_ATA_COMMAND_WRITE_DMA_QUEUED 0xcc +#define MV_ATA_COMMAND_WRITE_DMA_QUEUED_EXT 0x36 +#define MV_ATA_COMMAND_WRITE_FPDMA_QUEUED_EXT 0x61 +#define MV_ATA_COMMAND_READ_DMA 0xc8 +#define MV_ATA_COMMAND_READ_DMA_EXT 0x25 +#define MV_ATA_COMMAND_READ_DMA_QUEUED 0xc7 +#define MV_ATA_COMMAND_READ_DMA_QUEUED_EXT 0x26 +#define MV_ATA_COMMAND_READ_FPDMA_QUEUED_EXT 0x60 +#define MV_ATA_COMMAND_FLUSH_CACHE 0xe7 +#define MV_ATA_COMMAND_FLUSH_CACHE_EXT 0xea + + +#define MV_ATA_SET_FEATURES_DISABLE_8_BIT_PIO 0x01 +#define MV_ATA_SET_FEATURES_ENABLE_WCACHE 0x02 /* Enable write cache */ +#define MV_ATA_SET_FEATURES_TRANSFER 0x03 /* Set transfer mode */ +#define MV_ATA_TRANSFER_UDMA_0 0x40 +#define MV_ATA_TRANSFER_UDMA_1 0x41 +#define MV_ATA_TRANSFER_UDMA_2 0x42 +#define MV_ATA_TRANSFER_UDMA_3 0x43 +#define MV_ATA_TRANSFER_UDMA_4 0x44 +#define MV_ATA_TRANSFER_UDMA_5 0x45 +#define MV_ATA_TRANSFER_UDMA_6 0x46 +#define MV_ATA_TRANSFER_UDMA_7 0x47 +#define MV_ATA_TRANSFER_PIO_SLOW 0x00 +#define MV_ATA_TRANSFER_PIO_0 0x08 +#define MV_ATA_TRANSFER_PIO_1 0x09 +#define MV_ATA_TRANSFER_PIO_2 0x0A +#define MV_ATA_TRANSFER_PIO_3 0x0B +#define MV_ATA_TRANSFER_PIO_4 0x0C +/* Enable advanced power management */ +#define MV_ATA_SET_FEATURES_ENABLE_APM 0x05 +/* Disable media status notification*/ +#define MV_ATA_SET_FEATURES_DISABLE_MSN 0x31 +/* Disable read look-ahead */ +#define MV_ATA_SET_FEATURES_DISABLE_RLA 0x55 +/* Enable release interrupt */ +#define MV_ATA_SET_FEATURES_ENABLE_RI 0x5D +/* Enable SERVICE interrupt */ +#define MV_ATA_SET_FEATURES_ENABLE_SI 0x5E +/* Disable revert power-on defaults */ +#define MV_ATA_SET_FEATURES_DISABLE_RPOD 0x66 +/* Disable write cache */ +#define MV_ATA_SET_FEATURES_DISABLE_WCACHE 0x82 +/* Disable advanced power management*/ +#define MV_ATA_SET_FEATURES_DISABLE_APM 0x85 +/* Enable media status notification */ +#define MV_ATA_SET_FEATURES_ENABLE_MSN 0x95 +/* Enable read look-ahead */ +#define MV_ATA_SET_FEATURES_ENABLE_RLA 0xAA +/* Enable revert power-on defaults */ +#define MV_ATA_SET_FEATURES_ENABLE_RPOD 0xCC +/* Disable release interrupt */ +#define MV_ATA_SET_FEATURES_DISABLE_RI 0xDD +/* Disable SERVICE interrupt */ +#define MV_ATA_SET_FEATURES_DISABLE_SI 0xDE + +/* Defines for parsing the IDENTIFY command results*/ +#define IDEN_SERIAL_NUM_OFFSET 10 +#define IDEN_SERIAL_NUM_SIZE 19-10 +#define IDEN_FIRMWARE_OFFSET 23 +#define IDEN_FIRMWARE_SIZE 26-23 +#define IDEN_MODEL_OFFSET 27 +#define IDEN_MODEL_SIZE 46-27 +#define IDEN_CAPACITY_1_OFFSET 49 +#define IDEN_VALID 53 +#define IDEN_NUM_OF_ADDRESSABLE_SECTORS 60 +#define IDEN_PIO_MODE_SPPORTED 64 +#define IDEN_QUEUE_DEPTH 75 +#define IDEN_SATA_CAPABILITIES 76 +#define IDEN_SATA_FEATURES_SUPPORTED 78 +#define IDEN_SATA_FEATURES_ENABLED 79 +#define IDEN_ATA_VERSION 80 +#define IDEN_SUPPORTED_COMMANDS1 82 +#define IDEN_SUPPORTED_COMMANDS2 83 +#define IDEN_ENABLED_COMMANDS1 85 +#define IDEN_ENABLED_COMMANDS2 86 +#define IDEN_UDMA_MODE 88 +#define IDEN_SATA_CAPABILITY 76 + + +/* Typedefs */ + +/* Structures */ +typedef struct mvStorageDevRegisters +{ + /* Fields set by CORE driver */ + MV_U8 errorRegister; + MV_U16 sectorCountRegister; + MV_U16 lbaLowRegister; + MV_U16 lbaMidRegister; + MV_U16 lbaHighRegister; + MV_U8 deviceRegister; + MV_U8 statusRegister; +} MV_STORAGE_DEVICE_REGISTERS; + +/* Bits for HD_ERROR */ +#define NM_ERR 0x02 /* media present */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define IDNF_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define UNC_ERR 0x40 /* Uncorrect data */ +#define WP_ERR 0x40 /* write protect */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Function */ + +MV_BOOLEAN HPTLIBAPI mvStorageDevATAExecuteNonUDMACommand(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex, + MV_NON_UDMA_PROTOCOL protocolType, + MV_BOOLEAN isEXT, + MV_U16 FAR *bufPtr, MV_U32 count, + MV_U16 features, + MV_U16 sectorCount, + MV_U16 lbaLow, MV_U16 lbaMid, + MV_U16 lbaHigh, MV_U8 device, + MV_U8 command); + +MV_BOOLEAN HPTLIBAPI mvStorageDevATAIdentifyDevice(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvStorageDevATASetFeatures(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex, MV_U8 subCommand, + MV_U8 subCommandSpecific1, + MV_U8 subCommandSpecific2, + MV_U8 subCommandSpecific3, + MV_U8 subCommandSpecific4); + +MV_BOOLEAN HPTLIBAPI mvStorageDevATAIdleImmediate(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvStorageDevATAFlushWriteCache(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvStorageDevATASoftResetDevice(MV_SATA_ADAPTER *pAdapter, + MV_U8 channelIndex); + +MV_BOOLEAN HPTLIBAPI mvStorageDevWaitStat(MV_SATA_CHANNEL *pSataChannel, + MV_U8 good, MV_U8 bad, MV_U32 loops, MV_U32 delay); + +MV_BOOLEAN HPTLIBAPI mvReadWrite(MV_SATA_CHANNEL *pSataChannel, LBA_T Lba, UCHAR Cmd, void *tmpBuffer); + +#endif diff --git a/sys/dev/raid/hptmv/osbsd.h b/sys/dev/raid/hptmv/osbsd.h new file mode 100644 index 0000000000..a71bd91eac --- /dev/null +++ b/sys/dev/raid/hptmv/osbsd.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/osbsd.h,v 1.7 2009/04/07 16:38:25 delphij Exp $ + */ +#ifndef _OSBSD_H_ +#define _OSBSD_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + + +extern intrmask_t lock_driver(void); +extern void unlock_driver(intrmask_t spl); + +typedef struct +{ + UCHAR status; /* 0 nonbootable; 80h bootable */ + UCHAR start_head; + USHORT start_sector; + UCHAR type; + UCHAR end_head; + USHORT end_sector; + ULONG start_abs_sector; + ULONG num_of_sector; +} partition; + +typedef struct _INQUIRYDATA { + UCHAR DeviceType : 5; + UCHAR DeviceTypeQualifier : 3; + UCHAR DeviceTypeModifier : 7; + UCHAR RemovableMedia : 1; + UCHAR Versions; + UCHAR ResponseDataFormat; + UCHAR AdditionalLength; + UCHAR Reserved[2]; + UCHAR SoftReset : 1; + UCHAR CommandQueue : 1; + UCHAR Reserved2 : 1; + UCHAR LinkedCommands : 1; + UCHAR Synchronous : 1; + UCHAR Wide16Bit : 1; + UCHAR Wide32Bit : 1; + UCHAR RelativeAddressing : 1; + UCHAR VendorId[8]; + UCHAR ProductId[16]; + UCHAR ProductRevisionLevel[4]; + UCHAR VendorSpecific[20]; + UCHAR Reserved3[40]; +} INQUIRYDATA, *PINQUIRYDATA; + +#define MV_IAL_HT_SACOALT_DEFAULT 1 +#define MV_IAL_HT_SAITMTH_DEFAULT 1 + +/****************************************/ +/* GENERAL Definitions */ +/****************************************/ + +/* Bits for HD_ERROR */ +#define NM_ERR 0x02 /* media present */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define IDNF_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define UNC_ERR 0x40 /* Uncorrect data */ +#define WP_ERR 0x40 /* write protect */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +#define REQUESTS_ARRAY_SIZE (9 * MV_EDMA_REQUEST_QUEUE_SIZE) /* 9 K bytes */ +#define RESPONSES_ARRAY_SIZE (12 * MV_EDMA_RESPONSE_QUEUE_SIZE) /* 3 K bytes */ + +#define PRD_ENTRIES_PER_CMD (MAX_SG_DESCRIPTORS+1) +#define PRD_ENTRIES_SIZE (MV_EDMA_PRD_ENTRY_SIZE*PRD_ENTRIES_PER_CMD) +#define PRD_TABLES_FOR_VBUS (MV_SATA_CHANNELS_NUM*MV_EDMA_QUEUE_LENGTH) + +typedef enum _SataEvent +{ + SATA_EVENT_NO_CHANGE = 0, + SATA_EVENT_CHANNEL_CONNECTED, + SATA_EVENT_CHANNEL_DISCONNECTED +} SATA_EVENT; + +typedef ULONG_PTR dma_addr_t; + +typedef struct _MV_CHANNEL +{ + unsigned int maxUltraDmaModeSupported; + unsigned int maxDmaModeSupported; + unsigned int maxPioModeSupported; + MV_BOOLEAN online; + MV_BOOLEAN writeCacheSupported; + MV_BOOLEAN writeCacheEnabled; + MV_BOOLEAN readAheadSupported; + MV_BOOLEAN readAheadEnabled; + MV_U8 queueDepth; + +} MV_CHANNEL; + +typedef struct _BUS_DMAMAP +{ struct _BUS_DMAMAP *next; + struct IALAdapter *pAdapter; + bus_dmamap_t dma_map; + SCAT_GATH psg[MAX_SG_DESCRIPTORS]; +} BUS_DMAMAP, *PBUS_DMAMAP; + +typedef struct IALAdapter +{ + struct cam_path *path; + + bus_dma_tag_t io_dma_parent; /* I/O buffer DMA tag */ + PBUS_DMAMAP pbus_dmamap_list; + PBUS_DMAMAP pbus_dmamap; + + device_t hpt_dev; /* bus device */ + struct resource *hpt_irq; /* interrupt */ + struct resource *mem_res; + void *hpt_intr; /* interrupt handle */ + struct IALAdapter *next; + + MV_SATA_ADAPTER mvSataAdapter; + MV_CHANNEL mvChannel[MV_SATA_CHANNELS_NUM]; + MV_U8 *requestsArrayBaseAddr; + MV_U8 *requestsArrayBaseAlignedAddr; + dma_addr_t requestsArrayBaseDmaAddr; + dma_addr_t requestsArrayBaseDmaAlignedAddr; + MV_U8 *responsesArrayBaseAddr; + MV_U8 *responsesArrayBaseAlignedAddr; + dma_addr_t responsesArrayBaseDmaAddr; + dma_addr_t responsesArrayBaseDmaAlignedAddr; + SATA_EVENT sataEvents[MV_SATA_CHANNELS_NUM]; + + struct callout event_timer_connect; + struct callout event_timer_disconnect; + + struct _VBus VBus; + struct _VDevice VDevices[MV_SATA_CHANNELS_NUM]; + PCommand pCommandBlocks; + PUCHAR prdTableAddr; + PUCHAR prdTableAlignedAddr; + void* pFreePRDLink; + + union ccb *pending_Q; + + MV_U8 outstandingCommands; + + UCHAR status; + UCHAR ver_601; + UCHAR beeping; + + eventhandler_tag eh; +} +IAL_ADAPTER_T; + +extern IAL_ADAPTER_T *gIal_Adapter; + +/*entry.c*/ +typedef void (*HPT_DPC)(IAL_ADAPTER_T *,void*,UCHAR); + +int hpt_queue_dpc(HPT_DPC dpc, IAL_ADAPTER_T *pAdapter, void *arg, UCHAR flags); +void hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags); +void Check_Idle_Call(IAL_ADAPTER_T *pAdapter); +void fRescanAllDevice(_VBUS_ARG0); +int hpt_add_disk_to_array(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk); + +int Kernel_DeviceIoControl(_VBUS_ARG + DWORD dwIoControlCode, /* operation control code */ + PVOID lpInBuffer, /* input data buffer */ + DWORD nInBufferSize, /* size of input data buffer */ + PVOID lpOutBuffer, /* output data buffer */ + DWORD nOutBufferSize, /* size of output data buffer */ + PDWORD lpBytesReturned /* byte count */ + ); + + +#define __str_direct(x) #x +#define __str(x) __str_direct(x) +#define KMSG_LEADING __str(PROC_DIR_NAME) ": " +#define hpt_printk(_x_) do { kprintf(KMSG_LEADING); kprintf _x_ ; } while (0) + +#define DUPLICATE 0 +#define INITIALIZE 1 +#define REBUILD_PARITY 2 +#define VERIFY 3 + +/***********************************************************/ + +static __inline struct cam_periph * +hpt_get_periph(int path_id,int target_id) +{ + struct cam_periph *periph = NULL; + struct cam_path *path; + int status; + + status = xpt_create_path(&path, NULL, path_id, target_id, 0); + if (status == CAM_REQ_CMP) { + periph = cam_periph_find(path, "da"); + xpt_free_path(path); + + } + return periph; +} + +#ifdef __i386__ +#define BITS_PER_LONG 32 +#define VDEV_TO_ID(pVDev) (DEVICEID)(pVDev) +#define ID_TO_VDEV(id) (PVDevice)(id) +#else /*Only support x86_64(AMD64 and EM64T)*/ +#define BITS_PER_LONG 64 +#define VDEV_TO_ID(pVDev) (DEVICEID)(ULONG_PTR)(pVDev) +#define ID_TO_VDEV(id) (PVDevice)(((ULONG_PTR)gIal_Adapter & 0xffffffff00000000) | (id)) +#endif + +#define INVALID_DEVICEID (-1) +#define INVALID_STRIPSIZE (-1) + +#define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8)) + +#ifndef MinBlockSizeShift +#define MinBlockSizeShift 5 +#define MaxBlockSizeShift 12 +#endif + +#pragma pack(1) +typedef struct _HPT_IOCTL_TRANSFER_PARAM +{ + ULONG nInBufferSize; + ULONG nOutBufferSize; + UCHAR buffer[0]; +}HPT_IOCTL_TRANSFER_PARAM, *PHPT_IOCTL_TRANSFER_PARAM; + +typedef struct _HPT_SET_STATE_PARAM +{ + DEVICEID idArray; + DWORD state; +} HPT_SET_STATE_PARAM, *PHPT_SET_STATE_PARAM; + +typedef struct _HPT_SET_ARRAY_INFO +{ + DEVICEID idArray; + ALTERABLE_ARRAY_INFO Info; +} HPT_SET_ARRAY_INFO, *PHPT_SET_ARRAY_INFO; + +typedef struct _HPT_SET_DEVICE_INFO +{ + DEVICEID idDisk; + ALTERABLE_DEVICE_INFO Info; +} HPT_SET_DEVICE_INFO, *PHPT_SET_DEVICE_INFO; + +typedef struct _HPT_SET_DEVICE_INFO_V2 +{ + DEVICEID idDisk; + ALTERABLE_DEVICE_INFO_V2 Info; +} HPT_SET_DEVICE_INFO_V2, *PHPT_SET_DEVICE_INFO_V2; + +typedef struct _HPT_ADD_DISK_TO_ARRAY +{ + DEVICEID idArray; + DEVICEID idDisk; +} HPT_ADD_DISK_TO_ARRAY, *PHPT_ADD_DISK_TO_ARRAY; + +typedef struct _HPT_DEVICE_IO +{ + DEVICEID id; + int cmd; + ULONG lba; + DWORD nSector; + UCHAR buffer[0]; +} HPT_DEVICE_IO, *PHPT_DEVICE_IO; + +int check_VDevice_valid(PVDevice); +int hpt_default_ioctl(_VBUS_ARG DWORD, PVOID, DWORD, PVOID, DWORD, PDWORD); + +#define HPT_NULL_ID 0 + +#pragma pack() + +#endif diff --git a/sys/dev/raid/hptmv/raid5n.h b/sys/dev/raid/hptmv/raid5n.h new file mode 100644 index 0000000000..ceb59da904 --- /dev/null +++ b/sys/dev/raid/hptmv/raid5n.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/raid5n.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ +#ifdef _RAID5N_ + +/* OS provided function, call only at initialization time */ +extern void * HPTLIBAPI os_alloc_page(_VBUS_ARG0); /* may be cached memory */ +extern void * HPTLIBAPI os_alloc_dma_page(_VBUS_ARG0); /* must be non-cached memory */ +/* implement if the driver can be unloaded */ +void HPTLIBAPI os_free_page(_VBUS_ARG void *p); +void HPTLIBAPI os_free_dma_page(_VBUS_ARG void *p); + +typedef void (* HPTLIBAPI xfer_done_fn)(_VBUS_ARG void *tag, int result); + + +#define DATAXFER_STACK_VAR +#define DATAXFER_INIT_ARG 0 + +#define dataxfer_init(arg) 0 +#define dataxfer_add_item(handle, host, cache, bytes, tocache) \ + if (tocache) memcpy((PUCHAR)(cache), (PUCHAR)(host), bytes); \ + else memcpy((PUCHAR)(host), (PUCHAR)(cache), bytes) +#define dataxfer_exec(handle, done, tag) done(_VBUS_P tag, 0) +#define dataxfer_poll() + + +typedef void (* HPTLIBAPI xor_done_fn)(_VBUS_ARG void *tag, int result); + + +#define XOR_STACK_VAR +#define XOR_INIT_ARG 0 + +/* DoXor1, DoXor2 provided by platform dependent code */ +void HPTLIBAPI DoXor1(ULONG *p0, ULONG *p1, ULONG *p2, UINT nBytes); +void HPTLIBAPI DoXor2(ULONG *p0, ULONG *p2, UINT nBytes); +#define max_xor_way 2 +#define xor_init(arg) 0 +#define xor_add_item(handle, dest, src, nsrc, bytes) \ + do {\ + if (((void**)(src))[0]==dest)\ + DoXor2((PULONG)(dest), ((PULONG *)(src))[1], bytes);\ + else\ + DoXor1((PULONG)(dest), ((PULONG *)(src))[0], ((PULONG *)(src))[1], bytes);\ + } while(0) +#define xor_exec(handle, done, tag) done(_VBUS_P tag, 0) +#define xor_poll() + + +/* set before calling init_raid5_memory */ +extern UINT num_raid5_pages; + +/* called by init.c */ +extern void HPTLIBAPI init_raid5_memory(_VBUS_ARG0); +extern void HPTLIBAPI free_raid5_memory(_VBUS_ARG0); + +/* asynchronous flush, may be called periodly */ +extern void HPTLIBAPI flush_stripe_cache(_VBUS_ARG0); +extern void HPTLIBAPI flush_raid5_async(PVDevice pArray, DPC_PROC done, void *arg); + +/* synchronous function called at shutdown */ +extern int HPTLIBAPI flush_raid5(PVDevice pArray); + +extern void HPTLIBAPI raid5_free(_VBUS_ARG PVDevice pArray); + +struct free_heap_block { + struct free_heap_block *next; +}; + +#ifndef LIST_H_INCLUDED +struct list_head { + struct list_head *next, *prev; +}; +#endif + +struct free_page { + struct free_page *link; +}; + +struct r5_global_data { + int enable_write_back; + struct list_head inactive_list; + struct list_head dirty_list; + struct list_head active_list; +#ifdef R5_CONTIG_CACHE + BUS_ADDR page_base_phys; + PUCHAR page_base_virt; + PUCHAR page_current; +#endif + struct free_heap_block *free_heap_slots[10]; + struct free_page *free_pages; + UINT num_free_pages; + UINT active_stripes; + UINT num_flushing; + PCommand cache_wait_list; + + LBA_T __start[MAX_MEMBERS]; + USHORT __sectors[MAX_MEMBERS]; +}; + + +#endif diff --git a/sys/dev/raid/hptmv/readme.txt b/sys/dev/raid/hptmv/readme.txt new file mode 100644 index 0000000000..16ce0ae342 --- /dev/null +++ b/sys/dev/raid/hptmv/readme.txt @@ -0,0 +1,223 @@ +RocketRAID 18xx Driver for FreeBSD +Copyright (C) 2007-2008 HighPoint Technologies, Inc. All rights reserved. +$FreeBSD: src/sys/dev/hptmv/readme.txt,v 1.4 2009/04/07 16:38:25 delphij Exp $ + +############################################################################# +Revision History: + v1.16 2008-2-29 + Fix 7.0 compile error. + + v1.15 2007-8-6 + Override kernel driver(built-in) to support over 2T RAID array. + + v1.14 2006-3-21 + Fix 48-bit LBA compatibility for Seagate drives. + Fix 16 bytes CDB support. + + v1.13 2006-2-13 + Fix fail LED/beeper control. + Add 16 bytes CDB support. + + v1.12 2005-6-10 + Fix over 4G memory support on amd64. + Fix disk flush problem. + + v1.1 2004-9-23 + Fix activity LED problem. + Cleanup diagnostic code. + + v1.01 2004-5-24 + First source code release + +############################################################################# + +1. Overview +--------------------- + This package contains FreeBSD driver source code for HighPoint RocketRAID + 18xx SATA controller. + + NO WARRANTY + + THE DRIVER SOURCE CODE HIGHPOINT PROVIDED IS FREE OF CHARGE, AND THERE IS + NO WARRANTY FOR THE PROGRAM. THERE ARE NO RESTRICTIONS ON THE USE OF THIS + FREE SOURCE CODE. HIGHPOINT DOES NOT PROVIDE ANY TECHNICAL SUPPORT IF THE + CODE HAS BEEN CHANGED FROM ORIGINAL SOURCE CODE. + + LIMITATION OF LIABILITY + + IN NO EVENT WILL HIGHPOINT BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, + INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF OR + INABILITY TO USE THIS PRODUCT OR DOCUMENTATION, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. IN PARTICULAR, HIGHPOINT SHALL NOT HAVE + LIABILITY FOR ANY HARDWARE, SOFTWARE, OR DATA STORED USED WITH THE + PRODUCT, INCLUDING THE COSTS OF REPAIRING, REPLACING, OR RECOVERING + SUCH HARDWARE, OR DATA. + + +2. Rebuild the kernel with RR18xx support +-------------------------------------------- + + 1) Install kernel source package and building tools. + + 2) Extract the driver files under the kernel source tree: + + # cd /usr/src/sys/ + # tar xvzf /your/path/to/rr18xx-opensource-v1.12-bsd.tgz + + 3) Update the kernel configuration file to include the HighPoint source. + Assume the configure file is GENERIC, and new kernel configure file is + MYKERNEL: + + # cd i386/conf (or amd64/conf for AMD64) + # cp GENERIC MYKERNEL + + 4) Edit MYKERNEL, and add the following line under "RAID controllers + interfaced to the SCSI subsystem": + + device hptmv #HighPoint RocketRAID 18xx + + 5) For i386 system, edit /usr/src/sys/conf/files.i386 and append the lines + shown below: + + hptmvraid.o optional hptmv \ + dependency "$S/dev/hptmv/i386-elf.raid.o.uu" \ + compile-with "uudecode < $S/dev/hptmv/i386-elf.raid.o.uu" \ + no-implicit-rule + + dev/hptmv/gui_lib.c optional hptmv + dev/hptmv/hptproc.c optional hptmv + dev/hptmv/ioctl.c optional hptmv + dev/hptmv/entry.c optional hptmv + dev/hptmv/mv.c optional hptmv + + For amd64 system, edit /usr/src/sys/conf/files.amd64 and append the lines + shown below: + + hptmvraid.o optional hptmv \ + dependency "$S/dev/hptmv/amd64-elf.raid.o.uu" \ + compile-with "uudecode < $S/dev/hptmv/amd64-elf.raid.o.uu" \ + no-implicit-rule + + dev/hptmv/gui_lib.c optional hptmv + dev/hptmv/hptproc.c optional hptmv + dev/hptmv/ioctl.c optional hptmv + dev/hptmv/entry.c optional hptmv + dev/hptmv/mv.c optional hptmv + + Note FreeBSD 5.3/5.4/6.x/7.x i386 already have a built-in RR18xx driver, + you should replace the old configuration lines with the lines listed above. + + + 6) Rebuild and install the kernel: + + a) for FreeBSD 5.x/6.x/7.x i386: + + # cd /usr/src/sys/i386/conf/ + # /usr/sbin/config MYKERNEL + # cd ../compile/MYKERNEL/ + # make depend + # make + # make install + + b) for FreeBSD 5.x/6.x/7.x amd64: + + # cd /usr/src/sys/amd64/conf/ + # /usr/sbin/config MYKERNEL + # cd ../compile/MYKERNEL/ + # make depend + # make + # make install + + c) for FreeBSD 4.x: + + # cd /usr/src/sys/i386/conf/ + # /usr/sbin/config MYKERNEL + # cd ../../compile/MYKERNEL/ + # make depend + # make + # make install + + If the driver was previously configured as an auto-loaded module by + /boot/defaults/loader.conf, please remove the entry hptmv_load="YES" + from loader.conf to prevent the driver from being loaded twice. + + 7) Reboot from the new kernel. + + +3. Build/Load the driver as a kernel module +------------------------------------------------ + + 1) Install kernel source package and building tools. + + 2) Extract the driver files under the kernel source tree: + + # cd /usr/src/sys/ + # tar xvzf /your/path/to/rr18xx-opensource-v1.12-bsd.tgz + + + 4) Build the driver module: + + # cd modules/hptmv + # make + + 5) Copy the driver module to the kernel module directory + + For FreeBSD 4.x: + + # cp hptmv.ko /modules/ + + For FreeBSD 5.x/6.x/7.x: + + # cp hptmv.ko /boot/kernel/ + + 6) Reboot and load the driver under loader prompt. e.g: + + BTX loader 1.00 BTX version is 1.01 + Console: internal video/keyboard + BIOS driver A: is disk0 + BIOS driver C: is disk2 + BIOS 636kB/74512kB available memory + + FreeBSD/i386 bootstrap loader, Revision 0.8 + (mailto:jkh@narf.osd.bsdi.com, Sat Apr 21 08:46:19 GMT 2001) + Loading /boot/defaults/loader.conf + /kernel text=0x24f1db data=0x3007ec+0x2062c - + + Hit [Enter] to boot immediagely, or any other key for command prompt. + Booting [kernel] in 9 seconds¡­ + + <-- press SPACE key here + Type '?' for a list of commands, 'help' for more detailed help. + ok load hptmv + /modules/hptmv.ko text=0xf571 data=0x2c8+0x254 + ok boot + + For FreeBSD 5.x/6.x/7.x, you can select 6 on the boot menu to get a loader prompt. + + 7) You can add a below line into /boot/defaults/loader.conf to load the + driver automatically: + + hptmv_load="YES" + + Please refer to the installation guide in HighPoint FreeBSD driver release + package for more information. + + +############################################################################# +Technical support and service + + If you have questions about installing or using your HighPoint product, + check the user's guide or readme file first, and you will find answers to + most of your questions here. If you need further assistance, please + contact us. We offer the following support and information services: + + 1) The HighPoint Web Site provides information on software upgrades, + answers to common questions, and other topics. The Web Site is + available from Internet 24 hours a day, 7 days a week, at + http://www.highpoint-tech.com. + + 2) For technical support, send e-mail to support@highpoint-tech.com + + NOTE: Before you send an e-mail, please visit our Web Site + (http://www.highpoint-tech.com) to check if there is a new or + updated device driver for your system. diff --git a/sys/dev/raid/hptmv/vdevice.h b/sys/dev/raid/hptmv/vdevice.h new file mode 100644 index 0000000000..71e6114d48 --- /dev/null +++ b/sys/dev/raid/hptmv/vdevice.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/vdevice.h,v 1.4 2009/04/07 16:38:25 delphij Exp $ + */ + +#ifndef _VDEVICE_H_ +#define _VDEVICE_H_ + +/*************************************************************************** + * Description: virtual device header + ***************************************************************************/ + +typedef struct _VDevice +{ + UCHAR VDeviceType; + UCHAR vf_bootmark: 1; /* is boot device? */ + UCHAR vf_bootable: 1; /* has active partition */ + UCHAR vf_online: 1; /* is usable? */ + UCHAR vf_cache_disk: 1; /* Cache enabled */ + UCHAR vf_format_v2: 1; /* old array block */ + UCHAR vf_freed: 1; /* memory free */ + UCHAR reserve1; + UCHAR bSerialNumber; /* valid if pParent!=0 */ + + PVDevice pParent; /* parent array */ + PVBus pVBus; /* vbus this device located. Must not be NULL. */ + + LBA_T VDeviceCapacity; /* number of blocks */ + + LBA_T LockedLba; + USHORT LockedSectors; + USHORT ActiveRequests; + PCommand LockWaitList; + void (* HPTLIBAPI QuiesceAction)(_VBUS_ARG void *arg); + void *QuiesceArg; + void (* HPTLIBAPI flush_callback)(_VBUS_ARG void *arg); + void *flush_callback_arg; + + +#if defined(_RAID5N_) + struct stripe **CacheEntry; + struct range_lock *range_lock; +#endif + + void (* HPTLIBAPI pfnSendCommand)(_VBUS_ARG PCommand pCmd); /* call this to send a command to a VDevice */ + void (* HPTLIBAPI pfnDeviceFailed)(_VBUS_ARG PVDevice pVDev); /* call this when a VDevice failed */ + + union { +#ifdef SUPPORT_ARRAY + RaidArray array; +#endif + Device disk; + } u; + +} VDevice; + +#define ARRAY_VDEV_SIZE ((UINT)(ULONG_PTR)&((PVDevice)0)->u+sizeof(RaidArray)) +#define DISK_VDEV_SIZE ((UINT)(ULONG_PTR)&((PVDevice)0)->u+sizeof(Device)) + +#define Map2pVDevice(pDev) ((PVDevice)((UINT_PTR)pDev - (UINT)(UINT_PTR)&((PVDevice)0)->u.disk)) + +/* + * bUserDeviceMode + */ +#define MEMBER_NOT_SET_MODE 0x5F + +/* + * arrayType + */ +#define VD_SPARE 0 +#define VD_REMOVABLE 1 +#define VD_ATAPI 2 +#define VD_SINGLE_DISK 3 + +#define VD_JBOD 4 /* JBOD */ +#define VD_RAID_0 5 /* RAID 0 stripe */ +#define VD_RAID_1 6 /* RAID 1 mirror */ +#define VD_RAID_3 7 /* RAID 3 */ +#define VD_RAID_5 8 /* RAID 5 */ +#define VD_MAX_TYPE 8 + +#ifdef SUPPORT_ARRAY +#define mIsArray(pVDev) (pVDev->VDeviceType>VD_SINGLE_DISK) +#else +#define mIsArray(pVDev) 0 +#endif + +extern void (* HPTLIBAPI pfnSendCommand[])(_VBUS_ARG PCommand pCmd); +extern void (* HPTLIBAPI pfnDeviceFailed[])(_VBUS_ARG PVDevice pVDev); +void HPTLIBAPI fOsDiskFailed(_VBUS_ARG PVDevice pVDev); +void HPTLIBAPI fDeviceSendCommand(_VBUS_ARG PCommand pCmd); +void HPTLIBAPI fSingleDiskFailed(_VBUS_ARG PVDevice pVDev); + +/*************************************************************************** + * Description: RAID Adapter + ***************************************************************************/ + +typedef struct _VBus { + /* pVDevice[] may be non-continuous */ + PVDevice pVDevice[MAX_VDEVICE_PER_VBUS]; + + UINT nInstances; + PChipInstance pChipInstance[MAX_CHIP_IN_VBUS]; + + void * OsExt; /* for OS private use */ + + + int serial_mode; + int next_active; + int working_devs; + + + + PCommand pFreeCommands; + DPC_ROUTINE PendingRoutines[MAX_PENDING_ROUTINES]; + int PendingRoutinesFirst, PendingRoutinesLast; + DPC_ROUTINE IdleRoutines[MAX_IDLE_ROUTINES]; + int IdleRoutinesFirst, IdleRoutinesLast; + +#ifdef SUPPORT_ARRAY + PVDevice pFreeArrayLink; + BYTE _ArrayTables[MAX_ARRAY_PER_VBUS * ARRAY_VDEV_SIZE]; +#endif + + +#ifdef _RAID5N_ + struct r5_global_data r5; +#endif + +} VBus; + +/* + * Array members must be on same VBus. + * The platform dependent part shall select one of the following strategy. + */ +#ifdef SET_VBUS_FOR_EACH_IRQ +#define CHIP_ON_SAME_VBUS(pChip1, pChip2) ((pChip1)->bChipIntrNum==(pChip2)->bChipIntrNum) +#elif defined(SET_VBUS_FOR_EACH_CONTROLLER) +#define CHIP_ON_SAME_VBUS(pChip1, pChip2) \ + ((pChip1)->pci_bus==(pChip2)->pci_bus && (pChip1)->pci_dev==(pChip2)->pci_dev) +#elif defined(SET_VBUS_FOR_EACH_FUNCTION) +#define CHIP_ON_SAME_VBUS(pChip1, pChip2) \ + ((pChip1)->pci_bus==(pChip2)->pci_bus && (pChip1)->pci_dev==(pChip2)->pci_dev && (pChip1)->pci_func==(pChip2)->pci_func) +#else +#error You must set one vbus setting +#endif + +#define FOR_EACH_CHANNEL_ON_VBUS(_pVBus, _pChan) \ + for (_pChan=pChanStart; _pChanpChipInstance->pVBus!=_pVBus) ; else + +#define FOR_EACH_DEV_ON_VBUS(pVBus, pVDev, i) \ + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) \ + if ((pVDev=pVBus->pVDevice[i])==0) continue; else + + +#define FOR_EACH_VBUS(pVBus) \ + for(pVBus = gVBus; pVBus < &gVBus[MAX_VBUS]; pVBus++) \ + +#define FOR_EACH_ARRAY_ON_ALL_VBUS(pVBus, pArray, i) \ + for(pVBus = gVBus; pVBus < &gVBus[MAX_VBUS]; pVBus++) \ + for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) \ + if ((pArray=((PVDevice)&pVBus->_ArrayTables[i*ARRAY_VDEV_SIZE]))->u.array.dArStamp==0) continue; else + +#define FOR_EACH_DEV_ON_ALL_VBUS(pVBus, pVDev, i) \ + FOR_EACH_VBUS(pVBus) \ + for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) \ + if ((pVDev=pVBus->pVDevice[i])==0) continue; else + +/*************************************************************************** + * Description: the functions called by IDE layer + ***************************************************************************/ +#ifdef SUPPORT_ARRAY +#define IdeRegisterDevice fCheckArray +#else +void HPTLIBAPI IdeRegisterDevice(PDevice pDev); +#endif + +/*************************************************************************** + * Description: the functions OS must provided + ***************************************************************************/ + +void HPTLIBAPI OsSetDeviceTable(PDevice pDevice, PIDENTIFY_DATA pIdentify); + +/* + * allocate and free data structure + */ +PChannel fGetChannelTable(void); +PDevice fGetDeviceTable(void); +#define OsGetChannelTable(x, y) fGetChannelTable() +#define OsGetDeviceTable(x, y) fGetDeviceTable() +void OsReturnTable(PDevice pDevice); +/*************************************************************************** + * Description: the functions Prototype + ***************************************************************************/ +/* + * vdevice.c + */ +int Initialize(void); +int InitializeAllChips(void); +void InitializeVBus(PVBus pVBus); +void fRegisterChip(PChipInstance pChip); +void __fRegisterVDevices(PVBus pVBus); +void fRegisterVDevices(void); +void HPTLIBAPI UnregisterVDevice(PVDevice); +void HPTLIBAPI fCheckBootable(PVDevice pVDev); +void HPTLIBAPI fFlushVDev(PVDevice pVDev); +void HPTLIBAPI fFlushVDevAsync(PVDevice pVDev, DPC_PROC done, void *arg); +void HPTLIBAPI fShutdownVDev(PVDevice pVDev); +void HPTLIBAPI fResetVBus(_VBUS_ARG0); +void HPTLIBAPI fCompleteAllCommandsSynchronously(PVBus _vbus_p); + +#define RegisterVDevice(pVDev) +#define OsRegisterDevice(pVDev) +#define OsUnregisterDevice(pVDev) + +#ifdef SUPPORT_VBUS_CONFIG +void VBus_Config(PVBus pVBus, char *str); +#else +#define VBus_Config(pVBus, str) +#endif + +#pragma pack(1) +struct fdisk_partition_table +{ + UCHAR bootid; /* bootable? 0=no, 128=yes */ + UCHAR beghead; /* beginning head number */ + UCHAR begsect; /* beginning sector number */ + UCHAR begcyl; /* 10 bit nmbr, with high 2 bits put in begsect */ + UCHAR systid; /* Operating System type indicator code */ + UCHAR endhead; /* ending head number */ + UCHAR endsect; /* ending sector number */ + UCHAR endcyl; /* also a 10 bit nmbr, with same high 2 bit trick */ + ULONG relsect; /* first sector relative to start of disk */ + ULONG numsect; /* number of sectors in partition */ +}; + +typedef struct _Master_Boot_Record +{ + UCHAR bootinst[446]; /* space to hold actual boot code */ + struct fdisk_partition_table parts[4]; + USHORT signature; /* set to 0xAA55 to indicate PC MBR format */ +} +Master_Boot_Record, *PMaster_Boot_Record; + +#ifndef SUPPORT_ARRAY +/* TODO: move it later */ +#ifdef __BIG_ENDIAN_BITFIELD +typedef DWORD TIME_RECORD; +#else +typedef struct _TIME_RECORD { + UINT seconds:6; /* 0 - 59 */ + UINT minutes:6; /* 0 - 59 */ + UINT month:4; /* 1 - 12 */ + UINT hours:6; /* 0 - 59 */ + UINT day:5; /* 1 - 31 */ + UINT year:5; /* 0=2000, 31=2031 */ +} TIME_RECORD; +#endif +#endif + +#pragma pack() +#endif diff --git a/sys/dev/raid/hptmv/x86_64-elf.raid.o.uu b/sys/dev/raid/hptmv/x86_64-elf.raid.o.uu new file mode 100644 index 0000000000..aa9216eb33 --- /dev/null +++ b/sys/dev/raid/hptmv/x86_64-elf.raid.o.uu @@ -0,0 +1,1934 @@ +/* + * Copyright (c) 2004-2005 HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptmv/amd64-elf.raid.o.uu,v 1.2 2009/04/07 16:38:25 delphij Exp $ + */ +begin 644 hptmvraid.o +M?T5,1@(!`0D```````````$`/@`!`````````````````````````"CA```` +M`````````$```````$``#@`+`$B![$@"``!(B9PD&`(``$B)K"0@`@``3(FD +M)"@"``!,B:PD,`(``$R)M"0X`@``3(F\)$`"``!(B?M,BV\02(UOB$R-9"00 +MN`(```"`?P$`=0N`?P(!&<"#X`+_P(A%`$C'10@`````@$T!!$B+0Q!(B440 +MBU,82(E5&$@/MD4`2(L$Q0````!(B45H@'T``W4N2(U"]DB)11B+&Z(````$B)W^@`````08$\)/,6>%IT(&9FD&9FD$@/MD4`2(L$Q0````!( +MB45P@$T!!.E:!0``OI````!,B>?H`````(3`==5!]D0D"0)T'<9#"`%!#[9$ +M)`J(0PLZ0PES"P^V\$B)W^@`````O@`"``!,B>?H`````(3`=!=)C;PDD``` +M`+IP`0``O@````#H`````$$/MI0DDP```+X!````(=8/MD,$@^#\B=�() +M\`G(O@0````AUH/@\XG1@^$("?`)R+X0````(=:#X,^)T8/A(`GP""`>!`( +M#X=7_O__2`^V0!!(@SS&``^$1_[____".=%_UD6+?"0808N$))@```!(P>`@ +M20G'N@````!(8\)(:`@2`G028E&&$$/MD0D(T&(1GH/MLBX`0```-/@ +M9D&)AI````!)#[8&2(L$Q0````!)B49H2`^V`TB+!,4`````28E&<`^V1"0/ +M08A&`T@/MD0D#TR)M,.@````_D-Y28UT)"Q)C;[@````NA````#H`````$F- +M="0\28V^\````+H$````Z`````!)C;0D@````$F-OC0!``"Z$````.@````` +M28UT)$!)C;[T````ND````#H`````$'V1"0)`70%08!.`0%)#[9$)"))@[S& +MH`````!U4R)=0A)#[8&2(L$Q0````!( +MB45P33F^F````'9!38F^F````.LX2`^V1"0/2(.\PZ``````=2=(B:S#H``` +M`$B)70C^0WD/MD0D#XA%`T@/M@-(BP3%`````$B)17!(BYPD&`(``$B+K"0@ +M`@``3(ND)"@"``!,BZPD,`(``$R+M"0X`@``3(N\)$`"``!(@<1(`@``PV9F +M9I!54TB#[`A(B?.]``````^V1GB)PH/X``^.TP```&9FD$ACQ4B#O,.@```` +M`'0+_\4YZG_LZ;<```"X`0```(GIT^!F"8.4````2(G>Z`````!(B<)(A<`/ +MA),```#&``-`B&@#2(E8"(`["`^4P,'@`P^V2@&#X?<)P8A*`4B+!0````!( +MB4)H2`^V`TB+!,4`````2(E"UT(8!] +M``-V&TB)[DR)[^@`````]H62````!'0'@(N2````!$'_Q`^V0WA$.>!_P^DO +M`0``@$X!!(!^>0)U$X"FD@```/[I&0$``&9F9I!F9I"`II(```#]2(.^H``` +M``!U'4B+AJ@```#&0`,`2(F&H````$C'AJ@`````````2(N#H````(`X`W4+ +M2(G>3(GOZ`````"`BY(````$2,>#F`````````#IM@```&9F9I`/MD9Y.D9X +M=2F`3@$$#[:&D@```(/@_HB&D@```&:#OI0`````='F#R`*(AI(```#K;@^V +M1GG_P`^V5G@YT'5@9H.^E`````!T++D`````#[>&E````(G"J`%U"O_!B=#3 +M^*@!=/9(8\%(@[S#H`````!U(>L)]H:2`````G46@$L!!("+D@````1(B=Y, +MB>_H`````$C'@Y@`````````2`^W@Y````!(]]A((8.8````2(-["`!U&?:# +MD@````1T$.@`````B4-\2(G?Z`````!(BUPD"$B+;"003(MD)!A,BVPD($B# +MQ"C#9F:09I!!5%5328G\O0````!F9F:02&/%2&G`2`$``$J-G"#(1```@WM\ +M`'0@2(-["`!U&4B)WDR)Y^@`````]D,!!'0(2,=#<`````#_Q8/]#W[!6UU! +M7,-F9F:09F9FD&9F9I!!5T%6055!5%532('L"`(``$F)_4B)]4&)UDF)YTB) +M]^@`````@'T`"'4+2(GN3(GOZ`````!!O`````"`?7@`#X;'````26/$2(.\ +MQ:``````#X2H````2(NTQ:````"`/@-V$4$/MM9,B>_H`````.F*````26/$ +M2(N$R)^;HP```` +MO@````#H`````.L3#[95`8/B`0^V0P&#X/X)T(A#`4B)W^@`````9F:09F:0 +M0?_$1#AE>`^'.?___[I(`0``O@````!(B>_H`````$F+A$) +M00^V=E!F9F:09F:03(M%`+\```$`9H-]"`!T!`^W?0@Y^8GZ#T;11#GF=1%F +MB5,(9L=#"@``3(D#2(/#$"G7B=!)`<`IT74>_\9!#[9%>#G&N``````/1/!! +M#[>%D````(G!P>$)A?]UMF:!?0H`@'0&2(/%$.N49L=#^@"`N`$```!(@<0` +M`@``6UU!7$%=05[#9F:09F:09F:03(M/"$R+1D@/MD\##[=^6#A.4'4+2`^W +M1E9)`<#K$9`X3E!V"TD/MX&0````20'`.$Y0=0MF`WY49F9FD&9FD#A.474+ +M9@-^4F9F9I!F9I"`?EP`=`XX3E!S)3A.46:0=Q3K'#A.4',(9D$#N9`````X +M3E%V"F9!`[F0````9I!FB7H03(E"",-F9F:09F:04TF)^4F)\$B+?@A$#[=6 +M$$&[`````$$/MDEZ2(G^2-/N9D''0%@``$'&0%P!20^V47A(B?!(B=&Z```` +M`$CW\4$/MDEZ2-/@28E`2$D/ME%X2(GP2(G1N@````!(]_%!B%!0B=%!#[>! +MD````/_((?AF08E`5D$/MY&0````9BG"9D0YTG(-9D6)4%1!N@````#K8F9! +MB5!49D$ITD&[`0```+H!````B=#3X&9!"4!:_\%!.$EX=2FY`````$&`>%P` +M=`M!QD!<`.L69F9FD$$/MT!89D$#@9````!F08E`6&9%.9&0````0$B+!@^V2`.X_O___]/`9B%#6H!^(0%T!P^V1B&( +M0R%(B>_H`````&:#>UH`=1F`>R$`=03&0R$!2(MS.$B)VDB)[^@`````2(/$ +M"%M=PV9FD&:02(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F) +M_TB)]4R+-D'V1@$$=17&1B$"2(MV.$B)ZN@`````ZY,B>?H#OW__TC'0S@`````2,=#,`````!(B=Y,B?]!_U0D:&9FD$'_Q4$/ +MMD9X1#GH#X]P____2(M<)`A(BVPD$$R+9"083(ML)"!,BW0D*$R+?"0P2(/$ +M.,-F9F:09F9FD&9F9I!(@^P(2(M."`^V40&`9@'[@&$!^_Y)>8")D@````%( +M@WEP``^5P/;"!`^5P@^VP(7"=`U(B<[_47!F9F:09F:02(/$",-F9F:09F9F +MD&9FD$B#[`A,BT9`28MP*$B%]G0-9D$/MD`@@^`!.#``=!!,B<9! +M_U`PN@$```"%P'4PN@````#K*69F9I!(BP9(B0)(BT8(2(E""$B#PA!(C48* +M2(/&$&:#.`!YX+H!````B=!(@\0(PV9F9I!54TB)^P^V!X/H!(/X`7=0O0`` +M``"`?W@`=#=F9I!FD$ACQ4B#O,.@`````'012(N\PZ````#HQ?___X7`=0>X +M`````.LD_\4/MD-X.>AFD'_.N`$```#K$69F9I!F9I`/MD"@`=#/V0"`!="U(BT@H2(L!2(D"2(M!"$B)0@A(@\(02(U! +M"DB#P1!F@S@`>>#K'F9F9I!F9I"^`````$B#>#``=!!(B<:0_U`PB<;K!;X! +M````B?!(@\0(PV9F9I!F9I!F9I!F9I!(@^P82(D<)$B);"0(3(ED)!!)B?Q( +MB?-(BVY`2(L&#[9(`[C^____T\!F(45:@'XA`70'#[9&(8A%(4B)WDR)Y^@` +M````9H-]6@!U6H!](0!U),9%(0%(BTT`2(N1F````$@[4PAU#T@/MT,02`'0 +M2(F!F````$B+=3A(B>I,B>?H`````$B+10!FQT`H``!(BU4`2(/",$C'Q@`` +M``!,B>?H`````$B+'"1(BVPD"$R+9"002(/$&,-F9I!F9I!(@^P82(D<)$B) +M;"0(3(ED)!!)B?Q(B?-(BVY`@'XA`70.#[9&(8A%(>MY9F:09I"`?A(@=4K& +M1B$`2(M%`$B+@*@```!(B09(C7Y(NE@```"^`````.@`````QD,B`,9#$C`/ +MMD,@@^#]@\@$B$,@2(L#2(G>3(GG_U!HZV%FD,9%(0%(BTT`2(N1F````$@[ +M5@AU#T@/MT802`'02(F!F````$B)WDR)Y^@`````2(MU.$B)ZDR)Y^@````` +M2(M%`&;'0"@``$B+50!(@\(P2,?&`````$R)Y^@`````2(L<)$B+;"0(3(MD +M)!!(@\08PV9F9I!F9F:09F:09F:005154TF)]$B)U4B+1D"%R71&2(M0&$B) +M50`/MT80P>`)9HE%"&;'10H`@$B+!H!X`P`/A`T!``!(C8(```$`9H-]"`!T +M"4@/MT4(2(T$`DB)10#I[0````^W7A#!XPE(@W@H`'0L]D`@`70F2(M(*$B+ +M`4B)`DB+00A(B4((2(/"$$B-00I(@\$09H,X`'G@ZS2Z`````$B#>#``#X2H +M````2(GJ2(G&_U`PN@````"%P`^$D@```.L,9HE9"&;'00H`@.M&2(GI9F9F +MD&9FD+H```$`9H-Y"`!T!`^W40A)BP0D@'@#`'06.=IV%HG82`$!B=!F*=AF +MB4$(ZPYFD#G:<[9(@\$0*=-UQ$F+!"2`>`,`#Y7`2#G-#Y7"#[;`A<)T(4B+ +M`4B)10!(BT$(2(E%"$B#Q1!(C4$*2(/!$&:#.`!YW[H!````B=!;74%3(GG_U!HZW\/MU80P>()B=9( +MBWT82`'^Z`````"%P'0'QD4A#.LED,9%(0%(BTT`2(N1F````$@[4PAU#T@/ +MMT,02`'02(F!F````$B)WDR)Y^@`````2(MU.$B)ZDR)Y^@`````2(M%`&;' +M0"@``$B+50!(@\(P2,?&`````$R)Y^@`````2(L<)$B+;"0(3(MD)!!(@\08 +MPV9F9I!F9F:09F:09F:02(/L*$B)7"0(2(EL)!!,B60D&$R);"0@28G\2(GS +M2(LN2,=%.`````#VA9(````!#X5J`0``#[9&$H/X`@^$`P$``(/X`G\.@_@! +M#X2?````Z4H!``"#^`-F9F:09F:0#X4Z`0``2(M&"$B)12`/MT809HE%*`^W +M5A#!X@E(BWX8O@````#H`````&;'0UH#`$&]`````$R)Y^@`````2(G&QD`2 +M,$B+0PA(B48(#[=#$&:)1A"`3B`$2(E>0$C'1C@`````2,=&,`````!)8\5( +MBX3%H````$B)!DR)Y_]0:$'_Q4&#_0%^K.G#````2(M&"$B)12`/MT809HE% +M*.@`````2(G&QD`2($B+0PA(B48(#[=#$&:)1A"`3B`"2(E>0$C'1C@````` +M2,=&,`````!(BX6@````2(D&3(GG_U!HZVU(BT8(2(E%(`^W1A!FB44HZ``` +M``!(B<;&0!(@2(M#"$B)1@@/MT,09HE&$(!.(`)(B5Y`2,=&.`````!(QT8P +M`````$B+A:````!(B09,B>?_4&CK%V9F9I#&0R$&2(MS.$B)VDR)Y^@````` +M2(U5,$C'Q@````!,B>?H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,.0 +M2(/L.$B)7"0(2(EL)!!,B60D&$R);"0@3(ET)"A,B7PD,$F)_TF)]$B++O9% +M`01U%<9&(0)(BW8X3(GBZ`````#IV@$``/9&("!T)$C'13@`````2(EU0&:# +M?2H`#X6]`0``Z+C]___ILP$``&9FD$B#?3@`=2EF@WTH`&9F9I!T/D@/MT4H +M2`-%($@[1@AV+T@/MT802`-&"$@Y12!S($G'1"10`````$B-?3!,B>;H```` +M`.EF`0``9F:09F:09O]%*O:%D@````,/A9\```!!]D0D(`(/A),```!(BY6@ +M````2(NUJ````(`Z`W5D@#X#=5])BT0D"(G!*XJ8````08G`1"N&F````(NZ +MG````(NVG````(G(F3'1*=%$B<"903'002G01#G!?1.%]@^41"0'@_\%#Y?` +M($0D!^LTA?\/E40D!X/^!0^6P`A$)`?K(8"]E@`````/E$0D!P^V3"0'B(V6 +M````ZPAF9I#&1"0'`&9!QT0D6@``0;X`````1(GP1`^VZ$J#O.V@`````'1[ +M2HN$[:````#V0`$$=&U!#[94)"#`Z@)$.'0D!P^4P`G0J`%T5DR)_^@````` +M2(G#ND@```!,B>9(B3(G__U!H9F:00?_&08#^`0^&9O__ +M_V9FD$B+7"0(2(ML)!!,BV0D&$R+;"0@3(MT)"A,BWPD,$B#Q#C#9F9FD&9F +MD&9FD&9FD%532(/L"$B)]4B+7@@/ME8#@&8!^X"+D@````%(QX.8```````` +M`/Y+>8![>0!U!H!C`?OK'`^V@Y(```"H`G01@^#7B(.2````A=)U!(!C`?OV +M0P$$=1U(@WMP``^$+`$``$B)WO]3<&9F9I!F9I#I&@$``(72=21(BY.@```` +MQD(#`4B+@Z@```#&0`,`2(F#H````$B)DZ@```!(@WL(`'0.2(M#"/9``00/ +MA(,```!(BX.@````@#@#=7=(B=[H`````$B)PDB%P'1GQ@`#QD`#`4B)6`A( +MBP4`````2(E":$B+!0````!(B4)P]D,!$'0.@$H!$(N"D````$B)0AA(QT4( +M`````$B)DZ@````/MH.2````@^#^@\@*B(.2````_D-Y2(G6OP<```#H```` +M`$B#>P@`=`]F9F:02(M;"$B#>P@`=?6+@X@```")@XP```"+@X0```")@X@` +M``"+@X````")@X0```"+0WR)@X````#H`````(E#?,:#EP````%(B=_H```` +M`$B#Q`A;7<-F9F:09F:09F:02('L*`(``$B)G"0``@``2(FL)`@"``!,B:0D +M$`(``$R)K"08`@``3(FT)"`"``!)B=1,BS9(BVY`2(M=*$&]$0```$B)XDB% +MVW0,9@^V12"#X`$YR'4I2(G32(-],`!T#TB)[O]5,(7`=15F9I!FD+@````` +MZ>4```!F9I!F9I"`?5'_#X2^````#[=-5,'A";H```$`9H-["`!T!`^W4P@Y +MT78[00^V1@,Z15!U%$B+`TF)!"1(BT,(28E$)`A)@\00*=%(@\,0N@```0!F +M@WL(`'0$#[=3"$'_S3G1=\5!#[9&`SI%4'4<2(L#28D$)&9!B4PD"&9!QT0D +M"@"`N`$```#K63G1)R$@#`TF)!"2)T&8IR&9!B40D"&:!>PH`@'4/9D'' +M1"0*`("X`0```.LJ9D''1"0*``!)@\002(/#$$'_S42)ZDC!X@1(B=Y,B>?H +M`````+@!````2(N<)``"``!(BZPD"`(``$R+I"00`@``3(NL)!@"``!,B[0D +M(`(``$B!Q"@"``##D`^V1P,Z1E!U%P^W1E1FB4(02(M&2$B)0@C#9F:09F:0 +M#[=&4F:)0A!(QT((`````,-F9F:09F9FD&9F9I!F9I!,BT8(1`^W3A!!NP`` +M``"Y`````(!_>``/A(,```!%#[?1B_H`````$B#Q`A;7<-F9I!FD$B#[#A(B5PD"$B) +M;"003(ED)!A,B6PD($R)="0H3(E\)#!)B?](B?5,BS9!]D8!!'45QD8A`DB+ +M=CA(B>KH`````.G*````3(GWZ*'^__]F@WU:`'4:QD4A`DB+=3A(B>I,B?_H +M`````.FC````9I!!O0````!!@'YX``^$D`````^W15I$B>G3^*@!='),B?_H +M`````$B)PTECQ4V+I,:@````3(DC2(EK0`^V52"#X@(/MD,@@^#]"="(0R`/ +MME4@@^($@^#["="(0R`/MD42B$,22(G:2(GN3(GGZ,[]__](QT,X`````$C' +M0S``````2(G>3(G_0?]4)&AF9I!!_\5!#[9&>$0YZ`^/8"(D@````%(@WAP`'0&2(G&_U!P2(/$",-F9F:02&/. +M2(N4SX!9``!(A=)T"TB+`DB)A,^`60``2(G0PY!(8])(BX37@%D``$B)!DB) +MM->`60``PV9FD&9FD&9FD$%7059!54%455-(@^P(28G_O0"```"!_@!```!W +M:&:]`$"!_@`@``!W7&:]`""!_@`0``!W4&:]`!"!_@`(``!W1&:]``B!_@`$ +M``!W.&:]``2!_@`"``!W+&:]``*!_@`!``!W(&:]``&!_H````!W%&:]@`"# +M_D!W"X/^(1GM@^7@@\5`B=`/K\5$C;#_#P``0<'N#,=$)`0`````N`````"! +M_0`0```/A]L```!!_\Y!@_[_#X3*````0;T`$```3(G_Z`````!(BA(`<-!_\1$B>BZ`````/?U1#G@#X=W____0?_.08/^_P^%//__ +M_XM$)`1(@\0(6UU!7$%=05Y!7\-F9F:09F:055-(B?V)\[@`````.;?860`` +M2&/#2(M\Q0BZ`!```+X`````Z`````#_RX/[_W7B2(/$ +M"%M=PV9FD&9FD&9FD(L/_\F#^?]T+DACP4B+1,<(N@````!(@S@`=`:X```` +M`,/_PDB#P`B!^O\!``!VYO_)@_G_==*X`0```,-F9I!(@^P(NA````"^```` +M`.@`````2(/$",-F9F:09F9FD$B#?A@`=`Q(BU882(M&$$B)0A!(BU802(M& +M&$B)`DC'1A``````N@````#HL/S___/#9F9FD&9F9I!F9I!F9I!(C4]@2(M' +M8$B)1AA(A6^`````.C[^___2(G#3(D@2(EH +M"$B)QDR)[^AF____2(G82(L<)$B+;"0(3(MD)!!,BVPD&$B#Q"##9F9FD&9F +M9I!F9I`/MD=-#[;02(T4DDB-5-=0_\"(1TU(B3K&0@D`QD(*`,9""P!(B=## +M9F9FD&9F9I!!5%5328G\2(GSO0`````/ME9*C4+]T?@!PH/Z`'XED$ACQ4B+ +MM,.@"@``3(GGZ*W]____Q0^V4TJ-0OW1^`'".>I_W+H'````2(G>3(GGZ%S[ +M__];74%2Z!P```$B)[DR)[^AO^?__ +MN`````#K,DECQ$C!X`1(C1PH2(V[\`H``.A1_/__2(V[<`L``.A%_/__0?_$ +M13GF#X]Y____2(GH2(/$&%M=05Q!74%>05_#9F9FD&9FD$%455-(B?5(B=.) +MS@^V37J)T-/H)?\!``!(BU583(TDPDV+!"1-A$B)VNAH +M_?__28G`2(7`=%!(B6@X28L$)$F)0"A(A$&(<$H/MDUZ2(G82-/H2`^V57A(B=&Z`````$CW\4`HUO_.08AP +M2TR)P%M=05S#9F9FD&9F9I!!5T%6055!5%532('L:`$``$B)?"1(2(ET)$!( +MB50D.`^V5B")T-#H@_`!B<�&)3"0T2(-^*`!T!?;"`70<3(U\)%"Y`0`` +M`$R)^DB+="1`2(M\)$C_5C#K"4B+7"1`3(M[*,=$)`P```$`9D&#?P@`=`E! +M#[='"(E$)`Q!O0````#'1"0P`````$B+5"1`@+J```````^$=P$``$AC1"0P +M2(M,)$!(BT3!6$B)1"0@#[:88`P``(A<)"\XF&$,```/@C(!```/MD0D+TB+ +M5"0@.$)+#X0%`0``#[;`2(G1#[>4@D`,```/MX2!0@P``&:)1"00B=!FP>@# +M#[?`B40D"$&)UD&#Y@=!#[?&B<;!Y@FX"````&9$*?!!B<9F1#MT)!"+7"00 +M1`]'\T$/M\:)Q<'E"4@/MD0D+TB+5"0@2(N,PJ`*``"+5"0(B?!)B<1,`V31 +M"$0[;"0,=2-)@\<0QT0D#````0!F08-_"`!T"4$/MT\(B4PD#$&]`````(M< +M)`Q$*>LYZP]'W8-\)#0`=!)$B>Y)`S>)VDR)Y^@`````ZQ!$B>])`S^)VDR) +MYN@`````00'=*=UT!XG820'$ZY-F1"ET)!!T%/]$)`B^`````$&^"````.D_ +M_____D0D+P^V7"0O2(M$)"`XF&$,```/@\[^____1"0P2(M4)$`/MH*````` +M.T0D,`^/B?[__[H`````2(MT)$!(BWPD2/]4)#A(@<1H`0``6UU!7$%=05Y! +M7\-F9I!F9I!54TB#[`A(B?V%TG0$QD8A"T&[`````("^@``````/A,$```!( +MC9U@60``2(V]4%D``$ECPTR+1,982<>`,`P```````!-B<*Y`````$&`>$H` +M=D8/ML%(P>`$3`'02(V0\`H``$&Y`````(.X\`H```!U$H-Z!`!U#(-Z"`!U +M!H-Z#`!T!D&Y`0```$6%R9!U)?_!03A*2G>ZN`````"%P'0=2(M#"$R)0PA) +MB1A)B4`(3(D`ZQNX`0```.OA9I!(BT<(3(E'"$F).$F)0`A,B0!!_\,/MH:` +M````1#G8#X]-____2(GOZ%,X``!(@\0(6UW#9F9FD&9F9I!F9F:02(/L2$B) +M7"082(EL)"!,B60D*$R);"0P3(ET)#A,B7PD0$F)_4B)\TB+KC`,``#_C]Q9 +M``!(C4802(M("$B+5A!(B4H(2(D12(E&$$B)0`A(A>T/A*<"``#V12`@#X0M +M`0``3(ME`$@/MT9(28G&3`-V0$0/MWY(2,>&,`P```````!(C8=060``2(M0 +M"$B)<`A(B09(B58(2(DR@+YB#````758@'T2`G5)2`^V1DM(B[S&H`H``.@3 +M]___A$))````#WV$B82"-#0$DYA"28 +M````=@A)B80DF````("[8@P```%T&@^V@V(,``"(12%(B>Y,B>_H+C<``.F) +M`P``20^WA"20````2(M5"$C_PD@/K\),.?!V+4$/M\],B?),B>9,B>_HKOK_ +M_TB)J#`,``!(B4582(G&3(GOZ$@0``#I0P,``$D/MX0DD````$D#A"28```` +M3#GP=0A-B;0DF````$B)[DR)[^BZ-@``Z14#``!F9I!FD`^VA8$```#_P(B% +M@0```#J%@`````^%E0(``/9%(`0/A-P```!!O@````"`O8``````#X:Y```` +M2(V'4%D``$B)1"002(V78%D``$B)5"0(1(GR#[;"2(MY,B>_HM#4``.FO`0``0;X`````@+V``````'8J1(GR#[;"2(M< +MQ5B`NV(,```!=`H/MH-B#```B$4A0?_&1#BU@````'?6@'TA`'472,?"```` +M`$B)[DR)[^C>^?__Z5D!``"Z`````$B)[DR)[^@)_/__Z40!``!F9F:0@+YB +M#````0^%@P```$F)]+T`````@'Y*`'8D9F:09I")Z`^V^$C!YP1*C;PG\`H` +M`.C:]/___\5!.&PD2G?A2(.[.`P```!T*4B+@S@,``!(B8,P#```2,>#.`P` +M``````!(B=Y,B>_H,PX``.G.````28V%4%D``$B+4`A(B5@(2(D#2(E3"$B) +M&NM:9F:02(V'8%D``$B+4`A(B7`(2(D&2(E6"$B),DB#OC@,````=#1(BX8X +M#```#[:68@P``(A0(4B+EC@,``!(Q\8`````Z`````!(QX,X#````````.FY +M````2(MS,$R)[^@]]/__2,=#,`````!(BT,X2(-X,`!T%4B-4#!(Q\8````` +M3(GOZ`````#K)4F#O>A9````=!M)C97H60``2,?&`````$R)[^@`````9F:0 +M9I!!@[W@60```'16@+MB#````75-2(M[.$B#?T@`=##H#3(``(7`=2=(BT,X +M2(M04$B+<$A,B>_H`````$B+0SA(QT!(`````$'_C>!9``!!@[W@60```'0( +M3(GOZ`````!(BUPD&$B+;"0@3(MD)"A,BVPD,$R+="0X3(M\)$!(@\1(PV9F +M9I!F9I!F9I!F9I!(@^P(2(L6@'I.`'03QD).`$C'Q@````#H`````&9FD$B# +MQ`C#9F9FD&9F9I!F9I!!5T%6055!5%532(/L"$F)U$&)STB+1D!(BQ!(#[9` +M$4R+M,*@"@``BT8(*T)`P>`)#[=N$,'E"8G!@>'_#P``08G%0<'M#+L`$``` +M*05_#9F9FD&9F9I!F9I`/MD<2`D<3B$<22(U7%+X!```` +MZP^`?Q(`>0:X`````,/^1Q(/MD\2@_D?=Q.)\-/@A4<4#Y7`#[;`ZU1F9F:0 +M@_D_=Q*#Z2")\-/@A4($#Y7`#[;`ZSF#^5]W%(/I0(GPT^"%0@@/E<`/ML#K +M(F:0N`````"#^7]W%H/I8(GPT^"%0@P/E<`/ML!F9I!F9I"%P'2!QD<3`4R- +M1Q0/ME<2O@$```#K`_Y'$P^V1Q.-#`*#^1]W#XGPT^"%1Q0/E<`/ML#K3H/Y +M/W<6@^D@B?#3X$&%0`0/E<`/ML#K-F9FD(/Y7W<3@^E`B?#3X$&%0`@/E<`/ +MML#K&[@`````@_E_=Q&#Z6")\-/@085`#`^5P`^VP(7`=9"P`<-F9I!F9I!( +M@^P82(D<)$B);"0(3(ED)!!(B?U(BUY`3(LC#[9&(8A#"N@`````@'L*`75R +M2(G?Z*K^__^%P'06QD,*`$B)WDB)[^C'````ZV1F9I!FD(!["`%U2@^V0Q!! +M.$0D2Y!T/CA#$74Y#[;P2(GP2,'@!$J-M"!P"P``2(U+%(L&"T,4B0:+1@0+ +M002)1@2+1@@+00B)1@B+1@P+00R)1@R0QD,)`DB)WDB)[^A!_?__2(L<)$B+ +M;"0(3(MD)!!(@\08PV9F9I!F9F:09F:09F:02(/L&$B)7"0(3(ED)!!)B?Q( +MB?/&1A,`QD82`$B)]^CL_?__2(G>3(GGZ!$```!(BUPD"$R+9"002(/$&,-F +MD$B#["A(B5PD"$B);"003(ED)!A,B6PD($F)_4B)\TB++DB+53A(#[9&$$R+ +MI,*@````Z`````!(B<9,B2"`>P@!=0V`2"`"QD`2(.L+9F:0@$@@!,9`$C!( +M#[9#$D@#14!(B48(9@^V0Q-FB4802,=&,`````!(B5Y`2,=&.`````!,B>]! +M_U0D:$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:09F:09F:09F:00515 +M4T&Y`````$&[`````$B)_4&\`0```.L808/[?W8/1(G(Z5X!``!F9F:09F:0 +M0?_#1(G:08/['W<21(G@1(G9T^"%!P^5P`^VP.M208/[/W<3C4K@1(GCT^.% +M700/E<`/ML#K.4&#^U]W$XU*P$2)X-/@A44(#Y7`#[;`ZR"X`````$&#^W]W +M%8U*H$2)X]/CA5T,#Y7`#[;`9F9FD(7`#X1S____0;@!````2(GZ0;H!```` +MZPIF9F:09F:00?_`0XT,`X/Y'W<41(G0T^"%`@^5P`^VP.M59F:09I"#^3]W +M$X/I($2)T-/@A4($#Y7`#[;`ZSB#^5]W$X/I0$2)T]/CA5H(#Y7`#[;`ZR"X +M`````(/Y?W<6@^E@1(G0T^"%0@P/E<`/ML!F9I!FD(7`=8Q$B=E%`<-!N@@` +M``!$BQD`#X3A````2(-[$`!U"4B)@`````_\-$.?-\A.E_````2(UT)"!(B=_H,OW__T&)QD@/ +MMD,83(NDQ:`*``!)#[9%&$R+O,6@"@``NP````!$.?-]2TACTP^V1)0AB<'! +MX0D/MD24(D&)P$'!X`E(#[9$E"")SDB)]TD#?,0(2(E\)!!)`W3'"$B)="08 +M1(G"Z`````#_PT0Y\WRY9F9FD+H`````3(GN2(M\)`CHC@(``$B+G"0H`0`` +M2(NL)#`!``!,BZ0D.`$``$R+K"1``0``3(NT)$@!``!,B[PD4`$``$B!Q%@! +M``##9F:09F:02('L2`$``$B)G"08`0``2(FL)"`!``!,B:0D*`$``$R)K"0P +M`0``3(FT)#@!``!,B;PD0`$``$F)_TB)]4B+'DB-="002(U]$.@B_/__08G$ +M2`^V12!,B[3#H`H``$@/MD4A3(NLPZ`*``"[`````$0YXWT]2&/##[9TA!'! +MY@D/ME2$$L'B"4@/MD2$$(GV2(GW20-\Q@A(B3PD20-TQ0A(B70D".@````` +M_\-$.>-\P[H`````2(GN3(G_Z(X!``!(BYPD&`$``$B+K"0@`0``3(ND)"@! +M``!,BZPD,`$``$R+M"0X`0``3(N\)$`!``!(@<1(`0``PV9FD&9FD$%7059! +M54%455-(@>R(`0``28G_2(GU3(LF2(M>$$B-M"2`````2(G?Z$+[__]!B<9( +M#[9#&$V+K,2@"@``NP````"`?2``=B,/MDT@9F:0#[;#2`^V5"@828N4U*`* +M``!(B53$0/_#.-EWY$&\`````$4Y]`^-K0```&9FD&:026/$#[:4A($```!! +MB=)!P>()#[:4A((```!!B=-!P>,)#[:,A(````"[`````(!](`!V*$0/MLE% +MB=`/MG4@D`^VPTB+5,1`2HM\R@A)C10X2(D4Q/_#0#C>=^0/MM%$B=!(B<=) +M`WS5"$@Y/"1U$$B+="0(1(G:Z`````#K'9!(BU0D"$B+-"0/ML%$B==)`WS% +M"$2)V>@`````0?_$13GT#XQ8____N@````!(B>Y,B?_H&````$B!Q(@!``!; +M74%<05U!7D%?PV9FD&9FD$B#[!A(B1PD2(EL)`A,B60D$$F)_$B)\XG5QD8) +M`H/Z`1G`@^#U@\`,B$8*Z!_V__^`>P@#=2](BT,02(MP$$B%]G0B2,=`$``` +M``#&1@D"@_T!&<"#X/6#P`R(1@I,B>?HZO7__TB+'"1(BVPD"$R+9"002(/$ +M&,-F9F:09F:0#[96"X72=$:)T$@/MH1'L`D``$B-!(!(C43'4(!X"0)T!K@` +M````PX!X"@%T$L9&"0(/MD`*B$8*N`````##D(G0#[:41[$)``"%TG6ZN`$` +M``##9F9FD&9F9I!F9F:005=!5D%505154TB#[`A)B?Y(B?7&1DX`@+YC#``` +M``^$BP```$&\`````$B-75"`?4T`=$Z`>PD!=3B`>P@#=2E(BT,0@'@9`'0? +M2(-X$`!T&$C'0!``````QD,)`@^VA6(,``"(0PKK"<9%3@'IMP$``$'_Q$B# +MPR@/MD5-1#G@?[)(B>Y,B??H$O#__^F7`0``#[9#"HB%8@P``,:%8PP```'I +M?/___V9F9I!F9I!!OP````!!O0$```!!O`````!(C5U0@'U-``^$-`$``(![ +M"0!U>DB)WDB)[^B__O__APD"=1!!_\=F9F:09F:0@'L)`G0+0;T` +M````Z8\```"`>PH!#X2%````@'U/`)`/A!W___](BT4X2`^V4Q!(BX30H``` +M`/9``01T7T&]`````,9#"0'&0PH`3(GW2(G>#[9#"(/X!G=&B<#_),4````` +MZ)CV___K-F9FD&9FD.@+^?__ZRGH!/O__V9F9I#K'NCY^___ZQ?&14\!QD8) +M`L9&"@'HAO/__^L$QD,*`4'_Q$B#PR@/MD5-1#G@#X_,_O__187_#X6C_O__ +M187M=!3&A6(,```!2(GN3(GWZ'SN___K!,9%3@%(@\0(6UU!7$%=05Y!7\-F +M9F:09F:005=!5D%505154TB!['@!``!(B7PD2$B)]4B+7CA,BZ8P#```0;T` +M````387D=2A(#[=.2$B+5D!(`=%(B=[HO>;__TB)13"X_____TB#?3``#X2N +M(@``2(M$)$C_@-Q9``!(C4402(M4)$A(@<)P60``2(M*"$B)0@A(B5402(E( +M"$B)`6:#NY0`````=$/V@Y(````!=0U(BU5`2#F3F````'# +ME````(G"J`%U#D'_QHG01(GQT_BH`73R1(AU3.LIQD5,".LC]H.2`````G06 +M2(M]0$@YNY@```!W"0^V14N(14SK!,9%3`C&14T`QH6P"0```,9%3P#&A6(, +M````QH5C#````$C'A3@,````````387D#X1?#P``0?9$)"`@#X2.!P``00^V +M1"02@_@"#X1M!```@_@"?P^#^`$/A`0!``"0Z9XA``"#^`,/A94A``!(C5PD +M8$B)W^@%Y?__28G:OP`````/MW5(NP````!!N2````!!NP$```"#_Q]W/P^V +MPTF-%()$B_H<.7__\9`"`)$B'@0QD`1`$B+5"1@2(E0%$B+5"1H2(E0'$'_QT0X +M?4IWJ^FG(```N`$```#K54B)[[D`````@'U*`)!V00^VP4C!X`1(`?A(C9#P +M"@``O@````"#N/`*````=1*#>@0`=0R#>@@`=0:#>@P`=`6^`0```(7V=;#_ +MP3A/2G>_N`````"%P'073(FE.`P``$C'A3`,````````Z<(-``!(C5PD8$B) +MW^B@X___28G:OP`````/MW5(NP````!!N2````!!NP$```"#_Q]W/P^VPTF- +M%()$B;`)``!!#[9$)`N( +MA'FQ"0``08AT)`M!OP````"`?4H`#X;3'@``2(G31#A]3'1R2(GOZ%_C___& +M0`@!1(AX$$2(>!%(BU0D8$B)4!1(BU0D:$B)4!Q!#[95(`^VRD:(?"D8_\)! +MB%4@28M5`/Z"L`D```^VLK`)``")\4@IT$B#Z%!(P?@#2`^OPXB$2K`)``!! +M#[9%"XB$2K$)``!!B'4+0?_'1#A]2@^'>____^E&'@``0;\`````@'U*``^& +M-AX``$B-G?`+``!)OLW,S,S,S,S,1#A]3`^$O0```$B)[^BPXO__QD`(`42( +M>!!$B'@12(M4)&!(B5`42(M4)&A(B5`<2(E$)$!(B>_HA>+__\9`"`-(B5@0 +M1(AX&$F)Q4B+$/Z"L`D```^VLK`)``")\4B+1"1`2"G02(/H4$C!^`-)#Z_& +MB(1*L`D``$$/MD4+B(1*L0D``$&(=0M)BQ0D_H*P"0``#[:RL`D``(GQ3(GH +M2"G02(/H4$C!^`-)#Z_&B(1*L`D``$$/MD0D"XB$2K$)``!!B'0D"T'_QT0X +M?4H/ARS____I3!T``+@!````ZUE(B>^Y`````(!]2@!V1F9F9I`/ML%(P>`$ +M2`'X2(V0\`H``+X`````@[CP"@```'43@WH$`'4-@WH(`'4'@WH,`)!T!;X! +M````A?9UK/_!.$]*=[ZX`````(7`=!=,B:4X#```2,>%,`P```````#I8PH` +M`$B-7"1@2(G?Z$'@__])B=J_``````^W=4B[`````$&Y(````$&[`0```&9F +M9I"#_Q]W/P^VPTF-%()$B_HI>#__\9`"`5(B5@0QD`@`$F)Q4&_`````(!] +M2@`/AND;``!(N\W,S,S,S,S,2(GOZ'3@___&0`@!1(AX$$2(>!%(BU0D8$B) +M4!1(BU0D:$B)4!Q!#[95(`^VRD:(?"D8_\)!B%4@28M5`/Z"L`D```^VLK`) +M``")\4@IT$B#Z%!(P?@#2`^OPXB$2K`)``!!#[9%"XB$2K$)``!!B'4+0?_' +M1#A]2G>%Z5\;```/MEU+2(GOZ/#?___&0`@!B%@0B%@12(M4)&!(B5`42(M4 +M)&A(B5`<2(E$)#A!OP````"`?4H`#X8B&P``2(V=\`L``$F\S!%(BU0D8$B)4!1(BU0D:$B) +M4!Q(B40D0$B)[^AQW___QD`(`TB)6!!$B'@828G%2(L0_H*P"0``#[:RL`D` +M`(GQ2(M$)$!(*=!(@^A02,'X`TD/K\2(A$JP"0``00^V10N(A$JQ"0``08AU +M"TF+50#^@K`)```/MK*P"0``B?%(BT0D.$@IT$B#Z%!(P?@#20^OQ(B$2K`) +M``!!#[9%"XB$2K$)``!!B'4+0?_'1#A]2@^'+/___^DX&@``9F:09I!-A>0/ +MA+P'``!!]D0D(`*0#X2O!P``1`^VO6`,``!$.+UA#```#X)5`0``9F:09I!$ +M.'U+#X0V`0``1(GX#[;82(G82,'@!$R-I`3P````3(GGZ%G=__\/MY2=0`P` +M``^WO)U"#```NP````!!N2````!!N@$```"#^A]W1`^VPTF--(1$BAF +M9I!FD$'_QT0XO6$,```/@[#^__]%A.T/A)H%``!(C7PD8.@=W/__0;\````` +M@'U*`'99D$0X?4QT240X?4MT0T2)^`^VT$C!X@1(`>I(C8KP"@``BT0D8`N" +M\`H``(E$)&"+1"1D"T$$B40D9(M$)&@+00B)1"1HBT0D;`M!#(E$)&Q!_\=$ +M.'U*=ZA,#[9%3$G!X`1*C70$<(M\)&`C/HE\)%"+3"1D(TX$B4PD5(M4)&@C +M5@B)5"18BT0D;"-&#(E$)%SWUXE\)&#WT8E,)&3WTHE4)&CWT(E$)&PC/HE\ +M)&`C3@2)3"1D(U8(B50D:"-&#(E$)&Q(B>_H9-S__\9`"`!(B40D*+@````` +M@WPD8`!U%8-\)&0`=0Z#?"1H`'4'@WPD;`!T!;@!````A<`/A*8!```/MD5, +MB(4(#```2(M$)&!(B87P"P``2(M$)&A(B87X"P``QH4)#````4C'A0`,```` +M````0;\`````@'U*``^&`P(``$R-I?`+``!$.'U,#X0_`0``1#B]8`P``'!%(BU0D8$B)4!1( +MBU0D:$B)4!Q(B40D0.M21(GZ#[;"2,'@!$B-7`1PBT0D8`D#BT0D9`E#!(M$ +M)&@)0PB+1"1L"4,,2(GOZ&';___&0`@!1(AX$$2(>!%(BQ-(B5`42(M3"$B) +M4!Q(B40D0$B)[^@YV___QD`(`TR)8!!$B'@828G%2(L0_H*P"0``#[:RL`D` +M`(GQ2(M$)$!(*=!(@^A02,'X`TB_S`$2(U$!'"Z`````(,X`'42@W@$`'4, +M@W@(`'4&@W@,`'0%N@$```"%TG0R1(GY#[;!2,'@!$B-7`1P2(GOZ`[:___& +M0`@!1(AX$$2(>!%(BQ-(B5`42(M3"$B)4!Q!_\=$.'U*#X=O____N`````"# +M?"10`'45@WPD5`!U#H-\)%@`=0>#?"1<`'0%N`$```"%P`^$&Q4``$0/MF5, +M1(BE*`P``$B+1"102(F%$`P``$B+1"182(F%&`P``,:%*0P```!(QX4@#``` +M``````^V74M(B>_H=MG__\9`"`&(6!!$B&`12(M4)%!(B5`42(M4)%A(B5`< +M2(E$)#A(QT0D,`````!!OP````"`?4H`#X:>%```3(VE$`P``$F^S_H"MG__\9`"`%$B'@0B%@1 +M2(M4)%!(B5`42(M4)%A(B5`<2(E$)$!(BQ#^@K`)```/MK*P"0``B?%(BT0D +M*$@IT$B#Z%!(P?@#2+_-S,S,S,S,S$@/K\>(A$JP"0``2(M<)$`/MD,+B(1* +ML0D``$"(_H3=C__\9` +M"`-,B6`0B%@828G%2(E$)#!(BQ#^@K`)```/MK*P"0``B?%(BT0D0$@IT$B# +MZ%!(P?@#20^OQHB$2K`)``!!#[9%"XB$2K$)``!!B'4+28M5`/Z"L`D```^V +MLK`)``")\4B+1"0X2"G02(/H4$C!^`-)#Z_&B(1*L`D``$$/MD4+B(1*L0D` +M`$&(=0M!_\=$.'U*#X>(_O__Z1`3``!$#[:]8`P``$0XO6$,```/@OL2``!$ +M.'U+=')$B?H/ML)(P>`$2(U$!'"Z`````(,X`'49@W@$`'43@W@(`'4-@W@, +M`'0,9F9FD&9FD+H!````A=)T-T2)^0^VP4C!X`1(C5P$<$B)[^A`U___QD`( +M`42(>!!$B'@12(L32(E0%$B+4PA(B5`<9F:09I!!_\=$.+UA#```#X-X____ +MZ6X2``"`?4P'#X;3"0``2(U\)&#HU]7__\9$)"<`0;\`````@'U*``^&H0`` +M`&:01#A]2P^$B````$2)^P^VPTC!X`1(`>A(C9#P"@``N0````"#N/`*```` +M=1:#>@0`=1"#>@@`=0J#>@P`9F9FD'0%N0$```"%R71'1(GX#[;02,'B!$@! +MZDB-BO`*``"+1"1@"X+P"@``B40D8(M$)&0+002)1"1DBT0D:`M!"(E$)&B+ +M1"1L"T$,B40D;/Y$)"=!_\=$.'U*#X=A____#[94)"%``P```````!(B>_H[]7__\9`"`*(6!"(6!%(BU0D8$B)4!1(BU0D:$B) +M4!Q)B<1(B>_HR-7__\9`"`9(B40D*$F+%"3^@K`)```/MK*P"0``B?%(BT0D +M*$@IT$B#Z%!(P?@#2;[-S,S,S,S,S$D/K\:(A$JP"0``00^V1"0+B(1*L0D` +M`$&(="0+@'U*`@^'20(``$B-G?`+``!(B>_H7-7__\9`"`5(B5@0QD`@`$F) +MQ4B+3"0H2(L1_H*P"0``#[:RL`D``(GQ2"G02(/H4$C!^`-)#Z_&B(1*L`D` +M`$B+7"0H#[9#"XB$2K$)``!`B',+0;\`````@'U*``^&7Q```$0X?4L/A+X! +M``!!#[9%(`^VT$:(?"H8_\!!B$4@1(GX#[;P2,'F!$B-!"Y(C8AP"P``BY!P +M"P``]]*)5"10BT$$]]")1"14BT$(]]")1"18BT$,]]")1"1<2(U,-'`C5"1@ +MB1&+1"1D(T0D5(E!!(M$)&@C1"18B4$(BT0D;"-$)%R)00RX`````(,Y`'42 +M@WD$`'4,@WD(`'4&@WD,`'0%N`$```"%P'1K1(GZ#[;"2,'@!$B-7`1P2(GO +MZ#O4___&0`@!1(AX$$2(>!%(BQ-(B5`42(M3"$B)4!Q)BU4`_H*P"0``#[:R +ML`D``(GQ2"G02(/H4$C!^`-)#Z_&B(1*L`D``$$/MD4+B(1*L0D``$&(=0M$ +MB?D/ML%(P>`$2(V$*/`*``"Z`````(,X`'42@W@$`'4,@W@(`'4&@W@,`'0% +MN@$```"%TF:0='I$B?@/MMA(B=A(P>`$2(V<*/`*``!(B>_HD=/__\9`"`)$ +MB'@01(AX$4B+$TB)4!1(BU,(2(E0'$F)Q$B+$/Z"L`D```^VLK`)``")\4B+ +M1"0H2"G02(/H4$C!^`-)#Z_&B(1*L`D``$$/MD0D"XB$2K$)``!!B'0D"T'_ +MQT0X?4H/ARO^___IA0X``$&_`````(!]2@`/AG4.``!(C97P"P``2(E4)!A) +MOLW,S,S,S,S,1#A]2P^$"0(``$2)^0^V\4C!Y@1(C00N2(V(<`L``(N0<`L` +M`/?2B50D4(M!!/?0B40D5(M!"/?0B40D6(M!#/?0B40D7$B-7#1P(U0D8(D3 +MBT0D9"-$)%2)0P2+1"1H(T0D6(E#"(M$)&PC1"1!!$B'@12(L32(E0%$B+4PA(B5`<28M5`/Z"L`D` +M``^VLK`)``")\4@IT$B#Z%!(P?@#20^OQHB$2K`)``!!#[9%"XB$2K$)``!! +MB'4+1(GY#[;!2,'@!$B-A"CP"@``N@````"#.`!U$H-X!`!U#(-X"`!U!H-X +M#`!T!;H!````A=)T>D2)^`^VV$B)V$C!X`1(C9PH\`H``$B)[^A&T?__QD`( +M`D2(>!!$B'@12(L32(E0%$B+4PA(B5`<28G$2(L0_H*P"0``#[:RL`D``(GQ +M2(M$)"A(*=!(@^A02,'X`TD/K\:(A$JP"0``00^V1"0+B(1*L0D``$&(="0+ +M0?_'1#A]2@^'X/W__^DZ#```#[9=2TB)[^C+T/__QD`(`8A8$(A8$4B+5"1@ +M2(E0%$B+5"1H2(E0'$B)1"0X#[9=2TB)[^B>T/__QD`(`HA8$(A8$4B+5"1@ +M2(E0%$B+5"1H2(E0'$F)Q$B)[^AWT/__QD`(!DB)1"0H28L,)/Z!L`D```^V +MN;`)``")_DB+1"0H2"G(2(/H4$C!^`-(NLW,S,S,S,S,2`^OPHB$<;`)``!! +M#[9$)`N(A'&Q"0``08A\)`M!OP````"`?4H`#X9W"P``9F9FD$0X?4L/A,8" +M``!$B?H/ML)(P>`$2`'H2(V0\`H``+D`````@[CP"@```'46@WH$`'40@WH( +M`'4*@WH,`&9F9I!T!;D!````A_HC\___\9`"`%$B'@01(AP$4F+ +ME"3P"@``2(E0%$B+3"002(M1"$B)4!Q(B40D0`^V74M(B>_H6<___\9`"`2( +M6"!$B'`A28N4)/`*``!(B5`02(M<)!!(BU,(2(E0&$F)Q4B+$/Z"L`D```^V +MLK`)``")\4B+1"0X2"G02(/H4$C!^`-(O\W,S,S,S,S,2`^OQXB$2K`)``!! +M#[9%"XB$2K$)``!!B'4+28M5`/Z"L`D```^VLK`)``")\4B+1"1`2"G02(/H +M4$C!^`-(#Z_'B(1*L`D``$$/MD4+B(1*L0D``$&(=0M(BT0D*$B+$/Z"L`D` +M``^VLK`)``")\4R)Z$@IT$B#Z%!(P?@#2`^OQXB$2K`)``!(BUPD*`^V0PN( +MA$JQ"0``0(AS"P^V74M(B>_H7<[__\9`"`2(6"!$B'@A28N4)/`*``!(B5`0 +M2(M\)!!(BU<(2(E0&$F)Q4B+$/Z"L`D```^VLK`)``")\4B+1"0X2"G02(/H +M4$C!^`-(N\W,S,S,S,S,2`^OPXB$2K`)``!!#[9%"XB$2K$)``!!B'4+2(M\ +M)"A(BQ?^@K`)```/MK*P"0``B?%,B>A(*=!(@^A02,'X`T@/K\.(A$JP"0`` +M#[9'"XB$2K$)``!`B'<+2(GOZ*C-___&0`@"1(AX$$2(>!%)BY0D\`H``$B) +M4!1(BTPD$$B+40A(B5`<28G$2(L0_H*P"0``#[:RL`D``(GQ2(M$)"A(*=!( +M@^A02,'X`T@/K\.(A$JP"0``00^V1"0+B(1*L0D``$&(="0+D$'_QT0X?4H/ +MAR/]___ID0@```^V14PZ14L/A:@```!!OP````"`?4H`#X9T"```D$0X?4MT +M?T2)^P^VPTC!X`1(`>A(C9#P"@``N0````"#N/`*````=1B#>@0`=1*#>@@` +M=0R#>@P`=`MF9I!F9I"Y`0```(7)=#Q$B?@/MMA(P>,$2`'K3(VC\`H``$B) +M[^BKS/__QD`(`D2(>!!$B'@12(N3\`H``$B)4!1)BU0D"$B)4!Q!_\=$.'U* +M#X=N____Z=P'``!(C7PD8.A/R___2(GOZ&?,___&0`@&2(E$)"A!OP````"` +M?4H`#X8;`0``1#A]2P^$!`$``$2)^@^VPDC!X`1(`>A(C9#P"@``N0````"# +MN/`*````=12#>@0`=0Z#>@@`=0B#>@P`9I!T!;D!````A`$3(TD*$F-G"3P"@``BT0D8$$+A"3P"@``B40D8(M$)&0+0P2)1"1D +MBT0D:`M#"(E$)&B+1"1L"T,,B40D;$0X?4QT=$B)[^BLR___QD`(`D2(>!!$ +MB'@128N4)/`*``!(B5`42(M3"$B)4!Q)B<1(BPC^@;`)```/MKFP"0``B?Y( +MBT0D*$@IR$B#Z%!(P?@#2+K-S,S,S,S,S$@/K\*(A'&P"0``00^V1"0+B(1Q +ML0D``$&(?"0+0?_'1#A]2@^'Y?[__P^V74M(B>_H)\O__\9`"`*(6!"(6!%( +MBU0D8$B)4!1(BU0D:$B)4!Q)B<1(BPC^@;`)```/MKFP"0``B?Y(BT0D*$@I +MR$B#Z%!(P?@#2+K-S,S,S,S,S$@/K\*(A'&P"0``00^V1"0+B(1QL0D``$&( +M?"0+2`^V=4Q(B?=(B?!(P>`$2(VT*'`+``"+!O?0B40D4(M6!/?2B50D5(M. +M"/?1B4PD6(MV#/?61(M,)&!$(<$2(V\+W`+``!$(P]$B4PD8$0C1P1$B40D9"-7"(E4 +M)&@C1PR)1"1LN`````!%A%``P```````!!OP````"`?4H`#X;+`0``3(VU\`L``$F\S`$2(UA(C;AP"P`` +MB[!P"P``]]:),XM/!/?1B4L$BU<(]]*)4PB+1PSWT(E##"-T)&"),R-,)&2) +M2P0C5"1HB5,((T0D;(E##$B)[^CHR/__QD`(`TR)!%(BQ-( +MB5`42(M3"$B)4!Q)BU4`_H*P"0``#[:RL`D``(GQ2"G02(/H4$C!^`-)#Z_$ +MB(1*L`D``$$/MD4+B(1*L0D``$&(=0M!_\=$.'U*#X=+_O__N`````"#?"10 +M`'45@WPD5`!U#H-\)%@`=0>#?"1<`'0%N`$```"%P`^$,`,```^V74M(B>_H +MP`$2(UT!'!(`>A(C8CP"@``BU0D4".0\`H``(D6BT0D5"-!!(E& +M!(M$)%@C00B)1@B+1"1<(T$,B48,N`````"#/@!U$H-^!`!U#(-^"`!U!H-^ +M#`!T!;@!````A<`/A%8"``!$#[9E3$2)^P^VPTC!X`1(C5P$<$B)[^CDQO__ +MQD`(`42(>!!$B&`12(L32(E0%$B+4PA(B5`<2(E$)$!(@WPD,`!T2TB+$/Z" +ML`D```^VLK`)``")\4B+1"0P2"G02(/H4$C!^`-(O\W,S,S,S,S,2`^OQXB$ +M2K`)``!(BUPD0`^V0PN(A$JQ"0``0(AS"T0/MF5+#[9]3$"(?"0/1(GX1`^V +M\$G!Y@1*C5PT<$B)[^A+QO__QD`(!$2(8"`/ME0D#XA0(4B+$TB)4!!(BU,( +M2(E0&$F)Q4B)1"0P2(L0_H*P"0``#[:RL`D``(GQ2(M$)#A(*=!(@^A02,'X +M`TB[S"%)BQ0D2(E0$$F+5"0(2(E0&$F)Q4B+$/Z"L`D```^VLK`) +M``")\4B+1"0X2"G02(/H4$C!^`-(N\W,S,S,S,S,2`^OPXB$2K`)``!!#[9% +M"XB$2K$)``!!B'4+2(M\)"A(BQ?^@K`)```/MK*P"0``B?%,B>A(*=!(@^A0 +M2,'X`T@/K\.(A$JP"0``#[9'"XB$2K$)``!`B'<+0?_'1#A]2@^''?W__TB) +M[DB+?"1(Z,#:__^X`````$B!Q'@!``!;74%<05U!7D%?PV9FD&9FD&9FD$%7 +M059!54%455-(@^P828G]@[_<60```P^'$@$``$B-AV!9``!(.8=@60``#X3^ +M````28G'3(NW8%D``$B-AU!9``!(B40D$$R)?"0(9F:03(GS38LV2(M3"$F) +M5@A,B3)(B1M(B5L(2(M#./9``01U?DF)W+T`````@'M*`'8?B>@/MOA(P><$ +M2HV\)_`*``#HNL+____%03AL)$IWX4F+A5!9``!(B5@(2(D#2(M$)!!(B4,( +M28F=4%D``$B+0SA(@WA(`'182(M04$B+<$A,B>_H`````$B+0SA(QT!(```` +M`$'_C>!9``#K,V9FD$B)WDR)[^CEV___A4H`=D(/ML-(P>`$3`'`2(V0 +M\`H``+X`````@[CP"@```'42@WH$`'4,@WH(`'4&@WH,`'0%O@$```"%]G4; +M_\-!.%A*=[ZX`````(7`=!.X`0```.FX````N`$```!FD.OI2(L)23G*=89) +MBXEP60``28V!<%D``$@YR`^$BP```$F)P4B-0?!(.7@X=7)(B<:[`````(!X +M2@!V2&9F9I`/ML-(P>`$2`'P2(V0\`H``$&X`````(.X\`H```!U$H-Z!`!U +M#(-Z"`!U!H-Z#`!T!D&X`0```$6%P'47_\,X7DIWO+@`````A_HI+___TB+_H`````$B+`TB# +M>#``=!M(C5`P2,?&`````$B)[^@`````ZUQF9I!F9I!(@[WH60```'0H2(V% +M4%D``$@YA5!9``!T&$B-E>A9``!(Q\8`````2(GOZ`````#K)(&]V%D``/\` +M``!W&$B-A5!9``!(.85060``=0A(B>_H`````$B#Q`A;7<-F9I!!5T%6055! +M5%532('L6`$``$B)="0X28G4B4PD-$R+1D!)BP!(B40D"`^V4'C_RHE4)!Q! +M#[=`$&:)1"0R28N0D````$B)5"0H10^VL(H```!!#[:`BP```(E$)!A%#[>X +MF@```$$/MYB8````28-X*`!T#69!#[9`((/@`3G(=3*Z`````$F#>#``#X0F +M`@``3(UL)$"+3"0T3(GJ3(G&0?]0,+H`````A<`/A`8"``#K!$V+:"B]```` +M`$B+5"0X2(L"#[9``XE$)!2Y``````^WPT@#1"0H2(E$)"!$.W0D%`^%$@$` +M`$B%R715BT0D("G(B)P\'C"69F9I!!#[=5"(72N````0`/1-")T"GH.=AR+8GH20-%`$F) +M!"1F08E<)`AF0<=$)`H``$F#Q!`!W3G5=3V]`````$F#Q1#K,HGH20-%`$F) +M!"2)T&8IZ&9!B40D"&9!QT0D"@``28/$$(G0*>@IPTF#Q1"]`````.N*00^W +MST@#3"0@2(M4)#A(#[="$$@#0@A(.<@/A,0```#K2&9!B5PD"$F#Q!#I3/__ +M_P'=ZS5!#[??P>,)00^W50B%TK@```$`#T30B=`IZ#G8=]Z)T"GH*<-)@\40 +MO0````#KV&9FD&9FD&9$*7PD,G1RNP````!!_\9$.W0D&`^4P`^VP$$!QDB+ +M5"0(#[9">$0Y\'4JBT0D&/_(@WPD&``/1$0D'(E$)!B%P`^4P$0/MO!(#[>" +MD````$@!1"0H2(M$)`A$#[>XD````&9$.WPD,@^&,O[__T0/MWPD,NDG_O__ +M9D''1"3Z`("Z`0```(G02('$6`$``%M=05Q!74%>05_#9F:09I!(@^P82(E< +M)`A(B6PD$$B)_4B+7D"`?B$!=`R$#=`3&0R$+2(G>2(GO_U,X2(M<)`A(BVPD$$B#Q!C#9F9FD&9F9I!F9I!F +M9I!!5T%6055!5%532(/L&$B)?"0028GU2(L&2(E$)`CV1B`$#X3H`0``0;X` +M````@+Z```````^$8@$``$ECQDV+1,5800^VJ&`,``!!.*AA#```#X(Q`0`` +M03AH2P^$&`$``(GJ#[;"2(G"2,'B!$Z-E`+P"@``00^WE(!`#```00^WO(!" +M#```NP````!!NR````!!O`$```!F9F:09F:0@_H?=S\/ML-)C32"1(G9*=$Y +M^0]'SX/Y('4(QP;_____ZPU$B>#3X/_(B='3X`D&1(G8*=`Y^',5C7P7X+H` +M````ZP.#ZB#_PX#[`W:RB>L/ML-(B<)(P>($3HV4`G`+``!!#[>4@$`,``!! +M#[>\@$(,``"[`````$&[(````$&\`0```(/Z'W=&#[;#28TT@D2)V2G1.?D/ +M1\^#^2!U",<&_____^L-1(G@T^#_R(G1T^`)!D2)V"G0.?AS'(U\%^"Z```` +M`.L*9F9FD&9FD(/J(/_#@/L#=JO_Q4$XJ&$,```/@\_^__]!_\9!#[:%@``` +M`$0Y\`^/GO[__TB+7"00@[M(60````^$B0,``$&^`````$&`O8``````=#]( +MB=I(@<)@60``26/&38M$Q5A)QX`P#````````$B+0@A,B4((28D028E`"$R) +M`$'_QD$/MH6`````1#GP?\M,B>Y(BWPD$.BU^?__Z5H#``#V1B`"#X0>`P`` +M2(M$)!!(!?!9``!(B00D3(M\)!!)@<@0`=0R#>@@`=0:#>@P`=`6^`0```(7V=`>X`0```.L,_\$X3TIWN+@` +M````A<`/A5\"``!!#[:H8`P``$$XJ&$,``!R;$$X:$MT6XGI#[;19D&#/%<` +M=25)#[>$D$`,``!)`T!`2(L<)$B)!--!#[>$D$(,``!F08D$5^LIB>@/MM!! +M#[>$D$`,``!F00-`0&9!`X200@P``$B+#"1F*P319D&)!%?_Q4$XJ&$,``!S +ME$'_QD$/MH6`````1#GP#X\#____28MU4$B+?"00Z#BX__]!O@````!!@+V` +M``````^$]@```$B+3"002('!4%D``$ECQDV+1,58187V=6I)BT!`28F%D``` +M`$$/MH!@#```08B%B@```$$/MD!+08B%BP```$D/MH!@#```00^WA(!`#``` +M9D&)A9@```!)#[:`8`P``$$/MX2`0@P``&9!B86:````0<:%B`````!!QH6) +M`````.M-28M00$D[E9````!V0$B+7"0(#[>#D````/?82)A((<))(X60```` +M2#G"=2%)#[:08`P``$$/MX6:````9D$#A)!"#```9D&)A9H```!(BT$(3(E! +M"$F)"$F)0`A,B0!!_\9!#[:%@````$0Y\`^/%O___TB+1"002(.XZ%D```!T +M&4B)PDB!PNA9``!(Q\8`````2(G'Z`````"]`````$B+5"0(@'IX``^&K``` +M`(GI1`^VX69#@SQG`'1=2(M$)`A*BYS@H````$B+?"00Z`````!(B<9!_H6( +M````QD`2($,/MP1G9HE&$$B+%"1*BP3B2(E&"(!.(`)(QT8P`````$C'1C@` +M````2(D>3(EN0$B+?"00_U-H_\5(BTPD"$`X:7AWB.LR0;X`````08"]@``` +M``!T(DECQDF+=,582(M\)!#HQL___T'_QD$/MH6`````1#GP?]Y(@\086UU! +M7$%=05Y!7\-F9F:09F:005=!5D%505154TB#[%A(B7PD2$F)]TB)5"1`2(L& +M2(E$)#B^``````^WD)````!F@?J!`+B`````#T/09HE4)"!!]D<@('1$#[?* +M2(M<)$!(BU,02(MT)#CHDKG__TB)QKC_____2(7V#X2C`P``0<:'@`````%) +MB7=83(F^,`P``+@`````Z88#``!(BT0D0$@/ME`B2(G!2(L`2(G3N@````!( +M]_-!B=9(BT0D.$@/ME!X2(M!"$B)T;H`````2/?Q2(M<)$`/MD,B*-"(1"0? +M03C&08#>_TB+1"0X#[>0D````(U"_P^W2Q@AP4&)U&9!*``````$'&AX$`````QT0D&`$````/MT0D(/?82)A(B40D$`^WP4F) +MQ4B+5"1`3`-J$$B+3"1(2('!8%D``$B)3"0(2(M<)$A(@<-060``2(D<)(M$ +M)"#_R$0AZ(M<)"!F*<-F1#GC00]'W$B+;"003"'M@WPD&``/A'0!``#'1"08 +M`````(M4)"!(BT0D.&8YD)````!V++H`````00^VAX````")P8/X`'X82&/" +M28MTQUA(.6Y`#X0T`0``_\(YT7_H#[=,)"!(B>I(BW0D.$B+?"1(Z!&X__]( +MB<9(A<`/A=T```!!_H^`````08"_@````/\/A+X```!,BU0D"$R+#"1)#[:' +M@````$F+=,=82,>&,`P```````!)B?"Y`````(!^2@!V1)`/ML%(P>`$3`'` +M2(V0\`H``+\`````@[CP"@```'43@WH$`'4-@WH(`'4'@WH,`)!T!;\!```` +MA?]U)?_!03A(2G>]N`````"%P'0;28M""$F)<@A,B19(B48(2(DPZQFX`0`` +M`.OA28M!"$F)<0A,B0Y(B48(2(DP0?Z/@````$&`OX````#_#X5+____N/__ +M___I2@$``$$/MH>`````#[;028ETUUC_P$&(AX````!,B;XP#```QH9@#``` +M",:&80P```!$B?$/MM%$B>AF*>AFB8260`P``&:)G)9"#```1#BV8`P``'8' +M1(BV8`P``$0XMF$,``!S!T2(MF$,``!(BT0D0&8I6"!F02G<=!,/M\-)`<7' +M1"08`0```.D#_O__2(M4)$!F@WH@``^$J0```+D`````0?_&1#IT)!\/E,!! +M`<9(BUPD.$0X"D````$B+7"1`2`%#$,=$)!@!````ZQZ+5"0@2(M$)#AF +M.9"0````N`$````/1D0D&(E$)!A(BUPD0$0/MV,@2(M$)#AF1#N@D`````^& +M)_W__T0/MZ"0````Z1K]__^X`````$B#Q%A;74%<05U!7D%?PV9F9I!F9F:0 +M9F9FD&9FD$B#[`B%TG08QD8A"TB)\DC'Q@````#H`````.L(9F:0Z"OV__]( +M@\0(PV9FD&9FD$%455-(@^PP28G\2(GU2(L>]D,!!'49QD8A`DB+=CA(B>KH +M`````.ED`@``9F9FD$B#>U@`=2F^!P```&9F9I#H2Z[__TB)QTB)0UBZ`!`` +M`+X`````Z`````!F9I!FD`^V12"H(`^%U````*@&=1C&12$!2(MU.$B)ZDR) +MY^@`````Z0@"``#V12`$="=(@WM(`'0@2(M34$B+?H`````$C'0T@` +M````0?^,).!9``!(BWT(2(E\)!@/MT409HE$)"`/MD-X_\B(1"0B#[9+>DB) +M^$C3Z$B)!"1(#[9T)"*Z`````$CW]DB)1"0(#[9+>DC3X$B)1"00#[>3D``` +M``^V3"0B2`^W1"0@2`'X2`^O="002"GP#Z_12(U$$/](B=&Z`````$CW\4@/ +MMY.0````#Z_0ZSAF9F:0]H.2`````708QD4A!DB+=3A(B>I,B>?H`````.DO +M`0``#[>3D````(G02`^O10A(B40D$(G12(M4)!!(`=%(B=Y,B>?HM[#__TB) +M15!(A4```!F9I!FD$B)XDB)[DR) +MY^CB^?__A<`/A(H```!(BW503(GGZ/ZO__]!BXPDN$0``$$YC"2\1```=$9( +M8\%(P>`$2H&\()@B````````=''_P4ACP4AIP/$`#_!(P>@@C00!B<;!_@F) +MR)F)\"G0:<`B`@``*<%!.8PDO$0``'6Z2,=%4`````!)C;PDZ%D``$B)[N@` +M````3(GGZ`````#K1&9F9I#V12`$="E(Q\(`````2(GN3(GGZ/BS___K)L9% +M(05(BW4X2(GJ3(GGZ`````#K$4B)[DR)Y^B6\___9F:09F:02(/$,%M=05S# +M9F9FD&9FD%532(/L"$B)_4B)\TB#?E@`=%%(B??H`````+D`````2&/12(M# +M6$B+!-!(A%D``(L%`````,'@#(G"N*NJJJI(#Z_"2,'H($&) +MQ$'![`]$B>*^:`P``.A$J___B<5!C50D(+X@````2(G?Z#"K__\!Q8L5```` +M`,'B#,'J#KZ(````2(G?Z!6K__\!Q;H(````O@`0``!(B=_H`:O__P'%2(G? +MZ`````!(B04`````_\4[+0````!S-V9FD&9FD$B)W^@`````2(G"2(7`="%( +MBX/060``2(D"2(F3T%D``/^#V%D``/_%.RT`````_U-P9F:0@*.2````'^G4````9F9FD`^V@Y(` +M``!FB9.4````_DMY2,>#F`````````"#R`6(@Y(```"$P'D.@^!_B(.2```` +MZ9D```"`HY(```"?2(G>Z`````!(B<)(AP@`=`M(BUL( +M2(-["`!U]>@`````B4-\2(G?Z`````!(@\0(6UW#9F:09F:09F:0N@````#_ +MSH/^_W039F9FD`^V!P'"2/_'_\Z#_O]U\0^VPL-F9F:09F:09F:09F:055-( +M@^P(2(G[@#\#=EN]`````(!_>`!T1V9F9I!F9I!(8_5(@[SSH`````!T*$B+ +MC/.@````#[93`8/B`0^V00&#X/X)T(A!`4B+O/.@````Z`````#_Q0^V0W@Y +MZ'_`@*.2````^^L'Z!(```!FD$B#Q`A;7<-F9I!F9I!F9I!!54%455-(@>P( +M`@``28G\0;T`````2(GE@']X``^$6`(``$B+7PA(A=MT#DB#>P@`=`=)B=U( +MBUL(N@`"``"^`````$B)[^@`````QT4`\Q9X6K@`````2(7;=`.+0WR)101! +M@+PD@`````!T$(!-"0)!#[:$)(,```"(10I!#[94)'R^`0```"'6#[:%DP`` +M`(/@_(G1@^$""?`)R+X$````(=:#X/.)T8/A"`GP"HA%$_:#D@````)T +M!(!-%`$/MX.4````9HE%%DB+@Y@```")11B+@YP```")A9@```!(C;/@```` +M2(U]++H0````Z`````!(C;/P````2(U]/+H$````Z`````!(C;,T`0``2(V] +M@````+H0````Z`````!(C;/T````2(U]0+I`````Z`````!-A>UT8TF+11B) +M11Q!BT4(A%(4$/MD0D`XA%(D$/MD5ZB$4C +M0?:%D@````)T!(!-)`%!#[>%E````&:)129)BX68````B44H08N%G````(F% +MH````$B%VW4(00^V!"2(11"^D````$B)[^@`````]]B(10B^``(``$B)[^@` +M````]]B(A9````!!B[0DD````(/N"DF-?"1X2(GINC````#H`````$B!Q`@" +M``!;74%<05W#9F9FD&9FD$B)^(`_`W8XN@````"`?W@`=!@/MD]X2&/"2(.\ +MQZ``````=0S_PCG1?^RX`````,-(B[S'H````.@`````9I#SPV9F9I!F9F:0 +M9F:09F:055-(B?N`/P-V-KT`````@']X`'0O2&/%2(.\PZ``````=`U(B[S# +MH````.@`````_\4/MD-X.>A_V^L(9F9FD(!G`?Y;7<-F9I!F9I!F9I!(BT\0 +MN@````!F9F:09F:0B=!(.3S!=0E(QP3!`````,/_PH/Z!W;H\\-F9I!F9I!( +MB?>`9@'[Z`````#SPV:0055!5%532('L"`0``$F)_$B-G"0``@``2(G]#[9' +M`:@$#X0O`0``@#\"#X8F`0``@^#]B$!(BZV@````08`\)`AU<$B%[70,9D&#O"24`````75?2(G% +M0;T!````00^V1"1X@_@!?FM)8\5)B[S$H````$B#QWA(B>FZ(````+X````` +MZ`````"Y`````)!(8]&+!),S1)4`B023_\&#^7]^[$'_Q4$/MD0D>$0YZ'^W +MZR"`?0`##X5X____2(U]>$B)V;H@````O@````#H`````&:!N_X!``!5JG57 +M@[O*`0```'0=@7L&3$E,3W0,@;MV`0``1U)50G4(08!,)`$"ZS%!O0````!) +M8\5(P>`$2`'8@+B^`0``@'4/@[C*`0```'0&08!,)`$"0?_%08/]`W[52('$ +M"`0``%M=05Q!7<-F9F:09F9FD&9F9I!$BX>4(@``18U(`4ECP4AIP/$`#_!( +MP>@@08T$`<'X"42)R<'Y'RG(:<`B`@``02G!36/`2<'@!$F)=#AP2&.'E"(` +M`$C!X`1(B50X>$2)CY0B``##9F9FD&9F9I!F9I!32(/L$$B)^XN'D"(``#N' +ME"(``'1BBXN0(@``2&/!2,'@!$@!V$R+0'!,B00D2(MP>$B)="0(_\%(8\%( +M:<#Q``_P2,'H((T$`8G'P?\)B`$28FT.)@B``!(8X>\ +M1```2,'@!$B)E#B@(@``1(F/O$0``,-F9I!FD%-(@^P02(G[BX>X1```.X>\ +M1```#X2#````9F:09F:0BXNX1```2&/!2,'@!$B-A!B0(@``2(M0"$B)%"1( +MBT`02(E$)`C_P4ACP4AIP/$`#_!(P>@@C00!B<;!_@F)R)F)\"G0:<`B`@`` +M*<&)B[A$``"#N]Q9````=`A(B=_H`````$B+="0(2(G?_Q0DBX.X1```.X.\ +M1```=8-(@\006\-F9F:09F:09F:09F:04[@`````2(-_:`!T($B+7VA(BP-( +MB4=HNJ````"^`````$B)W^@`````2(G86\.02(M':$B)!DB)=VC#9F9FD$B# +M/P!T&DB+!TB+0$A(B49(2(L'2(EP2.L*9F:09F:02(EV2$B)-\-F9F:09F9F +MD$B#["A(B5PD"$B);"003(ED)!A,B6PD($F)_4B)]4B#/@!T/4R+)DB+10!( +MBUA(2#G8=0Q(QT4``````.L.9I!(BU4`2(M#2$B)0DA(B=Y,B>__4U!,.>-T +M!TB#?0``=<9(BUPD"$B+;"003(MD)!A,BVPD($B#Q"C#9F:09F:02(/L"(`_ +M"'4'Z`````!FD$B#Q`C#9F9FD&9F9I!F9I!(@^P(2(GQ2(M'$(`_"'4'Z``` +M``#K"TB)UDB)QV9FD/_12(/$",-F9I!F9I!F9I!(@^QH2(E<)#A(B6PD0$R) +M9"1(3(EL)%!,B70D6$R)?"1@28GT28G/08G52(MO,$0/MC=!#[;>B=Y(B>_H +M`````+H`````B=Y(B>_H`````,<$)`````!!N0````!!N`````"Y`````+H# +M````B=Y(B>_H`````+H`````A<`/A+T```!!]\0```#P#Y7`#[;(08#],`^4 +MP$0/MM!!_\)!#[;V00^VQ87)=!%!@/T@NC0```"X)`````]%PHE$)#"X0``` +M`(7)=0E$B>#!Z!B#R$")1"0H3(G@2,'H$`^W^$`/ML>)1"0@3(G@2,'H"`^V +MP(E$)!A!#[;4#[?"A_H`````(G#00^V]DB)[^@`````B=J)T$B+7"0X2(ML +M)$!,BV0D2$R+;"103(MT)%A,BWPD8$B#Q&C#9F9FD&9FD&9FD(GX@^`#P>`- +M!0`@``!`]L<$=`T%```#`,-F9F:09F:0!0```@##9F9FD&9FD&9FD$%455-) +MB?R)];\@H0<`Z`````"[(*$'`$`/MOWHK____XVH'`$``$F+?"00B>[H```` +M`(3`>`FX`0```.L?9I"_$"<``.@`````@<,0)P``@?L_2TP`=L^X`````%M= +M05S#9F9FD&9F9I!F9I!F9I!(@^P82(E<)`A,B60D$$F)_$`/MO[H1O___XG# +MC7,(28M\)!"Z`````.@`````C7,,28M\)!"Z&`$``.@`````2(M<)`A,BV0D +M$$B#Q!C#D%-(B?M`#[;^Z`/___^-<`Q(BWL0N@````#H`````%O#28G1N@`` +M``!,C4<*BT$0B0>+012)1P2#.0"X`0````]$T$$/MD$$`<`)PF:)5PB+AD0" +M``"%P`^4PH/X`@^4P`G0J`$/A&8!``"#>00!#X7<````9@^V00^`S!%F08D` +M28/``F8/MD$.@,P19D&)`$F#P`)!#[9!!,'@`V8E^`"`S!)F08D`28/``F8/ +MMD$+@,P39D&)`$F#P`)F#[9!"(#,$V9!B0!)@\`"9@^V00R`S!1F08D`28/` +M`F8/MD$)@,P49D&)`$F#P`)F#[9!#8#,%69!B0!)@\`"9@^V00J`S!5F08D` +M28/``F9!QP!`%DF#P`*#.0!U&8.^1`(```*Z)@```+A@````#T7"Z:`!``"# +MOD0"```"NC8```"X80````]%PNF'`0``9F9FD&8/MD$.@,P19D&)`$F#P`)! +M#[9!!,'@`V8E^`"`S!)F08D`28/``F8/MD$(@,P39D&)`$F#P`)F#[9!"8#, +M%&9!B0!)@\`"9@^V00J`S!5F08D`28/``HM!""4````/P>@89@U`%F9!B0!) +M@\`"@SD!&<"#X/N#Z#3I!0$``&:0@WD$`0^%EP```&8/MD$/@,P29D&)`$F# +MP`)F#[9!#H#,$F9!B0!)@\`"9@^V00N`S!-F08D`28/``F8/MD$(@,P39D&) +M`$F#P`)F#[9!#(#,%&9!B0!)@\`"9@^V00F`S!1F08D`28/``F8/MD$-@,P5 +M9D&)`$F#P`)F#[9!"H#,%69!B0!)@\`"9D''`$`628/``H,Y`1G`@^#P@\`U +MZV)F#[9!#H#,$F9!B0!)@\`"9@^V00B`S!-F08D`28/``F8/MD$)@,P49D&) +M`$F#P`)F#[9!"H#,%69!B0!)@\`"BT$()0````_!Z!AF#4`69D&)`$F#P`*# +M.0$9P(/@_H/H-F8/ML!F#0"79D&)`,-(@^Q(2(E<)!A(B6PD($R)9"0H3(EL +M)#!,B70D.$R)?"1`B?")5"042(G-3(MG$`^VP$B+1,?H`````&8/ML!FB44$ +M18V]$`$``$2)_DR)Y^@`````9@^VP&:)109%C;44`0``1(GV3(GGZ`````!F +M#[;`9HE%"(-\)!0!=6JZ@````(MT)!!,B>?H`````(MT)`Q,B>?H`````,'@ +M"&8)10*)WDR)Y^@`````P>`(9@E%!$2)_DR)Y^@`````P>`(9@E%!D2)]DR) +MY^@`````P>`(9@E%"+H`````BW0D$$R)Y^@`````08VU&`$``$R)Y^@````` +MB$4*08VU'`$``$R)Y^@`````B$4+2(M<)!A(BVPD($R+9"0H3(ML)#!,BW0D +M.$R+?"1`2(/$2,-F9F:09F:02(/L:$B)7"0X2(EL)$!,B60D2$R);"103(ET +M)%A,B7PD8$F)_XGS9HE4)!X/ML-,BW3',$&+=CR#QC!(BW\0Z`````!(B<6# +MY1](C42M`$C!X`1*C:PP4`(``(-]``%T74B-12!(B40D$$R-9"0@BU`$1`^V +MZTR)X42)[DR)_^CL_?__0?Z.90P``$B+7"002(M+($F+?C!,B20D0;D````` +M1`^W1"0>N@$```!$B>[_4QA(B>Y,B??H(A,``$B+7"0X2(ML)$!,BV0D2$R+ +M;"103(MT)%A,BWPD8$B#Q&C#9F9FD&9F9I!F9F:09F:02(/L:$B)7"0X2(EL +M)$!,B60D2$R);"103(ET)%A,B7PD8$F)_T&)]<=$)!0`````B?$/ML%(BVS' +M,$&^``````^W`F:)1"082(U,)!@/MT("9HE!`HM"!(E!!`^W1"082(G#@^,? +M2(T$FTC!X`1(C9PH4`(```^W00*$P'0JQT0D%`$````/MT$"1`^V\&9!@%8`P```````#'A4`"````````3(UC($B-1"08#[=``J@$=!=(C4PD($&+ +M5"0$00^V]4R)_^BQ_/__D(,[`0^$EP```/Z-90P``$B-1"081(M(!$F+3"0@ +M10^V[4B+?3!(C40D($B)!"1%#[?&BU0D%$2)[D'_5"082(G>2(GOZ-<1``"# +MO6`,````=$Y(@[U0#````'1$2(N%4`P``(-X&`%U-T2)[DR)_^@L%```2(NU +M4`P``$B)[^A]%0``AQ"^+`T``.@`````2(M[$+[P!`$` +MZ`````")ZO?2(=!$">A(BWL0B<*^\`0!`.@`````2(M[$+[P!`$`Z`````!( +MBWL01(GBOBP-``#H`````$B+7"0(2(ML)!!,BV0D&$R+;"0@2(/$*,-F9F:0 +M9F9FD&9F9I!F9I!(@^Q(2(E<)!A(B6PD($R)9"0H3(EL)#!,B70D.$R)?"1` +M28G^08G,1(E,)!1(BT<02(E$)`C'1"0$`````$2-/+4`````00G71(GZ#[;" +M3(MLQS!%AY,B??H_/S____#@^,? +M1#GC=>)!@[U@#````+@!````#T5$)`2)1"0$08F=\`P``(-\)!0`#Y7"@WPD +M!``/E<`)T*@!#X3P`0``00^V_^AB]O__1(U@"$2)YDB+?"0(Z`````")Q0^W +MV(G:]])$B>9(BWPD".@`````]L,(#X0<`0``387M=!9!QX5@#````````$'' +MA4`"````````08.^D`````%T"D&#OI0````!=12^``$``$2)^=/FB?),B??H +MW_W__T&#OHP````!=!1!@[Z0`````70*08.^E`````%U#D$/MO=,B??HQ0D` +M`.M_08.^B`````%T"D&#OHP````!=6M!#[;?B=_HI/7__T2-8"BZ!````$2) +MYDB+?"0(Z`````!$B>9(BWPD".@`````OQD```#H`````+H`````1(GF2(M\ +M)`CH`````$2)YDB+?"0(Z`````"_T`<``.@`````B=Y,B??H!`@``$$/MM^) +MWDR)]^@`````A<`/A;,```")V;H`````O@$```!,B?=!_U8HZ9L```!`]L40 +M=$Y!#[;W3(GWZ,0'``!!@[Z0`````70*08.^E`````%U%[X``0``1(GYT^:Z +M`````$R)]^C)_/__00^VS[H!````O@$```!,B?=!_U8HZT%0`(```````!!#[;W3(GWZ.SY__^# +M/0`````!=0A,B>_H2Q$``$B+7"082(ML)"!,BV0D*$R+;"0P3(MT)#A,BWPD +M0$B#Q$C#9F9FD&9F9I!(@^P(28GXC0RU``````G1#[;!2(M\QS!(A?]U$P^V +M\4R)Q^BH#@``ZTMF9I!F9I!(B[=0#```2(7V=10/MO%,B!#H`````/_%@?W_````=LZ!:Q```0``ZSN]`````$&+ +M="0\@<8``0``28M$)#!(BW@0Z`````!(BU,(9HD"2(-#"`+_Q8']_P```';1 +M@6L0``$``+@!````6UU!7,-(@^Q(2(E<)"!(B6PD*$R)9"0P3(EL)#A,B70D +M0$B)_4F)]$&)U4&^`````$B-7B!(C4PD$(M3!`^V-TB+?S#HW/3__T&#_0%U +M#4&V`<>%8`P```````!(BTLH#[9U`$B+?3!(C40D$$B)!"1!N0````!!N``` +M``!$B?+_4R!,B>9(B>_H!PH``$&#_0%U$8,]``````%U"$B)[^B`#0``2(.] +M4`P````/A*,```!(B[50#```@WX8`74F2(GOZ*T-``"%P`^%A@```$B+M5`, +M``"Z`0```$B)[^@A____ZW"#O40"````=2H/MG4`2(M],.C9"@``BW4\@\8H +M2(M%,$B+>!#H`````+\!````Z``````/MG4`2(M],.@/"P``2(N=4`P``$B% +MVW0D@WL8`'4>2(U3($B)WDB)[^AN#```2(M;"$B%VW0&@WL8`'3B2(M<)"!( +MBVPD*$R+9"0P3(ML)#A,BW0D0$B#Q$C#D$%505154TB#[`A(B?M(BTY,B>?H`````*@$=#&Z`@```(GN3(GGZ`````")[DR)Y^@` +M````O]`'``#H``````^V,TB+>S#H1@(``.L108UU*+H"````3(GGZ`````#& +M@T@"````QH-D#````,:#90P```#'@^P,````````QX/P#````````,>#0`(` +M``````#'@^@,```@````N@````"02&/"B92#:`P``/_"@_H??N^Z`````$AC +MPDB-!(!(P>`$QX084`(```$```#_PH/Z'W[C2,>#4`P```````!(QX-8#``` +M`````,>#8`P```````!!C74(N@````!,B>?H`````$&-=0RZ&`$``$R)Y^@` +M````BU,@08UU$$R)Y^@`````BU,D@>(`_/__08UU%$R)Y^@`````2(M#,+H` +M````@[BD`````'0#BU,D08UU&$R)Y^@`````BU,H08UU'$R)Y^@`````2(M# +M,+H`````@[BD`````'0#BU,D08UU($R)Y^@`````BU,LL@!!C74D3(GGZ``` +M``"X`0```$B#Q`A;74%<05W#9F:09I!!5T%6055!5%532(/L.$B)^XE4)!Q! +MB<^%]@^%H@```+T`````3(UT)"!F9I!F9I!(8\5(C02`2,'@!$@!V(.X4`(` +M``!U<$B-D&`"``"#>@@!=1.+4A1,BZ"8`@``3(NHD`(``.LB2&/%2(T$@$C! +MX`1(`=B+D'0"``!,BZ"0`@``3(NHB`(```^V,TB+>S!,B?'H6/'__P^V,TB+ +M>S!,B30D0;D`````10^WQTR)X8M4)!Q!_]7_Q8/]'P^.;O___TB#Q#A;74%< +M05U!7D%?PV9F9I!F9F:09F9FD&9FD$B#["A(B5PD"$B);"003(ED)!A,B6PD +M($B)^XGUB>B#X`1!B<5!P>T"0;P#````02'L@[^(`````70)@[^,`````75: +M00^V],'F"('&#`$``(V&```#`('&```"`$6$[0]%\$B+>Q#H`````(G!@^'\ +M@\D!00^V],'F"('&#`$``(V&```#`('&```"`$6$[0]%\$B+>Q")RN@````` +M00^V],'F"('&=`$``(V&```#`('&```"`$6$[0]%\$B+>Q#H`````(G!@.$? +MB>@/MM`/MH0:M0```,'@!27@````"<&`Y>8(@<9T`0``C88```,`@<8```(`183M#T7P2(M[$(G*Z`````!(BUPD +M"$B+;"003(MD)!A,BVPD($B#Q"C#9F:09F:02(/L&$B)'"1,B60D"$R);"00 +M2(G[1`^V[D2)[^C?Z___1(U@*$2)[DB)W^C`[/__2(M[$+H$````1(GFZ``` +M``!(BWL01(GFZ`````"_&0```.@`````2(M[$+H`````1(GFZ`````!(BWL0 +M1(GFZ`````!$B>Y(B=_H0?[__T2)[DB)W^@6[/__2(L<)$R+9"0(3(ML)!!( +M@\08PV9FD$%7059!54%455-(@^P(2(G]QD0D!P!!O@`````/MD0D!T2-/(4` +M````9F9FD&9FD$.-!#Y$#[;H1(GOZ"#K__]!B<1!C5PD*$B+?1"Z`@```(G> +MZ`````!(BWT0B=[H`````$2)[DB)[^CR_O__2(M]$+H`````B=[H`````$B+ +M?1"Z'P$``$2)YN@`````08UT)`1(BWT0N@````#H`````$&-="0(2(M]$+H` +M````Z`````!!C70D#$B+?1"Z`````.@`````08UT)!!(BWT0N@````#H```` +M`$&-="042(M]$+H`````Z`````!!C70D&$B+?1"Z`````.@`````08UT)!Q( +MBWT0N@````#H`````$&-="0D2(M]$+H`````Z`````!!C70D($B+?1"Z```` +M`.@`````08UT)"Q(BWT0N@````#H`````$&-="0T2(M]$+J\````Z`````!! +M_\9!@/X##X;#_O__@'PD!P$9VV:[``"!PP```P"-Z`````#^ +M1"0'@'PD!P$/AB#^__](@\0(6UU!7$%=05Y!7\-F9F:09F9FD&9FD$B#[`A( +MBW\0NO__SP^^;`0!`.@`````2(/$",-F9F:04TB)^XM'!+``/0``@%!T(4B+ +M?Q"^+`T``.@`````@\@!2(M[$(G"OBP-``#H`````$B+>Q"^``T``.@````` +M)?__`/](BWL0B<*^``T``.@`````2(M[$+H`````O@0-``#H`````$B+>Q"Z +M`````+XX#```Z`````!(BWL0NO\``0"^!!T``.@`````2(M[$+H`````OF0= +M``#H`````$B+>Q"Z`````+XH#```Z`````!(BWL0N@````"^6!T``.@````` +M2(M[$+H`````OEP=``#H`````$B+>Q"Z`````+Y`'0``Z`````!(BWL0N@`` +M``"^1!T``.@`````2(M[$+H`````OD@=``#H`````$B+>Q"Z`````+Y0'0`` +MZ`````!;PV9FD&9FD&9FD$C'1@@`````2(N'6`P``$B)1A!(@[]8#````'0+ +M2(N'6`P``$B)<`A(B;=8#```2(._4`P```!U!TB)MU`,``#SPV9F9I!F9F:0 +M9F:09F:02(-^"`!U&DB+1A!(B8=8#```2(7`=!9(QT`(`````.L,2(M6"$B+ +M1A!(B4(02(-^$`!U'$B+1@A(B8=0#```2(7`=!A(QT`0`````.L.9I!(BU80 +M2(M&"$B)0@A(QT8(`````$C'1A``````PV9FD$B#[!A(B1PD2(EL)`A,B60D +M$$F)_$B)]4B)TX,Z`'442(UR"$B-?2"Z*````.@`````ZQI(C7((2(U](+HP +M````Z`````!!_H0D9`P``(L#B4482(GN3(GGZ.+^___'10``````0?Z$)$@" +M``!(BQPD2(ML)`A,BV0D$$B#Q!C#2(/L$$B)'"1(B6PD"$B)^TB)]8-^&`!T +M!OZ/9`P``$B)[DB)W^CF_O__BX/H#```B<$/ME4$B92+:`P``/_`B8/H#``` +MQT4``0```/Z+2`(``$B+'"1(BVPD"$B#Q!##0(#_`W810`^VSXU,"0*X`0`` +M`$C3X,-`#[;/C4P)`;@!````2-/@PV9F9I!F9F:005154TF)_(N?@````$`/ +MMNZ)[^BX____"=A!B80D@````(GOZ`?F__^-L!P!``!)BWPD$.@`````B>F# +MX0.Z``$``-/B]]*)Z(/@!,'X`H/X`1GV9KX``('&%``#`$F+?"00Z`````!) +MBWPD$+YD'0``Z``````YV'4F08N4)(````!)BWPD$+YD'0``Z`````!)BWPD +M$+YD'0``Z`````!;74%@"B=F#X0.Z`0$``-/B]](\`1GV9KX``('&%``#`$R)[^@` +M````08MT)#R#Q@BZ`````$R)[^@`````#[;S3(GWZ!;___^-M1P!``!,B>_H +M`````$''A"1,`@```0```(UU*+H!````3(GOZ`````!(BQPD2(ML)`A,BV0D +M$$R+;"083(MT)"!(@\0HPV9F9I!F9F:09F9FD&9FD$%6055!5%5328G]08GV +MO0````!,BV<0B?(/ML)(BT3',(M8/,>`0`(```````"-?H`````*@!=!:_Z`,``.@`````_\6!_><#``!VWNL-@?WG +M`P``9F:09I!V#$$/MO9,B>_HPO?__T$/MO9,B>_HAOW__UM=05Q!74%>PV9F +M9I!F9I!F9I!F9I!!5%-(@^P(2(G[2(G12(M',$R+8!"+O^P,``!(P><%2`-[ +M$$B)\DB)WNB"Y/__BX/L#```_\"#X!^)@^P,``#^@V4,``"+4R2!X@#\___! +MX`4)PHMS/(/&%$R)Y^@`````2(/$"%M!7,-F9F:09F:04TB)^[D`````N@(` +M``"^`````.CX]/__2(G?Z##S__](B=_H`````(/X`746QX-@#````0````^V +M,TB+>S#HO?S__UO#9F9FD&9F9I!F9I!(@^PH2(E<)`A(B6PD$$R)9"083(EL +M)"!)B?U,C68@2(M',$B+:!"+7SR-LQP!``!(B>_H`````"7!````N@````"# +M^$`/A=H!``!!@WPD!`%U;4$/ME0D%8VS!`$``$B)[^@`````00^V5"07C;,( +M`0``2(GOZ`````!!#[94)!F-LPP!``!(B>_H`````$$/ME0D&XVS$`$``$B) +M[^@`````00^V5"0=C;,4`0``2(GOZ`````#K0V9F9I!F9I"X`/___V9!A40D +M%'4E9D&%1"06=1UF085$)!AU%69!A40D&G4-9D&%1"0<9F:09I!T"KH````` +MZ2D!``!!#[94)!2-LP0!``!(B>_H`````$$/ME0D%HVS"`$``$B)[^@````` +M00^V5"08C;,,`0``2(GOZ`````!!#[94)!J-LQ`!``!(B>_H`````$$/ME0D +M'(VS%`$``$B)[^@`````00^V5"0>C;,8`0``2(GOZ`````!!#[94)!^-LQP! +M``!(B>_H`````$&#/"0"#X6-````C;,@`0``2(GOZ`````!!N,@```"Y$"<` +M`+H!````O@````!,B>_H`````+H`````A``````````$B+?Q"Z`````+YD'0``Z`````!(BWL0Z`````"(0P2X```` +M`(![!``/A`P#``#'@X@`````````QX.,`````````,>#D`````````#'@Y0` +M````````QX.8`````````,>#G`````````#'@Z``````````QH.L`````;@` +M````2(-[*``/A*\"``"X`````&:!>P:!4`^%G@(```^V4P6#^@$/A)$"``"# +M^@%_"X72=!=F9I!FD.LL@_H"=!MF9I!F9I!F9I#K',>#C`````$```!F9F:0 +MZQ;'@Y`````!````ZPK'@Y0````!````O0````!F9I!`#[;5B="#X`/!X`@% +M=`$``/;"!'0*C;````,`ZPAFD(VP```"`$B+>Q#H`````(GJ#[;*BH%B)09M0```"4`&```2,'H"XB$&;T```#_Q4"`_0=VGDB)W^BV +M\___2(G?Z+[U__](B=_HUO7__TB+>Q"Z`````+[P!`$`Z`````!(BWL0OBP- +M``#H`````$&)Q4&#Y?Y(BWL01(GJOBP-``#H`````(.[L`````!U6TB+>Q"^ +M``T``.@`````J#!T18M#<*G@`P"`=`@E'_S_?XE#<(.[B`````%T&X.[C``` +M``%T$H.[D`````%T"8.[E`````%U$XM#<*@0=`R#X.^)0W#K!(-C<,^]```` +M`&9F9I!`#[;U2(G?Z!3Q____Q4"`_0=V[(M3<$B+>Q"^``P``.@`````BU-T +M2(M[$+XH#```Z`````"+4WA(BWL0OEP=``#H`````+T`````B>D/ML&+5(,8 +M0(#]`1GV9KX``('&#``#`$B+>Q#H`````(GJ#[;"BU2#($"`_0$9]F:^``"! +MQA```P!(BWL0Z`````#_Q4"`_0%VM,>#@````%6K!@"]`````$`/MO5(B=_H +M3=[____%0(#]!W;LOU##``#H`````(.[D`````%T"8.[E`````%U1T&]```` +M`+T`````0;X``0``1`^VY42)YDB)W^@`````AJ^`/\``$B)W^@RY?__N`$```!(BQPD2(ML)`A,BV0D$$R+;"08 +M3(MT)"!(@\0HPTB#[`A(BW\0N@````"^9!T``.@`````N`$```!(@\0(PV9F +M9I!F9F:09F9FD&9FD,<%``````$```##9F:09I#'!0``````````PV9FD&:0 +M2(/L&$B)7"0(2(EL)!!(B?V)\@^VPDB+7,Z`````"#X`^#^`%T$X/X`7(^@_@#=#'K-V9F9I!F9I!( +MBWT0B=[H`````+]`#0,`Z`````!(BWT0B=[H`````(/@#X/X`W4(N`$```#K +M!I"X`````$B#Q`A;7<-F9F:005=!5D%505154TB#[#A(B?U!B?>)\@^VPDB+ +M5,_H&-S__X/C!$&)W$'![`)!O0````!$B?B#X`/!X`@% +M"`$``$&)QHG"2(E4)"!(B50D&$B)5"00B)1"0$08V&```# +M`$&-M@```@!%A.0/1?!(BWT0Z`````")PX/C\(/+`4B+="0@C88```,`C;8` +M``(`183D#T7P2(M]$(G:Z`````!(BW0D&(V&```#`(VV```"`$6$Y`]%\$B+ +M?1#H`````+\9````Z`````"#X_!(BW0D$(V&```#`(VV```"`$6$Y`]%\$B+ +M?1")VN@`````2(MT)`B-A@```P"-M@```@!%A.0/1?!(BWT0Z`````"_T`<` +M`.@`````BUPD!(G>2(GOZ`````"%P'4<0?_%08/]`@^&(?___XG>2(GOZ)[: +M___IG_[__XMT)"R!QAP!``!(BWPD,.@`````)<````"#^$!T$T$/MO=(B>_H +M;]K__[@`````ZQA!#[;W2(GOZ%S:__^X`0```&9F9I!F9I!(@\0X6UU!7$%= +M05Y!7\.02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D((GPB=5!B+`_?__@,X!1(GF3(GOZ`````"Y`0```(G(2(L<)$B+ +M;"0(3(MD)!!,BVPD&$R+="0@2(/$*,-F9F:09F9FD&9FD$B#[`B)\0^VP4B+ +M5,C__[@!````6\-F9F:09F:09F:0B?`/ML!(BU3',+C_ +M````2(72=`(%@>+@````"="`Y.=$B>+!X@N!X@`8```)T$F+?1")PD2)]N@` +M````#[;#1HBD*+T```!"B*PHM0```+@!````9F:09I!(BQPD2(ML)`A,BV0D +M$$R+;"083(MT)"!(@\0HPV9FD$B#[!A(B1PD2(EL)`A,B60D$$B)^XGP0;P# +M````02'$@^`$B<7![0)`@/T!&?9FO@``@<88``,`2(M_$.@`````00^VU(U* +M&+H!````2-/B"=!`@/T!&?9FO@``@<88``,`2(M[$(G"Z`````!`@/T!&?9F +MO@``@<88``,`2(M[$.@`````N`$```!(BQPD2(ML)`A,BV0D$$B#Q!C#9I!! +M54%455-(@^P(28G\08GUO0,```!$(>U`#[;VB?.#XP3!ZP+HY^C__X#[`1GV +M9KX``('&&``#`$F+?"00Z`````!`#[;-@\$82,?"_O___TC3PB'0@/L!&?9F +MO@``@<88``,`28M\)!")PN@`````@/L!&?9FO@``@<88``,`28M\)!#H```` +M`$`/MO7!Y@B!Q@@!``"-A@```P"!Q@```@"$VP]%\$F+?"00Z`````"#X/"# +MR`%`#[;5P>((C8H(`0``C9$```,`@<$```(`A-N)U@]$\4F+?"00B<+H```` +M`$$/MO5,B>?H(>C__[@!````2(/$"%M=05Q!7<.005=!5D%505154TB#[`A) +MB?Q(B=-!B?5,BW\0B?(/ML)(BVS',$`/MM:)T(/@`\'@"`5T`0``]L($=`B- +ML````P#K!HVP```"`$F+?"00Z`````")0UA(A>UU$,<#`````+@!````Z=,` +M``!$BW4\00^V]4R)Y^@`````B0.X`0```(,[``^$LP```(N%8`P``(E#+(N% +M1`(``(E#,`^VA4@"``"(0S2Y`````&9F9I")R@^V1"IVB$0:!/_!@_DG=NY$ +MB?9,B?_H`````(E#.$&-=A!,B?_H`````(E#/$&-=A1,B?_H`````(E#0$&- +M=AA,B?_H`````(E#1$&-=AQ,B?_H`````(E#2$&-=B!,B?_H`````(E#3$&- +M=B1,B?_H`````(E#4$&-=BA,B?_H`````(E#5+@!````2(/$"%M=05Q!74%> +M05_#9F:02(/L*$B)'"1(B6PD"$R)9"003(EL)!A,B70D($F)_DF)U8GS#[;# +M2(MLQS"X`0```(.]8`P````/A$@, +M``"+A>@,``"+C(5H#```08G,2XT$I$C!X`1,C:0H4`(``$&(3"0$@SH`#X6N +M````2(U""(.]1`(```)U#\=`!`$```#K-F9FD&9FD(-X!`%U*H-]"`!U)(N% +MZ`P``(G"B8R5:`P``/_`B87H#```N`,```#IN````&9FD("]9`P```!U1X.] +M0`(```!U'@^VVXG>3(GWZ)'M__^)WDR)]^CG[?__9F9FD&9FD$R)ZDR)YDB) +M[^BRZ___28U5"$R)YDB)[^A#[___ZV&03(GJ3(GF2(GOZ)+K__]FD.M.3(GF +M2(GOZ(/K__^`O4@"```!=3J#O4`"```!=0L/MO-,B??H9N[__TR)YDB)[^B[ +M[___A98!``` +M@<8`&0``2(M\)!CH`````+D`````B=J^`````$R)_T'_5RC&1"0C`/?%_P$` +M``^$``$``(!\)",!&=MFNP``@<,4``,`NN____^)WDB+?"08Z`````")WDB+ +M?"08Z`````!!B<:)PO?2@\H0B=Y(BWPD&.@`````@'PD(P$9]F:^``"!Q@@` +M`P!(BWPD&.@`````08G$0;T`````#[9$)".)1"04B40D$&9F9I!!#[;5N``! +M``")T=/@B<-$(?.X`0```-/@1"'P08GI08/A`8G!1`G)=!E$B>]$B30D +M08G`BW0D%$R)_^A]V?__A=MT*HM<)!"-!)T`````1`GH#[;XZ%/J__^%1"0D +M=`Y!#[;5B=Y,B?_H3]S__\'M`D'![`A!_\5!@/T##X9[____ZP/![0C1[?Y$ +M)".`?"0C`0^&X/[__[@!````2(M<)"A(BVPD,$R+9"0X3(ML)$!,BW0D2$R+ +M?"102(/$6,-F9F:09F:09F:09F:02(/L"$B+?Q"Z`````+YD'0``Z`````"X +M`0```$B#Q`C#9F9FD&9F9I!F9F:09F:02(/L"(N7@````$B+?Q"^9!T``.@` +M````N`$```!(@\0(PV9F9I!F9F:09F:09F:02(/L.$B)7"0(2(EL)!!,B60D +M&$R);"0@3(ET)"A,B7PD,$B)^T&)S$6)Q4&)]HG0O0`````YS7-.1`GP08G' +MD(MS/('&'`$``$B+0S!(BW@0Z`````"$P'@.1"'X1#CP#Y3`#[;`ZR1$B>_H +M``````^V,TB+>S#H`````(7`=`S_Q40YY7*YN`````!(BUPD"$B+;"003(MD +M)!A,BVPD($R+="0H3(M\)#!(@\0XPY!32(G[BW<\@<8@`0``2(M',$B+>!"Z +M`````.@`````BW,\@<8@`0``2(M#,$B+>!#H`````%O#9F:09F:09F:04TB) +M^XMW/('&(`$``$B+1S!(BW@0N@(```#H`````(MS/('&'`$``$B+0S!(BW@0 +MZ`````!;PV9FD&9FD&9FD$B#[!A(B1PD2(EL)`A,B60D$(GP#[;`2(MP3(-W4W0`^V]<<$)`````!! +MN0````!!N`````"Y`````+H'````3(GGZ`````"%P'1+9L<#``#I7?____:# +MH````.!T,[D`````2(G>N`$```"`N_X!``"E=2*Z``````^WP@(,,/_"9H'Z +M_P%V\;@`````A,EU!;@!````2(/$.%M=05Q!7<.02(/L"(GP#[;`2(M\QS"X +M`````$B%_W03N`````"#OV`,```!=`7H`````$B#Q`C#2(/L.$`/MO;'1"0P +M[P```,=$)"@`````#[9$)$")1"0@10^VR42)3"0810^VP$2)1"00#[;)B4PD +M"`^VTHD4)$&Y`````$&X`````+D`````N@````#H`````$B#Q#C#2(/L:$B) +M7"0X2(EL)$!,B60D2$R);"103(ET)%A,B7PD8$B)^T&)UT&)SDV)Q46)S(GR +MBVPD<$2+3"1X1(N$)(````"+O"2(````BXPDD````$0/MIPDF````$0/MI0D +MH`````^VPKX`````2(-\PS``=$T/MO)!#[;"B40D,$$/ML.)1"0H#[?!B40D +M(`^WQXE$)!A!#[?`B40D$$$/M\&)1"0(#[?%B00D18GA38GH1(GQ1(GZ2(G? +MZ#$```")QHGP2(M<)#A(BVPD0$R+9"1(3(ML)%!,BW0D6$R+?"1@2(/$:,-F +M9F:09F:09F:02('LF````$B)7"1H2(EL)'!,B60D>$R)K"2`````3(FT)(@` +M``!,B;PDD````(GPB50D7(G-3(E$)%!$B4PD3$2+K"2@````1(N\)*@```"+ +ME"2P````9HE4)#"+C"2X````9HE,)""+E"3`````9HE4)!`/MHPDR````(A, +M)`\/MI0DT````(A4)`X/ML!(BUS',$R+9Q!$BW,\@[M``@```70)@[M@#``` +M`74*N@````#IV`(``$&XZ`,``+FX"P``N@````"^0````$B)W^@`````N@`` +M``"%P`^$K@(``$B)W^@`````@_T!=6Y,B>D/MM5!C;8$`0``3(GGZ`````!, +MB?@/MM1!C;8(`0``3(GGZ`````"+3"0P#[;508VV#`$``$R)Y^@`````BT0D +M(`^VU$&-MA`!``!,B>?H`````(M,)!`/MM5!C;84`0``3(GGZ`````#K/K@` +M____9D2%Z'4A9D2%^&9F9I!U%V:%1"0P=1!FA40D(&:0=0=FA40D$'022(G? +MZ`````"Z`````.GU`0``00^VU4&-M@0!``!,B>?H`````$$/MM=!C;8(`0`` +M3(GGZ``````/ME0D,$&-M@P!``!,B>?H``````^V5"0@08VV$`$``$R)Y^@` +M````#[94)!!!C;84`0``3(GGZ``````/ME0D#T&-MA@!``!,B>?H``````^V +M5"0.08VV'`$``$R)Y^@`````@WPD7`!U14&X$"<``+D<#```N@$```"^```` +M`$B)W^@`````AL```!!C;8<`0``3(GGZ`````"H"'422(G?Z`````"Z`````.G& +M````O0`````[;"1,L6 +MB>A(BTPD4`^W%$%$B>Y,B>?H`````/_%.VPD3'*=0;AD````N5##``"Z`0`` +M`+X`````2(G?Z`````"%P'4>2(G?Z`````"Z`````.LA2(G?Z`````"Z```` +M`.L22(G?Z`````"Z`0```&9FD&:0B=!(BUPD:$B+;"1P3(MD)'A,BZPD@``` +M`$R+M"2(````3(N\))````!(@<28````PV9F9I!F9F:09F9FD&9FD$%455-( +MB?M(BT_H`````+\*````Z`````!(B=_H`````+_T`0``Z`````"_]`$``.@````` +MO_0!``#H`````+_T`0``Z`````"[`````$&!Q!P!``"01(GF2(GOZ`````"$ +MP'@'N`$```#K'K_T`0``9F:09I#H`````/_#@?L/)P``=M&X`````%M=05S# +M9F9FD&9FD%-(B?OH-____[H!````@_@!=!2_]`$``.@`````2(G?Z!O___^) +MPHG06\-F9I!FD%532(/L"$B)_4B+!0````"+*^ +M+`T``$B)W^@`````2(L<)$B+;"0(3(MD)!!(@\08PV9FD&:005154TB)^[XL +M#0``Z`````!!B<2)PH/*`;XL#0``2(G?Z`````"^\`0!`$B)W^@`````B<6# +MX&*#^&)T%8GJ@\IB#[;2OO`$`0!(B=_H`````+X```0`2(G?Z`````!(B=_H +M"?W__TB+!0````"+<`B!Q@``!`"Z!P```$B)W^@`````2(L%`````(LP@<8` +M``0`N@````!(B=_H`````$B+!0````"+<`B!Q@``!`"Z!0```$B)W^@````` +M2(L%`````(LP@<8```0`N@````!(B=_H`````$B)W^@O_?__B>J^\`0!`$B) +MW^@`````OO`$`0!(B=_H`````$2)XKXL#0``2(G?Z`````!;74%J^\`0!`$B)W^@`````OO`$`0!(B=_H`````$2)ZKXL#0``2(G? +MZ`````!(BQPD2(ML)`A,BV0D$$R+;"083(MT)"!(@\0HPV:02(/L"(GQA-)T +M%K@!````T^`(A[0```#K%&9F9I!F9I"X_O___]/`((>T````#[:WM````.@` +M````2(/$",-FD$%7059!54%455-(@^P(2(G]0;\`````OBP-``#H`````$&) +MQHG"@\H!OBP-``!(B>_H`````+[P!`$`2(GOZ`````!!B<6#X&*#^&)T%D2) +MZH/*8@^VTK[P!`$`2(GOZ`````"^```$`$B)[^@`````O@``!`!(B>_H```` +M`&8]5:H/A>\```!!O`````!FD+L`````1#GC?RIF9I!F9I!(BP4`````BW`8 +M@<8```0`NJ````!(B>_H`````/_#1#GC?MQ!@?S(````?@J_`0```.@````` +MO@``!`!(B>_H`````(G#2(L%`````(MP&('&```$`+JP````2(GOZ`````!F +M@?M5JG480?_$08'\QP````^.=O___V:!^U6JD'152(L%`````(MP&('&```$ +M`+JP````2(GOZ`````"^```$`$B)[^@`````9CU5JG4E0;\!````2(GOZ.#Y +M__\\/G432(GOZ*3\__^%P+@"````1`]$^$B+!0````"+_H`````+[P!`$`2(GOZ`````!$B?*^+`T` +M`$B)[^@`````00^VQTB#Q`A;74%<05U!7D%?PV9F9I!F9F:09F9FD%532(/L +M"$B)_;L`````9I!(QP4``````````$B)[^C]_?__A,!U(4C'!0`````````` +M2(GOZ.;]__^$P'4*_\.!^^<#``!^R`^VP$B#Q`A;7<-F9F:09F9FD&9FD&9F +MD(!^`0)U&H!^`@%U%`^V1@.)!0````"X`````,-F9F:0N/_____#9F9FD&9F +MD&9FD$B#[#A(B5PD"$B);"003(ED)!A,B6PD($R)="0H3(E\)#!!B?=!B_H`````(E$)`2)PH/*`;XL#0``2(GOZ`````"^ +M\`0!`$B)[^@`````08G&@^!B@_AB=!9$B?*#RF(/MM*^\`0!`$B)[^@````` +MO@``!`!(B>_H`````(7;="R[`````$0YZWU29I!!C;0?```$`$B)[^@````` +M08@$)/_#2?_$1#GK?.+K,+L`````1#GK?29F9I!F9I!!#[84)$&-M!\```0` +M2(GOZ`````#_PTG_Q$0YZWSAD$2)\K[P!`$`2(GOZ`````"^\`0!`$B)[^@` +M````BU0D!+XL#0``2(GOZ`````"X`0```$B+7"0(2(ML)!!,BV0D&$R+;"0@ +M3(MT)"A,BWPD,$B#Q#C#```````````````$```````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`0`````````````````````````````````!``$``0`"``$``P`!``0``0`% +M``$`!@`!``<``0````$``"`!``!``0``8`$``(`!``"@`0``P`$``.`!```` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````````````````````````!0``````````0`!>!`,!PB0 +M`0```````"P````<``````````````!L!@```````$<.T`1PCP*.`XT$C`6& +M!H,'`````````"0```!,``````````````#W`````````$$.$$$.&$0.((,# +MA@(````D````=```````````````*P(```````!$#C!4C0*,`X8$@P4````` +M)````)P``````````````%0`````````0@X000X800X@@P2&`XP"`#P```#$ +M``````````````!*`0```````$(.$$(.&$(.($(.*$$.,$$..$<.P`2#!X8& +MC`6-!(X#CP(````````T````!`$`````````````]P````````!"#A!"#AA" +M#B!!#BA!#C!'#K`$@P:&!8P$C0..`@```!0````\`0````````````")```` +M`````!P```!4`0`````````````1`0```````$$.$(,"````)````'0!```` +M`````````%L`````````00X000X81`X@@P.&`@```"0```"<`0`````````` +M```T`0```````$0.0%Z/`HX#C02,!88&@P<<````Q`$`````````````10`` +M``````!$#A```````!P```#D`0````````````!L`````````$0.$``````` +M)`````0"`````````````&T`````````00X000X8@P.&`@```````"0````L +M`@````````````"2`0```````$0.,%B.`HT#C`2&!8,&```<````5`(````` +M````````@P````````!$#A```````"0```!T`@````````````"Z```````` +M`$0.($Z,`H8#@P0````````D````G`(`````````````\@````````!$#B!. +MC`*&`X,$````````)````,0"`````````````%$!````````0@X000X800X@ +M@P2&`XP"`"0```#L`@`````````````"`0```````$0.($Z,`H8#@P0````` +M```D````%`,`````````````WP$```````!$#C!4C0*,`X8$@P4`````)``` +M`#P#`````````````$,"````````1`Y`7H\"C@.-!(P%A@:#!R0```!D`P`` +M``````````"6`0```````$$.$$$.&$0.((,#A@(````D````C`,````````` +M````CP$```````!'#K`$:(X"C0.,!(8%@P8`%````+0#`````````````#$` +M````````%````,P#`````````````*4`````````)````.0#```````````` +M`%L`````````00X000X81`X@@P.&`@```"0````,!``````````````T`0`` +M`````$0.0%Z/`HX#C02,!88&@P<<````-`0`````````````+`````````!$ +M#A```````!0```!4!``````````````?`````````!0```!L!``````````` +M```7`````````#P```"$!`````````````"9`0```````$(.$$(.&$(.($(. +M*$$.,$$..$0.0(,'A@:,!8T$C@./`@`````````D````Q`0````````````` +M:@````````!!#A!!#AB#`X8"````````%````.P$`````````````$(````` +M````)`````0%`````````````#<`````````00X000X81`X@@P.&`@```!0` +M```L!0`````````````]`````````!P```!$!0`````````````8```````` +M`$0.$```````%````&0%`````````````#(`````````%````'P%```````` +M`````"4`````````)````)0%`````````````(4`````````1`XH4XT"C`.& +M!(,%`````!0```"\!0`````````````H`````````"0```#4!0`````````` +M``!9`````````$(.$$$.&$$.((,$A@.,`@`\````_`4`````````````*0(` +M``````!"#A!"#AA"#B!"#BA!#C!!#CA$#E"#!X8&C`6-!(X#CP(````````` +M)````#P&`````````````,@`````````0@X000X800X@@P2&`XP"`#P```!D +M!@`````````````Z`@```````$(.$$(.&$(.($(.*$$.,$$..$<.H`.#!X8& +MC`6-!(X#CP(````````D````I`8`````````````]`````````!!#A!!#AA$ +M#B"#`X8"````)````,P&`````````````,,$````````1`Y07H\"C@.-!(P% +MA@:#!QP```#T!@`````````````E`````````$0.$```````/````!0'```` +M`````````+4`````````0@X00@X80@X@0@XH00XP00XX1`Y`@P>&!HP%C02. +M`X\"`````````!0```!4!P`````````````:`0```````"0```!L!P`````` +M``````#"`````````$0.($Z,`H8#@P0````````<````E`<````````````` +M/@````````!$#B!*C`*#`R0```"T!P````````````"C`````````$0.,%2- +M`HP#A@2#!0`````D````W`<`````````````C`$```````!"#A!!#AA!#B"# +M!(8#C`(`+`````0(`````````````/H!````````1P[@`G"/`HX#C02,!88& +M@P<`````````+````#0(`````````````/H`````````1P[0`G"/`HX#C02, +M!88&@P<`````````/````&0(`````````````$H!````````0@X00@X80@X@ +M0@XH00XP00XX1P[``X,'A@:,!8T$C@./`@```````"0```"D"``````````` +M``!Y`````````$0.($Z,`H8#@P0````````4````S`@`````````````5``` +M```````\````Y`@`````````````.0(```````!"#A!"#AA"#B!"#BA!#C!! +M#CA$#D"#!X8&C`6-!(X#CP(`````````/````"0)`````````````!&!HP%C02.`X\"````````'````!P+```````` +M`````"H`````````1`X0```````L````/`L`````````````F0(```````!" +M#A!!#AA!#B!$#E"#!(8#C`(````````D````;`L`````````````:P`````` +M``!!#A!!#AA$#B"#`X8"````)````)0+`````````````!8!````````0@X0 +M00X800X@@P2&`XP"`"0```"\"P````````````!7`0```````$$.$$$.&$0. +M((,#A@(````4````Y`L`````````````(P`````````D````_`L````````` +M````=P````````!!#A!!#AA$#B"#`X8"````+````"0,`````````````(D" +M````````0@X00@X800X@00XH1PZP!(,%A@2,`XT"%````%0,```````````` +M`$(`````````)````&P,`````````````$<`````````00X000X8@P.&`@`` +M`````!0```"4#``````````````J`````````!0```"L#``````````````. +M`````````"P```#$#`````````````!D`0```````$(.$$(.&$$.($$.*$<. +ML`B#!88$C`.-`A0```#T#`````````````!5`````````!P````,#0`````` +M``````!^`````````$$.$$0.((,"%````"P-`````````````%L````````` +M'````$0-`````````````*,`````````00X01`X@@P(<````9`T````````` +M````+P````````!!#A"#`@```!0```"$#0`````````````,`````````!0` +M``"<#0`````````````H`````````"0```"T#0````````````!Z```````` +M`$0.,%2-`HP#A@2#!0`````<````W`T`````````````%0````````!$#A`` +M`````!P```#\#0`````````````G`````````$0.$```````)````!P.```` +M`````````&8!````````1`YP7H\"C@.-!(P%A@:#!Q0```!$#@`````````` +M```F`````````"0```!<#@````````````!B`````````$(.$$$.&$$.((,$ +MA@.,`@`<````A`X`````````````3P````````!$#B!*C`*#`QP```"D#@`` +M```````````@`````````$$.$(,"````%````,0.`````````````,`"```` +M````)````-P.`````````````(D!````````1`Y07H\"C@.-!(P%A@:#!R0` +M```$#P````````````#A`````````$0.<%Z/`HX#C02,!88&@PCP*.`XT$C`6&!H,')````%0/```````` +M`````+$`````````1`XP5(T"C`.&!(,%`````"0```!\#P````````````#X +M`@```````$0.4%Z/`HX#C02,!88&@P<<````I`\`````````````>@`````` +M``!$#A```````"0```#$#P````````````"Y`0```````$0.0%Z/`HX#C02, +M!88&@P`````````$0.($Z,`H8#@P0````````L +M````+!4`````````````_P````````!"#A!"#AA!#B!!#BA$#C"#!88$C`.- +M`@`\````7!4`````````````30$```````!"#A!"#AA"#B!"#BA!#C!!#CA$ +M#D"#!X8&C`6-!(X#CP(`````````)````)P5`````````````*(!```````` +M1`XP6(X"C0.,!(8%@P8``"0```#$%0`````````````#`@```````$0.8%Z/ +M`HX#C02,!88&@P<<````[!4`````````````(0````````!$#A```````!P` +M```,%@`````````````B`````````$0.$```````)````"P6```````````` +M`*\`````````1`Y`7H\"C@.-!(P%A@:#!QP```!4%@`````````````W```` +M`````$$.$(,"````'````'06`````````````#<`````````00X0@P(````D +M````E!8`````````````I@````````!$#B!.C`*&`X,$````````+````+P6 +M`````````````!\!````````0@X00@X800X@00XH1`Y@@P6&!(P#C0(`'``` +M`.P6`````````````#``````````1`X0```````<````#!<````````````` +M8`````````!$#D```````"0````L%P````````````#F`````````$0.<%Z/ +M`HX#C02,!88&@P6UT +M86(`+G-T````````!;`````````````````````0````````````````````$` +M```"`````````````````````````*CD````````^!,````````-````8@`` +M``@`````````&``````````)`````P````````````````````````"@^``` +M`````'\-```````````````````!```````````````````````````````` +M`````````````````````0````0`\?\```````````````````````````,` +M`0````````````````````````````,``P`````````````````````````` +M``,`!0``````````````````````"`````(``0!0#````````(D````````` +M&0````(``0#@#````````!$!````````+`````(``0!@$````````&T````` +M````.0````(``0`P%P```````-\!````````1@````(``0"0'@```````#$` +M````````50````(``0#0'@```````*4`````````9@````(``0!0(0`````` +M`!\`````````<@````(``0!P(0```````!<`````````?0````$`!0`````` +M``````@`````````B@````(``0"0(0```````)D!````````F@````(``0`P +M(P```````&H`````````HP````(``0"@(P```````$(`````````JP````(` +M`0#P(P```````#<`````````LP````(``0`P)````````#T`````````O@`` +M``(``0!P)````````!@`````````Q@````(``0"0)````````#(````````` +MV`````(``0#0)````````"4`````````YP````(``0``)0```````(4````` +M````\@````(``0"0)0```````"@`````````_P````(``0#`)0```````%D` +M````````"P$```(``0`@)@```````"D"````````&`$```(``0!0*``````` +M`,@`````````)0$```(``0`@*0```````#H"````````+P$```(``0!@*P`` +M`````/0`````````/@$```(``0"@9````````-T`````````20$```(``0!@ +M+````````,,$````````50$```(``0``/@```````!0$` +M``(``0#`.P```````#D"````````BP$```(``0!@,0```````+4````````` +MG`$```(``0`@,@```````!H!````````J0$```(``0!`,P```````,(````` +M````M@$```(``0!0-````````*,`````````PP$```(``0`0-````````#X` +M````````S@$```(``0``-0```````(P!````````V0$```(``0"0-@`````` +M`/H!````````Y0$```(``0#@.@```````'D`````````\P$```(``0"0.``` +M`````/H```````````(```(``0"0.0```````$H!````````#0(```(``0!@ +M.P```````%0```````````````,`!@``````````````````````'@(```(` +M`0"`90```````,L"````````+@(```(``0!0:````````((`````````10(` +M``(``0#@:````````'D%````````4`(```(``0!@;@```````"$$```````` +M7`(```(``0"0<@```````"H`````````;`(```(``0``>0```````(D"```` +M````>0(```(``0"`@@```````"8`````````B@(```(``0`@@P```````$\` +M````````GP(```(``0!P@P```````"``````````L@(```(``0"0@P`````` +M`,`"````````R`(```(``0!0A@```````(D!````````WP(```(``0#@AP`` +M`````.$`````````]P(```(``0#`FP```````&``````````!0,```(``0#0 +MB````````),!````````&`,```(``0!`G@```````),`````````)P,```(` +M`0"@GP```````$`"````````.P,```(``0`PD0```````&\!````````3@,` +M``(``0!PB@```````+$`````````70,```(``0`PBP```````/@"```````` +M<0,```(``0"`E@```````)T`````````@P,```(``0!`E0```````#H!```` +M````D0,```(``0!0GP```````$4`````````G@,```(``0`PC@```````'H` +M````````M`,```(``0``G0```````%\`````````RP,```(``0"PC@`````` +M`+D!````````W@,```(``0!PD````````,``````````[@,```(``0!@G0`` +M`````-$`````````^P,```(``0#@G@```````&D`````````#@0```(``0"@ +MD@```````+L!````````'P0```(``0!@E````````-$`````````+00```(` +M`0`@EP````````4"````````/@0```(``0`PF0```````!P`````````5P0` +M``(``0!0F0```````"````````",`````````E04``!`````````` +M````````````````HP4``!``````````````````````````K04``!`````` +M````````````````````MP4``!``````````````````````````P04``!`` +M````````````````````````T@4``!``````````````````````````X@4` +M`!``````````````````````````[`4``!(``0!P!@```````/<````````` +M]@4``!```````````````````````````P8``!`````````````````````` +M````%08``!(``0!P!P```````"L"````````)08``!`````````````````` +M````````+@8``!(``0"`>````````'<`````````/`8``!(``0"@"0`````` +M`%0`````````3P8``!(``0!@?`````````X`````````708``!(``0``"@`` +M`````$H!````````:@8``!(``0`P?````````"H`````````?`8``!(``0!@ +M=0```````&L`````````AP8``!(``0!0"P```````/<`````````F@8``!(` +M`0``#@```````%L`````````JP8``!(``0``@`````````P`````````MP8` +M`!(``0#@?0```````%4`````````QP8``!(``0!@#@```````#0!```````` +MV08``!(``0#0?P```````"\`````````Z08``!(``0"@#P```````$4````` +M````_`8``!(``0#P#P```````&P`````````#@<``!(``0#0$````````)(! +M````````)`<``!(``0!P$@```````(,`````````00<``!(``0``$P`````` +M`+H`````````50<``!(``0!`@````````'H`````````8P<``!(``0#`$P`` +M`````/(`````````>@<``!(``0#`%````````%$!````````D@<``!(``0`@ +M%@````````(!````````J`<``!``````````````````````````L@<``!(` +M`0`0&0```````$,"````````Q`<``!(``0`0@````````"@`````````U0<` +M`!(``0!@&P```````)8!````````Z`<``!(``0``'0```````(\!```````` +M^0<``!(``0"`'P```````%L`````````"0@``!(``0#@'P```````#0!```` +M````&@@``!(``0`@(0```````"P`````````+`@``!$``P````````````0` +M````````/`@``!``````````````````````````2@@``!(``0`@80`````` +M`#\!````````70@``!``````````````````````````<`@``!`````````` +M````````````````=P@``!``````````````````````````?@@``!(``0!@ +M8@```````&8`````````B@@``!``````````````````````````K`@``!(` +M`0`@?P```````*,`````````N@@``!(``0`@9````````'$`````````S`@` +M`!(``0#`<@```````)D"````````W@@``!(``0#P=@```````%P```````$(` +M````````-PD``!(``0#@>P```````$<`````````1@D``!(``0!P?``````` +M`&0!````````50D``!(``0!`?@```````'X`````````9@D``!(``0#`?@`` +M`````%L`````````F5R;P!C8E]I0!D:7)E8W1?6YC1&ES:TEN9F\`9V5T161M85)E9T]F9G-E=`!U;FUA&5C=71E3F]N541-04-O +M;6UA;F0`7V1O4V]F=%)E&ET-C`Q`&=E=%\V,#%?:60` +M0!P +M9FY396YD0V]M;6%N9`!F1&5296%D5W)I=&4`<&9N1&5V:6-E1F%I;&5D`$-H +M96-K4W5M`&9$95-E;&5C=$UO9&4`;W-?;65M5-T871E`$=E=%-T86UP`%-Y;F-!4EN9F\`0VAE8VM! +M4-R:71I8V%L`&9/6YC`&UV4F5A9%=R:71E +M`&UV4V%T841I5-H=71D;W=N`&UV +M4V%T84-H86YN96Q0:'E0;W=E#4P.'A?:6]C=&P`````/S_____ +M____;0H````````"````=@```/S_________GPH````````+````=0`````` +M````````PPH````````"````:````/S_________V0H````````"````9``` +M`/S_________]@H````````"````P```/S_________4`X````````" +M````?````/S_________G@X````````"````?````/S_________Q0X````` +M```"````?````/S_________\@X````````"````?@```/S_________1@\` +M```````+````>@``````````````3@\````````+````>0`````````````` +M8!$````````"````:````/S_________L1$````````"````:````/S_____ +M____[A$````````"````>P```/S_________'A(````````"````?````/S_ +M________0A,````````"````>P```/S_________@A,````````"````?``` +M`/S_________FQ,````````+````A```````````````HQ,````````"```` +M?````/S_________%Q0````````"````:````/S_________:Q0````````" +M````>P```/S_________>A0````````"````?````/S_________DQ0````` +M```+````A```````````````FQ0````````"````?````/S_________>A8` +M```````"````:````/S_________H18````````"````B````/S_________ +MVQ8````````"````>P```/S_________ZA8````````"````?````/S_____ +M____`Q<````````+````A```````````````"Q<````````"````?````/S_ +M________MQ<````````"````:````/S_________RQ<````````"````?@`` +M`/S_________\A<````````+````@P``````````````^A<````````+```` +M@@``````````````,1@````````"````?@```/S_________6!@````````+ +M````A0``````````````8!@````````+````@@``````````````AQ@````` +M```"````?@```/S_________KA@````````+````AP``````````````MA@` +M```````+````A@``````````````WQ@````````"````?````/S_________ +MZA@````````+````A```````````````\A@````````"````?````/S_____ +M____31D````````"````?````/S_________8!D````````+`````@```#`7 +M````````M1D````````+````B0``````````````P1D````````"````B@`` +M`/S_________SAH````````"````?@```/S_________X1H````````"```` +M;0```/S__________1H````````+````@0``````````````!1L````````+ +M````@```````````````(AP````````"````;P```/S_________/!P````` +M```"````8P```!0`````````1QP````````"````90```"P`````````D1P` +M```````"````<````/S_________V1P````````"````<@```/S_________ +MZQP````````"````P```/S_________T!\````````"````?````/S_ +M________'B`````````"````?````/S_________12`````````"````?``` +M`/S_________P```/S_________@S0````````"````?@```/S_________PC0` +M```````+`````@```&`Q````````SC0````````+`````@```$`S```````` +MCS<````````"````E````/S_________L3<````````"````E0```/S_____ +M____,3@````````"````E````/S_________-SD````````"````E````/S_ +M________B3H````````"````E````/S_________J#H````````"````E0`` +M`/S_________O3P````````+````+@``````````````;ST````````+```` +M+@```#@`````````]&$````````"````?````/S_________E&(````````" +M````D@```/S_________G&(````````"````EP```/S_________I&(````` +M```"````F````/S_________=&0````````"````D@```/S_________]V0` +M```````"````?````/S_________#&4````````+````A``````````````` +M%&4````````"````?````/S_________1&4````````+````A``````````` +M````3&4````````"````?````/S_________P```/S_________-6L````````"````:````/S_________?FT````````+ +M````A```````````````AFT````````"````?````/S_________OVT````` +M```"````?@```/S_________[FT````````+`````@```(!E````````]FT` +M```````+`````@```%!H````````HG(````````+`````@```*!D```````` +MIW(````````"````?````/S_________XW(````````"````?````/S_____ +M____%W,````````"````:````/S_________/W,````````"````?````/S_ +M________87,````````"````?````/S_________&'0````````"````?``` +M`/S_________5G0````````+````F@``````````````8G0````````"```` +MB@```/S_________LW0````````+````FP``````````````[G0````````+ +M````F@``````````````_G0````````"````B@```/S_________!G4````` +M```"````D@```/S_________&74````````+`````@```)!R````````.74` +M```````"````?````/S_________=W4````````"````E@```/S_________ +M(G8````````"````D````/S_________9'8````````"````D````/S_____ +M____E78````````"````G0```/S_________G'8````````"````!````/S_ +M________I'8````````"````D````/S_________M'8````````"````G0`` +M`/S_________VW8````````"````D````/S_________LG<````````"```` +M;P```/S_________TW<````````"````8P```!0`````````WG<````````" +M````90```#P`````````&G@````````"````<````/S_________,7@````` +M```"````<@```/S_________/'@````````"````IX````````"````KP```/S_________AYX````````"```` +ML@```/S_________E9X````````"````K0```/S_________/9\````````" +M````KP```/S_________=)\````````"````M@```/S_________U)\````` +M```"````K@```/S_________`Z`````````"````L0```/S_________%Z`` +M```````"````L0```/S_________*Z`````````"````L0```/S_________ +M/Z`````````"````L0```/S_________4Z`````````"````L0```/S_____ +M____K*`````````"````L0```/S_________P*`````````"````L0```/S_ +M________U*`````````"````L0```/S_________Z*`````````"````L0`` +M`/S__________*`````````"````L0```/S_________$*$````````"```` +ML0```/S_________)*$````````"````L0```/S_________/:$````````" +M````K@```/S_________6J$````````"````MP```/S_________<:$````` +M```"````K@```/S_________IZ$````````"````M````/S_________&*(` +M```````"````KP```/S_________(:(````````"````N0```/S_________ +M*Z,````````"````L@```/S_________B:,````````"````KP```/S_____ +M____EZ,````````"````L@```/S_________KZ,````````"````KP```/S_ +M________QJ,````````"````L@```/S_________0:0````````"````KP`` +M`/S_________4J0````````"````KP```/S_________8Z0````````"```` +MKP```/S_________BJ0````````"````KP```/S_________K*0````````" +M````KP```/S_________X:0````````"````K0```/S_________$Z4````` +M```"````LP```/S_________+H````````"````MP```/S_________A+H````` +M```"````R@```/S_________D[H````````"````R@```/S_________HKH` +M```````"````R@```/S_________%+L````````"````L0```/S_________ +M);L````````"````K@```/S_________+[L````````"````K0```/S_____ +M____-[L````````"````R@```/S_________0;L````````"````K0```/S_ +M________2[L````````"````K0```/S_________5;L````````"````K0`` +M`/S_________7[L````````"````K0```/S_________=[L````````"```` +MK@```/S_________D;L````````"````K0```/S_________R;L````````" +M````K0```/S_________[+L````````"`````P```!P!````````_[L````` +M```"````L0```/S_________"[P````````"`````P```!P!````````'+P` +M```````"````K@```/S_________,[P````````"`````P```!P!```````` +M1+P````````"````K@```/S_________5[P````````"`````P```!P!```` +M````:+P````````"````K@```/S_________A[P````````"`````P```!P! +M````````FKP````````"````L0```/S_________H;P````````"`````P`` +M`!P!````````M[P````````"````L0```/S_________V;P````````"```` +M`P```!P!````````[[P````````"````L0```/S_________]KP````````" +M`````P```!P!````````!KT````````"````K@```/S_________1[T````` +M```"````!`````,`````````6+T````````"````L@```/S_________;;T` +M```````"````KP```/S_________>KT````````"````L@```/S_________ +MF;T````````"````M````/S_________IKT````````"````L@```/S_____ +M____M;T````````"`````P```!P!````````R[T````````"````L0```/S_ +M________TKT````````"`````P```!P!````````Y[T````````"````L0`` +M`/S_________[KT````````"`````P```!P!````````!+X````````"```` +ML0```/S_________"[X````````"`````P```!P!````````(+X````````" +M````L0```/S_________-[X````````"````KP```/S_________1+X````` +M```"````L@```/S_________5+X````````"````KP```/S_________?;X` +M```````"````L@```/S_________DKX````````"````KP```/S_________ +MG[X````````"````L@```/S_________OKX````````"````M````/S_____ +M____R[X````````"````L@```/S_________VKX````````"`````P```!P! +M````````\+X````````"````L0```/S_________][X````````"`````P`` +M`!P!````````#+\````````"````L0```/S_________$[\````````"```` +M`P```!P!````````*;\````````"````L0```/S_________,+\````````" +M`````P```!P!````````1;\````````"````L0```/S_________7+\````` +M```"````KP```/S_________:;\````````"````L@```/S_________>;\` +M```````"````KP```/S_________G+\````````"`````P```!P!```````` +MLK\````````"````L0```/S_________N;\````````"`````P```!P!```` +M````SK\````````"````L0```/S_________X[\````````"````K@```/S_ +M________^[\````````"`````P```!P!````````$,`````````"````L0`` +M`/S_________(L`````````"````K0```/S_________+\`````````"```` +MK@```/S_________?\`````````"````L@```/S_________E,`````````" +M````KP```/S_________H<`````````"````L@```/S_________P,`````` +M```"````M````/S_________S<`````````"````L@```/S_________X,`` +M```````"`````P```!P!````````\<`````````"````L0```/S_________ +M`,$````````"````KP```/S_________#<$````````"````L@```/S_____ +M____'<$````````"````KP```/S_________=<$````````"````T0```/S_ +M________G<$````````"````L@```/S_________LL$````````"````KP`` +M`/S_________O\$````````"````L@```/S_________X,$````````"```` +MM````/S_________[<$````````"````L@```/S_________^L$````````" +M````M0```/S_________(\(````````"`````P```!P!````````.<(````` +M```"````L0```/S_________4\(````````"````K0```/S_________8,(` +M```````"````M0```/S_________:<(````````"`````P```!P!```````` +M?\(````````"````L0```/S_________I<(````````"`````P```!P!```` +M````N\(````````"````L0```/S_________R,(````````"````M0```/S_ +M________^L(````````"`````P```!P!````````$,,````````"````L0`` +M`/S_________(,,````````"````KP```/S_________+<,````````"```` +ML@```/S_________/<,````````"````KP```/S_________<\,````````" +M`````P```!@!````````=\,````````+`````P```.``````````BL,````` +M```"`````P```!@!````````CL,````````+`````P`````!````````TL,` +M```````"````!`````0`````````*\0````````"````L@```/S_________ +M0<0````````"````KP```/S_________3L0````````"````L@```/S_____ +M____;\0````````"````M````/S_________?,0````````"````L@```/S_ +M________G,0````````"````K@```/S_________T<0````````"````L0`` +M`/S_________[,0````````"````KP```/S_________^<0````````"```` +ML@```/S_________"L4````````"````KP```/S_________(``````````! +M````G@``````````````*``````````!````G@``````````````,``````` +M```!````G@``````````````.``````````!````G@``````````````0``` +M```````!````C@``````````````2``````````!````?0`````````````` +M4``````````!````B0``````````````8``````````!````F@`````````` +M````@``````````!````=0``````````````B``````````!````=0`````` +M````````D``````````!````=0``````````````F``````````!````=0`` +M````````````H``````````!````CP``````````````J``````````!```` +M?P``````````````L``````````!````BP``````````````P``````````! +M````FP``````````````(`$````````!`````P`````!```````````````` +M```!`````@```.T\````````"``````````!`````@```,$\````````$``` +M```````!`````@```,$\````````&``````````!`````@```,@\```````` +M(``````````!`````@```-<\````````*``````````!`````@```.(\```` +M````,``````````!`````@```.D\````````.``````````!`````@```)T] +M````````0``````````!`````@```',]````````2``````````!`````@`` +M`',]````````4``````````!`````@```'H]````````6``````````!```` +M`@```(<]````````8``````````!`````@```)(]````````:``````````! +M`````@```)D]````````(``````````!`````@``````````````4``````` +M```!`````@```'`&````````>``````````!`````@```'`'````````H``` +M```````!`````@```*`)````````R``````````!`````@`````*```````` +M"`$````````!`````@```%`+````````0`$````````!`````@```%`,```` +M````6`$````````!`````@```.`,````````>`$````````!`````@`````. +M````````H`$````````!`````@```&`.````````R`$````````!`````@`` +M`*`/````````Z`$````````!`````@```/`/````````"`(````````!```` +M`@```&`0````````,`(````````!`````@```-`0````````6`(````````! +M`````@```'`2````````>`(````````!`````@`````3````````H`(````` +M```!`````@```,`3````````R`(````````!`````@```,`4````````\`(` +M```````!`````@```"`6````````&`,````````!`````@```#`7```````` +M0`,````````!`````@```!`9````````:`,````````!`````@```&`;```` +M````D`,````````!`````@`````=````````N`,````````!`````@```)`> +M````````T`,````````!`````@```-`>````````Z`,````````!`````@`` +M`(`?````````$`0````````!`````@```.`?````````.`0````````!```` +M`@```"`A````````6`0````````!`````@```%`A````````<`0````````! +M`````@```'`A````````B`0````````!`````@```)`A````````R`0````` +M```!`````@```#`C````````\`0````````!`````@```*`C````````"`4` +M```````!`````@```/`C````````,`4````````!`````@```#`D```````` +M2`4````````!`````@```'`D````````:`4````````!`````@```)`D```` +M````@`4````````!`````@```-`D````````F`4````````!`````@`````E +M````````P`4````````!`````@```)`E````````V`4````````!`````@`` +M`,`E``````````8````````!`````@```"`F````````0`8````````!```` +M`@```%`H````````:`8````````!`````@```"`I````````J`8````````! +M`````@```&`K````````T`8````````!`````@```&`L````````^`8````` +M```!`````@```#`Q````````&`<````````!`````@```&`Q````````6`<` +M```````!`````@```"`R````````<`<````````!`````@```$`S```````` +MF`<````````!`````@```!`T````````N`<````````!`````@```%`T```` +M````X`<````````!`````@`````U````````"`@````````!`````@```)`V +M````````.`@````````!`````@```)`X````````:`@````````!`````@`` +M`)`Y````````J`@````````!`````@```.`Z````````T`@````````!```` +M`@```&`[````````Z`@````````!`````@```,`[````````*`D````````! +M`````@`````^````````:`D````````!`````@```"!A````````J`D````` +M```!`````@```&!B````````T`D````````!`````@```-!B````````\`D` +M```````!`````@```"!D````````&`H````````!`````@```*!D```````` +M0`H````````!`````@```(!E````````@`H````````!`````@```%!H```` +M````H`H````````!`````@```.!H````````X`H````````!`````@```&!N +M````````(`L````````!`````@```)!R````````0`L````````!`````@`` +M`,!R````````<`L````````!`````@```&!U````````F`L````````!```` +M`@```-!U````````P`L````````!`````@```/!V````````Z`L````````! +M`````@```%!X``````````P````````!`````@```(!X````````*`P````` +M```!`````@````!Y````````6`P````````!`````@```)![````````<`P` +M```````!`````@```.![````````F`P````````!`````@```#!\```````` +ML`P````````!`````@```&!\````````R`P````````!`````@```'!\```` +M````^`P````````!`````@```.!]````````$`T````````!`````@```$!^ +M````````,`T````````!`````@```,!^````````2`T````````!`````@`` +M`"!_````````:`T````````!`````@```-!_````````B`T````````!```` +M`@````"`````````H`T````````!`````@```!"`````````N`T````````! +M`````@```$"`````````X`T````````!`````@```,"```````````X````` +M```!`````@```."`````````(`X````````!`````@```!"!````````2`X` +M```````!`````@```(""````````8`X````````!`````@```+""```````` +MB`X````````!`````@```""#````````J`X````````!`````@```'"#```` +M````R`X````````!`````@```)"#````````X`X````````!`````@```%"& +M````````"`\````````!`````@```."'````````,`\````````!`````@`` +M`-"(````````6`\````````!`````@```'"*````````@`\````````!```` +M`@```#"+````````J`\````````!`````@```#".````````R`\````````! +M`````@```+".````````\`\````````!`````@```'"0````````&!`````` +M```!`````@```#"1````````0!`````````!`````@```*"2````````````````N!(` +M```````!`````@```.">````````X!(````````!`````@```%"?```````` +M`!,````````!`````@```*"?````````*!,````````!`````@```."A```` +M````4!,````````!`````@```&"E````````!8````````! +M`````@```)"S````````F!8````````!`````@```-"S````````P!8````` +M```!`````@```("T````````\!8````````!`````@```*"U````````$!<` +M```````!`````@```-"U````````,!<````````!`````@```#"V```````` +M6!<````````!`````@```""W````````B!<````````!`````@```/"Z```` +M````L!<````````!`````@```+"[````````T!<````````!`````@```."[ +M````````^!<````````!`````@```("\````````&!@````````!`````@`` +M`,"\````````.!@````````!`````@```#"]````````8!@````````!```` +M`@```'"^````````B!@````````!`````@```)"_````````J!@````````! +M`````@```%#`````````T!@````````!`````@```$#!````````\!@````` +M```!`````@```(#!````````,!D````````!`````@```&##````````6!D` +M```````!`````@```,##````````