Пример #1
0
static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
                           uint8_t *data, int sz)
{
    int rq_servact = cdb[1];
    struct prin_resp resp;
    size_t written;
    int r;

    switch (rq_servact) {
    case MPATH_PRIN_RKEY_SA:
    case MPATH_PRIN_RRES_SA:
    case MPATH_PRIN_RCAP_SA:
        break;
    case MPATH_PRIN_RFSTAT_SA:
        /* Nobody implements it anyway, so bail out. */
    default:
        /* Cannot parse any other output.  */
        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
        return CHECK_CONDITION;
    }

    r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose);
    if (r == MPATH_PR_SUCCESS) {
        switch (rq_servact) {
        case MPATH_PRIN_RKEY_SA:
        case MPATH_PRIN_RRES_SA: {
            struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys;
            assert(sz >= 8);
            written = MIN(out->additional_length + 8, sz);
            stl_be_p(&data[0], out->prgeneration);
            stl_be_p(&data[4], out->additional_length);
            memcpy(&data[8], out->key_list, written - 8);
            break;
        }
        case MPATH_PRIN_RCAP_SA: {
            struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap;
            assert(sz >= 6);
            written = 6;
            stw_be_p(&data[0], out->length);
            data[2] = out->flags[0];
            data[3] = out->flags[1];
            stw_be_p(&data[4], out->pr_type_mask);
            break;
        }
        default:
            scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
            return CHECK_CONDITION;
        }
        assert(written <= sz);
        memset(data + written, 0, sz - written);
    }

    return mpath_reconstruct_sense(fd, r, sense);
}
Пример #2
0
/* Helper function for command completion.  */
static void scsi_command_complete(void *opaque, int ret)
{
    int status;
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;

    r->req.aiocb = NULL;
    if (r->req.io_canceled) {
        scsi_req_cancel_complete(&r->req);
        goto done;
    }
    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;
        }
    }
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
            r, r->req.tag, status);

    scsi_req_complete(&r->req, status);
done:
    scsi_req_unref(&r->req);
}
Пример #3
0
static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
{
    switch (r) {
    case MPATH_PR_SUCCESS:
        return GOOD;
    case MPATH_PR_SENSE_NOT_READY:
    case MPATH_PR_SENSE_MEDIUM_ERROR:
    case MPATH_PR_SENSE_HARDWARE_ERROR:
    case MPATH_PR_SENSE_ABORTED_COMMAND:
        {
            /* libmpathpersist ate the exact sense.  Try to find it by
             * issuing TEST UNIT READY.
             */
            uint8_t cdb[6] = { TEST_UNIT_READY };
            int sz = 0;
            int r = do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE);

            if (r != GOOD) {
                return r;
            }
            scsi_build_sense(sense, mpath_generic_sense(r));
            return CHECK_CONDITION;
        }

    case MPATH_PR_SENSE_UNIT_ATTENTION:
        /* Congratulations libmpathpersist, you ruined the Unit Attention...
         * Return a heavyweight one.
         */
        scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET));
        return CHECK_CONDITION;
    case MPATH_PR_SENSE_INVALID_OP:
        /* Only one valid sense.  */
        scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
        return CHECK_CONDITION;
    case MPATH_PR_ILLEGAL_REQ:
        /* Guess.  */
        scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
        return CHECK_CONDITION;
    case MPATH_PR_NO_SENSE:
        scsi_build_sense(sense, SENSE_CODE(NO_SENSE));
        return CHECK_CONDITION;

    case MPATH_PR_RESERV_CONFLICT:
        return RESERVATION_CONFLICT;

    case MPATH_PR_OTHER:
    default:
        scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE));
        return CHECK_CONDITION;
    }
}
Пример #4
0
static SCSISense mpath_generic_sense(int r)
{
    switch (r) {
    case MPATH_PR_SENSE_NOT_READY:
         return SENSE_CODE(NOT_READY);
    case MPATH_PR_SENSE_MEDIUM_ERROR:
         return SENSE_CODE(READ_ERROR);
    case MPATH_PR_SENSE_HARDWARE_ERROR:
         return SENSE_CODE(TARGET_FAILURE);
    case MPATH_PR_SENSE_ABORTED_COMMAND:
         return SENSE_CODE(IO_ERROR);
    default:
         abort();
    }
}
Пример #5
0
/* Helper function for command completion.  */
static void scsi_command_complete(void *opaque, int ret)
{
    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);

    r->req.aiocb = NULL;
    s->driver_status = r->io_header.driver_status;
    if (s->driver_status & SG_ERR_DRIVER_SENSE)
        s->senselen = r->io_header.sb_len_wr;

    if (ret != 0) {
        switch (ret) {
        case -EDOM:
            r->req.status = TASK_SET_FULL;
            break;
        case -EINVAL:
            r->req.status = CHECK_CONDITION;
            scsi_set_sense(s, SENSE_CODE(INVALID_FIELD));
            break;
        case -ENOMEM:
            r->req.status = CHECK_CONDITION;
            scsi_set_sense(s, SENSE_CODE(TARGET_FAILURE));
            break;
        default:
            r->req.status = CHECK_CONDITION;
            scsi_set_sense(s, SENSE_CODE(IO_ERROR));
            break;
        }
    } else {
        if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
            r->req.status = BUSY;
            BADF("Driver Timeout\n");
        } else if (r->io_header.status)
            r->req.status = r->io_header.status;
        else if (s->driver_status & SG_ERR_DRIVER_SENSE)
            r->req.status = CHECK_CONDITION;
        else
            r->req.status = GOOD;
    }
    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
            r, r->req.tag, r->req.status);

    scsi_req_complete(&r->req);
}
Пример #6
0
static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
{
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
    int size = SCSI_SENSE_BUF_SIZE;

    if (!(s->driver_status & SG_ERR_DRIVER_SENSE)) {
        size = scsi_build_sense(SENSE_CODE(NO_SENSE), s->sensebuf,
                                SCSI_SENSE_BUF_SIZE, 0);
    }
    if (size > len) {
        size = len;
    }
    memcpy(outbuf, s->sensebuf, size);

    return size;
}
Пример #7
0
static void scsi_generic_reset(DeviceState *dev)
{
    SCSIDevice *s = SCSI_DEVICE(dev);

    scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
Пример #8
0
static void scsi_destroy(SCSIDevice *s)
{
    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
    blockdev_mark_auto_del(s->conf.bs);
}
Пример #9
0
static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
                            const uint8_t *param, int sz)
{
    int rq_servact = cdb[1];
    int rq_scope = cdb[2] >> 4;
    int rq_type = cdb[2] & 0xf;
    struct prout_param_descriptor paramp;
    char transportids[PR_HELPER_DATA_SIZE];
    int r;

    if (sz < PR_OUT_FIXED_PARAM_SIZE) {
        /* Illegal request, Parameter list length error.  This isn't fatal;
         * we have read the data, send an error without closing the socket.
         */
        scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN));
        return CHECK_CONDITION;
    }

    switch (rq_servact) {
    case MPATH_PROUT_REG_SA:
    case MPATH_PROUT_RES_SA:
    case MPATH_PROUT_REL_SA:
    case MPATH_PROUT_CLEAR_SA:
    case MPATH_PROUT_PREE_SA:
    case MPATH_PROUT_PREE_AB_SA:
    case MPATH_PROUT_REG_IGN_SA:
        break;
    case MPATH_PROUT_REG_MOV_SA:
        /* Not supported by struct prout_param_descriptor.  */
    default:
        /* Cannot parse any other input.  */
        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
        return CHECK_CONDITION;
    }

    /* Convert input data, especially transport IDs, to the structs
     * used by libmpathpersist (which, of course, will immediately
     * do the opposite).
     */
    memset(&paramp, 0, sizeof(paramp));
    memcpy(&paramp.key, &param[0], 8);
    memcpy(&paramp.sa_key, &param[8], 8);
    paramp.sa_flags = param[20];
    if (sz > PR_OUT_FIXED_PARAM_SIZE) {
        size_t transportid_len;
        int i, j;
        if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) {
            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN));
            return CHECK_CONDITION;
        }
        transportid_len = ldl_be_p(&param[24]) + PR_OUT_FIXED_PARAM_SIZE + 4;
        if (transportid_len > sz) {
            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
            return CHECK_CONDITION;
        }
        for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) {
            struct transportid *id = (struct transportid *) &transportids[j];
            int len;

            id->format_code = param[i] & 0xc0;
            id->protocol_id = param[i] & 0x0f;
            switch (param[i] & 0xcf) {
            case 0:
                /* FC transport.  */
                if (i + 24 > transportid_len) {
                    goto illegal_req;
                }
                memcpy(id->n_port_name, &param[i + 8], 8);
                j += offsetof(struct transportid, n_port_name[8]);
                i += 24;
                break;
            case 5:
            case 0x45:
                /* iSCSI transport.  */
                len = lduw_be_p(&param[i + 2]);
                if (len > 252 || (len & 3) || i + len + 4 > transportid_len) {
                    /* For format code 00, the standard says the maximum is 223
                     * plus the NUL terminator.  For format code 01 there is no
                     * maximum length, but libmpathpersist ignores the first
                     * byte of id->iscsi_name so our maximum is 252.
                     */
                    goto illegal_req;
                }
                if (memchr(&param[i + 4], 0, len) == NULL) {
                    goto illegal_req;
                }
                memcpy(id->iscsi_name, &param[i + 2], len + 2);
                j += offsetof(struct transportid, iscsi_name[len + 2]);
                i += len + 4;
                break;
            case 6:
                /* SAS transport.  */
                if (i + 24 > transportid_len) {
                    goto illegal_req;
                }
                memcpy(id->sas_address, &param[i + 4], 8);
                j += offsetof(struct transportid, sas_address[8]);
                i += 24;
                break;
            default:
            illegal_req:
                scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
                return CHECK_CONDITION;
            }

            paramp.trnptid_list[paramp.num_transportid++] = id;
        }
    }
Пример #10
0
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
{
    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
    int ret;

    if (cmd[0] != REQUEST_SENSE && req->lun != s->lun) {
        DPRINTF("Unimplemented LUN %d\n", req->lun);
        scsi_set_sense(s, SENSE_CODE(LUN_NOT_SUPPORTED));
        r->req.status = CHECK_CONDITION;
        scsi_req_complete(&r->req);
        return 0;
    }

    if (-1 == scsi_req_parse(&r->req, cmd)) {
        BADF("Unsupported command length, command %x\n", cmd[0]);
        scsi_command_complete(r, -EINVAL);
        return 0;
    }
    scsi_req_fixup(&r->req);

    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
            r->req.cmd.xfer, cmd[0]);

#ifdef DEBUG_SCSI
    {
        int i;
        for (i = 1; i < r->req.cmd.len; i++) {
            printf(" 0x%02x", cmd[i]);
        }
        printf("\n");
    }
#endif

    if (r->req.cmd.xfer == 0) {
        if (r->buf != NULL)
            qemu_free(r->buf);
        r->buflen = 0;
        r->buf = NULL;
        ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
        if (ret < 0) {
            scsi_command_complete(r, ret);
            return 0;
        }
        return 0;
    }

    if (r->buflen != r->req.cmd.xfer) {
        if (r->buf != NULL)
            qemu_free(r->buf);
        r->buf = qemu_malloc(r->req.cmd.xfer);
        r->buflen = r->req.cmd.xfer;
    }

    memset(r->buf, 0, r->buflen);
    r->len = r->req.cmd.xfer;
    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
        r->len = 0;
        return -r->req.cmd.xfer;
    } else {
        return r->req.cmd.xfer;
    }
}
Пример #11
0
static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
{
    scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
    scsi_req_complete(req, CHECK_CONDITION);
    return 0;
}
Пример #12
0
static void scsi_unrealize(SCSIDevice *s, Error **errp)
{
    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
    blockdev_mark_auto_del(s->conf.blk);
}