aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2009-11-26 15:34:02 +0100
committerAnthony Liguori <aliguori@us.ibm.com>2009-12-03 09:41:38 -0600
commitaa5dbdc190644cf36e4e7fbd68b4e40e13209039 (patch)
tree1246232387f24d7792cd2a643f86521cec892f91 /hw
parentec766865633be4a36803fa33ee518c4166cfc459 (diff)
scsi-disk: restruct emulation: core + TEST_UNIT_READY.
Add new scsi_disk_emulate_command() function, which will -- when finished -- handle all scsi disk command emulation except actual I/O (READ+WRITE commands) which goes to the block layer. The function builds on top of the new SCSIRequest struct. SCSI command emulation code is moved over from scsi_send_command() in steps to ease review and make it easier to pin down regressions (if any) using bisect. This patch moves over TEST_UNIT_READY only. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/scsi-disk.c47
1 files changed, 42 insertions, 5 deletions
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index bc8270ce87..f851694a06 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -306,6 +306,31 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
return (uint8_t *)r->iov.iov_base;
}
+static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
+{
+ BlockDriverState *bdrv = req->dev->dinfo->bdrv;
+ int buflen = 0;
+
+ switch (req->cmd.buf[0]) {
+ case TEST_UNIT_READY:
+ if (!bdrv_is_inserted(bdrv))
+ goto not_ready;
+ break;
+ default:
+ goto illegal_request;
+ }
+ scsi_req_set_status(req, GOOD, NO_SENSE);
+ return buflen;
+
+not_ready:
+ scsi_req_set_status(req, CHECK_CONDITION, NOT_READY);
+ return 0;
+
+illegal_request:
+ scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST);
+ return 0;
+}
+
/* Execute a scsi command. Returns the length of the data expected by the
command. This will be Positive for data transfers from the device
(eg. disk reads), negative for transfers to the device (eg. disk writes),
@@ -323,6 +348,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
uint8_t command;
uint8_t *outbuf;
SCSIDiskReq *r;
+ int rc;
command = buf[0];
r = scsi_find_request(s, tag);
@@ -377,6 +403,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
printf("\n");
}
#endif
+
+ if (scsi_req_parse(&r->req, buf) != 0) {
+ BADF("Unsupported command length, command %x\n", command);
+ goto fail;
+ }
+ assert(r->req.cmd.len == cmdlen);
+ assert(r->req.cmd.lba == lba);
+
if (lun || buf[1] >> 5) {
/* Only LUN 0 supported. */
DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
@@ -385,10 +419,14 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
}
switch (command) {
case TEST_UNIT_READY:
- DPRINTF("Test Unit Ready\n");
- if (!bdrv_is_inserted(s->qdev.dinfo->bdrv))
- goto notready;
- break;
+ rc = scsi_disk_emulate_command(&r->req, outbuf);
+ if (rc > 0) {
+ r->iov.iov_len = rc;
+ } else {
+ scsi_req_complete(&r->req);
+ scsi_remove_request(r);
+ }
+ return rc;
case REQUEST_SENSE:
DPRINTF("Request Sense (len %d)\n", len);
if (len < 4)
@@ -761,7 +799,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
outbuf[7] = 0;
r->iov.iov_len = 8;
} else {
- notready:
scsi_command_complete(r, CHECK_CONDITION, NOT_READY);
return 0;
}