1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. 14 */ 15 16 /* 17 * Supported IOCTLs : 18 * CPQARY3_IOCTL_DRIVER_INFO - to get driver details 19 * CPQARY3_IOCTL_CTLR_INFO - to get controller details 20 * CPQARY3_IOCTL_BMIC_PASS - to pass BMIC commands 21 * CPQARY3_IOCTL_SCSI_PASS - to pass SCSI commands 22 */ 23 24 #include "cpqary3.h" 25 26 /* 27 * Local Functions Declaration 28 */ 29 30 static int32_t cpqary3_ioctl_send_bmiccmd(cpqary3_t *, cpqary3_bmic_pass_t *, 31 int); 32 static void cpqary3_ioctl_fil_bmic(CommandList_t *, cpqary3_bmic_pass_t *); 33 static void cpqary3_ioctl_fil_bmic_sas(CommandList_t *, cpqary3_bmic_pass_t *); 34 static int32_t cpqary3_ioctl_send_scsicmd(cpqary3_t *, cpqary3_scsi_pass_t *, 35 int); 36 static void cpqary3_ioctl_fil_scsi(CommandList_t *, cpqary3_scsi_pass_t *); 37 38 /* 39 * Global Variables Definitions 40 */ 41 42 cpqary3_driver_info_t gdriver_info = {0}; 43 44 /* Function Definitions */ 45 46 /* 47 * Function : cpqary3_ioctl_driver_info 48 * Description : This routine will get major/ minor versions, Number of 49 * controllers detected & MAX Number of controllers 50 * supported 51 * Called By : cpqary3_ioctl 52 * Parameters : ioctl_reqp - address of the parameter sent from 53 * the application 54 * cpqary3p - address of the PerController structure 55 * mode - mode which comes from application 56 * Return Values: EFAULT on Failure, 0 on SUCCESS 57 */ 58 int32_t 59 cpqary3_ioctl_driver_info(uintptr_t ioctl_reqp, int mode) 60 { 61 cpqary3_ioctl_request_t *request; 62 63 request = (cpqary3_ioctl_request_t *) 64 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t)); 65 66 if (NULL == request) 67 return (FAILURE); 68 69 /* 70 * First let us copyin the ioctl_reqp user buffer to request(kernel) 71 * memory. This is very much recomended before we access any of the 72 * fields. 73 */ 74 if (ddi_copyin((void *)ioctl_reqp, (void *)request, 75 sizeof (cpqary3_ioctl_request_t), mode)) { 76 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 77 return (EFAULT); 78 } 79 80 /* 81 * Fill up the global structure "gdriver_info" memory. 82 * Fill this structure with available info, which will be copied 83 * back later 84 */ 85 86 (void) strcpy(gdriver_info.name, "cpqary3"); 87 gdriver_info.version.minor = CPQARY3_MINOR_REV_NO; 88 gdriver_info.version.major = CPQARY3_MAJOR_REV_NO; 89 gdriver_info.version.dd = CPQARY3_REV_MONTH; 90 gdriver_info.version.mm = CPQARY3_REV_DATE; 91 gdriver_info.version.yyyy = CPQARY3_REV_YEAR; 92 gdriver_info.max_num_ctlr = MAX_CTLRS; 93 94 /* 95 * First Copy out the driver_info structure 96 */ 97 98 if (ddi_copyout((void *)&gdriver_info, (void *)(uintptr_t)request->argp, 99 sizeof (cpqary3_driver_info_t), mode)) { 100 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 101 return (EFAULT); 102 } 103 104 /* 105 * Copy out the request structure back 106 */ 107 108 if (ddi_copyout((void *)request, (void *)ioctl_reqp, 109 sizeof (cpqary3_ioctl_request_t), mode)) { 110 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 111 return (EFAULT); 112 } 113 114 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 115 116 /* 117 * Everything looks fine. So return SUCCESS 118 */ 119 120 return (SUCCESS); 121 } 122 123 /* 124 * Function : cpqary3_ioctl_ctlr_info 125 * Description : This routine will get the controller related info, like 126 * board-id, subsystem-id, num of logical drives, 127 * slot number 128 * Called By : cpqary3_ioctl 129 * Parameters : ioctl_reqp - address of the parameter sent form the 130 * application 131 * cpqary3p - address of the PerController structure 132 * mode - mode which comes from application 133 * Return Values: EFAULT on Failure, 0 on SUCCESS 134 */ 135 int32_t 136 cpqary3_ioctl_ctlr_info(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode) 137 { 138 cpqary3_ioctl_request_t *request; 139 cpqary3_ctlr_info_t *ctlr_info; 140 141 request = (cpqary3_ioctl_request_t *) 142 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t)); 143 144 if (NULL == request) 145 return (FAILURE); 146 147 /* 148 * First let us copyin the buffer to kernel memory. This is very much 149 * recomended before we access any of the fields. 150 */ 151 152 if (ddi_copyin((void *) ioctl_reqp, (void *)request, 153 sizeof (cpqary3_ioctl_request_t), mode)) { 154 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 155 return (EFAULT); 156 } 157 158 ctlr_info = (cpqary3_ctlr_info_t *) 159 MEM_ZALLOC(sizeof (cpqary3_ctlr_info_t)); 160 161 if (NULL == ctlr_info) { 162 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 163 return (FAILURE); 164 } 165 166 /* 167 * in the driver, board_id is actually subsystem_id 168 */ 169 170 ctlr_info->subsystem_id = cpqary3p->board_id; 171 ctlr_info->bus = cpqary3p->bus; 172 ctlr_info->dev = cpqary3p->dev; 173 ctlr_info->fun = cpqary3p->fun; 174 ctlr_info->num_of_tgts = cpqary3p->num_of_targets; 175 ctlr_info->controller_instance = cpqary3p->instance; 176 177 /* 178 * TODO: ctlr_info.slot_num has to be implemented 179 * state & board_id fields are kept for future implementation i 180 * if required! 181 */ 182 183 /* 184 * First Copy out the ctlr_info structure 185 */ 186 187 if (ddi_copyout((void *)ctlr_info, (void *)(uintptr_t)request->argp, 188 sizeof (cpqary3_ctlr_info_t), mode)) { 189 MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t)); 190 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 191 return (EFAULT); 192 } 193 194 /* 195 * Copy out the request structure back 196 */ 197 198 if (ddi_copyout((void *)request, (void *)ioctl_reqp, 199 sizeof (cpqary3_ioctl_request_t), mode)) { 200 MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t)); 201 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 202 return (EFAULT); 203 } 204 205 MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t)); 206 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 207 208 /* 209 * Everything looks fine. So return SUCCESS 210 */ 211 212 return (SUCCESS); 213 } 214 215 /* 216 * Function : cpqary3_ioctl_bmic_pass 217 * Description : This routine will pass the BMIC commands to controller 218 * Called By : cpqary3_ioctl 219 * Parameters : ioctl_reqp - address of the parameter sent from the 220 * application 221 * cpqary3p - address of the PerController structure 222 * mode - mode which comes directly from application 223 * Return Values: EFAULT on Failure, 0 on SUCCESS 224 */ 225 int32_t 226 cpqary3_ioctl_bmic_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode) 227 { 228 cpqary3_ioctl_request_t *request; 229 cpqary3_bmic_pass_t *bmic_pass; 230 int32_t retval = SUCCESS; 231 232 request = (cpqary3_ioctl_request_t *) 233 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t)); 234 235 if (NULL == request) 236 return (FAILURE); 237 238 /* 239 * First let us copyin the ioctl_reqp(user) buffer to request(kernel) 240 * memory. This is very much recommended before we access any of the 241 * fields. 242 */ 243 244 if (ddi_copyin((void *)ioctl_reqp, (void *)request, 245 sizeof (cpqary3_ioctl_request_t), mode)) { 246 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 247 return (EFAULT); 248 } 249 250 bmic_pass = (cpqary3_bmic_pass_t *) 251 MEM_ZALLOC(sizeof (cpqary3_bmic_pass_t)); 252 253 if (NULL == bmic_pass) { 254 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 255 return (FAILURE); 256 } 257 258 /* 259 * Copy in "cpqary3_bmic_pass_t" structure from argp member 260 * of ioctl_reqp. 261 */ 262 263 if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)bmic_pass, 264 sizeof (cpqary3_bmic_pass_t), mode)) { 265 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t)); 266 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 267 return (EFAULT); 268 } 269 270 /* 271 * Get the free command list, fill in the bmic command and send it 272 * to the controller. This will return 0 on success. 273 */ 274 275 retval = cpqary3_ioctl_send_bmiccmd(cpqary3p, bmic_pass, mode); 276 277 /* 278 * Now copy the bmic_pass (kernel) to the user argp 279 */ 280 281 if (ddi_copyout((void *) bmic_pass, (void *)(uintptr_t)request->argp, 282 sizeof (cpqary3_bmic_pass_t), mode)) { 283 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t)); 284 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 285 retval = EFAULT; /* copyout failed */ 286 } 287 288 /* 289 * Now copy the request(kernel) to ioctl_reqp(user) 290 */ 291 292 if (ddi_copyout((void *) request, (void *)ioctl_reqp, 293 sizeof (cpqary3_ioctl_request_t), mode)) { 294 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t)); 295 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 296 retval = EFAULT; 297 } 298 299 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t)); 300 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 301 302 return (retval); 303 } 304 305 /* 306 * Function : cpqary3_ioctl_send_bmiccmd 307 * Description : This routine will get the free command, 308 * allocate memory and send it to controller. 309 * Called By : cpqary3_ioctl_bmic_pass 310 * Parameters : cpqary3_t - PerController structure 311 * cpqary3_bmic_pass_t - bmic structure 312 * mode - mode value sent from application 313 * Return Values: 0 on success 314 * FAILURE, EFAULT, ETIMEOUT based on the failure 315 */ 316 317 uint32_t cpqary3_ioctl_wait_ms = 30000; 318 319 static int32_t 320 cpqary3_ioctl_send_bmiccmd(cpqary3_t *cpqary3p, 321 cpqary3_bmic_pass_t *bmic_pass, int mode) 322 { 323 cpqary3_cmdpvt_t *memp = NULL; 324 CommandList_t *cmdlist = NULL; 325 int8_t *databuf = NULL; 326 uint8_t retval = 0; 327 328 /* allocate a command with a dma buffer */ 329 memp = cpqary3_synccmd_alloc(cpqary3p, bmic_pass->buf_len); 330 if (memp == NULL) 331 return (FAILURE); 332 333 /* Get the databuf when buf_len is greater than zero */ 334 if (bmic_pass->buf_len > 0) { 335 databuf = memp->driverdata->sg; 336 } 337 338 cmdlist = memp->cmdlist_memaddr; 339 340 /* 341 * If io_direction is CPQARY3_SCSI_OUT, we have to copy user buffer 342 * to databuf 343 */ 344 345 if (bmic_pass->io_direction == CPQARY3_SCSI_OUT) { 346 /* Do a copyin when buf_len is greater than zero */ 347 if (bmic_pass->buf_len > 0) { 348 if (ddi_copyin((void*)(uintptr_t)(bmic_pass->buf), 349 (void*)databuf, bmic_pass->buf_len, mode)) { 350 cpqary3_synccmd_free(cpqary3p, memp); 351 return (EFAULT); 352 } 353 } 354 } 355 356 /* 357 * Now fill the command as per the BMIC 358 */ 359 if (cpqary3p->bddef->bd_flags & SA_BD_SAS) { 360 cpqary3_ioctl_fil_bmic_sas(cmdlist, bmic_pass); 361 } else { 362 cpqary3_ioctl_fil_bmic(cmdlist, bmic_pass); 363 } 364 365 366 /* PERF */ 367 368 memp->complete = cpqary3_synccmd_complete; 369 370 /* PERF */ 371 372 /* send command to controller and wait for a reply */ 373 if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms, 374 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 375 cpqary3_synccmd_free(cpqary3p, memp); 376 return (ETIMEDOUT); 377 } 378 379 /* 380 * Now the command is completed and copy the buffers back 381 * First copy the buffer databuf to bmic_pass.buf 382 * which is used as a buffer before passing the command to the 383 * controller. 384 */ 385 386 if (bmic_pass->io_direction == CPQARY3_SCSI_IN) { 387 /* Do a copyout when buf_len is greater than zero */ 388 if (bmic_pass->buf_len > 0) { 389 if (ddi_copyout((void *)databuf, 390 (void *)(uintptr_t)bmic_pass->buf, 391 bmic_pass->buf_len, mode)) { 392 retval = EFAULT; 393 } 394 } 395 } 396 397 /* 398 * This is case where the command completes with error, 399 * Then tag would have set its 1st(10) bit. 400 */ 401 402 if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) { 403 bmic_pass->err_status = 1; 404 bcopy((caddr_t)memp->errorinfop, &bmic_pass->err_info, 405 sizeof (ErrorInfo_t)); 406 switch (memp->errorinfop->CommandStatus) { 407 case CISS_CMD_DATA_OVERRUN : 408 case CISS_CMD_DATA_UNDERRUN : 409 case CISS_CMD_SUCCESS : 410 case CISS_CMD_TARGET_STATUS : 411 retval = SUCCESS; 412 break; 413 default : 414 retval = EIO; 415 break; 416 } 417 } 418 419 cpqary3_synccmd_free(cpqary3p, memp); 420 421 return (retval); 422 } 423 424 /* 425 * Function : cpqary3_ioctl_fil_bmic 426 * Description : This routine will fill the cmdlist with BMIC details 427 * Called By : cpqary3_ioctl_send_bmiccmd 428 * Parameters : cmdlist - command packet 429 * bmic_pass - bmic structure 430 * Return Values: void 431 */ 432 static void 433 cpqary3_ioctl_fil_bmic(CommandList_t *cmdlist, 434 cpqary3_bmic_pass_t *bmic_pass) 435 { 436 cmdlist->Header.SGTotal = 1; 437 cmdlist->Header.SGList = 1; 438 cmdlist->Request.CDBLen = bmic_pass->cmd_len; 439 cmdlist->Request.Timeout = bmic_pass->timeout; 440 cmdlist->Request.Type.Type = CISS_TYPE_CMD; 441 cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE; 442 443 switch (bmic_pass->io_direction) { 444 case CPQARY3_SCSI_OUT: 445 cmdlist->Request.Type.Direction = CISS_XFER_WRITE; 446 break; 447 case CPQARY3_SCSI_IN: 448 cmdlist->Request.Type.Direction = CISS_XFER_READ; 449 break; 450 case CPQARY3_NODATA_XFER: 451 cmdlist->Request.Type.Direction = CISS_XFER_NONE; 452 break; 453 default: 454 cmdlist->Request.Type.Direction = CISS_XFER_RSVD; 455 break; 456 } 457 458 cmdlist ->Request.CDB[0] = 459 (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27; 460 cmdlist ->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */ 461 462 /* 463 * BMIC Detail - bytes 2[MSB] to 5[LSB] 464 */ 465 466 cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff; 467 cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff; 468 cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff; 469 cmdlist->Request.CDB[5] = bmic_pass->blk_number; 470 471 cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */ 472 473 /* Transfer Length - bytes 7[MSB] to 8[LSB] */ 474 475 cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff; 476 cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff; 477 cmdlist->Request.CDB[9] = 0x00; /* Reserved */ 478 479 /* 480 * Copy the Lun address from the request 481 */ 482 483 bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN), 484 sizeof (LUNAddr_t)); 485 cmdlist->SG[0].Len = bmic_pass->buf_len; 486 } 487 488 /* 489 * Function : cpqary3_ioctl_scsi_pass 490 * Description : This routine will pass the SCSI commands to controller 491 * Called By : cpqary3_ioctl 492 * Parameters : ioctl_reqp - address of the parameter sent 493 * from the application 494 * cpqary3p - Addess of the percontroller stucture 495 * mode - mode which comes directly from application 496 * Return Values: EFAULT on Failure, 0 on SUCCESS 497 */ 498 int32_t 499 cpqary3_ioctl_scsi_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode) 500 { 501 cpqary3_ioctl_request_t *request; 502 cpqary3_scsi_pass_t *scsi_pass; 503 int32_t retval = SUCCESS; 504 505 request = (cpqary3_ioctl_request_t *) 506 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t)); 507 508 if (NULL == request) 509 return (FAILURE); 510 511 /* 512 * First let us copyin the ioctl_reqp(user) buffer to request(kernel) 513 * memory. * This is very much recommended before we access any of 514 * the fields. 515 */ 516 517 if (ddi_copyin((void *)ioctl_reqp, (void *)request, 518 sizeof (cpqary3_ioctl_request_t), mode)) { 519 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 520 return (EFAULT); 521 } 522 523 scsi_pass = (cpqary3_scsi_pass_t *) 524 MEM_ZALLOC(sizeof (cpqary3_scsi_pass_t)); 525 526 if (NULL == scsi_pass) { 527 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 528 return (FAILURE); 529 } 530 531 /* 532 * Copy in "cpqary3_scsi_pass_t" structure from argp member 533 * of ioctl_reqp. 534 */ 535 536 if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)scsi_pass, 537 sizeof (cpqary3_scsi_pass_t), mode)) { 538 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t)); 539 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 540 return (EFAULT); 541 } 542 543 /* 544 * Get the free command list, fill in the scsi command and send it 545 * to the controller. This will return 0 on success. 546 */ 547 548 retval = cpqary3_ioctl_send_scsicmd(cpqary3p, scsi_pass, mode); 549 550 /* 551 * Now copy the scsi_pass (kernel) to the user argp 552 */ 553 554 if (ddi_copyout((void *)scsi_pass, (void *)(uintptr_t)request->argp, 555 sizeof (cpqary3_scsi_pass_t), mode)) { 556 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t)); 557 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 558 retval = EFAULT; /* copyout failed */ 559 } 560 561 /* 562 * Now copy the request(kernel) to ioctl_reqp(user) 563 */ 564 565 if (ddi_copyout((void *)request, (void *)ioctl_reqp, 566 sizeof (cpqary3_ioctl_request_t), mode)) { 567 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t)); 568 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 569 retval = EFAULT; 570 } 571 572 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t)); 573 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t)); 574 575 return (retval); 576 } 577 578 /* 579 * Function : cpqary3_ioctl_send_scsiccmd 580 * Description : This routine will pass the SCSI commands to controller 581 * Called By : cpqary3_ioctl_scsi_pass 582 * Parameters : cpqary3_t - PerController structure, 583 * cpqary3_scsi_pass_t - scsi parameter 584 * mode - sent from the application 585 * Return Values: 0 on success 586 * FAILURE, EFAULT, ETIMEOUT based on the failure 587 */ 588 static int32_t 589 cpqary3_ioctl_send_scsicmd(cpqary3_t *cpqary3p, 590 cpqary3_scsi_pass_t *scsi_pass, int mode) 591 { 592 cpqary3_cmdpvt_t *memp = NULL; 593 CommandList_t *cmdlist = NULL; 594 int8_t *databuf = NULL; 595 uint8_t retval = 0; 596 NoeBuffer *evt; 597 uint16_t drive = 0; 598 599 /* allocate a command with a dma buffer */ 600 memp = cpqary3_synccmd_alloc(cpqary3p, scsi_pass->buf_len); 601 if (memp == NULL) 602 return (FAILURE); 603 604 /* Get the databuf when buf_len is greater than zero */ 605 if (scsi_pass->buf_len > 0) { 606 databuf = memp->driverdata->sg; 607 } 608 609 cmdlist = memp->cmdlist_memaddr; 610 611 if (scsi_pass->io_direction == CPQARY3_SCSI_OUT) { 612 /* Do a copyin when buf_len is greater than zero */ 613 if (scsi_pass->buf_len > 0) { 614 if (ddi_copyin((void*)(uintptr_t)(scsi_pass->buf), 615 (void*)databuf, scsi_pass->buf_len, mode)) { 616 cpqary3_synccmd_free(cpqary3p, memp); 617 return (EFAULT); 618 } 619 } 620 } 621 622 /* 623 * Fill the scsi command 624 */ 625 cpqary3_ioctl_fil_scsi(cmdlist, scsi_pass); 626 627 /* PERF */ 628 memp->complete = cpqary3_synccmd_complete; 629 /* PERF */ 630 631 /* send command to controller and wait for a reply */ 632 if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms, 633 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 634 cpqary3_synccmd_free(cpqary3p, memp); 635 return (ETIMEDOUT); 636 } 637 638 /* 639 * If the command sent is NOE 640 * if the event class is CLASS_LOGICAL_DRIVE 641 * if the subcalls code is zero and if detail change is zero 642 * if the event specific data[3] is either 1 or 2 ie., if 643 * if the logical drive is failed set the target type to 644 * CPQARY3_TARGET_NONE 645 */ 646 647 /* NOE */ 648 if (cpqary3p->noe_support == 0 && 649 cmdlist->Request.CDB[0] == 0x26 && 650 cmdlist->Request.CDB[6] == BMIC_NOTIFY_ON_EVENT) { 651 652 evt = (NoeBuffer*)MEM2DRVPVT(memp)->sg; 653 654 if (evt->event_class_code == CLASS_LOGICAL_DRIVE && 655 evt->event_subclass_code == SUB_CLASS_STATUS && 656 evt->event_detail_code == DETAIL_CHANGE && 657 evt->event_specific_data[3] == 1) { 658 /* LINTED: alignment */ 659 drive = *(uint16_t *)(&evt->event_specific_data[0]); 660 drive = ((drive < CTLR_SCSI_ID) ? 661 drive : drive + CPQARY3_TGT_ALIGNMENT); 662 663 if (cpqary3p && cpqary3p->cpqary3_tgtp[drive]) { 664 cpqary3p->cpqary3_tgtp[drive]->type = 665 CPQARY3_TARGET_NONE; 666 } 667 } 668 } 669 670 /* 671 * Now the command is completed and copy the buffers back 672 * First copy the buffer databuf to scsi_pass->buf 673 * which is used as a buffer before passing the command to the 674 * controller. 675 */ 676 677 if (scsi_pass->io_direction == CPQARY3_SCSI_IN) { 678 if (scsi_pass->buf_len > 0) { 679 if (ddi_copyout((void *)databuf, 680 (void *)(uintptr_t)scsi_pass->buf, 681 scsi_pass->buf_len, mode)) { 682 retval = EFAULT; 683 } 684 } 685 } 686 687 /* 688 * This is case where the command completes with error, 689 * Then tag would have set its 1st(10) bit. 690 */ 691 692 if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) { 693 scsi_pass->err_status = 1; 694 bcopy((caddr_t)memp->errorinfop, &scsi_pass->err_info, 695 sizeof (ErrorInfo_t)); 696 switch (memp->errorinfop->CommandStatus) { 697 case CISS_CMD_DATA_OVERRUN: 698 case CISS_CMD_DATA_UNDERRUN: 699 case CISS_CMD_SUCCESS: 700 case CISS_CMD_TARGET_STATUS: 701 retval = SUCCESS; 702 break; 703 default: 704 retval = EIO; 705 break; 706 } 707 } 708 709 cpqary3_synccmd_free(cpqary3p, memp); 710 711 return (retval); 712 } 713 714 /* 715 * Function : cpqary3_ioctl_fil_scsi_ 716 * Description : This routine will fill the cmdlist with SCSI CDB 717 * Called By : cpqary3_ioctl_send_scsicmd 718 * Parameters : cmdlist - command packet 719 * cpqary3_scsi_pass_t - scsi parameter 720 * Return Values: void 721 */ 722 static void 723 cpqary3_ioctl_fil_scsi(CommandList_t *cmdlist, 724 cpqary3_scsi_pass_t *scsi_pass) 725 { 726 cmdlist->Header.SGTotal = 1; 727 cmdlist->Header.SGList = 1; 728 cmdlist->Request.CDBLen = scsi_pass->cdb_len; 729 cmdlist->Request.Timeout = scsi_pass->timeout; 730 cmdlist->Request.Type.Type = CISS_TYPE_CMD; 731 cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE; 732 733 switch (scsi_pass->io_direction) { 734 case CPQARY3_SCSI_OUT: 735 cmdlist->Request.Type.Direction = CISS_XFER_WRITE; 736 break; 737 case CPQARY3_SCSI_IN: 738 cmdlist->Request.Type.Direction = CISS_XFER_READ; 739 break; 740 case CPQARY3_NODATA_XFER: 741 cmdlist->Request.Type.Direction = CISS_XFER_NONE; 742 break; 743 default: 744 cmdlist->Request.Type.Direction = CISS_XFER_RSVD; 745 break; 746 } 747 748 /* 749 * Copy the SCSI CDB as is 750 */ 751 752 bcopy(&scsi_pass->cdb[0], &cmdlist->Request.CDB[0], 753 scsi_pass->cdb_len); 754 755 /* 756 * Copy the Lun address from the request 757 */ 758 759 bcopy(&scsi_pass->lun_addr[0], &(cmdlist->Header.LUN), 760 sizeof (LUNAddr_t)); 761 762 cmdlist->SG[0].Len = scsi_pass->buf_len; 763 } 764 765 /* 766 * Function : cpqary3_ioctl_fil_bmic_sas 767 * Description : This routine will fill the cmdlist with BMIC details 768 * Called By : cpqary3_ioctl_send_bmiccmd 769 * Parameters : cmdlist - command packet 770 * bmic_pass - bmic structure 771 * Return Values: void 772 */ 773 static void 774 cpqary3_ioctl_fil_bmic_sas(CommandList_t *cmdlist, 775 cpqary3_bmic_pass_t *bmic_pass) 776 { 777 cmdlist->Header.SGTotal = 1; 778 cmdlist->Header.SGList = 1; 779 cmdlist->Request.CDBLen = bmic_pass->cmd_len; 780 cmdlist->Request.Timeout = bmic_pass->timeout; 781 cmdlist->Request.Type.Type = CISS_TYPE_CMD; 782 cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE; 783 784 switch (bmic_pass->io_direction) { 785 case CPQARY3_SCSI_OUT: 786 cmdlist->Request.Type.Direction = CISS_XFER_WRITE; 787 break; 788 case CPQARY3_SCSI_IN: 789 cmdlist->Request.Type.Direction = CISS_XFER_READ; 790 break; 791 case CPQARY3_NODATA_XFER: 792 cmdlist->Request.Type.Direction = CISS_XFER_NONE; 793 break; 794 default: 795 cmdlist->Request.Type.Direction = CISS_XFER_RSVD; 796 break; 797 } 798 799 cmdlist->Request.CDB[0] = 800 (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27; 801 cmdlist->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */ 802 803 /* 804 * BMIC Detail - bytes 2[MSB] to 5[LSB] 805 */ 806 807 cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff; 808 cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff; 809 cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff; 810 cmdlist->Request.CDB[5] = bmic_pass->blk_number; 811 812 cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */ 813 814 /* Transfer Length - bytes 7[MSB] to 8[LSB] */ 815 816 cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff; 817 cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff; 818 cmdlist->Request.CDB[9] = 0x00; /* Reserved */ 819 820 /* Update CDB[2] = LSB bmix_index and CDB[9] = MSB bmic_index */ 821 switch (bmic_pass->cmd) { 822 case HPSAS_ID_PHYSICAL_DRIVE: 823 case HPSAS_TAPE_INQUIRY: 824 case HPSAS_SENSE_MP_STAT: 825 case HPSAS_SET_MP_THRESHOLD: 826 case HPSAS_MP_PARAM_CONTROL: 827 case HPSAS_SENSE_DRV_ERR_LOG: 828 case HPSAS_SET_MP_VALUE: 829 cmdlist -> Request.CDB[2] = bmic_pass->bmic_index & 0xff; 830 cmdlist -> Request.CDB[9] = (bmic_pass->bmic_index >>8) & 0xff; 831 break; 832 833 case HPSAS_ID_LOG_DRIVE: 834 case HPSAS_SENSE_LOG_DRIVE: 835 case HPSAS_READ: 836 case HPSAS_WRITE: 837 case HPSAS_WRITE_THROUGH: 838 case HPSAS_SENSE_CONFIG: 839 case HPSAS_SET_CONFIG: 840 case HPSAS_BYPASS_VOL_STATE: 841 case HPSAS_CHANGE_CONFIG: 842 case HPSAS_SENSE_ORIG_CONFIG: 843 case HPSAS_LABEL_LOG_DRIVE: 844 /* Unit Number MSB */ 845 cmdlist->Request.CDB[9] = (bmic_pass->unit_number >> 8) & 0xff; 846 break; 847 848 default: 849 break; 850 } 851 852 853 /* 854 * Copy the Lun address from the request 855 */ 856 857 bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN), 858 sizeof (LUNAddr_t)); 859 860 cmdlist->SG[0].Len = bmic_pass->buf_len; 861 } 862