gui_lib.c revision 315221
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: stable/11/sys/dev/hptmv/gui_lib.c 315221 2017-03-14 02:06:03Z pfg $
27 */
28/*
29 * gui_lib.c
30 * Copyright (c) 2002-2004 HighPoint Technologies, Inc. All rights reserved.
31 *
32 *  Platform independent ioctl interface implementation.
33 *  The platform dependent part may reuse this function and/or use it own
34 *  implementation for each ioctl function.
35 *
36 *  This implementation doesn't use any synchronization; the caller must
37 *  assure the proper context when calling these functions.
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44
45#ifndef __KERNEL__
46#define __KERNEL__
47#endif
48
49#include <dev/hptmv/global.h>
50#include <dev/hptmv/hptintf.h>
51#include <dev/hptmv/osbsd.h>
52#include <dev/hptmv/access601.h>
53
54static int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap);
55static int hpt_get_controller_count(void);
56static int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo);
57static int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo);
58static int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount);
59static int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo);
60static int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo);
61static DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam);
62static DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam);
63static int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk);
64static int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk);
65static int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo);
66static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo);
67static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo);
68
69int
70check_VDevice_valid(PVDevice p)
71{
72	int i;
73	PVDevice pVDevice;
74	PVBus    _vbus_p;
75	IAL_ADAPTER_T *pAdapter = gIal_Adapter;
76
77	while(pAdapter != NULL)
78	{
79		for (i = 0; i < MV_SATA_CHANNELS_NUM; i++)
80			if(&(pAdapter->VDevices[i]) == p)  return 0;
81		pAdapter = pAdapter->next;
82	}
83
84#ifdef SUPPORT_ARRAY
85	pAdapter = gIal_Adapter;
86	while(pAdapter != NULL)
87	{
88		_vbus_p = &pAdapter->VBus;
89		for (i=0;i<MAX_ARRAY_PER_VBUS;i++)
90		{
91			pVDevice=ArrayTables(i);
92			if ((pVDevice->u.array.dArStamp != 0) && (pVDevice == p))
93				return 0;
94		}
95		pAdapter = pAdapter->next;
96	}
97#endif
98
99	return -1;
100}
101
102#ifdef SUPPORT_ARRAY
103
104static UCHAR get_vdev_type(PVDevice pVDevice)
105	{
106	switch (pVDevice->VDeviceType) {
107		case VD_RAID_0: return AT_RAID0;
108		case VD_RAID_1: return AT_RAID1;
109		case VD_JBOD:   return AT_JBOD;
110		case VD_RAID_5: return AT_RAID5;
111		default:        return AT_UNKNOWN;
112	}
113	}
114
115static DWORD get_array_flag(PVDevice pVDevice)
116{
117	int i;
118	DWORD f = 0;
119
120	/* The array is disabled */
121	if(!pVDevice->vf_online)	{
122		f |= ARRAY_FLAG_DISABLED;
123		/* Ignore other info */
124		return f;
125	}
126
127	/* array need synchronizing */
128	if(pVDevice->u.array.rf_need_rebuild && !pVDevice->u.array.rf_duplicate_and_create)
129		f |= ARRAY_FLAG_NEEDBUILDING;
130
131	/* array is in rebuilding process */
132	if(pVDevice->u.array.rf_rebuilding)
133		f |= ARRAY_FLAG_REBUILDING;
134
135	/* array is being verified */
136	if(pVDevice->u.array.rf_verifying)
137		f |= ARRAY_FLAG_VERIFYING;
138
139	/* array is being initialized */
140	if(pVDevice->u.array.rf_initializing)
141		f |= ARRAY_FLAG_INITIALIZING;
142
143	/* broken but may still working */
144	if(pVDevice->u.array.rf_broken)
145		f |= ARRAY_FLAG_BROKEN;
146
147	/* array has a active partition */
148	if(pVDevice->vf_bootable)
149		f |= ARRAY_FLAG_BOOTDISK;
150
151	/* a newly created array */
152	if(pVDevice->u.array.rf_newly_created)
153		f |= ARRAY_FLAG_NEWLY_CREATED;
154
155	/* array has boot mark set */
156	if(pVDevice->vf_bootmark)
157		f |= ARRAY_FLAG_BOOTMARK;
158
159	/* auto-rebuild should start */
160	if(pVDevice->u.array.rf_auto_rebuild)
161		f |= ARRAY_FLAG_NEED_AUTOREBUILD;
162
163	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
164	{
165		PVDevice pMember = pVDevice->u.array.pMember[i];
166		if (!pMember || !pMember->vf_online || (pMember->VDeviceType==VD_SINGLE_DISK))
167			continue;
168
169		/* array need synchronizing */
170		if(pMember->u.array.rf_need_rebuild &&
171		   !pMember->u.array.rf_duplicate_and_create)
172			f |= ARRAY_FLAG_NEEDBUILDING;
173
174		/* array is in rebuilding process */
175		if(pMember->u.array.rf_rebuilding)
176			f |= ARRAY_FLAG_REBUILDING;
177
178		/* array is being verified */
179		if(pMember->u.array.rf_verifying)
180			f |= ARRAY_FLAG_VERIFYING;
181
182		/* array is being initialized */
183		if(pMember->u.array.rf_initializing)
184			f |= ARRAY_FLAG_INITIALIZING;
185
186		/* broken but may still working */
187		if(pMember->u.array.rf_broken)
188			f |= ARRAY_FLAG_BROKEN;
189
190		/* a newly created array */
191		if(pMember->u.array.rf_newly_created)
192			f |= ARRAY_FLAG_NEWLY_CREATED;
193
194		/* auto-rebuild should start */
195		if(pMember->u.array.rf_auto_rebuild)
196			f |= ARRAY_FLAG_NEED_AUTOREBUILD;
197	}
198
199	return f;
200}
201
202static DWORD calc_rebuild_progress(PVDevice pVDevice)
203{
204	int i;
205	DWORD result = ((ULONG)(pVDevice->u.array.RebuildSectors>>11)*1000 /
206		(ULONG)(pVDevice->VDeviceCapacity>>11) * (pVDevice->u.array.bArnMember-1)) * 10;
207
208	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
209	{
210		PVDevice pMember = pVDevice->u.array.pMember[i];
211		if (!pMember || !pMember->vf_online || (pMember->VDeviceType==VD_SINGLE_DISK))
212			continue;
213
214		/* for RAID1/0 case */
215		if (pMember->u.array.rf_rebuilding ||
216			pMember->u.array.rf_verifying ||
217			pMember->u.array.rf_initializing)
218		{
219			DWORD percent = ((ULONG)(pMember->u.array.RebuildSectors>>11)*1000 /
220				(ULONG)(pMember->VDeviceCapacity>>11) * (pMember->u.array.bArnMember-1)) * 10;
221			if (result==0 || result>percent)
222				result = percent;
223		}
224		}
225
226	if (result>10000) result = 10000;
227	return result;
228	}
229
230static void get_array_info(PVDevice pVDevice, PHPT_ARRAY_INFO pArrayInfo)
231{
232	int	i;
233
234	memcpy(pArrayInfo->Name, pVDevice->u.array.ArrayName, MAX_ARRAY_NAME);
235	pArrayInfo->ArrayType = get_vdev_type(pVDevice);
236	pArrayInfo->BlockSizeShift = pVDevice->u.array.bArBlockSizeShift;
237	pArrayInfo->RebuiltSectors = pVDevice->u.array.RebuildSectors;
238	pArrayInfo->Flags = get_array_flag(pVDevice);
239	pArrayInfo->RebuildingProgress = calc_rebuild_progress(pVDevice);
240
241	pArrayInfo->nDisk = 0;
242
243	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
244		if(pVDevice->u.array.pMember[i] != NULL)
245			pArrayInfo->Members[pArrayInfo->nDisk++] = VDEV_TO_ID(pVDevice->u.array.pMember[i]);
246
247	for(i=pArrayInfo->nDisk; i<MAX_ARRAY_MEMBERS; i++)
248		pArrayInfo->Members[i] = INVALID_DEVICEID;
249	}
250
251static void get_array_info_v2(PVDevice pVDevice, PHPT_ARRAY_INFO_V2 pArrayInfo)
252{
253	int	i;
254
255	memcpy(pArrayInfo->Name, pVDevice->u.array.ArrayName, MAX_ARRAYNAME_LEN);
256	pArrayInfo->ArrayType = get_vdev_type(pVDevice);
257	pArrayInfo->BlockSizeShift = pVDevice->u.array.bArBlockSizeShift;
258	pArrayInfo->RebuiltSectors.lo32 = pVDevice->u.array.RebuildSectors;
259	pArrayInfo->RebuiltSectors.hi32 = sizeof(LBA_T)>4? (pVDevice->u.array.RebuildSectors>>32) : 0;
260	pArrayInfo->Flags = get_array_flag(pVDevice);
261	pArrayInfo->RebuildingProgress = calc_rebuild_progress(pVDevice);
262
263	pArrayInfo->nDisk = 0;
264
265	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
266		if(pVDevice->u.array.pMember[i] != NULL)
267			pArrayInfo->Members[pArrayInfo->nDisk++] = VDEV_TO_ID(pVDevice->u.array.pMember[i]);
268
269	for(i=pArrayInfo->nDisk; i<MAX_ARRAY_MEMBERS_V2; i++)
270		pArrayInfo->Members[i] = INVALID_DEVICEID;
271}
272#endif
273
274static int get_disk_info(PVDevice pVDevice, PDEVICE_INFO pDiskInfo)
275{
276	MV_SATA_ADAPTER *pSataAdapter;
277	MV_SATA_CHANNEL *pSataChannel;
278	IAL_ADAPTER_T   *pAdapter;
279	MV_CHANNEL		*channelInfo;
280	char *p;
281	int i;
282
283	/* device location */
284	pSataChannel = pVDevice->u.disk.mv;
285	if(pSataChannel == NULL)	return -1;
286	pDiskInfo->TargetId = 0;
287	pSataAdapter = pSataChannel->mvSataAdapter;
288	if(pSataAdapter == NULL)	return -1;
289
290	pAdapter = pSataAdapter->IALData;
291
292	pDiskInfo->PathId = pSataChannel->channelNumber;
293	pDiskInfo->ControllerId = (UCHAR)pSataAdapter->adapterId;
294
295/*GUI uses DeviceModeSetting to display to users
296(1) if users select a mode, GUI/BIOS should display that mode.
297(2) if SATA/150, GUI/BIOS should display 150 if case (1) isn't satisfied.
298(3) display real mode if case (1)&&(2) not satisfied.
299*/
300	if (pVDevice->u.disk.df_user_mode_set)
301		pDiskInfo->DeviceModeSetting = pVDevice->u.disk.bDeUserSelectMode;
302	else if (((((PIDENTIFY_DATA)pVDevice->u.disk.mv->identifyDevice)->SataCapability) & 3)==2)
303		pDiskInfo->DeviceModeSetting = 15;
304	else {
305		p = (char *)&((PIDENTIFY_DATA)pVDevice->u.disk.mv->identifyDevice)->ModelNumber;
306		if (*(WORD*)p==(0x5354) /*'ST'*/ &&
307			(*(WORD*)(p+8)==(0x4153)/*'AS'*/ || (p[8]=='A' && p[11]=='S')))
308			pDiskInfo->DeviceModeSetting = 15;
309		else
310			pDiskInfo->DeviceModeSetting = pVDevice->u.disk.bDeModeSetting;
311	}
312
313	pDiskInfo->UsableMode = pVDevice->u.disk.bDeUsable_Mode;
314
315	pDiskInfo->DeviceType = PDT_HARDDISK;
316
317	pDiskInfo->Flags = 0x0;
318
319	/* device is disabled */
320	if(!pVDevice->u.disk.df_on_line)
321		pDiskInfo->Flags |= DEVICE_FLAG_DISABLED;
322
323	/* disk has a active partition */
324	if(pVDevice->vf_bootable)
325		pDiskInfo->Flags |= DEVICE_FLAG_BOOTDISK;
326
327	/* disk has boot mark set */
328	if(pVDevice->vf_bootmark)
329		pDiskInfo->Flags |= DEVICE_FLAG_BOOTMARK;
330
331	pDiskInfo->Flags |= DEVICE_FLAG_SATA;
332
333	/* is a spare disk */
334	if(pVDevice->VDeviceType == VD_SPARE)
335		pDiskInfo->Flags |= DEVICE_FLAG_IS_SPARE;
336
337	memcpy(&(pDiskInfo->IdentifyData), (pSataChannel->identifyDevice), sizeof(IDENTIFY_DATA2));
338	p = (char *)&pDiskInfo->IdentifyData.ModelNumber;
339	for (i = 0; i < 20; i++)
340		((WORD*)p)[i] = shortswap(pSataChannel->identifyDevice[IDEN_MODEL_OFFSET+i]);
341	p[39] = '\0';
342
343	channelInfo = &pAdapter->mvChannel[pSataChannel->channelNumber];
344	pDiskInfo->ReadAheadSupported = channelInfo->readAheadSupported;
345	pDiskInfo->ReadAheadEnabled = channelInfo->readAheadEnabled;
346	pDiskInfo->WriteCacheSupported = channelInfo->writeCacheSupported;
347	pDiskInfo->WriteCacheEnabled = channelInfo->writeCacheEnabled;
348	pDiskInfo->TCQSupported = (pSataChannel->identifyDevice[IDEN_SUPPORTED_COMMANDS2] & (0x2))!=0;
349	pDiskInfo->TCQEnabled = pSataChannel->queuedDMA==MV_EDMA_MODE_QUEUED;
350	pDiskInfo->NCQSupported = MV_SATA_GEN_2(pSataAdapter) &&
351		(pSataChannel->identifyDevice[IDEN_SATA_CAPABILITIES] & (0x0100));
352	pDiskInfo->NCQEnabled = pSataChannel->queuedDMA==MV_EDMA_MODE_NATIVE_QUEUING;
353	return 0;
354}
355
356int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap)
357{
358	ZeroMemory(cap, sizeof(DRIVER_CAPABILITIES));
359	cap->dwSize = sizeof(DRIVER_CAPABILITIES);
360	cap->MaximumControllers = MAX_VBUS;
361
362	/* cap->SupportCrossControllerRAID = 0; */
363	/* take care for various OSes! */
364	cap->SupportCrossControllerRAID = 0;
365
366
367	cap->MinimumBlockSizeShift = MinBlockSizeShift;
368	cap->MaximumBlockSizeShift = MaxBlockSizeShift;
369	cap->SupportDiskModeSetting = 0;
370	cap->SupportSparePool = 1;
371	cap->MaximumArrayNameLength = MAX_ARRAY_NAME - 1;
372	cap->SupportDedicatedSpare = 0;
373
374
375#ifdef SUPPORT_ARRAY
376	/* Stripe */
377	cap->SupportedRAIDTypes[0] = AT_RAID0;
378	cap->MaximumArrayMembers[0] = MAX_MEMBERS;
379	/* Mirror */
380	cap->SupportedRAIDTypes[1] = AT_RAID1;
381	cap->MaximumArrayMembers[1] = 2;
382	/* Mirror + Stripe */
383#ifdef ARRAY_V2_ONLY
384	cap->SupportedRAIDTypes[2] = (AT_RAID1<<4)|AT_RAID0; /* RAID0/1 */
385#else
386	cap->SupportedRAIDTypes[2] = (AT_RAID0<<4)|AT_RAID1; /* RAID1/0 */
387#endif
388	cap->MaximumArrayMembers[2] = MAX_MEMBERS;
389	/* Jbod */
390	cap->SupportedRAIDTypes[3] = AT_JBOD;
391	cap->MaximumArrayMembers[3] = MAX_MEMBERS;
392	/* RAID5 */
393#if SUPPORT_RAID5
394	cap->SupportedRAIDTypes[4] = AT_RAID5;
395	cap->MaximumArrayMembers[4] = MAX_MEMBERS;
396#endif
397#endif
398	return 0;
399}
400
401int hpt_get_controller_count(void)
402{
403	IAL_ADAPTER_T    *pAdapTemp = gIal_Adapter;
404	int iControllerCount = 0;
405
406	while(pAdapTemp != NULL)
407	{
408		iControllerCount++;
409		pAdapTemp = pAdapTemp->next;
410	}
411
412	return iControllerCount;
413}
414
415int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo)
416{
417	IAL_ADAPTER_T    *pAdapTemp;
418	int iControllerCount = 0;
419
420	for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) {
421		if (iControllerCount++==id) {
422			pInfo->InterruptLevel = 0;
423			pInfo->ChipType = 0;
424			pInfo->ChipFlags = CHIP_SUPPORT_ULTRA_100;
425			strcpy( pInfo->szVendorID, "HighPoint Technologies, Inc.");
426#ifdef GUI_CONTROLLER_NAME
427#ifdef FORCE_ATA150_DISPLAY
428			/* show "Bus Type: ATA/150" in GUI for SATA controllers */
429			pInfo->ChipFlags = CHIP_SUPPORT_ULTRA_150;
430#endif
431			strcpy(pInfo->szProductID, GUI_CONTROLLER_NAME);
432#define _set_product_id(x)
433#else
434#define _set_product_id(x) strcpy(pInfo->szProductID, x)
435#endif
436			_set_product_id("RocketRAID 18xx SATA Controller");
437			pInfo->NumBuses = 8;
438			pInfo->ChipFlags |= CHIP_SUPPORT_ULTRA_133|CHIP_SUPPORT_ULTRA_150;
439			return 0;
440		}
441	}
442	return -1;
443}
444
445
446int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo)
447{
448	IAL_ADAPTER_T    *pAdapTemp = gIal_Adapter;
449	int i,iControllerCount = 0;
450
451	while(pAdapTemp != NULL)
452	{
453		if (iControllerCount++==id)
454			goto found;
455		pAdapTemp = pAdapTemp->next;
456	}
457	return -1;
458
459found:
460
461	pInfo->IoPort = 0;
462	pInfo->ControlPort = 0;
463
464	for (i=0; i<2 ;i++)
465	{
466		pInfo->Devices[i] = (DEVICEID)INVALID_DEVICEID;
467	}
468
469	if (pAdapTemp->mvChannel[bus].online == MV_TRUE)
470		pInfo->Devices[0] = VDEV_TO_ID(&pAdapTemp->VDevices[bus]);
471	else
472		pInfo->Devices[0] = (DEVICEID)INVALID_DEVICEID;
473
474	return 0;
475
476
477}
478
479int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount)
480{
481	int count = 0;
482	int	i,j;
483	PVDevice pPhysical, pLogical;
484	IAL_ADAPTER_T    *pAdapTemp;
485
486	for(i = 0; i < nMaxCount; i++)
487		pIds[i] = INVALID_DEVICEID;
488
489	/* append the arrays not registered on VBus */
490	for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) {
491		for(i = 0; i < MV_SATA_CHANNELS_NUM; i++)
492		{
493			pPhysical = &pAdapTemp->VDevices[i];
494			pLogical = pPhysical;
495
496			while (pLogical->pParent) pLogical = pLogical->pParent;
497			if (pLogical->VDeviceType==VD_SPARE)
498				continue;
499
500			for (j=0; j<count; j++)
501				if (pIds[j]==VDEV_TO_ID(pLogical)) goto next;
502			pIds[count++] = VDEV_TO_ID(pLogical);
503			if (count>=nMaxCount) goto done;
504			next:;
505		}
506	}
507
508done:
509	return count;
510}
511
512int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo)
513{
514	PVDevice pVDevice = ID_TO_VDEV(id);
515
516	if((id == 0) || check_VDevice_valid(pVDevice))
517		return -1;
518
519#ifdef SUPPORT_ARRAY
520	if (mIsArray(pVDevice)) {
521		pInfo->Type = LDT_ARRAY;
522		pInfo->Capacity = pVDevice->VDeviceCapacity;
523		pInfo->ParentArray = VDEV_TO_ID(pVDevice->pParent);
524		get_array_info(pVDevice, &pInfo->u.array);
525		return 0;
526	}
527#endif
528
529	pInfo->Type = LDT_DEVICE;
530	pInfo->ParentArray = pVDevice->pParent? VDEV_TO_ID(pVDevice->pParent) : INVALID_DEVICEID;
531	/* report real capacity to be compatible with old arrays */
532	pInfo->Capacity = pVDevice->u.disk.dDeRealCapacity;
533	return get_disk_info(pVDevice, &pInfo->u.device);
534}
535
536int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo)
537{
538	PVDevice pVDevice = ID_TO_VDEV(id);
539
540	if((id == 0) || check_VDevice_valid(pVDevice))
541		return -1;
542
543#ifdef SUPPORT_ARRAY
544	if (mIsArray(pVDevice)) {
545		pInfo->Type = LDT_ARRAY;
546		pInfo->Capacity.lo32 = pVDevice->VDeviceCapacity;
547		pInfo->Capacity.hi32 = sizeof(LBA_T)>4? (pVDevice->VDeviceCapacity>>32) : 0;
548		pInfo->ParentArray = VDEV_TO_ID(pVDevice->pParent);
549		get_array_info_v2(pVDevice, &pInfo->u.array);
550	return 0;
551}
552#endif
553
554	pInfo->Type = LDT_DEVICE;
555	pInfo->ParentArray = pVDevice->pParent? VDEV_TO_ID(pVDevice->pParent) : INVALID_DEVICEID;
556	/* report real capacity to be compatible with old arrays */
557	pInfo->Capacity.lo32 = pVDevice->u.disk.dDeRealCapacity;
558	pInfo->Capacity.hi32 = 0;
559	return get_disk_info(pVDevice, &pInfo->u.device);
560}
561
562#ifdef SUPPORT_ARRAY
563DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam)
564{
565	ULONG Stamp = GetStamp();
566	int	i,j;
567	LBA_T  capacity = MAX_LBA_T;
568	PVDevice pArray,pChild;
569	int		Loca = -1;
570
571	if (pParam->nDisk > MAX_MEMBERS)
572		return INVALID_DEVICEID;
573/* check in verify_vd
574	for(i = 0; i < pParam->nDisk; i++)
575	{
576		PVDevice pVDev = ID_TO_VDEV(pParam->Members[i]);
577		if (check_VDevice_valid(pVDev)) return INVALID_DEVICEID;
578		if (mIsArray(pVDev)) return INVALID_DEVICEID;
579		if (!pVDev->vf_online) return INVALID_DEVICEID;
580		if (!_vbus_p)
581			_vbus_p = pVDev->u.disk.pVBus;
582		else if (_vbus_p != pVDev->u.disk.pVBus)
583			return INVALID_DEVICEID;
584	}
585*/
586	_vbus_p = (ID_TO_VDEV(pParam->Members[0]))->u.disk.pVBus;
587	if (!_vbus_p) return INVALID_DEVICEID;
588
589	mArGetArrayTable(pArray);
590	if(!pArray)	return INVALID_DEVICEID;
591
592	switch (pParam->ArrayType)
593	{
594		case AT_JBOD:
595			pArray->VDeviceType = VD_JBOD;
596			goto simple;
597
598		case AT_RAID0:
599			if((pParam->BlockSizeShift < MinBlockSizeShift) || (pParam->BlockSizeShift > MaxBlockSizeShift))
600				goto error;
601			pArray->VDeviceType = VD_RAID_0;
602			goto simple;
603
604		case AT_RAID5:
605			if((pParam->BlockSizeShift < MinBlockSizeShift) || (pParam->BlockSizeShift > MaxBlockSizeShift))
606				goto error;
607			pArray->VDeviceType = VD_RAID_5;
608			/* only "no build" R5 is not critical after creation. */
609			if ((pParam->CreateFlags & CAF_CREATE_R5_NO_BUILD)==0)
610				pArray->u.array.rf_need_rebuild = 1;
611			goto simple;
612
613		case AT_RAID1:
614			if(pParam->nDisk <= 2)
615			{
616				pArray->VDeviceType = VD_RAID_1;
617simple:
618				pArray->u.array.bArnMember = pParam->nDisk;
619				pArray->u.array.bArRealnMember = pParam->nDisk;
620				pArray->u.array.bArBlockSizeShift = pParam->BlockSizeShift;
621				pArray->u.array.bStripeWitch = (1 << pParam->BlockSizeShift);
622				pArray->u.array.dArStamp = Stamp;
623
624				pArray->u.array.rf_need_sync = 1;
625				pArray->u.array.rf_newly_created = 1;
626
627				if ((pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE) &&
628					(pArray->VDeviceType == VD_RAID_1))
629				{
630					pArray->u.array.rf_newly_created = 0; /* R1 shall still be accessible */
631					pArray->u.array.rf_need_rebuild = 1;
632					pArray->u.array.rf_auto_rebuild = 1;
633					pArray->u.array.rf_duplicate_and_create = 1;
634
635					for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
636						if (_vbus_p->pVDevice[i] == ID_TO_VDEV(pParam->Members[0]))
637							Loca = i;
638				}
639
640				pArray->u.array.RebuildSectors = pArray->u.array.rf_need_rebuild? 0 : MAX_LBA_T;
641
642				memcpy(pArray->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME);
643
644				for(i = 0; i < pParam->nDisk; i++)
645				{
646					pArray->u.array.pMember[i] = ID_TO_VDEV(pParam->Members[i]);
647					pArray->u.array.pMember[i]->bSerialNumber = i;
648					pArray->u.array.pMember[i]->pParent = pArray;
649
650					/* don't unregister source disk for duplicate RAID1 */
651					if (i ||
652						pArray->VDeviceType!=VD_RAID_1 ||
653						(pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE)==0)
654						UnregisterVDevice(pArray->u.array.pMember[i]);
655
656					if(pArray->VDeviceType == VD_RAID_5)
657						pArray->u.array.pMember[i]->vf_cache_disk = 1;
658				}
659			}
660			else
661			{
662				for(i = 0; i < (pParam->nDisk / 2); i++)
663				{
664					mArGetArrayTable(pChild);
665					pChild->VDeviceType = VD_RAID_1;
666
667					pChild->u.array.bArnMember = 2;
668					pChild->u.array.bArRealnMember = 2;
669					pChild->u.array.bArBlockSizeShift = pParam->BlockSizeShift;
670					pChild->u.array.bStripeWitch = (1 << pParam->BlockSizeShift);
671					pChild->u.array.dArStamp = Stamp;
672
673					pChild->u.array.rf_need_sync = 1;
674					pChild->u.array.rf_newly_created = 1;
675
676					pChild->u.array.RebuildSectors = MAX_LBA_T;
677
678					memcpy(pChild->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME);
679
680					for(j = 0; j < 2; j++)
681					{
682						pChild->u.array.pMember[j] = ID_TO_VDEV(pParam->Members[i*2 + j]);
683						pChild->u.array.pMember[j]->bSerialNumber = j;
684						pChild->u.array.pMember[j]->pParent = pChild;
685						pChild->u.array.pMember[j]->pfnDeviceFailed = pfnDeviceFailed[pChild->VDeviceType];
686						UnregisterVDevice(pChild->u.array.pMember[j]);
687					}
688
689					pArray->u.array.pMember[i] = pChild;
690
691					pChild->vf_online = 1;
692					pChild->bSerialNumber = i;
693					pChild->pParent = pArray;
694					pChild->VDeviceCapacity = MIN(pChild->u.array.pMember[0]->VDeviceCapacity,
695						pChild->u.array.pMember[1]->VDeviceCapacity);
696
697					pChild->pfnSendCommand = pfnSendCommand[pChild->VDeviceType];
698					pChild->pfnDeviceFailed = pfnDeviceFailed[VD_RAID_0];
699				}
700
701				pArray->VDeviceType = VD_RAID_0;
702
703				pArray->u.array.bArnMember = pParam->nDisk / 2;
704				pArray->u.array.bArRealnMember = pParam->nDisk / 2;
705				pArray->u.array.bArBlockSizeShift = pParam->BlockSizeShift;
706				pArray->u.array.bStripeWitch = (1 << pParam->BlockSizeShift);
707				pArray->u.array.dArStamp = Stamp;
708
709				pArray->u.array.rf_need_sync = 1;
710				pArray->u.array.rf_newly_created = 1;
711
712				memcpy(pArray->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME);
713			}
714			break;
715
716		default:
717			goto error;
718	}
719
720	for(i = 0; i < pArray->u.array.bArnMember; i++)
721		pArray->u.array.pMember[i]->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType];
722
723	if ((pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE) &&
724		(pArray->VDeviceType == VD_RAID_1))
725	{
726		pArray->vf_bootmark = pArray->u.array.pMember[0]->vf_bootmark;
727		pArray->vf_bootable = pArray->u.array.pMember[0]->vf_bootable;
728		pArray->u.array.pMember[0]->vf_bootable = 0;
729		pArray->u.array.pMember[0]->vf_bootmark = 0;
730		if (Loca>=0) {
731			_vbus_p->pVDevice[Loca] = pArray;
732			/* to comfort OS */
733			pArray->u.array.rf_duplicate_and_created = 1;
734			pArray->pVBus = _vbus_p;
735		}
736	}
737	else {
738		UCHAR TempBuffer[512];
739		ZeroMemory(TempBuffer, 512);
740		for(i = 0; i < pParam->nDisk; i++)
741		{
742			PVDevice	pDisk = ID_TO_VDEV(pParam->Members[i]);
743			pDisk->vf_bootmark = pDisk->vf_bootable = 0;
744			fDeReadWrite(&pDisk->u.disk, 0, IDE_COMMAND_WRITE, TempBuffer);
745		}
746	}
747
748	pArray->vf_online = 1;
749	pArray->pParent = NULL;
750
751	switch(pArray->VDeviceType)
752	{
753		case VD_RAID_0:
754			for(i = 0; i < pArray->u.array.bArnMember; i++)
755				if(pArray->u.array.pMember[i]->VDeviceCapacity < capacity)
756					capacity = pArray->u.array.pMember[i]->VDeviceCapacity;
757#ifdef ARRAY_V2_ONLY
758			capacity -= 10;
759#endif
760			capacity &= ~(pArray->u.array.bStripeWitch - 1);
761			/* shrink member capacity for RAID 1/0 */
762			for(i = 0; i < pArray->u.array.bArnMember; i++)
763				if (mIsArray(pArray->u.array.pMember[i]))
764					pArray->u.array.pMember[i]->VDeviceCapacity = capacity;
765			pArray->VDeviceCapacity = capacity * pArray->u.array.bArnMember;
766			break;
767
768		case VD_RAID_1:
769			pArray->VDeviceCapacity = MIN(pArray->u.array.pMember[0]->VDeviceCapacity,
770						pArray->u.array.pMember[1]->VDeviceCapacity);
771			break;
772
773		case VD_JBOD:
774			for(i = 0; i < pArray->u.array.bArnMember; i++)
775				pArray->VDeviceCapacity += pArray->u.array.pMember[i]->VDeviceCapacity
776#ifdef ARRAY_V2_ONLY
777				-10
778#endif
779				;
780			break;
781
782		case VD_RAID_5:
783			for(i = 0; i < pArray->u.array.bArnMember; i++)
784				if(pArray->u.array.pMember[i]->VDeviceCapacity < capacity)
785					capacity = pArray->u.array.pMember[i]->VDeviceCapacity;
786			pArray->VDeviceCapacity = rounddown2(capacity, pArray->u.array.bStripeWitch) *
787			    (pArray->u.array.bArnMember - 1);
788			break;
789
790		default:
791			goto error;
792	}
793
794	pArray->pfnSendCommand = pfnSendCommand[pArray->VDeviceType];
795	pArray->pfnDeviceFailed = fOsDiskFailed;
796	SyncArrayInfo(pArray);
797
798	if (!pArray->u.array.rf_duplicate_and_created)
799		RegisterVDevice(pArray);
800	return VDEV_TO_ID(pArray);
801
802error:
803	for(i = 0; i < pArray->u.array.bArnMember; i++)
804	{
805		pChild = pArray->u.array.pMember[i];
806		if((pChild != NULL) && (pChild->VDeviceType != VD_SINGLE_DISK))
807			mArFreeArrayTable(pChild);
808	}
809	mArFreeArrayTable(pArray);
810	return INVALID_DEVICEID;
811}
812
813DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam)
814{
815	CREATE_ARRAY_PARAMS_V2 param2;
816	param2.ArrayType = pParam->ArrayType;
817	param2.nDisk = pParam->nDisk;
818	param2.BlockSizeShift = pParam->BlockSizeShift;
819	param2.CreateFlags = pParam->CreateFlags;
820	param2.CreateTime = pParam->CreateTime;
821	memcpy(param2.ArrayName, pParam->ArrayName, sizeof(param2.ArrayName));
822	memcpy(param2.Description, pParam->Description, sizeof(param2.Description));
823	memcpy(param2.CreateManager, pParam->CreateManager, sizeof(param2.CreateManager));
824	param2.Capacity.lo32 = param2.Capacity.hi32 = 0;
825	memcpy(param2.Members, pParam->Members, sizeof(pParam->Members));
826	return hpt_create_array_v2(_VBUS_P &param2);
827}
828
829#ifdef SUPPORT_OLD_ARRAY
830/* this is only for old RAID 0/1 */
831int old_add_disk_to_raid01(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk)
832{
833	PVDevice pArray1 = ID_TO_VDEV(idArray);
834	PVDevice pArray2 = 0;
835	PVDevice pDisk	= ID_TO_VDEV(idDisk);
836	int	i;
837	IAL_ADAPTER_T *pAdapter = gIal_Adapter;
838
839	if (pArray1->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
840
841	if(pDisk->u.disk.dDeRealCapacity < (pArray1->VDeviceCapacity / 2))
842		return -1;
843
844	pArray2 = pArray1->u.array.pMember[1];
845	if(pArray2 == NULL)	{
846		/* create a Stripe */
847		mArGetArrayTable(pArray2);
848		pArray2->VDeviceType = VD_RAID_0;
849		pArray2->u.array.dArStamp = GetStamp();
850		pArray2->vf_format_v2 = 1;
851		pArray2->u.array.rf_broken = 1;
852		pArray2->u.array.bArBlockSizeShift = pArray1->u.array.bArBlockSizeShift;
853		pArray2->u.array.bStripeWitch = (1 << pArray2->u.array.bArBlockSizeShift);
854		pArray2->u.array.bArnMember = 2;
855		pArray2->VDeviceCapacity = pArray1->VDeviceCapacity;
856		pArray2->pfnSendCommand = pfnSendCommand[pArray2->VDeviceType];
857		pArray2->pfnDeviceFailed = pfnDeviceFailed[pArray1->VDeviceType];
858		memcpy(pArray2->u.array.ArrayName, pArray1->u.array.ArrayName, MAX_ARRAY_NAME);
859		pArray2->pParent = pArray1;
860		pArray2->bSerialNumber = 1;
861		pArray1->u.array.pMember[1] = pArray2;
862		pArray1->u.array.bArRealnMember++;
863	}
864
865	for(i = 0; i < pArray2->u.array.bArnMember; i++)
866		if((pArray2->u.array.pMember[i] == NULL) || !pArray2->u.array.pMember[i]->vf_online)
867		{
868			if(pArray2->u.array.pMember[i] != NULL)
869				pArray2->u.array.pMember[i]->pParent = NULL;
870			pArray2->u.array.pMember[i] = pDisk;
871			goto find;
872		}
873	return -1;
874
875find:
876	UnregisterVDevice(pDisk);
877	pDisk->VDeviceType = VD_SINGLE_DISK;
878	pDisk->bSerialNumber = i;
879	pDisk->pParent = pArray2;
880	pDisk->vf_format_v2 = 1;
881	pDisk->u.disk.dDeHiddenLba = i? 10 : 0;
882	pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity;
883	pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray2->VDeviceType];
884
885	pArray2->u.array.bArRealnMember++;
886	if(pArray2->u.array.bArnMember == pArray2->u.array.bArRealnMember){
887		pArray2->vf_online = 1;
888		pArray2->u.array.rf_broken = 0;
889	}
890
891	if(pArray1->u.array.pMember[0]->vf_online && pArray1->u.array.pMember[1]->vf_online){
892		pArray1->u.array.bArRealnMember = pArray1->u.array.bArnMember;
893		pArray1->u.array.rf_broken = 0;
894		pArray1->u.array.rf_need_rebuild = 1;
895		pArray1->u.array.rf_auto_rebuild = 1;
896
897	}
898	pArray1->u.array.RebuildSectors = 0;
899	pArray1->u.array.dArStamp = GetStamp();
900	SyncArrayInfo(pArray1);
901	return 1;
902}
903#endif
904
905int hpt_add_disk_to_array(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk)
906{
907	int	i;
908
909	LBA_T Capacity;
910	PVDevice pArray = ID_TO_VDEV(idArray);
911	PVDevice pDisk	= ID_TO_VDEV(idDisk);
912
913	if((idArray == 0) || (idDisk == 0))	return -1;
914	if(check_VDevice_valid(pArray) || check_VDevice_valid(pDisk))	return -1;
915	if(!pArray->u.array.rf_broken)	return -1;
916
917	if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5)
918		return -1;
919	if((pDisk->VDeviceType != VD_SINGLE_DISK) && (pDisk->VDeviceType != VD_SPARE))
920		return -1;
921
922#ifdef SUPPORT_OLD_ARRAY
923	/* RAID 0 + 1 */
924	if (pArray->vf_format_v2 && pArray->VDeviceType==VD_RAID_1 &&
925		pArray->u.array.pMember[0] &&
926		mIsArray(pArray->u.array.pMember[0]))
927	{
928		if(old_add_disk_to_raid01(_VBUS_P idArray, idDisk))
929			return 0;
930		else
931			return -1;
932	}
933#endif
934
935	Capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember - 1);
936
937	if (pArray->vf_format_v2) {
938		if(pDisk->u.disk.dDeRealCapacity < Capacity) return -1;
939	}
940	else
941		if(pDisk->VDeviceCapacity < Capacity) return -1;
942
943	if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
944
945	for(i = 0; i < pArray->u.array.bArnMember; i++)
946		if((pArray->u.array.pMember[i] == 0) || !pArray->u.array.pMember[i]->vf_online)
947		{
948			if(pArray->u.array.pMember[i] != NULL)
949				pArray->u.array.pMember[i]->pParent = NULL;
950			pArray->u.array.pMember[i] = pDisk;
951			goto find;
952		}
953	return -1;
954
955find:
956	UnregisterVDevice(pDisk);
957	pDisk->VDeviceType = VD_SINGLE_DISK;
958	pDisk->bSerialNumber = i;
959	pDisk->pParent = pArray;
960	if (pArray->VDeviceType==VD_RAID_5) pDisk->vf_cache_disk = 1;
961	pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType];
962	if (pArray->vf_format_v2) {
963		pDisk->vf_format_v2 = 1;
964		pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity;
965	}
966
967	pArray->u.array.bArRealnMember++;
968	if(pArray->u.array.bArnMember == pArray->u.array.bArRealnMember)
969	{
970		pArray->u.array.rf_need_rebuild = 1;
971		pArray->u.array.RebuildSectors = 0;
972		pArray->u.array.rf_auto_rebuild = 1;
973		pArray->u.array.rf_broken = 0;
974	}
975	pArray->u.array.RebuildSectors = 0;
976
977	/* sync the whole array */
978	while (pArray->pParent) pArray = pArray->pParent;
979	pArray->u.array.dArStamp = GetStamp();
980	SyncArrayInfo(pArray);
981	return 0;
982}
983
984int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk)
985{
986	PVDevice pVDevice = ID_TO_VDEV(idDisk);
987	DECLARE_BUFFER(PUCHAR, pbuffer);
988
989	if(idDisk == 0 || check_VDevice_valid(pVDevice))	return -1;
990	if (pVDevice->VDeviceType != VD_SINGLE_DISK || pVDevice->pParent)
991		return -1;
992
993	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
994
995	UnregisterVDevice(pVDevice);
996	pVDevice->VDeviceType = VD_SPARE;
997	pVDevice->vf_bootmark = 0;
998
999	ZeroMemory((char *)pbuffer, 512);
1000	fDeReadWrite(&pVDevice->u.disk, 0, IDE_COMMAND_WRITE, pbuffer);
1001	SyncArrayInfo(pVDevice);
1002	return 0;
1003}
1004
1005int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk)
1006{
1007	PVDevice pVDevice = ID_TO_VDEV(idDisk);
1008
1009	if(idDisk == 0 || check_VDevice_valid(pVDevice))	return -1;
1010
1011	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
1012
1013	pVDevice->VDeviceType = VD_SINGLE_DISK;
1014
1015	SyncArrayInfo(pVDevice);
1016	RegisterVDevice(pVDevice);
1017	return 0;
1018}
1019
1020int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo)
1021{
1022	PVDevice pVDevice = ID_TO_VDEV(idArray);
1023
1024	if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1;
1025	if (!mIsArray(pVDevice)) return -1;
1026
1027	/* if the pVDevice isn't a top level, return -1; */
1028	if(pVDevice->pParent != NULL) return -1;
1029
1030	if (pVDevice->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
1031
1032	if (pInfo->ValidFields & AAIF_NAME) {
1033		memset(pVDevice->u.array.ArrayName, 0, MAX_ARRAY_NAME);
1034		memcpy(pVDevice->u.array.ArrayName, pInfo->Name, sizeof(pInfo->Name));
1035		pVDevice->u.array.rf_need_sync = 1;
1036	}
1037
1038	if (pInfo->ValidFields & AAIF_DESCRIPTION) {
1039		memcpy(pVDevice->u.array.Description, pInfo->Description, sizeof(pInfo->Description));
1040		pVDevice->u.array.rf_need_sync = 1;
1041	}
1042
1043	if (pVDevice->u.array.rf_need_sync)
1044		SyncArrayInfo(pVDevice);
1045	return 0;
1046}
1047
1048static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo)
1049{
1050	PVDevice pVDevice = ID_TO_VDEV(idDisk);
1051
1052	if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1;
1053	if (mIsArray(pVDevice))
1054		return -1;
1055
1056	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
1057
1058	/* TODO */
1059		return 0;
1060	}
1061
1062static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo)
1063{
1064	PVDevice pVDevice = ID_TO_VDEV(idDisk);
1065	int sync = 0;
1066
1067	if(idDisk==0 || check_VDevice_valid(pVDevice)) return -1;
1068	if (mIsArray(pVDevice))
1069		return -1;
1070
1071	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
1072
1073	if (pInfo->ValidFields & ADIF_MODE) {
1074		pVDevice->u.disk.bDeModeSetting = pInfo->DeviceModeSetting;
1075		pVDevice->u.disk.bDeUserSelectMode = pInfo->DeviceModeSetting;
1076		pVDevice->u.disk.df_user_mode_set = 1;
1077		fDeSelectMode((PDevice)&(pVDevice->u.disk), (UCHAR)pInfo->DeviceModeSetting);
1078		sync = 1;
1079}
1080
1081	if (pInfo->ValidFields & ADIF_TCQ) {
1082		if (fDeSetTCQ(&pVDevice->u.disk, pInfo->TCQEnabled, 0)) {
1083			pVDevice->u.disk.df_tcq_set = 1;
1084			pVDevice->u.disk.df_tcq = pInfo->TCQEnabled!=0;
1085			sync = 1;
1086}
1087	}
1088
1089	if (pInfo->ValidFields & ADIF_NCQ) {
1090		if (fDeSetNCQ(&pVDevice->u.disk, pInfo->NCQEnabled, 0)) {
1091			pVDevice->u.disk.df_ncq_set = 1;
1092			pVDevice->u.disk.df_ncq = pInfo->NCQEnabled!=0;
1093			sync = 1;
1094	}
1095	}
1096
1097	if (pInfo->ValidFields & ADIF_WRITE_CACHE) {
1098		if (fDeSetWriteCache(&pVDevice->u.disk, pInfo->WriteCacheEnabled)) {
1099			pVDevice->u.disk.df_write_cache_set = 1;
1100			pVDevice->u.disk.df_write_cache = pInfo->WriteCacheEnabled!=0;
1101			sync = 1;
1102	}
1103	}
1104
1105	if (pInfo->ValidFields & ADIF_READ_AHEAD) {
1106		if (fDeSetReadAhead(&pVDevice->u.disk, pInfo->ReadAheadEnabled)) {
1107			pVDevice->u.disk.df_read_ahead_set = 1;
1108			pVDevice->u.disk.df_read_ahead = pInfo->ReadAheadEnabled!=0;
1109			sync = 1;
1110		}
1111	}
1112
1113	if (sync)
1114		SyncArrayInfo(pVDevice);
1115	return 0;
1116}
1117
1118#endif
1119
1120/* hpt_default_ioctl()
1121 *  This is a default implementation. The platform dependent part
1122 *  may reuse this function and/or use it own implementation for
1123 *  each ioctl function.
1124 */
1125int hpt_default_ioctl(_VBUS_ARG
1126							DWORD dwIoControlCode,       	/* operation control code */
1127							PVOID lpInBuffer,            	/* input data buffer */
1128							DWORD nInBufferSize,         	/* size of input data buffer */
1129							PVOID lpOutBuffer,           	/* output data buffer */
1130							DWORD nOutBufferSize,        	/* size of output data buffer */
1131							PDWORD lpBytesReturned      	/* byte count */
1132					)
1133{
1134	switch(dwIoControlCode)	{
1135
1136	case HPT_IOCTL_GET_VERSION:
1137
1138		if (nInBufferSize != 0) return -1;
1139		if (nOutBufferSize != sizeof(DWORD)) return -1;
1140		*((DWORD*)lpOutBuffer) = HPT_INTERFACE_VERSION;
1141		break;
1142
1143	case HPT_IOCTL_GET_CONTROLLER_COUNT:
1144
1145		if (nOutBufferSize!=sizeof(DWORD)) return -1;
1146		*(PDWORD)lpOutBuffer = hpt_get_controller_count();
1147		break;
1148
1149	case HPT_IOCTL_GET_CONTROLLER_INFO:
1150		{
1151			int id;
1152			PCONTROLLER_INFO pInfo;
1153
1154			if (nInBufferSize!=sizeof(DWORD)) return -1;
1155			if (nOutBufferSize!=sizeof(CONTROLLER_INFO)) return -1;
1156
1157			id = *(DWORD *)lpInBuffer;
1158			pInfo = (PCONTROLLER_INFO)lpOutBuffer;
1159			if (hpt_get_controller_info(id, pInfo)!=0)
1160				return -1;
1161		}
1162		break;
1163
1164	case HPT_IOCTL_GET_CHANNEL_INFO:
1165		{
1166			int id, bus;
1167			PCHANNEL_INFO pInfo;
1168
1169			if (nInBufferSize!=8) return -1;
1170			if (nOutBufferSize!=sizeof(CHANNEL_INFO)) return -1;
1171
1172			id = *(DWORD *)lpInBuffer;
1173			bus = ((DWORD *)lpInBuffer)[1];
1174			pInfo = (PCHANNEL_INFO)lpOutBuffer;
1175
1176			if (hpt_get_channel_info(id, bus, pInfo)!=0)
1177				return -1;
1178		}
1179		break;
1180
1181	case HPT_IOCTL_GET_LOGICAL_DEVICES:
1182		{
1183			DWORD nMax;
1184			DEVICEID *pIds;
1185
1186			if (nInBufferSize!=sizeof(DWORD)) return -1;
1187			nMax = *(DWORD *)lpInBuffer;
1188			if (nOutBufferSize < sizeof(DWORD)+sizeof(DWORD)*nMax) return -1;
1189
1190			pIds = ((DEVICEID *)lpOutBuffer)+1;
1191			*(DWORD*)lpOutBuffer = hpt_get_logical_devices(pIds, nMax);
1192		}
1193		break;
1194
1195	case HPT_IOCTL_GET_DEVICE_INFO:
1196		{
1197			DEVICEID id;
1198			PLOGICAL_DEVICE_INFO pInfo;
1199
1200			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1201			if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO)) return -1;
1202
1203			id = *(DWORD *)lpInBuffer;
1204			if (id == INVALID_DEVICEID)	return -1;
1205
1206			pInfo = (PLOGICAL_DEVICE_INFO)lpOutBuffer;
1207			memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO));
1208
1209			if (hpt_get_device_info(id, pInfo)!=0)
1210				return -1;
1211		}
1212		break;
1213
1214	case HPT_IOCTL_GET_DEVICE_INFO_V2:
1215		{
1216			DEVICEID id;
1217			PLOGICAL_DEVICE_INFO_V2 pInfo;
1218
1219			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1220			if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO_V2)) return -1;
1221
1222			id = *(DWORD *)lpInBuffer;
1223			if (id == INVALID_DEVICEID)	return -1;
1224
1225			pInfo = (PLOGICAL_DEVICE_INFO_V2)lpOutBuffer;
1226			memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO_V2));
1227
1228			if (hpt_get_device_info_v2(id, pInfo)!=0)
1229				return -1;
1230		}
1231		break;
1232
1233#ifdef SUPPORT_ARRAY
1234	case HPT_IOCTL_CREATE_ARRAY:
1235		{
1236			if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS)) return -1;
1237			if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
1238
1239			*(DEVICEID *)lpOutBuffer = hpt_create_array(_VBUS_P (PCREATE_ARRAY_PARAMS)lpInBuffer);
1240
1241			if(*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
1242				return -1;
1243		}
1244		break;
1245
1246	case HPT_IOCTL_CREATE_ARRAY_V2:
1247		{
1248			if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS_V2)) return -1;
1249			if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
1250
1251			*(DEVICEID *)lpOutBuffer = hpt_create_array_v2(_VBUS_P (PCREATE_ARRAY_PARAMS_V2)lpInBuffer);
1252
1253			if (*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
1254				return -1;
1255		}
1256		break;
1257
1258	case HPT_IOCTL_SET_ARRAY_INFO:
1259		{
1260			DEVICEID idArray;
1261			PALTERABLE_ARRAY_INFO pInfo;
1262
1263			if (nInBufferSize!=sizeof(HPT_SET_ARRAY_INFO)) return -1;
1264			if (nOutBufferSize!=0) return -1;
1265
1266			idArray = ((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray;
1267			pInfo = &((PHPT_SET_ARRAY_INFO)lpInBuffer)->Info;
1268
1269			if(hpt_set_array_info(_VBUS_P idArray,  pInfo))
1270				return -1;
1271		}
1272		break;
1273
1274	case HPT_IOCTL_SET_DEVICE_INFO:
1275		{
1276			DEVICEID idDisk;
1277			PALTERABLE_DEVICE_INFO pInfo;
1278
1279			if (nInBufferSize!=sizeof(HPT_SET_DEVICE_INFO)) return -1;
1280			if (nOutBufferSize!=0) return -1;
1281
1282			idDisk = ((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk;
1283			pInfo = &((PHPT_SET_DEVICE_INFO)lpInBuffer)->Info;
1284			if(hpt_set_device_info(_VBUS_P idDisk, pInfo) != 0)
1285				return -1;
1286		}
1287		break;
1288
1289	case HPT_IOCTL_SET_DEVICE_INFO_V2:
1290		{
1291			DEVICEID idDisk;
1292			PALTERABLE_DEVICE_INFO_V2 pInfo;
1293
1294			if (nInBufferSize < sizeof(HPT_SET_DEVICE_INFO_V2)) return -1;
1295			if (nOutBufferSize!=0) return -1;
1296
1297			idDisk = ((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk;
1298			pInfo = &((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->Info;
1299			if(hpt_set_device_info_v2(_VBUS_P idDisk, pInfo) != 0)
1300				return -1;
1301		}
1302		break;
1303
1304	case HPT_IOCTL_SET_BOOT_MARK:
1305		{
1306			DEVICEID id;
1307			PVDevice pTop;
1308			int i;
1309			IAL_ADAPTER_T *pAdapter = gIal_Adapter;
1310			PVBus pVBus;
1311
1312			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1313			id = *(DEVICEID *)lpInBuffer;
1314			while(pAdapter != 0)
1315			{
1316				pVBus = &pAdapter->VBus;
1317				for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
1318				{
1319					if(!(pTop = pVBus->pVDevice[i])) continue;
1320					if (pTop->pVBus!=_vbus_p) return -1;
1321					while (pTop->pParent) pTop = pTop->pParent;
1322					if (id==0 && pTop->vf_bootmark)
1323						pTop->vf_bootmark = 0;
1324					else if (pTop==ID_TO_VDEV(id) && !pTop->vf_bootmark)
1325						pTop->vf_bootmark = 1;
1326					else
1327						continue;
1328					SyncArrayInfo(pTop);
1329					break;
1330				}
1331				pAdapter = pAdapter->next;
1332			}
1333		}
1334		break;
1335
1336	case HPT_IOCTL_ADD_SPARE_DISK:
1337		{
1338			DEVICEID id;
1339
1340			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1341			if (nOutBufferSize!=0) return -1;
1342
1343			id = *(DEVICEID *)lpInBuffer;
1344
1345			if(hpt_add_spare_disk(_VBUS_P id))
1346				return -1;
1347		}
1348		break;
1349
1350	case HPT_IOCTL_REMOVE_SPARE_DISK:
1351		{
1352			DEVICEID id;
1353
1354			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1355			if (nOutBufferSize!=0) return -1;
1356
1357			id = *(DEVICEID *)lpInBuffer;
1358
1359			if(hpt_remove_spare_disk(_VBUS_P id))
1360				return -1;
1361		}
1362		break;
1363
1364	case HPT_IOCTL_ADD_DISK_TO_ARRAY:
1365		{
1366			DEVICEID id1,id2;
1367			id1 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray;
1368			id2 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idDisk;
1369
1370			if (nInBufferSize != sizeof(HPT_ADD_DISK_TO_ARRAY)) return -1;
1371			if (nOutBufferSize != 0) return -1;
1372
1373			if(hpt_add_disk_to_array(_VBUS_P id1, id2))
1374				return -1;
1375		}
1376		break;
1377#endif
1378	case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
1379		{
1380			PDRIVER_CAPABILITIES cap;
1381			if (nOutBufferSize<sizeof(DRIVER_CAPABILITIES)) return -1;
1382			cap = (PDRIVER_CAPABILITIES)lpOutBuffer;
1383
1384			if(hpt_get_driver_capabilities(cap))
1385				return -1;
1386		}
1387		break;
1388
1389	case HPT_IOCTL_GET_CONTROLLER_VENID:
1390		{
1391			DWORD id = ((DWORD*)lpInBuffer)[0];
1392			IAL_ADAPTER_T *pAdapTemp;
1393			int iControllerCount = 0;
1394
1395			for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
1396				if (iControllerCount++==id)
1397					break;
1398
1399			if (!pAdapTemp)
1400				return -1;
1401
1402			if (nOutBufferSize < 4)
1403				return -1;
1404
1405			*(DWORD*)lpOutBuffer = ((DWORD)pAdapTemp->mvSataAdapter.pciConfigDeviceId << 16) | 0x11AB;
1406			return 0;
1407		}
1408
1409	case HPT_IOCTL_EPROM_IO:
1410		{
1411			DWORD id           = ((DWORD*)lpInBuffer)[0];
1412			DWORD offset	   = ((DWORD*)lpInBuffer)[1];
1413			DWORD direction    = ((DWORD*)lpInBuffer)[2];
1414			DWORD length	   = ((DWORD*)lpInBuffer)[3];
1415			IAL_ADAPTER_T *pAdapTemp;
1416			int iControllerCount = 0;
1417
1418			for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
1419				if (iControllerCount++==id)
1420					break;
1421
1422			if (!pAdapTemp)
1423				return -1;
1424
1425			if (nInBufferSize < sizeof(DWORD) * 4 + (direction? length : 0) ||
1426				nOutBufferSize < (direction? 0 : length))
1427				return -1;
1428
1429			if (direction == 0) /* read */
1430				sx508x_flash_access(&pAdapTemp->mvSataAdapter,
1431					offset, lpOutBuffer, length, 1);
1432			else
1433				sx508x_flash_access(&pAdapTemp->mvSataAdapter,
1434					offset, (char *)lpInBuffer + 16, length, 0);
1435
1436			return 0;
1437		}
1438		break;
1439
1440	default:
1441		return -1;
1442	}
1443
1444	if (lpBytesReturned)
1445		*lpBytesReturned = nOutBufferSize;
1446	return 0;
1447}
1448