xref: /freebsd/sys/dev/hptmv/ioctl.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 		pause("switch", 1);
213 #endif
214 		oldspl = lock_driver();
215 	}
216 	CheckIdleCall(_VBUS_P0);
217 	return oldspl;
218 }
219 
220 int Kernel_DeviceIoControl(_VBUS_ARG
221 							DWORD dwIoControlCode,       	/* operation control code */
222 							PVOID lpInBuffer,            	/* input data buffer */
223 							DWORD nInBufferSize,         	/* size of input data buffer */
224 							PVOID lpOutBuffer,           	/* output data buffer */
225 							DWORD nOutBufferSize,        	/* size of output data buffer */
226 							PDWORD lpBytesReturned      	/* byte count */
227 						)
228 {
229 	IAL_ADAPTER_T *pAdapter;
230 
231 	switch(dwIoControlCode)	{
232 		case HPT_IOCTL_DELETE_ARRAY:
233 		{
234 			DEVICEID idArray;
235 			int iSuccess;
236 	        int i;
237 			PVDevice pArray;
238 			PVBus _vbus_p;
239 			struct cam_periph *periph = NULL;
240 
241 			if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1;
242 			if (nOutBufferSize!=sizeof(int)) return -1;
243 			idArray = *(DEVICEID *)lpInBuffer;
244 
245 			pArray = ID_TO_VDEV(idArray);
246 
247 			if((idArray == 0) || check_VDevice_valid(pArray))
248 		       	return -1;
249 
250         	if(!mIsArray(pArray))
251 			return -1;
252 
253 			_vbus_p=pArray->pVBus;
254 			pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
255 
256 	        for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) {
257 				if(pArray == _vbus_p->pVDevice[i])
258 				{
259 					periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
260 					if (periph != NULL && periph->refcount >= 1)
261 					{
262 						hpt_printk(("Can not delete a mounted device.\n"));
263 	                    return -1;
264 					}
265 				}
266 				/* the Mounted Disk isn't delete */
267 			}
268 
269 			iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1));
270 
271 			*(int*)lpOutBuffer = iSuccess;
272 
273 			if(iSuccess != 0)
274 				return -1;
275 			break;
276 		}
277 
278 		case HPT_IOCTL_GET_EVENT:
279 		{
280 			PHPT_EVENT pInfo;
281 
282 			if (nInBufferSize!=0) return -1;
283 			if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1;
284 
285 			pInfo = (PHPT_EVENT)lpOutBuffer;
286 
287 			if (hpt_get_event(pInfo)!=0)
288 				return -1;
289 		}
290 		break;
291 
292 		case HPT_IOCTL_SET_ARRAY_STATE:
293 		{
294 			DEVICEID idArray;
295 			DWORD state;
296 
297 			if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1;
298 			if (nOutBufferSize!=0) return -1;
299 
300 			idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray;
301 			state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state;
302 
303 			if(hpt_set_array_state(idArray, state)!=0)
304 				return -1;
305 		}
306 		break;
307 
308 		case HPT_IOCTL_RESCAN_DEVICES:
309 		{
310 			if (nInBufferSize!=0) return -1;
311 			if (nOutBufferSize!=0) return -1;
312 
313 #ifndef FOR_DEMO
314 			/* stop buzzer if user perform rescan */
315 			for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
316 				if (pAdapter->beeping) {
317 					pAdapter->beeping = 0;
318 					BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
319 				}
320 			}
321 #endif
322 		}
323 		break;
324 
325 		default:
326 		{
327 			PVDevice pVDev;
328 #ifdef SUPPORT_ARRAY
329 			intrmask_t oldspl;
330 #endif
331 			switch(dwIoControlCode) {
332 			/* read-only ioctl functions can be called directly. */
333 			case HPT_IOCTL_GET_VERSION:
334 			case HPT_IOCTL_GET_CONTROLLER_IDS:
335 			case HPT_IOCTL_GET_CONTROLLER_COUNT:
336 			case HPT_IOCTL_GET_CONTROLLER_INFO:
337 			case HPT_IOCTL_GET_CHANNEL_INFO:
338 			case HPT_IOCTL_GET_LOGICAL_DEVICES:
339 			case HPT_IOCTL_GET_DEVICE_INFO:
340 			case HPT_IOCTL_GET_EVENT:
341 			case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
342 				if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
343 					lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
344 				break;
345 
346 			default:
347 				/*
348 				 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
349 				 * wrong for second controller.
350 				 */
351 				switch(dwIoControlCode) {
352 				case HPT_IOCTL_CREATE_ARRAY:
353 					pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
354 				case HPT_IOCTL_SET_ARRAY_INFO:
355 					pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
356 				case HPT_IOCTL_SET_DEVICE_INFO:
357 					pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
358 				case HPT_IOCTL_SET_BOOT_MARK:
359 				case HPT_IOCTL_ADD_SPARE_DISK:
360 				case HPT_IOCTL_REMOVE_SPARE_DISK:
361 					pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
362 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
363 					pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
364 				default:
365 					pVDev = 0;
366 				}
367 
368 				if (pVDev && !check_VDevice_valid(pVDev)){
369 					_vbus_p = pVDev->pVBus;
370 
371 					pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
372 					/*
373 					 * create_array, and other functions can't be executed while channel is
374 					 * perform I/O commands. Wait until driver is idle.
375 					 */
376 					oldspl = lock_driver_idle(pAdapter);
377 					if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
378 						lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
379 						unlock_driver(oldspl);
380 						return -1;
381 					}
382 					unlock_driver(oldspl);
383 				}
384 				else
385 					return -1;
386 				break;
387 			}
388 
389 #ifdef SUPPORT_ARRAY
390 			switch(dwIoControlCode)
391 			{
392 				case HPT_IOCTL_CREATE_ARRAY:
393 				{
394 					pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
395 					oldspl = lock_driver();
396                     if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
397 				    {
398 						  (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
399                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
400 					}
401 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
402 				    {
403                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
404 					}
405 					else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
406 				    {
407                           hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
408 					}
409 					unlock_driver(oldspl);
410                     break;
411 				}
412 
413 				case HPT_IOCTL_ADD_DISK_TO_ARRAY:
414 				{
415 					PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
416 					pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
417 					if(pArray->u.array.rf_rebuilding == 0)
418 					{
419 						DWORD timeout = 0;
420 						oldspl = lock_driver();
421 						pArray->u.array.rf_auto_rebuild = 0;
422 						pArray->u.array.rf_abort_rebuild = 0;
423 						hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE);
424 						unlock_driver(oldspl);
425 						while (!pArray->u.array.rf_rebuilding)
426 						{
427 							pause("pause", 1);
428 							if ( timeout >= hz*3)
429 								break;
430 							timeout ++;
431 						}
432 					}
433 					break;
434 				}
435 			}
436 #endif
437             return 0;
438 		}
439 	}
440 
441 	if (lpBytesReturned)
442 		*lpBytesReturned = nOutBufferSize;
443 	return 0;
444 }
445 
446 static int
447 hpt_get_event(PHPT_EVENT pEvent)
448 {
449 	intrmask_t oldspl = lock_driver();
450 	int ret = event_queue_remove(pEvent);
451 	unlock_driver(oldspl);
452 	return ret;
453 }
454 
455 static int
456 hpt_set_array_state(DEVICEID idArray, DWORD state)
457 {
458 	IAL_ADAPTER_T *pAdapter;
459 	PVDevice pVDevice = ID_TO_VDEV(idArray);
460 	int	i;
461 	DWORD timeout = 0;
462 	intrmask_t oldspl;
463 
464 	if(idArray == 0 || check_VDevice_valid(pVDevice))	return -1;
465 	if(!mIsArray(pVDevice))
466 		return -1;
467 	if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
468 
469 	pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
470 
471 	switch(state)
472 	{
473 		case MIRROR_REBUILD_START:
474 		{
475 			if (pVDevice->u.array.rf_rebuilding ||
476 				pVDevice->u.array.rf_verifying ||
477 				pVDevice->u.array.rf_initializing)
478 				return -1;
479 
480 			oldspl = lock_driver();
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 			unlock_driver(oldspl);
489 
490 			while (!pVDevice->u.array.rf_rebuilding)
491 			{
492 				pause("pause", 1);
493 				if ( timeout >= hz*20)
494 					break;
495 				timeout ++;
496 			}
497 		}
498 
499 		break;
500 
501 		case MIRROR_REBUILD_ABORT:
502 		{
503 			for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
504 				if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
505 					hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
506 			}
507 
508 			if(pVDevice->u.array.rf_rebuilding != 1)
509 				return -1;
510 
511 			oldspl = lock_driver();
512 			pVDevice->u.array.rf_abort_rebuild = 1;
513 			unlock_driver(oldspl);
514 
515 			while (pVDevice->u.array.rf_abort_rebuild)
516 			{
517 				pause("pause", 1);
518 				if ( timeout >= hz*20)
519 					break;
520 				timeout ++;
521 			}
522 		}
523 		break;
524 
525 		case AS_VERIFY_START:
526 		{
527 			/*if(pVDevice->u.array.rf_verifying)
528 				return -1;*/
529 			if (pVDevice->u.array.rf_rebuilding ||
530 				pVDevice->u.array.rf_verifying ||
531 				pVDevice->u.array.rf_initializing)
532 				return -1;
533 
534 			oldspl = lock_driver();
535             pVDevice->u.array.RebuildSectors = 0;
536 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
537 			unlock_driver(oldspl);
538 
539 			while (!pVDevice->u.array.rf_verifying)
540 			{
541 				pause("pause", 1);
542 				if ( timeout >= hz*20)
543 					break;
544 				timeout ++;
545 			}
546 		}
547 		break;
548 
549 		case AS_VERIFY_ABORT:
550 		{
551 			if(pVDevice->u.array.rf_verifying != 1)
552 				return -1;
553 
554 			oldspl = lock_driver();
555 			pVDevice->u.array.rf_abort_rebuild = 1;
556 			unlock_driver(oldspl);
557 
558 			while (pVDevice->u.array.rf_abort_rebuild)
559 			{
560 				pause("pause", 1);
561 				if ( timeout >= hz*80)
562 					break;
563 				timeout ++;
564 			}
565 		}
566 		break;
567 
568 		case AS_INITIALIZE_START:
569 		{
570 			if (pVDevice->u.array.rf_rebuilding ||
571 				pVDevice->u.array.rf_verifying ||
572 				pVDevice->u.array.rf_initializing)
573 				return -1;
574 
575 			oldspl = lock_driver();
576 			hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
577 			unlock_driver(oldspl);
578 
579 			while (!pVDevice->u.array.rf_initializing)
580 			{
581 				pause("pause", 1);
582 				if ( timeout >= hz*80)
583 					break;
584 				timeout ++;
585 			}
586 		}
587 		break;
588 
589 		case AS_INITIALIZE_ABORT:
590 		{
591 			if(pVDevice->u.array.rf_initializing != 1)
592 				return -1;
593 
594 			oldspl = lock_driver();
595 			pVDevice->u.array.rf_abort_rebuild = 1;
596 			unlock_driver(oldspl);
597 
598 			while (pVDevice->u.array.rf_abort_rebuild)
599 			{
600 				pause("pause", 1);
601 				if ( timeout >= hz*80)
602 					break;
603 				timeout ++;
604 			}
605 		}
606 		break;
607 
608 		default:
609 			return -1;
610 	}
611 
612 	return 0;
613 }
614 
615 int HPTLIBAPI
616 R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
617 {
618 	ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
619 	if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
620 		bufferSize<<=1;
621 	if (logical) {
622 		pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
623 		pSgTable->wSgSize = (USHORT)bufferSize;
624 		pSgTable->wSgFlag = SG_FLAG_EOT;
625 	}
626 	else {
627 		/* build physical SG table for pCmd->uCmd.R1Control.Buffer */
628 		ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
629 		ULONG length;
630 		int idx = 0;
631 
632 		v = pCmd->uCmd.R1Control.Buffer;
633 		dataPointer = (ADDRESS)fOsPhysicalAddress(v);
634 
635 		if ((ULONG_PTR)dataPointer & 0x1)
636 			return FALSE;
637 
638 		#define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
639 		#define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
640 
641 		do {
642 			if (idx >= MAX_SG_DESCRIPTORS)  return FALSE;
643 
644 			pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
645 			currvaddr = v;
646 			currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
647 
648 
649 			do {
650 				nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
651 				nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
652 
653 				if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
654 				nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
655 
656 				if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
657 					nextvaddr = nextpage;
658 					break;
659 				}
660 
661 				currvaddr = nextvaddr;
662 				currphypage = nextphypage;
663 			}while (1);
664 
665 			length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
666 			v = nextvaddr;
667 			bufferSize -= length;
668 
669 			pSgTable[idx].wSgSize = (USHORT)length;
670 			pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
671 			idx++;
672 
673 		}while (bufferSize);
674 	}
675 	return 1;
676 }
677 
678 static int End_Job=0;
679 void HPTLIBAPI
680 thread_io_done(_VBUS_ARG PCommand pCmd)
681 {
682 	End_Job = 1;
683 	wakeup((caddr_t)pCmd);
684 }
685 
686 void
687 hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
688 {
689 	DWORD timeout = 0;
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 = 0;
695 	intrmask_t oldspl;
696 
697 	_VBUS_INST(&pAdapter->VBus)
698 
699 	if (pArray->u.array.rf_broken==1 ||
700     	pArray->u.array.RebuildSectors>=capacity)
701 		return;
702 
703 	oldspl = lock_driver();
704 
705 	switch(flags)
706 	{
707 		case DUPLICATE:
708 		case REBUILD_PARITY:
709 			if(pArray->u.array.rf_rebuilding == 0)
710 			{
711 				pArray->u.array.rf_rebuilding = 1;
712 				hpt_printk(("Rebuilding started.\n"));
713 				ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
714 			}
715 			break;
716 
717 		case INITIALIZE:
718 			if(pArray->u.array.rf_initializing == 0)
719 			{
720 				pArray->u.array.rf_initializing = 1;
721 				hpt_printk(("Initializing started.\n"));
722 				ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
723 			}
724 			break;
725 
726 		case VERIFY:
727 			if(pArray->u.array.rf_verifying == 0)
728 			{
729 				pArray->u.array.rf_verifying = 1;
730 				hpt_printk(("Verifying started.\n"));
731 				ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
732 			}
733 			break;
734 	}
735 
736 retry_cmd:
737 	pCmd = AllocateCommand(_VBUS_P0);
738 	HPT_ASSERT(pCmd);
739 	pCmd->cf_control = 1;
740 	End_Job = 0;
741 
742 	if (pArray->VDeviceType==VD_RAID_1)
743 	{
744 		#define MAX_REBUILD_SECTORS 0x40
745 
746 		/* take care for discontinuous buffer in R1ControlSgl */
747 		unlock_driver(oldspl);
748 		buffer = malloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
749 		oldspl = lock_driver();
750 		if(!buffer) {
751 			FreeCommand(_VBUS_P pCmd);
752 			hpt_printk(("can't allocate rebuild buffer\n"));
753 			goto fail;
754 		}
755 		switch(flags)
756 		{
757 			case DUPLICATE:
758 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
759 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
760 				break;
761 
762 			case VERIFY:
763 				pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
764 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
765 				break;
766 
767 			case INITIALIZE:
768 				pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
769 				pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
770 				break;
771 		}
772 
773 		pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
774 
775 		if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
776 			pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
777 
778 		pCmd->uCmd.R1Control.Buffer = buffer;
779 		pCmd->pfnBuildSgl = R1ControlSgl;
780 	}
781 	else if (pArray->VDeviceType==VD_RAID_5)
782 	{
783 		switch(flags)
784 		{
785 			case DUPLICATE:
786 			case REBUILD_PARITY:
787 				pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
788 			case VERIFY:
789 				pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
790 			case INITIALIZE:
791 				pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
792 		}
793 		pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
794 	}
795 	else
796 		HPT_ASSERT(0);
797 
798 	pCmd->pVDevice = pArray;
799 	pCmd->pfnCompletion = thread_io_done;
800 	pArray->pfnSendCommand(_VBUS_P pCmd);
801 	CheckPendingCall(_VBUS_P0);
802 
803 	if (!End_Job) {
804 		unlock_driver(oldspl);
805 		while (!End_Job) {
806 			tsleep((caddr_t)pCmd, PPAUSE, "pause", hz);
807 			if (timeout++>60) break;
808 		}
809 		oldspl = lock_driver();
810 		if (!End_Job) {
811 			hpt_printk(("timeout, reset\n"));
812 			fResetVBus(_VBUS_P0);
813 		}
814 	}
815 
816 	result = pCmd->Result;
817 	FreeCommand(_VBUS_P pCmd);
818 	unlock_driver(oldspl);
819 	if (buffer) free(buffer, M_DEVBUF);
820 	oldspl = lock_driver();
821 	KdPrintI(("cmd finished %d", result));
822 
823 	switch(result)
824 	{
825 		case RETURN_SUCCESS:
826 			if (!pArray->u.array.rf_abort_rebuild)
827 			{
828 				if(pArray->u.array.RebuildSectors < capacity)
829 				{
830 					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
831 				}
832 				else
833 				{
834 					switch (flags)
835 					{
836 						case DUPLICATE:
837 						case REBUILD_PARITY:
838 							needsync = 1;
839 							pArray->u.array.rf_rebuilding = 0;
840 							pArray->u.array.rf_need_rebuild = 0;
841 							pArray->u.array.CriticalMembers = 0;
842 							pArray->u.array.RebuildSectors = MAX_LBA_T;
843 							pArray->u.array.rf_duplicate_and_create = 0;
844 							hpt_printk(("Rebuilding finished.\n"));
845 							ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
846 							break;
847 						case INITIALIZE:
848 							needsync = 1;
849 							pArray->u.array.rf_initializing = 0;
850 							pArray->u.array.rf_need_rebuild = 0;
851 							pArray->u.array.RebuildSectors = MAX_LBA_T;
852 							hpt_printk(("Initializing finished.\n"));
853 							ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
854 							break;
855 						case VERIFY:
856 							pArray->u.array.rf_verifying = 0;
857 							hpt_printk(("Verifying finished.\n"));
858 							ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
859 							break;
860 					}
861 				}
862 			}
863 			else
864 			{
865 				pArray->u.array.rf_abort_rebuild = 0;
866 				if (pArray->u.array.rf_rebuilding)
867 				{
868 					hpt_printk(("Abort rebuilding.\n"));
869 					pArray->u.array.rf_rebuilding = 0;
870 					pArray->u.array.rf_duplicate_and_create = 0;
871 					ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
872 				}
873 				else if (pArray->u.array.rf_verifying)
874 				{
875 					hpt_printk(("Abort verifying.\n"));
876 					pArray->u.array.rf_verifying = 0;
877 					ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
878 				}
879 				else if (pArray->u.array.rf_initializing)
880 				{
881 					hpt_printk(("Abort initializing.\n"));
882 					pArray->u.array.rf_initializing = 0;
883 					ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
884 				}
885 				needdelete=1;
886 			}
887 			break;
888 
889 		case RETURN_DATA_ERROR:
890 			if (flags==VERIFY)
891 			{
892 				needsync = 1;
893 				pArray->u.array.rf_verifying = 0;
894 				pArray->u.array.rf_need_rebuild = 1;
895 				hpt_printk(("Verifying failed: found inconsistency\n"));
896 				ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
897 				ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
898 
899 				if (!pArray->vf_online || pArray->u.array.rf_broken) break;
900 
901 				pArray->u.array.rf_auto_rebuild = 0;
902 				pArray->u.array.rf_abort_rebuild = 0;
903 				hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
904 					(pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
905 			}
906 			break;
907 
908 		default:
909 			hpt_printk(("command failed with error %d\n", result));
910 			if (++retry<3)
911 			{
912 				hpt_printk(("retry (%d)\n", retry));
913 				goto retry_cmd;
914 			}
915 fail:
916 			pArray->u.array.rf_abort_rebuild = 0;
917 			switch (flags)
918 			{
919 				case DUPLICATE:
920 				case REBUILD_PARITY:
921 					needsync = 1;
922 					pArray->u.array.rf_rebuilding = 0;
923 					pArray->u.array.rf_duplicate_and_create = 0;
924 					hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
925 					ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
926 					break;
927 
928 				case INITIALIZE:
929 					needsync = 1;
930 					pArray->u.array.rf_initializing = 0;
931 					hpt_printk(("Initializing failed.\n"));
932 					ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
933 					break;
934 
935 				case VERIFY:
936 					needsync = 1;
937 					pArray->u.array.rf_verifying = 0;
938 					hpt_printk(("Verifying failed.\n"));
939 					ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
940 					break;
941 			}
942 			needdelete=1;
943 	}
944 
945 	while (pAdapter->outstandingCommands)
946 	{
947 		KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
948 		/* put this to have driver stop processing system commands quickly */
949 		if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
950 		unlock_driver(oldspl);
951 		/*Schedule out*/
952 #if (__FreeBSD_version < 500000)
953 		YIELD_THREAD;
954 #else
955 		pause("switch", 1);
956 #endif
957 		oldspl = lock_driver();
958 	}
959 
960 	if (needsync) SyncArrayInfo(pArray);
961 	if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
962 		fDeleteArray(_VBUS_P pArray, TRUE);
963 
964 	Check_Idle_Call(pAdapter);
965 	unlock_driver(oldspl);
966 }
967