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