Commit 9bcaf4fe authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

scsi-cd: check ready condition before processing several commands



This commit is more or less obvious.  What it caused is less obvious:
SCSI CD drives failed to eject under Linux, though for example the
"change" command worked okay.  This happens because of the autoclose
option in the Linux CD-ROM driver.

The actual chain of events is quite complex and somehow involves
udev helpers; the actual command that matters is READ TOC, though
honestly it's not really clear to me how because it should always be
invoked after autoclose, not before.

Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 7725d146
Loading
Loading
Loading
Loading
+29 −13
Original line number Diff line number Diff line
@@ -1152,9 +1152,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
    outbuf = r->iov.iov_base;
    switch (req->cmd.buf[0]) {
    case TEST_UNIT_READY:
        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
            goto not_ready;
        }
        assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs));
        break;
    case INQUIRY:
        buflen = scsi_disk_emulate_inquiry(req, outbuf);
@@ -1209,7 +1207,8 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
        memset(outbuf, 0, 8);
        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
        if (!nb_sectors) {
            goto not_ready;
            scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
            return -1;
        }
        if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
            goto illegal_request;
@@ -1269,7 +1268,8 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
            memset(outbuf, 0, req->cmd.xfer);
            bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
            if (!nb_sectors) {
                goto not_ready;
                scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
                return -1;
            }
            if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
                goto illegal_request;
@@ -1314,14 +1314,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
    buflen = MIN(buflen, req->cmd.xfer);
    return buflen;

not_ready:
    if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
    } else {
        scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
    }
    return -1;

illegal_request:
    if (r->req.status == -1) {
        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
@@ -1355,6 +1347,30 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
    }
#endif

    switch (command) {
    case INQUIRY:
    case MODE_SENSE:
    case MODE_SENSE_10:
    case RESERVE:
    case RESERVE_10:
    case RELEASE:
    case RELEASE_10:
    case START_STOP:
    case ALLOW_MEDIUM_REMOVAL:
    case GET_CONFIGURATION:
    case GET_EVENT_STATUS_NOTIFICATION:
    case MECHANISM_STATUS:
    case REQUEST_SENSE:
        break;

    default:
        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
            return 0;
        }
        break;
    }

    switch (command) {
    case TEST_UNIT_READY:
    case INQUIRY: