aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi
diff options
context:
space:
mode:
authorShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>2019-07-18 11:42:36 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2019-07-19 19:04:49 +0200
commit1849f297f5952ea60ddfd39fe02ce21cba6aa4d8 (patch)
tree8835126239cf372dca342517a81359c3af4f7a26 /hw/scsi
parent68fa7ca015dc8afb86e3aa51b31362f63048bd5c (diff)
downloadqemu-1849f297f5952ea60ddfd39fe02ce21cba6aa4d8.zip
qemu-1849f297f5952ea60ddfd39fe02ce21cba6aa4d8.tar.gz
qemu-1849f297f5952ea60ddfd39fe02ce21cba6aa4d8.tar.bz2
scsi-generic: Check sense key before request snooping and patching
When READ CAPACITY command completes, scsi_read_complete() function snoops the command result and updates SCSIDevice members blocksize and max_lba . However, this update is executed even when READ CAPACITY command indicates an error in sense data. This causes unexpected blocksize update with zero value for SCSI devices without READ CAPACITY(10) command support and eventually results in a divide by zero. An emulated device by TCMU-runner is an example of a device that doesn't support READ CAPACITY(10) command. To avoid the unexpected update, add sense key check in scsi_read_complete() function. The function already checks the sense key for VPD Block Limits emulation. Do the scsi_parse_sense_buf() call for all requests rather than just for VPD Block Limits emulation, so that blocksize and max_lba are only updated if READ CAPACITY returns zero sense key. Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> [Extend the check to all requests, not just READ CAPACITY] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/scsi')
-rw-r--r--hw/scsi/scsi-generic.c28
1 files changed, 16 insertions, 12 deletions
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f07891b..c11a0c9 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -254,24 +254,28 @@ static void scsi_read_complete(void * opaque, int ret)
r->len = -1;
- /*
- * Check if this is a VPD Block Limits request that
- * resulted in sense error but would need emulation.
- * In this case, emulate a valid VPD response.
- */
- if (s->needs_vpd_bl_emulation && ret == 0 &&
- (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) &&
- r->req.cmd.buf[0] == INQUIRY &&
- (r->req.cmd.buf[1] & 0x01) &&
- r->req.cmd.buf[2] == 0xb0) {
+ if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
SCSISense sense =
scsi_parse_sense_buf(r->req.sense, r->io_header.sb_len_wr);
- if (sense.key == ILLEGAL_REQUEST) {
+
+ /*
+ * Check if this is a VPD Block Limits request that
+ * resulted in sense error but would need emulation.
+ * In this case, emulate a valid VPD response.
+ */
+ if (sense.key == ILLEGAL_REQUEST &&
+ s->needs_vpd_bl_emulation &&
+ r->req.cmd.buf[0] == INQUIRY &&
+ (r->req.cmd.buf[1] & 0x01) &&
+ r->req.cmd.buf[2] == 0xb0) {
len = scsi_generic_emulate_block_limits(r, s);
/*
- * No need to let scsi_read_complete go on and handle an
+ * It's okay to jup to req_complete: no need to
+ * let scsi_handle_inquiry_reply handle an
* INQUIRY VPD BL request we created manually.
*/
+ }
+ if (sense.key) {
goto req_complete;
}
}