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