1136849Sscottl/*
2149871Sscottl * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
3136849Sscottl * All rights reserved.
4136849Sscottl *
5136849Sscottl * Redistribution and use in source and binary forms, with or without
6136849Sscottl * modification, are permitted provided that the following conditions
7136849Sscottl * are met:
8136849Sscottl * 1. Redistributions of source code must retain the above copyright
9136849Sscottl *    notice, this list of conditions and the following disclaimer.
10136849Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11136849Sscottl *    notice, this list of conditions and the following disclaimer in the
12136849Sscottl *    documentation and/or other materials provided with the distribution.
13136849Sscottl *
14136849Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15136849Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16136849Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17136849Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18136849Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19136849Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20136849Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21136849Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22136849Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23136849Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24136849Sscottl * SUCH DAMAGE.
25142988Sscottl *
26142988Sscottl * $FreeBSD$
27136849Sscottl */
28136849Sscottl/*
29136849Sscottl * ioctl.c   ioctl interface implementation
30136849Sscottl */
31136849Sscottl#include <sys/param.h>
32136849Sscottl#include <sys/systm.h>
33136849Sscottl#include <sys/kernel.h>
34136849Sscottl#include <sys/malloc.h>
35136849Sscottl
36149871Sscottl#if (__FreeBSD_version < 500000)
37149871Sscottl#include <sys/proc.h>
38149871Sscottl#include <sys/kthread.h>
39149871Sscottl#include <sys/wait.h>
40149871Sscottl#include <sys/sysproto.h>
41149871Sscottl#endif
42149871Sscottl
43149871Sscottl#ifndef __KERNEL__
44149871Sscottl#define __KERNEL__
45149871Sscottl#endif
46149871Sscottl
47136849Sscottl#include <dev/hptmv/global.h>
48136849Sscottl#include <dev/hptmv/hptintf.h>
49136849Sscottl#include <dev/hptmv/osbsd.h>
50143039Sscottl#include <dev/hptmv/access601.h>
51136849Sscottl
52136849Sscottl#pragma pack(1)
53136849Sscottl
54136849Sscottltypedef struct _HPT_REBUILD_PARAM
55136849Sscottl{
56136849Sscottl	DEVICEID idMirror;
57136849Sscottl	DWORD Lba;
58136849Sscottl	UCHAR nSector;
59136849Sscottl} HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM;
60136849Sscottl
61136849Sscottl#pragma pack()
62136849Sscottl
63136849Sscottl#define MAX_EVENTS 10
64136849Sscottlstatic HPT_EVENT hpt_event_queue[MAX_EVENTS];
65136849Sscottlstatic int event_queue_head=0, event_queue_tail=0;
66136849Sscottl
67136849Sscottlstatic int hpt_get_event(PHPT_EVENT pEvent);
68136849Sscottlstatic int hpt_set_array_state(DEVICEID idArray, DWORD state);
69136849Sscottlstatic intrmask_t lock_driver_idle(IAL_ADAPTER_T *pAdapter);
70136849Sscottlstatic void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd);
71136849Sscottlstatic int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd,
72136849Sscottl    FPSCAT_GATH pSgTable, int logical);
73136849Sscottl
74149871Sscottlstatic void
75149871Sscottlget_disk_location(PDevice pDev, int *controller, int *channel)
76136849Sscottl{
77136849Sscottl	IAL_ADAPTER_T *pAdapTemp;
78136849Sscottl	int i, j;
79136849Sscottl
80169823Smjacob	*controller = *channel = 0;
81169823Smjacob
82169823Smjacob	for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) {
83169823Smjacob		for (j=0; j<MV_SATA_CHANNELS_NUM; j++) {
84169823Smjacob			if (pDev == &pAdapTemp->VDevices[j].u.disk) {
85169823Smjacob				*controller = i;
86169823Smjacob				*channel = j;
87169823Smjacob				return;
88169823Smjacob			}
89169823Smjacob		}
90136849Sscottl	}
91136849Sscottl}
92136849Sscottl
93149871Sscottlstatic int
94149871Sscottlevent_queue_add(PHPT_EVENT pEvent)
95136849Sscottl{
96136849Sscottl	int p;
97136849Sscottl	p = (event_queue_tail + 1) % MAX_EVENTS;
98136849Sscottl	if (p==event_queue_head)
99136849Sscottl	{
100136849Sscottl		return -1;
101136849Sscottl	}
102136849Sscottl	hpt_event_queue[event_queue_tail] = *pEvent;
103136849Sscottl	event_queue_tail = p;
104136849Sscottl	return 0;
105136849Sscottl}
106136849Sscottl
107149871Sscottlstatic int
108149871Sscottlevent_queue_remove(PHPT_EVENT pEvent)
109136849Sscottl{
110136849Sscottl	if (event_queue_head != event_queue_tail)
111136849Sscottl	{
112136849Sscottl		*pEvent = hpt_event_queue[event_queue_head];
113136849Sscottl		event_queue_head++;
114136849Sscottl		event_queue_head %= MAX_EVENTS;
115136849Sscottl		return 0;
116136849Sscottl	}
117136849Sscottl	return -1;
118136849Sscottl}
119136849Sscottl
120149871Sscottlvoid HPTLIBAPI
121149871Sscottlioctl_ReportEvent(UCHAR event, PVOID param)
122136849Sscottl{
123136849Sscottl	HPT_EVENT e;
124136849Sscottl	ZeroMemory(&e, sizeof(e));
125136849Sscottl	e.EventType = event;
126136849Sscottl	switch(event)
127136849Sscottl	{
128136849Sscottl		case ET_INITIALIZE_ABORTED:
129136849Sscottl		case ET_INITIALIZE_FAILED:
130136849Sscottl			memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME);
131136849Sscottl		case ET_INITIALIZE_STARTED:
132136849Sscottl		case ET_INITIALIZE_FINISHED:
133136849Sscottl
134136849Sscottl		case ET_REBUILD_STARTED:
135136849Sscottl		case ET_REBUILD_ABORTED:
136136849Sscottl		case ET_REBUILD_FAILED:
137136849Sscottl		case ET_REBUILD_FINISHED:
138136849Sscottl
139136849Sscottl		case ET_VERIFY_STARTED:
140136849Sscottl		case ET_VERIFY_ABORTED:
141136849Sscottl		case ET_VERIFY_FAILED:
142136849Sscottl		case ET_VERIFY_FINISHED:
143136849Sscottl		case ET_VERIFY_DATA_ERROR:
144136849Sscottl
145136849Sscottl		case ET_SPARE_TOOK_OVER:
146136849Sscottl		case ET_DEVICE_REMOVED:
147136849Sscottl		case ET_DEVICE_PLUGGED:
148136849Sscottl		case ET_DEVICE_ERROR:
149136849Sscottl			e.DeviceID = VDEV_TO_ID((PVDevice)param);
150136849Sscottl			break;
151136849Sscottl
152136849Sscottl		default:
153136849Sscottl			break;
154136849Sscottl	}
155136849Sscottl	event_queue_add(&e);
156136849Sscottl	if (event==ET_DEVICE_REMOVED) {
157169823Smjacob		int controller, channel;
158136849Sscottl		get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel);
159136849Sscottl		hpt_printk(("Device removed: controller %d channel %d\n", controller, channel));
160136849Sscottl	}
161136849Sscottl}
162136849Sscottl
163149871Sscottlstatic int
164149871Sscottlhpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options)
165136849Sscottl{
166136849Sscottl	PVDevice	pArray = ID_TO_VDEV(id);
167136849Sscottl	BOOLEAN	del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1;
168136849Sscottl	int i;
169136849Sscottl	PVDevice pa;
170136849Sscottl
171149871Sscottl	if ((id==0) || check_VDevice_valid(pArray))
172136849Sscottl		return -1;
173136849Sscottl
174136849Sscottl	if(!mIsArray(pArray)) return -1;
175136849Sscottl
176136849Sscottl	if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying ||
177136849Sscottl		pArray->u.array.rf_initializing)
178136849Sscottl		return -1;
179136849Sscottl
180136849Sscottl	for(i=0; i<pArray->u.array.bArnMember; i++) {
181136849Sscottl		pa = pArray->u.array.pMember[i];
182136849Sscottl		if (pa && mIsArray(pa)) {
183136849Sscottl			if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying ||
184136849Sscottl				pa->u.array.rf_initializing)
185136849Sscottl				return -1;
186136849Sscottl		}
187136849Sscottl	}
188136849Sscottl
189136849Sscottl	if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
190136849Sscottl	fDeleteArray(_VBUS_P pArray, del_block0);
191136849Sscottl	return 0;
192136849Sscottl
193136849Sscottl}
194136849Sscottl
195136849Sscottl/* just to prevent driver from sending more commands */
196136849Sscottlstatic void HPTLIBAPI nothing(_VBUS_ARG void *notused){}
197136849Sscottl
198149871Sscottlintrmask_t
199149871Sscottllock_driver_idle(IAL_ADAPTER_T *pAdapter)
200136849Sscottl{
201136849Sscottl	intrmask_t oldspl;
202136849Sscottl	_VBUS_INST(&pAdapter->VBus)
203136849Sscottl	oldspl = lock_driver();
204136849Sscottl	while (pAdapter->outstandingCommands) {
205136849Sscottl		KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands));
206136849Sscottl		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
207136849Sscottl		unlock_driver(oldspl);
208149871Sscottl/*Schedule out*/
209149871Sscottl#if (__FreeBSD_version < 500000)
210149871Sscottl		YIELD_THREAD;
211149871Sscottl#else
212190809Sdelphij#if (__FreeBSD_version > 700033)
213167086Sjhb		pause("switch", 1);
214190809Sdelphij#else
215190809Sdelphij		tsleep(lock_driver_idle, PPAUSE, "switch", 1);
216149871Sscottl#endif
217190809Sdelphij#endif
218136849Sscottl		oldspl = lock_driver();
219136849Sscottl	}
220136849Sscottl	CheckIdleCall(_VBUS_P0);
221136849Sscottl	return oldspl;
222136849Sscottl}
223136849Sscottl
224136849Sscottlint Kernel_DeviceIoControl(_VBUS_ARG
225136849Sscottl							DWORD dwIoControlCode,       	/* operation control code */
226136849Sscottl							PVOID lpInBuffer,            	/* input data buffer */
227136849Sscottl							DWORD nInBufferSize,         	/* size of input data buffer */
228136849Sscottl							PVOID lpOutBuffer,           	/* output data buffer */
229136849Sscottl							DWORD nOutBufferSize,        	/* size of output data buffer */
230136849Sscottl							PDWORD lpBytesReturned      	/* byte count */
231136849Sscottl						)
232136849Sscottl{
233136849Sscottl	IAL_ADAPTER_T *pAdapter;
234136849Sscottl
235136849Sscottl	switch(dwIoControlCode)	{
236136849Sscottl		case HPT_IOCTL_DELETE_ARRAY:
237136849Sscottl		{
238136849Sscottl			DEVICEID idArray;
239136849Sscottl			int iSuccess;
240136849Sscottl	        int i;
241136849Sscottl			PVDevice pArray;
242136849Sscottl			PVBus _vbus_p;
243136849Sscottl			struct cam_periph *periph = NULL;
244136849Sscottl
245136849Sscottl			if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1;
246136849Sscottl			if (nOutBufferSize!=sizeof(int)) return -1;
247136849Sscottl			idArray = *(DEVICEID *)lpInBuffer;
248136849Sscottl
249136849Sscottl			pArray = ID_TO_VDEV(idArray);
250136849Sscottl
251149871Sscottl			if((idArray == 0) || check_VDevice_valid(pArray))
252136849Sscottl		       	return -1;
253136849Sscottl
254136849Sscottl        	if(!mIsArray(pArray))
255136849Sscottl			return -1;
256136849Sscottl
257136849Sscottl			_vbus_p=pArray->pVBus;
258136849Sscottl			pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
259136849Sscottl
260136849Sscottl	        for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) {
261136849Sscottl				if(pArray == _vbus_p->pVDevice[i])
262136849Sscottl				{
263136849Sscottl					periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
264149871Sscottl					if (periph != NULL && periph->refcount >= 1)
265136849Sscottl					{
266136849Sscottl						hpt_printk(("Can not delete a mounted device.\n"));
267136849Sscottl	                    return -1;
268136849Sscottl					}
269136849Sscottl				}
270136849Sscottl				/* the Mounted Disk isn't delete */
271136849Sscottl			}
272136849Sscottl
273136849Sscottl			iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1));
274136849Sscottl
275136849Sscottl			*(int*)lpOutBuffer = iSuccess;
276136849Sscottl
277136849Sscottl			if(iSuccess != 0)
278136849Sscottl				return -1;
279136849Sscottl			break;
280136849Sscottl		}
281136849Sscottl
282136849Sscottl		case HPT_IOCTL_GET_EVENT:
283136849Sscottl		{
284136849Sscottl			PHPT_EVENT pInfo;
285136849Sscottl
286136849Sscottl			if (nInBufferSize!=0) return -1;
287136849Sscottl			if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1;
288136849Sscottl
289136849Sscottl			pInfo = (PHPT_EVENT)lpOutBuffer;
290136849Sscottl
291136849Sscottl			if (hpt_get_event(pInfo)!=0)
292136849Sscottl				return -1;
293136849Sscottl		}
294136849Sscottl		break;
295136849Sscottl
296136849Sscottl		case HPT_IOCTL_SET_ARRAY_STATE:
297136849Sscottl		{
298136849Sscottl			DEVICEID idArray;
299136849Sscottl			DWORD state;
300136849Sscottl
301136849Sscottl			if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1;
302136849Sscottl			if (nOutBufferSize!=0) return -1;
303136849Sscottl
304136849Sscottl			idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray;
305136849Sscottl			state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state;
306136849Sscottl
307136849Sscottl			if(hpt_set_array_state(idArray, state)!=0)
308136849Sscottl				return -1;
309136849Sscottl		}
310136849Sscottl		break;
311136849Sscottl
312136849Sscottl		case HPT_IOCTL_RESCAN_DEVICES:
313136849Sscottl		{
314136849Sscottl			if (nInBufferSize!=0) return -1;
315136849Sscottl			if (nOutBufferSize!=0) return -1;
316136849Sscottl
317136849Sscottl#ifndef FOR_DEMO
318136849Sscottl			/* stop buzzer if user perform rescan */
319136849Sscottl			for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
320136849Sscottl				if (pAdapter->beeping) {
321136849Sscottl					pAdapter->beeping = 0;
322136849Sscottl					BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
323136849Sscottl				}
324136849Sscottl			}
325136849Sscottl#endif
326136849Sscottl		}
327136849Sscottl		break;
328136849Sscottl
329136849Sscottl		default:
330136849Sscottl		{
331136849Sscottl			PVDevice pVDev;
332136849Sscottl#ifdef SUPPORT_ARRAY
333136849Sscottl			intrmask_t oldspl;
334136849Sscottl#endif
335136849Sscottl			switch(dwIoControlCode) {
336136849Sscottl			/* read-only ioctl functions can be called directly. */
337136849Sscottl			case HPT_IOCTL_GET_VERSION:
338136849Sscottl			case HPT_IOCTL_GET_CONTROLLER_IDS:
339136849Sscottl			case HPT_IOCTL_GET_CONTROLLER_COUNT:
340136849Sscottl			case HPT_IOCTL_GET_CONTROLLER_INFO:
341136849Sscottl			case HPT_IOCTL_GET_CHANNEL_INFO:
342136849Sscottl			case HPT_IOCTL_GET_LOGICAL_DEVICES:
343136849Sscottl			case HPT_IOCTL_GET_DEVICE_INFO:
344190809Sdelphij			case HPT_IOCTL_GET_DEVICE_INFO_V2:
345136849Sscottl			case HPT_IOCTL_GET_EVENT:
346136849Sscottl			case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
347136849Sscottl				if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
348136849Sscottl					lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
349136849Sscottl				break;
350136849Sscottl
351136849Sscottl			default:
352136849Sscottl				/*
353136849Sscottl				 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
354136849Sscottl				 * wrong for second controller.
355136849Sscottl				 */
356136849Sscottl				switch(dwIoControlCode) {
357136849Sscottl				case HPT_IOCTL_CREATE_ARRAY:
358136849Sscottl					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
359190809Sdelphij				case HPT_IOCTL_CREATE_ARRAY_V2:
360190809Sdelphij					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break;
361136849Sscottl				case HPT_IOCTL_SET_ARRAY_INFO:
362136849Sscottl					pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
363136849Sscottl				case HPT_IOCTL_SET_DEVICE_INFO:
364136849Sscottl					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
365190809Sdelphij				case HPT_IOCTL_SET_DEVICE_INFO_V2:
366190809Sdelphij					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break;
367136849Sscottl				case HPT_IOCTL_SET_BOOT_MARK:
368136849Sscottl				case HPT_IOCTL_ADD_SPARE_DISK:
369136849Sscottl				case HPT_IOCTL_REMOVE_SPARE_DISK:
370136849Sscottl					pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
371136849Sscottl				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
372136849Sscottl					pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
373136849Sscottl				default:
374136849Sscottl					pVDev = 0;
375136849Sscottl				}
376136849Sscottl
377136849Sscottl				if (pVDev && !check_VDevice_valid(pVDev)){
378136849Sscottl					_vbus_p = pVDev->pVBus;
379136849Sscottl
380136849Sscottl					pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
381136849Sscottl					/*
382136849Sscottl					 * create_array, and other functions can't be executed while channel is
383136849Sscottl					 * perform I/O commands. Wait until driver is idle.
384136849Sscottl					 */
385136849Sscottl					oldspl = lock_driver_idle(pAdapter);
386136849Sscottl					if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
387136849Sscottl						lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
388136849Sscottl						unlock_driver(oldspl);
389136849Sscottl						return -1;
390136849Sscottl					}
391136849Sscottl					unlock_driver(oldspl);
392136849Sscottl				}
393136849Sscottl				else
394136849Sscottl					return -1;
395136849Sscottl				break;
396136849Sscottl			}
397136849Sscottl
398136849Sscottl#ifdef SUPPORT_ARRAY
399136849Sscottl			switch(dwIoControlCode)
400136849Sscottl			{
401136849Sscottl				case HPT_IOCTL_CREATE_ARRAY:
402136849Sscottl				{
403136849Sscottl					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
404136849Sscottl					oldspl = lock_driver();
405136849Sscottl                    if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
406136849Sscottl				    {
407136849Sscottl						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
408136849Sscottl                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
409136849Sscottl					}
410136849Sscottl					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
411136849Sscottl				    {
412136849Sscottl                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
413136849Sscottl					}
414136849Sscottl					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
415136849Sscottl				    {
416136849Sscottl                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
417136849Sscottl					}
418136849Sscottl					unlock_driver(oldspl);
419136849Sscottl                    break;
420136849Sscottl				}
421136849Sscottl
422190809Sdelphij
423190809Sdelphij				case HPT_IOCTL_CREATE_ARRAY_V2:
424190809Sdelphij				{
425190809Sdelphij					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
426190809Sdelphij					oldspl = lock_driver();
427190809Sdelphij				             if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) {
428190809Sdelphij						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
429190809Sdelphij				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
430190809Sdelphij					} else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) {
431190809Sdelphij				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
432190809Sdelphij					} else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) {
433190809Sdelphij				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
434190809Sdelphij					}
435190809Sdelphij					unlock_driver(oldspl);
436190809Sdelphij					break;
437190809Sdelphij				}
438136849Sscottl				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
439136849Sscottl				{
440136849Sscottl					PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
441136849Sscottl					pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
442149871Sscottl					if(pArray->u.array.rf_rebuilding == 0)
443136849Sscottl					{
444136849Sscottl						DWORD timeout = 0;
445136849Sscottl						oldspl = lock_driver();
446136849Sscottl						pArray->u.array.rf_auto_rebuild = 0;
447136849Sscottl						pArray->u.array.rf_abort_rebuild = 0;
448136849Sscottl						hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE);
449136849Sscottl						unlock_driver(oldspl);
450136849Sscottl						while (!pArray->u.array.rf_rebuilding)
451136849Sscottl						{
452190809Sdelphij#if (__FreeBSD_version > 700033)
453167086Sjhb							pause("pause", 1);
454190809Sdelphij#else
455190809Sdelphij							tsleep((caddr_t)Kernel_DeviceIoControl, PPAUSE, "pause", 1);
456190809Sdelphij#endif
457136849Sscottl							if ( timeout >= hz*3)
458136849Sscottl								break;
459136849Sscottl							timeout ++;
460136849Sscottl						}
461136849Sscottl					}
462136849Sscottl					break;
463136849Sscottl				}
464136849Sscottl			}
465136849Sscottl#endif
466136849Sscottl            return 0;
467136849Sscottl		}
468136849Sscottl	}
469136849Sscottl
470136849Sscottl	if (lpBytesReturned)
471136849Sscottl		*lpBytesReturned = nOutBufferSize;
472136849Sscottl	return 0;
473136849Sscottl}
474136849Sscottl
475149871Sscottlstatic int
476149871Sscottlhpt_get_event(PHPT_EVENT pEvent)
477136849Sscottl{
478136849Sscottl	intrmask_t oldspl = lock_driver();
479136849Sscottl	int ret = event_queue_remove(pEvent);
480136849Sscottl	unlock_driver(oldspl);
481136849Sscottl	return ret;
482136849Sscottl}
483136849Sscottl
484149871Sscottlstatic int
485149871Sscottlhpt_set_array_state(DEVICEID idArray, DWORD state)
486136849Sscottl{
487136849Sscottl	IAL_ADAPTER_T *pAdapter;
488136849Sscottl	PVDevice pVDevice = ID_TO_VDEV(idArray);
489136849Sscottl	int	i;
490136849Sscottl	DWORD timeout = 0;
491136849Sscottl	intrmask_t oldspl;
492136849Sscottl
493149871Sscottl	if(idArray == 0 || check_VDevice_valid(pVDevice))	return -1;
494136849Sscottl	if(!mIsArray(pVDevice))
495136849Sscottl		return -1;
496136849Sscottl	if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
497136849Sscottl
498136849Sscottl	pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
499136849Sscottl
500136849Sscottl	switch(state)
501136849Sscottl	{
502136849Sscottl		case MIRROR_REBUILD_START:
503136849Sscottl		{
504136849Sscottl			if (pVDevice->u.array.rf_rebuilding ||
505136849Sscottl				pVDevice->u.array.rf_verifying ||
506136849Sscottl				pVDevice->u.array.rf_initializing)
507136849Sscottl				return -1;
508136849Sscottl
509136849Sscottl			oldspl = lock_driver();
510136849Sscottl
511136849Sscottl			pVDevice->u.array.rf_auto_rebuild = 0;
512136849Sscottl			pVDevice->u.array.rf_abort_rebuild = 0;
513136849Sscottl
514136849Sscottl			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice,
515136849Sscottl				(UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
516136849Sscottl
517136849Sscottl			unlock_driver(oldspl);
518136849Sscottl
519136849Sscottl			while (!pVDevice->u.array.rf_rebuilding)
520136849Sscottl			{
521190809Sdelphij#if (__FreeBSD_version > 700033)
522167086Sjhb				pause("pause", 1);
523190809Sdelphij#else
524190809Sdelphij				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
525190809Sdelphij#endif
526136849Sscottl				if ( timeout >= hz*20)
527136849Sscottl					break;
528136849Sscottl				timeout ++;
529136849Sscottl			}
530136849Sscottl		}
531136849Sscottl
532136849Sscottl		break;
533136849Sscottl
534136849Sscottl		case MIRROR_REBUILD_ABORT:
535136849Sscottl		{
536136849Sscottl			for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
537149871Sscottl				if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
538136849Sscottl					hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
539136849Sscottl			}
540136849Sscottl
541136849Sscottl			if(pVDevice->u.array.rf_rebuilding != 1)
542136849Sscottl				return -1;
543136849Sscottl
544136849Sscottl			oldspl = lock_driver();
545136849Sscottl			pVDevice->u.array.rf_abort_rebuild = 1;
546136849Sscottl			unlock_driver(oldspl);
547136849Sscottl
548136849Sscottl			while (pVDevice->u.array.rf_abort_rebuild)
549136849Sscottl			{
550190809Sdelphij#if (__FreeBSD_version > 700033)
551167086Sjhb				pause("pause", 1);
552190809Sdelphij#else
553190809Sdelphij				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
554190809Sdelphij#endif
555136849Sscottl				if ( timeout >= hz*20)
556136849Sscottl					break;
557136849Sscottl				timeout ++;
558136849Sscottl			}
559136849Sscottl		}
560136849Sscottl		break;
561136849Sscottl
562136849Sscottl		case AS_VERIFY_START:
563136849Sscottl		{
564136849Sscottl			/*if(pVDevice->u.array.rf_verifying)
565136849Sscottl				return -1;*/
566136849Sscottl			if (pVDevice->u.array.rf_rebuilding ||
567136849Sscottl				pVDevice->u.array.rf_verifying ||
568136849Sscottl				pVDevice->u.array.rf_initializing)
569136849Sscottl				return -1;
570136849Sscottl
571136849Sscottl			oldspl = lock_driver();
572136849Sscottl            pVDevice->u.array.RebuildSectors = 0;
573136849Sscottl			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
574136849Sscottl			unlock_driver(oldspl);
575136849Sscottl
576136849Sscottl			while (!pVDevice->u.array.rf_verifying)
577136849Sscottl			{
578190809Sdelphij#if (__FreeBSD_version > 700033)
579167086Sjhb				pause("pause", 1);
580190809Sdelphij#else
581190809Sdelphij				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
582190809Sdelphij#endif
583136849Sscottl				if ( timeout >= hz*20)
584136849Sscottl					break;
585136849Sscottl				timeout ++;
586136849Sscottl			}
587136849Sscottl		}
588136849Sscottl		break;
589136849Sscottl
590136849Sscottl		case AS_VERIFY_ABORT:
591136849Sscottl		{
592136849Sscottl			if(pVDevice->u.array.rf_verifying != 1)
593136849Sscottl				return -1;
594136849Sscottl
595136849Sscottl			oldspl = lock_driver();
596136849Sscottl			pVDevice->u.array.rf_abort_rebuild = 1;
597136849Sscottl			unlock_driver(oldspl);
598136849Sscottl
599136849Sscottl			while (pVDevice->u.array.rf_abort_rebuild)
600136849Sscottl			{
601190809Sdelphij#if (__FreeBSD_version > 700033)
602167086Sjhb				pause("pause", 1);
603190809Sdelphij#else
604190809Sdelphij				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
605190809Sdelphij#endif
606136849Sscottl				if ( timeout >= hz*80)
607136849Sscottl					break;
608136849Sscottl				timeout ++;
609136849Sscottl			}
610136849Sscottl		}
611136849Sscottl		break;
612136849Sscottl
613136849Sscottl		case AS_INITIALIZE_START:
614136849Sscottl		{
615136849Sscottl			if (pVDevice->u.array.rf_rebuilding ||
616136849Sscottl				pVDevice->u.array.rf_verifying ||
617136849Sscottl				pVDevice->u.array.rf_initializing)
618136849Sscottl				return -1;
619136849Sscottl
620136849Sscottl			oldspl = lock_driver();
621136849Sscottl			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
622136849Sscottl			unlock_driver(oldspl);
623136849Sscottl
624136849Sscottl			while (!pVDevice->u.array.rf_initializing)
625136849Sscottl			{
626190809Sdelphij#if (__FreeBSD_version > 700033)
627167086Sjhb				pause("pause", 1);
628190809Sdelphij#else
629190809Sdelphij				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
630190809Sdelphij#endif
631136849Sscottl				if ( timeout >= hz*80)
632136849Sscottl					break;
633136849Sscottl				timeout ++;
634136849Sscottl			}
635136849Sscottl		}
636136849Sscottl		break;
637136849Sscottl
638136849Sscottl		case AS_INITIALIZE_ABORT:
639136849Sscottl		{
640136849Sscottl			if(pVDevice->u.array.rf_initializing != 1)
641136849Sscottl				return -1;
642136849Sscottl
643136849Sscottl			oldspl = lock_driver();
644136849Sscottl			pVDevice->u.array.rf_abort_rebuild = 1;
645136849Sscottl			unlock_driver(oldspl);
646136849Sscottl
647136849Sscottl			while (pVDevice->u.array.rf_abort_rebuild)
648136849Sscottl			{
649190809Sdelphij#if (__FreeBSD_version > 700033)
650167086Sjhb				pause("pause", 1);
651190809Sdelphij#else
652190809Sdelphij				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
653190809Sdelphij#endif
654136849Sscottl				if ( timeout >= hz*80)
655136849Sscottl					break;
656136849Sscottl				timeout ++;
657136849Sscottl			}
658136849Sscottl		}
659136849Sscottl		break;
660136849Sscottl
661136849Sscottl		default:
662136849Sscottl			return -1;
663136849Sscottl	}
664136849Sscottl
665136849Sscottl	return 0;
666136849Sscottl}
667136849Sscottl
668149871Sscottlint HPTLIBAPI
669149871SscottlR1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
670136849Sscottl{
671136849Sscottl	ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
672136849Sscottl	if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
673136849Sscottl		bufferSize<<=1;
674136849Sscottl	if (logical) {
675136849Sscottl		pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
676136849Sscottl		pSgTable->wSgSize = (USHORT)bufferSize;
677136849Sscottl		pSgTable->wSgFlag = SG_FLAG_EOT;
678136849Sscottl	}
679136849Sscottl	else {
680136849Sscottl		/* build physical SG table for pCmd->uCmd.R1Control.Buffer */
681136849Sscottl		ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
682136849Sscottl		ULONG length;
683136849Sscottl		int idx = 0;
684136849Sscottl
685136849Sscottl		v = pCmd->uCmd.R1Control.Buffer;
686136849Sscottl		dataPointer = (ADDRESS)fOsPhysicalAddress(v);
687136849Sscottl
688136849Sscottl		if ((ULONG_PTR)dataPointer & 0x1)
689136849Sscottl			return FALSE;
690136849Sscottl
691136849Sscottl		#define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
692136849Sscottl		#define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
693136849Sscottl
694136849Sscottl		do {
695136849Sscottl			if (idx >= MAX_SG_DESCRIPTORS)  return FALSE;
696136849Sscottl
697136849Sscottl			pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
698136849Sscottl			currvaddr = v;
699136849Sscottl			currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
700136849Sscottl
701136849Sscottl
702136849Sscottl			do {
703136849Sscottl				nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
704136849Sscottl				nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
705136849Sscottl
706136849Sscottl				if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
707136849Sscottl				nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
708136849Sscottl
709136849Sscottl				if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
710136849Sscottl					nextvaddr = nextpage;
711136849Sscottl					break;
712136849Sscottl				}
713136849Sscottl
714136849Sscottl				currvaddr = nextvaddr;
715136849Sscottl				currphypage = nextphypage;
716136849Sscottl			}while (1);
717136849Sscottl
718136849Sscottl			length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
719136849Sscottl			v = nextvaddr;
720136849Sscottl			bufferSize -= length;
721136849Sscottl
722136849Sscottl			pSgTable[idx].wSgSize = (USHORT)length;
723136849Sscottl			pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
724136849Sscottl			idx++;
725136849Sscottl
726136849Sscottl		}while (bufferSize);
727136849Sscottl	}
728136849Sscottl	return 1;
729136849Sscottl}
730136849Sscottl
731136849Sscottlstatic int End_Job=0;
732149871Sscottlvoid HPTLIBAPI
733149871Sscottlthread_io_done(_VBUS_ARG PCommand pCmd)
734136849Sscottl{
735136849Sscottl	End_Job = 1;
736136849Sscottl	wakeup((caddr_t)pCmd);
737136849Sscottl}
738136849Sscottl
739149871Sscottlvoid
740149871Sscottlhpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
741136849Sscottl{
742136849Sscottl	DWORD timeout = 0;
743136849Sscottl    ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1);
744136849Sscottl    PCommand pCmd;
745136849Sscottl	UINT result;
746136849Sscottl	int needsync=0, retry=0, needdelete=0;
747136849Sscottl	void *buffer = 0;
748136849Sscottl	intrmask_t oldspl;
749136849Sscottl
750136849Sscottl	_VBUS_INST(&pAdapter->VBus)
751136849Sscottl
752136849Sscottl	if (pArray->u.array.rf_broken==1 ||
753136849Sscottl    	pArray->u.array.RebuildSectors>=capacity)
754136849Sscottl		return;
755136849Sscottl
756136849Sscottl	oldspl = lock_driver();
757136849Sscottl
758136849Sscottl	switch(flags)
759136849Sscottl	{
760136849Sscottl		case DUPLICATE:
761136849Sscottl		case REBUILD_PARITY:
762136849Sscottl			if(pArray->u.array.rf_rebuilding == 0)
763136849Sscottl			{
764136849Sscottl				pArray->u.array.rf_rebuilding = 1;
765136849Sscottl				hpt_printk(("Rebuilding started.\n"));
766136849Sscottl				ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
767136849Sscottl			}
768136849Sscottl			break;
769136849Sscottl
770136849Sscottl		case INITIALIZE:
771136849Sscottl			if(pArray->u.array.rf_initializing == 0)
772136849Sscottl			{
773136849Sscottl				pArray->u.array.rf_initializing = 1;
774136849Sscottl				hpt_printk(("Initializing started.\n"));
775136849Sscottl				ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
776136849Sscottl			}
777136849Sscottl			break;
778136849Sscottl
779136849Sscottl		case VERIFY:
780136849Sscottl			if(pArray->u.array.rf_verifying == 0)
781136849Sscottl			{
782136849Sscottl				pArray->u.array.rf_verifying = 1;
783136849Sscottl				hpt_printk(("Verifying started.\n"));
784136849Sscottl				ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
785136849Sscottl			}
786136849Sscottl			break;
787136849Sscottl	}
788136849Sscottl
789136849Sscottlretry_cmd:
790136849Sscottl	pCmd = AllocateCommand(_VBUS_P0);
791136849Sscottl	HPT_ASSERT(pCmd);
792136849Sscottl	pCmd->cf_control = 1;
793136849Sscottl	End_Job = 0;
794136849Sscottl
795136849Sscottl	if (pArray->VDeviceType==VD_RAID_1)
796136849Sscottl	{
797136849Sscottl		#define MAX_REBUILD_SECTORS 0x40
798136849Sscottl
799136849Sscottl		/* take care for discontinuous buffer in R1ControlSgl */
800149871Sscottl		unlock_driver(oldspl);
801136849Sscottl		buffer = malloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
802149871Sscottl		oldspl = lock_driver();
803136849Sscottl		if(!buffer) {
804136849Sscottl			FreeCommand(_VBUS_P pCmd);
805136849Sscottl			hpt_printk(("can't allocate rebuild buffer\n"));
806136849Sscottl			goto fail;
807136849Sscottl		}
808136849Sscottl		switch(flags)
809136849Sscottl		{
810136849Sscottl			case DUPLICATE:
811136849Sscottl				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
812136849Sscottl				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
813136849Sscottl				break;
814136849Sscottl
815136849Sscottl			case VERIFY:
816136849Sscottl				pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
817136849Sscottl				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
818136849Sscottl				break;
819136849Sscottl
820136849Sscottl			case INITIALIZE:
821136849Sscottl				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
822136849Sscottl				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
823136849Sscottl				break;
824136849Sscottl		}
825136849Sscottl
826136849Sscottl		pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
827136849Sscottl
828136849Sscottl		if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
829136849Sscottl			pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
830136849Sscottl
831136849Sscottl		pCmd->uCmd.R1Control.Buffer = buffer;
832136849Sscottl		pCmd->pfnBuildSgl = R1ControlSgl;
833136849Sscottl	}
834136849Sscottl	else if (pArray->VDeviceType==VD_RAID_5)
835136849Sscottl	{
836136849Sscottl		switch(flags)
837136849Sscottl		{
838136849Sscottl			case DUPLICATE:
839136849Sscottl			case REBUILD_PARITY:
840136849Sscottl				pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
841136849Sscottl			case VERIFY:
842136849Sscottl				pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
843136849Sscottl			case INITIALIZE:
844136849Sscottl				pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
845136849Sscottl		}
846136849Sscottl		pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
847136849Sscottl	}
848136849Sscottl	else
849136849Sscottl		HPT_ASSERT(0);
850136849Sscottl
851136849Sscottl	pCmd->pVDevice = pArray;
852136849Sscottl	pCmd->pfnCompletion = thread_io_done;
853136849Sscottl	pArray->pfnSendCommand(_VBUS_P pCmd);
854136849Sscottl	CheckPendingCall(_VBUS_P0);
855136849Sscottl
856136849Sscottl	if (!End_Job) {
857136849Sscottl		unlock_driver(oldspl);
858136849Sscottl		while (!End_Job) {
859136849Sscottl			tsleep((caddr_t)pCmd, PPAUSE, "pause", hz);
860136849Sscottl			if (timeout++>60) break;
861136849Sscottl		}
862136849Sscottl		oldspl = lock_driver();
863136849Sscottl		if (!End_Job) {
864136849Sscottl			hpt_printk(("timeout, reset\n"));
865136849Sscottl			fResetVBus(_VBUS_P0);
866136849Sscottl		}
867136849Sscottl	}
868136849Sscottl
869136849Sscottl	result = pCmd->Result;
870136849Sscottl	FreeCommand(_VBUS_P pCmd);
871149871Sscottl	unlock_driver(oldspl);
872149871Sscottl	if (buffer) free(buffer, M_DEVBUF);
873149871Sscottl	oldspl = lock_driver();
874136849Sscottl	KdPrintI(("cmd finished %d", result));
875136849Sscottl
876136849Sscottl	switch(result)
877136849Sscottl	{
878136849Sscottl		case RETURN_SUCCESS:
879136849Sscottl			if (!pArray->u.array.rf_abort_rebuild)
880136849Sscottl			{
881136849Sscottl				if(pArray->u.array.RebuildSectors < capacity)
882136849Sscottl				{
883136849Sscottl					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
884136849Sscottl				}
885136849Sscottl				else
886136849Sscottl				{
887136849Sscottl					switch (flags)
888136849Sscottl					{
889136849Sscottl						case DUPLICATE:
890136849Sscottl						case REBUILD_PARITY:
891136849Sscottl							needsync = 1;
892136849Sscottl							pArray->u.array.rf_rebuilding = 0;
893136849Sscottl							pArray->u.array.rf_need_rebuild = 0;
894136849Sscottl							pArray->u.array.CriticalMembers = 0;
895136849Sscottl							pArray->u.array.RebuildSectors = MAX_LBA_T;
896136849Sscottl							pArray->u.array.rf_duplicate_and_create = 0;
897136849Sscottl							hpt_printk(("Rebuilding finished.\n"));
898136849Sscottl							ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
899136849Sscottl							break;
900136849Sscottl						case INITIALIZE:
901136849Sscottl							needsync = 1;
902136849Sscottl							pArray->u.array.rf_initializing = 0;
903136849Sscottl							pArray->u.array.rf_need_rebuild = 0;
904136849Sscottl							pArray->u.array.RebuildSectors = MAX_LBA_T;
905136849Sscottl							hpt_printk(("Initializing finished.\n"));
906136849Sscottl							ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
907136849Sscottl							break;
908136849Sscottl						case VERIFY:
909136849Sscottl							pArray->u.array.rf_verifying = 0;
910136849Sscottl							hpt_printk(("Verifying finished.\n"));
911136849Sscottl							ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
912136849Sscottl							break;
913136849Sscottl					}
914136849Sscottl				}
915136849Sscottl			}
916136849Sscottl			else
917136849Sscottl			{
918136849Sscottl				pArray->u.array.rf_abort_rebuild = 0;
919136849Sscottl				if (pArray->u.array.rf_rebuilding)
920136849Sscottl				{
921136849Sscottl					hpt_printk(("Abort rebuilding.\n"));
922136849Sscottl					pArray->u.array.rf_rebuilding = 0;
923136849Sscottl					pArray->u.array.rf_duplicate_and_create = 0;
924136849Sscottl					ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
925136849Sscottl				}
926136849Sscottl				else if (pArray->u.array.rf_verifying)
927136849Sscottl				{
928136849Sscottl					hpt_printk(("Abort verifying.\n"));
929136849Sscottl					pArray->u.array.rf_verifying = 0;
930136849Sscottl					ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
931136849Sscottl				}
932136849Sscottl				else if (pArray->u.array.rf_initializing)
933136849Sscottl				{
934136849Sscottl					hpt_printk(("Abort initializing.\n"));
935136849Sscottl					pArray->u.array.rf_initializing = 0;
936136849Sscottl					ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
937136849Sscottl				}
938136849Sscottl				needdelete=1;
939136849Sscottl			}
940136849Sscottl			break;
941136849Sscottl
942136849Sscottl		case RETURN_DATA_ERROR:
943136849Sscottl			if (flags==VERIFY)
944136849Sscottl			{
945136849Sscottl				needsync = 1;
946136849Sscottl				pArray->u.array.rf_verifying = 0;
947136849Sscottl				pArray->u.array.rf_need_rebuild = 1;
948136849Sscottl				hpt_printk(("Verifying failed: found inconsistency\n"));
949136849Sscottl				ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
950136849Sscottl				ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
951136849Sscottl
952136849Sscottl				if (!pArray->vf_online || pArray->u.array.rf_broken) break;
953136849Sscottl
954136849Sscottl				pArray->u.array.rf_auto_rebuild = 0;
955136849Sscottl				pArray->u.array.rf_abort_rebuild = 0;
956136849Sscottl				hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
957136849Sscottl					(pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
958136849Sscottl			}
959136849Sscottl			break;
960136849Sscottl
961136849Sscottl		default:
962136849Sscottl			hpt_printk(("command failed with error %d\n", result));
963136849Sscottl			if (++retry<3)
964136849Sscottl			{
965136849Sscottl				hpt_printk(("retry (%d)\n", retry));
966136849Sscottl				goto retry_cmd;
967136849Sscottl			}
968136849Sscottlfail:
969136849Sscottl			pArray->u.array.rf_abort_rebuild = 0;
970136849Sscottl			switch (flags)
971136849Sscottl			{
972136849Sscottl				case DUPLICATE:
973136849Sscottl				case REBUILD_PARITY:
974136849Sscottl					needsync = 1;
975136849Sscottl					pArray->u.array.rf_rebuilding = 0;
976136849Sscottl					pArray->u.array.rf_duplicate_and_create = 0;
977136849Sscottl					hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
978136849Sscottl					ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
979136849Sscottl					break;
980136849Sscottl
981136849Sscottl				case INITIALIZE:
982136849Sscottl					needsync = 1;
983136849Sscottl					pArray->u.array.rf_initializing = 0;
984136849Sscottl					hpt_printk(("Initializing failed.\n"));
985136849Sscottl					ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
986136849Sscottl					break;
987136849Sscottl
988136849Sscottl				case VERIFY:
989136849Sscottl					needsync = 1;
990136849Sscottl					pArray->u.array.rf_verifying = 0;
991136849Sscottl					hpt_printk(("Verifying failed.\n"));
992136849Sscottl					ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
993136849Sscottl					break;
994136849Sscottl			}
995136849Sscottl			needdelete=1;
996136849Sscottl	}
997136849Sscottl
998136849Sscottl	while (pAdapter->outstandingCommands)
999136849Sscottl	{
1000136849Sscottl		KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
1001136849Sscottl		/* put this to have driver stop processing system commands quickly */
1002136849Sscottl		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
1003136849Sscottl		unlock_driver(oldspl);
1004149871Sscottl		/*Schedule out*/
1005149871Sscottl#if (__FreeBSD_version < 500000)
1006149871Sscottl		YIELD_THREAD;
1007149871Sscottl#else
1008190809Sdelphij#if (__FreeBSD_version > 700033)
1009167086Sjhb		pause("switch", 1);
1010190809Sdelphij#else
1011190809Sdelphij		tsleep(hpt_rebuild_data_block, PPAUSE, "switch", 1);
1012149871Sscottl#endif
1013190809Sdelphij#endif
1014136849Sscottl		oldspl = lock_driver();
1015136849Sscottl	}
1016136849Sscottl
1017136849Sscottl	if (needsync) SyncArrayInfo(pArray);
1018136849Sscottl	if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
1019136849Sscottl		fDeleteArray(_VBUS_P pArray, TRUE);
1020136849Sscottl
1021136849Sscottl	Check_Idle_Call(pAdapter);
1022136849Sscottl	unlock_driver(oldspl);
1023136849Sscottl}
1024