xref: /titanic_50/usr/src/uts/common/io/aac/aac_ioctl.c (revision d4c0a8c59bf9b2697b3dda08963d7f424dcba394)
1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright 2005-06 Adaptec, Inc.
8  * Copyright (c) 2005-06 Adaptec Inc., Achim Leubner
9  * Copyright (c) 2000 Michael Smith
10  * Copyright (c) 2001 Scott Long
11  * Copyright (c) 2000 BSDi
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include <sys/modctl.h>
38 #include <sys/conf.h>
39 #include <sys/cmn_err.h>
40 #include <sys/ddi.h>
41 #include <sys/devops.h>
42 #include <sys/pci.h>
43 #include <sys/types.h>
44 #include <sys/ddidmareq.h>
45 #include <sys/scsi/scsi.h>
46 #include <sys/ksynch.h>
47 #include <sys/sunddi.h>
48 #include <sys/byteorder.h>
49 #include <sys/kmem.h>
50 #include "aac_regs.h"
51 #include "aac.h"
52 #include "aac_ioctl.h"
53 
54 struct aac_umem_sge {
55 	uint32_t bcount;
56 	caddr_t addr;
57 	struct aac_cmd acp;
58 };
59 
60 /*
61  * External functions
62  */
63 extern int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
64     uint32_t, uint32_t, uint32_t, uint32_t *);
65 extern int aac_cmd_dma_alloc(struct aac_softstate *, struct aac_cmd *,
66     struct buf *, int, int (*)(), caddr_t);
67 extern void aac_free_dmamap(struct aac_cmd *);
68 extern int aac_do_io(struct aac_softstate *, struct aac_cmd *);
69 extern void aac_cmd_fib_copy(struct aac_softstate *, struct aac_cmd *);
70 extern void aac_ioctl_complete(struct aac_softstate *, struct aac_cmd *);
71 
72 extern ddi_device_acc_attr_t aac_acc_attr;
73 extern int aac_check_dma_handle(ddi_dma_handle_t);
74 
75 /*
76  * IOCTL command handling functions
77  */
78 static int aac_check_revision(struct aac_softstate *, intptr_t, int);
79 static int aac_ioctl_send_fib(struct aac_softstate *, intptr_t, int);
80 static int aac_open_getadapter_fib(struct aac_softstate *, intptr_t, int);
81 static int aac_next_getadapter_fib(struct aac_softstate *, intptr_t, int);
82 static int aac_close_getadapter_fib(struct aac_softstate *, intptr_t);
83 static int aac_send_raw_srb(struct aac_softstate *, dev_t, intptr_t, int);
84 static int aac_get_pci_info(struct aac_softstate *, intptr_t, int);
85 static int aac_query_disk(struct aac_softstate *, intptr_t, int);
86 static int aac_delete_disk(struct aac_softstate *, intptr_t, int);
87 static int aac_supported_features(struct aac_softstate *, intptr_t, int);
88 
89 /*
90  * Warlock directives
91  */
92 _NOTE(SCHEME_PROTECTS_DATA("unique to each handling function", aac_features
93     aac_pci_info aac_query_disk aac_revision aac_umem_sge))
94 
95 int
96 aac_do_ioctl(struct aac_softstate *softs, dev_t dev, int cmd, intptr_t arg,
97     int mode)
98 {
99 	int status;
100 
101 	switch (cmd) {
102 	case FSACTL_MINIPORT_REV_CHECK:
103 		AACDB_PRINT_IOCTL(softs, "FSACTL_MINIPORT_REV_CHECK");
104 		status = aac_check_revision(softs, arg, mode);
105 		break;
106 	case FSACTL_SENDFIB:
107 		AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB");
108 		goto send_fib;
109 	case FSACTL_SEND_LARGE_FIB:
110 		AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB");
111 send_fib:
112 		status = aac_ioctl_send_fib(softs, arg, mode);
113 		break;
114 	case FSACTL_OPEN_GET_ADAPTER_FIB:
115 		AACDB_PRINT_IOCTL(softs, "FSACTL_OPEN_GET_ADAPTER_FIB");
116 		status = aac_open_getadapter_fib(softs, arg, mode);
117 		break;
118 	case FSACTL_GET_NEXT_ADAPTER_FIB:
119 		AACDB_PRINT_IOCTL(softs, "FSACTL_GET_NEXT_ADAPTER_FIB");
120 		status = aac_next_getadapter_fib(softs, arg, mode);
121 		break;
122 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
123 		AACDB_PRINT_IOCTL(softs, "FSACTL_CLOSE_GET_ADAPTER_FIB");
124 		status = aac_close_getadapter_fib(softs, arg);
125 		break;
126 	case FSACTL_SEND_RAW_SRB:
127 		AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_RAW_SRB");
128 		status = aac_send_raw_srb(softs, dev, arg, mode);
129 		break;
130 	case FSACTL_GET_PCI_INFO:
131 		AACDB_PRINT_IOCTL(softs, "FSACTL_GET_PCI_INFO");
132 		status = aac_get_pci_info(softs, arg, mode);
133 		break;
134 	case FSACTL_QUERY_DISK:
135 		AACDB_PRINT_IOCTL(softs, "FSACTL_QUERY_DISK");
136 		status = aac_query_disk(softs, arg, mode);
137 		break;
138 	case FSACTL_DELETE_DISK:
139 		AACDB_PRINT_IOCTL(softs, "FSACTL_DELETE_DISK");
140 		status = aac_delete_disk(softs, arg, mode);
141 		break;
142 	case FSACTL_GET_FEATURES:
143 		AACDB_PRINT_IOCTL(softs, "FSACTL_GET_FEATURES");
144 		status = aac_supported_features(softs, arg, mode);
145 		break;
146 	default:
147 		status = ENOTTY;
148 		AACDB_PRINT(softs, CE_WARN,
149 		    "!IOCTL cmd 0x%x not supported", cmd);
150 		break;
151 	}
152 
153 	return (status);
154 }
155 
156 /*ARGSUSED*/
157 static int
158 aac_check_revision(struct aac_softstate *softs, intptr_t arg, int mode)
159 {
160 	union aac_revision_align un;
161 	struct aac_revision *aac_rev = &un.d;
162 
163 	DBCALLED(softs, 2);
164 
165 	/* Copyin the revision struct from userspace */
166 	if (ddi_copyin((void *)arg, aac_rev,
167 	    sizeof (struct aac_revision), mode) != 0)
168 		return (EFAULT);
169 
170 	/* Doctor up the response struct */
171 	aac_rev->compat = 1;
172 	aac_rev->version =
173 	    ((uint32_t)AAC_DRIVER_MAJOR_VERSION << 24) |
174 	    ((uint32_t)AAC_DRIVER_MINOR_VERSION << 16) |
175 	    ((uint32_t)AAC_DRIVER_TYPE << 8) |
176 	    ((uint32_t)AAC_DRIVER_BUGFIX_LEVEL);
177 	aac_rev->build = (uint32_t)AAC_DRIVER_BUILD;
178 
179 	if (ddi_copyout(aac_rev, (void *)arg,
180 	    sizeof (struct aac_revision), mode) != 0)
181 		return (EFAULT);
182 
183 	return (0);
184 }
185 
186 static int
187 aac_send_fib(struct aac_softstate *softs, struct aac_cmd *acp)
188 {
189 	int rval;
190 
191 	acp->flags |= AAC_CMD_NO_CB | AAC_CMD_SYNC;
192 	acp->ac_comp = aac_ioctl_complete;
193 
194 	mutex_enter(&softs->io_lock);
195 	if (softs->state & AAC_STATE_DEAD) {
196 		mutex_exit(&softs->io_lock);
197 		return (ENXIO);
198 	}
199 
200 	rval = aac_do_io(softs, acp);
201 	if (rval == TRAN_ACCEPT) {
202 		rval = 0;
203 	} else if (rval == TRAN_BADPKT) {
204 		AACDB_PRINT(softs, CE_CONT, "User SendFib failed ENXIO");
205 		rval = ENXIO;
206 	} else if (rval == TRAN_BUSY) {
207 		AACDB_PRINT(softs, CE_CONT, "User SendFib failed EBUSY");
208 		rval = EBUSY;
209 	}
210 	mutex_exit(&softs->io_lock);
211 
212 	return (rval);
213 }
214 
215 static int
216 aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode)
217 {
218 	int hbalen;
219 	struct aac_cmd *acp;
220 	struct aac_fib *fibp;
221 	uint16_t fib_command;
222 	uint32_t fib_xfer_state;
223 	uint16_t fib_data_size, fib_size;
224 	uint16_t fib_sender_size;
225 	int rval;
226 
227 	DBCALLED(softs, 2);
228 
229 	/* Copy in FIB header */
230 	hbalen = sizeof (struct aac_cmd) + softs->aac_max_fib_size;
231 	if ((acp = kmem_zalloc(hbalen, KM_NOSLEEP)) == NULL)
232 		return (ENOMEM);
233 
234 	fibp = (struct aac_fib *)(acp + 1);
235 	acp->fibp = fibp;
236 	if (ddi_copyin((void *)arg, fibp,
237 	    sizeof (struct aac_fib_header), mode) != 0) {
238 		rval = EFAULT;
239 		goto finish;
240 	}
241 
242 	fib_xfer_state = LE_32(fibp->Header.XferState);
243 	fib_command = LE_16(fibp->Header.Command);
244 	fib_data_size = LE_16(fibp->Header.Size);
245 	fib_sender_size = LE_16(fibp->Header.SenderSize);
246 
247 	fib_size = fib_data_size + sizeof (struct aac_fib_header);
248 	if (fib_size < fib_sender_size)
249 		fib_size = fib_sender_size;
250 	if (fib_size > softs->aac_max_fib_size) {
251 		rval = EFAULT;
252 		goto finish;
253 	}
254 
255 	/* Copy in FIB data */
256 	if (ddi_copyin(((struct aac_fib *)arg)->data, fibp->data,
257 	    fib_data_size, mode) != 0) {
258 		rval = EFAULT;
259 		goto finish;
260 	}
261 	acp->fib_size = fib_size;
262 	fibp->Header.Size = LE_16(fib_size);
263 
264 	AACDB_PRINT_FIB(softs, fibp);
265 
266 	/* Process FIB */
267 	if (fib_command == TakeABreakPt) {
268 		(void) aac_sync_mbcommand(softs, AAC_BREAKPOINT_REQ,
269 		    0, 0, 0, 0, NULL);
270 		fibp->Header.XferState = LE_32(0);
271 	} else {
272 		ASSERT(!(fib_xfer_state & AAC_FIBSTATE_ASYNC));
273 		fibp->Header.XferState = LE_32(fib_xfer_state | \
274 		    (AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED));
275 
276 		acp->timeout = AAC_IOCTL_TIMEOUT;
277 		acp->aac_cmd_fib = aac_cmd_fib_copy;
278 		if ((rval = aac_send_fib(softs, acp)) != 0)
279 			goto finish;
280 	}
281 
282 	if (acp->flags & AAC_CMD_ERR) {
283 		AACDB_PRINT(softs, CE_CONT, "FIB data corrupt");
284 		rval = EIO;
285 		goto finish;
286 	}
287 
288 	if (ddi_copyout(fibp, (void *)arg, acp->fib_size, mode) != 0) {
289 		AACDB_PRINT(softs, CE_CONT, "FIB copyout failed");
290 		rval = EFAULT;
291 		goto finish;
292 	}
293 
294 	rval = 0;
295 finish:
296 	kmem_free(acp, hbalen);
297 	return (rval);
298 }
299 
300 static int
301 aac_open_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
302 {
303 	struct aac_fib_context *fibctx, *ctx;
304 
305 	DBCALLED(softs, 2);
306 
307 	fibctx = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP);
308 	if (fibctx == NULL)
309 		return (ENOMEM);
310 
311 	mutex_enter(&softs->aifq_mutex);
312 	/* All elements are already 0, add to queue */
313 	if (softs->fibctx == NULL) {
314 		softs->fibctx = fibctx;
315 	} else {
316 		for (ctx = softs->fibctx; ctx->next; ctx = ctx->next)
317 			;
318 		ctx->next = fibctx;
319 		fibctx->prev = ctx;
320 	}
321 
322 	/* Evaluate unique value */
323 	fibctx->unique = (unsigned long)fibctx & 0xfffffffful;
324 	ctx = softs->fibctx;
325 	while (ctx != fibctx) {
326 		if (ctx->unique == fibctx->unique) {
327 			fibctx->unique++;
328 			ctx = softs->fibctx;
329 		} else {
330 			ctx = ctx->next;
331 		}
332 	}
333 
334 	/* Set ctx_idx to the oldest AIF */
335 	if (softs->aifq_wrap) {
336 		fibctx->ctx_idx = softs->aifq_idx;
337 		fibctx->ctx_filled = 1;
338 	}
339 	mutex_exit(&softs->aifq_mutex);
340 
341 	if (ddi_copyout(&fibctx->unique, (void *)arg,
342 	    sizeof (uint32_t), mode) != 0)
343 		return (EFAULT);
344 
345 	return (0);
346 }
347 
348 static int
349 aac_return_aif(struct aac_softstate *softs,
350     struct aac_fib_context *ctx, caddr_t uptr, int mode)
351 {
352 	int current;
353 
354 	current = ctx->ctx_idx;
355 	if (current == softs->aifq_idx && !ctx->ctx_filled)
356 		return (EAGAIN); /* Empty */
357 	if (ddi_copyout(&softs->aifq[current].d, (void *)uptr,
358 	    sizeof (struct aac_fib), mode) != 0)
359 		return (EFAULT);
360 
361 	ctx->ctx_filled = 0;
362 	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
363 
364 	return (0);
365 }
366 
367 static int
368 aac_next_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
369 {
370 	union aac_get_adapter_fib_align un;
371 	struct aac_get_adapter_fib *af = &un.d;
372 	struct aac_fib_context *ctx;
373 	int rval;
374 
375 	DBCALLED(softs, 2);
376 
377 	if (ddi_copyin((void *)arg, af, sizeof (*af), mode) != 0)
378 		return (EFAULT);
379 
380 	mutex_enter(&softs->aifq_mutex);
381 	for (ctx = softs->fibctx; ctx; ctx = ctx->next) {
382 		if (af->context == ctx->unique)
383 			break;
384 	}
385 	if (ctx) {
386 #ifdef	_LP64
387 		rval = aac_return_aif(softs, ctx,
388 		    (caddr_t)(uint64_t)af->aif_fib, mode);
389 #else
390 		rval = aac_return_aif(softs, ctx,
391 		    (caddr_t)af->aif_fib, mode);
392 #endif
393 		if (rval == EAGAIN && af->wait) {
394 			AACDB_PRINT(softs, CE_NOTE,
395 			    "aac_next_getadapter_fib(): waiting for AIF");
396 			rval = cv_wait_sig(&softs->aifv, &softs->aifq_mutex);
397 			if (rval > 0) {
398 #ifdef	_LP64
399 				rval = aac_return_aif(softs, ctx,
400 				    (caddr_t)(uint64_t)af->aif_fib, mode);
401 #else
402 				rval = aac_return_aif(softs, ctx,
403 				    (caddr_t)af->aif_fib, mode);
404 #endif
405 			} else {
406 				rval = EINTR;
407 			}
408 		}
409 	} else {
410 		rval = EFAULT;
411 	}
412 	mutex_exit(&softs->aifq_mutex);
413 
414 	return (rval);
415 }
416 
417 static int
418 aac_close_getadapter_fib(struct aac_softstate *softs, intptr_t arg)
419 {
420 	struct aac_fib_context *ctx;
421 
422 	DBCALLED(softs, 2);
423 
424 	mutex_enter(&softs->aifq_mutex);
425 	for (ctx = softs->fibctx; ctx; ctx = ctx->next) {
426 		if (ctx->unique != (uint32_t)arg)
427 			continue;
428 
429 		if (ctx == softs->fibctx)
430 			softs->fibctx = ctx->next;
431 		else
432 			ctx->prev->next = ctx->next;
433 		if (ctx->next)
434 			ctx->next->prev = ctx->prev;
435 		break;
436 	}
437 	mutex_exit(&softs->aifq_mutex);
438 	if (ctx)
439 		kmem_free(ctx, sizeof (struct aac_fib_context));
440 
441 	return (0);
442 }
443 
444 /*
445  * The following function comes from Adaptec:
446  *
447  * SRB is required for the new management tools
448  * Note: SRB passed down from IOCTL is always in CPU endianness.
449  */
450 static int
451 aac_send_raw_srb(struct aac_softstate *softs, dev_t dev, intptr_t arg, int mode)
452 {
453 	struct aac_cmd *acp;
454 	struct aac_fib *fibp;
455 	struct aac_srb *srb;
456 	uint32_t usr_fib_size;
457 	uint32_t srb_sgcount;
458 	struct aac_umem_sge *usgt = NULL;
459 	struct aac_umem_sge *usge;
460 	ddi_umem_cookie_t cookie;
461 	int umem_flags = 0;
462 	int direct = 0;
463 	int locked = 0;
464 	caddr_t addrlo = (caddr_t)-1;
465 	caddr_t addrhi = 0;
466 	struct aac_sge *sge, *sge0;
467 	int sg64;
468 	int rval;
469 
470 	DBCALLED(softs, 2);
471 
472 	/* Read srb size */
473 	if (ddi_copyin(&((struct aac_srb *)arg)->count, &usr_fib_size,
474 	    sizeof (uint32_t), mode) != 0)
475 		return (EFAULT);
476 	if (usr_fib_size > (softs->aac_max_fib_size - \
477 	    sizeof (struct aac_fib_header)))
478 		return (EINVAL);
479 
480 	if ((acp = kmem_zalloc(sizeof (struct aac_cmd) + usr_fib_size + \
481 	    sizeof (struct aac_fib_header), KM_NOSLEEP)) == NULL)
482 		return (ENOMEM);
483 
484 	acp->fibp = (struct aac_fib *)(acp + 1);
485 	fibp = acp->fibp;
486 	srb = (struct aac_srb *)fibp->data;
487 
488 	/* Copy in srb */
489 	if (ddi_copyin((void *)arg, srb, usr_fib_size, mode) != 0) {
490 		rval = EFAULT;
491 		goto finish;
492 	}
493 
494 	srb_sgcount = srb->sg.SgCount; /* No endianness conversion needed */
495 	if (srb_sgcount == 0)
496 		goto send_fib;
497 
498 	/* Check FIB size */
499 	if (usr_fib_size == (sizeof (struct aac_srb) + \
500 	    srb_sgcount * sizeof (struct aac_sg_entry64) - \
501 	    sizeof (struct aac_sg_entry))) {
502 		sg64 = 1;
503 	} else if (usr_fib_size == (sizeof (struct aac_srb) + \
504 	    (srb_sgcount - 1) * sizeof (struct aac_sg_entry))) {
505 		sg64 = 0;
506 	} else {
507 		rval = EINVAL;
508 		goto finish;
509 	}
510 
511 	/* Read user SG table */
512 	if ((usgt = kmem_zalloc(sizeof (struct aac_umem_sge) * srb_sgcount,
513 	    KM_NOSLEEP)) == NULL) {
514 		rval = ENOMEM;
515 		goto finish;
516 	}
517 	for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
518 		if (sg64) {
519 			usge->bcount = ((struct aac_sg_entry64 *)srb-> \
520 			    sg.SgEntry)->SgByteCount;
521 #ifndef _LP64
522 			usge->addr = (caddr_t)
523 			    (uint32_t)((struct aac_sg_entry64 *) \
524 			    srb->sg.SgEntry)->SgAddress;
525 			if ((uint32_t)usge->addr > 0xfffffffful) {
526 #else
527 			usge->addr = (caddr_t)
528 			    ((struct aac_sg_entry64 *) \
529 			    srb->sg.SgEntry)->SgAddress;
530 			if ((uint64_t)usge->addr > 0xffffffffull) {
531 				if (!(softs->flags & AAC_FLAGS_SG_64BIT))
532 #endif
533 				{
534 					rval = EINVAL;
535 					AACDB_PRINT(softs, CE_NOTE,
536 					    "64-bit addresses not supported");
537 					goto finish;
538 				}
539 			}
540 		} else {
541 			usge->bcount = srb->sg.SgEntry->SgByteCount;
542 			usge->addr = (caddr_t)
543 #ifdef _LP64
544 			    (uint64_t)
545 #endif
546 			    srb->sg.SgEntry->SgAddress;
547 		}
548 		acp->bcount += usge->bcount;
549 		if (usge->addr < addrlo)
550 			addrlo = usge->addr;
551 		if ((usge->addr + usge->bcount) > addrhi)
552 			addrhi = usge->addr + usge->bcount;
553 	}
554 	if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
555 		AACDB_PRINT(softs, CE_NOTE,
556 		    "large srb xfer size received %d\n", acp->bcount);
557 		rval = EINVAL;
558 		goto finish;
559 	}
560 
561 	/* Lock user buffers */
562 	if (srb->flags & SRB_DataIn) {
563 		umem_flags |= DDI_UMEMLOCK_READ;
564 		direct |= B_READ;
565 	}
566 	if (srb->flags & SRB_DataOut) {
567 		umem_flags |= DDI_UMEMLOCK_WRITE;
568 		direct |= B_WRITE;
569 	}
570 	addrlo = (caddr_t)((uintptr_t)addrlo & (uintptr_t)PAGEMASK);
571 	rval = ddi_umem_lock(addrlo, (((size_t)addrhi + PAGEOFFSET) & \
572 	    PAGEMASK) - (size_t)addrlo, umem_flags, &cookie);
573 	if (rval != 0) {
574 		AACDB_PRINT(softs, CE_NOTE, "ddi_umem_lock failed: %d",
575 		    rval);
576 		goto finish;
577 	}
578 	locked = 1;
579 
580 	/* Allocate DMA for user buffers */
581 	for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
582 		struct buf *bp;
583 
584 		bp = ddi_umem_iosetup(cookie, usge->addr - addrlo,
585 		    usge->bcount, direct, dev, 0, NULL, DDI_UMEM_SLEEP);
586 		if (bp == NULL) {
587 			AACDB_PRINT(softs, CE_NOTE, "ddi_umem_iosetup failed");
588 			rval = EFAULT;
589 			goto finish;
590 		}
591 		if (aac_cmd_dma_alloc(softs, &usge->acp, bp, 0, NULL_FUNC,
592 		    0) != AACOK) {
593 			rval = EFAULT;
594 			goto finish;
595 		}
596 		acp->left_cookien += usge->acp.left_cookien;
597 		if (acp->left_cookien > softs->aac_sg_tablesize) {
598 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
599 			    acp->left_cookien);
600 			rval = EINVAL;
601 			goto finish;
602 		}
603 	}
604 
605 	/* Construct aac cmd SG table */
606 	if ((sge = kmem_zalloc(sizeof (struct aac_sge) * acp->left_cookien,
607 	    KM_NOSLEEP)) == NULL) {
608 		rval = ENOMEM;
609 		goto finish;
610 	}
611 	acp->sgt = sge;
612 	for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
613 		for (sge0 = usge->acp.sgt;
614 		    sge0 < &usge->acp.sgt[usge->acp.left_cookien];
615 		    sge0++, sge++)
616 			*sge = *sge0;
617 	}
618 
619 send_fib:
620 	acp->cmdlen = srb->cdb_size;
621 	acp->timeout = srb->timeout;
622 
623 	/* Send FIB command */
624 	AACDB_PRINT_FIB(softs, fibp);
625 	acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
626 	if ((rval = aac_send_fib(softs, acp)) != 0)
627 		goto finish;
628 
629 	/* Status struct */
630 	if (ddi_copyout((struct aac_srb_reply *)fibp->data,
631 	    ((uint8_t *)arg + usr_fib_size),
632 	    sizeof (struct aac_srb_reply), mode) != 0) {
633 		rval = EFAULT;
634 		goto finish;
635 	}
636 
637 	rval = 0;
638 finish:
639 	if (acp->sgt)
640 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
641 		    acp->left_cookien);
642 	if (usgt) {
643 		for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
644 			if (usge->acp.sgt)
645 				kmem_free(usge->acp.sgt,
646 				    sizeof (struct aac_sge) * \
647 				    usge->acp.left_cookien);
648 			aac_free_dmamap(&usge->acp);
649 			if (usge->acp.bp)
650 				freerbuf(usge->acp.bp);
651 		}
652 		kmem_free(usgt, sizeof (struct aac_umem_sge) * srb_sgcount);
653 	}
654 	if (locked)
655 		ddi_umem_unlock(cookie);
656 	kmem_free(acp, sizeof (struct aac_cmd) + usr_fib_size + \
657 	    sizeof (struct aac_fib_header));
658 	return (rval);
659 }
660 
661 /*ARGSUSED*/
662 static int
663 aac_get_pci_info(struct aac_softstate *softs, intptr_t arg, int mode)
664 {
665 	union aac_pci_info_align un;
666 	struct aac_pci_info *resp = &un.d;
667 
668 	DBCALLED(softs, 2);
669 
670 	resp->bus = 0;
671 	resp->slot = 0;
672 
673 	if (ddi_copyout(resp, (void *)arg,
674 	    sizeof (struct aac_pci_info), mode) != 0)
675 		return (EFAULT);
676 	return (0);
677 }
678 
679 static int
680 aac_query_disk(struct aac_softstate *softs, intptr_t arg, int mode)
681 {
682 	union aac_query_disk_align un;
683 	struct aac_query_disk *qdisk = &un.d;
684 	struct aac_container *dvp;
685 
686 	DBCALLED(softs, 2);
687 
688 	if (ddi_copyin((void *)arg, qdisk, sizeof (*qdisk), mode) != 0)
689 		return (EFAULT);
690 
691 	if (qdisk->container_no == -1) {
692 		qdisk->container_no = qdisk->target * 16 + qdisk->lun;
693 	} else if (qdisk->bus == -1 && qdisk->target == -1 &&
694 	    qdisk->lun == -1) {
695 		if (qdisk->container_no >= AAC_MAX_CONTAINERS)
696 			return (EINVAL);
697 		qdisk->bus = 0;
698 		qdisk->target = (qdisk->container_no & 0xf);
699 		qdisk->lun = (qdisk->container_no >> 4);
700 	} else {
701 		return (EINVAL);
702 	}
703 
704 	mutex_enter(&softs->io_lock);
705 	dvp = &softs->containers[qdisk->container_no];
706 	qdisk->valid = dvp->valid;
707 	qdisk->locked = dvp->locked;
708 	qdisk->deleted = dvp->deleted;
709 	mutex_exit(&softs->io_lock);
710 
711 	if (ddi_copyout(qdisk, (void *)arg, sizeof (*qdisk), mode) != 0)
712 		return (EFAULT);
713 	return (0);
714 }
715 
716 static int
717 aac_delete_disk(struct aac_softstate *softs, intptr_t arg, int mode)
718 {
719 	union aac_delete_disk_align un;
720 	struct aac_delete_disk *ddisk = &un.d;
721 	struct aac_container *dvp;
722 	int rval = 0;
723 
724 	DBCALLED(softs, 2);
725 
726 	if (ddi_copyin((void *)arg, ddisk, sizeof (*ddisk), mode) != 0)
727 		return (EFAULT);
728 
729 	if (ddisk->container_no >= AAC_MAX_CONTAINERS)
730 		return (EINVAL);
731 
732 	mutex_enter(&softs->io_lock);
733 	dvp = &softs->containers[ddisk->container_no];
734 	/*
735 	 * We don't trust the userland to tell us when to delete
736 	 * a container, rather we rely on an AIF coming from the
737 	 * controller.
738 	 */
739 	if (dvp->valid) {
740 		if (dvp->locked)
741 			rval = EBUSY;
742 	}
743 	mutex_exit(&softs->io_lock);
744 
745 	return (rval);
746 }
747 
748 /*
749  * The following function comes from Adaptec to support creation of arrays
750  * bigger than 2TB.
751  */
752 static int
753 aac_supported_features(struct aac_softstate *softs, intptr_t arg, int mode)
754 {
755 	union aac_features_align un;
756 	struct aac_features *f = &un.d;
757 
758 	DBCALLED(softs, 2);
759 
760 	if (ddi_copyin((void *)arg, f, sizeof (*f), mode) != 0)
761 		return (EFAULT);
762 
763 	/*
764 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
765 	 * ALL zero in the featuresState, the driver will return the current
766 	 * state of all the supported features, the data field will not be
767 	 * valid.
768 	 * When the management driver receives FSACTL_GET_FEATURES ioctl with
769 	 * a specific bit set in the featuresState, the driver will return the
770 	 * current state of this specific feature and whatever data that are
771 	 * associated with the feature in the data field or perform whatever
772 	 * action needed indicates in the data field.
773 	 */
774 	if (f->feat.fValue == 0) {
775 		f->feat.fBits.largeLBA =
776 		    (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
777 		/* TODO: In the future, add other features state here as well */
778 	} else {
779 		if (f->feat.fBits.largeLBA)
780 			f->feat.fBits.largeLBA =
781 			    (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
782 		/* TODO: Add other features state and data in the future */
783 	}
784 
785 	if (ddi_copyout(f, (void *)arg, sizeof (*f), mode) != 0)
786 		return (EFAULT);
787 	return (0);
788 }
789