| | 531 | static int sg_io_cmnd_v4(int dev_fd, struct scsi_cmnd_io * iop, int report, |
| | 532 | int unknown) |
| | 533 | { |
| | 534 | #ifndef SG_IO |
| | 535 | ARGUSED(dev_fd); ARGUSED(iop); ARGUSED(report); |
| | 536 | return -ENOTTY; |
| | 537 | #else |
| | 538 | struct sg_io_v4 io_hdr; |
| | 539 | |
| | 540 | if (report > 0) { |
| | 541 | int k, j; |
| | 542 | const unsigned char * ucp = iop->cmnd; |
| | 543 | const char * np; |
| | 544 | char buff[256]; |
| | 545 | const int sz = (int)sizeof(buff); |
| | 546 | |
| | 547 | np = scsi_get_opcode_name(ucp[0]); |
| | 548 | j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); |
| | 549 | for (k = 0; k < (int)iop->cmnd_len; ++k) |
| | 550 | j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); |
| | 551 | if ((report > 1) && |
| | 552 | (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { |
| | 553 | int trunc = (iop->dxfer_len > 256) ? 1 : 0; |
| | 554 | |
| | 555 | snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " |
| | 556 | "data, len=%d%s:\n", (int)iop->dxfer_len, |
| | 557 | (trunc ? " [only first 256 bytes shown]" : "")); |
| | 558 | dStrHex((const char *)iop->dxferp, |
| | 559 | (trunc ? 256 : iop->dxfer_len) , 1); |
| | 560 | } |
| | 561 | else |
| | 562 | snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); |
| | 563 | pout("%s", buff); |
| | 564 | } |
| | 565 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); |
| | 566 | io_hdr.guard = 'Q'; |
| | 567 | io_hdr.request_len = iop->cmnd_len; |
| | 568 | io_hdr.request = __u64(iop->cmnd); |
| | 569 | io_hdr.max_response_len = iop->max_sense_len; |
| | 570 | io_hdr.response = __u64(iop->sensep); |
| | 571 | /* sg_io_hdr interface timeout has millisecond units. Timeout of 0 |
| | 572 | defaults to 60 seconds. */ |
| | 573 | io_hdr.timeout = ((0 == iop->timeout) ? 60 : iop->timeout) * 1000; |
| | 574 | switch (iop->dxfer_dir) { |
| | 575 | case DXFER_NONE: |
| | 576 | break; |
| | 577 | case DXFER_FROM_DEVICE: |
| | 578 | io_hdr.din_xfer_len = iop->dxfer_len; |
| | 579 | io_hdr.din_xferp = __u64(iop->dxferp); |
| | 580 | break; |
| | 581 | case DXFER_TO_DEVICE: |
| | 582 | io_hdr.dout_xfer_len = iop->dxfer_len; |
| | 583 | io_hdr.dout_xferp = __u64(iop->dxferp); |
| | 584 | break; |
| | 585 | default: |
| | 586 | pout("do_scsi_cmnd_v4: bad dxfer_dir\n"); |
| | 587 | return -EINVAL; |
| | 588 | } |
| | 589 | iop->resp_sense_len = 0; |
| | 590 | iop->scsi_status = 0; |
| | 591 | iop->resid = 0; |
| | 592 | if (ioctl(dev_fd, SG_IO, &io_hdr) < 0) { |
| | 593 | if (report && (! unknown)) |
| | 594 | pout(" SG_IO ioctl failed, errno=%d [%s]\n", errno, |
| | 595 | strerror(errno)); |
| | 596 | return -errno; |
| | 597 | } |
| | 598 | switch (iop->dxfer_dir) { |
| | 599 | case DXFER_NONE: |
| | 600 | iop->resid = 0; |
| | 601 | break; |
| | 602 | case DXFER_FROM_DEVICE: |
| | 603 | iop->resid = io_hdr.din_resid; |
| | 604 | break; |
| | 605 | case DXFER_TO_DEVICE: |
| | 606 | iop->resid = io_hdr.dout_resid; |
| | 607 | break; |
| | 608 | } |
| | 609 | iop->scsi_status = io_hdr.device_status; |
| | 610 | if (report > 0) { |
| | 611 | pout(" scsi_status=0x%x, host_status=0x%x, driver_status=0x%x\n" |
| | 612 | " info=0x%x duration=%d milliseconds resid=%d\n", io_hdr.device_status, |
| | 613 | io_hdr.transport_status, io_hdr.driver_status, io_hdr.info, |
| | 614 | io_hdr.duration, iop->resid); |
| | 615 | if (report > 1) { |
| | 616 | if (DXFER_FROM_DEVICE == iop->dxfer_dir) { |
| | 617 | int trunc, len; |
| | 618 | |
| | 619 | len = iop->dxfer_len - iop->resid; |
| | 620 | trunc = (len > 256) ? 1 : 0; |
| | 621 | if (len > 0) { |
| | 622 | pout(" Incoming data, len=%d%s:\n", len, |
| | 623 | (trunc ? " [only first 256 bytes shown]" : "")); |
| | 624 | dStrHex((const char*)iop->dxferp, (trunc ? 256 : len), |
| | 625 | 1); |
| | 626 | } else |
| | 627 | pout(" Incoming data trimmed to nothing by resid\n"); |
| | 628 | } |
| | 629 | } |
| | 630 | } |
| | 631 | |
| | 632 | if (io_hdr.info & SG_INFO_CHECK) { /* error or warning */ |
| | 633 | int masked_driver_status = (LSCSI_DRIVER_MASK & io_hdr.driver_status); |
| | 634 | |
| | 635 | if (0 != io_hdr.transport_status) { |
| | 636 | if ((LSCSI_DID_NO_CONNECT == io_hdr.transport_status) || |
| | 637 | (LSCSI_DID_BUS_BUSY == io_hdr.transport_status) || |
| | 638 | (LSCSI_DID_TIME_OUT == io_hdr.transport_status)) |
| | 639 | return -ETIMEDOUT; |
| | 640 | else |
| | 641 | /* Check for DID_ERROR - workaround for aacraid driver quirk */ |
| | 642 | if (LSCSI_DID_ERROR != io_hdr.transport_status) { |
| | 643 | return -EIO; /* catch all if not DID_ERR */ |
| | 644 | } |
| | 645 | } |
| | 646 | if (0 != masked_driver_status) { |
| | 647 | if (LSCSI_DRIVER_TIMEOUT == masked_driver_status) |
| | 648 | return -ETIMEDOUT; |
| | 649 | else if (LSCSI_DRIVER_SENSE != masked_driver_status) |
| | 650 | return -EIO; |
| | 651 | } |
| | 652 | if (LSCSI_DRIVER_SENSE == masked_driver_status) |
| | 653 | iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; |
| | 654 | iop->resp_sense_len = io_hdr.response_len; |
| | 655 | if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) && |
| | 656 | iop->sensep && (iop->resp_sense_len > 0)) { |
| | 657 | if (report > 1) { |
| | 658 | pout(" >>> Sense buffer, len=%d:\n", |
| | 659 | (int)iop->resp_sense_len); |
| | 660 | dStrHex((const char *)iop->sensep, iop->resp_sense_len , 1); |
| | 661 | } |
| | 662 | } |
| | 663 | if (report) { |
| | 664 | if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status && iop->sensep) { |
| | 665 | if ((iop->sensep[0] & 0x7f) > 0x71) |
| | 666 | pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", |
| | 667 | iop->scsi_status, iop->sensep[1] & 0xf, |
| | 668 | iop->sensep[2], iop->sensep[3]); |
| | 669 | else |
| | 670 | pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", |
| | 671 | iop->scsi_status, iop->sensep[2] & 0xf, |
| | 672 | iop->sensep[12], iop->sensep[13]); |
| | 673 | } |
| | 674 | else |
| | 675 | pout(" status=0x%x\n", iop->scsi_status); |
| | 676 | } |
| | 677 | } |
| | 678 | return 0; |
| | 679 | #endif |
| | 680 | } |
| | 681 | |
| | 682 | /* Preferred implementation for issuing SCSI commands in linux. This |
| | 683 | * function uses the SG_IO ioctl. Return 0 if command issued successfully |
| | 684 | * (various status values should still be checked). If the SCSI command |
| | 685 | * cannot be issued then a negative errno value is returned. */ |