Patchwork Re: [patch] fix scsi-generic

login
register
mail settings
Submitter adq
Date Nov. 19, 2010, 2:07 a.m.
Message ID <AANLkTi=U2uJ6fhr1iAHpbYMAkbV=-KzSDoiQUVxQk0ZT@mail.gmail.com>
Download mbox | patch
Permalink /patch/72185/
State New
Headers show

Comments

adq - Nov. 19, 2010, 2:07 a.m.
On 17 November 2010 23:33, adq <adq@lidskialf.net> wrote:
>> On 12 November 2010 10:00, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> On 08/09/2010 01:51 AM, adq wrote:
>>>>
>>>> Figured out what the problem is - READ DVD STRUCTURE has its xfer
>>>> length in an unexpected place, so hw/scsi-bus.c retrieves completely
>>>> the wrong value for the transfer length. Attached nasty hacky (!)
>>>> patch fixes it as a proof of concept, will see what I can do to clean
>>>> it up later. I'd probably want it to warn if it sees SCSI commands it
>>>> doesn't know how to explicitly handle to aid debugging this sort of
>>>> thing in future.
>>>
>>> Hi Andrew, are you going to submit a similar patch in definitive form?
>
> Oops, sorry for top replying before.
>
> Anyway, found the patch and it looks to be in good condition (just
> missing one last SCSI MMC command and testing, which I shall work on).
>
> However, could someone please check the code for the existing
> SEND_VOLUME_TAG code in hw/scsi-bus.c? A doc on this command is h ere:
> http://www.t10.org/ftp/t10/document.05/05-414r4.pdf
>
> I'm not certain "req->cmd.xfer *= 40;" is correct. For a type 5 SCSI
> command, req->cmd.xfer will be set to the value in bytes 9/8/7/6,
> which is defined as PARAMETER LIST LENGTH (i.e. the number of bytes in
> the data transfer according to SPC3). The PARAMETER LIST LENGTH for
> this command should be 40, so multiplying it by 40 again ain't right
> surely?
>
> As I've never seen this command used and have no access to a device
> which could generate it, I just don't know....
>

Hi, attached is a cleaned up version of my patch against the latest
git. It adds support for all the SCSI MMC commands I could find
(although not all have been tested yet). AnyDVD is now able to rip a
video DVD.

Please let me know what you think. The SEND_VOLUME_TAG issue is still
unresolved.

Note for testers: to setup a CDROM to use with this, use a command
line something like: "-device lsi -device scsi-generic,drive=sgcd
-drive file=/dev/sg1,media=cdrom,if=none,id=sgcd" to hook in the
/dev/sgX device for your DVD drive.

Signed-off-by: Andrew de Quincey <adq@lidskialf.net>

Patch

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 5a3fd4b..aac8fa1 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -220,8 +220,19 @@  static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
     case SET_CD_SPEED:
     case SET_LIMITS:
     case WRITE_LONG:
-    case MOVE_MEDIUM:
+    case MOVE_MEDIUM: // also handles MMC PLAY_AUDIO_12
     case UPDATE_BLOCK:
+    case PLAY_AUDIO_10:
+    case PLAY_AUDIO_MSF:
+    case PAUSE_RESUME:
+    case STOP_PLAY_SCAN:
+    case RESERVE_TRACK:
+    case FORMAT_UNIT:
+    case SET_READ_AHEAD:
+    case SCAN:
+    case BLANK:
+    case CLOSE_TRACK_SESSION:
+    case REPAIR_TRACK:
         req->cmd.xfer = 0;
         break;
     case MODE_SENSE:
@@ -239,7 +250,11 @@  static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
         req->cmd.xfer = 20;
         break;
     case SEND_VOLUME_TAG:
-        req->cmd.xfer *= 40;
+        if (req->dev->type == TYPE_ROM) {
+            req->cmd.xfer = cmd[10] | (cmd[9] << 8); // MMC SET_STREAMING operation
+        } else {
+            req->cmd.xfer *= 40; // FIXME: questionable
+        }
         break;
     case MEDIUM_SCAN:
         req->cmd.xfer *= 8;
@@ -271,6 +286,46 @@  static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
             req->cmd.xfer = cmd[9] | (cmd[8] << 8);
         }
         break;
+    case READ_DISC_STRUCTURE:
+    case MECHANISM_STATUS:
+    case SEND_DISC_STRUCTURE:
+        req->cmd.xfer = cmd[9] | (cmd[8] << 8);
+        break;
+    case READ_CD:
+    case SEND_CUE_SHEET:
+    case READ_MASTER_CUE:
+        req->cmd.xfer = cmd[8] | (cmd[7] << 8) | (cmd[6] << 16);
+        break;
+    case READ_CD_MSF:
+        req->cmd.xfer = (((cmd[6] - cmd[3]) * 60 * 75) + 
+                         ((cmd[7] - cmd[4]) * 75) + 
+                          (cmd[8] - cmd[5])) * 2352;
+        break;
+    case GET_PERFORMANCE:
+	req->cmd.xfer = 8;
+
+	int max_descriptors = cmd[9] | (cmd[8] << 8);
+	switch(cmd[10]) {
+	case 0:	// performance
+		req->cmd.xfer += (max_descriptors * 16);
+		break;
+	case 1:	// Unusable area data
+		req->cmd.xfer += (max_descriptors * 8);
+		break;
+	case 2:	// defect status data
+		req->cmd.xfer += (max_descriptors * 2048);
+		break;
+	case 3:	// write speed
+		req->cmd.xfer += (max_descriptors * 16);
+		break;
+	case 4:	// DBI
+		req->cmd.xfer += (max_descriptors * 8);
+		break;
+	case 5:	// DBI cache zone
+		req->cmd.xfer += (max_descriptors * 8);
+		break;
+	}
+        break;
     }
     return 0;
 }
@@ -332,20 +387,34 @@  static void scsi_req_xfer_mode(SCSIRequest *req)
     case SEARCH_LOW_12:
     case SET_WINDOW:
     case MEDIUM_SCAN:
-    case SEND_VOLUME_TAG:
+    case SEND_VOLUME_TAG: // also handles MMC SET_STREAMING
     case WRITE_LONG_2:
     case PERSISTENT_RESERVE_OUT:
-    case MAINTENANCE_OUT:
+    case SEND_DISC_STRUCTURE:
+    case SEND_CUE_SHEET:
+    case SEND_OPC_INFORMATION:
+    case SECURITY_PROTOCOL_OUT:
         req->cmd.mode = SCSI_XFER_TO_DEV;
+        return;
+    case MAINTENANCE_OUT: /* same code as MMC REPORT KEY */
+        if (req->dev->type != TYPE_ROM) {
+            req->cmd.mode = SCSI_XFER_TO_DEV;
+            return;
+        }
         break;
-    default:
-        if (req->cmd.xfer)
-            req->cmd.mode = SCSI_XFER_FROM_DEV;
-        else {
-            req->cmd.mode = SCSI_XFER_NONE;
+    case MAINTENANCE_IN: /* same code as MMC SEND KEY */
+        if (req->dev->type == TYPE_ROM) {
+            req->cmd.mode = SCSI_XFER_TO_DEV;
+            return;
         }
         break;
     }
+
+    if (req->cmd.xfer)
+        req->cmd.mode = SCSI_XFER_FROM_DEV;
+    else {
+        req->cmd.mode = SCSI_XFER_NONE;
+    }
 }
 
 static uint64_t scsi_req_lba(SCSIRequest *req)
@@ -485,6 +554,33 @@  static const char *scsi_command_name(uint8_t cmd)
         [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ SET_CD_SPEED             ] = "SET_CD_SPEED",
         [ BLANK                    ] = "BLANK",
+        [ READ_FORMAT_CAPACITIES   ] = "READ_FORMAT_CAPACITIES",
+        [ PLAY_AUDIO_10            ] = "PLAY_AUDIO_10",
+        [ PLAY_AUDIO_MSF           ] = "PLAY_AUDIO_MSF",
+        [ GET_EVENT_STATUS         ] = "GET_EVENT_STATUS",
+        [ PAUSE_RESUME             ] = "PAUSE_RESUME",
+        [ STOP_PLAY_SCAN           ] = "STOP_PLAY_SCAN",
+        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
+        [ READ_TRACK_INFORMATION   ] = "READ_TRACK_INFORMATION",
+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
+        [ SEND_OPC_INFORMATION     ] = "SEND_OPC_INFORMATION",
+        [ REPAIR_TRACK             ] = "REPAIR_TRACK",
+        [ CLOSE_TRACK_SESSION      ] = "CLOSE_TRACK_SESSION",
+        [ READ_BUFFER_CAPACITY     ] = "READ_BUFFER_CAPACITY",
+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
+        [ SECURITY_PROTOCOL_IN     ] = "SECURITY_PROTOCOL_IN",
+        [ SECURITY_PROTOCOL_OUT    ] = "SECURITY_PROTOCOL_OUT",
+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
+        [ READ_MEDIA_SERIAL_NUMBER ] = "READ_MEDIA_SERIAL_NUMBER",
+        [ READ_DISC_STRUCTURE      ] = "READ_DISC_STRUCTURE",
+        [ SEND_DISC_STRUCTURE      ] = "SEND_DISC_STRUCTURE",
+        [ READ_CD_MSF              ] = "READ_CD_MSF",
+        [ READ_CD                  ] = "READ_CD",
+        [ SCAN                     ] = "SCAN",
+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
+        [ READ_SUB_CHANNEL         ] = "READ_SUB_CHANNEL",
+        [ READ_HEADER              ] = "READ_HEADER",
+        [ READ_MASTER_CUE          ] = "READ_MASTER_CUE",
     };
 
     if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index a4a3518..2d56044 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -49,6 +49,7 @@ 
 #define SEND_DIAGNOSTIC       0x1d
 #define ALLOW_MEDIUM_REMOVAL  0x1e
 
+#define READ_FORMAT_CAPACITIES 0x23
 #define SET_WINDOW            0x24
 #define READ_CAPACITY         0x25
 #define READ_10               0x28
@@ -75,26 +76,53 @@ 
 #define WRITE_LONG            0x3f
 #define CHANGE_DEFINITION     0x40
 #define WRITE_SAME            0x41
+#define READ_SUB_CHANNEL      0x42
 #define READ_TOC              0x43
+#define READ_HEADER           0x44
+#define PLAY_AUDIO_10         0x45
+#define PLAY_AUDIO_MSF        0x47
+#define GET_EVENT_STATUS      0x4a
+#define PAUSE_RESUME          0x4b
 #define LOG_SELECT            0x4c
 #define LOG_SENSE             0x4d
+#define STOP_PLAY_SCAN        0x4e
+#define READ_DISC_INFORMATION 0x51
+#define READ_TRACK_INFORMATION 0x52
+#define RESERVE_TRACK         0x53
+#define SEND_OPC_INFORMATION  0x54
 #define MODE_SELECT_10        0x55
 #define RESERVE_10            0x56
 #define RELEASE_10            0x57
+#define REPAIR_TRACK          0x58
+#define READ_MASTER_CUE       0x59
 #define MODE_SENSE_10         0x5a
+#define CLOSE_TRACK_SESSION   0x5b
+#define READ_BUFFER_CAPACITY  0x5c
+#define SEND_CUE_SHEET        0x5d
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define SECURITY_PROTOCOL_IN  0xa2
 #define MAINTENANCE_IN        0xa3
 #define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
+#define SET_READ_AHEAD        0xa7
 #define READ_12               0xa8
 #define WRITE_12              0xaa
+#define READ_MEDIA_SERIAL_NUMBER 0xab 
+#define GET_PERFORMANCE       0xac
+#define READ_DISC_STRUCTURE   0xad
 #define WRITE_VERIFY_12       0xae
 #define SEARCH_HIGH_12        0xb0
 #define SEARCH_EQUAL_12       0xb1
 #define SEARCH_LOW_12         0xb2
+#define SECURITY_PROTOCOL_OUT 0xb5
 #define READ_ELEMENT_STATUS   0xb8
 #define SEND_VOLUME_TAG       0xb6
+#define READ_CD_MSF           0xb9
+#define SCAN                  0xba
+#define MECHANISM_STATUS      0xbd
+#define READ_CD               0xbe
+#define SEND_DISC_STRUCTURE   0xbf
 #define WRITE_LONG_2          0xea
 
 /* from hw/scsi-generic.c */