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