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