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