Merge branch 'master' of ssh://webhost.codesrc.com/home/michael/projects/SCSI2SD
[SCSI2SD.git] / software / SCSI2SD / src / mode.c
index e748b1b..b7bd9c0 100755 (executable)
@@ -15,6 +15,8 @@
 //\r
 //     You should have received a copy of the GNU General Public License\r
 //     along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
+#pragma GCC push_options\r
+#pragma GCC optimize("-flto")\r
 \r
 #include "device.h"\r
 #include "scsi.h"\r
@@ -49,6 +51,18 @@ static const uint8 ReadWriteErrorRecoveryPage[] =
 0x00, 0x00 // Recovery time limit 0 (use default)*/\r
 };\r
 \r
+static const uint8 ReadWriteErrorRecoveryPage_SCSI1[] =\r
+{\r
+0x01, // Page code\r
+0x06, // Page length\r
+0x26,\r
+0x00, // Don't try recovery algorithm during reads\r
+0x00, // Correction span 0\r
+0x00, // Head offset count 0,\r
+0x00, // Data strobe offset count 0,\r
+0xFF // Reserved\r
+};\r
+\r
 static const uint8 DisconnectReconnectPage[] =\r
 {\r
 0x02, // Page code\r
@@ -63,6 +77,18 @@ static const uint8 DisconnectReconnectPage[] =
 0x00, 0x00, 0x00 // Reserved\r
 };\r
 \r
+static const uint8 DisconnectReconnectPage_SCSI1[] =\r
+{\r
+0x02, // Page code\r
+0x0A, // Page length\r
+0, // Buffer full ratio\r
+0, // Buffer empty ratio\r
+0x00, 10, // Bus inactivity limit, 100us increments. Allow 1ms.\r
+0x00, 0x00, // Disconnect time limit\r
+0x00, 0x00, // Connect time limit\r
+0x00, 0x00 // Maximum burst size\r
+};\r
+\r
 static const uint8 FormatDevicePage[] =\r
 {\r
 0x03 | 0x80, // Page code | PS (persist) bit.\r
@@ -71,7 +97,7 @@ static const uint8 FormatDevicePage[] =
 0x00, 0x00, // No alternate sectors\r
 0x00, 0x00, // No alternate tracks\r
 0x00, 0x00, // No alternate tracks per lun\r
-0x00, SCSI_SECTORS_PER_TRACK, // Sectors per track\r
+0x00, 0x00, // Sectors per track, configurable\r
 0xFF, 0xFF, // Data bytes per physical sector. Configurable.\r
 0x00, 0x01, // Interleave\r
 0x00, 0x00, // Track skew factor\r
@@ -85,7 +111,7 @@ static const uint8 RigidDiskDriveGeometry[] =
 0x04, // Page code\r
 0x16, // Page length\r
 0xFF, 0xFF, 0xFF, // Number of cylinders\r
-SCSI_HEADS_PER_CYLINDER, // Number of heads\r
+0x00, // Number of heads (replaced by configured value)\r
 0xFF, 0xFF, 0xFF, // Starting cylinder-write precompensation\r
 0xFF, 0xFF, 0xFF, // Starting cylinder-reduced write current\r
 0x00, 0x1, // Drive step rate (units of 100ns)\r
@@ -97,6 +123,21 @@ SCSI_HEADS_PER_CYLINDER, // Number of heads
 0x00, 0x00 // Reserved\r
 };\r
 \r
+static const uint8 RigidDiskDriveGeometry_SCSI1[] =\r
+{\r
+0x04, // Page code\r
+0x12, // Page length\r
+0xFF, 0xFF, 0xFF, // Number of cylinders\r
+0x00, // Number of heads (replaced by configured value)\r
+0xFF, 0xFF, 0xFF, // Starting cylinder-write precompensation\r
+0xFF, 0xFF, 0xFF, // Starting cylinder-reduced write current\r
+0x00, 0x1, // Drive step rate (units of 100ns)\r
+0x00, 0x00, 0x00, // Landing zone cylinder\r
+0x00, // RPL\r
+0x00, // Rotational offset\r
+0x00 // Reserved\r
+};\r
+\r
 static const uint8 CachingPage[] =\r
 {\r
 0x08, // Page Code\r
@@ -120,6 +161,22 @@ static const uint8 ControlModePage[] =
 0x00, 0x00 // AEN holdoff period.\r
 };\r
 \r
+static const uint8_t SequentialDeviceConfigPage[] =\r
+{\r
+0x10, // page code\r
+0x0E, // Page length\r
+0x00, // CAP, CAF, Active Format\r
+0x00, // Active partition\r
+0x00, // Write buffer full ratio\r
+0x00, // Read buffer empty ratio\r
+0x00,0x01, // Write delay time, in 100ms units\r
+0x00, // Default gap size\r
+0x10, // auto-generation of default eod (end of data)\r
+0x00,0x00,0x00 // buffer-size at early warning\r
+0x00, // No data compression\r
+0x00 // reserved\r
+};\r
+\r
 // Allow Apple 68k Drive Setup to format this drive.\r
 // Code\r
 static const uint8 AppleVendorPage[] =\r
@@ -143,230 +200,285 @@ static void pageIn(int pc, int dataIdx, const uint8* pageData, int pageLen)
 static void doModeSense(\r
        int sixByteCmd, int dbd, int pc, int pageCode, int allocLength)\r
 {\r
-       if (pc == 0x03) // Saved Values not supported.\r
+       ////////////// Mode Parameter Header\r
+       ////////////////////////////////////\r
+\r
+       // Skip the Mode Data Length, we set that last.\r
+       int idx = 1;\r
+       if (!sixByteCmd) ++idx;\r
+\r
+       uint8_t mediumType = 0;\r
+       uint8_t deviceSpecificParam = 0;\r
+       uint8_t density = 0;\r
+       switch (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)\r
        {\r
-               scsiDev.status = CHECK_CONDITION;\r
-               scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
-               scsiDev.target->sense.asc = SAVING_PARAMETERS_NOT_SUPPORTED;\r
-               scsiDev.phase = STATUS;\r
+       case CONFIG_FIXED:\r
+       case CONFIG_REMOVEABLE:\r
+               mediumType = 0; // We should support various floppy types here!\r
+               // Contains cache bits (0) and a Write-Protect bit.\r
+               deviceSpecificParam =\r
+                       (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+               density = 0; // reserved for direct access\r
+               break;\r
+\r
+       case CONFIG_FLOPPY_14MB:\r
+               mediumType = 0x1E; // 90mm/3.5"\r
+               deviceSpecificParam =\r
+                       (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+               density = 0; // reserved for direct access\r
+               break;\r
+\r
+       case CONFIG_OPTICAL:\r
+               mediumType = 0x02; // 120mm CDROM, data only.\r
+               deviceSpecificParam = 0;\r
+               density = 0x01; // User data only, 2048bytes per sector.\r
+               break;\r
+\r
+       case CONFIG_SEQUENTIAL:\r
+               mediumType = 0; // reserved\r
+               deviceSpecificParam =\r
+                       (blockDev.state & DISK_WP) ? 0x80 : 0;\r
+               density = 0x13; // DAT Data Storage, X3B5/88-185A \r
+               break;\r
+\r
+       case CONFIG_MO:\r
+               TODO\r
+               break;\r
+\r
+       };\r
+\r
+       scsiDev.data[idx++] = mediumType;\r
+       scsiDev.data[idx++] = deviceSpecificParam;\r
+\r
+       if (sixByteCmd)\r
+       {\r
+               if (dbd)\r
+               {\r
+                       scsiDev.data[idx++] = 0; // No block descriptor\r
+               }\r
+               else\r
+               {\r
+                       // One block descriptor of length 8 bytes.\r
+                       scsiDev.data[idx++] = 8;\r
+               }\r
        }\r
        else\r
        {\r
-               int pageFound = 1;\r
-\r
-               ////////////// Mode Parameter Header\r
-               ////////////////////////////////////\r
-\r
-               // Skip the Mode Data Length, we set that last.\r
-               int idx = 1;\r
-               if (!sixByteCmd) ++idx;\r
-\r
-               uint8_t mediumType = 0;\r
-               uint8_t deviceSpecificParam = 0;\r
-               uint8_t density = 0;\r
-               switch (scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)\r
+               scsiDev.data[idx++] = 0; // Reserved\r
+               scsiDev.data[idx++] = 0; // Reserved\r
+               if (dbd)\r
                {\r
-               case CONFIG_FIXED:\r
-               case CONFIG_REMOVEABLE:\r
-                       mediumType = 0; // We should support various floppy types here!\r
-                       // Contains cache bits (0) and a Write-Protect bit.\r
-                       deviceSpecificParam =\r
-                               (blockDev.state & DISK_WP) ? 0x80 : 0;\r
-                       density = 0; // reserved for direct access\r
-                       break;\r
-\r
-               case CONFIG_FLOPPY_14MB:\r
-                       mediumType = 0x1E; // 90mm/3.5"\r
-                       deviceSpecificParam =\r
-                               (blockDev.state & DISK_WP) ? 0x80 : 0;\r
-                       density = 0; // reserved for direct access\r
-                       break;\r
-\r
-               case CONFIG_OPTICAL:\r
-                       mediumType = 0x02; // 120mm CDROM, data only.\r
-                       deviceSpecificParam = 0;\r
-                       density = 0x01; // User data only, 2048bytes per sector.\r
-                       break;\r
+                       scsiDev.data[idx++] = 0; // No block descriptor\r
+                       scsiDev.data[idx++] = 0; // No block descriptor\r
+               }\r
+               else\r
+               {\r
+                       // One block descriptor of length 8 bytes.\r
+                       scsiDev.data[idx++] = 0;\r
+                       scsiDev.data[idx++] = 8;\r
+               }\r
+       }\r
 \r
-               };\r
+       ////////////// Block Descriptor\r
+       ////////////////////////////////////\r
+       if (!dbd)\r
+       {\r
+               scsiDev.data[idx++] = density;\r
+               // Number of blocks\r
+               // Zero == all remaining blocks shall have the medium\r
+               // characteristics specified.\r
+               scsiDev.data[idx++] = 0;\r
+               scsiDev.data[idx++] = 0;\r
+               scsiDev.data[idx++] = 0;\r
+\r
+               scsiDev.data[idx++] = 0; // reserved\r
+\r
+               // Block length\r
+               uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+               scsiDev.data[idx++] = bytesPerSector >> 16;\r
+               scsiDev.data[idx++] = bytesPerSector >> 8;\r
+               scsiDev.data[idx++] = bytesPerSector & 0xFF;\r
+       }\r
 \r
-               scsiDev.data[idx++] = mediumType;\r
-               scsiDev.data[idx++] = deviceSpecificParam;\r
+       int pageFound = 0;\r
 \r
-               if (sixByteCmd)\r
+       if (pageCode == 0x01 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
                {\r
-                       if (dbd)\r
-                       {\r
-                               scsiDev.data[idx++] = 0; // No block descriptor\r
-                       }\r
-                       else\r
-                       {\r
-                               // One block descriptor of length 8 bytes.\r
-                               scsiDev.data[idx++] = 8;\r
-                       }\r
+                       pageIn(pc, idx, ReadWriteErrorRecoveryPage, sizeof(ReadWriteErrorRecoveryPage));\r
+                       idx += sizeof(ReadWriteErrorRecoveryPage);\r
                }\r
                else\r
                {\r
-                       scsiDev.data[idx++] = 0; // Reserved\r
-                       scsiDev.data[idx++] = 0; // Reserved\r
-                       if (dbd)\r
-                       {\r
-                               scsiDev.data[idx++] = 0; // No block descriptor\r
-                               scsiDev.data[idx++] = 0; // No block descriptor\r
-                       }\r
-                       else\r
-                       {\r
-                               // One block descriptor of length 8 bytes.\r
-                               scsiDev.data[idx++] = 0;\r
-                               scsiDev.data[idx++] = 8;\r
-                       }\r
+                       pageIn(pc, idx, ReadWriteErrorRecoveryPage_SCSI1, sizeof(ReadWriteErrorRecoveryPage_SCSI1));\r
+                       idx += sizeof(ReadWriteErrorRecoveryPage_SCSI1);\r
                }\r
+       }\r
 \r
-               ////////////// Block Descriptor\r
-               ////////////////////////////////////\r
-               if (!dbd)\r
+       if (pageCode == 0x02 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
                {\r
-                       scsiDev.data[idx++] = density;\r
-                       // Number of blocks\r
-                       // Zero == all remaining blocks shall have the medium\r
-                       // characteristics specified.\r
-                       scsiDev.data[idx++] = 0;\r
-                       scsiDev.data[idx++] = 0;\r
-                       scsiDev.data[idx++] = 0;\r
+                       pageIn(pc, idx, DisconnectReconnectPage, sizeof(DisconnectReconnectPage));\r
+                       idx += sizeof(DisconnectReconnectPage);\r
+               }\r
+               else\r
+               {\r
+                       pageIn(pc, idx, DisconnectReconnectPage_SCSI1, sizeof(DisconnectReconnectPage_SCSI1));\r
+                       idx += sizeof(DisconnectReconnectPage_SCSI1);\r
+               }\r
+       }\r
 \r
-                       scsiDev.data[idx++] = 0; // reserved\r
+       if (pageCode == 0x03 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               pageIn(pc, idx, FormatDevicePage, sizeof(FormatDevicePage));\r
+               if (pc != 0x01)\r
+               {\r
+                       uint16_t sectorsPerTrack = scsiDev.target->cfg->sectorsPerTrack;\r
+                       scsiDev.data[idx+10] = sectorsPerTrack >> 8;\r
+                       scsiDev.data[idx+11] = sectorsPerTrack & 0xFF;\r
 \r
-                       // Block length\r
+                       // Fill out the configured bytes-per-sector\r
                        uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
-                       scsiDev.data[idx++] = bytesPerSector >> 16;\r
-                       scsiDev.data[idx++] = bytesPerSector >> 8;\r
-                       scsiDev.data[idx++] = bytesPerSector & 0xFF;\r
+                       scsiDev.data[idx+12] = bytesPerSector >> 8;\r
+                       scsiDev.data[idx+13] = bytesPerSector & 0xFF;\r
                }\r
-\r
-               switch (pageCode)\r
+               else\r
                {\r
-               case 0x3F:\r
-                       // EVERYTHING\r
-\r
-               case 0x01:\r
-                       pageIn(pc, idx, ReadWriteErrorRecoveryPage, sizeof(ReadWriteErrorRecoveryPage));\r
-                       idx += sizeof(ReadWriteErrorRecoveryPage);\r
-                       if (pageCode != 0x3f) break;\r
-\r
-               case 0x02:\r
-                       pageIn(pc, idx, DisconnectReconnectPage, sizeof(DisconnectReconnectPage));\r
-                       idx += sizeof(DisconnectReconnectPage);\r
-                       if (pageCode != 0x3f) break;\r
-\r
-               case 0x03:\r
-                       pageIn(pc, idx, FormatDevicePage, sizeof(FormatDevicePage));\r
-                       if (pc != 0x01)\r
-                       {\r
-                               // Fill out the configured bytes-per-sector\r
-                               uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
-                               scsiDev.data[idx+12] = bytesPerSector >> 8;\r
-                               scsiDev.data[idx+13] = bytesPerSector & 0xFF;\r
-                       }\r
-                       else\r
-                       {\r
-                               // Set a mask for the changeable values.\r
-                               scsiDev.data[idx+12] = 0xFF;\r
-                               scsiDev.data[idx+13] = 0xFF;\r
-                       }\r
+                       // Set a mask for the changeable values.\r
+                       scsiDev.data[idx+12] = 0xFF;\r
+                       scsiDev.data[idx+13] = 0xFF;\r
+               }\r
 \r
-                       idx += sizeof(FormatDevicePage);\r
-                       if (pageCode != 0x3f) break;\r
+               idx += sizeof(FormatDevicePage);\r
+       }\r
 \r
-               case 0x04:\r
+       if (pageCode == 0x04 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
                {\r
                        pageIn(pc, idx, RigidDiskDriveGeometry, sizeof(RigidDiskDriveGeometry));\r
+               }\r
+               else\r
+               {\r
+                       pageIn(pc, idx, RigidDiskDriveGeometry_SCSI1, sizeof(RigidDiskDriveGeometry_SCSI1));\r
+               }\r
 \r
-                       if (pc != 0x01)\r
-                       {\r
-                               // Need to fill out the number of cylinders.\r
-                               uint32 cyl;\r
-                               uint8 head;\r
-                               uint32 sector;\r
-                               LBA2CHS(\r
-                                       getScsiCapacity(\r
-                                               scsiDev.target->cfg->sdSectorStart,\r
-                                               scsiDev.target->liveCfg.bytesPerSector,\r
-                                               scsiDev.target->cfg->scsiSectors),\r
-                                       &cyl,\r
-                                       &head,\r
-                                       &sector);\r
-\r
-                               scsiDev.data[idx+2] = cyl >> 16;\r
-                               scsiDev.data[idx+3] = cyl >> 8;\r
-                               scsiDev.data[idx+4] = cyl;\r
-\r
-                               memcpy(&scsiDev.data[idx+6], &scsiDev.data[idx+2], 3);\r
-                               memcpy(&scsiDev.data[idx+9], &scsiDev.data[idx+2], 3);\r
-                       }\r
+               if (pc != 0x01)\r
+               {\r
+                       // Need to fill out the number of cylinders.\r
+                       uint32 cyl;\r
+                       uint8 head;\r
+                       uint32 sector;\r
+                       LBA2CHS(\r
+                               getScsiCapacity(\r
+                                       scsiDev.target->cfg->sdSectorStart,\r
+                                       scsiDev.target->liveCfg.bytesPerSector,\r
+                                       scsiDev.target->cfg->scsiSectors),\r
+                               &cyl,\r
+                               &head,\r
+                               &sector,\r
+                               scsiDev.target->cfg->headsPerCylinder,\r
+                               scsiDev.target->cfg->sectorsPerTrack);\r
+\r
+                       scsiDev.data[idx+2] = cyl >> 16;\r
+                       scsiDev.data[idx+3] = cyl >> 8;\r
+                       scsiDev.data[idx+4] = cyl;\r
+\r
+                       memcpy(&scsiDev.data[idx+6], &scsiDev.data[idx+2], 3);\r
+                       memcpy(&scsiDev.data[idx+9], &scsiDev.data[idx+2], 3);\r
+\r
+                       scsiDev.data[idx+5] = scsiDev.target->cfg->headsPerCylinder;\r
+               }\r
 \r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
+               {\r
                        idx += sizeof(RigidDiskDriveGeometry);\r
-                       if (pageCode != 0x3f) break;\r
                }\r
+               else\r
+               {\r
+                       idx += sizeof(RigidDiskDriveGeometry_SCSI1);\r
+               }\r
+       }\r
 \r
-               case 0x08:\r
-                       pageIn(pc, idx, CachingPage, sizeof(CachingPage));\r
-                       idx += sizeof(CachingPage);\r
-                       if (pageCode != 0x3f) break;\r
+       // DON'T output the following pages for SCSI1 hosts. They get upset when\r
+       // we have more data to send than the allocation length provided.\r
+       // (ie. Try not to output any more pages below this comment)\r
 \r
-               case 0x0A:\r
-                       pageIn(pc, idx, ControlModePage, sizeof(ControlModePage));\r
-                       idx += sizeof(ControlModePage);\r
-                       if (pageCode != 0x3f) break;\r
 \r
-               case 0x30:\r
-                       pageIn(pc, idx, AppleVendorPage, sizeof(AppleVendorPage));\r
-                       idx += sizeof(AppleVendorPage);\r
-                       break;\r
+       if ((scsiDev.compatMode >= COMPAT_SCSI2) &&\r
+               (pageCode == 0x08 || pageCode == 0x3F))\r
+       {\r
+               pageFound = 1;\r
+               pageIn(pc, idx, CachingPage, sizeof(CachingPage));\r
+               idx += sizeof(CachingPage);\r
+       }\r
 \r
-               default:\r
-                       // Unknown Page Code\r
-                       pageFound = 0;\r
-                       scsiDev.status = CHECK_CONDITION;\r
-                       scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
-                       scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
-                       scsiDev.phase = STATUS;\r
-               }\r
+       if ((scsiDev.compatMode >= COMPAT_SCSI2)\r
+               && (pageCode == 0x0A || pageCode == 0x3F))\r
+       {\r
+               pageFound = 1;\r
+               pageIn(pc, idx, ControlModePage, sizeof(ControlModePage));\r
+               idx += sizeof(ControlModePage);\r
+       }\r
 \r
+       if ((scsiDev.target->cfg->deviceType == CONFIG_SEQUENTIAL) &&\r
+               (pageCode == 0x10 || pageCode == 0x3F))\r
+       {\r
+               pageFound = 1;\r
+               pageIn(\r
+                       pc,\r
+                       idx,\r
+                       SequentialDeviceConfigPage,\r
+                       sizeof(SequentialDeviceConfigPage));\r
+               idx += sizeof(SequentialDeviceConfigPage);\r
+       }\r
 \r
-               if (idx > allocLength)\r
-               {\r
-                       // Chop the reply off early if shorter length is requested\r
-                       idx = allocLength;\r
-               }\r
+       if ((\r
+                       (scsiDev.target->cfg->quirks == CONFIG_QUIRKS_APPLE) ||\r
+                       (idx + sizeof(AppleVendorPage) <= allocLength)\r
+               ) &&\r
+               (pageCode == 0x30 || pageCode == 0x3F))\r
+       {\r
+               pageFound = 1;\r
+               pageIn(pc, idx, AppleVendorPage, sizeof(AppleVendorPage));\r
+               idx += sizeof(AppleVendorPage);\r
+       }\r
 \r
-               if (pageFound)\r
+       if (!pageFound)\r
+       {\r
+               // Unknown Page Code\r
+               pageFound = 0;\r
+               scsiDev.status = CHECK_CONDITION;\r
+               scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+               scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
+               scsiDev.phase = STATUS;\r
+       }\r
+       else\r
+       {\r
+               // Go back and fill out the mode data length\r
+               if (sixByteCmd)\r
                {\r
-                       // Go back and fill out the mode data length\r
-                       if (sixByteCmd)\r
-                       {\r
-                               // Cannot currently exceed limits. yay\r
-                               scsiDev.data[0] = idx - 1;\r
-                       }\r
-                       else\r
-                       {\r
-                               scsiDev.data[0] = ((idx - 2) >> 8);\r
-                               scsiDev.data[1] = (idx - 2);\r
-                       }\r
-\r
-                       scsiDev.dataLen = idx;\r
-                       scsiDev.phase = DATA_IN;\r
+                       // Cannot currently exceed limits. yay\r
+                       scsiDev.data[0] = idx - 1;\r
                }\r
                else\r
                {\r
-                       // Page not found\r
-                       scsiDev.status = CHECK_CONDITION;\r
-                       scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
-                       scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
-                       scsiDev.phase = STATUS;\r
+                       scsiDev.data[0] = ((idx - 2) >> 8);\r
+                       scsiDev.data[1] = (idx - 2);\r
                }\r
+\r
+               scsiDev.dataLen = idx > allocLength ? allocLength : idx;\r
+               scsiDev.phase = DATA_IN;\r
        }\r
 }\r
 \r
+\r
 // Callback after the DATA OUT phase is complete.\r
 static void doModeSelect(void)\r
 {\r
@@ -478,7 +590,10 @@ int scsiModeCommand()
                int pc = scsiDev.cdb[2] >> 6; // Page Control\r
                int pageCode = scsiDev.cdb[2] & 0x3F;\r
                int allocLength = scsiDev.cdb[4];\r
-               if (allocLength == 0) allocLength = 256;\r
+\r
+               // SCSI1 standard: (CCS X3T9.2/86-52)\r
+               // "An Allocation Length of zero indicates that no MODE SENSE data shall\r
+               // be transferred. This condition shall not be considered as an error."\r
                doModeSense(1, dbd, pc, pageCode, allocLength);\r
        }\r
        else if (command == 0x5A)\r
@@ -538,4 +653,4 @@ int scsiModeCommand()
        return commandHandled;\r
 }\r
 \r
-\r
+#pragma GCC pop_options\r