浏览代码

Speedup tape reads and fix a reported issue

This speeds up the tape reads to near disk read speeds instead
of around half. On linux it will do two zero reads at the end of
the tape and on the third Linux post an error.

Which is normal behavior according to this line
"In both cases end of data is signified by returning zero bytes for
two consecutive reads." in the Linux kernel doc for SCSI tape:
https://docs.kernel.org/scsi/st.html

It also fixes a bug caught in code review where the sense data
for the tape drive was logically wrong.
J. Morio Sakaguchi 4 月之前
父节点
当前提交
dd66632cca
共有 5 个文件被更改,包括 89 次插入78 次删除
  1. 6 8
      lib/SCSI2SD/src/firmware/scsi.c
  2. 1 0
      lib/SCSI2SD/src/firmware/scsi.h
  3. 6 5
      src/BlueSCSI_disk.cpp
  4. 1 1
      src/BlueSCSI_log_trace.cpp
  5. 75 64
      src/BlueSCSI_tape.cpp

+ 6 - 8
lib/SCSI2SD/src/firmware/scsi.c

@@ -570,10 +570,7 @@ static void process_Command()
 			if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
 			if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
 			{
 			{
 				scsiDev.data[2] |= scsiDev.target->sense.filemark ? 1 << 7 : 0;
 				scsiDev.data[2] |= scsiDev.target->sense.filemark ? 1 << 7 : 0;
-				scsiDev.data[3] |= scsiDev.target->sense.eom ? 1 << 6 : 0;
-			}
-			if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
-			{
+				scsiDev.data[2] |= scsiDev.target->sense.eom ? 1 << 6 : 0;
 				scsiDev.data[3] = scsiDev.target->sense.info >> 24;
 				scsiDev.data[3] = scsiDev.target->sense.info >> 24;
 				scsiDev.data[4] = scsiDev.target->sense.info >> 16;
 				scsiDev.data[4] = scsiDev.target->sense.info >> 16;
 				scsiDev.data[5] = scsiDev.target->sense.info >> 8;
 				scsiDev.data[5] = scsiDev.target->sense.info >> 8;
@@ -602,8 +599,7 @@ static void process_Command()
 		enter_DataIn(allocLength);
 		enter_DataIn(allocLength);
 
 
 		// This is a good time to clear out old sense information.
 		// This is a good time to clear out old sense information.
-		scsiDev.target->sense.code = NO_SENSE;
-		scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+		memset(&scsiDev.target->sense, 0, sizeof(ScsiSense));
 	}
 	}
 	// Some old SCSI drivers do NOT properly support
 	// Some old SCSI drivers do NOT properly support
 	// unitAttention. eg. the Mac Plus would trigger a SCSI reset
 	// unitAttention. eg. the Mac Plus would trigger a SCSI reset
@@ -1394,8 +1390,8 @@ void scsiInit()
 		{
 		{
 			scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
 			scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
 		}
 		}
-		scsiDev.targets[i].sense.code = NO_SENSE;
-		scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+		// reset sense
+		memset(&scsiDev.targets[i].sense, 0, sizeof(scsiDev.targets[i].sense));
 
 
 		if (g_force_sync > 0)
 		if (g_force_sync > 0)
 		{
 		{
@@ -1408,6 +1404,8 @@ void scsiInit()
 			scsiDev.targets[i].syncPeriod = 0;
 			scsiDev.targets[i].syncPeriod = 0;
 		}
 		}
 
 
+		scsiDev.targets[i].tapeMarkCount = 0;
+
 		// Always "start" the device. Many systems (eg. Apple System 7)
 		// Always "start" the device. Many systems (eg. Apple System 7)
 		// won't respond properly to
 		// won't respond properly to
 		// LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense
 		// LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense

+ 1 - 0
lib/SCSI2SD/src/firmware/scsi.h

@@ -113,6 +113,7 @@ typedef struct
 	uint8_t syncPeriod;
 	uint8_t syncPeriod;
 
 
 	uint8_t started; // Controlled by START STOP UNIT
 	uint8_t started; // Controlled by START STOP UNIT
+	uint8_t tapeMarkCount; // Number of times tape mark has been reached
 } TargetState;
 } TargetState;
 
 
 typedef struct
 typedef struct

+ 6 - 5
src/BlueSCSI_disk.cpp

@@ -499,9 +499,12 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_lun, in
         {
         {
             logmsg("---- Configuring as tape drive");
             logmsg("---- Configuring as tape drive");
             img.deviceType = S2S_CFG_SEQUENTIAL;
             img.deviceType = S2S_CFG_SEQUENTIAL;
-            img.tape_mark_count = 0;
+            img.tape_mark_count = 1;
             scsiDev.target->sense.filemark = false;
             scsiDev.target->sense.filemark = false;
             scsiDev.target->sense.eom = false;
             scsiDev.target->sense.eom = false;
+            img.tape_mark_index = 0;
+            img.tape_mark_block_offset = 0;
+            img.tape_load_next_file = true;
         }
         }
         else if (type == S2S_CFG_ZIP100)
         else if (type == S2S_CFG_ZIP100)
         {
         {
@@ -606,7 +609,7 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_lun, in
             img.bin_container.open(name);
             img.bin_container.open(name);
             FsFile file;
             FsFile file;
             bool valid = false;
             bool valid = false;
-
+            img.tape_mark_count = 0;
             while(file.openNext(&img.bin_container))
             while(file.openNext(&img.bin_container))
             {
             {
                 file.getName(name, sizeof(name));
                 file.getName(name, sizeof(name));
@@ -622,9 +625,7 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_lun, in
                 file.open(&img.bin_container, TAPE_DEFAULT_NAME, O_CREAT);
                 file.open(&img.bin_container, TAPE_DEFAULT_NAME, O_CREAT);
                 file.close();
                 file.close();
             }
             }
-            img.tape_mark_index = 0;
-            img.tape_mark_block_offset = 0;
-            img.tape_load_next_file = false;
+
         }
         }
 
 
         img.use_prefix = use_prefix;
         img.use_prefix = use_prefix;

+ 1 - 1
src/BlueSCSI_log_trace.cpp

@@ -164,7 +164,7 @@ static void printNewPhase(int phase, bool initiator = false)
             }
             }
             else if (scsiDev.status == CHECK_CONDITION && scsiDev.target)
             else if (scsiDev.status == CHECK_CONDITION && scsiDev.target)
             {
             {
-                dbgmsg("---- STATUS: 2 CHECK_CONDITION, sense ", (uint32_t)scsiDev.target->sense.asc);
+                dbgmsg("---- STATUS: 2 CHECK_CONDITION, sense code ", scsiDev.target->sense.code, ", asc ", (uint32_t)scsiDev.target->sense.asc);
             }
             }
             else
             else
             {
             {

+ 75 - 64
src/BlueSCSI_tape.cpp

@@ -63,11 +63,9 @@ static void doSeek(uint32_t lba)
 static void doTapeRead(uint32_t blocks)
 static void doTapeRead(uint32_t blocks)
 {
 {
     image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
     image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
-    uint32_t bytesPerSector = 0;
-    uint32_t capacity = 0;
-    bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
+    uint32_t capacity_lba = img.get_capacity_lba();
 
 
-    if (img.bin_container.isOpen())
+    if (img.tape_load_next_file && img.bin_container.isOpen())
     {
     {
         // multifile tape - multiple file markers
         // multifile tape - multiple file markers
         char dir_name[MAX_FILE_PATH + 1];
         char dir_name[MAX_FILE_PATH + 1];
@@ -76,79 +74,98 @@ static void doTapeRead(uint32_t blocks)
         int filename_len = 0;
         int filename_len = 0;
         img.bin_container.getName(dir_name, sizeof(dir_name));
         img.bin_container.getName(dir_name, sizeof(dir_name));
         img.file.getFilename(current_filename, sizeof(current_filename));
         img.file.getFilename(current_filename, sizeof(current_filename));
-        if (current_filename[0] == '\0' || img.tape_load_next_file)
+        img.tape_load_next_file = false;
+        // load first file in directory or load next file
+
+        filename_len = findNextImageAfter(img, dir_name, current_filename, next_filename, sizeof(next_filename), true);
+        if (filename_len > 0 && img.file.selectImageFile(next_filename))
         {
         {
-            // load first file in directory or load next file
-            if (img.tape_load_next_file)
-            {
-                capacity = img.file.size() / bytesPerSector;
-            }
-            filename_len = findNextImageAfter(img, dir_name, current_filename, next_filename, sizeof(next_filename), true);
-            if (filename_len > 0 && img.file.selectImageFile(next_filename))
+            if (img.tape_mark_index > 0)
             {
             {
-                if (img.tape_load_next_file)
-                {
-                    img.tape_mark_block_offset += capacity;
-                    img.tape_mark_index++;
-                }
-                capacity = img.file.size() / bytesPerSector;
-                dbgmsg("------ Read tape loaded file ", next_filename, " has ", (int) capacity, " sectors with filemark ", (int) img.tape_mark_index ," at the end");
-                img.tape_load_next_file = false;
+                img.tape_mark_block_offset += capacity_lba;
             }
             }
             else
             else
             {
             {
-                img.tape_load_next_file = false;
-                logmsg("No tape element images found or openable in tape directory ", dir_name);
-                scsiDev.target->sense.filemark = true;
-                scsiDev.status = CHECK_CONDITION;
-                scsiDev.target->sense.code = MEDIUM_ERROR;
-                scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
-                scsiDev.phase = STATUS;
-                return;
+                img.tape_mark_block_offset = 0;
             }
             }
+            capacity_lba = img.get_capacity_lba();
+
+            dbgmsg("------ Read tape loaded file ", next_filename, " has ", (int) capacity_lba, " sectors with filemark ", (int) img.tape_mark_index ," at the end");
         }
         }
         else
         else
-            capacity = img.file.size() / bytesPerSector;
-    }
-    else
-    {
-        capacity = img.file.size() / bytesPerSector;
+        {
+            logmsg("No tape element images found or openable in tape directory ", dir_name);
+            scsiDev.target->sense.filemark = true;
+            scsiDev.status = CHECK_CONDITION;
+            scsiDev.target->sense.code = MEDIUM_ERROR;
+            scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
+            scsiDev.phase = STATUS;
+            return;
+        }
     }
     }
 
 
-    bool passed_filemarker = false;
-    // bool end_of_tape = false;
-    if (unlikely(((uint64_t) img.tape_pos) - img.tape_mark_block_offset + blocks >= capacity))
+    if (img.file.isOpen())
     {
     {
-        // reading past a file, set blocks to end of file
-        uint32_t blocks_till_eof =  capacity - (img.tape_pos - img.tape_mark_block_offset);
-        dbgmsg("------ Read tape went past file marker, blocks left to be read ", (int) blocks_till_eof, " out of ", (int) blocks);
-        passed_filemarker = true;
-        // SCSI-2 Spec: "If the fixed bit is one, the information field shall be set to the requested transfer length minus the
-        //               actual number of blocks read (not including the filemark)"
-        scsiDev.target->sense.info = blocks - blocks_till_eof;
-        blocks = blocks_till_eof;
-        if (img.tape_mark_index < img.tape_mark_count - 1)
+        bool passed_filemarker = false;
+        uint32_t blocks_till_eof = 0;
+        if (unlikely(((uint64_t) img.tape_pos) - img.tape_mark_block_offset + blocks >= capacity_lba))
         {
         {
-            img.tape_load_next_file = true;
+            // reading past a file, set blocks to end of file
+            blocks_till_eof =  capacity_lba - (img.tape_pos - img.tape_mark_block_offset);
+            passed_filemarker = true;
+            // SCSI-2 Spec: "If the fixed bit is one, the information field shall be set to the requested transfer length minus the
+            //               actual number of blocks read (not including the filemark)"
+            scsiDev.target->sense.info = blocks - blocks_till_eof;
+            dbgmsg("------ Read tape went past file marker, blocks left to be read ", (int) blocks_till_eof, " out of ", (int) blocks, " sense info set to ", (int) scsiDev.target->sense.info);
+
+            blocks = blocks_till_eof;
         }
         }
-        // else
-        //     end_of_tape = true;
-    }
 
 
-    dbgmsg("------ Read tape ", (int)blocks, "x", (int)bytesPerSector, " tape position ",(int)img.tape_pos, " file position ", (int)(img.tape_pos - img.tape_mark_block_offset), " ends with file mark ", (int)img.tape_mark_index);
-    if (blocks > 0)
-        scsiDiskStartRead(img.tape_pos - img.tape_mark_block_offset, blocks);
+        if (blocks > 0)
+        {
+            dbgmsg("------ Read tape ", (int)blocks, "x", (int)scsiDev.target->liveCfg.bytesPerSector, " tape position ",(int)img.tape_pos,
+                            " file position ", (int)(img.tape_pos - img.tape_mark_block_offset), " ends with file mark ",
+                            (int)(img.tape_mark_index + 1), "/", (int) img.tape_mark_count, passed_filemarker ? " reached" : " not reached");
+            scsiDiskStartRead(img.tape_pos - img.tape_mark_block_offset, blocks);
+            scsiFinishWrite();
+            img.tape_pos += blocks;
+        }
 
 
-    if (passed_filemarker)
+        if (passed_filemarker)
+        {
+            if (img.tape_mark_index < img.tape_mark_count)
+            {
+                img.tape_mark_index++;
+                if(img.tape_mark_index < img.tape_mark_count)
+                    img.tape_load_next_file = true;
+
+                scsiDev.target->sense.filemark = true;
+                scsiDev.status = CHECK_CONDITION;
+                scsiDev.target->sense.code = NO_SENSE;
+                scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+                scsiDev.phase = STATUS;
+
+            }
+            else if (blocks_till_eof == 0)
+            {
+                dbgmsg("------ Reached end of tape");
+                scsiDev.target->sense.eom = true;
+                scsiDev.status = CHECK_CONDITION;
+                scsiDev.target->sense.code = BLANK_CHECK;
+                scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+                scsiDev.phase = STATUS;
+            }
+        }
+    }
+    else
     {
     {
-        scsiFinishWrite();
+        dbgmsg("------ No image open");
         scsiDev.target->sense.filemark = true;
         scsiDev.target->sense.filemark = true;
         scsiDev.status = CHECK_CONDITION;
         scsiDev.status = CHECK_CONDITION;
-        scsiDev.target->sense.code = NO_SENSE;
-        scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+        scsiDev.target->sense.code = MEDIUM_ERROR;
+        scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
         scsiDev.phase = STATUS;
         scsiDev.phase = STATUS;
     }
     }
-    img.tape_pos += blocks;
 }
 }
 
 
 static void doRewind()
 static void doRewind()
@@ -157,13 +174,7 @@ static void doRewind()
     img.tape_mark_block_offset = 0;
     img.tape_mark_block_offset = 0;
     img.tape_mark_index = 0;
     img.tape_mark_index = 0;
     img.tape_pos = 0;
     img.tape_pos = 0;
-    img.tape_load_next_file = false;
-    if (img.bin_container.isOpen())
-    {
-        // multifile tape - multiple
-        char emptyfile[] = "";
-        img.file.selectImageFile(emptyfile);
-    }
+    img.tape_load_next_file = true;
 }
 }
 
 
 extern "C" int scsiTapeCommand()
 extern "C" int scsiTapeCommand()