xref: /dflybsd-src/sys/dev/raid/hptmv/ioctl.c (revision 613a3753e74cbb972288e2c02fb5117c9fbc0f01)
135878b55SSascha Wildner /*
235878b55SSascha Wildner  * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
335878b55SSascha Wildner  * All rights reserved.
435878b55SSascha Wildner  *
535878b55SSascha Wildner  * Redistribution and use in source and binary forms, with or without
635878b55SSascha Wildner  * modification, are permitted provided that the following conditions
735878b55SSascha Wildner  * are met:
835878b55SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
935878b55SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
1035878b55SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1135878b55SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
1235878b55SSascha Wildner  *    documentation and/or other materials provided with the distribution.
1335878b55SSascha Wildner  *
1435878b55SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1535878b55SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1635878b55SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1735878b55SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1835878b55SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1935878b55SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2035878b55SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2135878b55SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2235878b55SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2335878b55SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2435878b55SSascha Wildner  * SUCH DAMAGE.
2535878b55SSascha Wildner  *
2635878b55SSascha Wildner  * $FreeBSD: src/sys/dev/hptmv/ioctl.c,v 1.9 2009/04/07 16:38:25 delphij Exp $
2735878b55SSascha Wildner  */
2835878b55SSascha Wildner /*
2935878b55SSascha Wildner  * ioctl.c   ioctl interface implementation
3035878b55SSascha Wildner  */
3135878b55SSascha Wildner #include <sys/param.h>
3235878b55SSascha Wildner #include <sys/systm.h>
3335878b55SSascha Wildner #include <sys/kernel.h>
3435878b55SSascha Wildner #include <sys/malloc.h>
3535878b55SSascha Wildner 
3635878b55SSascha Wildner #ifndef __KERNEL__
3735878b55SSascha Wildner #define __KERNEL__
3835878b55SSascha Wildner #endif
3935878b55SSascha Wildner 
4035878b55SSascha Wildner #include <dev/raid/hptmv/global.h>
4135878b55SSascha Wildner #include <dev/raid/hptmv/hptintf.h>
4235878b55SSascha Wildner #include <dev/raid/hptmv/osbsd.h>
4335878b55SSascha Wildner #include <dev/raid/hptmv/access601.h>
4435878b55SSascha Wildner 
4535878b55SSascha Wildner #pragma pack(1)
4635878b55SSascha Wildner 
4735878b55SSascha Wildner typedef struct _HPT_REBUILD_PARAM
4835878b55SSascha Wildner {
4935878b55SSascha Wildner 	DEVICEID idMirror;
5035878b55SSascha Wildner 	DWORD Lba;
5135878b55SSascha Wildner 	UCHAR nSector;
5235878b55SSascha Wildner } HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM;
5335878b55SSascha Wildner 
5435878b55SSascha Wildner #pragma pack()
5535878b55SSascha Wildner 
5635878b55SSascha Wildner #define MAX_EVENTS 10
5735878b55SSascha Wildner static HPT_EVENT hpt_event_queue[MAX_EVENTS];
5835878b55SSascha Wildner static int event_queue_head=0, event_queue_tail=0;
5935878b55SSascha Wildner 
6035878b55SSascha Wildner static int hpt_get_event(PHPT_EVENT pEvent);
6135878b55SSascha Wildner static int hpt_set_array_state(DEVICEID idArray, DWORD state);
62c898d682SSascha Wildner static void lock_driver_idle(IAL_ADAPTER_T *pAdapter);
6335878b55SSascha Wildner static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd);
6435878b55SSascha Wildner static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd,
6535878b55SSascha Wildner     FPSCAT_GATH pSgTable, int logical);
6635878b55SSascha Wildner 
6735878b55SSascha Wildner static void
get_disk_location(PDevice pDev,int * controller,int * channel)6835878b55SSascha Wildner get_disk_location(PDevice pDev, int *controller, int *channel)
6935878b55SSascha Wildner {
7035878b55SSascha Wildner 	IAL_ADAPTER_T *pAdapTemp;
7135878b55SSascha Wildner 	int i, j;
7235878b55SSascha Wildner 
7335878b55SSascha Wildner 	*controller = *channel = 0;
7435878b55SSascha Wildner 
7535878b55SSascha Wildner 	for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) {
7635878b55SSascha Wildner 		for (j=0; j<MV_SATA_CHANNELS_NUM; j++) {
7735878b55SSascha Wildner 			if (pDev == &pAdapTemp->VDevices[j].u.disk) {
7835878b55SSascha Wildner 				*controller = i;
7935878b55SSascha Wildner 				*channel = j;
8035878b55SSascha Wildner 				return;
8135878b55SSascha Wildner 			}
8235878b55SSascha Wildner 		}
8335878b55SSascha Wildner 	}
8435878b55SSascha Wildner }
8535878b55SSascha Wildner 
8635878b55SSascha Wildner static int
event_queue_add(PHPT_EVENT pEvent)8735878b55SSascha Wildner event_queue_add(PHPT_EVENT pEvent)
8835878b55SSascha Wildner {
8935878b55SSascha Wildner 	int p;
9035878b55SSascha Wildner 	p = (event_queue_tail + 1) % MAX_EVENTS;
9135878b55SSascha Wildner 	if (p==event_queue_head)
9235878b55SSascha Wildner 	{
9335878b55SSascha Wildner 		return -1;
9435878b55SSascha Wildner 	}
9535878b55SSascha Wildner 	hpt_event_queue[event_queue_tail] = *pEvent;
9635878b55SSascha Wildner 	event_queue_tail = p;
9735878b55SSascha Wildner 	return 0;
9835878b55SSascha Wildner }
9935878b55SSascha Wildner 
10035878b55SSascha Wildner static int
event_queue_remove(PHPT_EVENT pEvent)10135878b55SSascha Wildner event_queue_remove(PHPT_EVENT pEvent)
10235878b55SSascha Wildner {
10335878b55SSascha Wildner 	if (event_queue_head != event_queue_tail)
10435878b55SSascha Wildner 	{
10535878b55SSascha Wildner 		*pEvent = hpt_event_queue[event_queue_head];
10635878b55SSascha Wildner 		event_queue_head++;
10735878b55SSascha Wildner 		event_queue_head %= MAX_EVENTS;
10835878b55SSascha Wildner 		return 0;
10935878b55SSascha Wildner 	}
11035878b55SSascha Wildner 	return -1;
11135878b55SSascha Wildner }
11235878b55SSascha Wildner 
11335878b55SSascha Wildner void HPTLIBAPI
ioctl_ReportEvent(UCHAR event,PVOID param)11435878b55SSascha Wildner ioctl_ReportEvent(UCHAR event, PVOID param)
11535878b55SSascha Wildner {
11635878b55SSascha Wildner 	HPT_EVENT e;
11735878b55SSascha Wildner 	ZeroMemory(&e, sizeof(e));
11835878b55SSascha Wildner 	e.EventType = event;
11935878b55SSascha Wildner 	switch(event)
12035878b55SSascha Wildner 	{
12135878b55SSascha Wildner 		case ET_INITIALIZE_ABORTED:
12235878b55SSascha Wildner 		case ET_INITIALIZE_FAILED:
12335878b55SSascha Wildner 			memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME);
12435878b55SSascha Wildner 		case ET_INITIALIZE_STARTED:
12535878b55SSascha Wildner 		case ET_INITIALIZE_FINISHED:
12635878b55SSascha Wildner 
12735878b55SSascha Wildner 		case ET_REBUILD_STARTED:
12835878b55SSascha Wildner 		case ET_REBUILD_ABORTED:
12935878b55SSascha Wildner 		case ET_REBUILD_FAILED:
13035878b55SSascha Wildner 		case ET_REBUILD_FINISHED:
13135878b55SSascha Wildner 
13235878b55SSascha Wildner 		case ET_VERIFY_STARTED:
13335878b55SSascha Wildner 		case ET_VERIFY_ABORTED:
13435878b55SSascha Wildner 		case ET_VERIFY_FAILED:
13535878b55SSascha Wildner 		case ET_VERIFY_FINISHED:
13635878b55SSascha Wildner 		case ET_VERIFY_DATA_ERROR:
13735878b55SSascha Wildner 
13835878b55SSascha Wildner 		case ET_SPARE_TOOK_OVER:
13935878b55SSascha Wildner 		case ET_DEVICE_REMOVED:
14035878b55SSascha Wildner 		case ET_DEVICE_PLUGGED:
14135878b55SSascha Wildner 		case ET_DEVICE_ERROR:
14235878b55SSascha Wildner 			e.DeviceID = VDEV_TO_ID((PVDevice)param);
14335878b55SSascha Wildner 			break;
14435878b55SSascha Wildner 
14535878b55SSascha Wildner 		default:
14635878b55SSascha Wildner 			break;
14735878b55SSascha Wildner 	}
14835878b55SSascha Wildner 	event_queue_add(&e);
14935878b55SSascha Wildner 	if (event==ET_DEVICE_REMOVED) {
15035878b55SSascha Wildner 		int controller, channel;
15135878b55SSascha Wildner 		get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel);
15235878b55SSascha Wildner 		hpt_printk(("Device removed: controller %d channel %d\n", controller, channel));
15335878b55SSascha Wildner 	}
15435878b55SSascha Wildner }
15535878b55SSascha Wildner 
15635878b55SSascha Wildner static int
hpt_delete_array(_VBUS_ARG DEVICEID id,DWORD options)15735878b55SSascha Wildner hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options)
15835878b55SSascha Wildner {
15935878b55SSascha Wildner 	PVDevice	pArray = ID_TO_VDEV(id);
16035878b55SSascha Wildner 	BOOLEAN	del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1;
16135878b55SSascha Wildner 	int i;
16235878b55SSascha Wildner 	PVDevice pa;
16335878b55SSascha Wildner 
16435878b55SSascha Wildner 	if ((id==0) || check_VDevice_valid(pArray))
16535878b55SSascha Wildner 		return -1;
16635878b55SSascha Wildner 
16735878b55SSascha Wildner 	if(!mIsArray(pArray)) return -1;
16835878b55SSascha Wildner 
16935878b55SSascha Wildner 	if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying ||
17035878b55SSascha Wildner 		pArray->u.array.rf_initializing)
17135878b55SSascha Wildner 		return -1;
17235878b55SSascha Wildner 
17335878b55SSascha Wildner 	for(i=0; i<pArray->u.array.bArnMember; i++) {
17435878b55SSascha Wildner 		pa = pArray->u.array.pMember[i];
17535878b55SSascha Wildner 		if (pa && mIsArray(pa)) {
17635878b55SSascha Wildner 			if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying ||
17735878b55SSascha Wildner 				pa->u.array.rf_initializing)
17835878b55SSascha Wildner 				return -1;
17935878b55SSascha Wildner 		}
18035878b55SSascha Wildner 	}
18135878b55SSascha Wildner 
18235878b55SSascha Wildner 	if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
18335878b55SSascha Wildner 	fDeleteArray(_VBUS_P pArray, del_block0);
18435878b55SSascha Wildner 	return 0;
18535878b55SSascha Wildner 
18635878b55SSascha Wildner }
18735878b55SSascha Wildner 
18835878b55SSascha Wildner /* just to prevent driver from sending more commands */
nothing(_VBUS_ARG void * notused)18935878b55SSascha Wildner static void HPTLIBAPI nothing(_VBUS_ARG void *notused){}
19035878b55SSascha Wildner 
191*8406cf70SSascha Wildner static void
lock_driver_idle(IAL_ADAPTER_T * pAdapter)19235878b55SSascha Wildner lock_driver_idle(IAL_ADAPTER_T *pAdapter)
19335878b55SSascha Wildner {
19435878b55SSascha Wildner 	_VBUS_INST(&pAdapter->VBus)
195c898d682SSascha Wildner 	lock_driver();
19635878b55SSascha Wildner 	while (pAdapter->outstandingCommands) {
19735878b55SSascha Wildner 		KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands));
19835878b55SSascha Wildner 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
199c898d682SSascha Wildner 		unlock_driver();
20035878b55SSascha Wildner /*Schedule out*/
20135878b55SSascha Wildner 		tsleep(lock_driver_idle, 0, "switch", 1);
202c898d682SSascha Wildner 		lock_driver();
20335878b55SSascha Wildner 	}
20435878b55SSascha Wildner 	CheckIdleCall(_VBUS_P0);
20535878b55SSascha Wildner }
20635878b55SSascha Wildner 
Kernel_DeviceIoControl(_VBUS_ARG DWORD dwIoControlCode,PVOID lpInBuffer,DWORD nInBufferSize,PVOID lpOutBuffer,DWORD nOutBufferSize,PDWORD lpBytesReturned)20735878b55SSascha Wildner int Kernel_DeviceIoControl(_VBUS_ARG
20835878b55SSascha Wildner 							DWORD dwIoControlCode,       	/* operation control code */
20935878b55SSascha Wildner 							PVOID lpInBuffer,            	/* input data buffer */
21035878b55SSascha Wildner 							DWORD nInBufferSize,         	/* size of input data buffer */
21135878b55SSascha Wildner 							PVOID lpOutBuffer,           	/* output data buffer */
21235878b55SSascha Wildner 							DWORD nOutBufferSize,        	/* size of output data buffer */
21335878b55SSascha Wildner 							PDWORD lpBytesReturned      	/* byte count */
21435878b55SSascha Wildner 						)
21535878b55SSascha Wildner {
21635878b55SSascha Wildner 	IAL_ADAPTER_T *pAdapter;
21735878b55SSascha Wildner 
21835878b55SSascha Wildner 	switch(dwIoControlCode)	{
21935878b55SSascha Wildner 		case HPT_IOCTL_DELETE_ARRAY:
22035878b55SSascha Wildner 		{
22135878b55SSascha Wildner 			DEVICEID idArray;
22235878b55SSascha Wildner 			int iSuccess;
22335878b55SSascha Wildner 	        int i;
22435878b55SSascha Wildner 			PVDevice pArray;
22535878b55SSascha Wildner 			PVBus _vbus_p;
22635878b55SSascha Wildner 			struct cam_periph *periph = NULL;
22735878b55SSascha Wildner 
22835878b55SSascha Wildner 			if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1;
22935878b55SSascha Wildner 			if (nOutBufferSize!=sizeof(int)) return -1;
23035878b55SSascha Wildner 			idArray = *(DEVICEID *)lpInBuffer;
23135878b55SSascha Wildner 
23235878b55SSascha Wildner 			pArray = ID_TO_VDEV(idArray);
23335878b55SSascha Wildner 
23435878b55SSascha Wildner 			if((idArray == 0) || check_VDevice_valid(pArray))
23535878b55SSascha Wildner 			return -1;
23635878b55SSascha Wildner 
23735878b55SSascha Wildner 		if(!mIsArray(pArray))
23835878b55SSascha Wildner 			return -1;
23935878b55SSascha Wildner 
24035878b55SSascha Wildner 		_vbus_p=pArray->pVBus;
24135878b55SSascha Wildner 		pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
24235878b55SSascha Wildner 
24335878b55SSascha Wildner 	        for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) {
24435878b55SSascha Wildner 				if(pArray == _vbus_p->pVDevice[i])
24535878b55SSascha Wildner 				{
24635878b55SSascha Wildner 					periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
24735878b55SSascha Wildner 					if (periph != NULL && periph->refcount >= 1)
24835878b55SSascha Wildner 					{
24935878b55SSascha Wildner 						hpt_printk(("Can not delete a mounted device.\n"));
25035878b55SSascha Wildner 	                    return -1;
25135878b55SSascha Wildner 					}
25235878b55SSascha Wildner 				}
25335878b55SSascha Wildner 				/* the Mounted Disk isn't delete */
25435878b55SSascha Wildner 			}
25535878b55SSascha Wildner 
25635878b55SSascha Wildner 			iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1));
25735878b55SSascha Wildner 
25835878b55SSascha Wildner 			*(int*)lpOutBuffer = iSuccess;
25935878b55SSascha Wildner 
26035878b55SSascha Wildner 			if(iSuccess != 0)
26135878b55SSascha Wildner 				return -1;
26235878b55SSascha Wildner 			break;
26335878b55SSascha Wildner 		}
26435878b55SSascha Wildner 
26535878b55SSascha Wildner 		case HPT_IOCTL_GET_EVENT:
26635878b55SSascha Wildner 		{
26735878b55SSascha Wildner 			PHPT_EVENT pInfo;
26835878b55SSascha Wildner 
26935878b55SSascha Wildner 			if (nInBufferSize!=0) return -1;
27035878b55SSascha Wildner 			if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1;
27135878b55SSascha Wildner 
27235878b55SSascha Wildner 			pInfo = (PHPT_EVENT)lpOutBuffer;
27335878b55SSascha Wildner 
27435878b55SSascha Wildner 			if (hpt_get_event(pInfo)!=0)
27535878b55SSascha Wildner 				return -1;
27635878b55SSascha Wildner 		}
27735878b55SSascha Wildner 		break;
27835878b55SSascha Wildner 
27935878b55SSascha Wildner 		case HPT_IOCTL_SET_ARRAY_STATE:
28035878b55SSascha Wildner 		{
28135878b55SSascha Wildner 			DEVICEID idArray;
28235878b55SSascha Wildner 			DWORD state;
28335878b55SSascha Wildner 
28435878b55SSascha Wildner 			if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1;
28535878b55SSascha Wildner 			if (nOutBufferSize!=0) return -1;
28635878b55SSascha Wildner 
28735878b55SSascha Wildner 			idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray;
28835878b55SSascha Wildner 			state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state;
28935878b55SSascha Wildner 
29035878b55SSascha Wildner 			if(hpt_set_array_state(idArray, state)!=0)
29135878b55SSascha Wildner 				return -1;
29235878b55SSascha Wildner 		}
29335878b55SSascha Wildner 		break;
29435878b55SSascha Wildner 
29535878b55SSascha Wildner 		case HPT_IOCTL_RESCAN_DEVICES:
29635878b55SSascha Wildner 		{
29735878b55SSascha Wildner 			if (nInBufferSize!=0) return -1;
29835878b55SSascha Wildner 			if (nOutBufferSize!=0) return -1;
29935878b55SSascha Wildner 
30035878b55SSascha Wildner #ifndef FOR_DEMO
30135878b55SSascha Wildner 			/* stop buzzer if user perform rescan */
30235878b55SSascha Wildner 			for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
30335878b55SSascha Wildner 				if (pAdapter->beeping) {
30435878b55SSascha Wildner 					pAdapter->beeping = 0;
30535878b55SSascha Wildner 					BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
30635878b55SSascha Wildner 				}
30735878b55SSascha Wildner 			}
30835878b55SSascha Wildner #endif
30935878b55SSascha Wildner 		}
31035878b55SSascha Wildner 		break;
31135878b55SSascha Wildner 
31235878b55SSascha Wildner 		default:
31335878b55SSascha Wildner 		{
31435878b55SSascha Wildner 			PVDevice pVDev;
31535878b55SSascha Wildner 			switch(dwIoControlCode) {
31635878b55SSascha Wildner 			/* read-only ioctl functions can be called directly. */
31735878b55SSascha Wildner 			case HPT_IOCTL_GET_VERSION:
31835878b55SSascha Wildner 			case HPT_IOCTL_GET_CONTROLLER_IDS:
31935878b55SSascha Wildner 			case HPT_IOCTL_GET_CONTROLLER_COUNT:
32035878b55SSascha Wildner 			case HPT_IOCTL_GET_CONTROLLER_INFO:
32135878b55SSascha Wildner 			case HPT_IOCTL_GET_CHANNEL_INFO:
32235878b55SSascha Wildner 			case HPT_IOCTL_GET_LOGICAL_DEVICES:
32335878b55SSascha Wildner 			case HPT_IOCTL_GET_DEVICE_INFO:
32435878b55SSascha Wildner 			case HPT_IOCTL_GET_DEVICE_INFO_V2:
32535878b55SSascha Wildner 			case HPT_IOCTL_GET_EVENT:
32635878b55SSascha Wildner 			case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
32735878b55SSascha Wildner 				if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
32835878b55SSascha Wildner 					lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
32935878b55SSascha Wildner 				break;
33035878b55SSascha Wildner 
33135878b55SSascha Wildner 			default:
33235878b55SSascha Wildner 				/*
33335878b55SSascha Wildner 				 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
33435878b55SSascha Wildner 				 * wrong for second controller.
33535878b55SSascha Wildner 				 */
33635878b55SSascha Wildner 				switch(dwIoControlCode) {
33735878b55SSascha Wildner 				case HPT_IOCTL_CREATE_ARRAY:
33835878b55SSascha Wildner 					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
33935878b55SSascha Wildner 				case HPT_IOCTL_CREATE_ARRAY_V2:
34035878b55SSascha Wildner 					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break;
34135878b55SSascha Wildner 				case HPT_IOCTL_SET_ARRAY_INFO:
34235878b55SSascha Wildner 					pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
34335878b55SSascha Wildner 				case HPT_IOCTL_SET_DEVICE_INFO:
34435878b55SSascha Wildner 					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
34535878b55SSascha Wildner 				case HPT_IOCTL_SET_DEVICE_INFO_V2:
34635878b55SSascha Wildner 					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break;
34735878b55SSascha Wildner 				case HPT_IOCTL_SET_BOOT_MARK:
34835878b55SSascha Wildner 				case HPT_IOCTL_ADD_SPARE_DISK:
34935878b55SSascha Wildner 				case HPT_IOCTL_REMOVE_SPARE_DISK:
35035878b55SSascha Wildner 					pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
35135878b55SSascha Wildner 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
35235878b55SSascha Wildner 					pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
35335878b55SSascha Wildner 				default:
35435878b55SSascha Wildner 					pVDev = 0;
35535878b55SSascha Wildner 				}
35635878b55SSascha Wildner 
35735878b55SSascha Wildner 				if (pVDev && !check_VDevice_valid(pVDev)){
35835878b55SSascha Wildner 					_vbus_p = pVDev->pVBus;
35935878b55SSascha Wildner 
36035878b55SSascha Wildner 					pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
36135878b55SSascha Wildner 					/*
36235878b55SSascha Wildner 					 * create_array, and other functions can't be executed while channel is
36335878b55SSascha Wildner 					 * perform I/O commands. Wait until driver is idle.
36435878b55SSascha Wildner 					 */
365c898d682SSascha Wildner 					lock_driver_idle(pAdapter);
36635878b55SSascha Wildner 					if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
36735878b55SSascha Wildner 						lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
368c898d682SSascha Wildner 						unlock_driver();
36935878b55SSascha Wildner 						return -1;
37035878b55SSascha Wildner 					}
371c898d682SSascha Wildner 					unlock_driver();
37235878b55SSascha Wildner 				}
37335878b55SSascha Wildner 				else
37435878b55SSascha Wildner 					return -1;
37535878b55SSascha Wildner 				break;
37635878b55SSascha Wildner 			}
37735878b55SSascha Wildner 
37835878b55SSascha Wildner #ifdef SUPPORT_ARRAY
37935878b55SSascha Wildner 			switch(dwIoControlCode)
38035878b55SSascha Wildner 			{
38135878b55SSascha Wildner 				case HPT_IOCTL_CREATE_ARRAY:
38235878b55SSascha Wildner 				{
38335878b55SSascha Wildner 					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
384c898d682SSascha Wildner 					lock_driver();
38535878b55SSascha Wildner                     if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
38635878b55SSascha Wildner 				    {
38735878b55SSascha Wildner 						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
38835878b55SSascha Wildner                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
38935878b55SSascha Wildner 					}
39035878b55SSascha Wildner 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
39135878b55SSascha Wildner 				    {
39235878b55SSascha Wildner                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
39335878b55SSascha Wildner 					}
39435878b55SSascha Wildner 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
39535878b55SSascha Wildner 				    {
39635878b55SSascha Wildner                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
39735878b55SSascha Wildner 					}
398c898d682SSascha Wildner 					unlock_driver();
39935878b55SSascha Wildner                     break;
40035878b55SSascha Wildner 				}
40135878b55SSascha Wildner 
40235878b55SSascha Wildner 
40335878b55SSascha Wildner 				case HPT_IOCTL_CREATE_ARRAY_V2:
40435878b55SSascha Wildner 				{
40535878b55SSascha Wildner 					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
406c898d682SSascha Wildner 					lock_driver();
40735878b55SSascha Wildner 				             if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) {
40835878b55SSascha Wildner 						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
40935878b55SSascha Wildner 				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
41035878b55SSascha Wildner 					} else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) {
41135878b55SSascha Wildner 				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
41235878b55SSascha Wildner 					} else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) {
41335878b55SSascha Wildner 				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
41435878b55SSascha Wildner 					}
415c898d682SSascha Wildner 					unlock_driver();
41635878b55SSascha Wildner 					break;
41735878b55SSascha Wildner 				}
41835878b55SSascha Wildner 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
41935878b55SSascha Wildner 				{
42035878b55SSascha Wildner 					PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
42135878b55SSascha Wildner 					pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
42235878b55SSascha Wildner 					if(pArray->u.array.rf_rebuilding == 0)
42335878b55SSascha Wildner 					{
42435878b55SSascha Wildner 						DWORD timeout = 0;
425c898d682SSascha Wildner 						lock_driver();
42635878b55SSascha Wildner 						pArray->u.array.rf_auto_rebuild = 0;
42735878b55SSascha Wildner 						pArray->u.array.rf_abort_rebuild = 0;
42835878b55SSascha Wildner 						hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE);
429c898d682SSascha Wildner 						unlock_driver();
43035878b55SSascha Wildner 						while (!pArray->u.array.rf_rebuilding)
43135878b55SSascha Wildner 						{
43235878b55SSascha Wildner 							tsleep((caddr_t)Kernel_DeviceIoControl, 0, "pause", 1);
43335878b55SSascha Wildner 							if ( timeout >= hz*3)
43435878b55SSascha Wildner 								break;
43535878b55SSascha Wildner 							timeout ++;
43635878b55SSascha Wildner 						}
43735878b55SSascha Wildner 					}
43835878b55SSascha Wildner 					break;
43935878b55SSascha Wildner 				}
44035878b55SSascha Wildner 			}
44135878b55SSascha Wildner #endif
44235878b55SSascha Wildner             return 0;
44335878b55SSascha Wildner 		}
44435878b55SSascha Wildner 	}
44535878b55SSascha Wildner 
44635878b55SSascha Wildner 	if (lpBytesReturned)
44735878b55SSascha Wildner 		*lpBytesReturned = nOutBufferSize;
44835878b55SSascha Wildner 	return 0;
44935878b55SSascha Wildner }
45035878b55SSascha Wildner 
45135878b55SSascha Wildner static int
hpt_get_event(PHPT_EVENT pEvent)45235878b55SSascha Wildner hpt_get_event(PHPT_EVENT pEvent)
45335878b55SSascha Wildner {
454c898d682SSascha Wildner 	lock_driver();
45535878b55SSascha Wildner 	int ret = event_queue_remove(pEvent);
456c898d682SSascha Wildner 	unlock_driver();
45735878b55SSascha Wildner 	return ret;
45835878b55SSascha Wildner }
45935878b55SSascha Wildner 
46035878b55SSascha Wildner static int
hpt_set_array_state(DEVICEID idArray,DWORD state)46135878b55SSascha Wildner hpt_set_array_state(DEVICEID idArray, DWORD state)
46235878b55SSascha Wildner {
46335878b55SSascha Wildner 	IAL_ADAPTER_T *pAdapter;
46435878b55SSascha Wildner 	PVDevice pVDevice = ID_TO_VDEV(idArray);
46535878b55SSascha Wildner 	int	i;
46635878b55SSascha Wildner 	DWORD timeout = 0;
46735878b55SSascha Wildner 
46835878b55SSascha Wildner 	if(idArray == 0 || check_VDevice_valid(pVDevice))	return -1;
46935878b55SSascha Wildner 	if(!mIsArray(pVDevice))
47035878b55SSascha Wildner 		return -1;
47135878b55SSascha Wildner 	if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
47235878b55SSascha Wildner 
47335878b55SSascha Wildner 	pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
47435878b55SSascha Wildner 
47535878b55SSascha Wildner 	switch(state)
47635878b55SSascha Wildner 	{
47735878b55SSascha Wildner 		case MIRROR_REBUILD_START:
47835878b55SSascha Wildner 		{
47935878b55SSascha Wildner 			if (pVDevice->u.array.rf_rebuilding ||
48035878b55SSascha Wildner 				pVDevice->u.array.rf_verifying ||
48135878b55SSascha Wildner 				pVDevice->u.array.rf_initializing)
48235878b55SSascha Wildner 				return -1;
48335878b55SSascha Wildner 
484c898d682SSascha Wildner 			lock_driver();
48535878b55SSascha Wildner 
48635878b55SSascha Wildner 			pVDevice->u.array.rf_auto_rebuild = 0;
48735878b55SSascha Wildner 			pVDevice->u.array.rf_abort_rebuild = 0;
48835878b55SSascha Wildner 
48935878b55SSascha Wildner 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice,
49035878b55SSascha Wildner 				(UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
49135878b55SSascha Wildner 
492c898d682SSascha Wildner 			unlock_driver();
49335878b55SSascha Wildner 
49435878b55SSascha Wildner 			while (!pVDevice->u.array.rf_rebuilding)
49535878b55SSascha Wildner 			{
49635878b55SSascha Wildner 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
49735878b55SSascha Wildner 				if ( timeout >= hz*20)
49835878b55SSascha Wildner 					break;
49935878b55SSascha Wildner 				timeout ++;
50035878b55SSascha Wildner 			}
50135878b55SSascha Wildner 		}
50235878b55SSascha Wildner 
50335878b55SSascha Wildner 		break;
50435878b55SSascha Wildner 
50535878b55SSascha Wildner 		case MIRROR_REBUILD_ABORT:
50635878b55SSascha Wildner 		{
50735878b55SSascha Wildner 			for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
50835878b55SSascha Wildner 				if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
50935878b55SSascha Wildner 					hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
51035878b55SSascha Wildner 			}
51135878b55SSascha Wildner 
51235878b55SSascha Wildner 			if(pVDevice->u.array.rf_rebuilding != 1)
51335878b55SSascha Wildner 				return -1;
51435878b55SSascha Wildner 
515c898d682SSascha Wildner 			lock_driver();
51635878b55SSascha Wildner 			pVDevice->u.array.rf_abort_rebuild = 1;
517c898d682SSascha Wildner 			unlock_driver();
51835878b55SSascha Wildner 
51935878b55SSascha Wildner 			while (pVDevice->u.array.rf_abort_rebuild)
52035878b55SSascha Wildner 			{
52135878b55SSascha Wildner 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
52235878b55SSascha Wildner 				if ( timeout >= hz*20)
52335878b55SSascha Wildner 					break;
52435878b55SSascha Wildner 				timeout ++;
52535878b55SSascha Wildner 			}
52635878b55SSascha Wildner 		}
52735878b55SSascha Wildner 		break;
52835878b55SSascha Wildner 
52935878b55SSascha Wildner 		case AS_VERIFY_START:
53035878b55SSascha Wildner 		{
53135878b55SSascha Wildner 			/*if(pVDevice->u.array.rf_verifying)
53235878b55SSascha Wildner 				return -1;*/
53335878b55SSascha Wildner 			if (pVDevice->u.array.rf_rebuilding ||
53435878b55SSascha Wildner 				pVDevice->u.array.rf_verifying ||
53535878b55SSascha Wildner 				pVDevice->u.array.rf_initializing)
53635878b55SSascha Wildner 				return -1;
53735878b55SSascha Wildner 
538c898d682SSascha Wildner 			lock_driver();
53935878b55SSascha Wildner             pVDevice->u.array.RebuildSectors = 0;
54035878b55SSascha Wildner 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
541c898d682SSascha Wildner 			unlock_driver();
54235878b55SSascha Wildner 
54335878b55SSascha Wildner 			while (!pVDevice->u.array.rf_verifying)
54435878b55SSascha Wildner 			{
54535878b55SSascha Wildner 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
54635878b55SSascha Wildner 				if ( timeout >= hz*20)
54735878b55SSascha Wildner 					break;
54835878b55SSascha Wildner 				timeout ++;
54935878b55SSascha Wildner 			}
55035878b55SSascha Wildner 		}
55135878b55SSascha Wildner 		break;
55235878b55SSascha Wildner 
55335878b55SSascha Wildner 		case AS_VERIFY_ABORT:
55435878b55SSascha Wildner 		{
55535878b55SSascha Wildner 			if(pVDevice->u.array.rf_verifying != 1)
55635878b55SSascha Wildner 				return -1;
55735878b55SSascha Wildner 
558c898d682SSascha Wildner 			lock_driver();
55935878b55SSascha Wildner 			pVDevice->u.array.rf_abort_rebuild = 1;
560c898d682SSascha Wildner 			unlock_driver();
56135878b55SSascha Wildner 
56235878b55SSascha Wildner 			while (pVDevice->u.array.rf_abort_rebuild)
56335878b55SSascha Wildner 			{
56435878b55SSascha Wildner 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
56535878b55SSascha Wildner 				if ( timeout >= hz*80)
56635878b55SSascha Wildner 					break;
56735878b55SSascha Wildner 				timeout ++;
56835878b55SSascha Wildner 			}
56935878b55SSascha Wildner 		}
57035878b55SSascha Wildner 		break;
57135878b55SSascha Wildner 
57235878b55SSascha Wildner 		case AS_INITIALIZE_START:
57335878b55SSascha Wildner 		{
57435878b55SSascha Wildner 			if (pVDevice->u.array.rf_rebuilding ||
57535878b55SSascha Wildner 				pVDevice->u.array.rf_verifying ||
57635878b55SSascha Wildner 				pVDevice->u.array.rf_initializing)
57735878b55SSascha Wildner 				return -1;
57835878b55SSascha Wildner 
579c898d682SSascha Wildner 			lock_driver();
58035878b55SSascha Wildner 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
581c898d682SSascha Wildner 			unlock_driver();
58235878b55SSascha Wildner 
58335878b55SSascha Wildner 			while (!pVDevice->u.array.rf_initializing)
58435878b55SSascha Wildner 			{
58535878b55SSascha Wildner 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
58635878b55SSascha Wildner 				if ( timeout >= hz*80)
58735878b55SSascha Wildner 					break;
58835878b55SSascha Wildner 				timeout ++;
58935878b55SSascha Wildner 			}
59035878b55SSascha Wildner 		}
59135878b55SSascha Wildner 		break;
59235878b55SSascha Wildner 
59335878b55SSascha Wildner 		case AS_INITIALIZE_ABORT:
59435878b55SSascha Wildner 		{
59535878b55SSascha Wildner 			if(pVDevice->u.array.rf_initializing != 1)
59635878b55SSascha Wildner 				return -1;
59735878b55SSascha Wildner 
598c898d682SSascha Wildner 			lock_driver();
59935878b55SSascha Wildner 			pVDevice->u.array.rf_abort_rebuild = 1;
600c898d682SSascha Wildner 			unlock_driver();
60135878b55SSascha Wildner 
60235878b55SSascha Wildner 			while (pVDevice->u.array.rf_abort_rebuild)
60335878b55SSascha Wildner 			{
60435878b55SSascha Wildner 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
60535878b55SSascha Wildner 				if ( timeout >= hz*80)
60635878b55SSascha Wildner 					break;
60735878b55SSascha Wildner 				timeout ++;
60835878b55SSascha Wildner 			}
60935878b55SSascha Wildner 		}
61035878b55SSascha Wildner 		break;
61135878b55SSascha Wildner 
61235878b55SSascha Wildner 		default:
61335878b55SSascha Wildner 			return -1;
61435878b55SSascha Wildner 	}
61535878b55SSascha Wildner 
61635878b55SSascha Wildner 	return 0;
61735878b55SSascha Wildner }
61835878b55SSascha Wildner 
619*8406cf70SSascha Wildner static int HPTLIBAPI
R1ControlSgl(_VBUS_ARG PCommand pCmd,FPSCAT_GATH pSgTable,int logical)62035878b55SSascha Wildner R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
62135878b55SSascha Wildner {
62235878b55SSascha Wildner 	ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
62335878b55SSascha Wildner 	if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
62435878b55SSascha Wildner 		bufferSize<<=1;
62535878b55SSascha Wildner 	if (logical) {
62635878b55SSascha Wildner 		pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
62735878b55SSascha Wildner 		pSgTable->wSgSize = (USHORT)bufferSize;
62835878b55SSascha Wildner 		pSgTable->wSgFlag = SG_FLAG_EOT;
62935878b55SSascha Wildner 	}
63035878b55SSascha Wildner 	else {
63135878b55SSascha Wildner 		/* build physical SG table for pCmd->uCmd.R1Control.Buffer */
63235878b55SSascha Wildner 		ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
63335878b55SSascha Wildner 		ULONG length;
63435878b55SSascha Wildner 		int idx = 0;
63535878b55SSascha Wildner 
63635878b55SSascha Wildner 		v = pCmd->uCmd.R1Control.Buffer;
63735878b55SSascha Wildner 		dataPointer = (ADDRESS)fOsPhysicalAddress(v);
63835878b55SSascha Wildner 
63935878b55SSascha Wildner 		if ((ULONG_PTR)dataPointer & 0x1)
64035878b55SSascha Wildner 			return FALSE;
64135878b55SSascha Wildner 
64235878b55SSascha Wildner 		#define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
64335878b55SSascha Wildner 		#define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
64435878b55SSascha Wildner 
64535878b55SSascha Wildner 		do {
64635878b55SSascha Wildner 			if (idx >= MAX_SG_DESCRIPTORS)  return FALSE;
64735878b55SSascha Wildner 
64835878b55SSascha Wildner 			pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
64935878b55SSascha Wildner 			currvaddr = v;
65035878b55SSascha Wildner 			currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
65135878b55SSascha Wildner 
65235878b55SSascha Wildner 
65335878b55SSascha Wildner 			do {
65435878b55SSascha Wildner 				nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
65535878b55SSascha Wildner 				nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
65635878b55SSascha Wildner 
65735878b55SSascha Wildner 				if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
65835878b55SSascha Wildner 				nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
65935878b55SSascha Wildner 
66035878b55SSascha Wildner 				if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
66135878b55SSascha Wildner 					nextvaddr = nextpage;
66235878b55SSascha Wildner 					break;
66335878b55SSascha Wildner 				}
66435878b55SSascha Wildner 
66535878b55SSascha Wildner 				currvaddr = nextvaddr;
66635878b55SSascha Wildner 				currphypage = nextphypage;
66735878b55SSascha Wildner 			}while (1);
66835878b55SSascha Wildner 
66935878b55SSascha Wildner 			length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
67035878b55SSascha Wildner 			v = nextvaddr;
67135878b55SSascha Wildner 			bufferSize -= length;
67235878b55SSascha Wildner 
67335878b55SSascha Wildner 			pSgTable[idx].wSgSize = (USHORT)length;
67435878b55SSascha Wildner 			pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
67535878b55SSascha Wildner 			idx++;
67635878b55SSascha Wildner 
67735878b55SSascha Wildner 		}while (bufferSize);
67835878b55SSascha Wildner 	}
67935878b55SSascha Wildner 	return 1;
68035878b55SSascha Wildner }
68135878b55SSascha Wildner 
68235878b55SSascha Wildner static int End_Job=0;
683*8406cf70SSascha Wildner static void HPTLIBAPI
thread_io_done(_VBUS_ARG PCommand pCmd)68435878b55SSascha Wildner thread_io_done(_VBUS_ARG PCommand pCmd)
68535878b55SSascha Wildner {
68635878b55SSascha Wildner 	End_Job = 1;
68735878b55SSascha Wildner 	wakeup((caddr_t)pCmd);
68835878b55SSascha Wildner }
68935878b55SSascha Wildner 
69035878b55SSascha Wildner void
hpt_rebuild_data_block(IAL_ADAPTER_T * pAdapter,PVDevice pArray,UCHAR flags)69135878b55SSascha Wildner hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
69235878b55SSascha Wildner {
69335878b55SSascha Wildner 	DWORD timeout = 0;
69435878b55SSascha Wildner     ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1);
69535878b55SSascha Wildner     PCommand pCmd;
69635878b55SSascha Wildner 	UINT result;
69735878b55SSascha Wildner 	int needsync=0, retry=0, needdelete=0;
6984090d6ffSSascha Wildner 	void *buffer = NULL;
69935878b55SSascha Wildner 
70035878b55SSascha Wildner 	_VBUS_INST(&pAdapter->VBus)
70135878b55SSascha Wildner 
70235878b55SSascha Wildner 	if (pArray->u.array.rf_broken==1 ||
70335878b55SSascha Wildner 	pArray->u.array.RebuildSectors>=capacity)
70435878b55SSascha Wildner 		return;
70535878b55SSascha Wildner 
706c898d682SSascha Wildner 	lock_driver();
70735878b55SSascha Wildner 
70835878b55SSascha Wildner 	switch(flags)
70935878b55SSascha Wildner 	{
71035878b55SSascha Wildner 		case DUPLICATE:
71135878b55SSascha Wildner 		case REBUILD_PARITY:
71235878b55SSascha Wildner 			if(pArray->u.array.rf_rebuilding == 0)
71335878b55SSascha Wildner 			{
71435878b55SSascha Wildner 				pArray->u.array.rf_rebuilding = 1;
71535878b55SSascha Wildner 				hpt_printk(("Rebuilding started.\n"));
71635878b55SSascha Wildner 				ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
71735878b55SSascha Wildner 			}
71835878b55SSascha Wildner 			break;
71935878b55SSascha Wildner 
72035878b55SSascha Wildner 		case INITIALIZE:
72135878b55SSascha Wildner 			if(pArray->u.array.rf_initializing == 0)
72235878b55SSascha Wildner 			{
72335878b55SSascha Wildner 				pArray->u.array.rf_initializing = 1;
72435878b55SSascha Wildner 				hpt_printk(("Initializing started.\n"));
72535878b55SSascha Wildner 				ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
72635878b55SSascha Wildner 			}
72735878b55SSascha Wildner 			break;
72835878b55SSascha Wildner 
72935878b55SSascha Wildner 		case VERIFY:
73035878b55SSascha Wildner 			if(pArray->u.array.rf_verifying == 0)
73135878b55SSascha Wildner 			{
73235878b55SSascha Wildner 				pArray->u.array.rf_verifying = 1;
73335878b55SSascha Wildner 				hpt_printk(("Verifying started.\n"));
73435878b55SSascha Wildner 				ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
73535878b55SSascha Wildner 			}
73635878b55SSascha Wildner 			break;
73735878b55SSascha Wildner 	}
73835878b55SSascha Wildner 
73935878b55SSascha Wildner retry_cmd:
74035878b55SSascha Wildner 	pCmd = AllocateCommand(_VBUS_P0);
74135878b55SSascha Wildner 	HPT_ASSERT(pCmd);
74235878b55SSascha Wildner 	pCmd->cf_control = 1;
74335878b55SSascha Wildner 	End_Job = 0;
74435878b55SSascha Wildner 
74535878b55SSascha Wildner 	if (pArray->VDeviceType==VD_RAID_1)
74635878b55SSascha Wildner 	{
74735878b55SSascha Wildner 		#define MAX_REBUILD_SECTORS 0x40
74835878b55SSascha Wildner 
74935878b55SSascha Wildner 		/* take care for discontinuous buffer in R1ControlSgl */
750c898d682SSascha Wildner 		unlock_driver();
75135878b55SSascha Wildner 		buffer = kmalloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
752c898d682SSascha Wildner 		lock_driver();
75335878b55SSascha Wildner 		if(!buffer) {
75435878b55SSascha Wildner 			FreeCommand(_VBUS_P pCmd);
75535878b55SSascha Wildner 			hpt_printk(("can't allocate rebuild buffer\n"));
75635878b55SSascha Wildner 			goto fail;
75735878b55SSascha Wildner 		}
75835878b55SSascha Wildner 		switch(flags)
75935878b55SSascha Wildner 		{
76035878b55SSascha Wildner 			case DUPLICATE:
76135878b55SSascha Wildner 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
76235878b55SSascha Wildner 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
76335878b55SSascha Wildner 				break;
76435878b55SSascha Wildner 
76535878b55SSascha Wildner 			case VERIFY:
76635878b55SSascha Wildner 				pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
76735878b55SSascha Wildner 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
76835878b55SSascha Wildner 				break;
76935878b55SSascha Wildner 
77035878b55SSascha Wildner 			case INITIALIZE:
77135878b55SSascha Wildner 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
77235878b55SSascha Wildner 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
77335878b55SSascha Wildner 				break;
77435878b55SSascha Wildner 		}
77535878b55SSascha Wildner 
77635878b55SSascha Wildner 		pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
77735878b55SSascha Wildner 
77835878b55SSascha Wildner 		if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
77935878b55SSascha Wildner 			pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
78035878b55SSascha Wildner 
78135878b55SSascha Wildner 		pCmd->uCmd.R1Control.Buffer = buffer;
78235878b55SSascha Wildner 		pCmd->pfnBuildSgl = R1ControlSgl;
78335878b55SSascha Wildner 	}
78435878b55SSascha Wildner 	else if (pArray->VDeviceType==VD_RAID_5)
78535878b55SSascha Wildner 	{
78635878b55SSascha Wildner 		switch(flags)
78735878b55SSascha Wildner 		{
78835878b55SSascha Wildner 			case DUPLICATE:
78935878b55SSascha Wildner 			case REBUILD_PARITY:
79035878b55SSascha Wildner 				pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
79135878b55SSascha Wildner 			case VERIFY:
79235878b55SSascha Wildner 				pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
79335878b55SSascha Wildner 			case INITIALIZE:
79435878b55SSascha Wildner 				pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
79535878b55SSascha Wildner 		}
79635878b55SSascha Wildner 		pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
79735878b55SSascha Wildner 	}
79835878b55SSascha Wildner 	else
79935878b55SSascha Wildner 		HPT_ASSERT(0);
80035878b55SSascha Wildner 
80135878b55SSascha Wildner 	pCmd->pVDevice = pArray;
80235878b55SSascha Wildner 	pCmd->pfnCompletion = thread_io_done;
80335878b55SSascha Wildner 	pArray->pfnSendCommand(_VBUS_P pCmd);
80435878b55SSascha Wildner 	CheckPendingCall(_VBUS_P0);
80535878b55SSascha Wildner 
80635878b55SSascha Wildner 	if (!End_Job) {
807c898d682SSascha Wildner 		unlock_driver();
80835878b55SSascha Wildner 		while (!End_Job) {
80935878b55SSascha Wildner 			tsleep((caddr_t)pCmd, 0, "pause", hz);
81035878b55SSascha Wildner 			if (timeout++>60) break;
81135878b55SSascha Wildner 		}
812c898d682SSascha Wildner 		lock_driver();
81335878b55SSascha Wildner 		if (!End_Job) {
81435878b55SSascha Wildner 			hpt_printk(("timeout, reset\n"));
81535878b55SSascha Wildner 			fResetVBus(_VBUS_P0);
81635878b55SSascha Wildner 		}
81735878b55SSascha Wildner 	}
81835878b55SSascha Wildner 
81935878b55SSascha Wildner 	result = pCmd->Result;
82035878b55SSascha Wildner 	FreeCommand(_VBUS_P pCmd);
821c898d682SSascha Wildner 	unlock_driver();
82235878b55SSascha Wildner 	if (buffer) kfree(buffer, M_DEVBUF);
823c898d682SSascha Wildner 	lock_driver();
82435878b55SSascha Wildner 	KdPrintI(("cmd finished %d", result));
82535878b55SSascha Wildner 
82635878b55SSascha Wildner 	switch(result)
82735878b55SSascha Wildner 	{
82835878b55SSascha Wildner 		case RETURN_SUCCESS:
82935878b55SSascha Wildner 			if (!pArray->u.array.rf_abort_rebuild)
83035878b55SSascha Wildner 			{
83135878b55SSascha Wildner 				if(pArray->u.array.RebuildSectors < capacity)
83235878b55SSascha Wildner 				{
83335878b55SSascha Wildner 					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
83435878b55SSascha Wildner 				}
83535878b55SSascha Wildner 				else
83635878b55SSascha Wildner 				{
83735878b55SSascha Wildner 					switch (flags)
83835878b55SSascha Wildner 					{
83935878b55SSascha Wildner 						case DUPLICATE:
84035878b55SSascha Wildner 						case REBUILD_PARITY:
84135878b55SSascha Wildner 							needsync = 1;
84235878b55SSascha Wildner 							pArray->u.array.rf_rebuilding = 0;
84335878b55SSascha Wildner 							pArray->u.array.rf_need_rebuild = 0;
84435878b55SSascha Wildner 							pArray->u.array.CriticalMembers = 0;
84535878b55SSascha Wildner 							pArray->u.array.RebuildSectors = MAX_LBA_T;
84635878b55SSascha Wildner 							pArray->u.array.rf_duplicate_and_create = 0;
84735878b55SSascha Wildner 							hpt_printk(("Rebuilding finished.\n"));
84835878b55SSascha Wildner 							ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
84935878b55SSascha Wildner 							break;
85035878b55SSascha Wildner 						case INITIALIZE:
85135878b55SSascha Wildner 							needsync = 1;
85235878b55SSascha Wildner 							pArray->u.array.rf_initializing = 0;
85335878b55SSascha Wildner 							pArray->u.array.rf_need_rebuild = 0;
85435878b55SSascha Wildner 							pArray->u.array.RebuildSectors = MAX_LBA_T;
85535878b55SSascha Wildner 							hpt_printk(("Initializing finished.\n"));
85635878b55SSascha Wildner 							ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
85735878b55SSascha Wildner 							break;
85835878b55SSascha Wildner 						case VERIFY:
85935878b55SSascha Wildner 							pArray->u.array.rf_verifying = 0;
86035878b55SSascha Wildner 							hpt_printk(("Verifying finished.\n"));
86135878b55SSascha Wildner 							ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
86235878b55SSascha Wildner 							break;
86335878b55SSascha Wildner 					}
86435878b55SSascha Wildner 				}
86535878b55SSascha Wildner 			}
86635878b55SSascha Wildner 			else
86735878b55SSascha Wildner 			{
86835878b55SSascha Wildner 				pArray->u.array.rf_abort_rebuild = 0;
86935878b55SSascha Wildner 				if (pArray->u.array.rf_rebuilding)
87035878b55SSascha Wildner 				{
87135878b55SSascha Wildner 					hpt_printk(("Abort rebuilding.\n"));
87235878b55SSascha Wildner 					pArray->u.array.rf_rebuilding = 0;
87335878b55SSascha Wildner 					pArray->u.array.rf_duplicate_and_create = 0;
87435878b55SSascha Wildner 					ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
87535878b55SSascha Wildner 				}
87635878b55SSascha Wildner 				else if (pArray->u.array.rf_verifying)
87735878b55SSascha Wildner 				{
87835878b55SSascha Wildner 					hpt_printk(("Abort verifying.\n"));
87935878b55SSascha Wildner 					pArray->u.array.rf_verifying = 0;
88035878b55SSascha Wildner 					ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
88135878b55SSascha Wildner 				}
88235878b55SSascha Wildner 				else if (pArray->u.array.rf_initializing)
88335878b55SSascha Wildner 				{
88435878b55SSascha Wildner 					hpt_printk(("Abort initializing.\n"));
88535878b55SSascha Wildner 					pArray->u.array.rf_initializing = 0;
88635878b55SSascha Wildner 					ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
88735878b55SSascha Wildner 				}
88835878b55SSascha Wildner 				needdelete=1;
88935878b55SSascha Wildner 			}
89035878b55SSascha Wildner 			break;
89135878b55SSascha Wildner 
89235878b55SSascha Wildner 		case RETURN_DATA_ERROR:
89335878b55SSascha Wildner 			if (flags==VERIFY)
89435878b55SSascha Wildner 			{
89535878b55SSascha Wildner 				needsync = 1;
89635878b55SSascha Wildner 				pArray->u.array.rf_verifying = 0;
89735878b55SSascha Wildner 				pArray->u.array.rf_need_rebuild = 1;
89835878b55SSascha Wildner 				hpt_printk(("Verifying failed: found inconsistency\n"));
89935878b55SSascha Wildner 				ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
90035878b55SSascha Wildner 				ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
90135878b55SSascha Wildner 
90235878b55SSascha Wildner 				if (!pArray->vf_online || pArray->u.array.rf_broken) break;
90335878b55SSascha Wildner 
90435878b55SSascha Wildner 				pArray->u.array.rf_auto_rebuild = 0;
90535878b55SSascha Wildner 				pArray->u.array.rf_abort_rebuild = 0;
90635878b55SSascha Wildner 				hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
90735878b55SSascha Wildner 					(pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
90835878b55SSascha Wildner 			}
90935878b55SSascha Wildner 			break;
91035878b55SSascha Wildner 
91135878b55SSascha Wildner 		default:
91235878b55SSascha Wildner 			hpt_printk(("command failed with error %d\n", result));
91335878b55SSascha Wildner 			if (++retry<3)
91435878b55SSascha Wildner 			{
91535878b55SSascha Wildner 				hpt_printk(("retry (%d)\n", retry));
91635878b55SSascha Wildner 				goto retry_cmd;
91735878b55SSascha Wildner 			}
91835878b55SSascha Wildner fail:
91935878b55SSascha Wildner 			pArray->u.array.rf_abort_rebuild = 0;
92035878b55SSascha Wildner 			switch (flags)
92135878b55SSascha Wildner 			{
92235878b55SSascha Wildner 				case DUPLICATE:
92335878b55SSascha Wildner 				case REBUILD_PARITY:
92435878b55SSascha Wildner 					needsync = 1;
92535878b55SSascha Wildner 					pArray->u.array.rf_rebuilding = 0;
92635878b55SSascha Wildner 					pArray->u.array.rf_duplicate_and_create = 0;
92735878b55SSascha Wildner 					hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
92835878b55SSascha Wildner 					ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
92935878b55SSascha Wildner 					break;
93035878b55SSascha Wildner 
93135878b55SSascha Wildner 				case INITIALIZE:
93235878b55SSascha Wildner 					needsync = 1;
93335878b55SSascha Wildner 					pArray->u.array.rf_initializing = 0;
93435878b55SSascha Wildner 					hpt_printk(("Initializing failed.\n"));
93535878b55SSascha Wildner 					ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
93635878b55SSascha Wildner 					break;
93735878b55SSascha Wildner 
93835878b55SSascha Wildner 				case VERIFY:
93935878b55SSascha Wildner 					needsync = 1;
94035878b55SSascha Wildner 					pArray->u.array.rf_verifying = 0;
94135878b55SSascha Wildner 					hpt_printk(("Verifying failed.\n"));
94235878b55SSascha Wildner 					ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
94335878b55SSascha Wildner 					break;
94435878b55SSascha Wildner 			}
94535878b55SSascha Wildner 			needdelete=1;
94635878b55SSascha Wildner 	}
94735878b55SSascha Wildner 
94835878b55SSascha Wildner 	while (pAdapter->outstandingCommands)
94935878b55SSascha Wildner 	{
95035878b55SSascha Wildner 		KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
95135878b55SSascha Wildner 		/* put this to have driver stop processing system commands quickly */
95235878b55SSascha Wildner 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
953c898d682SSascha Wildner 		unlock_driver();
95435878b55SSascha Wildner 		/*Schedule out*/
95535878b55SSascha Wildner 		tsleep(hpt_rebuild_data_block, 0, "switch", 1);
956c898d682SSascha Wildner 		lock_driver();
95735878b55SSascha Wildner 	}
95835878b55SSascha Wildner 
95935878b55SSascha Wildner 	if (needsync) SyncArrayInfo(pArray);
96035878b55SSascha Wildner 	if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
96135878b55SSascha Wildner 		fDeleteArray(_VBUS_P pArray, TRUE);
96235878b55SSascha Wildner 
96335878b55SSascha Wildner 	Check_Idle_Call(pAdapter);
964c898d682SSascha Wildner 	unlock_driver();
96535878b55SSascha Wildner }
966