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