]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hptmv/gui_lib.c
Merge lld trunk r321017 to contrib/llvm/tools/lld.
[FreeBSD/FreeBSD.git] / sys / dev / hptmv / gui_lib.c
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 }