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 }