scsi-disk: adjust offsets in MODE SENSE by 2
authorPaolo Bonzini <pbonzini@redhat.com>
Thu, 12 Jul 2012 14:08:24 +0000 (16:08 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 26 Jul 2012 15:44:09 +0000 (17:44 +0200)
This will make offsets the same when implementing MODE SELECT.  This is
because MODE SELECT has to deal with both 2-byte and 4-byte headers.
Unfortunately, this means that the offsets are now off by two compared
to the descriptions in the SCSI specs, which include the header.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
hw/scsi-disk.c

index b8d6086..dca9866 100644 (file)
@@ -959,148 +959,156 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         [MODE_PAGE_AUDIO_CTL]              = (1 << TYPE_ROM),
         [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
     };
-    uint8_t *p = *p_outbuf;
+
+    uint8_t *p = *p_outbuf + 2;
+    int length;
 
     if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
         return -1;
     }
 
-    p[0] = page;
-
     /*
      * If Changeable Values are requested, a mask denoting those mode parameters
      * that are changeable shall be returned. As we currently don't support
      * parameter changes via MODE_SELECT all bits are returned set to zero.
      * The buffer was already menset to zero by the caller of this function.
+     *
+     * The offsets here are off by two compared to the descriptions in the
+     * SCSI specs, because those include a 2-byte header.  This is unfortunate,
+     * but it is done so that offsets are consistent within our implementation
+     * of MODE SENSE and MODE SELECT.  MODE SELECT has to deal with both
+     * 2-byte and 4-byte headers.
      */
     switch (page) {
     case MODE_PAGE_HD_GEOMETRY:
-        p[1] = 0x16;
+        length = 0x16;
         if (page_control == 1) { /* Changeable Values */
             break;
         }
         /* if a geometry hint is available, use it */
-        p[2] = (s->qdev.conf.cyls >> 16) & 0xff;
-        p[3] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[4] = s->qdev.conf.cyls & 0xff;
-        p[5] = s->qdev.conf.heads & 0xff;
+        p[0] = (s->qdev.conf.cyls >> 16) & 0xff;
+        p[1] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[2] = s->qdev.conf.cyls & 0xff;
+        p[3] = s->qdev.conf.heads & 0xff;
         /* Write precomp start cylinder, disabled */
-        p[6] = (s->qdev.conf.cyls >> 16) & 0xff;
-        p[7] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[8] = s->qdev.conf.cyls & 0xff;
+        p[4] = (s->qdev.conf.cyls >> 16) & 0xff;
+        p[5] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[6] = s->qdev.conf.cyls & 0xff;
         /* Reduced current start cylinder, disabled */
-        p[9] = (s->qdev.conf.cyls >> 16) & 0xff;
-        p[10] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[11] = s->qdev.conf.cyls & 0xff;
+        p[7] = (s->qdev.conf.cyls >> 16) & 0xff;
+        p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[9] = s->qdev.conf.cyls & 0xff;
         /* Device step rate [ns], 200ns */
-        p[12] = 0;
-        p[13] = 200;
+        p[10] = 0;
+        p[11] = 200;
         /* Landing zone cylinder */
+        p[12] = 0xff;
+        p[13] =  0xff;
         p[14] = 0xff;
-        p[15] =  0xff;
-        p[16] = 0xff;
         /* Medium rotation rate [rpm], 5400 rpm */
-        p[20] = (5400 >> 8) & 0xff;
-        p[21] = 5400 & 0xff;
+        p[18] = (5400 >> 8) & 0xff;
+        p[19] = 5400 & 0xff;
         break;
 
     case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
-        p[1] = 0x1e;
+        length = 0x1e;
         if (page_control == 1) { /* Changeable Values */
             break;
         }
         /* Transfer rate [kbit/s], 5Mbit/s */
-        p[2] = 5000 >> 8;
-        p[3] = 5000 & 0xff;
+        p[0] = 5000 >> 8;
+        p[1] = 5000 & 0xff;
         /* if a geometry hint is available, use it */
-        p[4] = s->qdev.conf.heads & 0xff;
-        p[5] = s->qdev.conf.secs & 0xff;
-        p[6] = s->qdev.blocksize >> 8;
+        p[2] = s->qdev.conf.heads & 0xff;
+        p[3] = s->qdev.conf.secs & 0xff;
+        p[4] = s->qdev.blocksize >> 8;
+        p[6] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[7] = s->qdev.conf.cyls & 0xff;
+        /* Write precomp start cylinder, disabled */
         p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
         p[9] = s->qdev.conf.cyls & 0xff;
-        /* Write precomp start cylinder, disabled */
+        /* Reduced current start cylinder, disabled */
         p[10] = (s->qdev.conf.cyls >> 8) & 0xff;
         p[11] = s->qdev.conf.cyls & 0xff;
-        /* Reduced current start cylinder, disabled */
-        p[12] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[13] = s->qdev.conf.cyls & 0xff;
         /* Device step rate [100us], 100us */
-        p[14] = 0;
-        p[15] = 1;
+        p[12] = 0;
+        p[13] = 1;
         /* Device step pulse width [us], 1us */
-        p[16] = 1;
+        p[14] = 1;
         /* Device head settle delay [100us], 100us */
-        p[17] = 0;
-        p[18] = 1;
+        p[15] = 0;
+        p[16] = 1;
         /* Motor on delay [0.1s], 0.1s */
-        p[19] = 1;
+        p[17] = 1;
         /* Motor off delay [0.1s], 0.1s */
-        p[20] = 1;
+        p[18] = 1;
         /* Medium rotation rate [rpm], 5400 rpm */
-        p[28] = (5400 >> 8) & 0xff;
-        p[29] = 5400 & 0xff;
+        p[26] = (5400 >> 8) & 0xff;
+        p[27] = 5400 & 0xff;
         break;
 
     case MODE_PAGE_CACHING:
-        p[0] = 8;
-        p[1] = 0x12;
+        length = 0x12;
         if (page_control == 1) { /* Changeable Values */
             break;
         }
         if (bdrv_enable_write_cache(s->qdev.conf.bs)) {
-            p[2] = 4; /* WCE */
+            p[0] = 4; /* WCE */
         }
         break;
 
     case MODE_PAGE_R_W_ERROR:
-        p[1] = 10;
-        p[2] = 0x80; /* Automatic Write Reallocation Enabled */
+        length = 10;
+        p[0] = 0x80; /* Automatic Write Reallocation Enabled */
         if (s->qdev.type == TYPE_ROM) {
-            p[3] = 0x20; /* Read Retry Count */
+            p[1] = 0x20; /* Read Retry Count */
         }
         break;
 
     case MODE_PAGE_AUDIO_CTL:
-        p[1] = 14;
+        length = 14;
         break;
 
     case MODE_PAGE_CAPABILITIES:
-        p[1] = 0x14;
+        length = 0x14;
         if (page_control == 1) { /* Changeable Values */
             break;
         }
 
-        p[2] = 0x3b; /* CD-R & CD-RW read */
-        p[3] = 0; /* Writing not supported */
-        p[4] = 0x7f; /* Audio, composite, digital out,
+        p[0] = 0x3b; /* CD-R & CD-RW read */
+        p[1] = 0; /* Writing not supported */
+        p[2] = 0x7f; /* Audio, composite, digital out,
                         mode 2 form 1&2, multi session */
-        p[5] = 0xff; /* CD DA, DA accurate, RW supported,
+        p[3] = 0xff; /* CD DA, DA accurate, RW supported,
                         RW corrected, C2 errors, ISRC,
                         UPC, Bar code */
-        p[6] = 0x2d | (s->tray_locked ? 2 : 0);
+        p[4] = 0x2d | (s->tray_locked ? 2 : 0);
         /* Locking supported, jumper present, eject, tray */
-        p[7] = 0; /* no volume & mute control, no
+        p[5] = 0; /* no volume & mute control, no
                      changer */
-        p[8] = (50 * 176) >> 8; /* 50x read speed */
-        p[9] = (50 * 176) & 0xff;
-        p[10] = 2 >> 8; /* Two volume levels */
-        p[11] = 2 & 0xff;
-        p[12] = 2048 >> 8; /* 2M buffer */
-        p[13] = 2048 & 0xff;
-        p[14] = (16 * 176) >> 8; /* 16x read speed current */
-        p[15] = (16 * 176) & 0xff;
-        p[18] = (16 * 176) >> 8; /* 16x write speed */
+        p[6] = (50 * 176) >> 8; /* 50x read speed */
+        p[7] = (50 * 176) & 0xff;
+        p[8] = 2 >> 8; /* Two volume levels */
+        p[9] = 2 & 0xff;
+        p[10] = 2048 >> 8; /* 2M buffer */
+        p[11] = 2048 & 0xff;
+        p[12] = (16 * 176) >> 8; /* 16x read speed current */
+        p[13] = (16 * 176) & 0xff;
+        p[16] = (16 * 176) >> 8; /* 16x write speed */
+        p[17] = (16 * 176) & 0xff;
+        p[18] = (16 * 176) >> 8; /* 16x write speed current */
         p[19] = (16 * 176) & 0xff;
-        p[20] = (16 * 176) >> 8; /* 16x write speed current */
-        p[21] = (16 * 176) & 0xff;
         break;
 
     default:
         return -1;
     }
 
-    *p_outbuf += p[1] + 2;
-    return p[1] + 2;
+    assert(length < 256);
+    (*p_outbuf)[0] = page;
+    (*p_outbuf)[1] = length;
+    *p_outbuf += length + 2;
+    return length + 2;
 }
 
 static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)