diff mbox

scsi-bus: Add support for SCSI scanners

Message ID 20160628161945.GA2022@ks392938.kimsufi.com
State New
Headers show

Commit Message

Jarkko Lavinen June 28, 2016, 4:19 p.m. UTC
I have been trying to get Minolta Multi Pro SCSI film scanner working
with Qemu in Linux and WinXP guests.  With Linux guest and virtio
interface the scanner works out of the box. Unfortunately I haven't
been able to find virtio SCSI driver for Win XP.

With Linux guest and pvscsi driver additional patches are needed to
add support for some missing commands. The same patches are also
needed with WinXP guest with virtual LSI SCSI adapter drivers.

With these patches I am able to do index scan, frame selection,
prescan, focus, scanner calibration,main scan (35mm and medium format)
and do the transport lockup. What is still missing is the real
implementation of REQUEST SENSE command with extra bytes which the
scanner application use with focusing.

Few times the scans start return nothing but black in XP but native
Vuescan in Linux works just right and I have to restart the scanner to
fix this.

I've also seen soft lockups while scanning with Test Unit Ready / Mode
Sense in loop with kernel watchdog nagging. Could be that too verbose
SCSI debugging is choking the system. I haven't touched the kernel
(4.4.14) only written 022000" or 022022 (not the octal number but
decimal value) to /proc/sys/dev/scsi/logging_level.

But these patches are still a proof of concept. I am able to use the
SCSI scanner with virtual LSI adapter from Qemu with XP or Linux guest
and and almost everything works. With VMware and VirtualBox not much
or almost nothing works.

Jarkko Lavinen

Comments

Paolo Bonzini June 28, 2016, 5:14 p.m. UTC | #1
> +    case INQUIRY:

This is wrong, because INQUIRY's byte 3 is defined to be part of the
length in modern SCSI standards.  Perhaps you can move it to
scsi_req_scanner_length if really necessary?

>      case MODE_SENSE:
> +    case MODE_SELECT:
> +    case REQUEST_SENSE:
> +        cmd->xfer = buf[4];
> +        break;

This is unnecessary, because scsi_cdb_xfer should get it right (the
commands are respectively 15h for MODE SELECT and 03h for REQUEST SENSE;
the existing entry for MODE SENSE is also unnecessary).

> +    case MODE_SENSE_10:
> +    case MODE_SELECT_10:
> +        cmd->xfer = (buf[7] << 8) | buf[8];
>          break;

Same here, scsi_cdb_xfer should handle it.

> 
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index 045594a..2f8da49 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -1139,6 +1139,32 @@ 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 GET_DATA_BUFFER_STATUS:
> +        cmd->xfer = buf[8] | (buf[7] << 8);
> +        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:
> +        return scsi_req_xfer(cmd, dev, buf);
> +    }

Looks good.

> +    return 0;
> +}
> +
>  static void scsi_cmd_xfer_mode(SCSICommand *cmd)
>  {
>      if (!cmd->xfer) {
> @@ -1184,6 +1210,8 @@ 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.  Add a comment please saying that
START_STOP has cmd->xfer set to 0 in scsi_req_xfer for non-scanner devices.

Everything else looks good.

Thanks,

Paolo

>          cmd->mode = SCSI_XFER_TO_DEV;
>          break;
>      case ATA_PASSTHROUGH_12:
> @@ -1264,6 +1292,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;
> diff --git a/include/block/scsi.h b/include/block/scsi.h
> index a311341..8b966d7 100644
> --- a/include/block/scsi.h
> +++ b/include/block/scsi.h
> @@ -48,13 +48,17 @@
>  #define ERASE                 0x19
>  #define MODE_SENSE            0x1a
>  #define LOAD_UNLOAD           0x1b
> +#define SCAN                  0x1b
>  #define START_STOP            0x1b
>  #define RECEIVE_DIAGNOSTIC    0x1c
>  #define SEND_DIAGNOSTIC       0x1d
>  #define ALLOW_MEDIUM_REMOVAL  0x1e
> +#define SET_WINDOW            0x24
>  #define READ_CAPACITY_10      0x25
> +#define GET_WINDOW            0x25
>  #define READ_10               0x28
>  #define WRITE_10              0x2a
> +#define SEND                  0x2a
>  #define SEEK_10               0x2b
>  #define LOCATE_10             0x2b
>  #define POSITION_TO_ELEMENT   0x2b
> @@ -62,10 +66,12 @@
>  #define VERIFY_10             0x2f
>  #define SEARCH_HIGH           0x30
>  #define SEARCH_EQUAL          0x31
> +#define OBJECT_POSITION       0x31
>  #define SEARCH_LOW            0x32
>  #define SET_LIMITS            0x33
>  #define PRE_FETCH             0x34
>  #define READ_POSITION         0x34
> +#define GET_DATA_BUFFER_STATUS 0x34
>  #define SYNCHRONIZE_CACHE     0x35
>  #define LOCK_UNLOCK_CACHE     0x36
>  #define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
> -- 
> 2.1.4
>
diff mbox

Patch

From e78b81f02cb53369499a0cc70495f1b84f6dbfc8 Mon Sep 17 00:00:00 2001
From: Jarkko Lavinen <jarkko.lavinen@iki.fi>
Date: Tue, 28 Jun 2016 17:49:41 +0300
Subject: [PATCH 2/2] scsi-bus: Add SCSI scanner support

Add support for missing scanner specific SCSI commands and their xfer
lenghts as per ANSI spec section 15.

Signed-off-by: Jarkko Lavinen <jarkko.lavinen@iki.fi>
---
 hw/scsi/scsi-bus.c   | 31 +++++++++++++++++++++++++++++++
 include/block/scsi.h |  6 ++++++
 2 files changed, 37 insertions(+)

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 045594a..2f8da49 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1139,6 +1139,32 @@  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 GET_DATA_BUFFER_STATUS:
+        cmd->xfer = buf[8] | (buf[7] << 8);
+        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:
+        return scsi_req_xfer(cmd, dev, buf);
+    }
+
+    return 0;
+}
+
 static void scsi_cmd_xfer_mode(SCSICommand *cmd)
 {
     if (!cmd->xfer) {
@@ -1184,6 +1210,8 @@  static void scsi_cmd_xfer_mode(SCSICommand *cmd)
     case SEND_DVD_STRUCTURE:
     case PERSISTENT_RESERVE_OUT:
     case MAINTENANCE_OUT:
+    case SET_WINDOW:
+    case SCAN:
         cmd->mode = SCSI_XFER_TO_DEV;
         break;
     case ATA_PASSTHROUGH_12:
@@ -1264,6 +1292,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;
diff --git a/include/block/scsi.h b/include/block/scsi.h
index a311341..8b966d7 100644
--- a/include/block/scsi.h
+++ b/include/block/scsi.h
@@ -48,13 +48,17 @@ 
 #define ERASE                 0x19
 #define MODE_SENSE            0x1a
 #define LOAD_UNLOAD           0x1b
+#define SCAN                  0x1b
 #define START_STOP            0x1b
 #define RECEIVE_DIAGNOSTIC    0x1c
 #define SEND_DIAGNOSTIC       0x1d
 #define ALLOW_MEDIUM_REMOVAL  0x1e
+#define SET_WINDOW            0x24
 #define READ_CAPACITY_10      0x25
+#define GET_WINDOW            0x25
 #define READ_10               0x28
 #define WRITE_10              0x2a
+#define SEND                  0x2a
 #define SEEK_10               0x2b
 #define LOCATE_10             0x2b
 #define POSITION_TO_ELEMENT   0x2b
@@ -62,10 +66,12 @@ 
 #define VERIFY_10             0x2f
 #define SEARCH_HIGH           0x30
 #define SEARCH_EQUAL          0x31
+#define OBJECT_POSITION       0x31
 #define SEARCH_LOW            0x32
 #define SET_LIMITS            0x33
 #define PRE_FETCH             0x34
 #define READ_POSITION         0x34
+#define GET_DATA_BUFFER_STATUS 0x34
 #define SYNCHRONIZE_CACHE     0x35
 #define LOCK_UNLOCK_CACHE     0x36
 #define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
-- 
2.1.4