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