xref: /dragonfly/sys/dev/raid/hptmv/ioctl.c (revision 37de577a)
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: src/sys/dev/hptmv/ioctl.c,v 1.9 2009/04/07 16:38:25 delphij Exp $
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/raid/hptmv/global.h>
41 #include <dev/raid/hptmv/hptintf.h>
42 #include <dev/raid/hptmv/osbsd.h>
43 #include <dev/raid/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 }
155 
156 static int
157 hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options)
158 {
159 	PVDevice	pArray = ID_TO_VDEV(id);
160 	BOOLEAN	del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1;
161 	int i;
162 	PVDevice pa;
163 
164 	if ((id==0) || check_VDevice_valid(pArray))
165 		return -1;
166 
167 	if(!mIsArray(pArray)) return -1;
168 
169 	if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying ||
170 		pArray->u.array.rf_initializing)
171 		return -1;
172 
173 	for(i=0; i<pArray->u.array.bArnMember; i++) {
174 		pa = pArray->u.array.pMember[i];
175 		if (pa && mIsArray(pa)) {
176 			if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying ||
177 				pa->u.array.rf_initializing)
178 				return -1;
179 		}
180 	}
181 
182 	if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
183 	fDeleteArray(_VBUS_P pArray, del_block0);
184 	return 0;
185 
186 }
187 
188 /* just to prevent driver from sending more commands */
189 static void HPTLIBAPI nothing(_VBUS_ARG void *notused){}
190 
191 static void
192 lock_driver_idle(IAL_ADAPTER_T *pAdapter)
193 {
194 	_VBUS_INST(&pAdapter->VBus)
195 	lock_driver();
196 	while (pAdapter->outstandingCommands) {
197 		KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands));
198 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
199 		unlock_driver();
200 /*Schedule out*/
201 		tsleep(lock_driver_idle, 0, "switch", 1);
202 		lock_driver();
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 			switch(dwIoControlCode) {
316 			/* read-only ioctl functions can be called directly. */
317 			case HPT_IOCTL_GET_VERSION:
318 			case HPT_IOCTL_GET_CONTROLLER_IDS:
319 			case HPT_IOCTL_GET_CONTROLLER_COUNT:
320 			case HPT_IOCTL_GET_CONTROLLER_INFO:
321 			case HPT_IOCTL_GET_CHANNEL_INFO:
322 			case HPT_IOCTL_GET_LOGICAL_DEVICES:
323 			case HPT_IOCTL_GET_DEVICE_INFO:
324 			case HPT_IOCTL_GET_DEVICE_INFO_V2:
325 			case HPT_IOCTL_GET_EVENT:
326 			case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
327 				if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
328 					lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
329 				break;
330 
331 			default:
332 				/*
333 				 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
334 				 * wrong for second controller.
335 				 */
336 				switch(dwIoControlCode) {
337 				case HPT_IOCTL_CREATE_ARRAY:
338 					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
339 				case HPT_IOCTL_CREATE_ARRAY_V2:
340 					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break;
341 				case HPT_IOCTL_SET_ARRAY_INFO:
342 					pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
343 				case HPT_IOCTL_SET_DEVICE_INFO:
344 					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
345 				case HPT_IOCTL_SET_DEVICE_INFO_V2:
346 					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break;
347 				case HPT_IOCTL_SET_BOOT_MARK:
348 				case HPT_IOCTL_ADD_SPARE_DISK:
349 				case HPT_IOCTL_REMOVE_SPARE_DISK:
350 					pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
351 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
352 					pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
353 				default:
354 					pVDev = 0;
355 				}
356 
357 				if (pVDev && !check_VDevice_valid(pVDev)){
358 					_vbus_p = pVDev->pVBus;
359 
360 					pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
361 					/*
362 					 * create_array, and other functions can't be executed while channel is
363 					 * perform I/O commands. Wait until driver is idle.
364 					 */
365 					lock_driver_idle(pAdapter);
366 					if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
367 						lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
368 						unlock_driver();
369 						return -1;
370 					}
371 					unlock_driver();
372 				}
373 				else
374 					return -1;
375 				break;
376 			}
377 
378 #ifdef SUPPORT_ARRAY
379 			switch(dwIoControlCode)
380 			{
381 				case HPT_IOCTL_CREATE_ARRAY:
382 				{
383 					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
384 					lock_driver();
385                     if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
386 				    {
387 						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
388                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
389 					}
390 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
391 				    {
392                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
393 					}
394 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
395 				    {
396                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
397 					}
398 					unlock_driver();
399                     break;
400 				}
401 
402 
403 				case HPT_IOCTL_CREATE_ARRAY_V2:
404 				{
405 					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
406 					lock_driver();
407 				             if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) {
408 						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
409 				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
410 					} else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) {
411 				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
412 					} else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) {
413 				                          hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
414 					}
415 					unlock_driver();
416 					break;
417 				}
418 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
419 				{
420 					PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
421 					pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
422 					if(pArray->u.array.rf_rebuilding == 0)
423 					{
424 						DWORD timeout = 0;
425 						lock_driver();
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 						unlock_driver();
430 						while (!pArray->u.array.rf_rebuilding)
431 						{
432 							tsleep((caddr_t)Kernel_DeviceIoControl, 0, "pause", 1);
433 							if ( timeout >= hz*3)
434 								break;
435 							timeout ++;
436 						}
437 					}
438 					break;
439 				}
440 			}
441 #endif
442             return 0;
443 		}
444 	}
445 
446 	if (lpBytesReturned)
447 		*lpBytesReturned = nOutBufferSize;
448 	return 0;
449 }
450 
451 static int
452 hpt_get_event(PHPT_EVENT pEvent)
453 {
454 	lock_driver();
455 	int ret = event_queue_remove(pEvent);
456 	unlock_driver();
457 	return ret;
458 }
459 
460 static int
461 hpt_set_array_state(DEVICEID idArray, DWORD state)
462 {
463 	IAL_ADAPTER_T *pAdapter;
464 	PVDevice pVDevice = ID_TO_VDEV(idArray);
465 	int	i;
466 	DWORD timeout = 0;
467 
468 	if(idArray == 0 || check_VDevice_valid(pVDevice))	return -1;
469 	if(!mIsArray(pVDevice))
470 		return -1;
471 	if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
472 
473 	pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
474 
475 	switch(state)
476 	{
477 		case MIRROR_REBUILD_START:
478 		{
479 			if (pVDevice->u.array.rf_rebuilding ||
480 				pVDevice->u.array.rf_verifying ||
481 				pVDevice->u.array.rf_initializing)
482 				return -1;
483 
484 			lock_driver();
485 
486 			pVDevice->u.array.rf_auto_rebuild = 0;
487 			pVDevice->u.array.rf_abort_rebuild = 0;
488 
489 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice,
490 				(UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
491 
492 			unlock_driver();
493 
494 			while (!pVDevice->u.array.rf_rebuilding)
495 			{
496 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
497 				if ( timeout >= hz*20)
498 					break;
499 				timeout ++;
500 			}
501 		}
502 
503 		break;
504 
505 		case MIRROR_REBUILD_ABORT:
506 		{
507 			for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
508 				if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
509 					hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
510 			}
511 
512 			if(pVDevice->u.array.rf_rebuilding != 1)
513 				return -1;
514 
515 			lock_driver();
516 			pVDevice->u.array.rf_abort_rebuild = 1;
517 			unlock_driver();
518 
519 			while (pVDevice->u.array.rf_abort_rebuild)
520 			{
521 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
522 				if ( timeout >= hz*20)
523 					break;
524 				timeout ++;
525 			}
526 		}
527 		break;
528 
529 		case AS_VERIFY_START:
530 		{
531 			/*if(pVDevice->u.array.rf_verifying)
532 				return -1;*/
533 			if (pVDevice->u.array.rf_rebuilding ||
534 				pVDevice->u.array.rf_verifying ||
535 				pVDevice->u.array.rf_initializing)
536 				return -1;
537 
538 			lock_driver();
539             pVDevice->u.array.RebuildSectors = 0;
540 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
541 			unlock_driver();
542 
543 			while (!pVDevice->u.array.rf_verifying)
544 			{
545 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
546 				if ( timeout >= hz*20)
547 					break;
548 				timeout ++;
549 			}
550 		}
551 		break;
552 
553 		case AS_VERIFY_ABORT:
554 		{
555 			if(pVDevice->u.array.rf_verifying != 1)
556 				return -1;
557 
558 			lock_driver();
559 			pVDevice->u.array.rf_abort_rebuild = 1;
560 			unlock_driver();
561 
562 			while (pVDevice->u.array.rf_abort_rebuild)
563 			{
564 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
565 				if ( timeout >= hz*80)
566 					break;
567 				timeout ++;
568 			}
569 		}
570 		break;
571 
572 		case AS_INITIALIZE_START:
573 		{
574 			if (pVDevice->u.array.rf_rebuilding ||
575 				pVDevice->u.array.rf_verifying ||
576 				pVDevice->u.array.rf_initializing)
577 				return -1;
578 
579 			lock_driver();
580 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
581 			unlock_driver();
582 
583 			while (!pVDevice->u.array.rf_initializing)
584 			{
585 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
586 				if ( timeout >= hz*80)
587 					break;
588 				timeout ++;
589 			}
590 		}
591 		break;
592 
593 		case AS_INITIALIZE_ABORT:
594 		{
595 			if(pVDevice->u.array.rf_initializing != 1)
596 				return -1;
597 
598 			lock_driver();
599 			pVDevice->u.array.rf_abort_rebuild = 1;
600 			unlock_driver();
601 
602 			while (pVDevice->u.array.rf_abort_rebuild)
603 			{
604 				tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
605 				if ( timeout >= hz*80)
606 					break;
607 				timeout ++;
608 			}
609 		}
610 		break;
611 
612 		default:
613 			return -1;
614 	}
615 
616 	return 0;
617 }
618 
619 static int HPTLIBAPI
620 R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
621 {
622 	ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
623 	if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
624 		bufferSize<<=1;
625 	if (logical) {
626 		pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
627 		pSgTable->wSgSize = (USHORT)bufferSize;
628 		pSgTable->wSgFlag = SG_FLAG_EOT;
629 	}
630 	else {
631 		/* build physical SG table for pCmd->uCmd.R1Control.Buffer */
632 		ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
633 		ULONG length;
634 		int idx = 0;
635 
636 		v = pCmd->uCmd.R1Control.Buffer;
637 		dataPointer = (ADDRESS)fOsPhysicalAddress(v);
638 
639 		if ((ULONG_PTR)dataPointer & 0x1)
640 			return FALSE;
641 
642 		#define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
643 		#define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
644 
645 		do {
646 			if (idx >= MAX_SG_DESCRIPTORS)  return FALSE;
647 
648 			pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
649 			currvaddr = v;
650 			currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
651 
652 
653 			do {
654 				nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
655 				nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
656 
657 				if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
658 				nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
659 
660 				if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
661 					nextvaddr = nextpage;
662 					break;
663 				}
664 
665 				currvaddr = nextvaddr;
666 				currphypage = nextphypage;
667 			}while (1);
668 
669 			length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
670 			v = nextvaddr;
671 			bufferSize -= length;
672 
673 			pSgTable[idx].wSgSize = (USHORT)length;
674 			pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
675 			idx++;
676 
677 		}while (bufferSize);
678 	}
679 	return 1;
680 }
681 
682 static int End_Job=0;
683 static void HPTLIBAPI
684 thread_io_done(_VBUS_ARG PCommand pCmd)
685 {
686 	End_Job = 1;
687 	wakeup((caddr_t)pCmd);
688 }
689 
690 void
691 hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
692 {
693 	DWORD timeout = 0;
694     ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1);
695     PCommand pCmd;
696 	UINT result;
697 	int needsync=0, retry=0, needdelete=0;
698 	void *buffer = NULL;
699 
700 	_VBUS_INST(&pAdapter->VBus)
701 
702 	if (pArray->u.array.rf_broken==1 ||
703 	pArray->u.array.RebuildSectors>=capacity)
704 		return;
705 
706 	lock_driver();
707 
708 	switch(flags)
709 	{
710 		case DUPLICATE:
711 		case REBUILD_PARITY:
712 			if(pArray->u.array.rf_rebuilding == 0)
713 			{
714 				pArray->u.array.rf_rebuilding = 1;
715 				hpt_printk(("Rebuilding started.\n"));
716 				ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
717 			}
718 			break;
719 
720 		case INITIALIZE:
721 			if(pArray->u.array.rf_initializing == 0)
722 			{
723 				pArray->u.array.rf_initializing = 1;
724 				hpt_printk(("Initializing started.\n"));
725 				ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
726 			}
727 			break;
728 
729 		case VERIFY:
730 			if(pArray->u.array.rf_verifying == 0)
731 			{
732 				pArray->u.array.rf_verifying = 1;
733 				hpt_printk(("Verifying started.\n"));
734 				ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
735 			}
736 			break;
737 	}
738 
739 retry_cmd:
740 	pCmd = AllocateCommand(_VBUS_P0);
741 	HPT_ASSERT(pCmd);
742 	pCmd->cf_control = 1;
743 	End_Job = 0;
744 
745 	if (pArray->VDeviceType==VD_RAID_1)
746 	{
747 		#define MAX_REBUILD_SECTORS 0x40
748 
749 		/* take care for discontinuous buffer in R1ControlSgl */
750 		unlock_driver();
751 		buffer = kmalloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
752 		lock_driver();
753 		if(!buffer) {
754 			FreeCommand(_VBUS_P pCmd);
755 			hpt_printk(("can't allocate rebuild buffer\n"));
756 			goto fail;
757 		}
758 		switch(flags)
759 		{
760 			case DUPLICATE:
761 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
762 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
763 				break;
764 
765 			case VERIFY:
766 				pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
767 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
768 				break;
769 
770 			case INITIALIZE:
771 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
772 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
773 				break;
774 		}
775 
776 		pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
777 
778 		if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
779 			pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
780 
781 		pCmd->uCmd.R1Control.Buffer = buffer;
782 		pCmd->pfnBuildSgl = R1ControlSgl;
783 	}
784 	else if (pArray->VDeviceType==VD_RAID_5)
785 	{
786 		switch(flags)
787 		{
788 			case DUPLICATE:
789 			case REBUILD_PARITY:
790 				pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
791 			case VERIFY:
792 				pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
793 			case INITIALIZE:
794 				pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
795 		}
796 		pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
797 	}
798 	else
799 		HPT_ASSERT(0);
800 
801 	pCmd->pVDevice = pArray;
802 	pCmd->pfnCompletion = thread_io_done;
803 	pArray->pfnSendCommand(_VBUS_P pCmd);
804 	CheckPendingCall(_VBUS_P0);
805 
806 	if (!End_Job) {
807 		unlock_driver();
808 		while (!End_Job) {
809 			tsleep((caddr_t)pCmd, 0, "pause", hz);
810 			if (timeout++>60) break;
811 		}
812 		lock_driver();
813 		if (!End_Job) {
814 			hpt_printk(("timeout, reset\n"));
815 			fResetVBus(_VBUS_P0);
816 		}
817 	}
818 
819 	result = pCmd->Result;
820 	FreeCommand(_VBUS_P pCmd);
821 	unlock_driver();
822 	if (buffer) kfree(buffer, M_DEVBUF);
823 	lock_driver();
824 	KdPrintI(("cmd finished %d", result));
825 
826 	switch(result)
827 	{
828 		case RETURN_SUCCESS:
829 			if (!pArray->u.array.rf_abort_rebuild)
830 			{
831 				if(pArray->u.array.RebuildSectors < capacity)
832 				{
833 					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
834 				}
835 				else
836 				{
837 					switch (flags)
838 					{
839 						case DUPLICATE:
840 						case REBUILD_PARITY:
841 							needsync = 1;
842 							pArray->u.array.rf_rebuilding = 0;
843 							pArray->u.array.rf_need_rebuild = 0;
844 							pArray->u.array.CriticalMembers = 0;
845 							pArray->u.array.RebuildSectors = MAX_LBA_T;
846 							pArray->u.array.rf_duplicate_and_create = 0;
847 							hpt_printk(("Rebuilding finished.\n"));
848 							ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
849 							break;
850 						case INITIALIZE:
851 							needsync = 1;
852 							pArray->u.array.rf_initializing = 0;
853 							pArray->u.array.rf_need_rebuild = 0;
854 							pArray->u.array.RebuildSectors = MAX_LBA_T;
855 							hpt_printk(("Initializing finished.\n"));
856 							ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
857 							break;
858 						case VERIFY:
859 							pArray->u.array.rf_verifying = 0;
860 							hpt_printk(("Verifying finished.\n"));
861 							ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
862 							break;
863 					}
864 				}
865 			}
866 			else
867 			{
868 				pArray->u.array.rf_abort_rebuild = 0;
869 				if (pArray->u.array.rf_rebuilding)
870 				{
871 					hpt_printk(("Abort rebuilding.\n"));
872 					pArray->u.array.rf_rebuilding = 0;
873 					pArray->u.array.rf_duplicate_and_create = 0;
874 					ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
875 				}
876 				else if (pArray->u.array.rf_verifying)
877 				{
878 					hpt_printk(("Abort verifying.\n"));
879 					pArray->u.array.rf_verifying = 0;
880 					ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
881 				}
882 				else if (pArray->u.array.rf_initializing)
883 				{
884 					hpt_printk(("Abort initializing.\n"));
885 					pArray->u.array.rf_initializing = 0;
886 					ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
887 				}
888 				needdelete=1;
889 			}
890 			break;
891 
892 		case RETURN_DATA_ERROR:
893 			if (flags==VERIFY)
894 			{
895 				needsync = 1;
896 				pArray->u.array.rf_verifying = 0;
897 				pArray->u.array.rf_need_rebuild = 1;
898 				hpt_printk(("Verifying failed: found inconsistency\n"));
899 				ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
900 				ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
901 
902 				if (!pArray->vf_online || pArray->u.array.rf_broken) break;
903 
904 				pArray->u.array.rf_auto_rebuild = 0;
905 				pArray->u.array.rf_abort_rebuild = 0;
906 				hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
907 					(pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
908 			}
909 			break;
910 
911 		default:
912 			hpt_printk(("command failed with error %d\n", result));
913 			if (++retry<3)
914 			{
915 				hpt_printk(("retry (%d)\n", retry));
916 				goto retry_cmd;
917 			}
918 fail:
919 			pArray->u.array.rf_abort_rebuild = 0;
920 			switch (flags)
921 			{
922 				case DUPLICATE:
923 				case REBUILD_PARITY:
924 					needsync = 1;
925 					pArray->u.array.rf_rebuilding = 0;
926 					pArray->u.array.rf_duplicate_and_create = 0;
927 					hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
928 					ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
929 					break;
930 
931 				case INITIALIZE:
932 					needsync = 1;
933 					pArray->u.array.rf_initializing = 0;
934 					hpt_printk(("Initializing failed.\n"));
935 					ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
936 					break;
937 
938 				case VERIFY:
939 					needsync = 1;
940 					pArray->u.array.rf_verifying = 0;
941 					hpt_printk(("Verifying failed.\n"));
942 					ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
943 					break;
944 			}
945 			needdelete=1;
946 	}
947 
948 	while (pAdapter->outstandingCommands)
949 	{
950 		KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
951 		/* put this to have driver stop processing system commands quickly */
952 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
953 		unlock_driver();
954 		/*Schedule out*/
955 		tsleep(hpt_rebuild_data_block, 0, "switch", 1);
956 		lock_driver();
957 	}
958 
959 	if (needsync) SyncArrayInfo(pArray);
960 	if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
961 		fDeleteArray(_VBUS_P pArray, TRUE);
962 
963 	Check_Idle_Call(pAdapter);
964 	unlock_driver();
965 }
966