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 int
  91 aac_do_ioctl(struct aac_softstate *softs, dev_t dev, int cmd, intptr_t arg,
  92     int mode)
  93 {
  94         int status;
  95 
  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;
 146         }
 147 
 148         return (status);
 149 }
 150 
 151 /*ARGSUSED*/
 152 static int
 153 aac_check_revision(struct aac_softstate *softs, intptr_t arg, int mode)
 154 {
 155         union aac_revision_align un;
 156         struct aac_revision *aac_rev = &un.d;
 157 
 158         DBCALLED(softs, 2);
 159 
 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);
 164 
 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;
 173 
 174         if (ddi_copyout(aac_rev, (void *)arg,
 175             sizeof (struct aac_revision), mode) != 0)
 176                 return (EFAULT);
 177 
 178         return (0);
 179 }
 180 
 181 static int
 182 aac_send_fib(struct aac_softstate *softs, struct aac_cmd *acp)
 183 {
 184         int rval;
 185 
 186         acp->flags |= AAC_CMD_NO_CB | AAC_CMD_SYNC;
 187         acp->ac_comp = aac_ioctl_complete;
 188 
 189         mutex_enter(&softs->io_lock);
 190         if (softs->state & AAC_STATE_DEAD) {
 191                 mutex_exit(&softs->io_lock);
 192                 return (ENXIO);
 193         }
 194 
 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;
 204         }
 205         mutex_exit(&softs->io_lock);
 206 
 207         return (rval);
 208 }
 209 
 210 static int
 211 aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode)
 212 {
 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;
 221 
 222         DBCALLED(softs, 2);
 223 
 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);
 228 
 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;
 235         }
 236 
 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);
 241 
 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;
 248         }
 249 
 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;
 255         }
 256         acp->fib_size = fib_size;
 257         fibp->Header.Size = LE_16(fib_size);
 258 
 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));
 274 
 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;
 282         }
 283 
 284         if (acp->flags & AAC_CMD_ERR) {
 285                 AACDB_PRINT(softs, CE_CONT, "FIB data corrupt");
 286                 rval = EIO;
 287                 goto finish;
 288         }
 289 
 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;
 294         }
 295 
 296         rval = 0;
 297 finish:
 298         kmem_free(acp, hbalen);
 299         return (rval);
 300 }
 301 
 302 static int
 303 aac_open_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
 304 {
 305         struct aac_fib_context *fibctx_p, *ctx_p;
 306 
 307         DBCALLED(softs, 2);
 308 
 309         fibctx_p = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP);
 310         if (fibctx_p == NULL)
 311                 return (ENOMEM);
 312 
 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)
 319                         ;
 320                 ctx_p->next = fibctx_p;
 321                 fibctx_p->prev = ctx_p;
 322         }
 323 
 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;
 333                 }
 334         }
 335 
 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;
 340         }
 341         mutex_exit(&softs->aifq_mutex);
 342 
 343         if (ddi_copyout(&fibctx_p->unique, (void *)arg,
 344             sizeof (uint32_t), mode) != 0)
 345                 return (EFAULT);
 346 
 347         return (0);
 348 }
 349 
 350 static int
 351 aac_next_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
 352 {
 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;
 358 
 359         DBCALLED(softs, 2);
 360 
 361         if (ddi_copyin((void *)arg, af, sizeof (*af), mode) != 0)
 362                 return (EFAULT);
 363 
 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;
 368         }
 369         mutex_exit(&softs->aifq_mutex);
 370 
 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);
 376         }
 377         else
 378                 rval = EFAULT;
 379 
 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;
 390         }
 391         return (rval);
 392 }
 393 
 394 static int
 395 aac_close_getadapter_fib(struct aac_softstate *softs, intptr_t arg)
 396 {
 397         struct aac_fib_context *ctx_p;
 398 
 399         DBCALLED(softs, 2);
 400 
 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;
 405 
 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;
 413         }
 414         mutex_exit(&softs->aifq_mutex);
 415         if (ctx_p)
 416                 kmem_free(ctx_p, sizeof (struct aac_fib_context));
 417 
 418         return (0);
 419 }
 420 
 421 /*
 422  * The following function comes from Adaptec:
 423  *
 424  * SRB is required for the new management tools
 425  * Note: SRB passed down from IOCTL is always in CPU endianness.
 426  */
 427 static int
 428 aac_send_raw_srb(struct aac_softstate *softs, dev_t dev, intptr_t arg, int mode)
 429 {
 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;
 446 
 447         DBCALLED(softs, 2);
 448 
 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);
 456 
 457         if ((acp = kmem_zalloc(sizeof (struct aac_cmd) + usr_fib_size + \
 458             sizeof (struct aac_fib_header), KM_NOSLEEP)) == NULL)
 459                 return (ENOMEM);
 460 
 461         acp->fibp = (struct aac_fib *)(acp + 1);
 462         fibp = acp->fibp;
 463         srb = (struct aac_srb *)fibp->data;
 464 
 465         /* Copy in srb */
 466         if (ddi_copyin((void *)arg, srb, usr_fib_size, mode) != 0) {
 467                 rval = EFAULT;
 468                 goto finish;
 469         }
 470 
 471         srb_sgcount = srb->sg.SgCount; /* No endianness conversion needed */
 472         if (srb_sgcount == 0)
 473                 goto send_fib;
 474 
 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;
 486         }
 487 
 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;
 493         }
 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;
 498 
 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;
 507 
 508                         usge->bcount = sgp->SgByteCount;
 509                         usge->addr = (caddr_t)
 510 #ifdef _LP64
 511                             (uint64_t)
 512 #endif
 513                             sgp->SgAddress;
 514                 }
 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;
 520         }
 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;
 526         }
 527 
 528         /* Lock user buffers */
 529         if (srb->flags & SRB_DataIn) {
 530                 umem_flags |= DDI_UMEMLOCK_READ;
 531                 direct |= B_READ;
 532         }
 533         if (srb->flags & SRB_DataOut) {
 534                 umem_flags |= DDI_UMEMLOCK_WRITE;
 535                 direct |= B_WRITE;
 536         }
 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;
 544         }
 545         locked = 1;
 546 
 547         /* Allocate DMA for user buffers */
 548         for (usge = usgt; usge < &usgt[srb_sgcount]; usge++) {
 549                 struct buf *bp;
 550 
 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;
 558                 }
 559                 if (aac_cmd_dma_alloc(softs, &usge->acp, bp, 0, NULL_FUNC,
 560                     0) != AACOK) {
 561                         rval = EFAULT;
 562                         goto finish;
 563                 }
 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;
 570                 }
 571         }
 572 
 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;
 578         }
 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;
 585         }
 586 
 587 send_fib:
 588         acp->cmdlen = srb->cdb_size;
 589         acp->timeout = srb->timeout;
 590 
 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;
 598 
 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;
 605         }
 606 
 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);
 621                 }
 622                 kmem_free(usgt, sizeof (struct aac_umem_sge) * srb_sgcount);
 623         }
 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);
 629 }
 630 
 631 /*ARGSUSED*/
 632 static int
 633 aac_get_pci_info(struct aac_softstate *softs, intptr_t arg, int mode)
 634 {
 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;
 639 
 640         DBCALLED(softs, 2);
 641 
 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);
 649         }
 650 
 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);
 654 
 655         if (ddi_copyout(resp, (void *)arg,
 656             sizeof (struct aac_pci_info), mode) != 0)
 657                 return (EFAULT);
 658         return (0);
 659 }
 660 
 661 static int
 662 aac_query_disk(struct aac_softstate *softs, intptr_t arg, int mode)
 663 {
 664         union aac_query_disk_align un;
 665         struct aac_query_disk *qdisk = &un.d;
 666         struct aac_container *dvp;
 667 
 668         DBCALLED(softs, 2);
 669 
 670         if (ddi_copyin((void *)arg, qdisk, sizeof (*qdisk), mode) != 0)
 671                 return (EFAULT);
 672 
 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);
 684         }
 685 
 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);
 692 
 693         if (ddi_copyout(qdisk, (void *)arg, sizeof (*qdisk), mode) != 0)
 694                 return (EFAULT);
 695         return (0);
 696 }
 697 
 698 static int
 699 aac_delete_disk(struct aac_softstate *softs, intptr_t arg, int mode)
 700 {
 701         union aac_delete_disk_align un;
 702         struct aac_delete_disk *ddisk = &un.d;
 703         struct aac_container *dvp;
 704         int rval = 0;
 705 
 706         DBCALLED(softs, 2);
 707 
 708         if (ddi_copyin((void *)arg, ddisk, sizeof (*ddisk), mode) != 0)
 709                 return (EFAULT);
 710 
 711         if (ddisk->container_no >= AAC_MAX_CONTAINERS)
 712                 return (EINVAL);
 713 
 714         mutex_enter(&softs->io_lock);
 715         dvp = &softs->containers[ddisk->container_no];
 716         /*
 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.
 720          */
 721         if (AAC_DEV_IS_VALID(&dvp->dev)) {
 722                 if (dvp->locked)
 723                         rval = EBUSY;
 724         }
 725         mutex_exit(&softs->io_lock);
 726 
 727         return (rval);
 728 }
 729 
 730 /*
 731  * The following function comes from Adaptec to support creation of arrays
 732  * bigger than 2TB.
 733  */
 734 static int
 735 aac_supported_features(struct aac_softstate *softs, intptr_t arg, int mode)
 736 {
 737         union aac_features_align un;
 738         struct aac_features *f = &un.d;
 739 
 740         DBCALLED(softs, 2);
 741 
 742         if (ddi_copyin((void *)arg, f, sizeof (*f), mode) != 0)
 743                 return (EFAULT);
 744 
 745         /*
 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.
 755          */
 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 */
 770         }
 771 
 772         if (ddi_copyout(f, (void *)arg, sizeof (*f), mode) != 0)
 773                 return (EFAULT);
 774         return (0);
 775 }