1 /* 2 * Copyright 2008 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 666 DBCALLED(softs, 2); 667 668 resp->bus = 0; 669 resp->slot = 0; 670 671 if (ddi_copyout(resp, (void *)arg, 672 sizeof (struct aac_pci_info), mode) != 0) 673 return (EFAULT); 674 return (0); 675 } 676 677 static int 678 aac_query_disk(struct aac_softstate *softs, intptr_t arg, int mode) 679 { 680 union aac_query_disk_align un; 681 struct aac_query_disk *qdisk = &un.d; 682 struct aac_container *dvp; 683 684 DBCALLED(softs, 2); 685 686 if (ddi_copyin((void *)arg, qdisk, sizeof (*qdisk), mode) != 0) 687 return (EFAULT); 688 689 if (qdisk->container_no == -1) { 690 qdisk->container_no = qdisk->target * 16 + qdisk->lun; 691 } else if (qdisk->bus == -1 && qdisk->target == -1 && 692 qdisk->lun == -1) { 693 if (qdisk->container_no >= AAC_MAX_CONTAINERS) 694 return (EINVAL); 695 qdisk->bus = 0; 696 qdisk->target = (qdisk->container_no & 0xf); 697 qdisk->lun = (qdisk->container_no >> 4); 698 } else { 699 return (EINVAL); 700 } 701 702 mutex_enter(&softs->io_lock); 703 dvp = &softs->containers[qdisk->container_no]; 704 qdisk->valid = AAC_DEV_IS_VALID(&dvp->dev); 705 qdisk->locked = dvp->locked; 706 qdisk->deleted = dvp->deleted; 707 mutex_exit(&softs->io_lock); 708 709 if (ddi_copyout(qdisk, (void *)arg, sizeof (*qdisk), mode) != 0) 710 return (EFAULT); 711 return (0); 712 } 713 714 static int 715 aac_delete_disk(struct aac_softstate *softs, intptr_t arg, int mode) 716 { 717 union aac_delete_disk_align un; 718 struct aac_delete_disk *ddisk = &un.d; 719 struct aac_container *dvp; 720 int rval = 0; 721 722 DBCALLED(softs, 2); 723 724 if (ddi_copyin((void *)arg, ddisk, sizeof (*ddisk), mode) != 0) 725 return (EFAULT); 726 727 if (ddisk->container_no >= AAC_MAX_CONTAINERS) 728 return (EINVAL); 729 730 mutex_enter(&softs->io_lock); 731 dvp = &softs->containers[ddisk->container_no]; 732 /* 733 * We don't trust the userland to tell us when to delete 734 * a container, rather we rely on an AIF coming from the 735 * controller. 736 */ 737 if (AAC_DEV_IS_VALID(&dvp->dev)) { 738 if (dvp->locked) 739 rval = EBUSY; 740 } 741 mutex_exit(&softs->io_lock); 742 743 return (rval); 744 } 745 746 /* 747 * The following function comes from Adaptec to support creation of arrays 748 * bigger than 2TB. 749 */ 750 static int 751 aac_supported_features(struct aac_softstate *softs, intptr_t arg, int mode) 752 { 753 union aac_features_align un; 754 struct aac_features *f = &un.d; 755 756 DBCALLED(softs, 2); 757 758 if (ddi_copyin((void *)arg, f, sizeof (*f), mode) != 0) 759 return (EFAULT); 760 761 /* 762 * When the management driver receives FSACTL_GET_FEATURES ioctl with 763 * ALL zero in the featuresState, the driver will return the current 764 * state of all the supported features, the data field will not be 765 * valid. 766 * When the management driver receives FSACTL_GET_FEATURES ioctl with 767 * a specific bit set in the featuresState, the driver will return the 768 * current state of this specific feature and whatever data that are 769 * associated with the feature in the data field or perform whatever 770 * action needed indicates in the data field. 771 */ 772 if (f->feat.fValue == 0) { 773 f->feat.fBits.largeLBA = 774 (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 775 /* TODO: In the future, add other features state here as well */ 776 } else { 777 if (f->feat.fBits.largeLBA) 778 f->feat.fBits.largeLBA = 779 (softs->flags & AAC_FLAGS_LBA_64BIT) ? 1 : 0; 780 /* TODO: Add other features state and data in the future */ 781 } 782 783 if (ddi_copyout(f, (void *)arg, sizeof (*f), mode) != 0) 784 return (EFAULT); 785 return (0); 786 } 787