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