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