2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
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
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
34 #include <sys/modctl.h>
36 #include <sys/cmn_err.h>
38 #include <sys/devops.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>
49 #include "aac_ioctl.h"
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
*,
70 extern int aac_return_aif(struct aac_softstate
*, struct aac_fib_context
*,
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);
91 aac_do_ioctl(struct aac_softstate
*softs
, dev_t dev
, int cmd
, intptr_t arg
,
97 case FSACTL_MINIPORT_REV_CHECK
:
98 AACDB_PRINT_IOCTL(softs
, "FSACTL_MINIPORT_REV_CHECK");
99 status
= aac_check_revision(softs
, arg
, mode
);
102 AACDB_PRINT_IOCTL(softs
, "FSACTL_SEND_LARGE_FIB");
104 case FSACTL_SEND_LARGE_FIB
:
105 AACDB_PRINT_IOCTL(softs
, "FSACTL_SEND_LARGE_FIB");
107 status
= aac_ioctl_send_fib(softs
, arg
, mode
);
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
);
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
);
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
);
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
);
125 case FSACTL_GET_PCI_INFO
:
126 AACDB_PRINT_IOCTL(softs
, "FSACTL_GET_PCI_INFO");
127 status
= aac_get_pci_info(softs
, arg
, mode
);
129 case FSACTL_QUERY_DISK
:
130 AACDB_PRINT_IOCTL(softs
, "FSACTL_QUERY_DISK");
131 status
= aac_query_disk(softs
, arg
, mode
);
133 case FSACTL_DELETE_DISK
:
134 AACDB_PRINT_IOCTL(softs
, "FSACTL_DELETE_DISK");
135 status
= aac_delete_disk(softs
, arg
, mode
);
137 case FSACTL_GET_FEATURES
:
138 AACDB_PRINT_IOCTL(softs
, "FSACTL_GET_FEATURES");
139 status
= aac_supported_features(softs
, arg
, mode
);
143 AACDB_PRINT(softs
, CE_WARN
,
144 "!IOCTL cmd 0x%x not supported", cmd
);
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
;
160 /* Copyin the revision struct from userspace */
161 if (ddi_copyin((void *)arg
, aac_rev
,
162 sizeof (struct aac_revision
), mode
) != 0)
165 /* Doctor up the response struct */
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)
182 aac_send_fib(struct aac_softstate
*softs
, struct aac_cmd
*acp
)
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
);
195 rval
= aac_do_io(softs
, acp
);
196 if (rval
== TRAN_ACCEPT
) {
198 } else if (rval
== TRAN_BADPKT
) {
199 AACDB_PRINT(softs
, CE_CONT
, "User SendFib failed ENXIO");
201 } else if (rval
== TRAN_BUSY
) {
202 AACDB_PRINT(softs
, CE_CONT
, "User SendFib failed EBUSY");
205 mutex_exit(&softs
->io_lock
);
211 aac_ioctl_send_fib(struct aac_softstate
*softs
, intptr_t arg
, int mode
)
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
;
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
)
229 fibp
= (struct aac_fib
*)(acp
+ 1);
231 if (ddi_copyin((void *)arg
, fibp
,
232 sizeof (struct aac_fib_header
), mode
) != 0) {
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
) {
250 /* Copy in FIB data */
251 if (ddi_copyin(((struct aac_fib
*)arg
)->data
, fibp
->data
,
252 fib_data_size
, mode
) != 0) {
256 acp
->fib_size
= fib_size
;
257 fibp
->Header
.Size
= LE_16(fib_size
);
260 if (fib_command
== TakeABreakPt
) {
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",
267 (void) aac_sync_mbcommand(softs
, AAC_BREAKPOINT_REQ
,
269 fibp
->Header
.XferState
= LE_32(0);
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
;
278 acp
->fib_flags
= AACDB_FLAGS_FIB_IOCTL
;
280 if ((rval
= aac_send_fib(softs
, acp
)) != 0)
284 if (acp
->flags
& AAC_CMD_ERR
) {
285 AACDB_PRINT(softs
, CE_CONT
, "FIB data corrupt");
290 if (ddi_copyout(fibp
, (void *)arg
, acp
->fib_size
, mode
) != 0) {
291 AACDB_PRINT(softs
, CE_CONT
, "FIB copyout failed");
298 kmem_free(acp
, hbalen
);
303 aac_open_getadapter_fib(struct aac_softstate
*softs
, intptr_t arg
, int mode
)
305 struct aac_fib_context
*fibctx_p
, *ctx_p
;
309 fibctx_p
= kmem_zalloc(sizeof (struct aac_fib_context
), KM_NOSLEEP
);
310 if (fibctx_p
== NULL
)
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
;
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
) {
330 ctx_p
= softs
->fibctx_p
;
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)
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
;
361 if (ddi_copyin((void *)arg
, af
, sizeof (*af
), mode
) != 0)
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
)
369 mutex_exit(&softs
->aifq_mutex
);
373 rval
= aac_return_aif_wait(softs
, ctx_p
, &fibp
);
375 rval
= aac_return_aif(softs
, ctx_p
, &fibp
);
382 if (ddi_copyout(fibp
,
384 (void *)(uint64_t)af
->aif_fib
,
388 sizeof (struct aac_fib
), mode
) != 0)
395 aac_close_getadapter_fib(struct aac_softstate
*softs
, intptr_t arg
)
397 struct aac_fib_context
*ctx_p
;
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
)
406 if (ctx_p
== softs
->fibctx_p
)
407 softs
->fibctx_p
= ctx_p
->next
;
409 ctx_p
->prev
->next
= ctx_p
->next
;
411 ctx_p
->next
->prev
= ctx_p
->prev
;
414 mutex_exit(&softs
->aifq_mutex
);
416 kmem_free(ctx_p
, sizeof (struct aac_fib_context
));
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.
428 aac_send_raw_srb(struct aac_softstate
*softs
, dev_t dev
, intptr_t arg
, int mode
)
431 struct aac_fib
*fibp
;
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
;
441 caddr_t addrlo
= (caddr_t
)-1;
443 struct aac_sge
*sge
, *sge0
;
450 if (ddi_copyin(&((struct aac_srb
*)arg
)->count
, &usr_fib_size
,
451 sizeof (uint32_t), mode
) != 0)
453 if (usr_fib_size
> (softs
->aac_max_fib_size
- \
454 sizeof (struct aac_fib_header
)))
457 if ((acp
= kmem_zalloc(sizeof (struct aac_cmd
) + usr_fib_size
+ \
458 sizeof (struct aac_fib_header
), KM_NOSLEEP
)) == NULL
)
461 acp
->fibp
= (struct aac_fib
*)(acp
+ 1);
463 srb
= (struct aac_srb
*)fibp
->data
;
466 if (ddi_copyin((void *)arg
, srb
, usr_fib_size
, mode
) != 0) {
471 srb_sgcount
= srb
->sg
.SgCount
; /* No endianness conversion needed */
472 if (srb_sgcount
== 0)
476 if (usr_fib_size
== (sizeof (struct aac_srb
) + \
477 srb_sgcount
* sizeof (struct aac_sg_entry64
) - \
478 sizeof (struct aac_sg_entry
))) {
480 } else if (usr_fib_size
== (sizeof (struct aac_srb
) + \
481 (srb_sgcount
- 1) * sizeof (struct aac_sg_entry
))) {
488 /* Read user SG table */
489 if ((usgt
= kmem_zalloc(sizeof (struct aac_umem_sge
) * srb_sgcount
,
490 KM_NOSLEEP
)) == NULL
) {
494 for (usge
= usgt
; usge
< &usgt
[srb_sgcount
]; usge
++) {
496 struct aac_sg_entry64
*sg64p
=
497 (struct aac_sg_entry64
*)srb
->sg
.SgEntry
;
499 usge
->bcount
= sg64p
->SgByteCount
;
500 usge
->addr
= (caddr_t
)
506 struct aac_sg_entry
*sgp
= srb
->sg
.SgEntry
;
508 usge
->bcount
= sgp
->SgByteCount
;
509 usge
->addr
= (caddr_t
)
515 acp
->bcount
+= usge
->bcount
;
516 if (usge
->addr
< addrlo
)
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
);
528 /* Lock user buffers */
529 if (srb
->flags
& SRB_DataIn
) {
530 umem_flags
|= DDI_UMEMLOCK_READ
;
533 if (srb
->flags
& SRB_DataOut
) {
534 umem_flags
|= DDI_UMEMLOCK_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
);
541 AACDB_PRINT(softs
, CE_NOTE
, "ddi_umem_lock failed: %d",
547 /* Allocate DMA for user buffers */
548 for (usge
= usgt
; usge
< &usgt
[srb_sgcount
]; usge
++) {
551 bp
= ddi_umem_iosetup(cookie
, (uintptr_t)usge
->addr
- \
552 (uintptr_t)addrlo
, usge
->bcount
, direct
, dev
, 0, NULL
,
555 AACDB_PRINT(softs
, CE_NOTE
, "ddi_umem_iosetup failed");
559 if (aac_cmd_dma_alloc(softs
, &usge
->acp
, bp
, 0, NULL_FUNC
,
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",
573 /* Construct aac cmd SG table */
574 if ((sge
= kmem_zalloc(sizeof (struct aac_sge
) * acp
->left_cookien
,
575 KM_NOSLEEP
)) == NULL
) {
580 for (usge
= usgt
; usge
< &usgt
[srb_sgcount
]; usge
++) {
581 for (sge0
= usge
->acp
.sgt
;
582 sge0
< &usge
->acp
.sgt
[usge
->acp
.left_cookien
];
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
;
594 acp
->fib_flags
= AACDB_FLAGS_FIB_SRB
;
596 if ((rval
= aac_send_fib(softs
, acp
)) != 0)
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) {
610 kmem_free(acp
->sgt
, sizeof (struct aac_sge
) * \
613 for (usge
= usgt
; usge
< &usgt
[srb_sgcount
]; usge
++) {
615 kmem_free(usge
->acp
.sgt
,
616 sizeof (struct aac_sge
) * \
617 usge
->acp
.left_cookien
);
618 aac_free_dmamap(&usge
->acp
);
620 freerbuf(usge
->acp
.bp
);
622 kmem_free(usgt
, sizeof (struct aac_umem_sge
) * srb_sgcount
);
625 ddi_umem_unlock(cookie
);
626 kmem_free(acp
, sizeof (struct aac_cmd
) + usr_fib_size
+ \
627 sizeof (struct aac_fib_header
));
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
;
642 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, softs
->devinfo_p
,
643 DDI_PROP_DONTPASS
, "reg", (int **)&pci_rp
, &num
) !=
646 if (num
< (sizeof (pci_regspec_t
) / sizeof (int))) {
647 ddi_prop_free(pci_rp
);
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)
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
;
670 if (ddi_copyin((void *)arg
, qdisk
, sizeof (*qdisk
), mode
) != 0)
673 if (qdisk
->container_no
== -1) {
674 qdisk
->container_no
= qdisk
->target
* 16 + qdisk
->lun
;
675 } else if (qdisk
->bus
== -1 && qdisk
->target
== -1 &&
677 if (qdisk
->container_no
>= AAC_MAX_CONTAINERS
)
680 qdisk
->target
= (qdisk
->container_no
& 0xf);
681 qdisk
->lun
= (qdisk
->container_no
>> 4);
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)
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
;
708 if (ddi_copyin((void *)arg
, ddisk
, sizeof (*ddisk
), mode
) != 0)
711 if (ddisk
->container_no
>= AAC_MAX_CONTAINERS
)
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
721 if (AAC_DEV_IS_VALID(&dvp
->dev
)) {
725 mutex_exit(&softs
->io_lock
);
731 * The following function comes from Adaptec to support creation of arrays
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
;
742 if (ddi_copyin((void *)arg
, f
, sizeof (*f
), mode
) != 0)
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
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 */
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)