It was tested with an 1820A card.
Thanks to HighPoint and FreeBSD (from which it was ported).
gusc.4 \
hifn.4 \
hptiop.4 \
+ hptmv.4 \
ichsmb.4 \
icmp.4 \
icmp6.4 \
.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
--- /dev/null
+.\"
+.\" 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.
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
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
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
device arcmsr # Areca SATA II RAID
#
+# Highpoint RocketRAID 182x.
+device hptmv
+
+#
# Highpoint RocketRaid 3xxx series SATA RAID
device hptiop
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
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
-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>
--- /dev/null
+#
+# 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>
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 ¶m2);
+}
+
+#ifdef SUPPORT_OLD_ARRAY
+/* this is only for old RAID 0/1 */
+int old_add_disk_to_raid01(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk)
+{
+ PVDevice pArray1 = ID_TO_VDEV(idArray);
+ PVDevice pArray2 = 0;
+ PVDevice pDisk = ID_TO_VDEV(idDisk);
+ int i;
+ IAL_ADAPTER_T *pAdapter = gIal_Adapter;
+
+ if (pArray1->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
+
+ if(pDisk->u.disk.dDeRealCapacity < (pArray1->VDeviceCapacity / 2))
+ return -1;
+
+ pArray2 = pArray1->u.array.pMember[1];
+ if(pArray2 == NULL) {
+ /* create a Stripe */
+ mArGetArrayTable(pArray2);
+ pArray2->VDeviceType = VD_RAID_0;
+ pArray2->u.array.dArStamp = GetStamp();
+ pArray2->vf_format_v2 = 1;
+ pArray2->u.array.rf_broken = 1;
+ pArray2->u.array.bArBlockSizeShift = pArray1->u.array.bArBlockSizeShift;
+ pArray2->u.array.bStripeWitch = (1 << pArray2->u.array.bArBlockSizeShift);
+ pArray2->u.array.bArnMember = 2;
+ pArray2->VDeviceCapacity = pArray1->VDeviceCapacity;
+ pArray2->pfnSendCommand = pfnSendCommand[pArray2->VDeviceType];
+ pArray2->pfnDeviceFailed = pfnDeviceFailed[pArray1->VDeviceType];
+ memcpy(pArray2->u.array.ArrayName, pArray1->u.array.ArrayName, MAX_ARRAY_NAME);
+ pArray2->pParent = pArray1;
+ pArray2->bSerialNumber = 1;
+ pArray1->u.array.pMember[1] = pArray2;
+ pArray1->u.array.bArRealnMember++;
+ }
+
+ for(i = 0; i < pArray2->u.array.bArnMember; i++)
+ if((pArray2->u.array.pMember[i] == NULL) || !pArray2->u.array.pMember[i]->vf_online)
+ {
+ if(pArray2->u.array.pMember[i] != NULL)
+ pArray2->u.array.pMember[i]->pParent = NULL;
+ pArray2->u.array.pMember[i] = pDisk;
+ goto find;
+ }
+ return -1;
+
+find:
+ UnregisterVDevice(pDisk);
+ pDisk->VDeviceType = VD_SINGLE_DISK;
+ pDisk->bSerialNumber = i;
+ pDisk->pParent = pArray2;
+ pDisk->vf_format_v2 = 1;
+ pDisk->u.disk.dDeHiddenLba = i? 10 : 0;
+ pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity;
+ pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray2->VDeviceType];
+
+ pArray2->u.array.bArRealnMember++;
+ if(pArray2->u.array.bArnMember == pArray2->u.array.bArRealnMember){
+ pArray2->vf_online = 1;
+ pArray2->u.array.rf_broken = 0;
+ }
+
+ if(pArray1->u.array.pMember[0]->vf_online && pArray1->u.array.pMember[1]->vf_online){
+ pArray1->u.array.bArRealnMember = pArray1->u.array.bArnMember;
+ pArray1->u.array.rf_broken = 0;
+ pArray1->u.array.rf_need_rebuild = 1;
+ pArray1->u.array.rf_auto_rebuild = 1;
+
+ }
+ pArray1->u.array.RebuildSectors = 0;
+ pArray1->u.array.dArStamp = GetStamp();
+ SyncArrayInfo(pArray1);
+ return 1;
+}
+#endif
+
+int hpt_add_disk_to_array(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk)
+{
+ int i;
+
+ LBA_T Capacity;
+ PVDevice pArray = ID_TO_VDEV(idArray);
+ PVDevice pDisk = ID_TO_VDEV(idDisk);
+
+ if((idArray == 0) || (idDisk == 0)) return -1;
+ if(check_VDevice_valid(pArray) || check_VDevice_valid(pDisk)) return -1;
+ if(!pArray->u.array.rf_broken) return -1;
+
+ if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5)
+ return -1;
+ if((pDisk->VDeviceType != VD_SINGLE_DISK) && (pDisk->VDeviceType != VD_SPARE))
+ return -1;
+
+#ifdef SUPPORT_OLD_ARRAY
+ /* RAID 0 + 1 */
+ if (pArray->vf_format_v2 && pArray->VDeviceType==VD_RAID_1 &&
+ pArray->u.array.pMember[0] &&
+ mIsArray(pArray->u.array.pMember[0]))
+ {
+ if(old_add_disk_to_raid01(_VBUS_P idArray, idDisk))
+ return 0;
+ else
+ return -1;
+ }
+#endif
+
+ Capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember - 1);
+
+ if (pArray->vf_format_v2) {
+ if(pDisk->u.disk.dDeRealCapacity < Capacity) return -1;
+ }
+ else
+ if(pDisk->VDeviceCapacity < Capacity) return -1;
+
+ if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
+
+ for(i = 0; i < pArray->u.array.bArnMember; i++)
+ if((pArray->u.array.pMember[i] == 0) || !pArray->u.array.pMember[i]->vf_online)
+ {
+ if(pArray->u.array.pMember[i] != NULL)
+ pArray->u.array.pMember[i]->pParent = NULL;
+ pArray->u.array.pMember[i] = pDisk;
+ goto find;
+ }
+ return -1;
+
+find:
+ UnregisterVDevice(pDisk);
+ pDisk->VDeviceType = VD_SINGLE_DISK;
+ pDisk->bSerialNumber = i;
+ pDisk->pParent = pArray;
+ if (pArray->VDeviceType==VD_RAID_5) pDisk->vf_cache_disk = 1;
+ pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType];
+ if (pArray->vf_format_v2) {
+ pDisk->vf_format_v2 = 1;
+ pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity;
+ }
+
+ pArray->u.array.bArRealnMember++;
+ if(pArray->u.array.bArnMember == pArray->u.array.bArRealnMember)
+ {
+ pArray->u.array.rf_need_rebuild = 1;
+ pArray->u.array.RebuildSectors = 0;
+ pArray->u.array.rf_auto_rebuild = 1;
+ pArray->u.array.rf_broken = 0;
+ }
+ pArray->u.array.RebuildSectors = 0;
+
+ /* sync the whole array */
+ while (pArray->pParent) pArray = pArray->pParent;
+ pArray->u.array.dArStamp = GetStamp();
+ SyncArrayInfo(pArray);
+ return 0;
+}
+
+int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk)
+{
+ PVDevice pVDevice = ID_TO_VDEV(idDisk);
+ DECLARE_BUFFER(PUCHAR, pbuffer);
+
+ if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1;
+ if (pVDevice->VDeviceType != VD_SINGLE_DISK || pVDevice->pParent)
+ return -1;
+
+ if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
+
+ UnregisterVDevice(pVDevice);
+ pVDevice->VDeviceType = VD_SPARE;
+ pVDevice->vf_bootmark = 0;
+
+ ZeroMemory((char *)pbuffer, 512);
+ fDeReadWrite(&pVDevice->u.disk, 0, IDE_COMMAND_WRITE, pbuffer);
+ SyncArrayInfo(pVDevice);
+ return 0;
+}
+
+int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk)
+{
+ PVDevice pVDevice = ID_TO_VDEV(idDisk);
+
+ if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1;
+
+ if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
+
+ pVDevice->VDeviceType = VD_SINGLE_DISK;
+
+ SyncArrayInfo(pVDevice);
+ RegisterVDevice(pVDevice);
+ return 0;
+}
+
+int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo)
+{
+ PVDevice pVDevice = ID_TO_VDEV(idArray);
+
+ if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1;
+ if (!mIsArray(pVDevice)) return -1;
+
+ /* if the pVDevice isn't a top level, return -1; */
+ if(pVDevice->pParent != NULL) return -1;
+
+ if (pVDevice->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
+
+ if (pInfo->ValidFields & AAIF_NAME) {
+ memset(pVDevice->u.array.ArrayName, 0, MAX_ARRAY_NAME);
+ memcpy(pVDevice->u.array.ArrayName, pInfo->Name, sizeof(pInfo->Name));
+ pVDevice->u.array.rf_need_sync = 1;
+ }
+
+ if (pInfo->ValidFields & AAIF_DESCRIPTION) {
+ memcpy(pVDevice->u.array.Description, pInfo->Description, sizeof(pInfo->Description));
+ pVDevice->u.array.rf_need_sync = 1;
+ }
+
+ if (pVDevice->u.array.rf_need_sync)
+ SyncArrayInfo(pVDevice);
+ return 0;
+}
+
+static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo)
+{
+ PVDevice pVDevice = ID_TO_VDEV(idDisk);
+
+ if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1;
+ if (mIsArray(pVDevice))
+ return -1;
+
+ if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
+
+ /* TODO */
+ return 0;
+ }
+
+static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo)
+{
+ PVDevice pVDevice = ID_TO_VDEV(idDisk);
+ int sync = 0;
+
+ if(idDisk==0 || check_VDevice_valid(pVDevice)) return -1;
+ if (mIsArray(pVDevice))
+ return -1;
+
+ if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
+
+ if (pInfo->ValidFields & ADIF_MODE) {
+ pVDevice->u.disk.bDeModeSetting = pInfo->DeviceModeSetting;
+ pVDevice->u.disk.bDeUserSelectMode = pInfo->DeviceModeSetting;
+ pVDevice->u.disk.df_user_mode_set = 1;
+ fDeSelectMode((PDevice)&(pVDevice->u.disk), (UCHAR)pInfo->DeviceModeSetting);
+ sync = 1;
+}
+
+ if (pInfo->ValidFields & ADIF_TCQ) {
+ if (fDeSetTCQ(&pVDevice->u.disk, pInfo->TCQEnabled, 0)) {
+ pVDevice->u.disk.df_tcq_set = 1;
+ pVDevice->u.disk.df_tcq = pInfo->TCQEnabled!=0;
+ sync = 1;
+}
+ }
+
+ if (pInfo->ValidFields & ADIF_NCQ) {
+ if (fDeSetNCQ(&pVDevice->u.disk, pInfo->NCQEnabled, 0)) {
+ pVDevice->u.disk.df_ncq_set = 1;
+ pVDevice->u.disk.df_ncq = pInfo->NCQEnabled!=0;
+ sync = 1;
+ }
+ }
+
+ if (pInfo->ValidFields & ADIF_WRITE_CACHE) {
+ if (fDeSetWriteCache(&pVDevice->u.disk, pInfo->WriteCacheEnabled)) {
+ pVDevice->u.disk.df_write_cache_set = 1;
+ pVDevice->u.disk.df_write_cache = pInfo->WriteCacheEnabled!=0;
+ sync = 1;
+ }
+ }
+
+ if (pInfo->ValidFields & ADIF_READ_AHEAD) {
+ if (fDeSetReadAhead(&pVDevice->u.disk, pInfo->ReadAheadEnabled)) {
+ pVDevice->u.disk.df_read_ahead_set = 1;
+ pVDevice->u.disk.df_read_ahead = pInfo->ReadAheadEnabled!=0;
+ sync = 1;
+ }
+ }
+
+ if (sync)
+ SyncArrayInfo(pVDevice);
+ return 0;
+}
+
+#endif
+
+/* hpt_default_ioctl()
+ * This is a default implementation. The platform dependent part
+ * may reuse this function and/or use it own implementation for
+ * each ioctl function.
+ */
+int hpt_default_ioctl(_VBUS_ARG
+ DWORD dwIoControlCode, /* operation control code */
+ PVOID lpInBuffer, /* input data buffer */
+ DWORD nInBufferSize, /* size of input data buffer */
+ PVOID lpOutBuffer, /* output data buffer */
+ DWORD nOutBufferSize, /* size of output data buffer */
+ PDWORD lpBytesReturned /* byte count */
+ )
+{
+ switch(dwIoControlCode) {
+
+ case HPT_IOCTL_GET_VERSION:
+
+ if (nInBufferSize != 0) return -1;
+ if (nOutBufferSize != sizeof(DWORD)) return -1;
+ *((DWORD*)lpOutBuffer) = HPT_INTERFACE_VERSION;
+ break;
+
+ case HPT_IOCTL_GET_CONTROLLER_COUNT:
+
+ if (nOutBufferSize!=sizeof(DWORD)) return -1;
+ *(PDWORD)lpOutBuffer = hpt_get_controller_count();
+ break;
+
+ case HPT_IOCTL_GET_CONTROLLER_INFO:
+ {
+ int id;
+ PCONTROLLER_INFO pInfo;
+
+ if (nInBufferSize!=sizeof(DWORD)) return -1;
+ if (nOutBufferSize!=sizeof(CONTROLLER_INFO)) return -1;
+
+ id = *(DWORD *)lpInBuffer;
+ pInfo = (PCONTROLLER_INFO)lpOutBuffer;
+ if (hpt_get_controller_info(id, pInfo)!=0)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_GET_CHANNEL_INFO:
+ {
+ int id, bus;
+ PCHANNEL_INFO pInfo;
+
+ if (nInBufferSize!=8) return -1;
+ if (nOutBufferSize!=sizeof(CHANNEL_INFO)) return -1;
+
+ id = *(DWORD *)lpInBuffer;
+ bus = ((DWORD *)lpInBuffer)[1];
+ pInfo = (PCHANNEL_INFO)lpOutBuffer;
+
+ if (hpt_get_channel_info(id, bus, pInfo)!=0)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_GET_LOGICAL_DEVICES:
+ {
+ DWORD nMax;
+ DEVICEID *pIds;
+
+ if (nInBufferSize!=sizeof(DWORD)) return -1;
+ nMax = *(DWORD *)lpInBuffer;
+ if (nOutBufferSize < sizeof(DWORD)+sizeof(DWORD)*nMax) return -1;
+
+ pIds = ((DEVICEID *)lpOutBuffer)+1;
+ *(DWORD*)lpOutBuffer = hpt_get_logical_devices(pIds, nMax);
+ }
+ break;
+
+ case HPT_IOCTL_GET_DEVICE_INFO:
+ {
+ DEVICEID id;
+ PLOGICAL_DEVICE_INFO pInfo;
+
+ if (nInBufferSize!=sizeof(DEVICEID)) return -1;
+ if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO)) return -1;
+
+ id = *(DWORD *)lpInBuffer;
+ if (id == INVALID_DEVICEID) return -1;
+
+ pInfo = (PLOGICAL_DEVICE_INFO)lpOutBuffer;
+ memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO));
+
+ if (hpt_get_device_info(id, pInfo)!=0)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_GET_DEVICE_INFO_V2:
+ {
+ DEVICEID id;
+ PLOGICAL_DEVICE_INFO_V2 pInfo;
+
+ if (nInBufferSize!=sizeof(DEVICEID)) return -1;
+ if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO_V2)) return -1;
+
+ id = *(DWORD *)lpInBuffer;
+ if (id == INVALID_DEVICEID) return -1;
+
+ pInfo = (PLOGICAL_DEVICE_INFO_V2)lpOutBuffer;
+ memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO_V2));
+
+ if (hpt_get_device_info_v2(id, pInfo)!=0)
+ return -1;
+ }
+ break;
+
+#ifdef SUPPORT_ARRAY
+ case HPT_IOCTL_CREATE_ARRAY:
+ {
+ if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS)) return -1;
+ if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
+
+ *(DEVICEID *)lpOutBuffer = hpt_create_array(_VBUS_P (PCREATE_ARRAY_PARAMS)lpInBuffer);
+
+ if(*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_CREATE_ARRAY_V2:
+ {
+ if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS_V2)) return -1;
+ if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
+
+ *(DEVICEID *)lpOutBuffer = hpt_create_array_v2(_VBUS_P (PCREATE_ARRAY_PARAMS_V2)lpInBuffer);
+
+ if (*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_SET_ARRAY_INFO:
+ {
+ DEVICEID idArray;
+ PALTERABLE_ARRAY_INFO pInfo;
+
+ if (nInBufferSize!=sizeof(HPT_SET_ARRAY_INFO)) return -1;
+ if (nOutBufferSize!=0) return -1;
+
+ idArray = ((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray;
+ pInfo = &((PHPT_SET_ARRAY_INFO)lpInBuffer)->Info;
+
+ if(hpt_set_array_info(_VBUS_P idArray, pInfo))
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_SET_DEVICE_INFO:
+ {
+ DEVICEID idDisk;
+ PALTERABLE_DEVICE_INFO pInfo;
+
+ if (nInBufferSize!=sizeof(HPT_SET_DEVICE_INFO)) return -1;
+ if (nOutBufferSize!=0) return -1;
+
+ idDisk = ((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk;
+ pInfo = &((PHPT_SET_DEVICE_INFO)lpInBuffer)->Info;
+ if(hpt_set_device_info(_VBUS_P idDisk, pInfo) != 0)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_SET_DEVICE_INFO_V2:
+ {
+ DEVICEID idDisk;
+ PALTERABLE_DEVICE_INFO_V2 pInfo;
+
+ if (nInBufferSize < sizeof(HPT_SET_DEVICE_INFO_V2)) return -1;
+ if (nOutBufferSize!=0) return -1;
+
+ idDisk = ((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk;
+ pInfo = &((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->Info;
+ if(hpt_set_device_info_v2(_VBUS_P idDisk, pInfo) != 0)
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_SET_BOOT_MARK:
+ {
+ DEVICEID id;
+ PVDevice pTop;
+ int i;
+ IAL_ADAPTER_T *pAdapter = gIal_Adapter;
+ PVBus pVBus;
+
+ if (nInBufferSize!=sizeof(DEVICEID)) return -1;
+ id = *(DEVICEID *)lpInBuffer;
+ while(pAdapter != 0)
+ {
+ pVBus = &pAdapter->VBus;
+ for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
+ {
+ if(!(pTop = pVBus->pVDevice[i])) continue;
+ if (pTop->pVBus!=_vbus_p) return -1;
+ while (pTop->pParent) pTop = pTop->pParent;
+ if (id==0 && pTop->vf_bootmark)
+ pTop->vf_bootmark = 0;
+ else if (pTop==ID_TO_VDEV(id) && !pTop->vf_bootmark)
+ pTop->vf_bootmark = 1;
+ else
+ continue;
+ SyncArrayInfo(pTop);
+ break;
+ }
+ pAdapter = pAdapter->next;
+ }
+ }
+ break;
+
+ case HPT_IOCTL_ADD_SPARE_DISK:
+ {
+ DEVICEID id;
+
+ if (nInBufferSize!=sizeof(DEVICEID)) return -1;
+ if (nOutBufferSize!=0) return -1;
+
+ id = *(DEVICEID *)lpInBuffer;
+
+ if(hpt_add_spare_disk(_VBUS_P id))
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_REMOVE_SPARE_DISK:
+ {
+ DEVICEID id;
+
+ if (nInBufferSize!=sizeof(DEVICEID)) return -1;
+ if (nOutBufferSize!=0) return -1;
+
+ id = *(DEVICEID *)lpInBuffer;
+
+ if(hpt_remove_spare_disk(_VBUS_P id))
+ return -1;
+ }
+ break;
+
+ case HPT_IOCTL_ADD_DISK_TO_ARRAY:
+ {
+ DEVICEID id1,id2;
+ id1 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray;
+ id2 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idDisk;
+
+ if (nInBufferSize != sizeof(HPT_ADD_DISK_TO_ARRAY)) return -1;
+ if (nOutBufferSize != 0) return -1;
+
+ if(hpt_add_disk_to_array(_VBUS_P id1, id2))
+ return -1;
+ }
+ break;
+#endif
+ case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
+ {
+ PDRIVER_CAPABILITIES cap;
+ if (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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_are