aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi/scsi-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/scsi/scsi-bus.c')
-rw-r--r--hw/scsi/scsi-bus.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index ad6f398c32..297216dfcb 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -461,6 +461,14 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
return true;
}
+static size_t scsi_sense_len(SCSIRequest *req)
+{
+ if (req->dev->type == TYPE_SCANNER)
+ return SCSI_SENSE_LEN_SCANNER;
+ else
+ return SCSI_SENSE_LEN;
+}
+
static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
{
SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
@@ -477,7 +485,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
}
break;
case REQUEST_SENSE:
- scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN);
+ scsi_target_alloc_buf(&r->req, scsi_sense_len(req));
r->len = scsi_device_get_sense(r->req.dev, r->buf,
MIN(req->cmd.xfer, r->buf_len),
(req->cmd.buf[1] & 1) == 0);
@@ -1132,6 +1140,29 @@ static int scsi_req_medium_changer_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8
return 0;
}
+static int scsi_req_scanner_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+{
+ switch (buf[0]) {
+ /* Scanner commands */
+ case OBJECT_POSITION:
+ cmd->xfer = 0;
+ break;
+ case SCAN:
+ cmd->xfer = buf[4];
+ break;
+ case READ_10:
+ case SEND:
+ case GET_WINDOW:
+ case SET_WINDOW:
+ cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
+ break;
+ default:
+ /* GET_DATA_BUFFER_STATUS xfer handled by scsi_req_xfer */
+ return scsi_req_xfer(cmd, dev, buf);
+ }
+
+ return 0;
+}
static void scsi_cmd_xfer_mode(SCSICommand *cmd)
{
@@ -1178,6 +1209,11 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
case SEND_DVD_STRUCTURE:
case PERSISTENT_RESERVE_OUT:
case MAINTENANCE_OUT:
+ case SET_WINDOW:
+ case SCAN:
+ /* SCAN conflicts with START_STOP. START_STOP has cmd->xfer set to 0 for
+ * non-scanner devices, so we only get here for SCAN and not for START_STOP.
+ */
cmd->mode = SCSI_XFER_TO_DEV;
break;
case ATA_PASSTHROUGH_12:
@@ -1258,6 +1294,9 @@ int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
case TYPE_MEDIUM_CHANGER:
rc = scsi_req_medium_changer_xfer(cmd, dev, buf);
break;
+ case TYPE_SCANNER:
+ rc = scsi_req_scanner_length(cmd, dev, buf);
+ break;
default:
rc = scsi_req_xfer(cmd, dev, buf);
break;