Reduce size of mode pages for SCSI1 hosts
[SCSI2SD.git] / software / SCSI2SD / src / mode.c
index c66608a..b234549 100755 (executable)
@@ -51,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
@@ -65,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
@@ -99,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
+SCSI_HEADS_PER_CYLINDER, // Number of heads\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
@@ -145,231 +184,254 @@ 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
-       {\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
-       }\r
-       else\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
-               {\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
+       ////////////// Mode Parameter Header\r
+       ////////////////////////////////////\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
-               };\r
-\r
-               scsiDev.data[idx++] = mediumType;\r
-               scsiDev.data[idx++] = deviceSpecificParam;\r
+       // Skip the Mode Data Length, we set that last.\r
+       int idx = 1;\r
+       if (!sixByteCmd) ++idx;\r
 \r
-               if (sixByteCmd)\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
+       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
+       };\r
+\r
+       scsiDev.data[idx++] = mediumType;\r
+       scsiDev.data[idx++] = deviceSpecificParam;\r
+\r
+       if (sixByteCmd)\r
+       {\r
+               if (dbd)\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
+                       scsiDev.data[idx++] = 0; // No block descriptor\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
+                       // One block descriptor of length 8 bytes.\r
+                       scsiDev.data[idx++] = 8;\r
                }\r
-\r
-               ////////////// Block Descriptor\r
-               ////////////////////////////////////\r
-               if (!dbd)\r
+       }\r
+       else\r
+       {\r
+               scsiDev.data[idx++] = 0; // Reserved\r
+               scsiDev.data[idx++] = 0; // Reserved\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; // 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
-\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
+                       scsiDev.data[idx++] = 8;\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
-               int pageFound = 0;\r
+       int pageFound = 0;\r
 \r
-               if (pageCode == 0x01 || pageCode == 0x3F)\r
+       if (pageCode == 0x01 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
                {\r
-                       pageFound = 1;\r
                        pageIn(pc, idx, ReadWriteErrorRecoveryPage, sizeof(ReadWriteErrorRecoveryPage));\r
                        idx += sizeof(ReadWriteErrorRecoveryPage);\r
                }\r
+               else\r
+               {\r
+                       pageIn(pc, idx, ReadWriteErrorRecoveryPage_SCSI1, sizeof(ReadWriteErrorRecoveryPage_SCSI1));\r
+                       idx += sizeof(ReadWriteErrorRecoveryPage_SCSI1);\r
+               }\r
+       }\r
 \r
-               if (pageCode == 0x02 || pageCode == 0x3F)\r
+       if (pageCode == 0x02 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
                {\r
-                       pageFound = 1;\r
                        pageIn(pc, idx, DisconnectReconnectPage, sizeof(DisconnectReconnectPage));\r
                        idx += sizeof(DisconnectReconnectPage);\r
                }\r
-\r
-               if (pageCode == 0x03 || pageCode == 0x3F)\r
+               else\r
                {\r
-                       pageFound = 1;\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
-\r
-                       idx += sizeof(FormatDevicePage);\r
+                       pageIn(pc, idx, DisconnectReconnectPage_SCSI1, sizeof(DisconnectReconnectPage_SCSI1));\r
+                       idx += sizeof(DisconnectReconnectPage_SCSI1);\r
                }\r
+       }\r
 \r
-               if (pageCode == 0x04 || pageCode == 0x3F)\r
+       if (pageCode == 0x03 || pageCode == 0x3F)\r
+       {\r
+               pageFound = 1;\r
+               pageIn(pc, idx, FormatDevicePage, sizeof(FormatDevicePage));\r
+               if (pc != 0x01)\r
                {\r
-                       pageFound = 1;\r
-                       pageIn(pc, idx, RigidDiskDriveGeometry, sizeof(RigidDiskDriveGeometry));\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
-\r
-                       idx += sizeof(RigidDiskDriveGeometry);\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
 \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
+               idx += sizeof(FormatDevicePage);\r
+       }\r
 \r
-               if (!scsiDev.compatMode && (pageCode == 0x08 || pageCode == 0x3F))\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
-                       pageFound = 1;\r
-                       pageIn(pc, idx, CachingPage, sizeof(CachingPage));\r
-                       idx += sizeof(CachingPage);\r
+                       pageIn(pc, idx, RigidDiskDriveGeometry_SCSI1, sizeof(RigidDiskDriveGeometry_SCSI1));\r
                }\r
 \r
-               if (!scsiDev.compatMode && (pageCode == 0x0A || pageCode == 0x3F))\r
+               if (pc != 0x01)\r
                {\r
-                       pageFound = 1;\r
-                       pageIn(pc, idx, ControlModePage, sizeof(ControlModePage));\r
-                       idx += sizeof(ControlModePage);\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
 \r
-               if ((\r
-                               (scsiDev.target->cfg->quirks == CONFIG_QUIRKS_APPLE) ||\r
-                               (idx + sizeof(AppleVendorPage) <= allocLength)\r
-                       ) &&\r
-                       (pageCode == 0x30 || pageCode == 0x3F))\r
+               if ((scsiDev.compatMode >= COMPAT_SCSI2))\r
                {\r
-                       pageFound = 1;\r
-                       pageIn(pc, idx, AppleVendorPage, sizeof(AppleVendorPage));\r
-                       idx += sizeof(AppleVendorPage);\r
+                       idx += sizeof(RigidDiskDriveGeometry);\r
                }\r
+               else\r
+               {\r
+                       idx += sizeof(RigidDiskDriveGeometry_SCSI1);\r
+               }\r
+       }\r
+\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
+\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
+       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 ((\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
-                       // 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
+                       // Cannot currently exceed limits. yay\r
+                       scsiDev.data[0] = idx - 1;\r
                }\r
                else\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 > allocLength ? allocLength : idx;\r
-                       scsiDev.phase = DATA_IN;\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