Quellcode durchsuchen

Add rudimentary support for tapes

 - Add support for reading a single file.
 - Add support for rewinding the tape.
 - Add support for the OMTI 5400 version of the SPACE command.

Original pull request adapted by Petteri Aimonen:

 - Separate tape code to ZuluSCSI_tape.cpp
 - Add basic support of fixed bit
Kars de Jong vor 2 Jahren
Ursprung
Commit
cc3587d96a
5 geänderte Dateien mit 152 neuen und 29 gelöschten Zeilen
  1. 0 29
      lib/SCSI2SD/src/firmware/tape.c
  2. 3 0
      src/BlueSCSI_disk.h
  3. 1 0
      src/BlueSCSI_log_trace.cpp
  4. 142 0
      src/BlueSCSI_tape.cpp
  5. 6 0
      src/BlueSCSI_tape.h

+ 0 - 29
lib/SCSI2SD/src/firmware/tape.c

@@ -1,29 +0,0 @@
-//	Copyright (C) 2015 Michael McMaster <michael@codesrc.com>
-//
-//	This file is part of SCSI2SD.
-//
-//	SCSI2SD is free software: you can redistribute it and/or modify
-//	it under the terms of the GNU General Public License as published by
-//	the Free Software Foundation, either version 3 of the License, or
-//	(at your option) any later version.
-//
-//	SCSI2SD is distributed in the hope that it will be useful,
-//	but WITHOUT ANY WARRANTY; without even the implied warranty of
-//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//	GNU General Public License for more details.
-//
-//	You should have received a copy of the GNU General Public License
-//	along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
-
-#include "scsi.h"
-#include "config.h"
-#include "tape.h"
-
-// Handle sequential scsi device commands
-int scsiTapeCommand()
-{
-	// TODO handle tape-specific read/write commands and return 1
-
-	return 0;
-}
-

+ 3 - 0
src/BlueSCSI_disk.h

@@ -49,6 +49,9 @@ struct image_config_t: public S2S_TargetCfg
     uint8_t cdrom_events;
     bool reinsert_on_inquiry;
 
+    // For tape drive emulation, current position in blocks
+    uint32_t tape_pos;
+
     // Index of image, for when image on-the-fly switching is used for CD drives
     int image_index;
 

+ 1 - 0
src/BlueSCSI_log_trace.cpp

@@ -27,6 +27,7 @@ static const char *getCommandName(uint8_t cmd)
         case 0x0A: return "Write6";
         case 0x0B: return "Seek6";
         case 0x0F: return "WriteSectorBuffer";
+        case 0x11: return "Space";
         case 0x12: return "Inquiry";
         case 0x15: return "ModeSelect6";
         case 0x16: return "Reserve";

+ 142 - 0
src/BlueSCSI_tape.cpp

@@ -0,0 +1,142 @@
+/* Tape device emulation
+ * Will be called by scsi.c from SCSI2SD.
+ *
+ * ZuluSCSI™ - Copyright (c) 2023 Rabbit Hole Computing™
+ * Copyright (c) 2023 Kars de Jong
+ *
+ * This file is licensed under the GPL version 3 or any later version. 
+ * It is derived from cdrom.c in SCSI2SD V6
+ *
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "BlueSCSI_disk.h"
+#include "BlueSCSI_log.h"
+#include "BlueSCSI_config.h"
+
+extern "C" {
+#include <scsi.h>
+}
+
+extern "C" int scsiTapeCommand()
+{
+    image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
+    int commandHandled = 1;
+
+    uint8_t command = scsiDev.cdb[0];
+    if (command == 0x08)
+    {
+        // READ6
+        bool fixed = scsiDev.cdb[1] & 1;
+        bool supress_invalid_length = scsiDev.cdb[1] & 2;
+
+        if (img.quirks == S2S_CFG_QUIRKS_OMTI)
+        {
+            fixed = true;
+        }
+
+        uint32_t length =
+            (((uint32_t) scsiDev.cdb[2]) << 16) +
+            (((uint32_t) scsiDev.cdb[3]) << 8) +
+            scsiDev.cdb[4];
+
+        // Host can request either multiple fixed-length blocks, or a single variable length one.
+        // If host requests variable length block, we return one blocklen sized block.
+        uint32_t blocklen = scsiDev.target->liveCfg.bytesPerSector;
+        uint32_t blocks_to_read = length;
+        if (!fixed)
+        {
+            blocks_to_read = 1;
+
+            bool underlength = (length > blocklen);
+            bool overlength = (length < blocklen);
+            if (overlength || (underlength && !supress_invalid_length))
+            {
+                debuglog("Host requested variable block max ", (int)length, " bytes, blocksize is ", (int)blocklen);
+                scsiDev.status = CHECK_CONDITION;
+                scsiDev.target->sense.code = ILLEGAL_REQUEST;
+                scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
+                scsiDev.phase = STATUS;
+                return 1;
+            }
+        }
+
+
+        if (blocks_to_read > 0)
+        {
+            scsiDiskStartRead(img.tape_pos, blocks_to_read);
+            img.tape_pos += blocks_to_read;
+        }
+    }
+    else if (command == 0x01)
+    {
+        // REWIND
+        // Set tape position back to 0.
+        img.tape_pos = 0;
+    }
+    else if (command == 0x11)
+    {
+        // SPACE
+        // Set the tape position forward to a specified offset.
+        uint8_t code = scsiDev.cdb[1] & 7;
+        uint32_t count =
+            (((uint32_t) scsiDev.cdb[2]) << 24) +
+            (((uint32_t) scsiDev.cdb[3]) << 16) +
+            (((uint32_t) scsiDev.cdb[4]) << 8) +
+            scsiDev.cdb[5];
+        if (code == 0)
+        {
+            // Blocks.
+            uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
+            uint32_t capacity = img.file.size() / bytesPerSector;
+
+            if (count < capacity)
+            {
+                img.tape_pos = count;
+            }
+            else
+            {
+                scsiDev.status = CHECK_CONDITION;
+                scsiDev.target->sense.code = BLANK_CHECK;
+                scsiDev.target->sense.asc = 0; // END-OF-DATA DETECTED
+                scsiDev.phase = STATUS;
+            }
+        }
+        else if (code == 1)
+        {
+            // Filemarks.
+            // For now just indicate end of data
+            scsiDev.status = CHECK_CONDITION;
+            scsiDev.target->sense.code = BLANK_CHECK;
+            scsiDev.target->sense.asc = 0; // END-OF-DATA DETECTED
+            scsiDev.phase = STATUS;
+        }
+        else if (code == 3)
+        {
+            // End-of-data.
+            scsiDev.status = CHECK_CONDITION;
+            scsiDev.target->sense.code = BLANK_CHECK;
+            scsiDev.target->sense.asc = 0; // END-OF-DATA DETECTED
+            scsiDev.phase = STATUS;
+        }
+    }
+    else
+    {
+        commandHandled = 0;
+    }
+
+    return commandHandled;
+}

+ 6 - 0
src/BlueSCSI_tape.h

@@ -0,0 +1,6 @@
+// Tape device emulation
+// Will be called by scsi.c from SCSI2SD.
+
+#pragma once
+
+extern "C" int scsiTapeCommand();