Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / aac / aac_ioctl.c
blob4c821d181a6c03a8134cb2167a867cf8f67a9843
1 /*
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 */
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.
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.
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.
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"
51 struct aac_umem_sge {
52 uint32_t bcount;
53 caddr_t addr;
54 struct aac_cmd acp;
58 * External functions
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 **);
73 extern ddi_device_acc_attr_t aac_acc_attr;
74 extern int aac_check_dma_handle(ddi_dma_handle_t);
77 * IOCTL command handling functions
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);
90 int
91 aac_do_ioctl(struct aac_softstate *softs, dev_t dev, int cmd, intptr_t arg,
92 int mode)
94 int status;
96 switch (cmd) {
97 case FSACTL_MINIPORT_REV_CHECK:
98 AACDB_PRINT_IOCTL(softs, "FSACTL_MINIPORT_REV_CHECK");
99 status = aac_check_revision(softs, arg, mode);
100 break;
101 case FSACTL_SENDFIB:
102 AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB");
103 goto send_fib;
104 case FSACTL_SEND_LARGE_FIB:
105 AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_LARGE_FIB");
106 send_fib:
107 status = aac_ioctl_send_fib(softs, arg, mode);
108 break;
109 case FSACTL_OPEN_GET_ADAPTER_FIB:
110 AACDB_PRINT_IOCTL(softs, "FSACTL_OPEN_GET_ADAPTER_FIB");
111 status = aac_open_getadapter_fib(softs, arg, mode);
112 break;
113 case FSACTL_GET_NEXT_ADAPTER_FIB:
114 AACDB_PRINT_IOCTL(softs, "FSACTL_GET_NEXT_ADAPTER_FIB");
115 status = aac_next_getadapter_fib(softs, arg, mode);
116 break;
117 case FSACTL_CLOSE_GET_ADAPTER_FIB:
118 AACDB_PRINT_IOCTL(softs, "FSACTL_CLOSE_GET_ADAPTER_FIB");
119 status = aac_close_getadapter_fib(softs, arg);
120 break;
121 case FSACTL_SEND_RAW_SRB:
122 AACDB_PRINT_IOCTL(softs, "FSACTL_SEND_RAW_SRB");
123 status = aac_send_raw_srb(softs, dev, arg, mode);
124 break;
125 case FSACTL_GET_PCI_INFO:
126 AACDB_PRINT_IOCTL(softs, "FSACTL_GET_PCI_INFO");
127 status = aac_get_pci_info(softs, arg, mode);
128 break;
129 case FSACTL_QUERY_DISK:
130 AACDB_PRINT_IOCTL(softs, "FSACTL_QUERY_DISK");
131 status = aac_query_disk(softs, arg, mode);
132 break;
133 case FSACTL_DELETE_DISK:
134 AACDB_PRINT_IOCTL(softs, "FSACTL_DELETE_DISK");
135 status = aac_delete_disk(softs, arg, mode);
136 break;
137 case FSACTL_GET_FEATURES:
138 AACDB_PRINT_IOCTL(softs, "FSACTL_GET_FEATURES");
139 status = aac_supported_features(softs, arg, mode);
140 break;
141 default:
142 status = ENOTTY;
143 AACDB_PRINT(softs, CE_WARN,
144 "!IOCTL cmd 0x%x not supported", cmd);
145 break;
148 return (status);
151 /*ARGSUSED*/
152 static int
153 aac_check_revision(struct aac_softstate *softs, intptr_t arg, int mode)
155 union aac_revision_align un;
156 struct aac_revision *aac_rev = &un.d;
158 DBCALLED(softs, 2);
160 /* Copyin the revision struct from userspace */
161 if (ddi_copyin((void *)arg, aac_rev,
162 sizeof (struct aac_revision), mode) != 0)
163 return (EFAULT);
165 /* Doctor up the response struct */
166 aac_rev->compat = 1;
167 aac_rev->version =
168 ((uint32_t)AAC_DRIVER_MAJOR_VERSION << 24) |
169 ((uint32_t)AAC_DRIVER_MINOR_VERSION << 16) |
170 ((uint32_t)AAC_DRIVER_TYPE << 8) |
171 ((uint32_t)AAC_DRIVER_BUGFIX_LEVEL);
172 aac_rev->build = (uint32_t)AAC_DRIVER_BUILD;
174 if (ddi_copyout(aac_rev, (void *)arg,
175 sizeof (struct aac_revision), mode) != 0)
176 return (EFAULT);
178 return (0);
181 static int
182 aac_send_fib(struct aac_softstate *softs, struct aac_cmd *acp)
184 int rval;
186 acp->flags |= AAC_CMD_NO_CB | AAC_CMD_SYNC;
187 acp->ac_comp = aac_ioctl_complete;
189 mutex_enter(&softs->io_lock);
190 if (softs->state & AAC_STATE_DEAD) {
191 mutex_exit(&softs->io_lock);
192 return (ENXIO);
195 rval = aac_do_io(softs, acp);
196 if (rval == TRAN_ACCEPT) {
197 rval = 0;
198 } else if (rval == TRAN_BADPKT) {
199 AACDB_PRINT(softs, CE_CONT, "User SendFib failed ENXIO");
200 rval = ENXIO;
201 } else if (rval == TRAN_BUSY) {
202 AACDB_PRINT(softs, CE_CONT, "User SendFib failed EBUSY");
203 rval = EBUSY;
205 mutex_exit(&softs->io_lock);
207 return (rval);
210 static int
211 aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode)
213 int hbalen;
214 struct aac_cmd *acp;
215 struct aac_fib *fibp;
216 uint16_t fib_command;
217 uint32_t fib_xfer_state;
218 uint16_t fib_data_size, fib_size;
219 uint16_t fib_sender_size;
220 int rval;
222 DBCALLED(softs, 2);
224 /* Copy in FIB header */
225 hbalen = sizeof (struct aac_cmd) + softs->aac_max_fib_size;
226 if ((acp = kmem_zalloc(hbalen, KM_NOSLEEP)) == NULL)
227 return (ENOMEM);
229 fibp = (struct aac_fib *)(acp + 1);
230 acp->fibp = fibp;
231 if (ddi_copyin((void *)arg, fibp,
232 sizeof (struct aac_fib_header), mode) != 0) {
233 rval = EFAULT;
234 goto finish;
237 fib_xfer_state = LE_32(fibp->Header.XferState);
238 fib_command = LE_16(fibp->Header.Command);
239 fib_data_size = LE_16(fibp->Header.Size);
240 fib_sender_size = LE_16(fibp->Header.SenderSize);
242 fib_size = fib_data_size + sizeof (struct aac_fib_header);
243 if (fib_size < fib_sender_size)
244 fib_size = fib_sender_size;
245 if (fib_size > softs->aac_max_fib_size) {
246 rval = EFAULT;
247 goto finish;
250 /* Copy in FIB data */
251 if (ddi_copyin(((struct aac_fib *)arg)->data, fibp->data,
252 fib_data_size, mode) != 0) {
253 rval = EFAULT;
254 goto finish;
256 acp->fib_size = fib_size;
257 fibp->Header.Size = LE_16(fib_size);
259 /* Process FIB */
260 if (fib_command == TakeABreakPt) {
261 #ifdef DEBUG
262 if (aac_dbflag_on(softs, AACDB_FLAGS_FIB) &&
263 (softs->debug_fib_flags & AACDB_FLAGS_FIB_IOCTL))
264 aac_printf(softs, CE_NOTE, "FIB> TakeABreakPt, sz=%d",
265 fib_size);
266 #endif
267 (void) aac_sync_mbcommand(softs, AAC_BREAKPOINT_REQ,
268 0, 0, 0, 0, NULL);
269 fibp->Header.XferState = LE_32(0);
270 } else {
271 ASSERT(!(fib_xfer_state & AAC_FIBSTATE_ASYNC));
272 fibp->Header.XferState = LE_32(fib_xfer_state | \
273 (AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED));
275 acp->timeout = AAC_IOCTL_TIMEOUT;
276 acp->aac_cmd_fib = aac_cmd_fib_copy;
277 #ifdef DEBUG
278 acp->fib_flags = AACDB_FLAGS_FIB_IOCTL;
279 #endif
280 if ((rval = aac_send_fib(softs, acp)) != 0)
281 goto finish;
284 if (acp->flags & AAC_CMD_ERR) {
285 AACDB_PRINT(softs, CE_CONT, "FIB data corrupt");
286 rval = EIO;
287 goto finish;
290 if (ddi_copyout(fibp, (void *)arg, acp->fib_size, mode) != 0) {
291 AACDB_PRINT(softs, CE_CONT, "FIB copyout failed");
292 rval = EFAULT;
293 goto finish;
296 rval = 0;
297 finish:
298 kmem_free(acp, hbalen);
299 return (rval);
302 static int
303 aac_open_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
305 struct aac_fib_context *fibctx_p, *ctx_p;
307 DBCALLED(softs, 2);
309 fibctx_p = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP);
310 if (fibctx_p == NULL)
311 return (ENOMEM);
313 mutex_enter(&softs->aifq_mutex);
314 /* All elements are already 0, add to queue */
315 if (softs->fibctx_p == NULL) {
316 softs->fibctx_p = fibctx_p;
317 } else {
318 for (ctx_p = softs->fibctx_p; ctx_p->next; ctx_p = ctx_p->next)
320 ctx_p->next = fibctx_p;
321 fibctx_p->prev = ctx_p;
324 /* Evaluate unique value */
325 fibctx_p->unique = (unsigned long)fibctx_p & 0xfffffffful;
326 ctx_p = softs->fibctx_p;
327 while (ctx_p != fibctx_p) {
328 if (ctx_p->unique == fibctx_p->unique) {
329 fibctx_p->unique++;
330 ctx_p = softs->fibctx_p;
331 } else {
332 ctx_p = ctx_p->next;
336 /* Set ctx_idx to the oldest AIF */
337 if (softs->aifq_wrap) {
338 fibctx_p->ctx_idx = softs->aifq_idx;
339 fibctx_p->ctx_filled = 1;
341 mutex_exit(&softs->aifq_mutex);
343 if (ddi_copyout(&fibctx_p->unique, (void *)arg,
344 sizeof (uint32_t), mode) != 0)
345 return (EFAULT);
347 return (0);
350 static int
351 aac_next_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
353 union aac_get_adapter_fib_align un;
354 struct aac_get_adapter_fib *af = &un.d;
355 struct aac_fib_context *ctx_p;
356 struct aac_fib *fibp;
357 int rval;
359 DBCALLED(softs, 2);
361 if (ddi_copyin((void *)arg, af, sizeof (*af), mode) != 0)
362 return (EFAULT);
364 mutex_enter(&softs->aifq_mutex);
365 for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
366 if (af->context == ctx_p->unique)
367 break;
369 mutex_exit(&softs->aifq_mutex);
371 if (ctx_p) {
372 if (af->wait)
373 rval = aac_return_aif_wait(softs, ctx_p, &fibp);
374 else
375 rval = aac_return_aif(softs, ctx_p, &fibp);
377 else
378 rval = EFAULT;
380 finish:
381 if (rval == 0) {
382 if (ddi_copyout(fibp,
383 #ifdef _LP64
384 (void *)(uint64_t)af->aif_fib,
385 #else
386 (void *)af->aif_fib,
387 #endif
388 sizeof (struct aac_fib), mode) != 0)
389 rval = EFAULT;
391 return (rval);
394 static int
395 aac_close_getadapter_fib(struct aac_softstate *softs, intptr_t arg)
397 struct aac_fib_context *ctx_p;
399 DBCALLED(softs, 2);
401 mutex_enter(&softs->aifq_mutex);
402 for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
403 if (ctx_p->unique != (uint32_t)arg)
404 continue;
406 if (ctx_p == softs->fibctx_p)
407 softs->fibctx_p = ctx_p->next;
408 else
409 ctx_p->prev->next = ctx_p->next;
410 if (ctx_p->next)
411 ctx_p->next->prev = ctx_p->prev;
412 break;
414 mutex_exit(&softs->aifq_mutex);
415 if (ctx_p)
416 kmem_free(ctx_p, sizeof (struct aac_fib_context));
418 return (0);
422 * The following function comes from Adaptec:
424 * SRB is required for the new management tools
425 * Note: SRB passed down from IOCTL is always in CPU endianness.
427 static int
428 aac_send_raw_srb(struct aac_softstate *softs, dev_t dev, intptr_t arg, int mode)
430 struct aac_cmd *acp;
431 struct aac_fib *fibp;
432 struct aac_srb *srb;
433 uint32_t usr_fib_size;
434 uint32_t srb_sgcount;
435 struct aac_umem_sge *usgt = NULL;
436 struct aac_umem_sge *usge;
437 ddi_umem_cookie_t cookie;
438 int umem_flags = 0;
439 int direct = 0;
440 int locked = 0;
441 caddr_t addrlo = (caddr_t)-1;
442 caddr_t addrhi = 0;
443 struct aac_sge *sge, *sge0;
444 int sg64;
445 int rval;
447 DBCALLED(softs, 2);
449 /* Read srb size */
450 if (ddi_copyin(&((struct aac_srb *)arg)->count, &usr_fib_size,
451 sizeof (uint32_t), mode) != 0)
452 return (EFAULT);
453 if (usr_fib_size > (softs->aac_max_fib_size - \
454 sizeof (struct aac_fib_header)))
455 return (EINVAL);
457 if ((acp = kmem_zalloc(sizeof (struct aac_cmd) + usr_fib_size + \
458 sizeof (struct aac_fib_header), KM_NOSLEEP)) == NULL)
459 return (ENOMEM);
461 acp->fibp = (struct aac_fib *)(acp + 1);
462 fibp = acp->fibp;
463 srb = (struct aac_srb *)fibp->data;
465 /* Copy in srb */
466 if (ddi_copyin((void *)arg, srb, usr_fib_size, mode) != 0) {
467 rval = EFAULT;
468 goto finish;
471 srb_sgcount = srb->sg.SgCount; /* No endianness conversion needed */
472 if (srb_sgcount == 0)
473 goto send_fib;
475 /* Check FIB size */
476 if (usr_fib_size == (sizeof (struct aac_srb) + \
477 srb_sgcount * sizeof (struct aac_sg_entry64) - \
478 sizeof (struct aac_sg_entry))) {
479 sg64 = 1;
480 } else if (usr_fib_size == (sizeof (struct aac_srb) + \
481 (srb_sgcount - 1) * sizeof (struct aac_sg_entry))) {
482 sg64 = 0;
483 } else {
484 rval = EINVAL;
485 goto finish;
488 /* Read user SG table */
489 if ((usgt = kmem_zalloc(sizeof (struct aac_umem_sge) * srb_sgcount,
490 KM_NOSLEEP)) == NULL) {
491 rval = ENOMEM;
492 goto finish;
494 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
495 if (sg64) {
496 struct aac_sg_entry64 *sg64p =
497 (struct aac_sg_entry64 *)srb->sg.SgEntry;
499 usge->bcount = sg64p->SgByteCount;
500 usge->addr = (caddr_t)
501 #ifndef _LP64
502 (uint32_t)
503 #endif
504 sg64p->SgAddress;
505 } else {
506 struct aac_sg_entry *sgp = srb->sg.SgEntry;
508 usge->bcount = sgp->SgByteCount;
509 usge->addr = (caddr_t)
510 #ifdef _LP64
511 (uint64_t)
512 #endif
513 sgp->SgAddress;
515 acp->bcount += usge->bcount;
516 if (usge->addr < addrlo)
517 addrlo = usge->addr;
518 if ((usge->addr + usge->bcount) > addrhi)
519 addrhi = usge->addr + usge->bcount;
521 if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
522 AACDB_PRINT(softs, CE_NOTE,
523 "large srb xfer size received %d\n", acp->bcount);
524 rval = EINVAL;
525 goto finish;
528 /* Lock user buffers */
529 if (srb->flags & SRB_DataIn) {
530 umem_flags |= DDI_UMEMLOCK_READ;
531 direct |= B_READ;
533 if (srb->flags & SRB_DataOut) {
534 umem_flags |= DDI_UMEMLOCK_WRITE;
535 direct |= B_WRITE;
537 addrlo = (caddr_t)((uintptr_t)addrlo & (uintptr_t)PAGEMASK);
538 rval = ddi_umem_lock(addrlo, (((size_t)addrhi + PAGEOFFSET) & \
539 PAGEMASK) - (size_t)addrlo, umem_flags, &cookie);
540 if (rval != 0) {
541 AACDB_PRINT(softs, CE_NOTE, "ddi_umem_lock failed: %d",
542 rval);
543 goto finish;
545 locked = 1;
547 /* Allocate DMA for user buffers */
548 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
549 struct buf *bp;
551 bp = ddi_umem_iosetup(cookie, (uintptr_t)usge->addr - \
552 (uintptr_t)addrlo, usge->bcount, direct, dev, 0, NULL,
553 DDI_UMEM_NOSLEEP);
554 if (bp == NULL) {
555 AACDB_PRINT(softs, CE_NOTE, "ddi_umem_iosetup failed");
556 rval = ENOMEM;
557 goto finish;
559 if (aac_cmd_dma_alloc(softs, &usge->acp, bp, 0, NULL_FUNC,
560 0) != AACOK) {
561 rval = EFAULT;
562 goto finish;
564 acp->left_cookien += usge->acp.left_cookien;
565 if (acp->left_cookien > softs->aac_sg_tablesize) {
566 AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
567 acp->left_cookien);
568 rval = EINVAL;
569 goto finish;
573 /* Construct aac cmd SG table */
574 if ((sge = kmem_zalloc(sizeof (struct aac_sge) * acp->left_cookien,
575 KM_NOSLEEP)) == NULL) {
576 rval = ENOMEM;
577 goto finish;
579 acp->sgt = sge;
580 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
581 for (sge0 = usge->acp.sgt;
582 sge0 < &usge->acp.sgt[usge->acp.left_cookien];
583 sge0++, sge++)
584 *sge = *sge0;
587 send_fib:
588 acp->cmdlen = srb->cdb_size;
589 acp->timeout = srb->timeout;
591 /* Send FIB command */
592 acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
593 #ifdef DEBUG
594 acp->fib_flags = AACDB_FLAGS_FIB_SRB;
595 #endif
596 if ((rval = aac_send_fib(softs, acp)) != 0)
597 goto finish;
599 /* Status struct */
600 if (ddi_copyout((struct aac_srb_reply *)fibp->data,
601 ((uint8_t *)arg + usr_fib_size),
602 sizeof (struct aac_srb_reply), mode) != 0) {
603 rval = EFAULT;
604 goto finish;
607 rval = 0;
608 finish:
609 if (acp->sgt)
610 kmem_free(acp->sgt, sizeof (struct aac_sge) * \
611 acp->left_cookien);
612 if (usgt) {
613 for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
614 if (usge->acp.sgt)
615 kmem_free(usge->acp.sgt,
616 sizeof (struct aac_sge) * \
617 usge->acp.left_cookien);
618 aac_free_dmamap(&usge->acp);
619 if (usge->acp.bp)
620 freerbuf(usge->acp.bp);
622 kmem_free(usgt, sizeof (struct aac_umem_sge) * srb_sgcount);
624 if (locked)
625 ddi_umem_unlock(cookie);
626 kmem_free(acp, sizeof (struct aac_cmd) + usr_fib_size + \
627 sizeof (struct aac_fib_header));
628 return (rval);
631 /*ARGSUSED*/
632 static int
633 aac_get_pci_info(struct aac_softstate *softs, intptr_t arg, int mode)
635 union aac_pci_info_align un;
636 struct aac_pci_info *resp = &un.d;
637 pci_regspec_t *pci_rp;
638 uint_t num;
640 DBCALLED(softs, 2);
642 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, softs->devinfo_p,
643 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &num) !=
644 DDI_PROP_SUCCESS)
645 return (EINVAL);
646 if (num < (sizeof (pci_regspec_t) / sizeof (int))) {
647 ddi_prop_free(pci_rp);
648 return (EINVAL);
651 resp->bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
652 resp->slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
653 ddi_prop_free(pci_rp);
655 if (ddi_copyout(resp, (void *)arg,
656 sizeof (struct aac_pci_info), mode) != 0)
657 return (EFAULT);
658 return (0);
661 static int
662 aac_query_disk(struct aac_softstate *softs, intptr_t arg, int mode)
664 union aac_query_disk_align un;
665 struct aac_query_disk *qdisk = &un.d;
666 struct aac_container *dvp;
668 DBCALLED(softs, 2);
670 if (ddi_copyin((void *)arg, qdisk, sizeof (*qdisk), mode) != 0)
671 return (EFAULT);
673 if (qdisk->container_no == -1) {
674 qdisk->container_no = qdisk->target * 16 + qdisk->lun;
675 } else if (qdisk->bus == -1 && qdisk->target == -1 &&
676 qdisk->lun == -1) {
677 if (qdisk->container_no >= AAC_MAX_CONTAINERS)
678 return (EINVAL);
679 qdisk->bus = 0;
680 qdisk->target = (qdisk->container_no & 0xf);
681 qdisk->lun = (qdisk->container_no >> 4);
682 } else {
683 return (EINVAL);
686 mutex_enter(&softs->io_lock);
687 dvp = &softs->containers[qdisk->container_no];
688 qdisk->valid = AAC_DEV_IS_VALID(&dvp->dev);
689 qdisk->locked = dvp->locked;
690 qdisk->deleted = dvp->deleted;
691 mutex_exit(&softs->io_lock);
693 if (ddi_copyout(qdisk, (void *)arg, sizeof (*qdisk), mode) != 0)
694 return (EFAULT);
695 return (0);
698 static int
699 aac_delete_disk(struct aac_softstate *softs, intptr_t arg, int mode)
701 union aac_delete_disk_align un;
702 struct aac_delete_disk *ddisk = &un.d;
703 struct aac_container *dvp;
704 int rval = 0;
706 DBCALLED(softs, 2);
708 if (ddi_copyin((void *)arg, ddisk, sizeof (*ddisk), mode) != 0)
709 return (EFAULT);
711 if (ddisk->container_no >= AAC_MAX_CONTAINERS)
712 return (EINVAL);
714 mutex_enter(&softs->io_lock);
715 dvp = &softs->containers[ddisk->container_no];
717 * We don't trust the userland to tell us when to delete
718 * a container, rather we rely on an AIF coming from the
719 * controller.
721 if (AAC_DEV_IS_VALID(&dvp->dev)) {
722 if (dvp->locked)
723 rval = EBUSY;
725 mutex_exit(&softs->io_lock);
727 return (rval);
731 * The following function comes from Adaptec to support creation of arrays
732 * bigger than 2TB.
734 static int
735 aac_supported_features(struct aac_softstate *softs, intptr_t arg, int mode)
737 union aac_features_align un;
738 struct aac_features *f = &un.d;
740 DBCALLED(softs, 2);
742 if (ddi_copyin((void *)arg, f, sizeof (*f), mode) != 0)
743 return (EFAULT);
746 * When the management driver receives FSACTL_GET_FEATURES ioctl with
747 * ALL zero in the featuresState, the driver will return the current
748 * state of all the supported features, the data field will not be
749 * valid.
750 * When the management driver receives FSACTL_GET_FEATURES ioctl with
751 * a specific bit set in the featuresState, the driver will return the
752 * current state of this specific feature and whatever data that are
753 * associated with the feature in the data field or perform whatever
754 * action needed indicates in the data field.
756 if (f->feat.fValue == 0) {
757 f->feat.fBits.largeLBA =
758 (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
759 f->feat.fBits.JBODSupport =
760 (softs->flags & AAC_FLAGS_JBOD) ? 1 : 0;
761 /* TODO: In the future, add other features state here as well */
762 } else {
763 if (f->feat.fBits.largeLBA)
764 f->feat.fBits.largeLBA =
765 (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0;
766 if (f->feat.fBits.JBODSupport)
767 f->feat.fBits.JBODSupport =
768 (softs->flags & AAC_FLAGS_JBOD) ? 1 : 0;
769 /* TODO: Add other features state and data in the future */
772 if (ddi_copyout(f, (void *)arg, sizeof (*f), mode) != 0)
773 return (EFAULT);
774 return (0);