Add hptmv(4), a driver for HighPoint RocketRAID 182x controllers.
authorSascha Wildner <saw@online.de>
Tue, 4 Jan 2011 15:19:23 +0000 (16:19 +0100)
committerSascha Wildner <saw@online.de>
Tue, 4 Jan 2011 15:20:34 +0000 (16:20 +0100)
It was tested with an 1820A card.

Thanks to HighPoint and FreeBSD (from which it was ported).

33 files changed:
share/man/man4/Makefile
share/man/man4/hptiop.4
share/man/man4/hptmv.4 [new file with mode: 0644]
sys/conf/files
sys/config/GENERIC
sys/config/GENERIC_SMP
sys/config/LINT
sys/config/X86_64_GENERIC
sys/config/X86_64_GENERIC_SMP
sys/dev/raid/Makefile
sys/dev/raid/hptmv/Makefile [new file with mode: 0644]
sys/dev/raid/hptmv/access601.h [new file with mode: 0644]
sys/dev/raid/hptmv/array.h [new file with mode: 0644]
sys/dev/raid/hptmv/atapi.h [new file with mode: 0644]
sys/dev/raid/hptmv/command.h [new file with mode: 0644]
sys/dev/raid/hptmv/entry.c [new file with mode: 0644]
sys/dev/raid/hptmv/global.h [new file with mode: 0644]
sys/dev/raid/hptmv/gui_lib.c [new file with mode: 0644]
sys/dev/raid/hptmv/hptintf.h [new file with mode: 0644]
sys/dev/raid/hptmv/hptproc.c [new file with mode: 0644]
sys/dev/raid/hptmv/i386-elf.raid.o.uu [new file with mode: 0644]
sys/dev/raid/hptmv/ioctl.c [new file with mode: 0644]
sys/dev/raid/hptmv/mv.c [new file with mode: 0644]
sys/dev/raid/hptmv/mvOs.h [new file with mode: 0644]
sys/dev/raid/hptmv/mvSata.h [new file with mode: 0644]
sys/dev/raid/hptmv/mvStorageDev.h [new file with mode: 0644]
sys/dev/raid/hptmv/osbsd.h [new file with mode: 0644]
sys/dev/raid/hptmv/raid5n.h [new file with mode: 0644]
sys/dev/raid/hptmv/readme.txt [new file with mode: 0644]
sys/dev/raid/hptmv/vdevice.h [new file with mode: 0644]
sys/dev/raid/hptmv/x86_64-elf.raid.o.uu [new file with mode: 0644]
sys/platform/pc32/conf/files
sys/platform/pc64/conf/files

index 48f548a..052208d 100644 (file)
@@ -99,6 +99,7 @@ MAN=  aac.4 \
        gusc.4 \
        hifn.4 \
        hptiop.4 \
+       hptmv.4 \
        ichsmb.4 \
        icmp.4 \
        icmp6.4 \
index 8a76b95..d2cba69 100644 (file)
@@ -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 (file)
index 0000000..acef40d
--- /dev/null
@@ -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.
index 38a4b87..3a0ce75 100644 (file)
@@ -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
index dc73e58..9d88a80 100644 (file)
@@ -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
index 57ba282..371a30e 100644 (file)
@@ -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
index bf3654e..f7ad2ad 100644 (file)
@@ -1270,6 +1270,10 @@ options  MFI_DEBUG
 device         arcmsr          # Areca SATA II RAID
 
 #
+# Highpoint RocketRAID 182x.
+device         hptmv
+
+#
 # Highpoint RocketRaid 3xxx series SATA RAID
 device         hptiop
 
index 9c42e01..e242026 100644 (file)
@@ -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
index 04adf51..b0cd69a 100644 (file)
@@ -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
index 04e5b18..8a343fc 100644 (file)
@@ -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 <bsd.subdir.mk>
diff --git a/sys/dev/raid/hptmv/Makefile b/sys/dev/raid/hptmv/Makefile
new file mode 100644 (file)
index 0000000..cc8c8dd
--- /dev/null
@@ -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 <bsd.kmod.mk>
diff --git a/sys/dev/raid/hptmv/access601.h b/sys/dev/raid/hptmv/access601.h
new file mode 100644 (file)
index 0000000..6c8e458
--- /dev/null
@@ -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 (file)
index 0000000..126e3f8
--- /dev/null
@@ -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 (file)
index 0000000..5bda300
--- /dev/null
@@ -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 (file)
index 0000000..e2d3081
--- /dev/null
@@ -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 (file)
index 0000000..15aed04
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/callout.h>
+#include <sys/signalvar.h>
+#include <sys/eventhandler.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
+
+#include <sys/lock.h>
+#include <sys/module.h>
+
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <dev/raid/hptmv/global.h>
+#include <dev/raid/hptmv/hptintf.h>
+#include <dev/raid/hptmv/osbsd.h>
+#include <dev/raid/hptmv/access601.h>
+
+
+#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;i<MV_SATA_CHANNELS_NUM;i++) {
+               pPhysical = &(pAdapter->VDevices[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(j<MAX_VDEVICE_PER_VBUS && pVBus->pVDevice[j]) j++;
+                       if(j<MAX_VDEVICE_PER_VBUS){
+                               pVBus->pVDevice[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;i<MV_SATA_CHANNELS_NUM;i++)
+       {
+               pVDevice = &pAdapter->VDevices[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; i<MAX_COMMAND_BLOCKS_FOR_EACH_VBUS; i++) {
+               FreeCommand(_VBUS_P &(pAdapter->pCommandBlocks[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; i<PRD_TABLES_FOR_VBUS; i++)
+               {
+/*                     KdPrint(("i=%d,pAdapter->pFreePRDLink=%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;channel<MV_SATA_CHANNELS_NUM;channel++) {
+               pVDev = _vbus_p->pVDevice[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; i<MAX_VDEVICE_PER_VBUS; i++) {
+               PVDevice pVDev = pAdapter->VBus.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;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_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 (file)
index 0000000..5f4635a
--- /dev/null
@@ -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 <dev/raid/hptmv/mvOs.h>
+#include <dev/raid/hptmv/mvSata.h>
+#include <dev/raid/hptmv/mvStorageDev.h>
+
+#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 <dev/raid/hptmv/atapi.h>
+#include <dev/raid/hptmv/command.h>
+#include <dev/raid/hptmv/array.h>
+#include <dev/raid/hptmv/raid5n.h>
+#include <dev/raid/hptmv/vdevice.h>
+
+#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 (file)
index 0000000..3a78629
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <dev/raid/hptmv/global.h>
+#include <dev/raid/hptmv/hptintf.h>
+#include <dev/raid/hptmv/osbsd.h>
+#include <dev/raid/hptmv/access601.h>
+
+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;i<MAX_ARRAY_PER_VBUS;i++)
+               {
+                       pVDevice=ArrayTables(i);
+                       if ((pVDevice->u.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; i<MAX_ARRAY_MEMBERS; i++)
+               pArrayInfo->Members[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; i<MAX_ARRAY_MEMBERS_V2; i++)
+               pArrayInfo->Members[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<count; j++)
+                               if (pIds[j]==VDEV_TO_ID(pLogical)) goto next;
+                       pIds[count++] = VDEV_TO_ID(pLogical);
+                       if (count>=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 &param2);
+}
+
+#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 (nOutBufferSize<sizeof(DRIVER_CAPABILITIES)) return -1;
+                       cap = (PDRIVER_CAPABILITIES)lpOutBuffer;
+
+                       if(hpt_get_driver_capabilities(cap))
+                               return -1;
+               }
+               break;
+
+       case HPT_IOCTL_GET_CONTROLLER_VENID:
+               {
+                       DWORD id = ((DWORD*)lpInBuffer)[0];
+                       IAL_ADAPTER_T *pAdapTemp;
+                       int iControllerCount = 0;
+
+                       for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
+                               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 (file)
index 0000000..4eec0a5
--- /dev/null
@@ -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 (file)
index 0000000..87f1da9
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <machine/stdarg.h>
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <dev/raid/hptmv/global.h>
+#include <dev/raid/hptmv/hptintf.h>
+#include <dev/raid/hptmv/osbsd.h>
+#include <dev/raid/hptmv/access601.h>
+
+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;i<MV_SATA_CHANNELS_NUM;i++)
+                               if(i == ichan)
+                                   goto rebuild;
+
+               return -EINVAL;
+
+rebuild:
+               pVDev = &pAdapter->VDevices[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,
+          &n