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