xref: /freebsd/sys/dev/hptmv/ioctl.c (revision 1713e81b9cdf06d2a9a365a7ded13a54fad84798)
1 /*
2  * Copyright (c) 2003-2004 HighPoint Technologies, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27  * ioctl.c   ioctl interface implementation
28  */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 
34 #include <dev/hptmv/global.h>
35 #include <dev/hptmv/hptintf.h>
36 #include <dev/hptmv/osbsd.h>
37 #include <contrib/dev/hptmv/access601.h>
38 
39 #pragma pack(1)
40 
41 typedef struct _HPT_REBUILD_PARAM
42 {
43 	DEVICEID idMirror;
44 	DWORD Lba;
45 	UCHAR nSector;
46 } HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM;
47 
48 #pragma pack()
49 
50 #define MAX_EVENTS 10
51 static HPT_EVENT hpt_event_queue[MAX_EVENTS];
52 static int event_queue_head=0, event_queue_tail=0;
53 
54 static int hpt_get_event(PHPT_EVENT pEvent);
55 static int hpt_set_array_state(DEVICEID idArray, DWORD state);
56 static intrmask_t lock_driver_idle(IAL_ADAPTER_T *pAdapter);
57 static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd);
58 static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd,
59     FPSCAT_GATH pSgTable, int logical);
60 
61 static void get_disk_location(PDevice pDev, int *controller, int *channel)
62 {
63 	IAL_ADAPTER_T *pAdapTemp;
64 	int i, j;
65 
66     for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) {
67     	for (j=0; j<MV_SATA_CHANNELS_NUM; j++)
68     		if (pDev==&pAdapTemp->VDevices[j].u.disk) {
69     			*controller = i;
70     			*channel = j;
71     			return;
72     		}
73 	}
74 }
75 
76 static int event_queue_add(PHPT_EVENT pEvent)
77 {
78 	int p;
79 	p = (event_queue_tail + 1) % MAX_EVENTS;
80 	if (p==event_queue_head)
81 	{
82 		return -1;
83 	}
84 	hpt_event_queue[event_queue_tail] = *pEvent;
85 	event_queue_tail = p;
86 	return 0;
87 }
88 
89 static int event_queue_remove(PHPT_EVENT pEvent)
90 {
91 	if (event_queue_head != event_queue_tail)
92 	{
93 		*pEvent = hpt_event_queue[event_queue_head];
94 		event_queue_head++;
95 		event_queue_head %= MAX_EVENTS;
96 		return 0;
97 	}
98 	return -1;
99 }
100 
101 void HPTLIBAPI ioctl_ReportEvent(UCHAR event, PVOID param)
102 {
103 	HPT_EVENT e;
104 	ZeroMemory(&e, sizeof(e));
105 	e.EventType = event;
106 	switch(event)
107 	{
108 		case ET_INITIALIZE_ABORTED:
109 		case ET_INITIALIZE_FAILED:
110 			memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME);
111 		case ET_INITIALIZE_STARTED:
112 		case ET_INITIALIZE_FINISHED:
113 
114 		case ET_REBUILD_STARTED:
115 		case ET_REBUILD_ABORTED:
116 		case ET_REBUILD_FAILED:
117 		case ET_REBUILD_FINISHED:
118 
119 		case ET_VERIFY_STARTED:
120 		case ET_VERIFY_ABORTED:
121 		case ET_VERIFY_FAILED:
122 		case ET_VERIFY_FINISHED:
123 		case ET_VERIFY_DATA_ERROR:
124 
125 		case ET_SPARE_TOOK_OVER:
126 		case ET_DEVICE_REMOVED:
127 		case ET_DEVICE_PLUGGED:
128 		case ET_DEVICE_ERROR:
129 			e.DeviceID = VDEV_TO_ID((PVDevice)param);
130 			break;
131 
132 		default:
133 			break;
134 	}
135 	event_queue_add(&e);
136 	if (event==ET_DEVICE_REMOVED) {
137 		int controller, channel;
138 		get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel);
139 		hpt_printk(("Device removed: controller %d channel %d\n", controller, channel));
140 	}
141 }
142 
143 static int hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options)
144 {
145 	PVDevice	pArray = ID_TO_VDEV(id);
146 	BOOLEAN	del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1;
147 	int i;
148 	PVDevice pa;
149 
150 	if((id== HPT_NULL_ID) || check_VDevice_valid(pArray))
151 		return -1;
152 
153 	if(!mIsArray(pArray)) return -1;
154 
155 	if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying ||
156 		pArray->u.array.rf_initializing)
157 		return -1;
158 
159 	for(i=0; i<pArray->u.array.bArnMember; i++) {
160 		pa = pArray->u.array.pMember[i];
161 		if (pa && mIsArray(pa)) {
162 			if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying ||
163 				pa->u.array.rf_initializing)
164 				return -1;
165 		}
166 	}
167 
168 	if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
169 	fDeleteArray(_VBUS_P pArray, del_block0);
170 	return 0;
171 
172 }
173 
174 /* just to prevent driver from sending more commands */
175 static void HPTLIBAPI nothing(_VBUS_ARG void *notused){}
176 
177 static intrmask_t lock_driver_idle(IAL_ADAPTER_T *pAdapter)
178 {
179 	intrmask_t oldspl;
180 	_VBUS_INST(&pAdapter->VBus)
181 	oldspl = lock_driver();
182 	while (pAdapter->outstandingCommands) {
183 		KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands));
184 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
185 		unlock_driver(oldspl);
186 		oldspl = lock_driver();
187 	}
188 	CheckIdleCall(_VBUS_P0);
189 	return oldspl;
190 }
191 
192 int Kernel_DeviceIoControl(_VBUS_ARG
193 							DWORD dwIoControlCode,       	/* operation control code */
194 							PVOID lpInBuffer,            	/* input data buffer */
195 							DWORD nInBufferSize,         	/* size of input data buffer */
196 							PVOID lpOutBuffer,           	/* output data buffer */
197 							DWORD nOutBufferSize,        	/* size of output data buffer */
198 							PDWORD lpBytesReturned      	/* byte count */
199 						)
200 {
201 	IAL_ADAPTER_T *pAdapter;
202 
203 	switch(dwIoControlCode)	{
204 		case HPT_IOCTL_DELETE_ARRAY:
205 		{
206 			DEVICEID idArray;
207 			int iSuccess;
208 	        int i;
209 			PVDevice pArray;
210 			PVBus _vbus_p;
211 			struct cam_periph *periph = NULL;
212 
213 			if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1;
214 			if (nOutBufferSize!=sizeof(int)) return -1;
215 			idArray = *(DEVICEID *)lpInBuffer;
216 
217 			pArray = ID_TO_VDEV(idArray);
218 
219 			if((idArray == HPT_NULL_ID) || check_VDevice_valid(pArray))
220 		       	return -1;
221 
222         	if(!mIsArray(pArray))
223 			return -1;
224 
225 			_vbus_p=pArray->pVBus;
226 			pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
227 
228 	        for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) {
229 				if(pArray == _vbus_p->pVDevice[i])
230 				{
231 					periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
232 					if (periph != NULL && periph->refcount == 1)
233 					{
234 						hpt_printk(("Can not delete a mounted device.\n"));
235 	                    return -1;
236 					}
237 				}
238 				/* the Mounted Disk isn't delete */
239 			}
240 
241 			iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1));
242 
243 			*(int*)lpOutBuffer = iSuccess;
244 
245 			if(iSuccess != 0)
246 				return -1;
247 			break;
248 		}
249 
250 		case HPT_IOCTL_GET_EVENT:
251 		{
252 			PHPT_EVENT pInfo;
253 
254 			if (nInBufferSize!=0) return -1;
255 			if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1;
256 
257 			pInfo = (PHPT_EVENT)lpOutBuffer;
258 
259 			if (hpt_get_event(pInfo)!=0)
260 				return -1;
261 		}
262 		break;
263 
264 		case HPT_IOCTL_SET_ARRAY_STATE:
265 		{
266 			DEVICEID idArray;
267 			DWORD state;
268 
269 			if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1;
270 			if (nOutBufferSize!=0) return -1;
271 
272 			idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray;
273 			state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state;
274 
275 			if(hpt_set_array_state(idArray, state)!=0)
276 				return -1;
277 		}
278 		break;
279 
280 		case HPT_IOCTL_RESCAN_DEVICES:
281 		{
282 			if (nInBufferSize!=0) return -1;
283 			if (nOutBufferSize!=0) return -1;
284 
285 #ifndef FOR_DEMO
286 			/* stop buzzer if user perform rescan */
287 			for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
288 				if (pAdapter->beeping) {
289 					pAdapter->beeping = 0;
290 					BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
291 				}
292 			}
293 #endif
294 		}
295 		break;
296 
297 		default:
298 		{
299 			PVDevice pVDev;
300 #ifdef SUPPORT_ARRAY
301 			intrmask_t oldspl;
302 #endif
303 			switch(dwIoControlCode) {
304 			/* read-only ioctl functions can be called directly. */
305 			case HPT_IOCTL_GET_VERSION:
306 			case HPT_IOCTL_GET_CONTROLLER_IDS:
307 			case HPT_IOCTL_GET_CONTROLLER_COUNT:
308 			case HPT_IOCTL_GET_CONTROLLER_INFO:
309 			case HPT_IOCTL_GET_CHANNEL_INFO:
310 			case HPT_IOCTL_GET_LOGICAL_DEVICES:
311 			case HPT_IOCTL_GET_DEVICE_INFO:
312 			case HPT_IOCTL_GET_EVENT:
313 			case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
314 				if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
315 					lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
316 				break;
317 
318 			default:
319 				/*
320 				 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
321 				 * wrong for second controller.
322 				 */
323 				switch(dwIoControlCode) {
324 				case HPT_IOCTL_CREATE_ARRAY:
325 					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
326 				case HPT_IOCTL_SET_ARRAY_INFO:
327 					pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
328 				case HPT_IOCTL_SET_DEVICE_INFO:
329 					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
330 				case HPT_IOCTL_SET_BOOT_MARK:
331 				case HPT_IOCTL_ADD_SPARE_DISK:
332 				case HPT_IOCTL_REMOVE_SPARE_DISK:
333 					pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
334 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
335 					pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
336 				default:
337 					pVDev = 0;
338 				}
339 
340 				if (pVDev && !check_VDevice_valid(pVDev)){
341 					_vbus_p = pVDev->pVBus;
342 
343 					pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
344 					/*
345 					 * create_array, and other functions can't be executed while channel is
346 					 * perform I/O commands. Wait until driver is idle.
347 					 */
348 					oldspl = lock_driver_idle(pAdapter);
349 					if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
350 						lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
351 						unlock_driver(oldspl);
352 						return -1;
353 					}
354 					unlock_driver(oldspl);
355 				}
356 				else
357 					return -1;
358 				break;
359 			}
360 
361 #ifdef SUPPORT_ARRAY
362 			switch(dwIoControlCode)
363 			{
364 				case HPT_IOCTL_CREATE_ARRAY:
365 				{
366 					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
367 					oldspl = lock_driver();
368                     if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
369 				    {
370 						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
371                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
372 					}
373 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
374 				    {
375                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
376 					}
377 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
378 				    {
379                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
380 					}
381 					unlock_driver(oldspl);
382                     break;
383 				}
384 
385 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
386 				{
387 					PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
388 					pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
389 					if(pArray->u.array.rf_rebuilding == HPT_NULL_ID)
390 					{
391 						DWORD timeout = 0;
392 						oldspl = lock_driver();
393 						pArray->u.array.rf_auto_rebuild = 0;
394 						pArray->u.array.rf_abort_rebuild = 0;
395 						hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE);
396 						unlock_driver(oldspl);
397 						while (!pArray->u.array.rf_rebuilding)
398 						{
399 							tsleep((caddr_t)Kernel_DeviceIoControl, PPAUSE, "pause", 1);
400 							if ( timeout >= hz*3)
401 								break;
402 							timeout ++;
403 						}
404 					}
405 					break;
406 				}
407 			}
408 #endif
409             return 0;
410 		}
411 	}
412 
413 	if (lpBytesReturned)
414 		*lpBytesReturned = nOutBufferSize;
415 	return 0;
416 }
417 
418 static int hpt_get_event(PHPT_EVENT pEvent)
419 {
420 	intrmask_t oldspl = lock_driver();
421 	int ret = event_queue_remove(pEvent);
422 	unlock_driver(oldspl);
423 	return ret;
424 }
425 
426 static int hpt_set_array_state(DEVICEID idArray, DWORD state)
427 {
428 	IAL_ADAPTER_T *pAdapter;
429 	PVDevice pVDevice = ID_TO_VDEV(idArray);
430 	int	i;
431 	DWORD timeout = 0;
432 	intrmask_t oldspl;
433 
434 	if(idArray == HPT_NULL_ID || check_VDevice_valid(pVDevice))
435 		return -1;
436 	if(!mIsArray(pVDevice))
437 		return -1;
438 	if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
439 
440 	pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
441 
442 	switch(state)
443 	{
444 		case MIRROR_REBUILD_START:
445 		{
446 			if (pVDevice->u.array.rf_rebuilding ||
447 				pVDevice->u.array.rf_verifying ||
448 				pVDevice->u.array.rf_initializing)
449 				return -1;
450 
451 			oldspl = lock_driver();
452 
453 			pVDevice->u.array.rf_auto_rebuild = 0;
454 			pVDevice->u.array.rf_abort_rebuild = 0;
455 
456 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice,
457 				(UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
458 
459 			unlock_driver(oldspl);
460 
461 			while (!pVDevice->u.array.rf_rebuilding)
462 			{
463 				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
464 				if ( timeout >= hz*20)
465 					break;
466 				timeout ++;
467 			}
468 		}
469 
470 		break;
471 
472 		case MIRROR_REBUILD_ABORT:
473 		{
474 			for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
475 				if(pVDevice->u.array.pMember[i] != NULL && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
476 					hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
477 			}
478 
479 			if(pVDevice->u.array.rf_rebuilding != 1)
480 				return -1;
481 
482 			oldspl = lock_driver();
483 			pVDevice->u.array.rf_abort_rebuild = 1;
484 			unlock_driver(oldspl);
485 
486 			while (pVDevice->u.array.rf_abort_rebuild)
487 			{
488 				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
489 				if ( timeout >= hz*20)
490 					break;
491 				timeout ++;
492 			}
493 		}
494 		break;
495 
496 		case AS_VERIFY_START:
497 		{
498 			/*if(pVDevice->u.array.rf_verifying)
499 				return -1;*/
500 			if (pVDevice->u.array.rf_rebuilding ||
501 				pVDevice->u.array.rf_verifying ||
502 				pVDevice->u.array.rf_initializing)
503 				return -1;
504 
505 			oldspl = lock_driver();
506             pVDevice->u.array.RebuildSectors = 0;
507 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
508 			unlock_driver(oldspl);
509 
510 			while (!pVDevice->u.array.rf_verifying)
511 			{
512 				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
513 				if ( timeout >= hz*20)
514 					break;
515 				timeout ++;
516 			}
517 		}
518 		break;
519 
520 		case AS_VERIFY_ABORT:
521 		{
522 			if(pVDevice->u.array.rf_verifying != 1)
523 				return -1;
524 
525 			oldspl = lock_driver();
526 			pVDevice->u.array.rf_abort_rebuild = 1;
527 			unlock_driver(oldspl);
528 
529 			while (pVDevice->u.array.rf_abort_rebuild)
530 			{
531 				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
532 				if ( timeout >= hz*80)
533 					break;
534 				timeout ++;
535 			}
536 		}
537 		break;
538 
539 		case AS_INITIALIZE_START:
540 		{
541 			if (pVDevice->u.array.rf_rebuilding ||
542 				pVDevice->u.array.rf_verifying ||
543 				pVDevice->u.array.rf_initializing)
544 				return -1;
545 
546 			oldspl = lock_driver();
547 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
548 			unlock_driver(oldspl);
549 
550 			while (!pVDevice->u.array.rf_initializing)
551 			{
552 				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
553 				if ( timeout >= hz*80)
554 					break;
555 				timeout ++;
556 			}
557 		}
558 		break;
559 
560 		case AS_INITIALIZE_ABORT:
561 		{
562 			if(pVDevice->u.array.rf_initializing != 1)
563 				return -1;
564 
565 			oldspl = lock_driver();
566 			pVDevice->u.array.rf_abort_rebuild = 1;
567 			unlock_driver(oldspl);
568 
569 			while (pVDevice->u.array.rf_abort_rebuild)
570 			{
571 				tsleep((caddr_t)hpt_set_array_state, PPAUSE, "pause", 1);
572 				if ( timeout >= hz*80)
573 					break;
574 				timeout ++;
575 			}
576 		}
577 		break;
578 
579 		default:
580 			return -1;
581 	}
582 
583 	return 0;
584 }
585 
586 static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
587 {
588 	ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
589 	if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
590 		bufferSize<<=1;
591 	if (logical) {
592 		pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
593 		pSgTable->wSgSize = (USHORT)bufferSize;
594 		pSgTable->wSgFlag = SG_FLAG_EOT;
595 	}
596 	else {
597 		/* build physical SG table for pCmd->uCmd.R1Control.Buffer */
598 		ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
599 		ULONG length;
600 		int idx = 0;
601 
602 		v = pCmd->uCmd.R1Control.Buffer;
603 		dataPointer = (ADDRESS)fOsPhysicalAddress(v);
604 
605 		if ((ULONG_PTR)dataPointer & 0x1)
606 			return FALSE;
607 
608 		#define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
609 		#define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
610 
611 		do {
612 			if (idx >= MAX_SG_DESCRIPTORS)  return FALSE;
613 
614 			pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
615 			currvaddr = v;
616 			currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
617 
618 
619 			do {
620 				nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
621 				nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
622 
623 				if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
624 				nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
625 
626 				if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
627 					nextvaddr = nextpage;
628 					break;
629 				}
630 
631 				currvaddr = nextvaddr;
632 				currphypage = nextphypage;
633 			}while (1);
634 
635 			length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
636 			v = nextvaddr;
637 			bufferSize -= length;
638 
639 			pSgTable[idx].wSgSize = (USHORT)length;
640 			pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
641 			idx++;
642 
643 		}while (bufferSize);
644 	}
645 	return 1;
646 }
647 
648 static int End_Job=0;
649 static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd)
650 {
651 	End_Job = 1;
652 	wakeup((caddr_t)pCmd);
653 }
654 
655 void hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
656 {
657 	DWORD timeout = 0;
658     ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1);
659     PCommand pCmd;
660 	UINT result;
661 	int needsync=0, retry=0, needdelete=0;
662 	void *buffer = 0;
663 	intrmask_t oldspl;
664 
665 	_VBUS_INST(&pAdapter->VBus)
666 
667 	if (pArray->u.array.rf_broken==1 ||
668     	pArray->u.array.RebuildSectors>=capacity)
669 		return;
670 
671 	oldspl = lock_driver();
672 
673 	switch(flags)
674 	{
675 		case DUPLICATE:
676 		case REBUILD_PARITY:
677 			if(pArray->u.array.rf_rebuilding == 0)
678 			{
679 				pArray->u.array.rf_rebuilding = 1;
680 				hpt_printk(("Rebuilding started.\n"));
681 				ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
682 			}
683 			break;
684 
685 		case INITIALIZE:
686 			if(pArray->u.array.rf_initializing == 0)
687 			{
688 				pArray->u.array.rf_initializing = 1;
689 				hpt_printk(("Initializing started.\n"));
690 				ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
691 			}
692 			break;
693 
694 		case VERIFY:
695 			if(pArray->u.array.rf_verifying == 0)
696 			{
697 				pArray->u.array.rf_verifying = 1;
698 				hpt_printk(("Verifying started.\n"));
699 				ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
700 			}
701 			break;
702 	}
703 
704 retry_cmd:
705 	pCmd = AllocateCommand(_VBUS_P0);
706 	HPT_ASSERT(pCmd);
707 	pCmd->cf_control = 1;
708 	End_Job = 0;
709 
710 	if (pArray->VDeviceType==VD_RAID_1)
711 	{
712 		#define MAX_REBUILD_SECTORS 0x40
713 
714 		/* take care for discontinuous buffer in R1ControlSgl */
715 		buffer = malloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
716 		if(!buffer) {
717 			FreeCommand(_VBUS_P pCmd);
718 			hpt_printk(("can't allocate rebuild buffer\n"));
719 			goto fail;
720 		}
721 		switch(flags)
722 		{
723 			case DUPLICATE:
724 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
725 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
726 				break;
727 
728 			case VERIFY:
729 				pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
730 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
731 				break;
732 
733 			case INITIALIZE:
734 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
735 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
736 				break;
737 		}
738 
739 		pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
740 
741 		if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
742 			pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
743 
744 		pCmd->uCmd.R1Control.Buffer = buffer;
745 		pCmd->pfnBuildSgl = R1ControlSgl;
746 	}
747 	else if (pArray->VDeviceType==VD_RAID_5)
748 	{
749 		switch(flags)
750 		{
751 			case DUPLICATE:
752 			case REBUILD_PARITY:
753 				pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
754 			case VERIFY:
755 				pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
756 			case INITIALIZE:
757 				pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
758 		}
759 		pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
760 	}
761 	else
762 		HPT_ASSERT(0);
763 
764 	pCmd->pVDevice = pArray;
765 	pCmd->pfnCompletion = thread_io_done;
766 	pArray->pfnSendCommand(_VBUS_P pCmd);
767 	CheckPendingCall(_VBUS_P0);
768 
769 	if (!End_Job) {
770 		unlock_driver(oldspl);
771 		while (!End_Job) {
772 			tsleep((caddr_t)pCmd, PPAUSE, "pause", hz);
773 			if (timeout++>60) break;
774 		}
775 		oldspl = lock_driver();
776 		if (!End_Job) {
777 			hpt_printk(("timeout, reset\n"));
778 			fResetVBus(_VBUS_P0);
779 		}
780 	}
781 
782 	result = pCmd->Result;
783 	FreeCommand(_VBUS_P pCmd);
784 	if (buffer) free(buffer, M_DEVBUF);
785 	KdPrintI(("cmd finished %d", result));
786 
787 	switch(result)
788 	{
789 		case RETURN_SUCCESS:
790 			if (!pArray->u.array.rf_abort_rebuild)
791 			{
792 				if(pArray->u.array.RebuildSectors < capacity)
793 				{
794 					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
795 				}
796 				else
797 				{
798 					switch (flags)
799 					{
800 						case DUPLICATE:
801 						case REBUILD_PARITY:
802 							needsync = 1;
803 							pArray->u.array.rf_rebuilding = 0;
804 							pArray->u.array.rf_need_rebuild = 0;
805 							pArray->u.array.CriticalMembers = 0;
806 							pArray->u.array.RebuildSectors = MAX_LBA_T;
807 							pArray->u.array.rf_duplicate_and_create = 0;
808 							hpt_printk(("Rebuilding finished.\n"));
809 							ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
810 							break;
811 						case INITIALIZE:
812 							needsync = 1;
813 							pArray->u.array.rf_initializing = 0;
814 							pArray->u.array.rf_need_rebuild = 0;
815 							pArray->u.array.RebuildSectors = MAX_LBA_T;
816 							hpt_printk(("Initializing finished.\n"));
817 							ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
818 							break;
819 						case VERIFY:
820 							pArray->u.array.rf_verifying = 0;
821 							hpt_printk(("Verifying finished.\n"));
822 							ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
823 							break;
824 					}
825 				}
826 			}
827 			else
828 			{
829 				pArray->u.array.rf_abort_rebuild = 0;
830 				if (pArray->u.array.rf_rebuilding)
831 				{
832 					hpt_printk(("Abort rebuilding.\n"));
833 					pArray->u.array.rf_rebuilding = 0;
834 					pArray->u.array.rf_duplicate_and_create = 0;
835 					ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
836 				}
837 				else if (pArray->u.array.rf_verifying)
838 				{
839 					hpt_printk(("Abort verifying.\n"));
840 					pArray->u.array.rf_verifying = 0;
841 					ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
842 				}
843 				else if (pArray->u.array.rf_initializing)
844 				{
845 					hpt_printk(("Abort initializing.\n"));
846 					pArray->u.array.rf_initializing = 0;
847 					ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
848 				}
849 				needdelete=1;
850 			}
851 			break;
852 
853 		case RETURN_DATA_ERROR:
854 			if (flags==VERIFY)
855 			{
856 				needsync = 1;
857 				pArray->u.array.rf_verifying = 0;
858 				pArray->u.array.rf_need_rebuild = 1;
859 				hpt_printk(("Verifying failed: found inconsistency\n"));
860 				ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
861 				ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
862 
863 				if (!pArray->vf_online || pArray->u.array.rf_broken) break;
864 
865 				pArray->u.array.rf_auto_rebuild = 0;
866 				pArray->u.array.rf_abort_rebuild = 0;
867 				hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
868 					(pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
869 			}
870 			break;
871 
872 		default:
873 			hpt_printk(("command failed with error %d\n", result));
874 			if (++retry<3)
875 			{
876 				hpt_printk(("retry (%d)\n", retry));
877 				goto retry_cmd;
878 			}
879 fail:
880 			pArray->u.array.rf_abort_rebuild = 0;
881 			switch (flags)
882 			{
883 				case DUPLICATE:
884 				case REBUILD_PARITY:
885 					needsync = 1;
886 					pArray->u.array.rf_rebuilding = 0;
887 					pArray->u.array.rf_duplicate_and_create = 0;
888 					hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
889 					ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
890 					break;
891 
892 				case INITIALIZE:
893 					needsync = 1;
894 					pArray->u.array.rf_initializing = 0;
895 					hpt_printk(("Initializing failed.\n"));
896 					ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
897 					break;
898 
899 				case VERIFY:
900 					needsync = 1;
901 					pArray->u.array.rf_verifying = 0;
902 					hpt_printk(("Verifying failed.\n"));
903 					ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
904 					break;
905 			}
906 			needdelete=1;
907 	}
908 
909 	while (pAdapter->outstandingCommands)
910 	{
911 		KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
912 		/* put this to have driver stop processing system commands quickly */
913 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
914 		unlock_driver(oldspl);
915 		oldspl = lock_driver();
916 	}
917 
918 	if (needsync) SyncArrayInfo(pArray);
919 	if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
920 		fDeleteArray(_VBUS_P pArray, TRUE);
921 
922 	Check_Idle_Call(pAdapter);
923 	unlock_driver(oldspl);
924 }
925