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