Преглед на файлове

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)
 			{
 				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[4] = scsiDev.target->sense.info >> 16;
 				scsiDev.data[5] = scsiDev.target->sense.info >> 8;
@@ -602,8 +599,7 @@ static void process_Command()
 		enter_DataIn(allocLength);
 
 		// 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
 	// 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].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)
 		{
@@ -1408,6 +1404,8 @@ void scsiInit()
 			scsiDev.targets[i].syncPeriod = 0;
 		}
 
+		scsiDev.targets[i].tapeMarkCount = 0;
+
 		// Always "start" the device. Many systems (eg. Apple System 7)
 		// won't respond properly to
 		// 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 started; // Controlled by START STOP UNIT
+	uint8_t tapeMarkCount; // Number of times tape mark has been reached
 } TargetState;
 
 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");
             img.deviceType = S2S_CFG_SEQUENTIAL;
-            img.tape_mark_count = 0;
+            img.tape_mark_count = 1;
             scsiDev.target->sense.filemark = 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)
         {
@@ -606,7 +609,7 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_lun, in
             img.bin_container.open(name);
             FsFile file;
             bool valid = false;
-
+            img.tape_mark_count = 0;
             while(file.openNext(&img.bin_container))
             {
                 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.close();
             }
-            img.tape_mark_index = 0;
-            img.tape_mark_block_offset = 0;
-            img.tape_load_next_file = false;
+
         }
 
         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)
             {
-                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
             {

+ 75 - 64
src/BlueSCSI_tape.cpp

@@ -63,11 +63,9 @@ static void doSeek(uint32_t lba)
 static void doTapeRead(uint32_t blocks)
 {
     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
         char dir_name[MAX_FILE_PATH + 1];
@@ -76,79 +74,98 @@ static void doTapeRead(uint32_t blocks)
         int filename_len = 0;
         img.bin_container.getName(dir_name, sizeof(dir_name));
         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
             {
-                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
-            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.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;
     }
-    img.tape_pos += blocks;
 }
 
 static void doRewind()
@@ -157,13 +174,7 @@ static void doRewind()
     img.tape_mark_block_offset = 0;
     img.tape_mark_index = 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()