Commit 1ead6b4e authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

scsi: introduce sg_io_sense_from_errno



Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
reusability.

Reviewed-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent a3760467
Loading
Loading
Loading
Loading
+7 −33
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
{
    int status;
    SCSISense sense;

    assert(r->req.aiocb == NULL);

@@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
        scsi_req_cancel_complete(&r->req);
        goto done;
    }
    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
    if (status == CHECK_CONDITION) {
        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
            r->req.sense_len = r->io_header.sb_len_wr;
    }

    if (ret != 0) {
        switch (ret) {
        case -EDOM:
            status = TASK_SET_FULL;
            break;
        case -ENOMEM:
            status = CHECK_CONDITION;
            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
            break;
        default:
            status = CHECK_CONDITION;
            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
            break;
        }
        } else {
        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
            status = BUSY;
            BADF("Driver Timeout\n");
        } else if (r->io_header.host_status) {
            status = CHECK_CONDITION;
            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
        } else if (r->io_header.status) {
            status = r->io_header.status;
        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
            status = CHECK_CONDITION;
        } else {
            status = GOOD;
            scsi_req_build_sense(&r->req, sense);
        }
    }

    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
            r, r->req.tag, status);

+3 −0
Original line number Diff line number Diff line
@@ -116,6 +116,9 @@ int scsi_cdb_length(uint8_t *buf);
#define SG_ERR_DID_TIME_OUT    0x03

#define SG_ERR_DRIVER_SENSE    0x08

int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
                           SCSISense *sense);
#endif

#endif
+35 −0
Original line number Diff line number Diff line
@@ -501,3 +501,38 @@ const char *scsi_command_name(uint8_t cmd)
    }
    return names[cmd];
}

#ifdef CONFIG_LINUX
int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
                           SCSISense *sense)
{
    if (errno_value != 0) {
        switch (errno_value) {
        case EDOM:
            return TASK_SET_FULL;
        case ENOMEM:
            *sense = SENSE_CODE(TARGET_FAILURE);
            return CHECK_CONDITION;
        default:
            *sense = SENSE_CODE(IO_ERROR);
            return CHECK_CONDITION;
        }
    } else {
        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
            return BUSY;
        } else if (io_hdr->host_status) {
            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
            return CHECK_CONDITION;
        } else if (io_hdr->status) {
            return io_hdr->status;
        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
            return CHECK_CONDITION;
        } else {
            return GOOD;
        }
    }
}
#endif