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
56static int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap);
57static int hpt_get_controller_count(void);
58static int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo);
59static int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo);
60static int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount);
61static int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo);
62static int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo);
63static DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam);
64static DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam);
65static int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk);
66static int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk);
67static int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo);
68static int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo);
69static int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo);
70
71int
72check_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
106static 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
117static 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
204static 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
232static 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
253static 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
276static 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
358int 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
403int 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
417int 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
448int 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
461found:
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
481int 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
510done:
511	return count;
512}
513
514int 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
538int 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
565DEVICEID 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;
619simple:
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
804error:
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
815DEVICEID 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 */
833int 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
877find:
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
907int 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
957find:
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
986int 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
1007int 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
1022int 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
1050static 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
1064static 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 */
1127int hpt_default_ioctl(_VBUS_ARG
1128							DWORD dwIoControlCode,       	/* operation control code */
1129							PVOID lpInBuffer,            	/* input data buffer */
1130							DWORD nInBufferSize,         	/* size of input data buffer */
1131							PVOID lpOutBuffer,           	/* output data buffer */
1132							DWORD nOutBufferSize,        	/* size of output data buffer */
1133							PDWORD lpBytesReturned      	/* byte count */
1134					)
1135{
1136	switch(dwIoControlCode)	{
1137
1138	case HPT_IOCTL_GET_VERSION:
1139
1140		if (nInBufferSize != 0) return -1;
1141		if (nOutBufferSize != sizeof(DWORD)) return -1;
1142		*((DWORD*)lpOutBuffer) = HPT_INTERFACE_VERSION;
1143		break;
1144
1145	case HPT_IOCTL_GET_CONTROLLER_COUNT:
1146
1147		if (nOutBufferSize!=sizeof(DWORD)) return -1;
1148		*(PDWORD)lpOutBuffer = hpt_get_controller_count();
1149		break;
1150
1151	case HPT_IOCTL_GET_CONTROLLER_INFO:
1152		{
1153			int id;
1154			PCONTROLLER_INFO pInfo;
1155
1156			if (nInBufferSize!=sizeof(DWORD)) return -1;
1157			if (nOutBufferSize!=sizeof(CONTROLLER_INFO)) return -1;
1158
1159			id = *(DWORD *)lpInBuffer;
1160			pInfo = (PCONTROLLER_INFO)lpOutBuffer;
1161			if (hpt_get_controller_info(id, pInfo)!=0)
1162				return -1;
1163		}
1164		break;
1165
1166	case HPT_IOCTL_GET_CHANNEL_INFO:
1167		{
1168			int id, bus;
1169			PCHANNEL_INFO pInfo;
1170
1171			if (nInBufferSize!=8) return -1;
1172			if (nOutBufferSize!=sizeof(CHANNEL_INFO)) return -1;
1173
1174			id = *(DWORD *)lpInBuffer;
1175			bus = ((DWORD *)lpInBuffer)[1];
1176			pInfo = (PCHANNEL_INFO)lpOutBuffer;
1177
1178			if (hpt_get_channel_info(id, bus, pInfo)!=0)
1179				return -1;
1180		}
1181		break;
1182
1183	case HPT_IOCTL_GET_LOGICAL_DEVICES:
1184		{
1185			DWORD nMax;
1186			DEVICEID *pIds;
1187
1188			if (nInBufferSize!=sizeof(DWORD)) return -1;
1189			nMax = *(DWORD *)lpInBuffer;
1190			if (nOutBufferSize < sizeof(DWORD)+sizeof(DWORD)*nMax) return -1;
1191
1192			pIds = ((DEVICEID *)lpOutBuffer)+1;
1193			*(DWORD*)lpOutBuffer = hpt_get_logical_devices(pIds, nMax);
1194		}
1195		break;
1196
1197	case HPT_IOCTL_GET_DEVICE_INFO:
1198		{
1199			DEVICEID id;
1200			PLOGICAL_DEVICE_INFO pInfo;
1201
1202			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1203			if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO)) return -1;
1204
1205			id = *(DWORD *)lpInBuffer;
1206			if (id == INVALID_DEVICEID)	return -1;
1207
1208			pInfo = (PLOGICAL_DEVICE_INFO)lpOutBuffer;
1209			memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO));
1210
1211			if (hpt_get_device_info(id, pInfo)!=0)
1212				return -1;
1213		}
1214		break;
1215
1216	case HPT_IOCTL_GET_DEVICE_INFO_V2:
1217		{
1218			DEVICEID id;
1219			PLOGICAL_DEVICE_INFO_V2 pInfo;
1220
1221			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1222			if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO_V2)) return -1;
1223
1224			id = *(DWORD *)lpInBuffer;
1225			if (id == INVALID_DEVICEID)	return -1;
1226
1227			pInfo = (PLOGICAL_DEVICE_INFO_V2)lpOutBuffer;
1228			memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO_V2));
1229
1230			if (hpt_get_device_info_v2(id, pInfo)!=0)
1231				return -1;
1232		}
1233		break;
1234
1235#ifdef SUPPORT_ARRAY
1236	case HPT_IOCTL_CREATE_ARRAY:
1237		{
1238			if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS)) return -1;
1239			if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
1240
1241			*(DEVICEID *)lpOutBuffer = hpt_create_array(_VBUS_P (PCREATE_ARRAY_PARAMS)lpInBuffer);
1242
1243			if(*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
1244				return -1;
1245		}
1246		break;
1247
1248	case HPT_IOCTL_CREATE_ARRAY_V2:
1249		{
1250			if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS_V2)) return -1;
1251			if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
1252
1253			*(DEVICEID *)lpOutBuffer = hpt_create_array_v2(_VBUS_P (PCREATE_ARRAY_PARAMS_V2)lpInBuffer);
1254
1255			if (*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
1256				return -1;
1257		}
1258		break;
1259
1260	case HPT_IOCTL_SET_ARRAY_INFO:
1261		{
1262			DEVICEID idArray;
1263			PALTERABLE_ARRAY_INFO pInfo;
1264
1265			if (nInBufferSize!=sizeof(HPT_SET_ARRAY_INFO)) return -1;
1266			if (nOutBufferSize!=0) return -1;
1267
1268			idArray = ((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray;
1269			pInfo = &((PHPT_SET_ARRAY_INFO)lpInBuffer)->Info;
1270
1271			if(hpt_set_array_info(_VBUS_P idArray,  pInfo))
1272				return -1;
1273		}
1274		break;
1275
1276	case HPT_IOCTL_SET_DEVICE_INFO:
1277		{
1278			DEVICEID idDisk;
1279			PALTERABLE_DEVICE_INFO pInfo;
1280
1281			if (nInBufferSize!=sizeof(HPT_SET_DEVICE_INFO)) return -1;
1282			if (nOutBufferSize!=0) return -1;
1283
1284			idDisk = ((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk;
1285			pInfo = &((PHPT_SET_DEVICE_INFO)lpInBuffer)->Info;
1286			if(hpt_set_device_info(_VBUS_P idDisk, pInfo) != 0)
1287				return -1;
1288		}
1289		break;
1290
1291	case HPT_IOCTL_SET_DEVICE_INFO_V2:
1292		{
1293			DEVICEID idDisk;
1294			PALTERABLE_DEVICE_INFO_V2 pInfo;
1295
1296			if (nInBufferSize < sizeof(HPT_SET_DEVICE_INFO_V2)) return -1;
1297			if (nOutBufferSize!=0) return -1;
1298
1299			idDisk = ((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk;
1300			pInfo = &((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->Info;
1301			if(hpt_set_device_info_v2(_VBUS_P idDisk, pInfo) != 0)
1302				return -1;
1303		}
1304		break;
1305
1306	case HPT_IOCTL_SET_BOOT_MARK:
1307		{
1308			DEVICEID id;
1309			PVDevice pTop;
1310			int i;
1311			IAL_ADAPTER_T *pAdapter = gIal_Adapter;
1312			PVBus pVBus;
1313
1314			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1315			id = *(DEVICEID *)lpInBuffer;
1316			while(pAdapter != 0)
1317			{
1318				pVBus = &pAdapter->VBus;
1319				for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
1320				{
1321					if(!(pTop = pVBus->pVDevice[i])) continue;
1322					if (pTop->pVBus!=_vbus_p) return -1;
1323					while (pTop->pParent) pTop = pTop->pParent;
1324					if (id==0 && pTop->vf_bootmark)
1325						pTop->vf_bootmark = 0;
1326					else if (pTop==ID_TO_VDEV(id) && !pTop->vf_bootmark)
1327						pTop->vf_bootmark = 1;
1328					else
1329						continue;
1330					SyncArrayInfo(pTop);
1331					break;
1332				}
1333				pAdapter = pAdapter->next;
1334			}
1335		}
1336		break;
1337
1338	case HPT_IOCTL_ADD_SPARE_DISK:
1339		{
1340			DEVICEID id;
1341
1342			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1343			if (nOutBufferSize!=0) return -1;
1344
1345			id = *(DEVICEID *)lpInBuffer;
1346
1347			if(hpt_add_spare_disk(_VBUS_P id))
1348				return -1;
1349		}
1350		break;
1351
1352	case HPT_IOCTL_REMOVE_SPARE_DISK:
1353		{
1354			DEVICEID id;
1355
1356			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1357			if (nOutBufferSize!=0) return -1;
1358
1359			id = *(DEVICEID *)lpInBuffer;
1360
1361			if(hpt_remove_spare_disk(_VBUS_P id))
1362				return -1;
1363		}
1364		break;
1365
1366	case HPT_IOCTL_ADD_DISK_TO_ARRAY:
1367		{
1368			DEVICEID id1,id2;
1369			id1 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray;
1370			id2 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idDisk;
1371
1372			if (nInBufferSize != sizeof(HPT_ADD_DISK_TO_ARRAY)) return -1;
1373			if (nOutBufferSize != 0) return -1;
1374
1375			if(hpt_add_disk_to_array(_VBUS_P id1, id2))
1376				return -1;
1377		}
1378		break;
1379#endif
1380	case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
1381		{
1382			PDRIVER_CAPABILITIES cap;
1383			if (nOutBufferSize<sizeof(DRIVER_CAPABILITIES)) return -1;
1384			cap = (PDRIVER_CAPABILITIES)lpOutBuffer;
1385
1386			if(hpt_get_driver_capabilities(cap))
1387				return -1;
1388		}
1389		break;
1390
1391	case HPT_IOCTL_GET_CONTROLLER_VENID:
1392		{
1393			DWORD id = ((DWORD*)lpInBuffer)[0];
1394			IAL_ADAPTER_T *pAdapTemp;
1395			int iControllerCount = 0;
1396
1397			for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
1398				if (iControllerCount++==id)
1399					break;
1400
1401			if (!pAdapTemp)
1402				return -1;
1403
1404			if (nOutBufferSize < 4)
1405				return -1;
1406
1407			*(DWORD*)lpOutBuffer = ((DWORD)pAdapTemp->mvSataAdapter.pciConfigDeviceId << 16) | 0x11AB;
1408			return 0;
1409		}
1410
1411	case HPT_IOCTL_EPROM_IO:
1412		{
1413			DWORD id           = ((DWORD*)lpInBuffer)[0];
1414			DWORD offset	   = ((DWORD*)lpInBuffer)[1];
1415			DWORD direction    = ((DWORD*)lpInBuffer)[2];
1416			DWORD length	   = ((DWORD*)lpInBuffer)[3];
1417			IAL_ADAPTER_T *pAdapTemp;
1418			int iControllerCount = 0;
1419
1420			for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
1421				if (iControllerCount++==id)
1422					break;
1423
1424			if (!pAdapTemp)
1425				return -1;
1426
1427			if (nInBufferSize < sizeof(DWORD) * 4 + (direction? length : 0) ||
1428				nOutBufferSize < (direction? 0 : length))
1429				return -1;
1430
1431			if (direction == 0) /* read */
1432				sx508x_flash_access(&pAdapTemp->mvSataAdapter,
1433					offset, lpOutBuffer, length, 1);
1434			else
1435				sx508x_flash_access(&pAdapTemp->mvSataAdapter,
1436					offset, (char *)lpInBuffer + 16, length, 0);
1437
1438			return 0;
1439		}
1440		break;
1441
1442	default:
1443		return -1;
1444	}
1445
1446	if (lpBytesReturned)
1447		*lpBytesReturned = nOutBufferSize;
1448	return 0;
1449}
1450