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