Ticket #782: sgio.patch

File sgio.patch, 8.8 KB (added by Alex Samorukov, 7 years ago)

Fixed patch against r4523

  • os_linux.cpp

     
    6363#include <scsi/scsi.h>
    6464#include <scsi/scsi_ioctl.h>
    6565#include <scsi/sg.h>
     66#include <linux/bsg.h>
    6667#include <stdlib.h>
    6768#include <string.h>
    6869#include <sys/ioctl.h>
     
    511512#endif
    512513
    513514#define SG_IO_PRESENT_UNKNOWN 0
    514 #define SG_IO_PRESENT_YES 1
    515515#define SG_IO_PRESENT_NO 2
     516#define SG_IO_PRESENT_V3 3
     517#define SG_IO_PRESENT_V4 4
    516518
    517519static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
    518520                         int unknown);
     521static int sg_io_cmnd_v4(int dev_fd, struct scsi_cmnd_io * iop, int report,
     522                         int unknown);
    519523static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
    520524
    521525static int sg_io_state = SG_IO_PRESENT_UNKNOWN;
     
    524528 * function uses the SG_IO ioctl. Return 0 if command issued successfully
    525529 * (various status values should still be checked). If the SCSI command
    526530 * cannot be issued then a negative errno value is returned. */
     531static 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_v4));
     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. */
    527686static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
    528687                         int unknown)
    529688{
     
    810969    case SG_IO_PRESENT_UNKNOWN:
    811970        /* ignore report argument */
    812971        if (0 == (res = sg_io_cmnd_io(dev_fd, iop, report, 1))) {
    813             sg_io_state = SG_IO_PRESENT_YES;
     972            sg_io_state = SG_IO_PRESENT_V3;
    814973            return 0;
    815974        } else if ((-ENODEV == res) || (-EACCES == res) || (-EPERM == res))
    816975            return res;         /* wait until we see a device */
     976        if (0 == (res = sg_io_cmnd_v4(dev_fd, iop, report, 1))) {
     977            sg_io_state = SG_IO_PRESENT_V4;
     978            return 0;
     979        } else if ((-ENODEV == res) || (-EACCES == res) || (-EPERM == res))
     980            return res;         /* wait until we see a device */
    817981        sg_io_state = SG_IO_PRESENT_NO;
    818982        /* drop through by design */
    819983    case SG_IO_PRESENT_NO:
    820984        return sisc_cmnd_io(dev_fd, iop, report);
    821     case SG_IO_PRESENT_YES:
     985    case SG_IO_PRESENT_V3:
    822986        return sg_io_cmnd_io(dev_fd, iop, report, 0);
     987    case SG_IO_PRESENT_V4:
     988        return sg_io_cmnd_v4(dev_fd, iop, report, 0);
    823989    default:
    824990        pout(">>>> do_scsi_cmnd_io: bad sg_io_state=%d\n", sg_io_state);
    825991        sg_io_state = SG_IO_PRESENT_UNKNOWN;
     
    31993365  if (str_starts_with(test_name, "scsi/"))
    32003366    return new linux_scsi_device(this, name, "");
    32013367
     3368  // form /dev/bsg/* or bsg/*
     3369  if (str_starts_with(test_name, "bsg/"))
     3370    return new linux_scsi_device(this, name, "");
     3371
    32023372  // form /dev/ns* or ns*
    32033373  if (str_starts_with(test_name, "ns"))
    32043374    return new linux_scsi_device(this, name, "");