mirror of https://gitee.com/openkylin/qemu.git
scsi-disk: split scsi-disk reqops
Only checks for present medium were still done in scsi_send_command for emulated commands. So move those to scsi_disk_emulate_command and return different SCSIReqOps depending on the kind of command. Checks for present medium can be done unconditionally for the scsi_disk_dma_reqops case. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
101aa85f98
commit
b08d0ea044
191
hw/scsi-disk.c
191
hw/scsi-disk.c
|
@ -1262,14 +1262,39 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||||
{
|
{
|
||||||
SCSIRequest *req = &r->req;
|
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
uint8_t *outbuf;
|
uint8_t *outbuf;
|
||||||
int buflen = 0;
|
int buflen = 0;
|
||||||
|
|
||||||
|
switch (req->cmd.buf[0]) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(req->cmd.mode != SCSI_XFER_TO_DEV);
|
||||||
if (!r->iov.iov_base) {
|
if (!r->iov.iov_base) {
|
||||||
/*
|
/*
|
||||||
* FIXME: we shouldn't return anything bigger than 4k, but the code
|
* FIXME: we shouldn't return anything bigger than 4k, but the code
|
||||||
|
@ -1332,7 +1357,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
||||||
break;
|
break;
|
||||||
case START_STOP:
|
case START_STOP:
|
||||||
if (scsi_disk_emulate_start_stop(r) < 0) {
|
if (scsi_disk_emulate_start_stop(r) < 0) {
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ALLOW_MEDIUM_REMOVAL:
|
case ALLOW_MEDIUM_REMOVAL:
|
||||||
|
@ -1503,18 +1528,23 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
|
||||||
scsi_aio_complete, r);
|
scsi_aio_complete, r);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
|
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||||
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
assert(r->sector_count == 0);
|
assert(!r->req.aiocb && r->sector_count == 0);
|
||||||
buflen = MIN(buflen, req->cmd.xfer);
|
r->iov.iov_len = MIN(buflen, req->cmd.xfer);
|
||||||
return buflen;
|
r->sector_count = -1;
|
||||||
|
if (r->iov.iov_len == 0) {
|
||||||
|
scsi_req_complete(&r->req, GOOD);
|
||||||
|
}
|
||||||
|
return r->iov.iov_len;
|
||||||
|
|
||||||
illegal_request:
|
illegal_request:
|
||||||
if (r->req.status == -1) {
|
if (r->req.status == -1) {
|
||||||
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||||
}
|
}
|
||||||
return -1;
|
return 0;
|
||||||
|
|
||||||
illegal_lba:
|
illegal_lba:
|
||||||
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||||
|
@ -1526,49 +1556,18 @@ illegal_lba:
|
||||||
(eg. disk reads), negative for transfers to the device (eg. disk writes),
|
(eg. disk reads), negative for transfers to the device (eg. disk writes),
|
||||||
and zero if the command does not transfer any data. */
|
and zero if the command does not transfer any data. */
|
||||||
|
|
||||||
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||||
{
|
{
|
||||||
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
int32_t len;
|
int32_t len;
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
int rc;
|
|
||||||
|
|
||||||
command = buf[0];
|
command = buf[0];
|
||||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
|
|
||||||
|
|
||||||
#ifdef DEBUG_SCSI
|
if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
|
||||||
{
|
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
|
||||||
int i;
|
return 0;
|
||||||
for (i = 1; i < r->req.cmd.len; i++) {
|
|
||||||
printf(" 0x%02x", buf[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
#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) {
|
switch (command) {
|
||||||
|
@ -1605,30 +1604,19 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||||
r->sector_count = len * (s->qdev.blocksize / 512);
|
r->sector_count = len * (s->qdev.blocksize / 512);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rc = scsi_disk_emulate_command(r);
|
abort();
|
||||||
if (rc < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (r->req.aiocb) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
r->iov.iov_len = rc;
|
|
||||||
break;
|
|
||||||
illegal_lba:
|
illegal_lba:
|
||||||
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (r->sector_count == 0 && r->iov.iov_len == 0) {
|
if (r->sector_count == 0) {
|
||||||
scsi_req_complete(&r->req, GOOD);
|
scsi_req_complete(&r->req, GOOD);
|
||||||
}
|
}
|
||||||
len = r->sector_count * 512 + r->iov.iov_len;
|
assert(r->iov.iov_len == 0);
|
||||||
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
||||||
return -len;
|
return -r->sector_count * 512;
|
||||||
} else {
|
} else {
|
||||||
if (!r->sector_count) {
|
return r->sector_count * 512;
|
||||||
r->sector_count = -1;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1793,10 +1781,19 @@ static int scsi_disk_initfn(SCSIDevice *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const SCSIReqOps scsi_disk_reqops = {
|
static const SCSIReqOps scsi_disk_emulate_reqops = {
|
||||||
.size = sizeof(SCSIDiskReq),
|
.size = sizeof(SCSIDiskReq),
|
||||||
.free_req = scsi_free_request,
|
.free_req = scsi_free_request,
|
||||||
.send_command = scsi_send_command,
|
.send_command = scsi_disk_emulate_command,
|
||||||
|
.read_data = scsi_read_data,
|
||||||
|
.write_data = scsi_write_data,
|
||||||
|
.get_buf = scsi_get_buf,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const SCSIReqOps scsi_disk_dma_reqops = {
|
||||||
|
.size = sizeof(SCSIDiskReq),
|
||||||
|
.free_req = scsi_free_request,
|
||||||
|
.send_command = scsi_disk_dma_command,
|
||||||
.read_data = scsi_read_data,
|
.read_data = scsi_read_data,
|
||||||
.write_data = scsi_write_data,
|
.write_data = scsi_write_data,
|
||||||
.cancel_io = scsi_cancel_io,
|
.cancel_io = scsi_cancel_io,
|
||||||
|
@ -1805,13 +1802,72 @@ static const SCSIReqOps scsi_disk_reqops = {
|
||||||
.save_request = scsi_disk_save_request,
|
.save_request = scsi_disk_save_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
|
||||||
|
[TEST_UNIT_READY] = &scsi_disk_emulate_reqops,
|
||||||
|
[INQUIRY] = &scsi_disk_emulate_reqops,
|
||||||
|
[MODE_SENSE] = &scsi_disk_emulate_reqops,
|
||||||
|
[MODE_SENSE_10] = &scsi_disk_emulate_reqops,
|
||||||
|
[START_STOP] = &scsi_disk_emulate_reqops,
|
||||||
|
[ALLOW_MEDIUM_REMOVAL] = &scsi_disk_emulate_reqops,
|
||||||
|
[READ_CAPACITY_10] = &scsi_disk_emulate_reqops,
|
||||||
|
[READ_TOC] = &scsi_disk_emulate_reqops,
|
||||||
|
[READ_DVD_STRUCTURE] = &scsi_disk_emulate_reqops,
|
||||||
|
[READ_DISC_INFORMATION] = &scsi_disk_emulate_reqops,
|
||||||
|
[GET_CONFIGURATION] = &scsi_disk_emulate_reqops,
|
||||||
|
[GET_EVENT_STATUS_NOTIFICATION] = &scsi_disk_emulate_reqops,
|
||||||
|
[MECHANISM_STATUS] = &scsi_disk_emulate_reqops,
|
||||||
|
[SERVICE_ACTION_IN_16] = &scsi_disk_emulate_reqops,
|
||||||
|
[REQUEST_SENSE] = &scsi_disk_emulate_reqops,
|
||||||
|
[SYNCHRONIZE_CACHE] = &scsi_disk_emulate_reqops,
|
||||||
|
[SEEK_10] = &scsi_disk_emulate_reqops,
|
||||||
|
#if 0
|
||||||
|
[MODE_SELECT] = &scsi_disk_emulate_reqops,
|
||||||
|
[MODE_SELECT_10] = &scsi_disk_emulate_reqops,
|
||||||
|
#endif
|
||||||
|
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
|
||||||
|
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
|
||||||
|
|
||||||
|
[READ_6] = &scsi_disk_dma_reqops,
|
||||||
|
[READ_10] = &scsi_disk_dma_reqops,
|
||||||
|
[READ_12] = &scsi_disk_dma_reqops,
|
||||||
|
[READ_16] = &scsi_disk_dma_reqops,
|
||||||
|
[VERIFY_10] = &scsi_disk_dma_reqops,
|
||||||
|
[VERIFY_12] = &scsi_disk_dma_reqops,
|
||||||
|
[VERIFY_16] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_6] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_10] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_12] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_16] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_VERIFY_10] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_VERIFY_12] = &scsi_disk_dma_reqops,
|
||||||
|
[WRITE_VERIFY_16] = &scsi_disk_dma_reqops,
|
||||||
|
};
|
||||||
|
|
||||||
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||||
uint8_t *buf, void *hba_private)
|
uint8_t *buf, void *hba_private)
|
||||||
{
|
{
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
|
||||||
SCSIRequest *req;
|
SCSIRequest *req;
|
||||||
|
const SCSIReqOps *ops;
|
||||||
|
uint8_t command;
|
||||||
|
|
||||||
req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
|
#ifdef DEBUG_SCSI
|
||||||
|
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, buf[0]);
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < r->req.cmd.len; i++) {
|
||||||
|
printf(" 0x%02x", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
command = buf[0];
|
||||||
|
ops = scsi_disk_reqops_dispatch[command];
|
||||||
|
if (!ops) {
|
||||||
|
ops = &scsi_disk_emulate_reqops;
|
||||||
|
}
|
||||||
|
req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1925,15 +1981,14 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
||||||
* unreliable, too. It is even possible that reads deliver random data
|
* unreliable, too. It is even possible that reads deliver random data
|
||||||
* from the host page cache (this is probably a Linux bug).
|
* from the host page cache (this is probably a Linux bug).
|
||||||
*
|
*
|
||||||
* We might use scsi_disk_reqops as long as no writing commands are
|
* We might use scsi_disk_dma_reqops as long as no writing commands are
|
||||||
* seen, but performance usually isn't paramount on optical media. So,
|
* seen, but performance usually isn't paramount on optical media. So,
|
||||||
* just make scsi-block operate the same as scsi-generic for them.
|
* just make scsi-block operate the same as scsi-generic for them.
|
||||||
*/
|
*/
|
||||||
if (s->qdev.type == TYPE_ROM) {
|
if (s->qdev.type != TYPE_ROM) {
|
||||||
break;
|
return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun,
|
||||||
}
|
hba_private);
|
||||||
return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun,
|
}
|
||||||
hba_private);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
|
return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
|
||||||
|
|
Loading…
Reference in New Issue