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