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