xref: /freebsd/sys/dev/hptmv/gui_lib.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
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  * 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 
54 static int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap);
55 static int hpt_get_controller_count(void);
56 static int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo);
57 static int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo);
58 static int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount);
59 static int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo);
60 static int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo);
61 static DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam);
62 static DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam);
63 static int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk);
64 static int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk);
65 static int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo);
66 static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo);
67 static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo);
68 
69 int
70 check_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 != 0)
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 != 0)
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 
104 static 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 
115 static 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 
202 static 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 
230 static 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 
251 static 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 
274 static 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 
356 int 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 
401 int hpt_get_controller_count(void)
402 {
403 	IAL_ADAPTER_T    *pAdapTemp = gIal_Adapter;
404 	int iControllerCount = 0;
405 
406 	while(pAdapTemp != 0)
407 	{
408 		iControllerCount++;
409 		pAdapTemp = pAdapTemp->next;
410 	}
411 
412 	return iControllerCount;
413 }
414 
415 int 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 
446 int 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 != 0)
452 	{
453 		if (iControllerCount++==id)
454 			goto found;
455 		pAdapTemp = pAdapTemp->next;
456 	}
457 	return -1;
458 
459 found:
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 
479 int 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 
508 done:
509 	return count;
510 }
511 
512 int 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 
536 int 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
563 DEVICEID 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;
617 simple:
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 = (capacity & ~(pArray->u.array.bStripeWitch - 1))
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 
802 error:
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 
813 DEVICEID 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 */
831 int 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 
875 find:
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 
905 int 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 
955 find:
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 
984 int 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 
1005 int 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 
1020 int 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 
1048 static 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 
1062 static 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  */
1125 int 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