aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi-disk.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-11-14 08:50:45 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2012-11-14 08:50:45 -0600
commit5f580e9411a24b7decc07013edeb8abf8d5ae25c (patch)
treeb5f0120fc2acc4080d09ecd903c647b4e8140bbd /hw/scsi-disk.c
parentce5e5b522e8d3b848b6445c34226b69c77c46403 (diff)
parentdd72fdd06268860a24f9f3828efade547ee2e2a9 (diff)
downloadqemu-5f580e9411a24b7decc07013edeb8abf8d5ae25c.zip
qemu-5f580e9411a24b7decc07013edeb8abf8d5ae25c.tar.gz
qemu-5f580e9411a24b7decc07013edeb8abf8d5ae25c.tar.bz2
Merge remote-tracking branch 'bonzini/scsi-next' into staging
* bonzini/scsi-next: virtio-scsi: use dma_context_memory dma: Define dma_context_memory and use in sysbus-ohci megasas: Correct target/lun mapping scsi-disk: flush cache after disabling it megasas: do not include block_int.h scsi: remove superfluous call to scsi_device_set_ua virtio-scsi: factor checks for VIRTIO_SCSI_S_DRIVER_OK when reporting events scsi: do not return short responses for emulated commands Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/scsi-disk.c')
-rw-r--r--hw/scsi-disk.c44
1 files changed, 27 insertions, 17 deletions
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1b0afa6..49b5686 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -652,7 +652,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
if (buflen > SCSI_MAX_INQUIRY_LEN) {
buflen = SCSI_MAX_INQUIRY_LEN;
}
- memset(outbuf, 0, buflen);
outbuf[0] = s->qdev.type & 0x1f;
outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;
@@ -1388,6 +1387,7 @@ invalid_param_len:
static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint8_t *p = inbuf;
int cmd = r->req.cmd.buf[0];
int len = r->req.cmd.xfer;
@@ -1424,6 +1424,14 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
return;
}
}
+ if (!bdrv_enable_write_cache(s->qdev.conf.bs)) {
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
+ return;
+ }
+
scsi_req_complete(&r->req, GOOD);
return;
@@ -1596,24 +1604,26 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
break;
}
+ /*
+ * FIXME: we shouldn't return anything bigger than 4k, but the code
+ * requires the buffer to be as big as req->cmd.xfer in several
+ * places. So, do not allow CDBs with a very large ALLOCATION
+ * LENGTH. The real fix would be to modify scsi_read_data and
+ * dma_buf_read, so that they return data beyond the buflen
+ * as all zeros.
+ */
+ if (req->cmd.xfer > 65536) {
+ goto illegal_request;
+ }
+ r->buflen = MAX(4096, req->cmd.xfer);
+
if (!r->iov.iov_base) {
- /*
- * FIXME: we shouldn't return anything bigger than 4k, but the code
- * requires the buffer to be as big as req->cmd.xfer in several
- * places. So, do not allow CDBs with a very large ALLOCATION
- * LENGTH. The real fix would be to modify scsi_read_data and
- * dma_buf_read, so that they return data beyond the buflen
- * as all zeros.
- */
- if (req->cmd.xfer > 65536) {
- goto illegal_request;
- }
- r->buflen = MAX(4096, req->cmd.xfer);
r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
buflen = req->cmd.xfer;
outbuf = r->iov.iov_base;
+ memset(outbuf, 0, r->buflen);
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs));
@@ -1694,12 +1704,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
outbuf[5] = 0;
outbuf[6] = s->qdev.blocksize >> 8;
outbuf[7] = 0;
- buflen = 8;
break;
case REQUEST_SENSE:
/* Just return "NO SENSE". */
buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
(req->cmd.buf[1] & 1) == 0);
+ if (buflen < 0) {
+ goto illegal_request;
+ }
break;
case MECHANISM_STATUS:
buflen = scsi_emulate_mechanism_status(s, outbuf);
@@ -1770,7 +1782,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
}
/* Protection, exponent and lowest lba field left blank. */
- buflen = req->cmd.xfer;
break;
}
DPRINTF("Unsupported Service Action In\n");
@@ -1827,7 +1838,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
assert(!r->req.aiocb);
- r->iov.iov_len = MIN(buflen, req->cmd.xfer);
+ r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
if (r->iov.iov_len == 0) {
scsi_req_complete(&r->req, GOOD);
}
@@ -1962,7 +1973,6 @@ static void scsi_disk_resize_cb(void *opaque)
* direct-access devices.
*/
if (s->qdev.type == TYPE_DISK) {
- scsi_device_set_ua(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
}
}