Adding Ensoniq ASR-10 support and improved FORMAT UNIT command.
authorMichael McMaster <michael@codesrc.com>
Tue, 29 Apr 2014 07:40:22 +0000 (17:40 +1000)
committerMichael McMaster <michael@codesrc.com>
Tue, 29 Apr 2014 07:40:22 +0000 (17:40 +1000)
- Read the data-phase bytes during a FORMAT UNIT command
- Return the exact number of bytes requested for the REQUEST SENSE command

CHANGELOG
readme.txt
software/SCSI2SD/src/disk.c
software/SCSI2SD/src/scsi.c

index 896e65c..7c694e0 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,7 @@
 201404??               3.4
        - Fix to ensure SCSI phase bits are set atomically.
+       - Always return the requested number of bytes for a REQUEST SENSE command
+               This is required to support the Ensoniq ASR-10.
        - Decreased (unused) heap and stack sizes to prepare for a memory
        write cache
 
index f6de680..daaea7c 100644 (file)
@@ -66,5 +66,5 @@ Users have reported success on these systems:
     Roland JS-30 Sampler
     Akai S1000, S3200, S3000XL, MPC 2000XL, DPS 12
     EMU Emulator E4X with EOS 3.00b and E6400 (classic) with Eos 4.01
-    Ensoniq ASR-X
+    Ensoniq ASR-X, ASR-10 (from v3.4, 2GB size limit)
     HP 16601A logic analyzer
index fb76ff2..d9961d3 100755 (executable)
@@ -18,6 +18,7 @@
 \r
 #include "device.h"\r
 #include "scsi.h"\r
+#include "scsiPhy.h"\r
 #include "config.h"\r
 #include "disk.h"\r
 #include "sd.h"\r
@@ -38,11 +39,69 @@ static int doSdInit()
        return result;\r
 }\r
 \r
+// Callback once all data has been read in the data out phase.\r
+static void doFormatUnitComplete(void)\r
+{\r
+       // TODO start writing the initialisation pattern to the SD\r
+       // card\r
+       scsiDev.phase = STATUS;\r
+}\r
+\r
+static void doFormatUnitSkipData(int bytes)\r
+{\r
+       // We may not have enough memory to store the initialisation pattern and\r
+       // defect list data.  Since we're not making use of it yet anyway, just\r
+       // discard the bytes.\r
+       scsiEnterPhase(DATA_OUT);\r
+       int i;\r
+       for (i = 0; i < bytes; ++i)\r
+       {\r
+               scsiReadByte(); \r
+       }\r
+}\r
 \r
-static void doFormatUnit()\r
+// Callback from the data out phase.\r
+static void doFormatUnitPatternHeader(void)\r
 {\r
-       // Low-level formatting is not required.\r
-       // Nothing left to do.\r
+       int defectLength =\r
+               ((((uint16_t)scsiDev.data[2])) << 8) +\r
+                       scsiDev.data[3];\r
+                       \r
+       int patternLength =\r
+               ((((uint16_t)scsiDev.data[4 + 2])) << 8) +\r
+               scsiDev.data[4 + 3];\r
+\r
+               doFormatUnitSkipData(defectLength + patternLength);\r
+               doFormatUnitComplete();\r
+}\r
+\r
+// Callback from the data out phase.\r
+static void doFormatUnitHeader(void)\r
+{\r
+       int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;\r
+       int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;\r
+       \r
+       if (! DSP) // disable save parameters\r
+       {\r
+               configSave(); // Save the "MODE SELECT savable parameters"\r
+       }\r
+       \r
+       if (IP)\r
+       {\r
+               // We need to read the initialisation pattern header first.\r
+               scsiDev.dataLen += 4;\r
+               scsiDev.phase = DATA_OUT;\r
+               scsiDev.postDataOutHook = doFormatUnitPatternHeader;\r
+       }\r
+       else\r
+       {\r
+               // Read the defect list data\r
+               int defectLength =\r
+                       ((((uint16_t)scsiDev.data[2])) << 8) +\r
+                       scsiDev.data[3];\r
+               doFormatUnitSkipData(defectLength);\r
+               doFormatUnitComplete();\r
+       }\r
 }\r
 \r
 static void doReadCapacity()\r
@@ -240,7 +299,22 @@ int scsiDiskCommand()
        else if (command == 0x04)\r
        {\r
                // FORMAT UNIT\r
-               doFormatUnit();\r
+               // We don't really do any formatting, but we need to read the correct\r
+               // number of bytes in the DATA_OUT phase to make the SCSI host happy.\r
+               \r
+               int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;\r
+               if (fmtData)\r
+               {\r
+                       // We need to read the parameter list, but we don't know how\r
+                       // big it is yet. Start with the header.\r
+                       scsiDev.dataLen = 4;\r
+                       scsiDev.phase = DATA_OUT;\r
+                       scsiDev.postDataOutHook = doFormatUnitHeader;\r
+               }\r
+               else\r
+               {\r
+                       // No data to read, we're already finished!\r
+               }\r
        }\r
        else if (command == 0x08)\r
        {\r
index 3d64116..a687cef 100755 (executable)
@@ -281,8 +281,12 @@ static void process_Command()
        {\r
                // REQUEST SENSE\r
                uint32 allocLength = scsiDev.cdb[4];\r
-               if (allocLength == 0) allocLength = 256;\r
-               memset(scsiDev.data, 0, 18);\r
+\r
+               // As specified by the SASI and SCSI1 standard.\r
+               // Newer initiators won't be specifying 0 anyway.\r
+               if (allocLength == 0) allocLength = 4;\r
+\r
+               memset(scsiDev.data, 0, 256); // Max possible alloc length\r
                scsiDev.data[0] = 0xF0;\r
                scsiDev.data[2] = scsiDev.sense.code & 0x0F;\r
 \r
@@ -292,23 +296,12 @@ static void process_Command()
                scsiDev.data[6] = transfer.lba;\r
 \r
                // Additional bytes if there are errors to report\r
-               int responseLength;\r
-               if (scsiDev.sense.code == NO_SENSE)\r
-               {\r
-                       responseLength = 8;\r
-               }\r
-               else\r
-               {\r
-                       responseLength = 18;\r
-                       scsiDev.data[7] = 10; // additional length\r
-                       scsiDev.data[12] = scsiDev.sense.asc >> 8;\r
-                       scsiDev.data[13] = scsiDev.sense.asc;\r
-               }\r
+               scsiDev.data[7] = 10; // additional length\r
+               scsiDev.data[12] = scsiDev.sense.asc >> 8;\r
+               scsiDev.data[13] = scsiDev.sense.asc;\r
 \r
                // Silently truncate results. SCSI-2 spec 8.2.14.\r
-               enter_DataIn(\r
-                       (allocLength < responseLength) ? allocLength : responseLength\r
-                       );\r
+               enter_DataIn(allocLength);\r
 \r
                // This is a good time to clear out old sense information.\r
                scsiDev.sense.code = NO_SENSE;\r