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