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