xref: /titanic_51/usr/src/uts/common/io/aac/aac_ioctl.c (revision 3fced4392c3510db4e569c4f8188c45bb5b5f5d3)
1942c5e3cSpl196000 /*
2*3fced439Szhongyan gu - Sun Microsystems - Beijing China  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3942c5e3cSpl196000  */
4942c5e3cSpl196000 
5942c5e3cSpl196000 /*
6942c5e3cSpl196000  * Copyright 2005-06 Adaptec, Inc.
7942c5e3cSpl196000  * Copyright (c) 2005-06 Adaptec Inc., Achim Leubner
8942c5e3cSpl196000  * Copyright (c) 2000 Michael Smith
9942c5e3cSpl196000  * Copyright (c) 2001 Scott Long
10942c5e3cSpl196000  * Copyright (c) 2000 BSDi
11942c5e3cSpl196000  * All rights reserved.
12942c5e3cSpl196000  *
13942c5e3cSpl196000  * Redistribution and use in source and binary forms, with or without
14942c5e3cSpl196000  * modification, are permitted provided that the following conditions
15942c5e3cSpl196000  * are met:
16942c5e3cSpl196000  * 1. Redistributions of source code must retain the above copyright
17942c5e3cSpl196000  *    notice, this list of conditions and the following disclaimer.
18942c5e3cSpl196000  * 2. Redistributions in binary form must reproduce the above copyright
19942c5e3cSpl196000  *    notice, this list of conditions and the following disclaimer in the
20942c5e3cSpl196000  *    documentation and/or other materials provided with the distribution.
21942c5e3cSpl196000  *
22942c5e3cSpl196000  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23942c5e3cSpl196000  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24942c5e3cSpl196000  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25942c5e3cSpl196000  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26942c5e3cSpl196000  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27942c5e3cSpl196000  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28942c5e3cSpl196000  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29942c5e3cSpl196000  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30942c5e3cSpl196000  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31942c5e3cSpl196000  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32942c5e3cSpl196000  * SUCH DAMAGE.
33942c5e3cSpl196000  */
34942c5e3cSpl196000 #include <sys/modctl.h>
35942c5e3cSpl196000 #include <sys/conf.h>
36942c5e3cSpl196000 #include <sys/cmn_err.h>
37942c5e3cSpl196000 #include <sys/ddi.h>
38942c5e3cSpl196000 #include <sys/devops.h>
39942c5e3cSpl196000 #include <sys/pci.h>
40942c5e3cSpl196000 #include <sys/types.h>
41942c5e3cSpl196000 #include <sys/ddidmareq.h>
42942c5e3cSpl196000 #include <sys/scsi/scsi.h>
43942c5e3cSpl196000 #include <sys/ksynch.h>
44942c5e3cSpl196000 #include <sys/sunddi.h>
45942c5e3cSpl196000 #include <sys/byteorder.h>
46942c5e3cSpl196000 #include <sys/kmem.h>
47942c5e3cSpl196000 #include "aac_regs.h"
48942c5e3cSpl196000 #include "aac.h"
49942c5e3cSpl196000 #include "aac_ioctl.h"
50942c5e3cSpl196000 
51942c5e3cSpl196000 struct aac_umem_sge {
52942c5e3cSpl196000 	uint32_t bcount;
53942c5e3cSpl196000 	caddr_t addr;
54942c5e3cSpl196000 	struct aac_cmd acp;
55942c5e3cSpl196000 };
56942c5e3cSpl196000 
57942c5e3cSpl196000 /*
58942c5e3cSpl196000  * External functions
59942c5e3cSpl196000  */
60942c5e3cSpl196000 extern int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
61942c5e3cSpl196000     uint32_t, uint32_t, uint32_t, uint32_t *);
62942c5e3cSpl196000 extern int aac_cmd_dma_alloc(struct aac_softstate *, struct aac_cmd *,
63942c5e3cSpl196000     struct buf *, int, int (*)(), caddr_t);
64942c5e3cSpl196000 extern void aac_free_dmamap(struct aac_cmd *);
65942c5e3cSpl196000 extern int aac_do_io(struct aac_softstate *, struct aac_cmd *);
66942c5e3cSpl196000 extern void aac_cmd_fib_copy(struct aac_softstate *, struct aac_cmd *);
67942c5e3cSpl196000 extern void aac_ioctl_complete(struct aac_softstate *, struct aac_cmd *);
680749e8deSXin Chen - Sun Microsystems - Beijing China extern int aac_return_aif_wait(struct aac_softstate *, struct aac_fib_context *,
690749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **);
700749e8deSXin Chen - Sun Microsystems - Beijing China extern int aac_return_aif(struct aac_softstate *, struct aac_fib_context *,
710749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **);
72942c5e3cSpl196000 
73942c5e3cSpl196000 extern ddi_device_acc_attr_t aac_acc_attr;
74942c5e3cSpl196000 extern int aac_check_dma_handle(ddi_dma_handle_t);
75942c5e3cSpl196000 
76942c5e3cSpl196000 /*
77942c5e3cSpl196000  * IOCTL command handling functions
78942c5e3cSpl196000  */
79942c5e3cSpl196000 static int aac_check_revision(struct aac_softstate *, intptr_t, int);
80942c5e3cSpl196000 static int aac_ioctl_send_fib(struct aac_softstate *, intptr_t, int);
81942c5e3cSpl196000 static int aac_open_getadapter_fib(struct aac_softstate *, intptr_t, int);
82942c5e3cSpl196000 static int aac_next_getadapter_fib(struct aac_softstate *, intptr_t, int);
83942c5e3cSpl196000 static int aac_close_getadapter_fib(struct aac_softstate *, intptr_t);
84942c5e3cSpl196000 static int aac_send_raw_srb(struct aac_softstate *, dev_t, intptr_t, int);
85942c5e3cSpl196000 static int aac_get_pci_info(struct aac_softstate *, intptr_t, int);
86942c5e3cSpl196000 static int aac_query_disk(struct aac_softstate *, intptr_t, int);
87942c5e3cSpl196000 static int aac_delete_disk(struct aac_softstate *, intptr_t, int);
88942c5e3cSpl196000 static int aac_supported_features(struct aac_softstate *, intptr_t, int);
89942c5e3cSpl196000 
90942c5e3cSpl196000 /*
91942c5e3cSpl196000  * Warlock directives
92942c5e3cSpl196000  */
93942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("unique to each handling function", aac_features
94942c5e3cSpl196000     aac_pci_info aac_query_disk aac_revision aac_umem_sge))
95942c5e3cSpl196000 
96942c5e3cSpl196000 int
97942c5e3cSpl196000 aac_do_ioctl(struct aac_softstate *softs, dev_t dev, int cmd, intptr_t arg,
98942c5e3cSpl196000     int mode)
99942c5e3cSpl196000 {
100942c5e3cSpl196000 	int status;
101942c5e3cSpl196000 
102942c5e3cSpl196000 	switch (cmd) {
103942c5e3cSpl196000 	case FSACTL_MINIPORT_REV_CHECK:
104942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_MINIPORT_REV_CHECK");
105942c5e3cSpl196000 		status = aac_check_revision(softs, arg, mode);
106942c5e3cSpl196000 		break;
107942c5e3cSpl196000 	case FSACTL_SENDFIB:
108942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB");
109942c5e3cSpl196000 		goto send_fib;
110942c5e3cSpl196000 	case FSACTL_SEND_LARGE_FIB:
111942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB");
112942c5e3cSpl196000 send_fib:
113942c5e3cSpl196000 		status = aac_ioctl_send_fib(softs, arg, mode);
114942c5e3cSpl196000 		break;
115942c5e3cSpl196000 	case FSACTL_OPEN_GET_ADAPTER_FIB:
116942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_OPEN_GET_ADAPTER_FIB");
117942c5e3cSpl196000 		status = aac_open_getadapter_fib(softs, arg, mode);
118942c5e3cSpl196000 		break;
119942c5e3cSpl196000 	case FSACTL_GET_NEXT_ADAPTER_FIB:
120942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_GET_NEXT_ADAPTER_FIB");
121942c5e3cSpl196000 		status = aac_next_getadapter_fib(softs, arg, mode);
122942c5e3cSpl196000 		break;
123942c5e3cSpl196000 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
124942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_CLOSE_GET_ADAPTER_FIB");
125942c5e3cSpl196000 		status = aac_close_getadapter_fib(softs, arg);
126942c5e3cSpl196000 		break;
127942c5e3cSpl196000 	case FSACTL_SEND_RAW_SRB:
128942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_RAW_SRB");
129942c5e3cSpl196000 		status = aac_send_raw_srb(softs, dev, arg, mode);
130942c5e3cSpl196000 		break;
131942c5e3cSpl196000 	case FSACTL_GET_PCI_INFO:
132942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_GET_PCI_INFO");
133942c5e3cSpl196000 		status = aac_get_pci_info(softs, arg, mode);
134942c5e3cSpl196000 		break;
135942c5e3cSpl196000 	case FSACTL_QUERY_DISK:
136942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_QUERY_DISK");
137942c5e3cSpl196000 		status = aac_query_disk(softs, arg, mode);
138942c5e3cSpl196000 		break;
139942c5e3cSpl196000 	case FSACTL_DELETE_DISK:
140942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_DELETE_DISK");
141942c5e3cSpl196000 		status = aac_delete_disk(softs, arg, mode);
142942c5e3cSpl196000 		break;
143942c5e3cSpl196000 	case FSACTL_GET_FEATURES:
144942c5e3cSpl196000 		AACDB_PRINT_IOCTL(softs, "FSACTL_GET_FEATURES");
145942c5e3cSpl196000 		status = aac_supported_features(softs, arg, mode);
146942c5e3cSpl196000 		break;
147942c5e3cSpl196000 	default:
148942c5e3cSpl196000 		status = ENOTTY;
149942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
150942c5e3cSpl196000 		    "!IOCTL cmd 0x%x not supported", cmd);
151942c5e3cSpl196000 		break;
152942c5e3cSpl196000 	}
153942c5e3cSpl196000 
154942c5e3cSpl196000 	return (status);
155942c5e3cSpl196000 }
156942c5e3cSpl196000 
157942c5e3cSpl196000 /*ARGSUSED*/
158942c5e3cSpl196000 static int
159942c5e3cSpl196000 aac_check_revision(struct aac_softstate *softs, intptr_t arg, int mode)
160942c5e3cSpl196000 {
161942c5e3cSpl196000 	union aac_revision_align un;
162942c5e3cSpl196000 	struct aac_revision *aac_rev = &un.d;
163942c5e3cSpl196000 
164942c5e3cSpl196000 	DBCALLED(softs, 2);
165942c5e3cSpl196000 
166942c5e3cSpl196000 	/* Copyin the revision struct from userspace */
167942c5e3cSpl196000 	if (ddi_copyin((void *)arg, aac_rev,
168942c5e3cSpl196000 	    sizeof (struct aac_revision), mode) != 0)
169942c5e3cSpl196000 		return (EFAULT);
170942c5e3cSpl196000 
171942c5e3cSpl196000 	/* Doctor up the response struct */
172942c5e3cSpl196000 	aac_rev->compat = 1;
173942c5e3cSpl196000 	aac_rev->version =
174942c5e3cSpl196000 	    ((uint32_t)AAC_DRIVER_MAJOR_VERSION << 24) |
175942c5e3cSpl196000 	    ((uint32_t)AAC_DRIVER_MINOR_VERSION << 16) |
176942c5e3cSpl196000 	    ((uint32_t)AAC_DRIVER_TYPE << 8) |
177942c5e3cSpl196000 	    ((uint32_t)AAC_DRIVER_BUGFIX_LEVEL);
178942c5e3cSpl196000 	aac_rev->build = (uint32_t)AAC_DRIVER_BUILD;
179942c5e3cSpl196000 
180942c5e3cSpl196000 	if (ddi_copyout(aac_rev, (void *)arg,
181942c5e3cSpl196000 	    sizeof (struct aac_revision), mode) != 0)
182942c5e3cSpl196000 		return (EFAULT);
183942c5e3cSpl196000 
184942c5e3cSpl196000 	return (0);
185942c5e3cSpl196000 }
186942c5e3cSpl196000 
187942c5e3cSpl196000 static int
188942c5e3cSpl196000 aac_send_fib(struct aac_softstate *softs, struct aac_cmd *acp)
189942c5e3cSpl196000 {
190942c5e3cSpl196000 	int rval;
191942c5e3cSpl196000 
192942c5e3cSpl196000 	acp->flags |= AAC_CMD_NO_CB | AAC_CMD_SYNC;
193942c5e3cSpl196000 	acp->ac_comp = aac_ioctl_complete;
194942c5e3cSpl196000 
195942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
196942c5e3cSpl196000 	if (softs->state & AAC_STATE_DEAD) {
197942c5e3cSpl196000 		mutex_exit(&softs->io_lock);
198942c5e3cSpl196000 		return (ENXIO);
199942c5e3cSpl196000 	}
200942c5e3cSpl196000 
201942c5e3cSpl196000 	rval = aac_do_io(softs, acp);
202942c5e3cSpl196000 	if (rval == TRAN_ACCEPT) {
203942c5e3cSpl196000 		rval = 0;
204942c5e3cSpl196000 	} else if (rval == TRAN_BADPKT) {
205942c5e3cSpl196000 		AACDB_PRINT(softs, CE_CONT, "User SendFib failed ENXIO");
206942c5e3cSpl196000 		rval = ENXIO;
207942c5e3cSpl196000 	} else if (rval == TRAN_BUSY) {
208942c5e3cSpl196000 		AACDB_PRINT(softs, CE_CONT, "User SendFib failed EBUSY");
209942c5e3cSpl196000 		rval = EBUSY;
210942c5e3cSpl196000 	}
211942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
212942c5e3cSpl196000 
213942c5e3cSpl196000 	return (rval);
214942c5e3cSpl196000 }
215942c5e3cSpl196000 
216942c5e3cSpl196000 static int
217942c5e3cSpl196000 aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode)
218942c5e3cSpl196000 {
219942c5e3cSpl196000 	int hbalen;
220942c5e3cSpl196000 	struct aac_cmd *acp;
221942c5e3cSpl196000 	struct aac_fib *fibp;
222942c5e3cSpl196000 	uint16_t fib_command;
223942c5e3cSpl196000 	uint32_t fib_xfer_state;
224942c5e3cSpl196000 	uint16_t fib_data_size, fib_size;
225942c5e3cSpl196000 	uint16_t fib_sender_size;
226942c5e3cSpl196000 	int rval;
227942c5e3cSpl196000 
228942c5e3cSpl196000 	DBCALLED(softs, 2);
229942c5e3cSpl196000 
230942c5e3cSpl196000 	/* Copy in FIB header */
231942c5e3cSpl196000 	hbalen = sizeof (struct aac_cmd) + softs->aac_max_fib_size;
232942c5e3cSpl196000 	if ((acp = kmem_zalloc(hbalen, KM_NOSLEEP)) == NULL)
233942c5e3cSpl196000 		return (ENOMEM);
234942c5e3cSpl196000 
235942c5e3cSpl196000 	fibp = (struct aac_fib *)(acp + 1);
236942c5e3cSpl196000 	acp->fibp = fibp;
237942c5e3cSpl196000 	if (ddi_copyin((void *)arg, fibp,
238942c5e3cSpl196000 	    sizeof (struct aac_fib_header), mode) != 0) {
239942c5e3cSpl196000 		rval = EFAULT;
240942c5e3cSpl196000 		goto finish;
241942c5e3cSpl196000 	}
242942c5e3cSpl196000 
243942c5e3cSpl196000 	fib_xfer_state = LE_32(fibp->Header.XferState);
244942c5e3cSpl196000 	fib_command = LE_16(fibp->Header.Command);
245942c5e3cSpl196000 	fib_data_size = LE_16(fibp->Header.Size);
246942c5e3cSpl196000 	fib_sender_size = LE_16(fibp->Header.SenderSize);
247942c5e3cSpl196000 
248942c5e3cSpl196000 	fib_size = fib_data_size + sizeof (struct aac_fib_header);
249942c5e3cSpl196000 	if (fib_size < fib_sender_size)
250942c5e3cSpl196000 		fib_size = fib_sender_size;
251942c5e3cSpl196000 	if (fib_size > softs->aac_max_fib_size) {
252942c5e3cSpl196000 		rval = EFAULT;
253942c5e3cSpl196000 		goto finish;
254942c5e3cSpl196000 	}
255942c5e3cSpl196000 
256942c5e3cSpl196000 	/* Copy in FIB data */
257942c5e3cSpl196000 	if (ddi_copyin(((struct aac_fib *)arg)->data, fibp->data,
258942c5e3cSpl196000 	    fib_data_size, mode) != 0) {
259942c5e3cSpl196000 		rval = EFAULT;
260942c5e3cSpl196000 		goto finish;
261942c5e3cSpl196000 	}
262942c5e3cSpl196000 	acp->fib_size = fib_size;
263942c5e3cSpl196000 	fibp->Header.Size = LE_16(fib_size);
264942c5e3cSpl196000 
265942c5e3cSpl196000 	/* Process FIB */
266942c5e3cSpl196000 	if (fib_command == TakeABreakPt) {
26758bc78c7SXin Chen #ifdef DEBUG
26858bc78c7SXin Chen 		if (aac_dbflag_on(softs, AACDB_FLAGS_FIB) &&
26958bc78c7SXin Chen 		    (softs->debug_fib_flags & AACDB_FLAGS_FIB_IOCTL))
27058bc78c7SXin Chen 			aac_printf(softs, CE_NOTE, "FIB> TakeABreakPt, sz=%d",
27158bc78c7SXin Chen 			    fib_size);
27258bc78c7SXin Chen #endif
273942c5e3cSpl196000 		(void) aac_sync_mbcommand(softs, AAC_BREAKPOINT_REQ,
274942c5e3cSpl196000 		    0, 0, 0, 0, NULL);
275942c5e3cSpl196000 		fibp->Header.XferState = LE_32(0);
276942c5e3cSpl196000 	} else {
277942c5e3cSpl196000 		ASSERT(!(fib_xfer_state & AAC_FIBSTATE_ASYNC));
278942c5e3cSpl196000 		fibp->Header.XferState = LE_32(fib_xfer_state | \
279942c5e3cSpl196000 		    (AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED));
280942c5e3cSpl196000 
281942c5e3cSpl196000 		acp->timeout = AAC_IOCTL_TIMEOUT;
282942c5e3cSpl196000 		acp->aac_cmd_fib = aac_cmd_fib_copy;
28358bc78c7SXin Chen #ifdef DEBUG
28458bc78c7SXin Chen 		acp->fib_flags = AACDB_FLAGS_FIB_IOCTL;
28558bc78c7SXin Chen #endif
286942c5e3cSpl196000 		if ((rval = aac_send_fib(softs, acp)) != 0)
287942c5e3cSpl196000 			goto finish;
288942c5e3cSpl196000 	}
289942c5e3cSpl196000 
290942c5e3cSpl196000 	if (acp->flags & AAC_CMD_ERR) {
291942c5e3cSpl196000 		AACDB_PRINT(softs, CE_CONT, "FIB data corrupt");
292942c5e3cSpl196000 		rval = EIO;
293942c5e3cSpl196000 		goto finish;
294942c5e3cSpl196000 	}
295942c5e3cSpl196000 
296942c5e3cSpl196000 	if (ddi_copyout(fibp, (void *)arg, acp->fib_size, mode) != 0) {
297942c5e3cSpl196000 		AACDB_PRINT(softs, CE_CONT, "FIB copyout failed");
298942c5e3cSpl196000 		rval = EFAULT;
299942c5e3cSpl196000 		goto finish;
300942c5e3cSpl196000 	}
301942c5e3cSpl196000 
302942c5e3cSpl196000 	rval = 0;
303942c5e3cSpl196000 finish:
304942c5e3cSpl196000 	kmem_free(acp, hbalen);
305942c5e3cSpl196000 	return (rval);
306942c5e3cSpl196000 }
307942c5e3cSpl196000 
308942c5e3cSpl196000 static int
309942c5e3cSpl196000 aac_open_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
310942c5e3cSpl196000 {
3110749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib_context *fibctx_p, *ctx_p;
312942c5e3cSpl196000 
313942c5e3cSpl196000 	DBCALLED(softs, 2);
314942c5e3cSpl196000 
3150749e8deSXin Chen - Sun Microsystems - Beijing China 	fibctx_p = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP);
3160749e8deSXin Chen - Sun Microsystems - Beijing China 	if (fibctx_p == NULL)
317942c5e3cSpl196000 		return (ENOMEM);
318942c5e3cSpl196000 
319942c5e3cSpl196000 	mutex_enter(&softs->aifq_mutex);
320942c5e3cSpl196000 	/* All elements are already 0, add to queue */
3210749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->fibctx_p == NULL) {
3220749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->fibctx_p = fibctx_p;
323942c5e3cSpl196000 	} else {
3240749e8deSXin Chen - Sun Microsystems - Beijing China 		for (ctx_p = softs->fibctx_p; ctx_p->next; ctx_p = ctx_p->next)
325942c5e3cSpl196000 			;
3260749e8deSXin Chen - Sun Microsystems - Beijing China 		ctx_p->next = fibctx_p;
3270749e8deSXin Chen - Sun Microsystems - Beijing China 		fibctx_p->prev = ctx_p;
328942c5e3cSpl196000 	}
329942c5e3cSpl196000 
330942c5e3cSpl196000 	/* Evaluate unique value */
3310749e8deSXin Chen - Sun Microsystems - Beijing China 	fibctx_p->unique = (unsigned long)fibctx_p & 0xfffffffful;
3320749e8deSXin Chen - Sun Microsystems - Beijing China 	ctx_p = softs->fibctx_p;
3330749e8deSXin Chen - Sun Microsystems - Beijing China 	while (ctx_p != fibctx_p) {
3340749e8deSXin Chen - Sun Microsystems - Beijing China 		if (ctx_p->unique == fibctx_p->unique) {
3350749e8deSXin Chen - Sun Microsystems - Beijing China 			fibctx_p->unique++;
3360749e8deSXin Chen - Sun Microsystems - Beijing China 			ctx_p = softs->fibctx_p;
337942c5e3cSpl196000 		} else {
3380749e8deSXin Chen - Sun Microsystems - Beijing China 			ctx_p = ctx_p->next;
339942c5e3cSpl196000 		}
340942c5e3cSpl196000 	}
341942c5e3cSpl196000 
342942c5e3cSpl196000 	/* Set ctx_idx to the oldest AIF */
343942c5e3cSpl196000 	if (softs->aifq_wrap) {
3440749e8deSXin Chen - Sun Microsystems - Beijing China 		fibctx_p->ctx_idx = softs->aifq_idx;
3450749e8deSXin Chen - Sun Microsystems - Beijing China 		fibctx_p->ctx_filled = 1;
346942c5e3cSpl196000 	}
347942c5e3cSpl196000 	mutex_exit(&softs->aifq_mutex);
348942c5e3cSpl196000 
3490749e8deSXin Chen - Sun Microsystems - Beijing China 	if (ddi_copyout(&fibctx_p->unique, (void *)arg,
350942c5e3cSpl196000 	    sizeof (uint32_t), mode) != 0)
351942c5e3cSpl196000 		return (EFAULT);
352942c5e3cSpl196000 
353942c5e3cSpl196000 	return (0);
354942c5e3cSpl196000 }
355942c5e3cSpl196000 
356942c5e3cSpl196000 static int
357942c5e3cSpl196000 aac_next_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
358942c5e3cSpl196000 {
359942c5e3cSpl196000 	union aac_get_adapter_fib_align un;
360942c5e3cSpl196000 	struct aac_get_adapter_fib *af = &un.d;
3610749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib_context *ctx_p;
3620749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
363942c5e3cSpl196000 	int rval;
364942c5e3cSpl196000 
365942c5e3cSpl196000 	DBCALLED(softs, 2);
366942c5e3cSpl196000 
367942c5e3cSpl196000 	if (ddi_copyin((void *)arg, af, sizeof (*af), mode) != 0)
368942c5e3cSpl196000 		return (EFAULT);
369942c5e3cSpl196000 
370942c5e3cSpl196000 	mutex_enter(&softs->aifq_mutex);
3710749e8deSXin Chen - Sun Microsystems - Beijing China 	for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
3720749e8deSXin Chen - Sun Microsystems - Beijing China 		if (af->context == ctx_p->unique)
373942c5e3cSpl196000 			break;
374942c5e3cSpl196000 	}
375942c5e3cSpl196000 	mutex_exit(&softs->aifq_mutex);
376942c5e3cSpl196000 
3770749e8deSXin Chen - Sun Microsystems - Beijing China 	if (ctx_p) {
3780749e8deSXin Chen - Sun Microsystems - Beijing China 		if (af->wait)
3790749e8deSXin Chen - Sun Microsystems - Beijing China 			rval = aac_return_aif_wait(softs, ctx_p, &fibp);
3800749e8deSXin Chen - Sun Microsystems - Beijing China 		else
3810749e8deSXin Chen - Sun Microsystems - Beijing China 			rval = aac_return_aif(softs, ctx_p, &fibp);
3820749e8deSXin Chen - Sun Microsystems - Beijing China 	}
3830749e8deSXin Chen - Sun Microsystems - Beijing China 	else
3840749e8deSXin Chen - Sun Microsystems - Beijing China 		rval = EFAULT;
3850749e8deSXin Chen - Sun Microsystems - Beijing China 
3860749e8deSXin Chen - Sun Microsystems - Beijing China finish:
3870749e8deSXin Chen - Sun Microsystems - Beijing China 	if (rval == 0) {
3880749e8deSXin Chen - Sun Microsystems - Beijing China 		if (ddi_copyout(fibp,
3890749e8deSXin Chen - Sun Microsystems - Beijing China #ifdef _LP64
3900749e8deSXin Chen - Sun Microsystems - Beijing China 		    (void *)(uint64_t)af->aif_fib,
3910749e8deSXin Chen - Sun Microsystems - Beijing China #else
3920749e8deSXin Chen - Sun Microsystems - Beijing China 		    (void *)af->aif_fib,
3930749e8deSXin Chen - Sun Microsystems - Beijing China #endif
3940749e8deSXin Chen - Sun Microsystems - Beijing China 		    sizeof (struct aac_fib), mode) != 0)
3950749e8deSXin Chen - Sun Microsystems - Beijing China 			rval = EFAULT;
3960749e8deSXin Chen - Sun Microsystems - Beijing China 	}
397942c5e3cSpl196000 	return (rval);
398942c5e3cSpl196000 }
399942c5e3cSpl196000 
400942c5e3cSpl196000 static int
401942c5e3cSpl196000 aac_close_getadapter_fib(struct aac_softstate *softs, intptr_t arg)
402942c5e3cSpl196000 {
4030749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib_context *ctx_p;
404942c5e3cSpl196000 
405942c5e3cSpl196000 	DBCALLED(softs, 2);
406942c5e3cSpl196000 
407942c5e3cSpl196000 	mutex_enter(&softs->aifq_mutex);
4080749e8deSXin Chen - Sun Microsystems - Beijing China 	for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
4090749e8deSXin Chen - Sun Microsystems - Beijing China 		if (ctx_p->unique != (uint32_t)arg)
410942c5e3cSpl196000 			continue;
411942c5e3cSpl196000 
4120749e8deSXin Chen - Sun Microsystems - Beijing China 		if (ctx_p == softs->fibctx_p)
4130749e8deSXin Chen - Sun Microsystems - Beijing China 			softs->fibctx_p = ctx_p->next;
414942c5e3cSpl196000 		else
4150749e8deSXin Chen - Sun Microsystems - Beijing China 			ctx_p->prev->next = ctx_p->next;
4160749e8deSXin Chen - Sun Microsystems - Beijing China 		if (ctx_p->next)
4170749e8deSXin Chen - Sun Microsystems - Beijing China 			ctx_p->next->prev = ctx_p->prev;
418942c5e3cSpl196000 		break;
419942c5e3cSpl196000 	}
420942c5e3cSpl196000 	mutex_exit(&softs->aifq_mutex);
4210749e8deSXin Chen - Sun Microsystems - Beijing China 	if (ctx_p)
4220749e8deSXin Chen - Sun Microsystems - Beijing China 		kmem_free(ctx_p, sizeof (struct aac_fib_context));
423942c5e3cSpl196000 
424942c5e3cSpl196000 	return (0);
425942c5e3cSpl196000 }
426942c5e3cSpl196000 
427942c5e3cSpl196000 /*
428942c5e3cSpl196000  * The following function comes from Adaptec:
429942c5e3cSpl196000  *
430942c5e3cSpl196000  * SRB is required for the new management tools
431942c5e3cSpl196000  * Note: SRB passed down from IOCTL is always in CPU endianness.
432942c5e3cSpl196000  */
433942c5e3cSpl196000 static int
434942c5e3cSpl196000 aac_send_raw_srb(struct aac_softstate *softs, dev_t dev, intptr_t arg, int mode)
435942c5e3cSpl196000 {
436942c5e3cSpl196000 	struct aac_cmd *acp;
437942c5e3cSpl196000 	struct aac_fib *fibp;
438942c5e3cSpl196000 	struct aac_srb *srb;
439942c5e3cSpl196000 	uint32_t usr_fib_size;
440942c5e3cSpl196000 	uint32_t srb_sgcount;
441942c5e3cSpl196000 	struct aac_umem_sge *usgt = NULL;
442942c5e3cSpl196000 	struct aac_umem_sge *usge;
443942c5e3cSpl196000 	ddi_umem_cookie_t cookie;
444942c5e3cSpl196000 	int umem_flags = 0;
445942c5e3cSpl196000 	int direct = 0;
446942c5e3cSpl196000 	int locked = 0;
447942c5e3cSpl196000 	caddr_t addrlo = (caddr_t)-1;
448942c5e3cSpl196000 	caddr_t addrhi = 0;
449942c5e3cSpl196000 	struct aac_sge *sge, *sge0;
450942c5e3cSpl196000 	int sg64;
451942c5e3cSpl196000 	int rval;
452942c5e3cSpl196000 
453942c5e3cSpl196000 	DBCALLED(softs, 2);
454942c5e3cSpl196000 
455942c5e3cSpl196000 	/* Read srb size */
456942c5e3cSpl196000 	if (ddi_copyin(&((struct aac_srb *)arg)->count, &usr_fib_size,
457942c5e3cSpl196000 	    sizeof (uint32_t), mode) != 0)
458942c5e3cSpl196000 		return (EFAULT);
459942c5e3cSpl196000 	if (usr_fib_size > (softs->aac_max_fib_size - \
460942c5e3cSpl196000 	    sizeof (struct aac_fib_header)))
461942c5e3cSpl196000 		return (EINVAL);
462942c5e3cSpl196000 
463942c5e3cSpl196000 	if ((acp = kmem_zalloc(sizeof (struct aac_cmd) + usr_fib_size + \
464942c5e3cSpl196000 	    sizeof (struct aac_fib_header), KM_NOSLEEP)) == NULL)
465942c5e3cSpl196000 		return (ENOMEM);
466942c5e3cSpl196000 
467942c5e3cSpl196000 	acp->fibp = (struct aac_fib *)(acp + 1);
468942c5e3cSpl196000 	fibp = acp->fibp;
469942c5e3cSpl196000 	srb = (struct aac_srb *)fibp->data;
470942c5e3cSpl196000 
471942c5e3cSpl196000 	/* Copy in srb */
472942c5e3cSpl196000 	if (ddi_copyin((void *)arg, srb, usr_fib_size, mode) != 0) {
473942c5e3cSpl196000 		rval = EFAULT;
474942c5e3cSpl196000 		goto finish;
475942c5e3cSpl196000 	}
476942c5e3cSpl196000 
477942c5e3cSpl196000 	srb_sgcount = srb->sg.SgCount; /* No endianness conversion needed */
478942c5e3cSpl196000 	if (srb_sgcount == 0)
479942c5e3cSpl196000 		goto send_fib;
480942c5e3cSpl196000 
481942c5e3cSpl196000 	/* Check FIB size */
482942c5e3cSpl196000 	if (usr_fib_size == (sizeof (struct aac_srb) + \
483942c5e3cSpl196000 	    srb_sgcount * sizeof (struct aac_sg_entry64) - \
484942c5e3cSpl196000 	    sizeof (struct aac_sg_entry))) {
485942c5e3cSpl196000 		sg64 = 1;
486942c5e3cSpl196000 	} else if (usr_fib_size == (sizeof (struct aac_srb) + \
487942c5e3cSpl196000 	    (srb_sgcount - 1) * sizeof (struct aac_sg_entry))) {
488942c5e3cSpl196000 		sg64 = 0;
489942c5e3cSpl196000 	} else {
490942c5e3cSpl196000 		rval = EINVAL;
491942c5e3cSpl196000 		goto finish;
492942c5e3cSpl196000 	}
493942c5e3cSpl196000 
494942c5e3cSpl196000 	/* Read user SG table */
495942c5e3cSpl196000 	if ((usgt = kmem_zalloc(sizeof (struct aac_umem_sge) * srb_sgcount,
496942c5e3cSpl196000 	    KM_NOSLEEP)) == NULL) {
497942c5e3cSpl196000 		rval = ENOMEM;
498942c5e3cSpl196000 		goto finish;
499942c5e3cSpl196000 	}
500942c5e3cSpl196000 	for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
501942c5e3cSpl196000 		if (sg64) {
50251ccf66eSjd218194 			struct aac_sg_entry64 *sg64p =
50351ccf66eSjd218194 			    (struct aac_sg_entry64 *)srb->sg.SgEntry;
5046d1d45eeSjd218194 
50551ccf66eSjd218194 			usge->bcount = sg64p->SgByteCount;
5066d1d45eeSjd218194 			usge->addr = (caddr_t)
5076d1d45eeSjd218194 #ifndef _LP64
5086d1d45eeSjd218194 			    (uint32_t)
5096d1d45eeSjd218194 #endif
51051ccf66eSjd218194 			    sg64p->SgAddress;
511942c5e3cSpl196000 		} else {
51251ccf66eSjd218194 			struct aac_sg_entry *sgp = srb->sg.SgEntry;
51351ccf66eSjd218194 
51451ccf66eSjd218194 			usge->bcount = sgp->SgByteCount;
515942c5e3cSpl196000 			usge->addr = (caddr_t)
516942c5e3cSpl196000 #ifdef _LP64
517942c5e3cSpl196000 			    (uint64_t)
518942c5e3cSpl196000 #endif
51951ccf66eSjd218194 			    sgp->SgAddress;
520942c5e3cSpl196000 		}
521942c5e3cSpl196000 		acp->bcount += usge->bcount;
522942c5e3cSpl196000 		if (usge->addr < addrlo)
523942c5e3cSpl196000 			addrlo = usge->addr;
524942c5e3cSpl196000 		if ((usge->addr + usge->bcount) > addrhi)
525942c5e3cSpl196000 			addrhi = usge->addr + usge->bcount;
526942c5e3cSpl196000 	}
527942c5e3cSpl196000 	if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
528942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE,
529942c5e3cSpl196000 		    "large srb xfer size received %d\n", acp->bcount);
530942c5e3cSpl196000 		rval = EINVAL;
531942c5e3cSpl196000 		goto finish;
532942c5e3cSpl196000 	}
533942c5e3cSpl196000 
534942c5e3cSpl196000 	/* Lock user buffers */
535942c5e3cSpl196000 	if (srb->flags & SRB_DataIn) {
536942c5e3cSpl196000 		umem_flags |= DDI_UMEMLOCK_READ;
537942c5e3cSpl196000 		direct |= B_READ;
538942c5e3cSpl196000 	}
539942c5e3cSpl196000 	if (srb->flags & SRB_DataOut) {
540942c5e3cSpl196000 		umem_flags |= DDI_UMEMLOCK_WRITE;
541942c5e3cSpl196000 		direct |= B_WRITE;
542942c5e3cSpl196000 	}
543942c5e3cSpl196000 	addrlo = (caddr_t)((uintptr_t)addrlo & (uintptr_t)PAGEMASK);
544942c5e3cSpl196000 	rval = ddi_umem_lock(addrlo, (((size_t)addrhi + PAGEOFFSET) & \
545942c5e3cSpl196000 	    PAGEMASK) - (size_t)addrlo, umem_flags, &cookie);
546942c5e3cSpl196000 	if (rval != 0) {
547942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "ddi_umem_lock failed: %d",
548942c5e3cSpl196000 		    rval);
549942c5e3cSpl196000 		goto finish;
550942c5e3cSpl196000 	}
551942c5e3cSpl196000 	locked = 1;
552942c5e3cSpl196000 
553942c5e3cSpl196000 	/* Allocate DMA for user buffers */
554942c5e3cSpl196000 	for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
555942c5e3cSpl196000 		struct buf *bp;
556942c5e3cSpl196000 
557a74f7440Spl196000 		bp = ddi_umem_iosetup(cookie, (uintptr_t)usge->addr - \
558a74f7440Spl196000 		    (uintptr_t)addrlo, usge->bcount, direct, dev, 0, NULL,
55958bc78c7SXin Chen 		    DDI_UMEM_NOSLEEP);
560942c5e3cSpl196000 		if (bp == NULL) {
561942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE, "ddi_umem_iosetup failed");
56258bc78c7SXin Chen 			rval = ENOMEM;
563942c5e3cSpl196000 			goto finish;
564942c5e3cSpl196000 		}
565942c5e3cSpl196000 		if (aac_cmd_dma_alloc(softs, &usge->acp, bp, 0, NULL_FUNC,
566942c5e3cSpl196000 		    0) != AACOK) {
567942c5e3cSpl196000 			rval = EFAULT;
568942c5e3cSpl196000 			goto finish;
569942c5e3cSpl196000 		}
570942c5e3cSpl196000 		acp->left_cookien += usge->acp.left_cookien;
571942c5e3cSpl196000 		if (acp->left_cookien > softs->aac_sg_tablesize) {
572942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
573942c5e3cSpl196000 			    acp->left_cookien);
574942c5e3cSpl196000 			rval = EINVAL;
575942c5e3cSpl196000 			goto finish;
576942c5e3cSpl196000 		}
577942c5e3cSpl196000 	}
578942c5e3cSpl196000 
579942c5e3cSpl196000 	/* Construct aac cmd SG table */
580942c5e3cSpl196000 	if ((sge = kmem_zalloc(sizeof (struct aac_sge) * acp->left_cookien,
581942c5e3cSpl196000 	    KM_NOSLEEP)) == NULL) {
582942c5e3cSpl196000 		rval = ENOMEM;
583942c5e3cSpl196000 		goto finish;
584942c5e3cSpl196000 	}
585942c5e3cSpl196000 	acp->sgt = sge;
586942c5e3cSpl196000 	for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
587942c5e3cSpl196000 		for (sge0 = usge->acp.sgt;
588942c5e3cSpl196000 		    sge0 < &usge->acp.sgt[usge->acp.left_cookien];
589942c5e3cSpl196000 		    sge0++, sge++)
590942c5e3cSpl196000 			*sge = *sge0;
591942c5e3cSpl196000 	}
592942c5e3cSpl196000 
593942c5e3cSpl196000 send_fib:
594942c5e3cSpl196000 	acp->cmdlen = srb->cdb_size;
595942c5e3cSpl196000 	acp->timeout = srb->timeout;
596942c5e3cSpl196000 
597942c5e3cSpl196000 	/* Send FIB command */
598942c5e3cSpl196000 	acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
59958bc78c7SXin Chen #ifdef DEBUG
60058bc78c7SXin Chen 	acp->fib_flags = AACDB_FLAGS_FIB_SRB;
60158bc78c7SXin Chen #endif
602942c5e3cSpl196000 	if ((rval = aac_send_fib(softs, acp)) != 0)
603942c5e3cSpl196000 		goto finish;
604942c5e3cSpl196000 
605942c5e3cSpl196000 	/* Status struct */
606942c5e3cSpl196000 	if (ddi_copyout((struct aac_srb_reply *)fibp->data,
607942c5e3cSpl196000 	    ((uint8_t *)arg + usr_fib_size),
608942c5e3cSpl196000 	    sizeof (struct aac_srb_reply), mode) != 0) {
609942c5e3cSpl196000 		rval = EFAULT;
610942c5e3cSpl196000 		goto finish;
611942c5e3cSpl196000 	}
612942c5e3cSpl196000 
613942c5e3cSpl196000 	rval = 0;
614942c5e3cSpl196000 finish:
615942c5e3cSpl196000 	if (acp->sgt)
616942c5e3cSpl196000 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
617942c5e3cSpl196000 		    acp->left_cookien);
618942c5e3cSpl196000 	if (usgt) {
619942c5e3cSpl196000 		for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
620942c5e3cSpl196000 			if (usge->acp.sgt)
621942c5e3cSpl196000 				kmem_free(usge->acp.sgt,
622942c5e3cSpl196000 				    sizeof (struct aac_sge) * \
623942c5e3cSpl196000 				    usge->acp.left_cookien);
624942c5e3cSpl196000 			aac_free_dmamap(&usge->acp);
625942c5e3cSpl196000 			if (usge->acp.bp)
626942c5e3cSpl196000 				freerbuf(usge->acp.bp);
627942c5e3cSpl196000 		}
628942c5e3cSpl196000 		kmem_free(usgt, sizeof (struct aac_umem_sge) * srb_sgcount);
629942c5e3cSpl196000 	}
630942c5e3cSpl196000 	if (locked)
631942c5e3cSpl196000 		ddi_umem_unlock(cookie);
632942c5e3cSpl196000 	kmem_free(acp, sizeof (struct aac_cmd) + usr_fib_size + \
633942c5e3cSpl196000 	    sizeof (struct aac_fib_header));
634942c5e3cSpl196000 	return (rval);
635942c5e3cSpl196000 }
636942c5e3cSpl196000 
637942c5e3cSpl196000 /*ARGSUSED*/
638942c5e3cSpl196000 static int
639942c5e3cSpl196000 aac_get_pci_info(struct aac_softstate *softs, intptr_t arg, int mode)
640942c5e3cSpl196000 {
641942c5e3cSpl196000 	union aac_pci_info_align un;
642942c5e3cSpl196000 	struct aac_pci_info *resp = &un.d;
643f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	pci_regspec_t *pci_rp;
644f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	uint_t num;
645942c5e3cSpl196000 
646942c5e3cSpl196000 	DBCALLED(softs, 2);
647942c5e3cSpl196000 
648f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, softs->devinfo_p,
649f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &num) !=
650f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    DDI_PROP_SUCCESS)
651f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (EINVAL);
652f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (num < (sizeof (pci_regspec_t) / sizeof (int))) {
653f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		ddi_prop_free(pci_rp);
654f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (EINVAL);
655f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
656f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
657f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	resp->bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
658f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	resp->slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
659f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_prop_free(pci_rp);
660942c5e3cSpl196000 
661942c5e3cSpl196000 	if (ddi_copyout(resp, (void *)arg,
662942c5e3cSpl196000 	    sizeof (struct aac_pci_info), mode) != 0)
663942c5e3cSpl196000 		return (EFAULT);
664942c5e3cSpl196000 	return (0);
665942c5e3cSpl196000 }
666942c5e3cSpl196000 
667942c5e3cSpl196000 static int
668942c5e3cSpl196000 aac_query_disk(struct aac_softstate *softs, intptr_t arg, int mode)
669942c5e3cSpl196000 {
670942c5e3cSpl196000 	union aac_query_disk_align un;
671942c5e3cSpl196000 	struct aac_query_disk *qdisk = &un.d;
672942c5e3cSpl196000 	struct aac_container *dvp;
673942c5e3cSpl196000 
674942c5e3cSpl196000 	DBCALLED(softs, 2);
675942c5e3cSpl196000 
676942c5e3cSpl196000 	if (ddi_copyin((void *)arg, qdisk, sizeof (*qdisk), mode) != 0)
677942c5e3cSpl196000 		return (EFAULT);
678942c5e3cSpl196000 
679942c5e3cSpl196000 	if (qdisk->container_no == -1) {
680942c5e3cSpl196000 		qdisk->container_no = qdisk->target * 16 + qdisk->lun;
681942c5e3cSpl196000 	} else if (qdisk->bus == -1 && qdisk->target == -1 &&
682942c5e3cSpl196000 	    qdisk->lun == -1) {
683942c5e3cSpl196000 		if (qdisk->container_no >= AAC_MAX_CONTAINERS)
684942c5e3cSpl196000 			return (EINVAL);
685942c5e3cSpl196000 		qdisk->bus = 0;
686942c5e3cSpl196000 		qdisk->target = (qdisk->container_no & 0xf);
687942c5e3cSpl196000 		qdisk->lun = (qdisk->container_no >> 4);
688942c5e3cSpl196000 	} else {
689942c5e3cSpl196000 		return (EINVAL);
690942c5e3cSpl196000 	}
691942c5e3cSpl196000 
692942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
693942c5e3cSpl196000 	dvp = &softs->containers[qdisk->container_no];
69458bc78c7SXin Chen 	qdisk->valid = AAC_DEV_IS_VALID(&dvp->dev);
695942c5e3cSpl196000 	qdisk->locked = dvp->locked;
696942c5e3cSpl196000 	qdisk->deleted = dvp->deleted;
697942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
698942c5e3cSpl196000 
699942c5e3cSpl196000 	if (ddi_copyout(qdisk, (void *)arg, sizeof (*qdisk), mode) != 0)
700942c5e3cSpl196000 		return (EFAULT);
701942c5e3cSpl196000 	return (0);
702942c5e3cSpl196000 }
703942c5e3cSpl196000 
704942c5e3cSpl196000 static int
705942c5e3cSpl196000 aac_delete_disk(struct aac_softstate *softs, intptr_t arg, int mode)
706942c5e3cSpl196000 {
707942c5e3cSpl196000 	union aac_delete_disk_align un;
708942c5e3cSpl196000 	struct aac_delete_disk *ddisk = &un.d;
709942c5e3cSpl196000 	struct aac_container *dvp;
710942c5e3cSpl196000 	int rval = 0;
711942c5e3cSpl196000 
712942c5e3cSpl196000 	DBCALLED(softs, 2);
713942c5e3cSpl196000 
714942c5e3cSpl196000 	if (ddi_copyin((void *)arg, ddisk, sizeof (*ddisk), mode) != 0)
715942c5e3cSpl196000 		return (EFAULT);
716942c5e3cSpl196000 
717942c5e3cSpl196000 	if (ddisk->container_no >= AAC_MAX_CONTAINERS)
718942c5e3cSpl196000 		return (EINVAL);
719942c5e3cSpl196000 
720942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
721942c5e3cSpl196000 	dvp = &softs->containers[ddisk->container_no];
722942c5e3cSpl196000 	/*
723942c5e3cSpl196000 	 * We don't trust the userland to tell us when to delete
724942c5e3cSpl196000 	 * a container, rather we rely on an AIF coming from the
725942c5e3cSpl196000 	 * controller.
726942c5e3cSpl196000 	 */
72758bc78c7SXin Chen 	if (AAC_DEV_IS_VALID(&dvp->dev)) {
728942c5e3cSpl196000 		if (dvp->locked)
729942c5e3cSpl196000 			rval = EBUSY;
730942c5e3cSpl196000 	}
731942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
732942c5e3cSpl196000 
733942c5e3cSpl196000 	return (rval);
734942c5e3cSpl196000 }
735942c5e3cSpl196000 
736942c5e3cSpl196000 /*
737942c5e3cSpl196000  * The following function comes from Adaptec to support creation of arrays
738942c5e3cSpl196000  * bigger than 2TB.
739942c5e3cSpl196000  */
740942c5e3cSpl196000 static int
741942c5e3cSpl196000 aac_supported_features(struct aac_softstate *softs, intptr_t arg, int mode)
742942c5e3cSpl196000 {
743942c5e3cSpl196000 	union aac_features_align un;
744942c5e3cSpl196000 	struct aac_features *f = &un.d;
745942c5e3cSpl196000 
746942c5e3cSpl196000 	DBCALLED(softs, 2);
747942c5e3cSpl196000 
748942c5e3cSpl196000 	if (ddi_copyin((void *)arg, f, sizeof (*f), mode) != 0)
749942c5e3cSpl196000 		return (EFAULT);
750942c5e3cSpl196000 
751942c5e3cSpl196000 	/*
752942c5e3cSpl196000 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
753942c5e3cSpl196000 	 * ALL zero in the featuresState, the driver will return the current
754942c5e3cSpl196000 	 * state of all the supported features, the data field will not be
755942c5e3cSpl196000 	 * valid.
756942c5e3cSpl196000 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
757942c5e3cSpl196000 	 * a specific bit set in the featuresState, the driver will return the
758942c5e3cSpl196000 	 * current state of this specific feature and whatever data that are
759942c5e3cSpl196000 	 * associated with the feature in the data field or perform whatever
760942c5e3cSpl196000 	 * action needed indicates in the data field.
761942c5e3cSpl196000 	 */
762942c5e3cSpl196000 	if (f->feat.fValue == 0) {
763942c5e3cSpl196000 		f->feat.fBits.largeLBA =
764942c5e3cSpl196000 		    (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
765*3fced439Szhongyan gu - Sun Microsystems - Beijing China 		f->feat.fBits.JBODSupport =
766*3fced439Szhongyan gu - Sun Microsystems - Beijing China 		    (softs->flags & AAC_FLAGS_JBOD) ? 1 : 0;
767942c5e3cSpl196000 		/* TODO: In the future, add other features state here as well */
768942c5e3cSpl196000 	} else {
769942c5e3cSpl196000 		if (f->feat.fBits.largeLBA)
770942c5e3cSpl196000 			f->feat.fBits.largeLBA =
771942c5e3cSpl196000 			    (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
772*3fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (f->feat.fBits.JBODSupport)
773*3fced439Szhongyan gu - Sun Microsystems - Beijing China 			f->feat.fBits.JBODSupport =
774*3fced439Szhongyan gu - Sun Microsystems - Beijing China 			    (softs->flags & AAC_FLAGS_JBOD) ? 1 : 0;
775942c5e3cSpl196000 		/* TODO: Add other features state and data in the future */
776942c5e3cSpl196000 	}
777942c5e3cSpl196000 
778942c5e3cSpl196000 	if (ddi_copyout(f, (void *)arg, sizeof (*f), mode) != 0)
779942c5e3cSpl196000 		return (EFAULT);
780942c5e3cSpl196000 	return (0);
781942c5e3cSpl196000 }
782