1136849Sscottl/*
2149871Sscottl * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
3136849Sscottl * All rights reserved.
4136849Sscottl *
5136849Sscottl * Redistribution and use in source and binary forms, with or without
6136849Sscottl * modification, are permitted provided that the following conditions
7136849Sscottl * are met:
8136849Sscottl * 1. Redistributions of source code must retain the above copyright
9136849Sscottl *    notice, this list of conditions and the following disclaimer.
10136849Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11136849Sscottl *    notice, this list of conditions and the following disclaimer in the
12136849Sscottl *    documentation and/or other materials provided with the distribution.
13136849Sscottl *
14136849Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15136849Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16136849Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17136849Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18136849Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19136849Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20136849Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21136849Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22136849Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23136849Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24136849Sscottl * SUCH DAMAGE.
25142988Sscottl *
26142988Sscottl * $FreeBSD$
27136849Sscottl */
28136849Sscottl/*
29136849Sscottl * gui_lib.c
30136849Sscottl * Copyright (c) 2002-2004 HighPoint Technologies, Inc. All rights reserved.
31136849Sscottl *
32136849Sscottl *  Platform independent ioctl interface implementation.
33136849Sscottl *  The platform dependent part may reuse this function and/or use it own
34136849Sscottl *  implementation for each ioctl function.
35136849Sscottl *
36136849Sscottl *  This implementation doesn't use any synchronization; the caller must
37136849Sscottl *  assure the proper context when calling these functions.
38136849Sscottl */
39136849Sscottl
40136849Sscottl#include <sys/param.h>
41136849Sscottl#include <sys/systm.h>
42136849Sscottl#include <sys/kernel.h>
43136849Sscottl#include <sys/malloc.h>
44136849Sscottl
45149871Sscottl#ifndef __KERNEL__
46149871Sscottl#define __KERNEL__
47149871Sscottl#endif
48149871Sscottl
49136849Sscottl#include <dev/hptmv/global.h>
50136849Sscottl#include <dev/hptmv/hptintf.h>
51136849Sscottl#include <dev/hptmv/osbsd.h>
52143039Sscottl#include <dev/hptmv/access601.h>
53136849Sscottl
54136849Sscottlstatic int hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap);
55136849Sscottlstatic int hpt_get_controller_count(void);
56136849Sscottlstatic int hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo);
57136849Sscottlstatic int hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo);
58136849Sscottlstatic int hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount);
59136849Sscottlstatic int hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo);
60190809Sdelphijstatic int hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo);
61136849Sscottlstatic DEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam);
62190809Sdelphijstatic DEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam);
63136849Sscottlstatic int hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk);
64136849Sscottlstatic int hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk);
65136849Sscottlstatic int hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo);
66136849Sscottlstatic int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo);
67190809Sdelphijstatic int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo);
68136849Sscottl
69149871Sscottlint
70149871Sscottlcheck_VDevice_valid(PVDevice p)
71136849Sscottl{
72136849Sscottl	int i;
73136849Sscottl	PVDevice pVDevice;
74136849Sscottl	PVBus    _vbus_p;
75136849Sscottl	IAL_ADAPTER_T *pAdapter = gIal_Adapter;
76136849Sscottl
77136849Sscottl	while(pAdapter != 0)
78136849Sscottl	{
79136849Sscottl		for (i = 0; i < MV_SATA_CHANNELS_NUM; i++)
80136849Sscottl			if(&(pAdapter->VDevices[i]) == p)  return 0;
81136849Sscottl		pAdapter = pAdapter->next;
82136849Sscottl	}
83136849Sscottl
84136849Sscottl#ifdef SUPPORT_ARRAY
85136849Sscottl	pAdapter = gIal_Adapter;
86136849Sscottl	while(pAdapter != 0)
87136849Sscottl	{
88136849Sscottl		_vbus_p = &pAdapter->VBus;
89136849Sscottl		for (i=0;i<MAX_ARRAY_PER_VBUS;i++)
90136849Sscottl		{
91136849Sscottl			pVDevice=ArrayTables(i);
92136849Sscottl			if ((pVDevice->u.array.dArStamp != 0) && (pVDevice == p))
93136849Sscottl				return 0;
94136849Sscottl		}
95136849Sscottl		pAdapter = pAdapter->next;
96136849Sscottl	}
97136849Sscottl#endif
98136849Sscottl
99136849Sscottl	return -1;
100136849Sscottl}
101136849Sscottl
102136849Sscottl#ifdef SUPPORT_ARRAY
103136849Sscottl
104190809Sdelphijstatic UCHAR get_vdev_type(PVDevice pVDevice)
105136849Sscottl	{
106190809Sdelphij	switch (pVDevice->VDeviceType) {
107190809Sdelphij		case VD_RAID_0: return AT_RAID0;
108190809Sdelphij		case VD_RAID_1: return AT_RAID1;
109190809Sdelphij		case VD_JBOD:   return AT_JBOD;
110190809Sdelphij		case VD_RAID_5: return AT_RAID5;
111190809Sdelphij		default:        return AT_UNKNOWN;
112136849Sscottl	}
113190809Sdelphij	}
114136849Sscottl
115190809Sdelphijstatic DWORD get_array_flag(PVDevice pVDevice)
116190809Sdelphij{
117190809Sdelphij	int i;
118190809Sdelphij	DWORD f = 0;
119136849Sscottl
120136849Sscottl	/* The array is disabled */
121136849Sscottl	if(!pVDevice->vf_online)	{
122190809Sdelphij		f |= ARRAY_FLAG_DISABLED;
123190809Sdelphij		/* Ignore other info */
124190809Sdelphij		return f;
125136849Sscottl	}
126136849Sscottl
127136849Sscottl	/* array need synchronizing */
128136849Sscottl	if(pVDevice->u.array.rf_need_rebuild && !pVDevice->u.array.rf_duplicate_and_create)
129190809Sdelphij		f |= ARRAY_FLAG_NEEDBUILDING;
130136849Sscottl
131136849Sscottl	/* array is in rebuilding process */
132136849Sscottl	if(pVDevice->u.array.rf_rebuilding)
133190809Sdelphij		f |= ARRAY_FLAG_REBUILDING;
134136849Sscottl
135136849Sscottl	/* array is being verified */
136136849Sscottl	if(pVDevice->u.array.rf_verifying)
137190809Sdelphij		f |= ARRAY_FLAG_VERIFYING;
138136849Sscottl
139136849Sscottl	/* array is being initialized */
140136849Sscottl	if(pVDevice->u.array.rf_initializing)
141190809Sdelphij		f |= ARRAY_FLAG_INITIALIZING;
142136849Sscottl
143136849Sscottl	/* broken but may still working */
144136849Sscottl	if(pVDevice->u.array.rf_broken)
145190809Sdelphij		f |= ARRAY_FLAG_BROKEN;
146136849Sscottl
147136849Sscottl	/* array has a active partition */
148136849Sscottl	if(pVDevice->vf_bootable)
149190809Sdelphij		f |= ARRAY_FLAG_BOOTDISK;
150136849Sscottl
151136849Sscottl	/* a newly created array */
152136849Sscottl	if(pVDevice->u.array.rf_newly_created)
153190809Sdelphij		f |= ARRAY_FLAG_NEWLY_CREATED;
154136849Sscottl
155136849Sscottl	/* array has boot mark set */
156136849Sscottl	if(pVDevice->vf_bootmark)
157190809Sdelphij		f |= ARRAY_FLAG_BOOTMARK;
158136849Sscottl
159136849Sscottl	/* auto-rebuild should start */
160136849Sscottl	if(pVDevice->u.array.rf_auto_rebuild)
161190809Sdelphij		f |= ARRAY_FLAG_NEED_AUTOREBUILD;
162136849Sscottl
163136849Sscottl	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
164136849Sscottl	{
165136849Sscottl		PVDevice pMember = pVDevice->u.array.pMember[i];
166136849Sscottl		if (!pMember || !pMember->vf_online || (pMember->VDeviceType==VD_SINGLE_DISK))
167136849Sscottl			continue;
168136849Sscottl
169136849Sscottl		/* array need synchronizing */
170136849Sscottl		if(pMember->u.array.rf_need_rebuild &&
171136849Sscottl		   !pMember->u.array.rf_duplicate_and_create)
172190809Sdelphij			f |= ARRAY_FLAG_NEEDBUILDING;
173136849Sscottl
174136849Sscottl		/* array is in rebuilding process */
175136849Sscottl		if(pMember->u.array.rf_rebuilding)
176190809Sdelphij			f |= ARRAY_FLAG_REBUILDING;
177136849Sscottl
178136849Sscottl		/* array is being verified */
179136849Sscottl		if(pMember->u.array.rf_verifying)
180190809Sdelphij			f |= ARRAY_FLAG_VERIFYING;
181136849Sscottl
182136849Sscottl		/* array is being initialized */
183136849Sscottl		if(pMember->u.array.rf_initializing)
184190809Sdelphij			f |= ARRAY_FLAG_INITIALIZING;
185136849Sscottl
186136849Sscottl		/* broken but may still working */
187136849Sscottl		if(pMember->u.array.rf_broken)
188190809Sdelphij			f |= ARRAY_FLAG_BROKEN;
189136849Sscottl
190136849Sscottl		/* a newly created array */
191136849Sscottl		if(pMember->u.array.rf_newly_created)
192190809Sdelphij			f |= ARRAY_FLAG_NEWLY_CREATED;
193136849Sscottl
194136849Sscottl		/* auto-rebuild should start */
195136849Sscottl		if(pMember->u.array.rf_auto_rebuild)
196190809Sdelphij			f |= ARRAY_FLAG_NEED_AUTOREBUILD;
197190809Sdelphij	}
198136849Sscottl
199190809Sdelphij	return f;
200190809Sdelphij}
201190809Sdelphij
202190809Sdelphijstatic DWORD calc_rebuild_progress(PVDevice pVDevice)
203190809Sdelphij{
204190809Sdelphij	int i;
205190809Sdelphij	DWORD result = ((ULONG)(pVDevice->u.array.RebuildSectors>>11)*1000 /
206190809Sdelphij		(ULONG)(pVDevice->VDeviceCapacity>>11) * (pVDevice->u.array.bArnMember-1)) * 10;
207190809Sdelphij
208190809Sdelphij	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
209190809Sdelphij	{
210190809Sdelphij		PVDevice pMember = pVDevice->u.array.pMember[i];
211190809Sdelphij		if (!pMember || !pMember->vf_online || (pMember->VDeviceType==VD_SINGLE_DISK))
212190809Sdelphij			continue;
213190809Sdelphij
214136849Sscottl		/* for RAID1/0 case */
215136849Sscottl		if (pMember->u.array.rf_rebuilding ||
216136849Sscottl			pMember->u.array.rf_verifying ||
217136849Sscottl			pMember->u.array.rf_initializing)
218136849Sscottl		{
219190809Sdelphij			DWORD percent = ((ULONG)(pMember->u.array.RebuildSectors>>11)*1000 /
220190809Sdelphij				(ULONG)(pMember->VDeviceCapacity>>11) * (pMember->u.array.bArnMember-1)) * 10;
221190809Sdelphij			if (result==0 || result>percent)
222190809Sdelphij				result = percent;
223136849Sscottl		}
224190809Sdelphij		}
225190809Sdelphij
226190809Sdelphij	if (result>10000) result = 10000;
227190809Sdelphij	return result;
228136849Sscottl	}
229136849Sscottl
230190809Sdelphijstatic void get_array_info(PVDevice pVDevice, PHPT_ARRAY_INFO pArrayInfo)
231190809Sdelphij{
232190809Sdelphij	int	i;
233136849Sscottl
234190809Sdelphij	memcpy(pArrayInfo->Name, pVDevice->u.array.ArrayName, MAX_ARRAY_NAME);
235190809Sdelphij	pArrayInfo->ArrayType = get_vdev_type(pVDevice);
236190809Sdelphij	pArrayInfo->BlockSizeShift = pVDevice->u.array.bArBlockSizeShift;
237190809Sdelphij	pArrayInfo->RebuiltSectors = pVDevice->u.array.RebuildSectors;
238190809Sdelphij	pArrayInfo->Flags = get_array_flag(pVDevice);
239190809Sdelphij	pArrayInfo->RebuildingProgress = calc_rebuild_progress(pVDevice);
240136849Sscottl
241190809Sdelphij	pArrayInfo->nDisk = 0;
242136849Sscottl
243136849Sscottl	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
244190809Sdelphij		if(pVDevice->u.array.pMember[i] != NULL)
245190809Sdelphij			pArrayInfo->Members[pArrayInfo->nDisk++] = VDEV_TO_ID(pVDevice->u.array.pMember[i]);
246190809Sdelphij
247190809Sdelphij	for(i=pArrayInfo->nDisk; i<MAX_ARRAY_MEMBERS; i++)
248190809Sdelphij		pArrayInfo->Members[i] = INVALID_DEVICEID;
249136849Sscottl	}
250190809Sdelphij
251190809Sdelphijstatic void get_array_info_v2(PVDevice pVDevice, PHPT_ARRAY_INFO_V2 pArrayInfo)
252190809Sdelphij{
253190809Sdelphij	int	i;
254190809Sdelphij
255190809Sdelphij	memcpy(pArrayInfo->Name, pVDevice->u.array.ArrayName, MAX_ARRAYNAME_LEN);
256190809Sdelphij	pArrayInfo->ArrayType = get_vdev_type(pVDevice);
257190809Sdelphij	pArrayInfo->BlockSizeShift = pVDevice->u.array.bArBlockSizeShift;
258190809Sdelphij	pArrayInfo->RebuiltSectors.lo32 = pVDevice->u.array.RebuildSectors;
259190809Sdelphij	pArrayInfo->RebuiltSectors.hi32 = sizeof(LBA_T)>4? (pVDevice->u.array.RebuildSectors>>32) : 0;
260190809Sdelphij	pArrayInfo->Flags = get_array_flag(pVDevice);
261190809Sdelphij	pArrayInfo->RebuildingProgress = calc_rebuild_progress(pVDevice);
262190809Sdelphij
263190809Sdelphij	pArrayInfo->nDisk = 0;
264190809Sdelphij
265190809Sdelphij	for(i = 0; i < pVDevice->u.array.bArnMember; i++)
266190809Sdelphij		if(pVDevice->u.array.pMember[i] != NULL)
267190809Sdelphij			pArrayInfo->Members[pArrayInfo->nDisk++] = VDEV_TO_ID(pVDevice->u.array.pMember[i]);
268190809Sdelphij
269190809Sdelphij	for(i=pArrayInfo->nDisk; i<MAX_ARRAY_MEMBERS_V2; i++)
270190809Sdelphij		pArrayInfo->Members[i] = INVALID_DEVICEID;
271136849Sscottl}
272136849Sscottl#endif
273136849Sscottl
274190809Sdelphijstatic int get_disk_info(PVDevice pVDevice, PDEVICE_INFO pDiskInfo)
275136849Sscottl{
276136849Sscottl	MV_SATA_ADAPTER *pSataAdapter;
277136849Sscottl	MV_SATA_CHANNEL *pSataChannel;
278136849Sscottl	IAL_ADAPTER_T   *pAdapter;
279190809Sdelphij	MV_CHANNEL		*channelInfo;
280136849Sscottl	char *p;
281136849Sscottl	int i;
282136849Sscottl
283136849Sscottl	/* device location */
284136849Sscottl	pSataChannel = pVDevice->u.disk.mv;
285136849Sscottl	if(pSataChannel == NULL)	return -1;
286190809Sdelphij	pDiskInfo->TargetId = 0;
287136849Sscottl	pSataAdapter = pSataChannel->mvSataAdapter;
288136849Sscottl	if(pSataAdapter == NULL)	return -1;
289136849Sscottl
290136849Sscottl	pAdapter = pSataAdapter->IALData;
291136849Sscottl
292190809Sdelphij	pDiskInfo->PathId = pSataChannel->channelNumber;
293190809Sdelphij	pDiskInfo->ControllerId = (UCHAR)pSataAdapter->adapterId;
294136849Sscottl
295136849Sscottl/*GUI uses DeviceModeSetting to display to users
296136849Sscottl(1) if users select a mode, GUI/BIOS should display that mode.
297136849Sscottl(2) if SATA/150, GUI/BIOS should display 150 if case (1) isn't satisfied.
298136849Sscottl(3) display real mode if case (1)&&(2) not satisfied.
299136849Sscottl*/
300136849Sscottl	if (pVDevice->u.disk.df_user_mode_set)
301190809Sdelphij		pDiskInfo->DeviceModeSetting = pVDevice->u.disk.bDeUserSelectMode;
302190809Sdelphij	else if (((((PIDENTIFY_DATA)pVDevice->u.disk.mv->identifyDevice)->SataCapability) & 3)==2)
303190809Sdelphij		pDiskInfo->DeviceModeSetting = 15;
304136849Sscottl	else {
305136849Sscottl		p = (char *)&((PIDENTIFY_DATA)pVDevice->u.disk.mv->identifyDevice)->ModelNumber;
306190809Sdelphij		if (*(WORD*)p==(0x5354) /*'ST'*/ &&
307190809Sdelphij			(*(WORD*)(p+8)==(0x4153)/*'AS'*/ || (p[8]=='A' && p[11]=='S')))
308190809Sdelphij			pDiskInfo->DeviceModeSetting = 15;
309136849Sscottl		else
310190809Sdelphij			pDiskInfo->DeviceModeSetting = pVDevice->u.disk.bDeModeSetting;
311136849Sscottl	}
312136849Sscottl
313190809Sdelphij	pDiskInfo->UsableMode = pVDevice->u.disk.bDeUsable_Mode;
314136849Sscottl
315190809Sdelphij	pDiskInfo->DeviceType = PDT_HARDDISK;
316136849Sscottl
317190809Sdelphij	pDiskInfo->Flags = 0x0;
318136849Sscottl
319136849Sscottl	/* device is disabled */
320136849Sscottl	if(!pVDevice->u.disk.df_on_line)
321190809Sdelphij		pDiskInfo->Flags |= DEVICE_FLAG_DISABLED;
322136849Sscottl
323136849Sscottl	/* disk has a active partition */
324136849Sscottl	if(pVDevice->vf_bootable)
325190809Sdelphij		pDiskInfo->Flags |= DEVICE_FLAG_BOOTDISK;
326136849Sscottl
327136849Sscottl	/* disk has boot mark set */
328136849Sscottl	if(pVDevice->vf_bootmark)
329190809Sdelphij		pDiskInfo->Flags |= DEVICE_FLAG_BOOTMARK;
330136849Sscottl
331190809Sdelphij	pDiskInfo->Flags |= DEVICE_FLAG_SATA;
332136849Sscottl
333136849Sscottl	/* is a spare disk */
334136849Sscottl	if(pVDevice->VDeviceType == VD_SPARE)
335190809Sdelphij		pDiskInfo->Flags |= DEVICE_FLAG_IS_SPARE;
336136849Sscottl
337190809Sdelphij	memcpy(&(pDiskInfo->IdentifyData), (pSataChannel->identifyDevice), sizeof(IDENTIFY_DATA2));
338190809Sdelphij	p = (char *)&pDiskInfo->IdentifyData.ModelNumber;
339136849Sscottl	for (i = 0; i < 20; i++)
340136849Sscottl		((WORD*)p)[i] = shortswap(pSataChannel->identifyDevice[IDEN_MODEL_OFFSET+i]);
341136849Sscottl	p[39] = '\0';
342136849Sscottl
343190809Sdelphij	channelInfo = &pAdapter->mvChannel[pSataChannel->channelNumber];
344190809Sdelphij	pDiskInfo->ReadAheadSupported = channelInfo->readAheadSupported;
345190809Sdelphij	pDiskInfo->ReadAheadEnabled = channelInfo->readAheadEnabled;
346190809Sdelphij	pDiskInfo->WriteCacheSupported = channelInfo->writeCacheSupported;
347190809Sdelphij	pDiskInfo->WriteCacheEnabled = channelInfo->writeCacheEnabled;
348190809Sdelphij	pDiskInfo->TCQSupported = (pSataChannel->identifyDevice[IDEN_SUPPORTED_COMMANDS2] & (0x2))!=0;
349190809Sdelphij	pDiskInfo->TCQEnabled = pSataChannel->queuedDMA==MV_EDMA_MODE_QUEUED;
350190809Sdelphij	pDiskInfo->NCQSupported = MV_SATA_GEN_2(pSataAdapter) &&
351190809Sdelphij		(pSataChannel->identifyDevice[IDEN_SATA_CAPABILITIES] & (0x0100));
352190809Sdelphij	pDiskInfo->NCQEnabled = pSataChannel->queuedDMA==MV_EDMA_MODE_NATIVE_QUEUING;
353136849Sscottl	return 0;
354136849Sscottl}
355136849Sscottl
356149871Sscottlint hpt_get_driver_capabilities(PDRIVER_CAPABILITIES cap)
357136849Sscottl{
358136849Sscottl	ZeroMemory(cap, sizeof(DRIVER_CAPABILITIES));
359136849Sscottl	cap->dwSize = sizeof(DRIVER_CAPABILITIES);
360136849Sscottl	cap->MaximumControllers = MAX_VBUS;
361136849Sscottl
362136849Sscottl	/* cap->SupportCrossControllerRAID = 0; */
363136849Sscottl	/* take care for various OSes! */
364136849Sscottl	cap->SupportCrossControllerRAID = 0;
365136849Sscottl
366136849Sscottl
367136849Sscottl	cap->MinimumBlockSizeShift = MinBlockSizeShift;
368136849Sscottl	cap->MaximumBlockSizeShift = MaxBlockSizeShift;
369136849Sscottl	cap->SupportDiskModeSetting = 0;
370136849Sscottl	cap->SupportSparePool = 1;
371136849Sscottl	cap->MaximumArrayNameLength = MAX_ARRAY_NAME - 1;
372136849Sscottl	cap->SupportDedicatedSpare = 0;
373136849Sscottl
374136849Sscottl
375136849Sscottl#ifdef SUPPORT_ARRAY
376136849Sscottl	/* Stripe */
377136849Sscottl	cap->SupportedRAIDTypes[0] = AT_RAID0;
378136849Sscottl	cap->MaximumArrayMembers[0] = MAX_MEMBERS;
379136849Sscottl	/* Mirror */
380136849Sscottl	cap->SupportedRAIDTypes[1] = AT_RAID1;
381136849Sscottl	cap->MaximumArrayMembers[1] = 2;
382136849Sscottl	/* Mirror + Stripe */
383136849Sscottl#ifdef ARRAY_V2_ONLY
384136849Sscottl	cap->SupportedRAIDTypes[2] = (AT_RAID1<<4)|AT_RAID0; /* RAID0/1 */
385149871Sscottl#else
386136849Sscottl	cap->SupportedRAIDTypes[2] = (AT_RAID0<<4)|AT_RAID1; /* RAID1/0 */
387136849Sscottl#endif
388136849Sscottl	cap->MaximumArrayMembers[2] = MAX_MEMBERS;
389136849Sscottl	/* Jbod */
390136849Sscottl	cap->SupportedRAIDTypes[3] = AT_JBOD;
391136849Sscottl	cap->MaximumArrayMembers[3] = MAX_MEMBERS;
392136849Sscottl	/* RAID5 */
393136849Sscottl#if SUPPORT_RAID5
394136849Sscottl	cap->SupportedRAIDTypes[4] = AT_RAID5;
395136849Sscottl	cap->MaximumArrayMembers[4] = MAX_MEMBERS;
396136849Sscottl#endif
397136849Sscottl#endif
398136849Sscottl	return 0;
399136849Sscottl}
400136849Sscottl
401149871Sscottlint hpt_get_controller_count(void)
402136849Sscottl{
403136849Sscottl	IAL_ADAPTER_T    *pAdapTemp = gIal_Adapter;
404136849Sscottl	int iControllerCount = 0;
405136849Sscottl
406136849Sscottl	while(pAdapTemp != 0)
407136849Sscottl	{
408136849Sscottl		iControllerCount++;
409136849Sscottl		pAdapTemp = pAdapTemp->next;
410136849Sscottl	}
411136849Sscottl
412136849Sscottl	return iControllerCount;
413136849Sscottl}
414136849Sscottl
415149871Sscottlint hpt_get_controller_info(int id, PCONTROLLER_INFO pInfo)
416136849Sscottl{
417136849Sscottl	IAL_ADAPTER_T    *pAdapTemp;
418136849Sscottl	int iControllerCount = 0;
419136849Sscottl
420136849Sscottl	for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) {
421136849Sscottl		if (iControllerCount++==id) {
422136849Sscottl			pInfo->InterruptLevel = 0;
423136849Sscottl			pInfo->ChipType = 0;
424136849Sscottl			pInfo->ChipFlags = CHIP_SUPPORT_ULTRA_100;
425136849Sscottl			strcpy( pInfo->szVendorID, "HighPoint Technologies, Inc.");
426136849Sscottl#ifdef GUI_CONTROLLER_NAME
427136849Sscottl#ifdef FORCE_ATA150_DISPLAY
428136849Sscottl			/* show "Bus Type: ATA/150" in GUI for SATA controllers */
429136849Sscottl			pInfo->ChipFlags = CHIP_SUPPORT_ULTRA_150;
430136849Sscottl#endif
431136849Sscottl			strcpy(pInfo->szProductID, GUI_CONTROLLER_NAME);
432136849Sscottl#define _set_product_id(x)
433149871Sscottl#else
434136849Sscottl#define _set_product_id(x) strcpy(pInfo->szProductID, x)
435136849Sscottl#endif
436190809Sdelphij			_set_product_id("RocketRAID 18xx SATA Controller");
437136849Sscottl			pInfo->NumBuses = 8;
438136849Sscottl			pInfo->ChipFlags |= CHIP_SUPPORT_ULTRA_133|CHIP_SUPPORT_ULTRA_150;
439136849Sscottl			return 0;
440136849Sscottl		}
441136849Sscottl	}
442136849Sscottl	return -1;
443136849Sscottl}
444136849Sscottl
445136849Sscottl
446149871Sscottlint hpt_get_channel_info(int id, int bus, PCHANNEL_INFO pInfo)
447136849Sscottl{
448136849Sscottl	IAL_ADAPTER_T    *pAdapTemp = gIal_Adapter;
449136849Sscottl	int i,iControllerCount = 0;
450136849Sscottl
451136849Sscottl	while(pAdapTemp != 0)
452136849Sscottl	{
453136849Sscottl		if (iControllerCount++==id)
454136849Sscottl			goto found;
455136849Sscottl		pAdapTemp = pAdapTemp->next;
456136849Sscottl	}
457136849Sscottl	return -1;
458136849Sscottl
459136849Sscottlfound:
460136849Sscottl
461136849Sscottl	pInfo->IoPort = 0;
462136849Sscottl	pInfo->ControlPort = 0;
463136849Sscottl
464136849Sscottl	for (i=0; i<2 ;i++)
465136849Sscottl	{
466136849Sscottl		pInfo->Devices[i] = (DEVICEID)INVALID_DEVICEID;
467136849Sscottl	}
468136849Sscottl
469136849Sscottl	if (pAdapTemp->mvChannel[bus].online == MV_TRUE)
470136849Sscottl		pInfo->Devices[0] = VDEV_TO_ID(&pAdapTemp->VDevices[bus]);
471136849Sscottl	else
472136849Sscottl		pInfo->Devices[0] = (DEVICEID)INVALID_DEVICEID;
473136849Sscottl
474136849Sscottl	return 0;
475136849Sscottl
476136849Sscottl
477136849Sscottl}
478136849Sscottl
479149871Sscottlint hpt_get_logical_devices(DEVICEID * pIds, int nMaxCount)
480136849Sscottl{
481136849Sscottl	int count = 0;
482136849Sscottl	int	i,j;
483136849Sscottl	PVDevice pPhysical, pLogical;
484136849Sscottl	IAL_ADAPTER_T    *pAdapTemp;
485136849Sscottl
486136849Sscottl	for(i = 0; i < nMaxCount; i++)
487136849Sscottl		pIds[i] = INVALID_DEVICEID;
488136849Sscottl
489136849Sscottl	/* append the arrays not registered on VBus */
490136849Sscottl	for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next) {
491136849Sscottl		for(i = 0; i < MV_SATA_CHANNELS_NUM; i++)
492136849Sscottl		{
493136849Sscottl			pPhysical = &pAdapTemp->VDevices[i];
494136849Sscottl			pLogical = pPhysical;
495136849Sscottl
496136849Sscottl			while (pLogical->pParent) pLogical = pLogical->pParent;
497136849Sscottl			if (pLogical->VDeviceType==VD_SPARE)
498136849Sscottl				continue;
499136849Sscottl
500136849Sscottl			for (j=0; j<count; j++)
501136849Sscottl				if (pIds[j]==VDEV_TO_ID(pLogical)) goto next;
502136849Sscottl			pIds[count++] = VDEV_TO_ID(pLogical);
503136849Sscottl			if (count>=nMaxCount) goto done;
504136849Sscottl			next:;
505136849Sscottl		}
506136849Sscottl	}
507136849Sscottl
508136849Sscottldone:
509136849Sscottl	return count;
510136849Sscottl}
511136849Sscottl
512149871Sscottlint hpt_get_device_info(DEVICEID id, PLOGICAL_DEVICE_INFO pInfo)
513136849Sscottl{
514136849Sscottl	PVDevice pVDevice = ID_TO_VDEV(id);
515136849Sscottl
516149871Sscottl	if((id == 0) || check_VDevice_valid(pVDevice))
517136849Sscottl		return -1;
518136849Sscottl
519136849Sscottl#ifdef SUPPORT_ARRAY
520190809Sdelphij	if (mIsArray(pVDevice)) {
521190809Sdelphij		pInfo->Type = LDT_ARRAY;
522190809Sdelphij		pInfo->Capacity = pVDevice->VDeviceCapacity;
523190809Sdelphij		pInfo->ParentArray = VDEV_TO_ID(pVDevice->pParent);
524190809Sdelphij		get_array_info(pVDevice, &pInfo->u.array);
525190809Sdelphij		return 0;
526190809Sdelphij	}
527136849Sscottl#endif
528136849Sscottl
529190809Sdelphij	pInfo->Type = LDT_DEVICE;
530190809Sdelphij	pInfo->ParentArray = pVDevice->pParent? VDEV_TO_ID(pVDevice->pParent) : INVALID_DEVICEID;
531190809Sdelphij	/* report real capacity to be compatible with old arrays */
532190809Sdelphij	pInfo->Capacity = pVDevice->u.disk.dDeRealCapacity;
533190809Sdelphij	return get_disk_info(pVDevice, &pInfo->u.device);
534190809Sdelphij}
535190809Sdelphij
536190809Sdelphijint hpt_get_device_info_v2(DEVICEID id, PLOGICAL_DEVICE_INFO_V2 pInfo)
537190809Sdelphij{
538190809Sdelphij	PVDevice pVDevice = ID_TO_VDEV(id);
539190809Sdelphij
540190809Sdelphij	if((id == 0) || check_VDevice_valid(pVDevice))
541190809Sdelphij		return -1;
542190809Sdelphij
543190809Sdelphij#ifdef SUPPORT_ARRAY
544190809Sdelphij	if (mIsArray(pVDevice)) {
545190809Sdelphij		pInfo->Type = LDT_ARRAY;
546190809Sdelphij		pInfo->Capacity.lo32 = pVDevice->VDeviceCapacity;
547190809Sdelphij		pInfo->Capacity.hi32 = sizeof(LBA_T)>4? (pVDevice->VDeviceCapacity>>32) : 0;
548190809Sdelphij		pInfo->ParentArray = VDEV_TO_ID(pVDevice->pParent);
549190809Sdelphij		get_array_info_v2(pVDevice, &pInfo->u.array);
550136849Sscottl	return 0;
551136849Sscottl}
552190809Sdelphij#endif
553136849Sscottl
554190809Sdelphij	pInfo->Type = LDT_DEVICE;
555190809Sdelphij	pInfo->ParentArray = pVDevice->pParent? VDEV_TO_ID(pVDevice->pParent) : INVALID_DEVICEID;
556190809Sdelphij	/* report real capacity to be compatible with old arrays */
557190809Sdelphij	pInfo->Capacity.lo32 = pVDevice->u.disk.dDeRealCapacity;
558190809Sdelphij	pInfo->Capacity.hi32 = 0;
559190809Sdelphij	return get_disk_info(pVDevice, &pInfo->u.device);
560190809Sdelphij}
561190809Sdelphij
562136849Sscottl#ifdef SUPPORT_ARRAY
563190809SdelphijDEVICEID hpt_create_array_v2(_VBUS_ARG PCREATE_ARRAY_PARAMS_V2 pParam)
564136849Sscottl{
565136849Sscottl	ULONG Stamp = GetStamp();
566136849Sscottl	int	i,j;
567190809Sdelphij	LBA_T  capacity = MAX_LBA_T;
568136849Sscottl	PVDevice pArray,pChild;
569136849Sscottl	int		Loca = -1;
570136849Sscottl
571190809Sdelphij	if (pParam->nDisk > MAX_MEMBERS)
572190809Sdelphij		return INVALID_DEVICEID;
573190809Sdelphij/* check in verify_vd
574136849Sscottl	for(i = 0; i < pParam->nDisk; i++)
575136849Sscottl	{
576136849Sscottl		PVDevice pVDev = ID_TO_VDEV(pParam->Members[i]);
577136849Sscottl		if (check_VDevice_valid(pVDev)) return INVALID_DEVICEID;
578136849Sscottl		if (mIsArray(pVDev)) return INVALID_DEVICEID;
579136849Sscottl		if (!pVDev->vf_online) return INVALID_DEVICEID;
580136849Sscottl		if (!_vbus_p)
581136849Sscottl			_vbus_p = pVDev->u.disk.pVBus;
582136849Sscottl		else if (_vbus_p != pVDev->u.disk.pVBus)
583136849Sscottl			return INVALID_DEVICEID;
584136849Sscottl	}
585190809Sdelphij*/
586190809Sdelphij	_vbus_p = (ID_TO_VDEV(pParam->Members[0]))->u.disk.pVBus;
587136849Sscottl	if (!_vbus_p) return INVALID_DEVICEID;
588136849Sscottl
589136849Sscottl	mArGetArrayTable(pArray);
590136849Sscottl	if(!pArray)	return INVALID_DEVICEID;
591136849Sscottl
592136849Sscottl	switch (pParam->ArrayType)
593136849Sscottl	{
594136849Sscottl		case AT_JBOD:
595136849Sscottl			pArray->VDeviceType = VD_JBOD;
596136849Sscottl			goto simple;
597136849Sscottl
598136849Sscottl		case AT_RAID0:
599136849Sscottl			if((pParam->BlockSizeShift < MinBlockSizeShift) || (pParam->BlockSizeShift > MaxBlockSizeShift))
600136849Sscottl				goto error;
601136849Sscottl			pArray->VDeviceType = VD_RAID_0;
602136849Sscottl			goto simple;
603136849Sscottl
604136849Sscottl		case AT_RAID5:
605136849Sscottl			if((pParam->BlockSizeShift < MinBlockSizeShift) || (pParam->BlockSizeShift > MaxBlockSizeShift))
606136849Sscottl				goto error;
607136849Sscottl			pArray->VDeviceType = VD_RAID_5;
608136849Sscottl			/* only "no build" R5 is not critical after creation. */
609136849Sscottl			if ((pParam->CreateFlags & CAF_CREATE_R5_NO_BUILD)==0)
610136849Sscottl				pArray->u.array.rf_need_rebuild = 1;
611136849Sscottl			goto simple;
612136849Sscottl
613136849Sscottl		case AT_RAID1:
614136849Sscottl			if(pParam->nDisk <= 2)
615136849Sscottl			{
616136849Sscottl				pArray->VDeviceType = VD_RAID_1;
617136849Sscottlsimple:
618136849Sscottl				pArray->u.array.bArnMember = pParam->nDisk;
619136849Sscottl				pArray->u.array.bArRealnMember = pParam->nDisk;
620136849Sscottl				pArray->u.array.bArBlockSizeShift = pParam->BlockSizeShift;
621136849Sscottl				pArray->u.array.bStripeWitch = (1 << pParam->BlockSizeShift);
622136849Sscottl				pArray->u.array.dArStamp = Stamp;
623136849Sscottl
624136849Sscottl				pArray->u.array.rf_need_sync = 1;
625136849Sscottl				pArray->u.array.rf_newly_created = 1;
626136849Sscottl
627136849Sscottl				if ((pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE) &&
628136849Sscottl					(pArray->VDeviceType == VD_RAID_1))
629136849Sscottl				{
630136849Sscottl					pArray->u.array.rf_newly_created = 0; /* R1 shall still be accessible */
631136849Sscottl					pArray->u.array.rf_need_rebuild = 1;
632136849Sscottl					pArray->u.array.rf_auto_rebuild = 1;
633136849Sscottl					pArray->u.array.rf_duplicate_and_create = 1;
634136849Sscottl
635136849Sscottl					for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
636136849Sscottl						if (_vbus_p->pVDevice[i] == ID_TO_VDEV(pParam->Members[0]))
637136849Sscottl							Loca = i;
638136849Sscottl				}
639136849Sscottl
640136849Sscottl				pArray->u.array.RebuildSectors = pArray->u.array.rf_need_rebuild? 0 : MAX_LBA_T;
641136849Sscottl
642136849Sscottl				memcpy(pArray->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME);
643136849Sscottl
644136849Sscottl				for(i = 0; i < pParam->nDisk; i++)
645136849Sscottl				{
646136849Sscottl					pArray->u.array.pMember[i] = ID_TO_VDEV(pParam->Members[i]);
647136849Sscottl					pArray->u.array.pMember[i]->bSerialNumber = i;
648136849Sscottl					pArray->u.array.pMember[i]->pParent = pArray;
649136849Sscottl
650136849Sscottl					/* don't unregister source disk for duplicate RAID1 */
651136849Sscottl					if (i ||
652136849Sscottl						pArray->VDeviceType!=VD_RAID_1 ||
653136849Sscottl						(pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE)==0)
654136849Sscottl						UnregisterVDevice(pArray->u.array.pMember[i]);
655136849Sscottl
656136849Sscottl					if(pArray->VDeviceType == VD_RAID_5)
657136849Sscottl						pArray->u.array.pMember[i]->vf_cache_disk = 1;
658136849Sscottl				}
659136849Sscottl			}
660136849Sscottl			else
661136849Sscottl			{
662136849Sscottl				for(i = 0; i < (pParam->nDisk / 2); i++)
663136849Sscottl				{
664136849Sscottl					mArGetArrayTable(pChild);
665136849Sscottl					pChild->VDeviceType = VD_RAID_1;
666136849Sscottl
667136849Sscottl					pChild->u.array.bArnMember = 2;
668136849Sscottl					pChild->u.array.bArRealnMember = 2;
669136849Sscottl					pChild->u.array.bArBlockSizeShift = pParam->BlockSizeShift;
670136849Sscottl					pChild->u.array.bStripeWitch = (1 << pParam->BlockSizeShift);
671136849Sscottl					pChild->u.array.dArStamp = Stamp;
672136849Sscottl
673136849Sscottl					pChild->u.array.rf_need_sync = 1;
674136849Sscottl					pChild->u.array.rf_newly_created = 1;
675136849Sscottl
676136849Sscottl					pChild->u.array.RebuildSectors = MAX_LBA_T;
677136849Sscottl
678136849Sscottl					memcpy(pChild->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME);
679136849Sscottl
680136849Sscottl					for(j = 0; j < 2; j++)
681136849Sscottl					{
682136849Sscottl						pChild->u.array.pMember[j] = ID_TO_VDEV(pParam->Members[i*2 + j]);
683136849Sscottl						pChild->u.array.pMember[j]->bSerialNumber = j;
684136849Sscottl						pChild->u.array.pMember[j]->pParent = pChild;
685136849Sscottl						pChild->u.array.pMember[j]->pfnDeviceFailed = pfnDeviceFailed[pChild->VDeviceType];
686136849Sscottl						UnregisterVDevice(pChild->u.array.pMember[j]);
687136849Sscottl					}
688136849Sscottl
689136849Sscottl					pArray->u.array.pMember[i] = pChild;
690136849Sscottl
691136849Sscottl					pChild->vf_online = 1;
692136849Sscottl					pChild->bSerialNumber = i;
693136849Sscottl					pChild->pParent = pArray;
694136849Sscottl					pChild->VDeviceCapacity = MIN(pChild->u.array.pMember[0]->VDeviceCapacity,
695136849Sscottl						pChild->u.array.pMember[1]->VDeviceCapacity);
696136849Sscottl
697136849Sscottl					pChild->pfnSendCommand = pfnSendCommand[pChild->VDeviceType];
698136849Sscottl					pChild->pfnDeviceFailed = pfnDeviceFailed[VD_RAID_0];
699136849Sscottl				}
700136849Sscottl
701136849Sscottl				pArray->VDeviceType = VD_RAID_0;
702136849Sscottl
703136849Sscottl				pArray->u.array.bArnMember = pParam->nDisk / 2;
704136849Sscottl				pArray->u.array.bArRealnMember = pParam->nDisk / 2;
705136849Sscottl				pArray->u.array.bArBlockSizeShift = pParam->BlockSizeShift;
706136849Sscottl				pArray->u.array.bStripeWitch = (1 << pParam->BlockSizeShift);
707136849Sscottl				pArray->u.array.dArStamp = Stamp;
708136849Sscottl
709136849Sscottl				pArray->u.array.rf_need_sync = 1;
710136849Sscottl				pArray->u.array.rf_newly_created = 1;
711136849Sscottl
712136849Sscottl				memcpy(pArray->u.array.ArrayName, pParam->ArrayName, MAX_ARRAY_NAME);
713136849Sscottl			}
714136849Sscottl			break;
715136849Sscottl
716136849Sscottl		default:
717136849Sscottl			goto error;
718136849Sscottl	}
719136849Sscottl
720136849Sscottl	for(i = 0; i < pArray->u.array.bArnMember; i++)
721136849Sscottl		pArray->u.array.pMember[i]->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType];
722136849Sscottl
723136849Sscottl	if ((pParam->CreateFlags & CAF_CREATE_AND_DUPLICATE) &&
724136849Sscottl		(pArray->VDeviceType == VD_RAID_1))
725136849Sscottl	{
726136849Sscottl		pArray->vf_bootmark = pArray->u.array.pMember[0]->vf_bootmark;
727136849Sscottl		pArray->vf_bootable = pArray->u.array.pMember[0]->vf_bootable;
728136849Sscottl		pArray->u.array.pMember[0]->vf_bootable = 0;
729136849Sscottl		pArray->u.array.pMember[0]->vf_bootmark = 0;
730136849Sscottl		if (Loca>=0) {
731136849Sscottl			_vbus_p->pVDevice[Loca] = pArray;
732136849Sscottl			/* to comfort OS */
733136849Sscottl			pArray->u.array.rf_duplicate_and_created = 1;
734136849Sscottl			pArray->pVBus = _vbus_p;
735136849Sscottl		}
736136849Sscottl	}
737136849Sscottl	else {
738136849Sscottl		UCHAR TempBuffer[512];
739136849Sscottl		ZeroMemory(TempBuffer, 512);
740136849Sscottl		for(i = 0; i < pParam->nDisk; i++)
741136849Sscottl		{
742136849Sscottl			PVDevice	pDisk = ID_TO_VDEV(pParam->Members[i]);
743136849Sscottl			pDisk->vf_bootmark = pDisk->vf_bootable = 0;
744136849Sscottl			fDeReadWrite(&pDisk->u.disk, 0, IDE_COMMAND_WRITE, TempBuffer);
745136849Sscottl		}
746136849Sscottl	}
747136849Sscottl
748136849Sscottl	pArray->vf_online = 1;
749136849Sscottl	pArray->pParent = NULL;
750136849Sscottl
751136849Sscottl	switch(pArray->VDeviceType)
752136849Sscottl	{
753136849Sscottl		case VD_RAID_0:
754136849Sscottl			for(i = 0; i < pArray->u.array.bArnMember; i++)
755136849Sscottl				if(pArray->u.array.pMember[i]->VDeviceCapacity < capacity)
756136849Sscottl					capacity = pArray->u.array.pMember[i]->VDeviceCapacity;
757136849Sscottl#ifdef ARRAY_V2_ONLY
758136849Sscottl			capacity -= 10;
759136849Sscottl#endif
760136849Sscottl			capacity &= ~(pArray->u.array.bStripeWitch - 1);
761136849Sscottl			/* shrink member capacity for RAID 1/0 */
762136849Sscottl			for(i = 0; i < pArray->u.array.bArnMember; i++)
763136849Sscottl				if (mIsArray(pArray->u.array.pMember[i]))
764136849Sscottl					pArray->u.array.pMember[i]->VDeviceCapacity = capacity;
765136849Sscottl			pArray->VDeviceCapacity = capacity * pArray->u.array.bArnMember;
766136849Sscottl			break;
767136849Sscottl
768136849Sscottl		case VD_RAID_1:
769136849Sscottl			pArray->VDeviceCapacity = MIN(pArray->u.array.pMember[0]->VDeviceCapacity,
770136849Sscottl						pArray->u.array.pMember[1]->VDeviceCapacity);
771136849Sscottl			break;
772136849Sscottl
773136849Sscottl		case VD_JBOD:
774136849Sscottl			for(i = 0; i < pArray->u.array.bArnMember; i++)
775136849Sscottl				pArray->VDeviceCapacity += pArray->u.array.pMember[i]->VDeviceCapacity
776136849Sscottl#ifdef ARRAY_V2_ONLY
777136849Sscottl				-10
778136849Sscottl#endif
779136849Sscottl				;
780136849Sscottl			break;
781136849Sscottl
782136849Sscottl		case VD_RAID_5:
783136849Sscottl			for(i = 0; i < pArray->u.array.bArnMember; i++)
784136849Sscottl				if(pArray->u.array.pMember[i]->VDeviceCapacity < capacity)
785136849Sscottl					capacity = pArray->u.array.pMember[i]->VDeviceCapacity;
786136849Sscottl			pArray->VDeviceCapacity = (capacity & ~(pArray->u.array.bStripeWitch - 1))
787136849Sscottl				* (pArray->u.array.bArnMember - 1);
788136849Sscottl			break;
789136849Sscottl
790136849Sscottl		default:
791136849Sscottl			goto error;
792136849Sscottl	}
793136849Sscottl
794136849Sscottl	pArray->pfnSendCommand = pfnSendCommand[pArray->VDeviceType];
795136849Sscottl	pArray->pfnDeviceFailed = fOsDiskFailed;
796136849Sscottl	SyncArrayInfo(pArray);
797136849Sscottl
798136849Sscottl	if (!pArray->u.array.rf_duplicate_and_created)
799136849Sscottl		RegisterVDevice(pArray);
800136849Sscottl	return VDEV_TO_ID(pArray);
801136849Sscottl
802136849Sscottlerror:
803136849Sscottl	for(i = 0; i < pArray->u.array.bArnMember; i++)
804136849Sscottl	{
805136849Sscottl		pChild = pArray->u.array.pMember[i];
806136849Sscottl		if((pChild != NULL) && (pChild->VDeviceType != VD_SINGLE_DISK))
807136849Sscottl			mArFreeArrayTable(pChild);
808136849Sscottl	}
809136849Sscottl	mArFreeArrayTable(pArray);
810136849Sscottl	return INVALID_DEVICEID;
811136849Sscottl}
812136849Sscottl
813190809SdelphijDEVICEID hpt_create_array(_VBUS_ARG PCREATE_ARRAY_PARAMS pParam)
814190809Sdelphij{
815190809Sdelphij	CREATE_ARRAY_PARAMS_V2 param2;
816190809Sdelphij	param2.ArrayType = pParam->ArrayType;
817190809Sdelphij	param2.nDisk = pParam->nDisk;
818190809Sdelphij	param2.BlockSizeShift = pParam->BlockSizeShift;
819190809Sdelphij	param2.CreateFlags = pParam->CreateFlags;
820190809Sdelphij	param2.CreateTime = pParam->CreateTime;
821190809Sdelphij	memcpy(param2.ArrayName, pParam->ArrayName, sizeof(param2.ArrayName));
822190809Sdelphij	memcpy(param2.Description, pParam->Description, sizeof(param2.Description));
823190809Sdelphij	memcpy(param2.CreateManager, pParam->CreateManager, sizeof(param2.CreateManager));
824190809Sdelphij	param2.Capacity.lo32 = param2.Capacity.hi32 = 0;
825190809Sdelphij	memcpy(param2.Members, pParam->Members, sizeof(pParam->Members));
826190809Sdelphij	return hpt_create_array_v2(_VBUS_P &param2);
827190809Sdelphij}
828190809Sdelphij
829136849Sscottl#ifdef SUPPORT_OLD_ARRAY
830136849Sscottl/* this is only for old RAID 0/1 */
831136849Sscottlint old_add_disk_to_raid01(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk)
832136849Sscottl{
833136849Sscottl	PVDevice pArray1 = ID_TO_VDEV(idArray);
834136849Sscottl	PVDevice pArray2 = 0;
835136849Sscottl	PVDevice pDisk	= ID_TO_VDEV(idDisk);
836136849Sscottl	int	i;
837136849Sscottl	IAL_ADAPTER_T *pAdapter = gIal_Adapter;
838136849Sscottl
839136849Sscottl	if (pArray1->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
840136849Sscottl
841136849Sscottl	if(pDisk->u.disk.dDeRealCapacity < (pArray1->VDeviceCapacity / 2))
842136849Sscottl		return -1;
843136849Sscottl
844136849Sscottl	pArray2 = pArray1->u.array.pMember[1];
845136849Sscottl	if(pArray2 == NULL)	{
846136849Sscottl		/* create a Stripe */
847136849Sscottl		mArGetArrayTable(pArray2);
848136849Sscottl		pArray2->VDeviceType = VD_RAID_0;
849136849Sscottl		pArray2->u.array.dArStamp = GetStamp();
850136849Sscottl		pArray2->vf_format_v2 = 1;
851136849Sscottl		pArray2->u.array.rf_broken = 1;
852136849Sscottl		pArray2->u.array.bArBlockSizeShift = pArray1->u.array.bArBlockSizeShift;
853136849Sscottl		pArray2->u.array.bStripeWitch = (1 << pArray2->u.array.bArBlockSizeShift);
854136849Sscottl		pArray2->u.array.bArnMember = 2;
855136849Sscottl		pArray2->VDeviceCapacity = pArray1->VDeviceCapacity;
856136849Sscottl		pArray2->pfnSendCommand = pfnSendCommand[pArray2->VDeviceType];
857136849Sscottl		pArray2->pfnDeviceFailed = pfnDeviceFailed[pArray1->VDeviceType];
858136849Sscottl		memcpy(pArray2->u.array.ArrayName, pArray1->u.array.ArrayName, MAX_ARRAY_NAME);
859136849Sscottl		pArray2->pParent = pArray1;
860136849Sscottl		pArray2->bSerialNumber = 1;
861136849Sscottl		pArray1->u.array.pMember[1] = pArray2;
862136849Sscottl		pArray1->u.array.bArRealnMember++;
863136849Sscottl	}
864136849Sscottl
865136849Sscottl	for(i = 0; i < pArray2->u.array.bArnMember; i++)
866136849Sscottl		if((pArray2->u.array.pMember[i] == NULL) || !pArray2->u.array.pMember[i]->vf_online)
867136849Sscottl		{
868136849Sscottl			if(pArray2->u.array.pMember[i] != NULL)
869136849Sscottl				pArray2->u.array.pMember[i]->pParent = NULL;
870136849Sscottl			pArray2->u.array.pMember[i] = pDisk;
871136849Sscottl			goto find;
872136849Sscottl		}
873136849Sscottl	return -1;
874136849Sscottl
875136849Sscottlfind:
876136849Sscottl	UnregisterVDevice(pDisk);
877136849Sscottl	pDisk->VDeviceType = VD_SINGLE_DISK;
878136849Sscottl	pDisk->bSerialNumber = i;
879136849Sscottl	pDisk->pParent = pArray2;
880136849Sscottl	pDisk->vf_format_v2 = 1;
881136849Sscottl	pDisk->u.disk.dDeHiddenLba = i? 10 : 0;
882136849Sscottl	pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity;
883136849Sscottl	pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray2->VDeviceType];
884136849Sscottl
885136849Sscottl	pArray2->u.array.bArRealnMember++;
886136849Sscottl	if(pArray2->u.array.bArnMember == pArray2->u.array.bArRealnMember){
887136849Sscottl		pArray2->vf_online = 1;
888136849Sscottl		pArray2->u.array.rf_broken = 0;
889136849Sscottl	}
890136849Sscottl
891136849Sscottl	if(pArray1->u.array.pMember[0]->vf_online && pArray1->u.array.pMember[1]->vf_online){
892136849Sscottl		pArray1->u.array.bArRealnMember = pArray1->u.array.bArnMember;
893136849Sscottl		pArray1->u.array.rf_broken = 0;
894136849Sscottl		pArray1->u.array.rf_need_rebuild = 1;
895136849Sscottl		pArray1->u.array.rf_auto_rebuild = 1;
896136849Sscottl
897136849Sscottl	}
898136849Sscottl	pArray1->u.array.RebuildSectors = 0;
899136849Sscottl	pArray1->u.array.dArStamp = GetStamp();
900136849Sscottl	SyncArrayInfo(pArray1);
901136849Sscottl	return 1;
902136849Sscottl}
903136849Sscottl#endif
904136849Sscottl
905136849Sscottlint hpt_add_disk_to_array(_VBUS_ARG DEVICEID idArray, DEVICEID idDisk)
906136849Sscottl{
907136849Sscottl	int	i;
908136849Sscottl
909190809Sdelphij	LBA_T Capacity;
910136849Sscottl	PVDevice pArray = ID_TO_VDEV(idArray);
911136849Sscottl	PVDevice pDisk	= ID_TO_VDEV(idDisk);
912136849Sscottl
913149871Sscottl	if((idArray == 0) || (idDisk == 0))	return -1;
914136849Sscottl	if(check_VDevice_valid(pArray) || check_VDevice_valid(pDisk))	return -1;
915136849Sscottl	if(!pArray->u.array.rf_broken)	return -1;
916136849Sscottl
917136849Sscottl	if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5)
918136849Sscottl		return -1;
919136849Sscottl	if((pDisk->VDeviceType != VD_SINGLE_DISK) && (pDisk->VDeviceType != VD_SPARE))
920136849Sscottl		return -1;
921136849Sscottl
922136849Sscottl#ifdef SUPPORT_OLD_ARRAY
923136849Sscottl	/* RAID 0 + 1 */
924136849Sscottl	if (pArray->vf_format_v2 && pArray->VDeviceType==VD_RAID_1 &&
925136849Sscottl		pArray->u.array.pMember[0] &&
926136849Sscottl		mIsArray(pArray->u.array.pMember[0]))
927136849Sscottl	{
928136849Sscottl		if(old_add_disk_to_raid01(_VBUS_P idArray, idDisk))
929136849Sscottl			return 0;
930136849Sscottl		else
931136849Sscottl			return -1;
932136849Sscottl	}
933136849Sscottl#endif
934136849Sscottl
935136849Sscottl	Capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember - 1);
936136849Sscottl
937136849Sscottl	if (pArray->vf_format_v2) {
938136849Sscottl		if(pDisk->u.disk.dDeRealCapacity < Capacity) return -1;
939136849Sscottl	}
940136849Sscottl	else
941136849Sscottl		if(pDisk->VDeviceCapacity < Capacity) return -1;
942136849Sscottl
943136849Sscottl	if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
944136849Sscottl
945136849Sscottl	for(i = 0; i < pArray->u.array.bArnMember; i++)
946190809Sdelphij		if((pArray->u.array.pMember[i] == 0) || !pArray->u.array.pMember[i]->vf_online)
947136849Sscottl		{
948136849Sscottl			if(pArray->u.array.pMember[i] != NULL)
949136849Sscottl				pArray->u.array.pMember[i]->pParent = NULL;
950136849Sscottl			pArray->u.array.pMember[i] = pDisk;
951136849Sscottl			goto find;
952136849Sscottl		}
953136849Sscottl	return -1;
954136849Sscottl
955136849Sscottlfind:
956136849Sscottl	UnregisterVDevice(pDisk);
957136849Sscottl	pDisk->VDeviceType = VD_SINGLE_DISK;
958136849Sscottl	pDisk->bSerialNumber = i;
959136849Sscottl	pDisk->pParent = pArray;
960136849Sscottl	if (pArray->VDeviceType==VD_RAID_5) pDisk->vf_cache_disk = 1;
961136849Sscottl	pDisk->pfnDeviceFailed = pfnDeviceFailed[pArray->VDeviceType];
962136849Sscottl	if (pArray->vf_format_v2) {
963136849Sscottl		pDisk->vf_format_v2 = 1;
964136849Sscottl		pDisk->VDeviceCapacity = pDisk->u.disk.dDeRealCapacity;
965136849Sscottl	}
966136849Sscottl
967136849Sscottl	pArray->u.array.bArRealnMember++;
968136849Sscottl	if(pArray->u.array.bArnMember == pArray->u.array.bArRealnMember)
969136849Sscottl	{
970136849Sscottl		pArray->u.array.rf_need_rebuild = 1;
971136849Sscottl		pArray->u.array.RebuildSectors = 0;
972136849Sscottl		pArray->u.array.rf_auto_rebuild = 1;
973136849Sscottl		pArray->u.array.rf_broken = 0;
974136849Sscottl	}
975136849Sscottl	pArray->u.array.RebuildSectors = 0;
976136849Sscottl
977136849Sscottl	/* sync the whole array */
978136849Sscottl	while (pArray->pParent) pArray = pArray->pParent;
979136849Sscottl	pArray->u.array.dArStamp = GetStamp();
980136849Sscottl	SyncArrayInfo(pArray);
981136849Sscottl	return 0;
982136849Sscottl}
983136849Sscottl
984149871Sscottlint hpt_add_spare_disk(_VBUS_ARG DEVICEID idDisk)
985136849Sscottl{
986136849Sscottl	PVDevice pVDevice = ID_TO_VDEV(idDisk);
987136849Sscottl	DECLARE_BUFFER(PUCHAR, pbuffer);
988136849Sscottl
989149871Sscottl	if(idDisk == 0 || check_VDevice_valid(pVDevice))	return -1;
990136849Sscottl	if (pVDevice->VDeviceType != VD_SINGLE_DISK || pVDevice->pParent)
991136849Sscottl		return -1;
992136849Sscottl
993136849Sscottl	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
994136849Sscottl
995136849Sscottl	UnregisterVDevice(pVDevice);
996136849Sscottl	pVDevice->VDeviceType = VD_SPARE;
997136849Sscottl	pVDevice->vf_bootmark = 0;
998136849Sscottl
999136849Sscottl	ZeroMemory((char *)pbuffer, 512);
1000136849Sscottl	fDeReadWrite(&pVDevice->u.disk, 0, IDE_COMMAND_WRITE, pbuffer);
1001136849Sscottl	SyncArrayInfo(pVDevice);
1002136849Sscottl	return 0;
1003136849Sscottl}
1004136849Sscottl
1005149871Sscottlint hpt_remove_spare_disk(_VBUS_ARG DEVICEID idDisk)
1006136849Sscottl{
1007136849Sscottl	PVDevice pVDevice = ID_TO_VDEV(idDisk);
1008136849Sscottl
1009136849Sscottl	if(idDisk == 0 || check_VDevice_valid(pVDevice))	return -1;
1010136849Sscottl
1011136849Sscottl	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
1012136849Sscottl
1013136849Sscottl	pVDevice->VDeviceType = VD_SINGLE_DISK;
1014136849Sscottl
1015136849Sscottl	SyncArrayInfo(pVDevice);
1016136849Sscottl	RegisterVDevice(pVDevice);
1017136849Sscottl	return 0;
1018136849Sscottl}
1019136849Sscottl
1020149871Sscottlint hpt_set_array_info(_VBUS_ARG DEVICEID idArray, PALTERABLE_ARRAY_INFO pInfo)
1021136849Sscottl{
1022136849Sscottl	PVDevice pVDevice = ID_TO_VDEV(idArray);
1023136849Sscottl
1024149871Sscottl	if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1;
1025136849Sscottl	if (!mIsArray(pVDevice)) return -1;
1026136849Sscottl
1027136849Sscottl	/* if the pVDevice isn't a top level, return -1; */
1028136849Sscottl	if(pVDevice->pParent != NULL) return -1;
1029136849Sscottl
1030136849Sscottl	if (pVDevice->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
1031136849Sscottl
1032136849Sscottl	if (pInfo->ValidFields & AAIF_NAME) {
1033136849Sscottl		memset(pVDevice->u.array.ArrayName, 0, MAX_ARRAY_NAME);
1034136849Sscottl		memcpy(pVDevice->u.array.ArrayName, pInfo->Name, sizeof(pInfo->Name));
1035136849Sscottl		pVDevice->u.array.rf_need_sync = 1;
1036136849Sscottl	}
1037136849Sscottl
1038136849Sscottl	if (pInfo->ValidFields & AAIF_DESCRIPTION) {
1039136849Sscottl		memcpy(pVDevice->u.array.Description, pInfo->Description, sizeof(pInfo->Description));
1040136849Sscottl		pVDevice->u.array.rf_need_sync = 1;
1041136849Sscottl	}
1042136849Sscottl
1043136849Sscottl	if (pVDevice->u.array.rf_need_sync)
1044136849Sscottl		SyncArrayInfo(pVDevice);
1045136849Sscottl	return 0;
1046136849Sscottl}
1047136849Sscottl
1048190809Sdelphijstatic int hpt_set_device_info(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO pInfo)
1049136849Sscottl{
1050136849Sscottl	PVDevice pVDevice = ID_TO_VDEV(idDisk);
1051136849Sscottl
1052190809Sdelphij	if(idDisk == 0 || check_VDevice_valid(pVDevice)) return -1;
1053190809Sdelphij	if (mIsArray(pVDevice))
1054190809Sdelphij		return -1;
1055190809Sdelphij
1056190809Sdelphij	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
1057190809Sdelphij
1058190809Sdelphij	/* TODO */
1059136849Sscottl		return 0;
1060136849Sscottl	}
1061136849Sscottl
1062190809Sdelphijstatic int hpt_set_device_info_v2(_VBUS_ARG DEVICEID idDisk, PALTERABLE_DEVICE_INFO_V2 pInfo)
1063190809Sdelphij{
1064190809Sdelphij	PVDevice pVDevice = ID_TO_VDEV(idDisk);
1065190809Sdelphij	int sync = 0;
1066190809Sdelphij
1067190809Sdelphij	if(idDisk==0 || check_VDevice_valid(pVDevice)) return -1;
1068136849Sscottl	if (mIsArray(pVDevice))
1069136849Sscottl		return -1;
1070136849Sscottl
1071136849Sscottl	if (pVDevice->u.disk.pVBus!=_vbus_p) return -1;
1072136849Sscottl
1073190809Sdelphij	if (pInfo->ValidFields & ADIF_MODE) {
1074136849Sscottl		pVDevice->u.disk.bDeModeSetting = pInfo->DeviceModeSetting;
1075136849Sscottl		pVDevice->u.disk.bDeUserSelectMode = pInfo->DeviceModeSetting;
1076136849Sscottl		pVDevice->u.disk.df_user_mode_set = 1;
1077136849Sscottl		fDeSelectMode((PDevice)&(pVDevice->u.disk), (UCHAR)pInfo->DeviceModeSetting);
1078190809Sdelphij		sync = 1;
1079136849Sscottl}
1080136849Sscottl
1081190809Sdelphij	if (pInfo->ValidFields & ADIF_TCQ) {
1082190809Sdelphij		if (fDeSetTCQ(&pVDevice->u.disk, pInfo->TCQEnabled, 0)) {
1083190809Sdelphij			pVDevice->u.disk.df_tcq_set = 1;
1084190809Sdelphij			pVDevice->u.disk.df_tcq = pInfo->TCQEnabled!=0;
1085190809Sdelphij			sync = 1;
1086136849Sscottl}
1087136849Sscottl	}
1088136849Sscottl
1089190809Sdelphij	if (pInfo->ValidFields & ADIF_NCQ) {
1090190809Sdelphij		if (fDeSetNCQ(&pVDevice->u.disk, pInfo->NCQEnabled, 0)) {
1091190809Sdelphij			pVDevice->u.disk.df_ncq_set = 1;
1092190809Sdelphij			pVDevice->u.disk.df_ncq = pInfo->NCQEnabled!=0;
1093190809Sdelphij			sync = 1;
1094136849Sscottl	}
1095136849Sscottl	}
1096136849Sscottl
1097190809Sdelphij	if (pInfo->ValidFields & ADIF_WRITE_CACHE) {
1098190809Sdelphij		if (fDeSetWriteCache(&pVDevice->u.disk, pInfo->WriteCacheEnabled)) {
1099190809Sdelphij			pVDevice->u.disk.df_write_cache_set = 1;
1100190809Sdelphij			pVDevice->u.disk.df_write_cache = pInfo->WriteCacheEnabled!=0;
1101190809Sdelphij			sync = 1;
1102136849Sscottl	}
1103136849Sscottl	}
1104136849Sscottl
1105190809Sdelphij	if (pInfo->ValidFields & ADIF_READ_AHEAD) {
1106190809Sdelphij		if (fDeSetReadAhead(&pVDevice->u.disk, pInfo->ReadAheadEnabled)) {
1107190809Sdelphij			pVDevice->u.disk.df_read_ahead_set = 1;
1108190809Sdelphij			pVDevice->u.disk.df_read_ahead = pInfo->ReadAheadEnabled!=0;
1109190809Sdelphij			sync = 1;
1110190809Sdelphij		}
1111190809Sdelphij	}
1112136849Sscottl
1113190809Sdelphij	if (sync)
1114190809Sdelphij		SyncArrayInfo(pVDevice);
1115136849Sscottl	return 0;
1116136849Sscottl}
1117190809Sdelphij
1118136849Sscottl#endif
1119136849Sscottl
1120136849Sscottl/* hpt_default_ioctl()
1121136849Sscottl *  This is a default implementation. The platform dependent part
1122136849Sscottl *  may reuse this function and/or use it own implementation for
1123136849Sscottl *  each ioctl function.
1124136849Sscottl */
1125136849Sscottlint hpt_default_ioctl(_VBUS_ARG
1126136849Sscottl							DWORD dwIoControlCode,       	/* operation control code */
1127136849Sscottl							PVOID lpInBuffer,            	/* input data buffer */
1128136849Sscottl							DWORD nInBufferSize,         	/* size of input data buffer */
1129136849Sscottl							PVOID lpOutBuffer,           	/* output data buffer */
1130136849Sscottl							DWORD nOutBufferSize,        	/* size of output data buffer */
1131136849Sscottl							PDWORD lpBytesReturned      	/* byte count */
1132136849Sscottl					)
1133136849Sscottl{
1134136849Sscottl	switch(dwIoControlCode)	{
1135136849Sscottl
1136136849Sscottl	case HPT_IOCTL_GET_VERSION:
1137136849Sscottl
1138136849Sscottl		if (nInBufferSize != 0) return -1;
1139136849Sscottl		if (nOutBufferSize != sizeof(DWORD)) return -1;
1140136849Sscottl		*((DWORD*)lpOutBuffer) = HPT_INTERFACE_VERSION;
1141136849Sscottl		break;
1142136849Sscottl
1143136849Sscottl	case HPT_IOCTL_GET_CONTROLLER_COUNT:
1144136849Sscottl
1145136849Sscottl		if (nOutBufferSize!=sizeof(DWORD)) return -1;
1146136849Sscottl		*(PDWORD)lpOutBuffer = hpt_get_controller_count();
1147136849Sscottl		break;
1148136849Sscottl
1149136849Sscottl	case HPT_IOCTL_GET_CONTROLLER_INFO:
1150136849Sscottl		{
1151136849Sscottl			int id;
1152136849Sscottl			PCONTROLLER_INFO pInfo;
1153136849Sscottl
1154136849Sscottl			if (nInBufferSize!=sizeof(DWORD)) return -1;
1155136849Sscottl			if (nOutBufferSize!=sizeof(CONTROLLER_INFO)) return -1;
1156136849Sscottl
1157136849Sscottl			id = *(DWORD *)lpInBuffer;
1158136849Sscottl			pInfo = (PCONTROLLER_INFO)lpOutBuffer;
1159136849Sscottl			if (hpt_get_controller_info(id, pInfo)!=0)
1160136849Sscottl				return -1;
1161136849Sscottl		}
1162136849Sscottl		break;
1163136849Sscottl
1164136849Sscottl	case HPT_IOCTL_GET_CHANNEL_INFO:
1165136849Sscottl		{
1166136849Sscottl			int id, bus;
1167136849Sscottl			PCHANNEL_INFO pInfo;
1168136849Sscottl
1169136849Sscottl			if (nInBufferSize!=8) return -1;
1170136849Sscottl			if (nOutBufferSize!=sizeof(CHANNEL_INFO)) return -1;
1171136849Sscottl
1172136849Sscottl			id = *(DWORD *)lpInBuffer;
1173136849Sscottl			bus = ((DWORD *)lpInBuffer)[1];
1174136849Sscottl			pInfo = (PCHANNEL_INFO)lpOutBuffer;
1175136849Sscottl
1176136849Sscottl			if (hpt_get_channel_info(id, bus, pInfo)!=0)
1177136849Sscottl				return -1;
1178136849Sscottl		}
1179136849Sscottl		break;
1180136849Sscottl
1181136849Sscottl	case HPT_IOCTL_GET_LOGICAL_DEVICES:
1182136849Sscottl		{
1183136849Sscottl			DWORD nMax;
1184136849Sscottl			DEVICEID *pIds;
1185136849Sscottl
1186136849Sscottl			if (nInBufferSize!=sizeof(DWORD)) return -1;
1187136849Sscottl			nMax = *(DWORD *)lpInBuffer;
1188136849Sscottl			if (nOutBufferSize < sizeof(DWORD)+sizeof(DWORD)*nMax) return -1;
1189136849Sscottl
1190136849Sscottl			pIds = ((DEVICEID *)lpOutBuffer)+1;
1191136849Sscottl			*(DWORD*)lpOutBuffer = hpt_get_logical_devices(pIds, nMax);
1192136849Sscottl		}
1193136849Sscottl		break;
1194136849Sscottl
1195136849Sscottl	case HPT_IOCTL_GET_DEVICE_INFO:
1196136849Sscottl		{
1197136849Sscottl			DEVICEID id;
1198136849Sscottl			PLOGICAL_DEVICE_INFO pInfo;
1199136849Sscottl
1200136849Sscottl			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1201136849Sscottl			if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO)) return -1;
1202136849Sscottl
1203136849Sscottl			id = *(DWORD *)lpInBuffer;
1204136849Sscottl			if (id == INVALID_DEVICEID)	return -1;
1205136849Sscottl
1206136849Sscottl			pInfo = (PLOGICAL_DEVICE_INFO)lpOutBuffer;
1207136849Sscottl			memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO));
1208136849Sscottl
1209136849Sscottl			if (hpt_get_device_info(id, pInfo)!=0)
1210136849Sscottl				return -1;
1211136849Sscottl		}
1212136849Sscottl		break;
1213136849Sscottl
1214190809Sdelphij	case HPT_IOCTL_GET_DEVICE_INFO_V2:
1215190809Sdelphij		{
1216190809Sdelphij			DEVICEID id;
1217190809Sdelphij			PLOGICAL_DEVICE_INFO_V2 pInfo;
1218190809Sdelphij
1219190809Sdelphij			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1220190809Sdelphij			if (nOutBufferSize!=sizeof(LOGICAL_DEVICE_INFO_V2)) return -1;
1221190809Sdelphij
1222190809Sdelphij			id = *(DWORD *)lpInBuffer;
1223190809Sdelphij			if (id == INVALID_DEVICEID)	return -1;
1224190809Sdelphij
1225190809Sdelphij			pInfo = (PLOGICAL_DEVICE_INFO_V2)lpOutBuffer;
1226190809Sdelphij			memset(pInfo, 0, sizeof(LOGICAL_DEVICE_INFO_V2));
1227190809Sdelphij
1228190809Sdelphij			if (hpt_get_device_info_v2(id, pInfo)!=0)
1229190809Sdelphij				return -1;
1230190809Sdelphij		}
1231190809Sdelphij		break;
1232190809Sdelphij
1233136849Sscottl#ifdef SUPPORT_ARRAY
1234136849Sscottl	case HPT_IOCTL_CREATE_ARRAY:
1235136849Sscottl		{
1236136849Sscottl			if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS)) return -1;
1237136849Sscottl			if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
1238136849Sscottl
1239190809Sdelphij			*(DEVICEID *)lpOutBuffer = hpt_create_array(_VBUS_P (PCREATE_ARRAY_PARAMS)lpInBuffer);
1240136849Sscottl
1241190809Sdelphij			if(*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
1242190809Sdelphij				return -1;
1243190809Sdelphij		}
1244190809Sdelphij		break;
1245136849Sscottl
1246190809Sdelphij	case HPT_IOCTL_CREATE_ARRAY_V2:
1247190809Sdelphij		{
1248190809Sdelphij			if (nInBufferSize!=sizeof(CREATE_ARRAY_PARAMS_V2)) return -1;
1249190809Sdelphij			if (nOutBufferSize!=sizeof(DEVICEID)) return -1;
1250190809Sdelphij
1251190809Sdelphij			*(DEVICEID *)lpOutBuffer = hpt_create_array_v2(_VBUS_P (PCREATE_ARRAY_PARAMS_V2)lpInBuffer);
1252190809Sdelphij
1253190809Sdelphij			if (*(DEVICEID *)lpOutBuffer == INVALID_DEVICEID)
1254136849Sscottl				return -1;
1255136849Sscottl		}
1256136849Sscottl		break;
1257136849Sscottl
1258136849Sscottl	case HPT_IOCTL_SET_ARRAY_INFO:
1259136849Sscottl		{
1260136849Sscottl			DEVICEID idArray;
1261136849Sscottl			PALTERABLE_ARRAY_INFO pInfo;
1262136849Sscottl
1263136849Sscottl			if (nInBufferSize!=sizeof(HPT_SET_ARRAY_INFO)) return -1;
1264136849Sscottl			if (nOutBufferSize!=0) return -1;
1265136849Sscottl
1266136849Sscottl			idArray = ((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray;
1267136849Sscottl			pInfo = &((PHPT_SET_ARRAY_INFO)lpInBuffer)->Info;
1268136849Sscottl
1269136849Sscottl			if(hpt_set_array_info(_VBUS_P idArray,  pInfo))
1270136849Sscottl				return -1;
1271136849Sscottl		}
1272136849Sscottl		break;
1273136849Sscottl
1274136849Sscottl	case HPT_IOCTL_SET_DEVICE_INFO:
1275136849Sscottl		{
1276136849Sscottl			DEVICEID idDisk;
1277136849Sscottl			PALTERABLE_DEVICE_INFO pInfo;
1278136849Sscottl
1279136849Sscottl			if (nInBufferSize!=sizeof(HPT_SET_DEVICE_INFO)) return -1;
1280136849Sscottl			if (nOutBufferSize!=0) return -1;
1281136849Sscottl
1282136849Sscottl			idDisk = ((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk;
1283136849Sscottl			pInfo = &((PHPT_SET_DEVICE_INFO)lpInBuffer)->Info;
1284136849Sscottl			if(hpt_set_device_info(_VBUS_P idDisk, pInfo) != 0)
1285136849Sscottl				return -1;
1286136849Sscottl		}
1287136849Sscottl		break;
1288136849Sscottl
1289190809Sdelphij	case HPT_IOCTL_SET_DEVICE_INFO_V2:
1290190809Sdelphij		{
1291190809Sdelphij			DEVICEID idDisk;
1292190809Sdelphij			PALTERABLE_DEVICE_INFO_V2 pInfo;
1293190809Sdelphij
1294190809Sdelphij			if (nInBufferSize < sizeof(HPT_SET_DEVICE_INFO_V2)) return -1;
1295190809Sdelphij			if (nOutBufferSize!=0) return -1;
1296190809Sdelphij
1297190809Sdelphij			idDisk = ((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk;
1298190809Sdelphij			pInfo = &((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->Info;
1299190809Sdelphij			if(hpt_set_device_info_v2(_VBUS_P idDisk, pInfo) != 0)
1300190809Sdelphij				return -1;
1301190809Sdelphij		}
1302190809Sdelphij		break;
1303190809Sdelphij
1304136849Sscottl	case HPT_IOCTL_SET_BOOT_MARK:
1305136849Sscottl		{
1306136849Sscottl			DEVICEID id;
1307136849Sscottl			PVDevice pTop;
1308136849Sscottl			int i;
1309136849Sscottl			IAL_ADAPTER_T *pAdapter = gIal_Adapter;
1310136849Sscottl			PVBus pVBus;
1311136849Sscottl
1312136849Sscottl			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1313136849Sscottl			id = *(DEVICEID *)lpInBuffer;
1314136849Sscottl			while(pAdapter != 0)
1315136849Sscottl			{
1316136849Sscottl				pVBus = &pAdapter->VBus;
1317190809Sdelphij				for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
1318136849Sscottl				{
1319136849Sscottl					if(!(pTop = pVBus->pVDevice[i])) continue;
1320136849Sscottl					if (pTop->pVBus!=_vbus_p) return -1;
1321136849Sscottl					while (pTop->pParent) pTop = pTop->pParent;
1322136849Sscottl					if (id==0 && pTop->vf_bootmark)
1323136849Sscottl						pTop->vf_bootmark = 0;
1324136849Sscottl					else if (pTop==ID_TO_VDEV(id) && !pTop->vf_bootmark)
1325136849Sscottl						pTop->vf_bootmark = 1;
1326136849Sscottl					else
1327136849Sscottl						continue;
1328136849Sscottl					SyncArrayInfo(pTop);
1329136849Sscottl					break;
1330136849Sscottl				}
1331136849Sscottl				pAdapter = pAdapter->next;
1332136849Sscottl			}
1333136849Sscottl		}
1334136849Sscottl		break;
1335136849Sscottl
1336136849Sscottl	case HPT_IOCTL_ADD_SPARE_DISK:
1337136849Sscottl		{
1338136849Sscottl			DEVICEID id;
1339136849Sscottl
1340136849Sscottl			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1341136849Sscottl			if (nOutBufferSize!=0) return -1;
1342136849Sscottl
1343136849Sscottl			id = *(DEVICEID *)lpInBuffer;
1344136849Sscottl
1345136849Sscottl			if(hpt_add_spare_disk(_VBUS_P id))
1346136849Sscottl				return -1;
1347136849Sscottl		}
1348136849Sscottl		break;
1349136849Sscottl
1350136849Sscottl	case HPT_IOCTL_REMOVE_SPARE_DISK:
1351136849Sscottl		{
1352136849Sscottl			DEVICEID id;
1353136849Sscottl
1354136849Sscottl			if (nInBufferSize!=sizeof(DEVICEID)) return -1;
1355136849Sscottl			if (nOutBufferSize!=0) return -1;
1356136849Sscottl
1357136849Sscottl			id = *(DEVICEID *)lpInBuffer;
1358136849Sscottl
1359136849Sscottl			if(hpt_remove_spare_disk(_VBUS_P id))
1360136849Sscottl				return -1;
1361136849Sscottl		}
1362136849Sscottl		break;
1363136849Sscottl
1364136849Sscottl	case HPT_IOCTL_ADD_DISK_TO_ARRAY:
1365136849Sscottl		{
1366136849Sscottl			DEVICEID id1,id2;
1367136849Sscottl			id1 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray;
1368136849Sscottl			id2 = ((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idDisk;
1369136849Sscottl
1370136849Sscottl			if (nInBufferSize != sizeof(HPT_ADD_DISK_TO_ARRAY)) return -1;
1371136849Sscottl			if (nOutBufferSize != 0) return -1;
1372136849Sscottl
1373136849Sscottl			if(hpt_add_disk_to_array(_VBUS_P id1, id2))
1374136849Sscottl				return -1;
1375136849Sscottl		}
1376136849Sscottl		break;
1377136849Sscottl#endif
1378136849Sscottl	case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
1379136849Sscottl		{
1380136849Sscottl			PDRIVER_CAPABILITIES cap;
1381136849Sscottl			if (nOutBufferSize<sizeof(DRIVER_CAPABILITIES)) return -1;
1382136849Sscottl			cap = (PDRIVER_CAPABILITIES)lpOutBuffer;
1383136849Sscottl
1384136849Sscottl			if(hpt_get_driver_capabilities(cap))
1385136849Sscottl				return -1;
1386136849Sscottl		}
1387136849Sscottl		break;
1388136849Sscottl
1389190809Sdelphij	case HPT_IOCTL_GET_CONTROLLER_VENID:
1390136849Sscottl		{
1391190809Sdelphij			DWORD id = ((DWORD*)lpInBuffer)[0];
1392190809Sdelphij			IAL_ADAPTER_T *pAdapTemp;
1393190809Sdelphij			int iControllerCount = 0;
1394136849Sscottl
1395190809Sdelphij			for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
1396190809Sdelphij				if (iControllerCount++==id)
1397190809Sdelphij					break;
1398190809Sdelphij
1399190809Sdelphij			if (!pAdapTemp)
1400136849Sscottl				return -1;
1401190809Sdelphij
1402190809Sdelphij			if (nOutBufferSize < 4)
1403190809Sdelphij				return -1;
1404190809Sdelphij
1405190809Sdelphij			*(DWORD*)lpOutBuffer = ((DWORD)pAdapTemp->mvSataAdapter.pciConfigDeviceId << 16) | 0x11AB;
1406190809Sdelphij			return 0;
1407136849Sscottl		}
1408136849Sscottl
1409190809Sdelphij	case HPT_IOCTL_EPROM_IO:
1410136849Sscottl		{
1411190809Sdelphij			DWORD id           = ((DWORD*)lpInBuffer)[0];
1412190809Sdelphij			DWORD offset	   = ((DWORD*)lpInBuffer)[1];
1413190809Sdelphij			DWORD direction    = ((DWORD*)lpInBuffer)[2];
1414190809Sdelphij			DWORD length	   = ((DWORD*)lpInBuffer)[3];
1415190809Sdelphij			IAL_ADAPTER_T *pAdapTemp;
1416190809Sdelphij			int iControllerCount = 0;
1417136849Sscottl
1418190809Sdelphij			for (pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next)
1419190809Sdelphij				if (iControllerCount++==id)
1420190809Sdelphij					break;
1421190809Sdelphij
1422190809Sdelphij			if (!pAdapTemp)
1423190809Sdelphij				return -1;
1424190809Sdelphij
1425190809Sdelphij			if (nInBufferSize < sizeof(DWORD) * 4 + (direction? length : 0) ||
1426190809Sdelphij				nOutBufferSize < (direction? 0 : length))
1427190809Sdelphij				return -1;
1428136849Sscottl
1429190809Sdelphij			if (direction == 0) /* read */
1430190809Sdelphij				sx508x_flash_access(&pAdapTemp->mvSataAdapter,
1431190809Sdelphij					offset, lpOutBuffer, length, 1);
1432190809Sdelphij			else
1433190809Sdelphij				sx508x_flash_access(&pAdapTemp->mvSataAdapter,
1434190809Sdelphij					offset, (char *)lpInBuffer + 16, length, 0);
1435190809Sdelphij
1436190809Sdelphij			return 0;
1437136849Sscottl		}
1438136849Sscottl		break;
1439190809Sdelphij
1440136849Sscottl	default:
1441136849Sscottl		return -1;
1442136849Sscottl	}
1443136849Sscottl
1444136849Sscottl	if (lpBytesReturned)
1445136849Sscottl		*lpBytesReturned = nOutBufferSize;
1446136849Sscottl	return 0;
1447136849Sscottl}
1448