diff --git a/src/raspberrypi/.vscode/launch.json b/src/raspberrypi/.vscode/launch.json index 4ac5ab4b..e3cd4037 100644 --- a/src/raspberrypi/.vscode/launch.json +++ b/src/raspberrypi/.vscode/launch.json @@ -8,13 +8,15 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/bin/rascsi", + "program": "${workspaceFolder}/bin/fullspec/rascsi", "args": [], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", + "targetArchitecture": "arm", + "miDebuggerPath": "${workspaceFolder}/launch_sudo.sh", "setupCommands": [ { "description": "Enable pretty-printing for gdb", @@ -24,4 +26,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/raspberrypi/.vscode/tasks.json b/src/raspberrypi/.vscode/tasks.json index eeedfe8a..6105ee09 100644 --- a/src/raspberrypi/.vscode/tasks.json +++ b/src/raspberrypi/.vscode/tasks.json @@ -5,7 +5,7 @@ "type": "shell", "label": "g++ build active file", "command": "make", - "args": ["all", "DEBUG=1"], + "args": ["all", "DEBUG=1", "-j4"], "options": { "cwd": "${workspaceFolder}/" }, @@ -16,4 +16,4 @@ } } ] - } \ No newline at end of file + } diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index 34d421a4..9a9984be 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -33,9 +33,9 @@ endif CFLAGS += -iquote . -MD -MP CXXFLAGS += -std=c++14 -iquote . -MD -MP -## CONNECT_TYPE=STANDARD : Specify the type of RaSCSI board type +## CONNECT_TYPE=FULLSPEC : Specify the type of RaSCSI board type ## that you are using. The typical options are -## STANDARD or FULLSPEC. The default is STANDARD +## STANDARD or FULLSPEC. The default is FULLSPEC ## * THIS IS TYPICALLY THE ONLY COMPILE OPTION YOU ## * NEED TO SPECIFY # If its not specified, build for FULLSPEC configuration @@ -75,6 +75,7 @@ SRC_RASCSI = \ gpiobus.cpp \ filepath.cpp \ fileio.cpp\ + os.cpp\ rascsi_version.cpp # os.cpp # rasctl_command.cpp @@ -88,11 +89,8 @@ SRC_SCSIMON = \ scsi.cpp \ gpiobus.cpp \ filepath.cpp \ - fileio.cpp\ + fileio.cpp \ rascsi_version.cpp -SRC_SCSIMON += $(shell find ./controllers -name '*.cpp') -SRC_SCSIMON += $(shell find ./devices -name '*.cpp') - SRC_RASCTL = \ rasctl.cpp\ @@ -154,7 +152,7 @@ ALL: all docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt $(BINDIR)/$(RASCSI): $(OBJ_RASCSI) | $(BINDIR) - $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread + $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lz $(BINDIR)/$(RASCTL): $(OBJ_RASCTL) | $(BINDIR) $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) diff --git a/src/raspberrypi/controllers/sasidev_ctrl.cpp b/src/raspberrypi/controllers/sasidev_ctrl.cpp index 0cd1f420..6fc5987c 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.cpp +++ b/src/raspberrypi/controllers/sasidev_ctrl.cpp @@ -17,6 +17,8 @@ #include "filepath.h" #include "gpiobus.h" #include "devices/scsi_host_bridge.h" +#include "controllers/scsidev_ctrl.h" +#include "devices/scsi_daynaport.h" //=========================================================================== // @@ -44,7 +46,7 @@ SASIDEV::SASIDEV(Device *dev) // Work initialization ctrl.phase = BUS::busfree; - ctrl.id = -1; + ctrl.m_scsi_id = -1; ctrl.bus = NULL; memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd)); ctrl.status = 0x00; @@ -52,7 +54,7 @@ SASIDEV::SASIDEV(Device *dev) #ifdef RASCSI ctrl.execstart = 0; #endif // RASCSI - ctrl.bufsize = 0x800; + ctrl.bufsize = ETH_FRAME_LEN + 16 + ETH_FCS_LEN; ctrl.buffer = (BYTE *)malloc(ctrl.bufsize); memset(ctrl.buffer, 0x00, ctrl.bufsize); ctrl.blocks = 0; @@ -201,7 +203,7 @@ void FASTCALL SASIDEV::Connect(int id, BUS *bus) { ASSERT(this); - ctrl.id = id; + ctrl.m_scsi_id = id; ctrl.bus = bus; } @@ -291,7 +293,7 @@ BUS::phase_t FASTCALL SASIDEV::Process() ASSERT(this); // Do nothing if not connected - if (ctrl.id < 0 || ctrl.bus == NULL) { + if (ctrl.m_scsi_id < 0 || ctrl.bus == NULL) { return ctrl.phase; } @@ -301,9 +303,7 @@ BUS::phase_t FASTCALL SASIDEV::Process() // For the monitor tool, we shouldn't need to reset. We're just logging information // Reset if (ctrl.bus->GetRST()) { -#if defined(DISK_LOG) - Log(Log::Normal, "RESET signal received"); -#endif // DISK_LOG + LOGINFO("RESET signal received"); // Reset the controller Reset(); @@ -371,9 +371,7 @@ void FASTCALL SASIDEV::BusFree() // Phase change if (ctrl.phase != BUS::busfree) { -#if defined(DISK_LOG) - Log(Log::Normal, "Bus free phase"); -#endif // DISK_LOG + LOGINFO("Bus free phase"); // Phase Setting ctrl.phase = BUS::busfree; @@ -411,7 +409,7 @@ void FASTCALL SASIDEV::Selection() // Phase change if (ctrl.phase != BUS::selection) { // Invalid if IDs do not match - id = 1 << ctrl.id; + id = 1 << ctrl.m_scsi_id; if ((ctrl.bus->GetDAT() & id) == 0) { return; } @@ -421,10 +419,7 @@ void FASTCALL SASIDEV::Selection() return; } -#if defined(DISK_LOG) - Log(Log::Normal, - "Selection Phase ID=%d (with device)", ctrl.id); -#endif // DISK_LOG + LOGTRACE("%s Selection Phase ID=%d (with device)", __PRETTY_FUNCTION__, (int)ctrl.m_scsi_id); // Phase change ctrl.phase = BUS::selection; @@ -457,9 +452,7 @@ void FASTCALL SASIDEV::Command() // Phase change if (ctrl.phase != BUS::command) { -#if defined(DISK_LOG) - Log(Log::Normal, "Command Phase"); -#endif // DISK_LOG + LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__); // Phase Setting ctrl.phase = BUS::command; @@ -537,9 +530,7 @@ void FASTCALL SASIDEV::Execute() { ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "Execution Phase Command %02X", ctrl.cmd[0]); -#endif // DISK_LOG + LOGTRACE("%s Execution Phase Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]); // Phase Setting ctrl.phase = BUS::execute; @@ -552,65 +543,68 @@ void FASTCALL SASIDEV::Execute() #endif // RASCSI // Process by command - switch (ctrl.cmd[0]) { + switch ((SCSIDEV::scsi_command)ctrl.cmd[0]) { // TEST UNIT READY - case 0x00: + case SCSIDEV::eCmdTestUnitReady: CmdTestUnitReady(); return; // REZERO UNIT - case 0x01: + case SCSIDEV::eCmdRezero: CmdRezero(); return; // REQUEST SENSE - case 0x03: + case SCSIDEV::eCmdRequestSense: CmdRequestSense(); return; // FORMAT UNIT - case 0x04: - CmdFormat(); - return; - - // FORMAT UNIT - case 0x06: + // This doesn't exist in the SCSI Spec, but was in the original RaSCSI code. + // leaving it here for now.... + case SCSIDEV::eCmdFormat: CmdFormat(); return; // REASSIGN BLOCKS - case 0x07: + case SCSIDEV::eCmdReassign: CmdReassign(); return; // READ(6) - case 0x08: + case SCSIDEV::eCmdRead6: CmdRead6(); return; // WRITE(6) - case 0x0a: + case SCSIDEV::eCmdWrite6: CmdWrite6(); return; // SEEK(6) - case 0x0b: + case SCSIDEV::eCmdSeek6: CmdSeek6(); return; // ASSIGN(SASIのみ) - case 0x0e: + // This doesn't exist in the SCSI Spec, but was in the original RaSCSI code. + // leaving it here for now.... + case SCSIDEV::eCmdSasiCmdAssign: CmdAssign(); return; // SPECIFY(SASIのみ) - case 0xc2: + // This doesn't exist in the SCSI Spec, but was in the original RaSCSI code. + // leaving it here for now.... + case SCSIDEV::eCmdInvalid: CmdSpecify(); return; + default: + break; } // Unsupported command - Log(Log::Warning, "Unsupported command $%02X", ctrl.cmd[0]); + LOGWARN("%s Unsupported command $%02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]); CmdInvalid(); } @@ -645,9 +639,7 @@ void FASTCALL SASIDEV::Status() } #endif // RASCSI -#if defined(DISK_LOG) - Log(Log::Normal, "Status phase"); -#endif // DISK_LOG + LOGTRACE("%s Status phase", __PRETTY_FUNCTION__); // Phase Setting ctrl.phase = BUS::status; @@ -668,9 +660,7 @@ void FASTCALL SASIDEV::Status() ctrl.bus->SetDAT(ctrl.buffer[0]); ctrl.bus->SetREQ(TRUE); -#if defined(DISK_LOG) - Log(Log::Normal, "Status Phase $%02X", ctrl.status); -#endif // DISK_LOG + LOGTRACE( "%s Status Phase $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.status); #endif // RASCSI return; } @@ -705,10 +695,7 @@ void FASTCALL SASIDEV::MsgIn() // Phase change if (ctrl.phase != BUS::msgin) { - -#if defined(DISK_LOG) - Log(Log::Normal, "Message in phase"); -#endif // DISK_LOG + LOGTRACE("%s Starting Message in phase", __PRETTY_FUNCTION__); // Phase Setting ctrl.phase = BUS::msgin; @@ -722,36 +709,12 @@ void FASTCALL SASIDEV::MsgIn() ASSERT(ctrl.length > 0); ASSERT(ctrl.blocks > 0); ctrl.offset = 0; - -#ifndef RASCSI - // Request message - ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); - ctrl.bus->SetREQ(TRUE); - -#if defined(DISK_LOG) - Log(Log::Normal, "Message in phase $%02X", ctrl.buffer[ctrl.offset]); -#endif // DISK_LOG -#endif // RASCSI return; } -#ifdef RASCSI //Send + LOGTRACE("%s Transitioning to Send()", __PRETTY_FUNCTION__); Send(); -#else - // Requesting - if (ctrl.bus->GetREQ()) { - // Initator received - if (ctrl.bus->GetACK()) { - SendNext(); - } - } else { - // Initiator requests next - if (!ctrl.bus->GetACK()) { - Send(); - } - } -#endif // RASCSI } //--------------------------------------------------------------------------- @@ -790,10 +753,7 @@ void FASTCALL SASIDEV::DataIn() return; } -#if defined(DISK_LOG) - Log(Log::Normal, "Data-in Phase"); -#endif // DISK_LOG - + LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__); // Phase Setting ctrl.phase = BUS::datain; @@ -807,33 +767,11 @@ void FASTCALL SASIDEV::DataIn() ASSERT(ctrl.blocks > 0); ctrl.offset = 0; -#ifndef RASCSI - // Assert the DAT signal - ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); - - // Request data - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI return; } -#ifdef RASCSI // Send Send(); -#else - // Requesting - if (ctrl.bus->GetREQ()) { - // Initator received - if (ctrl.bus->GetACK()) { - SendNext(); - } - } else { - // Initiator requests next - if (!ctrl.bus->GetACK()) { - Send(); - } - } -#endif // RASCSI } //--------------------------------------------------------------------------- @@ -872,9 +810,7 @@ void FASTCALL SASIDEV::DataOut() return; } -#if defined(DISK_LOG) - Log(Log::Normal, "Data out phase"); -#endif // DISK_LOG + LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__); // Phase Setting ctrl.phase = BUS::dataout; @@ -946,7 +882,7 @@ void FASTCALL SASIDEV::Error() } #if defined(DISK_LOG) - Log(Log::Warning, "Error occured (going to status phase)"); + LOGWARN("Error occured (going to status phase)"); #endif // DISK_LOG // Logical Unit @@ -971,9 +907,7 @@ void FASTCALL SASIDEV::CmdTestUnitReady() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "TEST UNIT READY Command "); -#endif // DISK_LOG + LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1006,9 +940,7 @@ void FASTCALL SASIDEV::CmdRezero() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "REZERO UNIT Command "); -#endif // DISK_LOG + LOGTRACE( "%s REZERO UNIT Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1040,9 +972,7 @@ void FASTCALL SASIDEV::CmdRequestSense() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "REQUEST SENSE Command "); -#endif // DISK_LOG + LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1051,13 +981,11 @@ void FASTCALL SASIDEV::CmdRequestSense() return; } - // Command processing on drive ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer); ASSERT(ctrl.length > 0); -#if defined(DISK_LOG) - Log(Log::Normal, "Sense key $%02X", ctrl.buffer[2]); -#endif // DISK_LOG + + LOGTRACE("%s Sense key $%02X",__PRETTY_FUNCTION__, (WORD)ctrl.buffer[2]); // Read phase DataIn(); @@ -1075,9 +1003,7 @@ void FASTCALL SASIDEV::CmdFormat() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "FORMAT UNIT Command "); -#endif // DISK_LOG + LOGTRACE( "%s FORMAT UNIT Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1110,9 +1036,7 @@ void FASTCALL SASIDEV::CmdReassign() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "REASSIGN BLOCKS Command "); -#endif // DISK_LOG + LOGTRACE("%s REASSIGN BLOCKS Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1163,13 +1087,82 @@ void FASTCALL SASIDEV::CmdRead6() ctrl.blocks = 0x100; } -#if defined(DISK_LOG) - Log(Log::Normal, - "READ(6) command record=%06X blocks=%d", record, ctrl.blocks); -#endif // DISK_LOG + if(ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'D', 'P')){ + // The DaynaPort only wants one block. + // ctrl.cmd[4] and ctrl.cmd[5] are used to specify the maximum buffer size for the DaynaPort + ctrl.blocks=1; + } + + LOGTRACE("%s READ(6) command record=%06X blocks=%d ID %08X", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks, (unsigned int)ctrl.unit[lun]->GetID()); // Command processing on drive - ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); + ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, ctrl.buffer, record); + LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl.length); + + // The DaynaPort will respond a status of 0x02 when a read of size 1 occurs. + if ((ctrl.length <= 0) && (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P'))) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.next = record + 1; + + // Read phase + DataIn(); +} + + +//--------------------------------------------------------------------------- +// +// This Send Message command is used by the DaynaPort SCSI/Link +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::DaynaPortWrite() +{ + DWORD lun; + DWORD data_format; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Error if not a host bridge + if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P')) { + LOGERROR("Received DaynaPortWrite for a non-DaynaPort device"); + Error(); + return; + } + + // Reallocate buffer (because it is not transfer for each block) + if (ctrl.bufsize < 0x1000000) { + free(ctrl.buffer); + ctrl.bufsize = 0x1000000; + ctrl.buffer = (BYTE *)malloc(ctrl.bufsize); + } + + + data_format = ctrl.cmd[5]; + + + if(data_format == 0x00){ + ctrl.length = (WORD)ctrl.cmd[4] + ((WORD)ctrl.cmd[3] << 8); + } + else if (data_format == 0x80){ + ctrl.length = (WORD)ctrl.cmd[4] + ((WORD)ctrl.cmd[3] << 8) + 8; + } + else + { + LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format); + } + LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.length, (int)ctrl.length, (unsigned int)data_format); + if (ctrl.length <= 0) { // Failure (Error) Error(); @@ -1177,12 +1170,14 @@ void FASTCALL SASIDEV::CmdRead6() } // Set next block - ctrl.next = record + 1; + ctrl.blocks = 1; + ctrl.next = 1; - // Read phase - DataIn(); + // Light phase + DataOut(); } + //--------------------------------------------------------------------------- // // WRITE(6) @@ -1202,6 +1197,12 @@ void FASTCALL SASIDEV::CmdWrite6() return; } + // Special receive function for the DaynaPort + if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'D', 'P')){ + DaynaPortWrite(); + return; + } + // Get record number and block number record = ctrl.cmd[1] & 0x1f; record <<= 8; @@ -1213,14 +1214,12 @@ void FASTCALL SASIDEV::CmdWrite6() ctrl.blocks = 0x100; } -#if defined(DISK_LOG) - Log(Log::Normal, - "WRITE(6) command record=%06X blocks=%d", record, ctrl.blocks); -#endif // DISK_LOG + LOGTRACE("%s WRITE(6) command record=%06X blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks); // Command processing on drive ctrl.length = ctrl.unit[lun]->WriteCheck(record); if (ctrl.length <= 0) { + LOGDEBUG("WriteCheck failed"); // Failure (Error) Error(); return; @@ -1245,9 +1244,7 @@ void FASTCALL SASIDEV::CmdSeek6() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "SEEK(6) Command "); -#endif // DISK_LOG + LOGTRACE("%s SEEK(6) Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1280,9 +1277,7 @@ void FASTCALL SASIDEV::CmdAssign() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "ASSIGN Command "); -#endif // DISK_LOG + LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1318,9 +1313,7 @@ void FASTCALL SASIDEV::CmdSpecify() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "SPECIFY Command "); -#endif // DISK_LOG + LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1354,10 +1347,7 @@ void FASTCALL SASIDEV::CmdInvalid() DWORD lun; ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "Command not supported"); -#endif // DISK_LOG + LOGWARN("%s Command not supported", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1392,7 +1382,6 @@ void FASTCALL SASIDEV::Send() ASSERT(!ctrl.bus->GetREQ()); ASSERT(ctrl.bus->GetIO()); -#ifdef RASCSI // Check that the length isn't 0 if (ctrl.length != 0) { len = ctrl.bus->SendHandShake( @@ -1400,6 +1389,7 @@ void FASTCALL SASIDEV::Send() // If you can not send it all, move on to the status phase if (len != (int)ctrl.length) { + LOGERROR("%s ctrl.length (%d) did not match the amount of data sent (%d)",__PRETTY_FUNCTION__, (int)ctrl.length, len); Error(); return; } @@ -1409,20 +1399,9 @@ void FASTCALL SASIDEV::Send() ctrl.length = 0; return; } -#else - // Offset and Length - ASSERT(ctrl.length >= 1); - ctrl.offset++; - ctrl.length--; - - // Immediately after ACK is asserted, if the data - // has been set by SendNext, raise the request - if (ctrl.length != 0) { - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); - return; + else{ + LOGINFO("%s ctrl.length was 0", __PRETTY_FUNCTION__); } -#endif // RASCSI // Remove block and initialize the result ctrl.blocks--; @@ -1433,8 +1412,8 @@ void FASTCALL SASIDEV::Send() if (ctrl.blocks != 0) { // Set next buffer (set offset, length) result = XferIn(ctrl.buffer); - //** printf("xfer in: %d \n",result); - + LOGTRACE("%s xfer in: %d",__PRETTY_FUNCTION__, result); + LOGTRACE("%s processing after data collection", __PRETTY_FUNCTION__); #ifndef RASCSI ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); #endif // RASCSI @@ -1443,6 +1422,7 @@ void FASTCALL SASIDEV::Send() // If result FALSE, move to the status phase if (!result) { + LOGERROR("%s Send result was false", __PRETTY_FUNCTION__); Error(); return; } @@ -1538,9 +1518,7 @@ void FASTCALL SASIDEV::Receive() // Command phase case BUS::command: ctrl.cmd[ctrl.offset] = data; -#if defined(DISK_LOG) - Log(Log::Normal, "Command phase $%02X", data); -#endif // DISK_LOG + LOGTRACE( "%s Command phase $%02X", __PRETTY_FUNCTION__, data); // Set the length again with the first data (offset 0) if (ctrl.offset == 0) { @@ -1597,6 +1575,7 @@ void FASTCALL SASIDEV::ReceiveNext() // Receive len = ctrl.bus->ReceiveHandShake( &ctrl.buffer[ctrl.offset], ctrl.length); + LOGDEBUG("%s Received %d bytes", __PRETTY_FUNCTION__, len); // If not able to receive all, move to status phase if (len != (int)ctrl.length) { @@ -1609,6 +1588,10 @@ void FASTCALL SASIDEV::ReceiveNext() ctrl.length = 0; return; } + else + { + LOGDEBUG("%s ctrl.length was 0", __PRETTY_FUNCTION__); + } #else // Offset and Length ASSERT(ctrl.length >= 1); @@ -1667,6 +1650,7 @@ void FASTCALL SASIDEV::ReceiveNext() // Data out phase case BUS::dataout: + LOGTRACE("%s transitioning to FlushUnit()",__PRETTY_FUNCTION__); // Flush FlushUnit(); @@ -1693,6 +1677,7 @@ BOOL FASTCALL SASIDEV::XferIn(BYTE *buf) ASSERT(this); ASSERT(ctrl.phase == BUS::datain); + LOGTRACE("%s ctrl.cmd[0]=%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0]); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1707,7 +1692,7 @@ BOOL FASTCALL SASIDEV::XferIn(BYTE *buf) // READ(10) case 0x28: // Read from disk - ctrl.length = ctrl.unit[lun]->Read(buf, ctrl.next); + ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, buf, ctrl.next); ctrl.next++; // If there is an error, go to the status phase @@ -1750,12 +1735,9 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont) return FALSE; } - // MODE SELECT or WRITE system - switch (ctrl.cmd[0]) { - // MODE SELECT - case 0x15: - // MODE SELECT(10) - case 0x55: + switch ((SCSIDEV::scsi_command) ctrl.cmd[0]) { + case SCSIDEV::eCmdModeSelect: + case SCSIDEV::eCmdModeSelect10: if (!ctrl.unit[lun]->ModeSelect( ctrl.cmd, ctrl.buffer, ctrl.offset)) { // MODE SELECT failed @@ -1763,11 +1745,11 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont) } break; - // WRITE(6) - case 0x0a: - // WRITE(10) - case 0x2a: - // Replace the host bridge with SEND MESSAGE 10 + case SCSIDEV::eCmdWrite6: + case SCSIDEV::eCmdWrite10: + case SCSIDEV::eCmdWriteAndVerify10: + // If we're a host bridge, use the host bridge's SendMessage10 + // function if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) { bridge = (SCSIBR*)ctrl.unit[lun]; if (!bridge->SendMessage10(ctrl.cmd, ctrl.buffer)) { @@ -1780,10 +1762,23 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont) break; } - // WRITE AND VERIFY - case 0x2e: - // Write - if (!ctrl.unit[lun]->Write(ctrl.buffer, ctrl.next - 1)) { + // Special case Write function for DaynaPort + if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'D', 'P')) { + LOGTRACE("%s Doing special case write for DayanPort", __PRETTY_FUNCTION__); + if (!(SCSIDaynaPort*)ctrl.unit[lun]->Write(ctrl.cmd, ctrl.buffer, ctrl.length)) { + // write failed + return FALSE; + } + LOGTRACE("%s Done with DaynaPort Write", __PRETTY_FUNCTION__); + + // If normal, work setting + ctrl.offset = 0; + ctrl.blocks = 0; + break; + } + + LOGTRACE("%s eCmdWriteAndVerify10 Calling Write... cmd: %02X next: %d", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd, (int)ctrl.next); + if (!ctrl.unit[lun]->Write(ctrl.cmd, ctrl.buffer, ctrl.next - 1)) { // Write failed return FALSE; } @@ -1806,10 +1801,14 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont) break; // SPECIFY(SASI only) - case 0xc2: + case SCSIDEV::eCmdInvalid: break; + case SCSIDEV::eCmdSetMcastAddr: + LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__); + break; default: + LOGWARN("Received an unexpected command (%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__) ASSERT(FALSE); break; } @@ -1837,45 +1836,49 @@ void FASTCALL SASIDEV::FlushUnit() } // WRITE system only - switch (ctrl.cmd[0]) { - // WRITE(6) - case 0x0a: - // WRITE(10) - case 0x2a: - // WRITE AND VERIFY - case 0x2e: + switch ((SCSIDEV::scsi_command)ctrl.cmd[0]) { + case SCSIDEV::eCmdWrite6: + case SCSIDEV::eCmdWrite10: + case SCSIDEV::eCmdWriteAndVerify10: // Flush if (!ctrl.unit[lun]->IsCacheWB()) { ctrl.unit[lun]->Flush(); } break; - // Mode Select (6) - case 0x15: - // MODE SELECT(10) - case 0x55: + case SCSIDEV::eCmdModeSelect: + case SCSIDEV::eCmdModeSelect10: // Debug code related to Issue #2 on github, where we get an unhandled Model select when // the mac is rebooted // https://github.com/akuker/RASCSI/issues/2 - Log(Log::Warning, "Received \'Mode Select\'\n"); - Log(Log::Warning, " Operation Code: [%02X]\n", ctrl.cmd[0]); - Log(Log::Warning, " Logical Unit %01X, PF %01X, SP %01X [%02X]\n", ctrl.cmd[1] >> 5, 1 & (ctrl.cmd[1] >> 4), ctrl.cmd[1] & 1, ctrl.cmd[1]); - Log(Log::Warning, " Reserved: %02X\n", ctrl.cmd[2]); - Log(Log::Warning, " Reserved: %02X\n", ctrl.cmd[3]); - Log(Log::Warning, " Parameter List Len %02X\n", ctrl.cmd[4]); - Log(Log::Warning, " Reserved: %02X\n", ctrl.cmd[5]); - Log(Log::Warning, " Ctrl Len: %08X\n",ctrl.length); + LOGWARN("Received \'Mode Select\'\n"); + LOGWARN(" Operation Code: [%02X]\n", (WORD)ctrl.cmd[0]); + LOGWARN(" Logical Unit %01X, PF %01X, SP %01X [%02X]\n",\ + (WORD)ctrl.cmd[1] >> 5, 1 & ((WORD)ctrl.cmd[1] >> 4), \ + (WORD)ctrl.cmd[1] & 1, (WORD)ctrl.cmd[1]); + LOGWARN(" Reserved: %02X\n", (WORD)ctrl.cmd[2]); + LOGWARN(" Reserved: %02X\n", (WORD)ctrl.cmd[3]); + LOGWARN(" Parameter List Len %02X\n", (WORD)ctrl.cmd[4]); + LOGWARN(" Reserved: %02X\n",(WORD)ctrl.cmd[5]); + LOGWARN(" Ctrl Len: %08X\n",(WORD)ctrl.length); if (!ctrl.unit[lun]->ModeSelect( ctrl.cmd, ctrl.buffer, ctrl.offset)) { // MODE SELECT failed - Log(Log::Warning, "Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]); + LOGWARN("Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]); return; } break; - + case SCSIDEV::eCmdSetIfaceMode: + LOGWARN("%s Trying to flush a command set interface mode. This should be a daynaport?", __PRETTY_FUNCTION__); + break; + case SCSIDEV::eCmdSetMcastAddr: + // TODO: Eventually, we should store off the multicast address configuration data here... + break; default: - Log(Log::Warning, "Received an invalid flush command %02X!!!!!\n",ctrl.cmd[0]); - ASSERT(FALSE); + LOGWARN("Received an unexpected flush command %02X!!!!!\n",(WORD)ctrl.cmd[0]); + // The following statement makes debugging a huge pain. You can un-comment it + // if you're not trying to add new devices.... + // ASSERT(FALSE); break; } } @@ -1929,71 +1932,3 @@ void SASIDEV::GetPhaseStr(char *str) } } #endif - -//--------------------------------------------------------------------------- -// -// Log output -// -// TODO: This function needs some cleanup. Its very kludgey -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Log(Log::loglevel level, const char *format, ...) -{ -#if !defined(BAREMETAL) -#ifdef DISK_LOG - char buffer[0x200]; - char buffer2[0x250]; - char buffer3[0x250]; - char phase_str[20]; -#endif - va_list args; - va_start(args, format); - - if(this->GetID() != 6) - { - return; - } - -#ifdef RASCSI -#ifndef DISK_LOG - if (level == Log::Warning) { - return; - } -#endif // DISK_LOG -#endif // RASCSI - -#ifdef DISK_LOG - // format - vsprintf(buffer, format, args); - - // end variable length argument - va_end(args); - - // Add the date/timestamp - // current date/time based on current system - time_t now = time(0); - // convert now to string form - char* dt = ctime(&now); - - - strcpy(buffer2, "["); - strcat(buffer2, dt); - // Get rid of the carriage return - buffer2[strlen(buffer2)-1] = '\0'; - strcat(buffer2, "] "); - - // Get the phase - this->GetPhaseStr(phase_str); - sprintf(buffer3, "[%d][%s] ", this->GetID(), phase_str); - strcat(buffer2,buffer3); - strcat(buffer2, buffer); - - - // Log output -#ifdef RASCSI - printf("%s\n", buffer2); -#else - host->GetVM()->GetLog()->Format(level, host, buffer); -#endif // RASCSI -#endif // BAREMETAL -#endif // DISK_LOG -} diff --git a/src/raspberrypi/controllers/sasidev_ctrl.h b/src/raspberrypi/controllers/sasidev_ctrl.h index fc8ec2d0..7f7bfb3f 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.h +++ b/src/raspberrypi/controllers/sasidev_ctrl.h @@ -46,9 +46,9 @@ public: // Internal data definition typedef struct { - // 全般 + // General BUS::phase_t phase; // Transition phase - int id; // Controller ID (0-7) + int m_scsi_id; // Controller ID (0-7) BUS *bus; // Bus // commands @@ -116,7 +116,7 @@ public: void FASTCALL GetPhaseStr(char *str); #endif - int FASTCALL GetID() {return ctrl.id;} + int FASTCALL GetSCSIID() {return ctrl.m_scsi_id;} // Get the ID void FASTCALL GetCTRL(ctrl_t *buffer); // Get the internal information @@ -161,9 +161,9 @@ protected: // FORMAT command void FASTCALL CmdReassign(); // REASSIGN BLOCKS command - void FASTCALL CmdRead6(); + virtual void FASTCALL CmdRead6(); // READ(6) command - void FASTCALL CmdWrite6(); + virtual void FASTCALL CmdWrite6(); // WRITE(6) command void FASTCALL CmdSeek6(); // SEEK(6) command @@ -173,6 +173,8 @@ protected: // SPECIFY command void FASTCALL CmdInvalid(); // Unsupported command + void FASTCALL DaynaPortWrite(); + // DaynaPort specific 'write' operation // データ転送 virtual void FASTCALL Send(); @@ -196,10 +198,6 @@ protected: void FASTCALL FlushUnit(); // Flush the logical unit - // Log - void FASTCALL Log(Log::loglevel level, const char *format, ...); - // Log output - protected: #ifndef RASCSI Device *host; diff --git a/src/raspberrypi/controllers/scsidev_ctrl.cpp b/src/raspberrypi/controllers/scsidev_ctrl.cpp index a496eeb4..da9b6b79 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.cpp +++ b/src/raspberrypi/controllers/scsidev_ctrl.cpp @@ -13,10 +13,11 @@ // [ SCSI device controller ] // //--------------------------------------------------------------------------- +#include "log.h" #include "controllers/scsidev_ctrl.h" #include "gpiobus.h" #include "devices/scsi_host_bridge.h" -#include "rascsi_version.h" +#include "devices/scsi_daynaport.h" //=========================================================================== // @@ -72,18 +73,16 @@ BUS::phase_t FASTCALL SCSIDEV::Process() ASSERT(this); // Do nothing if not connected - if (ctrl.id < 0 || ctrl.bus == NULL) { + if (ctrl.m_scsi_id < 0 || ctrl.bus == NULL) { return ctrl.phase; } // Get bus information ((GPIOBUS*)ctrl.bus)->Aquire(); - // Reset + // Check to see if the reset signal was asserted if (ctrl.bus->GetRST()) { -#if defined(DISK_LOG) - Log(Log::Normal, "RESET信号受信"); -#endif // DISK_LOG + LOGWARN("RESET signal received!"); // Reset the controller Reset(); @@ -146,7 +145,7 @@ BUS::phase_t FASTCALL SCSIDEV::Process() //--------------------------------------------------------------------------- // -// Phaes +// Phases // //--------------------------------------------------------------------------- @@ -162,9 +161,7 @@ void FASTCALL SCSIDEV::BusFree() // Phase change if (ctrl.phase != BUS::busfree) { -#if defined(DISK_LOG) - Log(Log::Normal, "Bus free phase"); -#endif // DISK_LOG + LOGTRACE( "%s Bus free phase", __PRETTY_FUNCTION__); // Phase setting ctrl.phase = BUS::busfree; @@ -205,7 +202,7 @@ void FASTCALL SCSIDEV::Selection() // Phase change if (ctrl.phase != BUS::selection) { // invalid if IDs do not match - id = 1 << ctrl.id; + id = 1 << ctrl.m_scsi_id; if ((ctrl.bus->GetDAT() & id) == 0) { return; } @@ -215,10 +212,7 @@ void FASTCALL SCSIDEV::Selection() return; } -#if defined(DISK_LOG) - Log(Log::Normal, - "Selection Phase ID=%d (with device)", ctrl.id); -#endif // DISK_LOG + LOGTRACE("%s Selection Phase ID=%d (with device)", __PRETTY_FUNCTION__, (int)ctrl.m_scsi_id); // Phase setting ctrl.phase = BUS::selection; @@ -248,9 +242,7 @@ void FASTCALL SCSIDEV::Execute() { ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "Execution phase command $%02X", ctrl.cmd[0]); -#endif // DISK_LOG + LOGTRACE( "%s Execution phase command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0]); // Phase Setting ctrl.phase = BUS::execute; @@ -263,157 +255,188 @@ void FASTCALL SCSIDEV::Execute() #endif // RASCSI // Process by command - switch (ctrl.cmd[0]) { + switch ((scsi_command)ctrl.cmd[0]) { // TEST UNIT READY - case 0x00: + case eCmdTestUnitReady: + LOGDEBUG("++++ CMD ++++ %s Received eCmdTestUnitReady", __PRETTY_FUNCTION__); CmdTestUnitReady(); return; // REZERO - case 0x01: + case eCmdRezero: CmdRezero(); return; // REQUEST SENSE - case 0x03: + case eCmdRequestSense: + LOGDEBUG("++++ CMD ++++ %s Received eCmdRequestSense", __PRETTY_FUNCTION__); CmdRequestSense(); return; // FORMAT UNIT - case 0x04: + case eCmdFormat: CmdFormat(); return; // REASSIGN BLOCKS - case 0x07: + case eCmdReassign: CmdReassign(); return; // READ(6) - case 0x08: + case eCmdRead6: + LOGTRACE("++++ CMD ++++ %s Received eCmdRead6", __PRETTY_FUNCTION__); CmdRead6(); return; + case eCmdRetrieveStats: + LOGDEBUG("++++ CMD ++++ %s Received eCmdRetrieveStats", __PRETTY_FUNCTION__); + CmdRetrieveStats(); + return; + + case eCmdSetIfaceMode: + LOGDEBUG("++++ CMD ++++ %s Received eCmdSetIfaceMode", __PRETTY_FUNCTION__); + CmdSetIfaceMode(); + return; + + case eCmdSetMcastAddr: + LOGDEBUG("++++ CMD ++++ %s Received eCmdSetMcastAddr", __PRETTY_FUNCTION__); + CmdSetMcastAddr(); + return; + + case eCmdEnableInterface: + LOGDEBUG("++++ CMD ++++ %s Received eCmdEnableInterface", __PRETTY_FUNCTION__); + CmdEnableInterface(); + return; + // WRITE(6) - case 0x0a: + case eCmdWrite6: + LOGDEBUG("++++ CMD ++++ %s Received eCmdWrite6", __PRETTY_FUNCTION__); CmdWrite6(); return; // SEEK(6) - case 0x0b: + case eCmdSeek6: + LOGDEBUG("++++ CMD ++++ %s Received eCmdSeek6", __PRETTY_FUNCTION__); CmdSeek6(); return; // INQUIRY - case 0x12: + case eCmdInquiry: + LOGDEBUG("++++ CMD ++++ %s Received eCmdInquiry", __PRETTY_FUNCTION__); CmdInquiry(); return; // MODE SELECT - case 0x15: + case eCmdModeSelect: + LOGDEBUG("++++ CMD ++++ %s Received eCmdModeSelect", __PRETTY_FUNCTION__); CmdModeSelect(); return; - // MDOE SENSE - case 0x1a: + // MODE SENSE + case eCmdModeSense: + LOGDEBUG("++++ CMD ++++ %s Received eCmdModeSense", __PRETTY_FUNCTION__); CmdModeSense(); return; // START STOP UNIT - case 0x1b: + case eCmdStartStop: + LOGDEBUG("++++ CMD ++++ %s Received eCmdStartStop", __PRETTY_FUNCTION__); CmdStartStop(); return; // SEND DIAGNOSTIC - case 0x1d: + case eCmdSendDiag: + LOGDEBUG("++++ CMD ++++ %s Received eCmdSendDiag", __PRETTY_FUNCTION__); CmdSendDiag(); return; // PREVENT/ALLOW MEDIUM REMOVAL - case 0x1e: + case eCmdRemoval: CmdRemoval(); return; // READ CAPACITY - case 0x25: + case eCmdReadCapacity: CmdReadCapacity(); return; // READ(10) - case 0x28: + case eCmdRead10: + LOGDEBUG("++++ CMD ++++ %s Received eCmdRead10", __PRETTY_FUNCTION__); CmdRead10(); return; // WRITE(10) - case 0x2a: + // WRITE and VERIFY(10) + case eCmdWrite10: + case eCmdWriteAndVerify10: + LOGDEBUG("++++ CMD ++++ %s Received eCmdWrite10", __PRETTY_FUNCTION__); CmdWrite10(); return; // SEEK(10) - case 0x2b: + case eCmdSeek10: CmdSeek10(); return; - // WRITE and VERIFY - case 0x2e: - CmdWrite10(); - return; - // VERIFY - case 0x2f: + case eCmdVerify: CmdVerify(); return; // SYNCHRONIZE CACHE - case 0x35: + case eCmdSynchronizeCache: CmdSynchronizeCache(); return; // READ DEFECT DATA(10) - case 0x37: + case eCmdReadDefectData10: CmdReadDefectData10(); return; // READ TOC - case 0x43: + case eCmdReadToc: CmdReadToc(); return; // PLAY AUDIO(10) - case 0x45: + case eCmdPlayAudio10: CmdPlayAudio10(); return; // PLAY AUDIO MSF - case 0x47: + case eCmdPlayAudioMSF: CmdPlayAudioMSF(); return; // PLAY AUDIO TRACK - case 0x48: + case eCmdPlayAudioTrack: CmdPlayAudioTrack(); return; // MODE SELECT(10) - case 0x55: + case eCmdModeSelect10: CmdModeSelect10(); return; // MDOE SENSE(10) - case 0x5a: + case eCmdModeSense10: CmdModeSense10(); return; // SPECIFY (SASI only/Suppress warning when using SxSI) - case 0xc2: + case eCmdInvalid: CmdInvalid(); return; + default: + // No other support + LOGWARN("%s Received unsupported command: $%02X", __PRETTY_FUNCTION__, (BYTE)ctrl.cmd[0]); + CmdInvalid(); } + return; - // No other support - Log(Log::Normal, "Unsupported command received: $%02X", ctrl.cmd[0]); - CmdInvalid(); } //--------------------------------------------------------------------------- @@ -424,13 +447,12 @@ void FASTCALL SCSIDEV::Execute() void FASTCALL SCSIDEV::MsgOut() { ASSERT(this); + LOGTRACE("%s ID: %d",__PRETTY_FUNCTION__, this->GetSCSIID()); // Phase change if (ctrl.phase != BUS::msgout) { -#if defined(DISK_LOG) - Log(Log::Normal, "Message Out Phase"); -#endif // DISK_LOG + LOGTRACE("Message Out Phase"); // Message out phase after selection // process the IDENTIFY message @@ -460,23 +482,8 @@ void FASTCALL SCSIDEV::MsgOut() return; } -#ifdef RASCSI // Receive Receive(); -#else - // Requesting - if (ctrl.bus->GetREQ()) { - // Sent by the initiator - if (ctrl.bus->GetACK()) { - Receive(); - } - } else { - // Request the initator to - if (!ctrl.bus->GetACK()) { - ReceiveNext(); - } - } -#endif // RASCSI } //--------------------------------------------------------------------------- @@ -507,9 +514,7 @@ void FASTCALL SCSIDEV::Error() return; } -#if defined(DISK_LOG) - Log(Log::Normal, "Error (to status phase)"); -#endif // DISK_LOG + LOGTRACE( "%s Error (to status phase)", __PRETTY_FUNCTION__); // Set status and message(CHECK CONDITION) ctrl.status = 0x02; @@ -539,9 +544,7 @@ void FASTCALL SCSIDEV::CmdInquiry() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "INQUIRY Command"); -#endif // DISK_LOG + LOGTRACE("%s INQUIRY Command", __PRETTY_FUNCTION__); // Find a valid unit disk = NULL; @@ -554,8 +557,9 @@ void FASTCALL SCSIDEV::CmdInquiry() // Processed on the disk side (it is originally processed by the controller) if (disk) { - major = (DWORD)rascsi_major_version; - minor = (DWORD)rascsi_minor_version; + major = (DWORD)(RASCSI >> 8); + minor = (DWORD)(RASCSI & 0xff); + LOGTRACE("%s Buffer size is %d",__PRETTY_FUNCTION__, ctrl.bufsize); ctrl.length = ctrl.unit[lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor); } else { @@ -588,9 +592,7 @@ void FASTCALL SCSIDEV::CmdModeSelect() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SELECT Command"); -#endif // DISK_LOG + LOGTRACE( "%s MODE SELECT Command", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -622,9 +624,7 @@ void FASTCALL SCSIDEV::CmdModeSense() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SENSE Command "); -#endif // DISK_LOG + LOGTRACE( "%s MODE SENSE Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -637,8 +637,7 @@ void FASTCALL SCSIDEV::CmdModeSense() ctrl.length = ctrl.unit[lun]->ModeSense(ctrl.cmd, ctrl.buffer); ASSERT(ctrl.length >= 0); if (ctrl.length == 0) { - Log(Log::Warning, - "Not supported MODE SENSE page $%02X", ctrl.cmd[2]); + LOGWARN("%s Not supported MODE SENSE page $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[2]); // Failure (Error) Error(); @@ -661,9 +660,7 @@ void FASTCALL SCSIDEV::CmdStartStop() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "START STOP UNIT Command "); -#endif // DISK_LOG + LOGTRACE( "%s START STOP UNIT Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -696,9 +693,7 @@ void FASTCALL SCSIDEV::CmdSendDiag() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "SEND DIAGNOSTIC Command "); -#endif // DISK_LOG + LOGTRACE( "%s SEND DIAGNOSTIC Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -731,9 +726,7 @@ void FASTCALL SCSIDEV::CmdRemoval() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "PREVENT/ALLOW MEDIUM REMOVAL Command "); -#endif // DISK_LOG + LOGTRACE( "%s PREVENT/ALLOW MEDIUM REMOVAL Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -766,9 +759,7 @@ void FASTCALL SCSIDEV::CmdReadCapacity() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "READ CAPACITY Command "); -#endif // DISK_LOG + LOGTRACE( "%s READ CAPACITY Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -829,9 +820,7 @@ void FASTCALL SCSIDEV::CmdRead10() ctrl.blocks <<= 8; ctrl.blocks |= ctrl.cmd[8]; -#if defined(DISK_LOG) - Log(Log::Normal, "READ(10) command record=%08X block=%d", record, ctrl.blocks); -#endif // DISK_LOG + LOGTRACE("%s READ(10) command record=%08X block=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks); // Do not process 0 blocks if (ctrl.blocks == 0) { @@ -840,7 +829,7 @@ void FASTCALL SCSIDEV::CmdRead10() } // Command processing on drive - ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); + ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, ctrl.buffer, record); if (ctrl.length <= 0) { // Failure (Error) Error(); @@ -891,10 +880,7 @@ void FASTCALL SCSIDEV::CmdWrite10() ctrl.blocks <<= 8; ctrl.blocks |= ctrl.cmd[8]; -#if defined(DISK_LOG) - Log(Log::Normal, - "WRTIE(10) command record=%08X blocks=%d", record, ctrl.blocks); -#endif // DISK_LOG + LOGTRACE("%s WRTIE(10) command record=%08X blocks=%d",__PRETTY_FUNCTION__, (unsigned int)record, (unsigned int)ctrl.blocks); // Do not process 0 blocks if (ctrl.blocks == 0) { @@ -929,9 +915,7 @@ void FASTCALL SCSIDEV::CmdSeek10() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "SEEK(10) Command "); -#endif // DISK_LOG + LOGTRACE( "%s SEEK(10) Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -984,10 +968,7 @@ void FASTCALL SCSIDEV::CmdVerify() ctrl.blocks <<= 8; ctrl.blocks |= ctrl.cmd[8]; -#if defined(DISK_LOG) - Log(Log::Normal, - "VERIFY command record=%08X blocks=%d", record, ctrl.blocks); -#endif // DISK_LOG + LOGTRACE("%s VERIFY command record=%08X blocks=%d",__PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks); // Do not process 0 blocks if (ctrl.blocks == 0) { @@ -1011,7 +992,7 @@ void FASTCALL SCSIDEV::CmdVerify() } // Test loading - ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); + ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, ctrl.buffer, record); if (ctrl.length <= 0) { // Failure (Error) Error(); @@ -1060,9 +1041,7 @@ void FASTCALL SCSIDEV::CmdReadDefectData10() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "READ DEFECT DATA(10) Command "); -#endif // DISK_LOG + LOGTRACE( "%s READ DEFECT DATA(10) Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1218,9 +1197,7 @@ void FASTCALL SCSIDEV::CmdModeSelect10() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SELECT10 Command "); -#endif // DISK_LOG + LOGTRACE( "%s MODE SELECT10 Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1252,9 +1229,7 @@ void FASTCALL SCSIDEV::CmdModeSense10() ASSERT(this); -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SENSE(10) Command "); -#endif // DISK_LOG + LOGTRACE( "%s MODE SENSE(10) Command ", __PRETTY_FUNCTION__); // Logical Unit lun = (ctrl.cmd[1] >> 5) & 0x07; @@ -1267,8 +1242,7 @@ void FASTCALL SCSIDEV::CmdModeSense10() ctrl.length = ctrl.unit[lun]->ModeSense10(ctrl.cmd, ctrl.buffer); ASSERT(ctrl.length >= 0); if (ctrl.length == 0) { - Log(Log::Warning, - "Not supported MODE SENSE(10) page $%02X", ctrl.cmd[2]); + LOGWARN("%s Not supported MODE SENSE(10) page $%02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[2]); // Failure (Error) Error(); @@ -1299,7 +1273,9 @@ void FASTCALL SCSIDEV::CmdGetMessage10() } // Error if not a host bridge - if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'B', 'R')) { + if ((ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'B', 'R')) && + (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'N', 'L'))){ + LOGWARN("Received a GetMessage10 command for a non-bridge unit"); Error(); return; } @@ -1333,6 +1309,8 @@ void FASTCALL SCSIDEV::CmdGetMessage10() // // SEND MESSAGE(10) // +// This Send Message command is used by the X68000 host driver +// //--------------------------------------------------------------------------- void FASTCALL SCSIDEV::CmdSendMessage10() { @@ -1349,6 +1327,7 @@ void FASTCALL SCSIDEV::CmdSendMessage10() // Error if not a host bridge if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'B', 'R')) { + LOGERROR("Received CmdSendMessage10 for a non-bridge device"); Error(); return; } @@ -1381,6 +1360,186 @@ void FASTCALL SCSIDEV::CmdSendMessage10() DataOut(); } +//--------------------------------------------------------------------------- +// +// Retrieve Statistics (09) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdRetrieveStats() +{ + DWORD lun; + SCSIDaynaPort *dayna_port; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Error if not a DaynaPort SCSI Link + if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P')){ + LOGWARN("Received a CmdRetrieveStats command for a non-daynaport unit %08X", (unsigned int)ctrl.unit[lun]->GetID()); + Error(); + return; + } + + // Process with drive + dayna_port = (SCSIDaynaPort*)ctrl.unit[lun]; + ctrl.length = dayna_port->RetrieveStats(ctrl.cmd, ctrl.buffer); + + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.blocks = 1; + ctrl.next = 1; + + // Data in phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// Set Interface Mode (0c) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdSetIfaceMode() +{ + DWORD lun; + // BOOL status; + SCSIDaynaPort *dayna_port; + + ASSERT(this); + + LOGTRACE("%s",__PRETTY_FUNCTION__); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Error if not a DaynaPort SCSI Link + if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P')){ + LOGWARN("%s Received a CmdRetrieveStats command for a non-daynaport unit %08X", __PRETTY_FUNCTION__, (unsigned int)ctrl.unit[lun]->GetID()); + Error(); + return; + } + + dayna_port = (SCSIDaynaPort*)ctrl.unit[lun]; + + // Check whether this command is telling us to "Set Interface Mode" + // or "Set MAC Address" + + ctrl.length = dayna_port->RetrieveStats(ctrl.cmd, ctrl.buffer); + switch(ctrl.cmd[5]){ + case SCSIDaynaPort::CMD_SCSILINK_SETMODE: + dayna_port->SetMode(ctrl.cmd, ctrl.buffer); + Status(); + break; + break; + case SCSIDaynaPort::CMD_SCSILINK_SETMAC: + ctrl.length = 6; + // Write phase + DataOut(); + break; + default: + LOGWARN("%s Unknown SetInterface command received: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[5]); + } +} + +//--------------------------------------------------------------------------- +// +// Set the multicast address +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdSetMcastAddr() +{ + DWORD lun; + + ASSERT(this); + + LOGTRACE("%s Set Multicast Address Command ", __PRETTY_FUNCTION__); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P')){ + LOGWARN("Received a SetMcastAddress command for a non-daynaport unit"); + Error(); + return; + } + + // Command processing on drive + ctrl.length = (DWORD)ctrl.cmd[4]; + + // ASSERT(ctrl.length >= 0); + if (ctrl.length == 0) { + LOGWARN("%s Not supported SetMcastAddr Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[2]); + + // Failure (Error) + Error(); + return; + } + + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// Enable/disable Interface (0e) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdEnableInterface() +{ + DWORD lun=0; + BOOL status; + SCSIDaynaPort *dayna_port; + + ASSERT(this); + + LOGTRACE("%s",__PRETTY_FUNCTION__); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Error if not a DaynaPort SCSI Link + if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P')){ + LOGWARN("%s Received a CmdRetrieveStats command for a non-daynaport unit %08X", __PRETTY_FUNCTION__, (unsigned int)ctrl.unit[lun]->GetID()); + Error(); + return; + } + + dayna_port = (SCSIDaynaPort*)ctrl.unit[lun]; + + // Command processing on drive + status = dayna_port->EnableInterface(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + + //=========================================================================== // // Data Transfer @@ -1406,6 +1565,7 @@ void FASTCALL SCSIDEV::Send() #ifdef RASCSI //if Length! = 0, send if (ctrl.length != 0) { + LOGTRACE("%s sending handhake with offset %lu, length %lu", __PRETTY_FUNCTION__, ctrl.offset, ctrl.length); len = ctrl.bus->SendHandShake( &ctrl.buffer[ctrl.offset], ctrl.length); @@ -1444,6 +1604,7 @@ void FASTCALL SCSIDEV::Send() if (ctrl.blocks != 0) { // // set next buffer (set offset, length) result = XferIn(ctrl.buffer); + LOGTRACE("%s processing after data collection. Blocks: %lu", __PRETTY_FUNCTION__, ctrl.blocks); #ifndef RASCSI ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); #endif // RASCSI @@ -1458,6 +1619,7 @@ void FASTCALL SCSIDEV::Send() // Continue sending if block !=0 if (ctrl.blocks != 0){ + LOGTRACE("%s Continuing to send. blocks = %lu", __PRETTY_FUNCTION__, ctrl.blocks); ASSERT(ctrl.length > 0); ASSERT(ctrl.offset == 0); #ifndef RASCSI @@ -1468,6 +1630,7 @@ void FASTCALL SCSIDEV::Send() } // Move to next phase + LOGTRACE("%s Move to next phase %s (%d)", __PRETTY_FUNCTION__, BUS::GetPhaseStrRaw(ctrl.phase), ctrl.phase); switch (ctrl.phase) { // Message in phase case BUS::msgin: @@ -1530,132 +1693,52 @@ void FASTCALL SCSIDEV::SendNext() } #endif // RASCSI -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Receive data -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Receive() -{ - DWORD data; - - ASSERT(this); - - // Req is up - ASSERT(ctrl.bus->GetREQ()); - ASSERT(!ctrl.bus->GetIO()); - - // Get data - data = (DWORD)ctrl.bus->GetDAT(); - - // Signal line operated by the target - ctrl.bus->SetREQ(FALSE); - - switch (ctrl.phase) { - // Command phase - case BUS::command: - ctrl.cmd[ctrl.offset] = data; -#if defined(DISK_LOG) - Log(Log::Normal, "Command phase $%02X", data); -#endif // DISK_LOG - - // Set the length again with the first data (offset 0) - if (ctrl.offset == 0) { - if (ctrl.cmd[0] >= 0x20) { - // 10バイトCDB - ctrl.length = 10; - } - } - break; - - // Message out phase - case BUS::msgout: - ctrl.message = data; -#if defined(DISK_LOG) - Log(Log::Normal, "Message out phase $%02X", data); -#endif // DISK_LOG - break; - - // Data out phase - case BUS::dataout: - ctrl.buffer[ctrl.offset] = (BYTE)data; - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} -#endif // RASCSI - -#ifdef RASCSI //--------------------------------------------------------------------------- // // Receive Data // //--------------------------------------------------------------------------- void FASTCALL SCSIDEV::Receive() -#else -//--------------------------------------------------------------------------- -// -// Continue receiving data -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::ReceiveNext() -#endif // RASCSI { -#ifdef RASCSI int len; -#endif // RASCSI BOOL result; int i; BYTE data; ASSERT(this); + LOGTRACE("%s",__PRETTY_FUNCTION__); + // REQ is low ASSERT(!ctrl.bus->GetREQ()); ASSERT(!ctrl.bus->GetIO()); -#ifdef RASCSI // Length != 0 if received if (ctrl.length != 0) { + LOGTRACE("%s length was != 0", __PRETTY_FUNCTION__); // Receive len = ctrl.bus->ReceiveHandShake( &ctrl.buffer[ctrl.offset], ctrl.length); // If not able to receive all, move to status phase if (len != (int)ctrl.length) { + LOGERROR("%s Not able to receive all data. Going to error",__PRETTY_FUNCTION__); Error(); return; } // Offset and Length ctrl.offset += ctrl.length; - ctrl.length = 0;; + ctrl.length = 0; return; } -#else - // Offset and Length - ASSERT(ctrl.length >= 1); - ctrl.offset++; - ctrl.length--; - - // If length!=0, set req again - if (ctrl.length != 0) { - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); - return; - } -#endif // RASCSI // Block subtraction, result initialization ctrl.blocks--; result = TRUE; // Processing after receiving data (by phase) + LOGTRACE("%s ctrl.phase: %d (%s)",__PRETTY_FUNCTION__, (int)ctrl.phase, BUS::GetPhaseStrRaw(ctrl.phase)); switch (ctrl.phase) { // Data out phase @@ -1696,10 +1779,6 @@ void FASTCALL SCSIDEV::ReceiveNext() if (ctrl.blocks != 0){ ASSERT(ctrl.length > 0); ASSERT(ctrl.offset == 0); -#ifndef RASCSI - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI return; } @@ -1707,7 +1786,6 @@ void FASTCALL SCSIDEV::ReceiveNext() switch (ctrl.phase) { // Command phase case BUS::command: -#ifdef RASCSI // Command data transfer len = 6; if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) { @@ -1716,11 +1794,8 @@ void FASTCALL SCSIDEV::ReceiveNext() } for (i = 0; i < len; i++) { ctrl.cmd[i] = (DWORD)ctrl.buffer[i]; -#if defined(DISK_LOG) - Log(Log::Normal, "Command $%02X", ctrl.cmd[i]); -#endif // DISK_LOG + LOGTRACE("%s Command $%02X",__PRETTY_FUNCTION__, (int)ctrl.cmd[i]); } -#endif // RASCSI // Execution Phase Execute(); @@ -1734,10 +1809,7 @@ void FASTCALL SCSIDEV::ReceiveNext() ctrl.offset = 0; ctrl.length = 1; ctrl.blocks = 1; -#ifndef RASCSI - // Request message - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI + return; } @@ -1750,20 +1822,14 @@ void FASTCALL SCSIDEV::ReceiveNext() // ABORT if (data == 0x06) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code ABORT $%02X", data); -#endif // DISK_LOG + LOGTRACE("Message code ABORT $%02X", (int)data); BusFree(); return; } // BUS DEVICE RESET if (data == 0x0C) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code BUS DEVICE RESET $%02X", data); -#endif // DISK_LOG + LOGTRACE("Message code BUS DEVICE RESET $%02X", (int)data); scsi.syncoffset = 0; BusFree(); return; @@ -1771,18 +1837,12 @@ void FASTCALL SCSIDEV::ReceiveNext() // IDENTIFY if (data >= 0x80) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code IDENTIFY $%02X", data); -#endif // DISK_LOG + LOGTRACE("Message code IDENTIFY $%02X", (int)data); } // Extended Message if (data == 0x01) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code EXTENDED MESSAGE $%02X", data); -#endif // DISK_LOG + LOGTRACE("Message code EXTENDED MESSAGE $%02X", (int)data); // Check only when synchronous transfer is possible if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) { diff --git a/src/raspberrypi/controllers/scsidev_ctrl.h b/src/raspberrypi/controllers/scsidev_ctrl.h index f830b2d0..c5318efd 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.h +++ b/src/raspberrypi/controllers/scsidev_ctrl.h @@ -38,13 +38,74 @@ public: BYTE msb[256]; } scsi_t; + + enum scsi_message_code : BYTE { + eMsgCodeAbort = 0x06, + eMsgCodeAbortTag = 0x0D, + eMsgCodeBusDeviceReset = 0x0C, + eMsgCodeClearQueue = 0x0E, + eMsgCodeCommandComplete = 0x00, + eMsgCodeDisconnect = 0x04, + eMsgCodeIdentify = 0x80, + eMsgCodeIgnoreWideResidue = 0x23, // (Two Bytes) + eMsgCodeInitiateRecovery = 0x0F, + eMsgCodeInitiatorDetectedError = 0x05, + eMsgCodeLinkedCommandComplete = 0x0A, + eMsgCodeLinkedCommandCompleteWithFlag = 0x0B, + eMsgCodeMessageParityError = 0x09, + eMsgCodeMessageReject = 0x07, + eMsgCodeNoOperation = 0x08, + eMsgCodeHeadOfQueueTag = 0x21, + eMsgCodeOrderedQueueTag = 0x22, + eMsgCodeSimpleQueueTag = 0x20, + eMsgCodeReleaseRecovery = 0x10, + eMsgCodeRestorePointers = 0x03, + eMsgCodeSaveDataPointer = 0x02, + eMsgCodeTerminateIOProcess = 0x11, + }; + + + enum scsi_command : BYTE { + eCmdTestUnitReady = 0x00, + eCmdRezero = 0x01, + eCmdRequestSense = 0x03, + eCmdFormat = 0x04, + eCmdReassign = 0x07, + eCmdRead6 = 0x08, + eCmdRetrieveStats = 0x09, // DaynaPort specific command + eCmdWrite6 = 0x0A, + eCmdSeek6 = 0x0B, + eCmdSetIfaceMode = 0x0C, // DaynaPort specific command + eCmdSetMcastAddr = 0x0D, // DaynaPort specific command + eCmdEnableInterface = 0x0E, // DaynaPort specific command + eCmdInquiry = 0x12, + eCmdModeSelect = 0x15, + eCmdModeSense = 0x1A, + eCmdStartStop = 0x1B, + eCmdRcvDiag = 0x1C, + eCmdSendDiag = 0x1D, + eCmdRemoval = 0x1E, + eCmdReadCapacity = 0x25, + eCmdRead10 = 0x28, + eCmdWrite10 = 0x2A, + eCmdSeek10 = 0x2B, + eCmdWriteAndVerify10 = 0x2E, + eCmdVerify = 0x2F, + eCmdSynchronizeCache = 0x35, + eCmdReadDefectData10 = 0x37, + eCmdReadToc = 0x43, + eCmdPlayAudio10 = 0x45, + eCmdPlayAudioMSF = 0x47, + eCmdPlayAudioTrack = 0x48, + eCmdModeSelect10 = 0x55, + eCmdModeSense10 = 0x5A, + eCmdInvalid = 0xC2, // (SASI only/Suppress warning when using SxSI) + eCmdSasiCmdAssign = 0x0e, // This isn't used by SCSI, and can probably be removed. + }; + public: // Basic Functions -#ifdef RASCSI SCSIDEV(); -#else - SCSIDEV(Device *dev); -#endif // RASCSI // Constructor void FASTCALL Reset(); @@ -119,8 +180,16 @@ private: // GET MESSAGE(10) command void FASTCALL CmdSendMessage10(); // SEND MESSAGE(10) command + void FASTCALL CmdRetrieveStats(); + // DaynaPort specific command + void FASTCALL CmdSetIfaceMode(); + // DaynaPort specific command + void FASTCALL CmdSetMcastAddr(); + // DaynaPort specific command + void FASTCALL CmdEnableInterface(); + // DaynaPort specific command - // データ転送 + // Data transfer void FASTCALL Send(); // Send data #ifndef RASCSI diff --git a/src/raspberrypi/devices/ctapdriver.cpp b/src/raspberrypi/devices/ctapdriver.cpp index e06e3eb0..098c20df 100644 --- a/src/raspberrypi/devices/ctapdriver.cpp +++ b/src/raspberrypi/devices/ctapdriver.cpp @@ -5,16 +5,19 @@ // // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS +// Copyright (C) akuker // -// Imported NetBSD support and some optimisation patch by Rin Okuyama. +// Imported NetBSD support and some optimisation patches by Rin Okuyama. // // [ TAP Driver ] // //--------------------------------------------------------------------------- +#include // For crc32() #include "os.h" #include "xm6.h" #include "ctapdriver.h" +#include "log.h" //--------------------------------------------------------------------------- // @@ -23,6 +26,7 @@ //--------------------------------------------------------------------------- CTapDriver::CTapDriver() { + LOGTRACE("%s",__PRETTY_FUNCTION__); // Initialization m_hTAP = -1; memset(&m_MacAddr, 0, sizeof(m_MacAddr)); @@ -36,38 +40,56 @@ CTapDriver::CTapDriver() #ifdef __linux__ BOOL FASTCALL CTapDriver::Init() { + LOGTRACE("%s",__PRETTY_FUNCTION__); + char dev[IFNAMSIZ] = "ras0"; struct ifreq ifr; int ret; ASSERT(this); + LOGTRACE("Opening Tap device"); // TAP device initilization if ((m_hTAP = open("/dev/net/tun", O_RDWR)) < 0) { - printf("Error: can't open tun\n"); + LOGERROR("Error: can't open tun. Errno: %d %s", errno, strerror(errno)); return FALSE; } + LOGTRACE("Opened tap device %d",m_hTAP); + // IFF_NO_PI for no extra packet information memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, dev, IFNAMSIZ); + LOGTRACE("Going to open %s", ifr.ifr_name); if ((ret = ioctl(m_hTAP, TUNSETIFF, (void *)&ifr)) < 0) { - printf("Error: can't ioctl TUNSETIFF\n"); + LOGERROR("Error: can't ioctl TUNSETIFF. Errno: %d %s", errno, strerror(errno)); close(m_hTAP); return FALSE; } + LOGTRACE("return code from ioctl was %d", ret); + LOGDEBUG("ip link set ras0 up"); + ret = run_system_cmd("ip link set ras0 up"); + LOGTRACE("return code from ip link set ras0 up was %d", ret); + + LOGDEBUG("brctl addif rascsi_bridge ras0"); + ret = run_system_cmd("brctl addif rascsi_bridge ras0"); + LOGTRACE("return code from brctl addif rascsi_bridge ras0 was %d", ret); + // Get MAC address + LOGTRACE("Getting the MAC address"); ifr.ifr_addr.sa_family = AF_INET; if ((ret = ioctl(m_hTAP, SIOCGIFHWADDR, &ifr)) < 0) { - printf("Error: can't ioctl SIOCGIFHWADDR\n"); + LOGERROR("Error: can't ioctl SIOCGIFHWADDR. Errno: %d %s", errno, strerror(errno)); close(m_hTAP); return FALSE; } + LOGTRACE("got the mac"); // Save MAC address memcpy(m_MacAddr, ifr.ifr_hwaddr.sa_data, sizeof(m_MacAddr)); + LOGINFO("Tap device %s created", ifr.ifr_name); return TRUE; } #endif // __linux__ @@ -82,20 +104,20 @@ BOOL FASTCALL CTapDriver::Init() // TAP Device Initialization if ((m_hTAP = open("/dev/tap", O_RDWR)) < 0) { - printf("Error: can't open tap\n"); + LOGERROR("Error: can't open tap. Errno: %d %s", errno, strerror(errno)); return FALSE; } // Get device name if (ioctl(m_hTAP, TAPGIFNAME, (void *)&ifr) < 0) { - printf("Error: can't ioctl TAPGIFNAME\n"); + LOGERROR("Error: can't ioctl TAPGIFNAME. Errno: %d %s", errno, strerror(errno)); close(m_hTAP); return FALSE; } // Get MAC address if (getifaddrs(&ifa) == -1) { - printf("Error: can't getifaddrs\n"); + LOGERROR("Error: can't getifaddrs. Errno: %d %s", errno, strerror(errno)); close(m_hTAP); return FALSE; } @@ -104,7 +126,7 @@ BOOL FASTCALL CTapDriver::Init() a->ifa_addr->sa_family == AF_LINK) break; if (a == NULL) { - printf("Error: can't get MAC address\n"); + LOGERROR("Error: can't get MAC addressErrno: %d %s", errno, strerror(errno)); close(m_hTAP); return FALSE; } @@ -114,7 +136,7 @@ BOOL FASTCALL CTapDriver::Init() sizeof(m_MacAddr)); freeifaddrs(ifa); - printf("Tap device : %s\n", ifr.ifr_name); + LOGINFO("Tap device : %s\n", ifr.ifr_name); return TRUE; } @@ -128,14 +150,59 @@ BOOL FASTCALL CTapDriver::Init() void FASTCALL CTapDriver::Cleanup() { ASSERT(this); + int result; - // TAPデバイス解放 + LOGDEBUG("brctl delif rascsi_bridge ras0"); + result = run_system_cmd("brctl delif rascsi_bridge ras0"); + if(result != EXIT_SUCCESS){ + LOGWARN("Warning: The brctl delif command failed."); + LOGWARN("You may need to manually remove the ras0 tap device from the bridge"); + } + + // Release TAP defice if (m_hTAP != -1) { close(m_hTAP); m_hTAP = -1; } } +//--------------------------------------------------------------------------- +// +// Enable +// +//--------------------------------------------------------------------------- +BOOL FASTCALL CTapDriver::Enable(){ + int result; + LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__); + result = run_system_cmd("ip link set ras0 up"); + return (result == EXIT_SUCCESS); +} + +//--------------------------------------------------------------------------- +// +// Disable +// +//--------------------------------------------------------------------------- +BOOL FASTCALL CTapDriver::Disable(){ + int result; + LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__); + result = run_system_cmd("ip link set ras0 down"); + return (result == EXIT_SUCCESS); +} + +//--------------------------------------------------------------------------- +// +// Flush +// +//--------------------------------------------------------------------------- +BOOL FASTCALL CTapDriver::Flush(){ + LOGTRACE("%s", __PRETTY_FUNCTION__); + while(PendingPackets()){ + (void)Rx(m_garbage_buffer); + } + return TRUE; +} + //--------------------------------------------------------------------------- // // MGet MAC Address @@ -154,10 +221,9 @@ void FASTCALL CTapDriver::GetMacAddr(BYTE *mac) // Receive // //--------------------------------------------------------------------------- -int FASTCALL CTapDriver::Rx(BYTE *buf) +BOOL FASTCALL CTapDriver::PendingPackets() { struct pollfd fds; - DWORD dwReceived; ASSERT(this); ASSERT(m_hTAP != -1); @@ -167,7 +233,29 @@ int FASTCALL CTapDriver::Rx(BYTE *buf) fds.events = POLLIN | POLLERR; fds.revents = 0; poll(&fds, 1, 0); + LOGTRACE("%s %u revents", __PRETTY_FUNCTION__, fds.revents); if (!(fds.revents & POLLIN)) { + return FALSE; + }else { + return TRUE; + } +} + +//--------------------------------------------------------------------------- +// +// Receive +// +//--------------------------------------------------------------------------- +int FASTCALL CTapDriver::Rx(BYTE *buf) +{ + DWORD dwReceived; + DWORD crc; + + ASSERT(this); + ASSERT(m_hTAP != -1); + + // Check if there is data that can be received + if(!PendingPackets()){ return 0; } @@ -179,14 +267,23 @@ int FASTCALL CTapDriver::Rx(BYTE *buf) // If reception is enabled if (dwReceived > 0) { - // Pad to the maximum frame size (60 bytes) excluding FCS - if (dwReceived < 60) { - memset(buf + dwReceived, 0, 60 - dwReceived); - dwReceived = 60; - } + // We need to add the Frame Check Status (FCS) CRC back onto the end of the packet. + // The Linux network subsystem removes it, since most software apps shouldn't ever + // need it. - // Add a dummy FCS - memset(buf + dwReceived, 0, 4); + // Initialize the CRC + crc = crc32(0L, Z_NULL, 0); + // Calculate the CRC + crc = crc32(crc, buf, dwReceived); + + buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF); + buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF); + buf[dwReceived + 2] = (BYTE)((crc >> 16) & 0xFF); + buf[dwReceived + 3] = (BYTE)((crc >> 24) & 0xFF); + + LOGDEBUG("%s CRC is %08lX - %02X %02X %02X %02X\n", __PRETTY_FUNCTION__, crc, buf[dwReceived+0], buf[dwReceived+1], buf[dwReceived+2], buf[dwReceived+3]); + + // Add FCS size to the received message size dwReceived += 4; } @@ -199,7 +296,7 @@ int FASTCALL CTapDriver::Rx(BYTE *buf) // Send // //--------------------------------------------------------------------------- -int FASTCALL CTapDriver::Tx(BYTE *buf, int len) +int FASTCALL CTapDriver::Tx(const BYTE *buf, int len) { ASSERT(this); ASSERT(m_hTAP != -1); diff --git a/src/raspberrypi/devices/ctapdriver.h b/src/raspberrypi/devices/ctapdriver.h index 68dffe66..02fb5695 100644 --- a/src/raspberrypi/devices/ctapdriver.h +++ b/src/raspberrypi/devices/ctapdriver.h @@ -5,6 +5,7 @@ // // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS +// Copyright (C) akuker // // Imported NetBSD support and some optimisation patch by Rin Okuyama. // @@ -38,8 +39,16 @@ public: // Get Mac Address int FASTCALL Rx(BYTE *buf); // Receive - int FASTCALL Tx(BYTE *buf, int len); + int FASTCALL Tx(const BYTE *buf, int len); // Send + BOOL FASTCALL PendingPackets(); + // Check if there are IP packets available + BOOL FASTCALL Enable(); + // Enable the ras0 interface + BOOL FASTCALL Disable(); + // Disable the ras0 interface + BOOL FASTCALL Flush(); + // Purge all of the packets that are waiting to be processed private: BYTE m_MacAddr[6]; @@ -48,6 +57,7 @@ private: // Send Valid Flag int m_hTAP; // File handle + BYTE m_garbage_buffer[ETH_FRAME_LEN]; }; #endif // ctapdriver_h diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index a05f27ac..4701b2ff 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -357,6 +357,7 @@ BOOL FASTCALL DiskTrack::Read(BYTE *buf, int sec) const ASSERT(buf); ASSERT((sec >= 0) & (sec < 0x100)); + LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec); // Error if not initialized if (!dt.init) { return FALSE; @@ -974,6 +975,47 @@ BOOL FASTCALL Disk::IsNULL() const return FALSE; } +//--------------------------------------------------------------------------- +// +// Retrieve the disk's ID +// +//--------------------------------------------------------------------------- +DWORD FASTCALL Disk::GetID() const +{ + return disk.id; +} + + +//--------------------------------------------------------------------------- +// +// Get cache writeback mode +// +//--------------------------------------------------------------------------- +BOOL FASTCALL Disk::IsCacheWB() +{ + return cache_wb; +} + +//--------------------------------------------------------------------------- +// +// Set cache writeback mode +// +//--------------------------------------------------------------------------- +void FASTCALL Disk::SetCacheWB(BOOL enable) +{ + cache_wb = enable; +} + +//--------------------------------------------------------------------------- +// +// Set unsupported command +// +//--------------------------------------------------------------------------- +void FASTCALL Disk::InvalidCmd() +{ + disk.code = DISK_INVALIDCMD; +} + //--------------------------------------------------------------------------- // // SASI Check @@ -1162,6 +1204,7 @@ BOOL FASTCALL Disk::CheckReady() if (disk.reset) { disk.code = DISK_DEVRESET; disk.reset = FALSE; + LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__); return FALSE; } @@ -1169,17 +1212,21 @@ BOOL FASTCALL Disk::CheckReady() if (disk.attn) { disk.code = DISK_ATTENTION; disk.attn = FALSE; + LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__); return FALSE; } // Return status if not ready if (!disk.ready) { disk.code = DISK_NOTREADY; + LOGTRACE("%s Disk not ready", __PRETTY_FUNCTION__); return FALSE; } // Initialization with no error disk.code = DISK_NOERROR; + LOGTRACE("%s Disk is ready!", __PRETTY_FUNCTION__); + return TRUE; } @@ -1222,6 +1269,7 @@ int FASTCALL Disk::RequestSense(const DWORD *cdb, BYTE *buf) // Size determination (according to allocation length) size = (int)cdb[4]; + LOGTRACE("%s size of data = %d", __PRETTY_FUNCTION__, size); ASSERT((size >= 0) && (size < 0x100)); // For SCSI-1, transfer 4 bytes when the size is 0 @@ -1966,7 +2014,7 @@ BOOL FASTCALL Disk::Reassign(const DWORD* /*cdb*/) // READ // //--------------------------------------------------------------------------- -int FASTCALL Disk::Read(BYTE *buf, DWORD block) +int FASTCALL Disk::Read(const DWORD *cdb, BYTE *buf, DWORD block) { ASSERT(this); ASSERT(buf); @@ -2026,11 +2074,12 @@ int FASTCALL Disk::WriteCheck(DWORD block) // WRITE // //--------------------------------------------------------------------------- -BOOL FASTCALL Disk::Write(const BYTE *buf, DWORD block) +BOOL FASTCALL Disk::Write(const DWORD *cdb, const BYTE *buf, DWORD block) { ASSERT(this); ASSERT(buf); + LOGTRACE("%s", __PRETTY_FUNCTION__); // Error if not ready if (!disk.ready) { disk.code = DISK_NOTREADY; diff --git a/src/raspberrypi/devices/disk.h b/src/raspberrypi/devices/disk.h index 725880fb..5f8e9da3 100644 --- a/src/raspberrypi/devices/disk.h +++ b/src/raspberrypi/devices/disk.h @@ -233,7 +233,7 @@ public: #endif // RASCSI // ID - DWORD FASTCALL GetID() const { return disk.id; } + DWORD FASTCALL GetID() const; // Get media ID BOOL FASTCALL IsNULL() const; // NULL check @@ -298,11 +298,11 @@ public: // FORMAT UNIT command BOOL FASTCALL Reassign(const DWORD *cdb); // REASSIGN UNIT command - virtual int FASTCALL Read(BYTE *buf, DWORD block); + virtual int FASTCALL Read(const DWORD *cdb, BYTE *buf, DWORD block); // READ command - int FASTCALL WriteCheck(DWORD block); + virtual int FASTCALL WriteCheck(DWORD block); // WRITE check - BOOL FASTCALL Write(const BYTE *buf, DWORD block); + virtual BOOL FASTCALL Write(const DWORD *cdb, const BYTE *buf, DWORD block); // WRITE command BOOL FASTCALL Seek(const DWORD *cdb); // SEEK command @@ -328,13 +328,13 @@ public: // PLAY AUDIO MSF command virtual BOOL FASTCALL PlayAudioTrack(const DWORD *cdb); // PLAY AUDIO TRACK command - void FASTCALL InvalidCmd() { disk.code = DISK_INVALIDCMD; } + void FASTCALL InvalidCmd(); // Unsupported command // Other - BOOL IsCacheWB() { return cache_wb; } + BOOL FASTCALL IsCacheWB(); // Get cache writeback mode - void SetCacheWB(BOOL enable) { cache_wb = enable; } + void FASTCALL SetCacheWB(BOOL enable); // Set cache writeback mode protected: diff --git a/src/raspberrypi/devices/scsi_daynaport.cpp b/src/raspberrypi/devices/scsi_daynaport.cpp new file mode 100644 index 00000000..4d6ce26d --- /dev/null +++ b/src/raspberrypi/devices/scsi_daynaport.cpp @@ -0,0 +1,540 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2020 akuker +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ Emulation of the DaynaPort SCSI Link Ethernet interface ] +// +// This design is derived from the SLINKCMD.TXT file, as well as David Kuder's +// Tiny SCSI Emulator +// - SLINKCMD: http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/SLINKCMD.TXT +// - Tiny SCSI : https://hackaday.io/project/18974-tiny-scsi-emulator +// +// Additional documentation and clarification is available at the +// following link: +// - https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link +// +// This does NOT include the file system functionality that is present +// in the Sharp X68000 host bridge. +// +// Note: This requires the DaynaPort SCSI Link driver. +//--------------------------------------------------------------------------- + +#include "scsi_daynaport.h" + +//=========================================================================== +// +// DaynaPort SCSI Link Ethernet Adapter +// +//=========================================================================== +const char* SCSIDaynaPort::m_vendor_name = "DAYNA "; +const char* SCSIDaynaPort::m_device_name = "SCSI/Link "; +const char* SCSIDaynaPort::m_revision = "1.4a"; +const char* SCSIDaynaPort::m_firmware_version = "01.00.00"; + +const BYTE SCSIDaynaPort::m_bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff }; + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +SCSIDaynaPort::SCSIDaynaPort() : Disk() +{ + LOGTRACE("SCSI DaynaPort Constructor"); + // DaynaPort + disk.id = MAKEID('S', 'C', 'D', 'P'); + +#if defined(__linux__) && !defined(BAREMETAL) + // TAP Driver Generation + m_tap = new CTapDriver(); + m_bTapEnable = m_tap->Init(); + if(!m_bTapEnable){ + LOGERROR("Unable to open the TAP interface"); + }else { + LOGDEBUG("Tap interface created"); + } + + LOGTRACE("%s this->reset()", __PRETTY_FUNCTION__); + this->Reset(); + disk.ready = true; + disk.reset = false; + + // Generate MAC Address + LOGTRACE("%s memset(m_mac_addr, 0x00, 6);", __PRETTY_FUNCTION__); + memset(m_mac_addr, 0x00, 6); + + // if (m_bTapEnable) { + // tap->GetMacAddr(m_mac_addr); + // m_mac_addr[5]++; + // } + // !!!!!!!!!!!!!!!!! For now, hard code the MAC address. Its annoying when it keeps changing during development! + // TODO: Remove this hard-coded address + LOGTRACE("%s m_mac_addr[0]=0x00;", __PRETTY_FUNCTION__); + m_mac_addr[0]=0x00; + m_mac_addr[1]=0x80; + m_mac_addr[2]=0x19; + m_mac_addr[3]=0x10; + m_mac_addr[4]=0x98; + m_mac_addr[5]=0xE3; + +#endif // RASCSI && !BAREMETAL + LOGTRACE("SCSIDaynaPort Constructor End"); + +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +SCSIDaynaPort::~SCSIDaynaPort() +{ + LOGTRACE("SCSIDaynaPort Destructor"); + // TAP driver release + if (m_tap) { + m_tap->Cleanup(); + delete m_tap; + } +} + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIDaynaPort::Inquiry( + const DWORD *cdb, BYTE *buffer, DWORD major, DWORD minor) +{ + DWORD allocation_length; + // scsi_cdb_6_byte_t command; + // memcpy(&command,cdb,sizeof(command)); + + ASSERT(this); + ASSERT(cdb); + ASSERT(buffer); + ASSERT(cdb[0] == 0x12); + + //allocation_length = command->length; + allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8); + // if(allocation_length != command.length){ + // LOGDEBUG("%s CDB: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, (unsigned int)cdb[0], (unsigned int)cdb[1], (unsigned int)cdb[2], (unsigned int)cdb[3], (unsigned int)cdb[4], (unsigned int)cdb[5] ); + // LOGWARN(":::::::::: Expected allocation length %04X but found %04X", (unsigned int)allocation_length, (unsigned int)command.length); + // LOGWARN(":::::::::: Doing runtime pointer conversion: %04X", ((scsi_cdb_6_byte_t*)cdb)->length); + // } + + LOGTRACE("%s Inquiry with major %ld, minor %ld. Allocaiton length: %d",__PRETTY_FUNCTION__, major, minor, (int)allocation_length); + + if(cdb[1] & 0x3) { + LOGWARN("Tiny SCSI Emulator says this is an invalid request"); + } + + if(allocation_length > 4){ + // Copy the pre-canned response + memcpy(buffer, m_target_ethernet_inquiry_response, allocation_length); + // Set the size + //buffer[4] = (BYTE)((allocation_length - 7) & 0xFF); + // The inquiry response format only allows for a 1 byte 'additional size' field + if(allocation_length > 0xFF){ + LOGWARN("%s The inquiry format only allows for a maximum of %d (0xFF + 4) bytes",\ + __PRETTY_FUNCTION__, (int)0xFF + 4) + } + } + + LOGTRACE("response size is %d", (int)allocation_length); + + // Success + disk.code = DISK_NOERROR; + return allocation_length; +} + +//--------------------------------------------------------------------------- +// +// RequestSense +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIDaynaPort::RequestSense(const DWORD *cdb, BYTE *buffer) +{ + // The DaynaPort RequestSense response will always be 9 bytes. + int size = 9; + + LOGTRACE("%s size of sense data = %d", __PRETTY_FUNCTION__, size); + + // Clear the buffer + memset(buffer, 0, size); + + // Only set the response code (70h) + buffer[0] = 0x70; + + // Clear the code + disk.code = 0x00; + + return size; +} + +//--------------------------------------------------------------------------- +// +// READ +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, DWORD block) +{ + WORD requested_length = 0; + int rx_packet_size = 0; + BOOL send_message_to_host; + scsi_resp_read_t *response = (scsi_resp_read_t*)buf; + scsi_cmd_read_6_t *command = (scsi_cmd_read_6_t*)cdb; + int read_count = 0; + + ASSERT(this); + ASSERT(buf); + + LOGTRACE("%s reading DaynaPort block %lu", __PRETTY_FUNCTION__, block); + + if(command->operation_code != 0x08){ + LOGERROR("Received unexpected cdb command: %02X. Expected 0x08", (unsigned int)command->operation_code); + } + + requested_length = (WORD)command->transfer_length; + LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, (unsigned int)requested_length, (unsigned int)requested_length); + + + // At host startup, it will send a READ(6) command with a length of 1. We should + // respond by going into the status mode with a code of 0x02 + if(requested_length == 1){ + return 0; + } + + // Some of the packets we receive will not be for us. So, we'll keep pulling messages + // until the buffer is empty, or we've read X times. (X is just a made up number) + while(read_count < 50) + { + read_count++; + + // The first 2 bytes are reserved for the length of the packet + // The next 4 bytes are reserved for a flag field + //rx_packet_size = m_tap->Rx(response->data); + rx_packet_size = m_tap->Rx(&buf[m_read_header_size]); + + // If we didn't receive anything, return size of 0 + if(rx_packet_size <= 0){ + LOGTRACE("%s No packet received", __PRETTY_FUNCTION__); + response->length = 0; + response->flags = e_no_more_data; + return m_read_header_size; + } + + LOGTRACE("%s Packet Sz %d (%08X) read: %d", __PRETTY_FUNCTION__, (unsigned int) rx_packet_size, (unsigned int) rx_packet_size, read_count); + + // This is a very basic filter to prevent unnecessary packets from + // being sent to the SCSI initiator. + send_message_to_host = FALSE; + + // Check if received packet destination MAC address matches the + // DaynaPort MAC. For IP packets, the mac_address will be the first 6 bytes + // of the data. + if (memcmp(response->data, m_mac_addr, 6) == 0) { + send_message_to_host = TRUE; + } + + // Check to see if this is a broadcast message + if (memcmp(response->data, m_bcast_addr, 6) == 0) { + send_message_to_host = TRUE; + } + + // Check to see if this is an AppleTalk Message + if (memcmp(response->data, m_apple_talk_addr, 6) == 0) { + + send_message_to_host = TRUE; + } + + // TODO: We should check to see if this message is in the multicast + // configuration from SCSI command 0x0D + + if(!send_message_to_host){ + LOGDEBUG("%s Received a packet that's not for me: %02X %02X %02X %02X %02X %02X", \ + __PRETTY_FUNCTION__, + (int)response->data[0], + (int)response->data[1], + (int)response->data[2], + (int)response->data[3], + (int)response->data[4], + (int)response->data[5]); + + // If there are pending packets to be processed, we'll tell the host that the read + // length was 0. + if(!m_tap->PendingPackets()) + { + response->length = 0; + response->flags = e_no_more_data; + return m_read_header_size; + } + } + else + { + + // TODO: Need to do some sort of size checking. The buffer can easily overflow, probably. + + + // response->length = rx_packet_size; + // if(m_tap->PendingPackets()){ + // response->flags = e_more_data_available; + // } else { + // response->flags = e_no_more_data; + // } + buf[0] = (BYTE)((rx_packet_size >> 8) & 0xFF); + buf[1] = (BYTE)(rx_packet_size & 0xFF); + + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + if(m_tap->PendingPackets()){ + buf[5] = 0x10; + } else { + buf[5] = 0; + } + + // Return the packet size + 2 for the length + 4 for the flag field + // The CRC was already appended by the ctapdriver + return rx_packet_size + m_read_header_size; + } + // If we got to this point, there are still messages in the queue, so + // we should loop back and get the next one. + } // end while + + response->length = 0; + response->flags = e_no_more_data; + return m_read_header_size; +} + +//--------------------------------------------------------------------------- +// +// WRITE check +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIDaynaPort::WriteCheck(DWORD block) +{ + LOGTRACE("%s block: %lu", __PRETTY_FUNCTION__, block); + + // Status check + if (!CheckReady()) { + return 0; + } + + if(!m_bTapEnable){ + disk.code = DISK_NOTREADY; + return 0; + } + + // Success + return 1; +} + + +//--------------------------------------------------------------------------- +// +// Write +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIDaynaPort::Write(const DWORD *cdb, const BYTE *buf, DWORD block) +{ + BYTE data_format; + WORD data_length; + // const scsi_cmd_daynaport_write_t* command = (const scsi_cmd_daynaport_write_t*)cdb; + + data_format = cdb[5]; + data_length = (WORD)cdb[4] + ((WORD)cdb[3] << 8); + + // if(data_format != command->format){ + // LOGDEBUG("%s CDB: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, (unsigned int)cdb[0], (unsigned int)cdb[1], (unsigned int)cdb[2], (unsigned int)cdb[3], (unsigned int)cdb[4], (unsigned int)cdb[5] ); + // LOGWARN("Expected data_format: %02X, but found %02X", (unsigned int)cdb[5], (unsigned int)command->format); + // } + // if(data_length != command->length){ + // LOGDEBUG("%s CDB: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, (unsigned int)cdb[0], (unsigned int)cdb[1], (unsigned int)cdb[2], (unsigned int)cdb[3], (unsigned int)cdb[4], (unsigned int)cdb[5] ); + // LOGWARN("Expected data_length: %04X, but found %04X", data_length, (unsigned int)command->length); + // } + + if(data_format == 0x00){ + m_tap->Tx(buf, data_length); + LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length); + return TRUE; + } + else if (data_format == 0x80){ + // The data length is actuall specified in the first 2 bytes of the payload + data_length=(WORD)buf[1] + ((WORD)buf[0] << 8); + m_tap->Tx(&buf[4], data_length); + LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length); + return TRUE; + } + else + { + // LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format); + LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format); + return FALSE; + } + +} + + +//--------------------------------------------------------------------------- +// +// RetrieveStats +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer) +{ + DWORD response_size; + DWORD allocation_length; + + // DWORD frame_alignment_errors; + // DWORD crc_errors; + // DWORD frames_lost; + + LOGTRACE("%s RetrieveStats ", __PRETTY_FUNCTION__); + + ASSERT(this); + ASSERT(cdb); + ASSERT(buffer); + + allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8); + LOGTRACE("%s Retrieve Stats buffer size was %d", __PRETTY_FUNCTION__, (int)allocation_length); + + // // ASSERT(cdb[0] == 0x09); + + // if(cdb[0] != 0x09) + // { + // LOGWARN("%s cdb[0] was not 0x09, as I expected. It was %02X.", __PRETTY_FUNCTION__, (unsigned int)cdb[0]); + // } + // if(cdb[4] != 0x12) + // { + // LOGWARN("%s cdb[4] was not 0x12, as I expected. It was %02X.", __PRETTY_FUNCTION__, (unsigned int)cdb[4]); + // } + + // memset(buffer,0,18); + + // memcpy(&buffer[0],m_mac_addr,sizeof(m_mac_addr)); + // // frame alignment errors + // frame_alignment_errors = htonl(0); + // memcpy(&(buffer[6]),&frame_alignment_errors,sizeof(frame_alignment_errors)); + // // CRC errors + // crc_errors = htonl(0); + // memcpy(&(buffer[10]),&crc_errors,sizeof(crc_errors)); + // // frames lost + // frames_lost = htonl(0); + // memcpy(&(buffer[14]),&frames_lost,sizeof(frames_lost)); + + for(int i=0; i< 6; i++) + { + LOGTRACE("%s CDB byte %d: %02X",__PRETTY_FUNCTION__, i, (unsigned int)cdb[i]); + } + + response_size = 18; + + + response_size = sizeof(m_scsi_link_stats); + memcpy(buffer, &m_scsi_link_stats, sizeof(m_scsi_link_stats)); + + LOGTRACE("%s response size is %d", __PRETTY_FUNCTION__, (int)response_size); + + if(response_size > allocation_length) + { + response_size = allocation_length; + LOGINFO("%s Truncating the inquiry response", __PRETTY_FUNCTION__) + } + + // Success + disk.code = DISK_NOERROR; + return response_size; + // scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb; + // scsi_resp_link_stats_t *response = (scsi_resp_link_stats_t*) buffer; + + // LOGTRACE("%s Retrieve Stats buffer size was %d", __PRETTY_FUNCTION__, command->length); + + // ASSERT(sizeof(scsi_resp_link_stats_t) == 18); + + // memcpy(response->mac_address, m_mac_addr, sizeof(m_mac_addr)); + // response->crc_errors = 0; + // response->frames_lost = 0; + // response->frame_alignment_errors = 0; + + // // Success + // disk.code = DISK_NOERROR; + // return sizeof(scsi_resp_link_stats_t); +} + +//--------------------------------------------------------------------------- +// +// Enable or Disable the interface +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIDaynaPort::EnableInterface(const DWORD *cdb) +{ + int result; + // scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb; + + // if(command->control & 0x80) + if(cdb[5] & 0x80) + + { + result = m_tap->Enable(); + if(result){ + LOGINFO("The DaynaPort interface has been ENABLED."); + } + else{ + LOGWARN("Unable to enable the DaynaPort Interface"); + } + m_tap->Flush(); + } + else + { + result = m_tap->Disable(); + if(result){ + LOGINFO("The DaynaPort interface has been DISABLED."); + } + else{ + LOGWARN("Unable to disable the DaynaPort Interface"); + } + } + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// TEST UNIT READY +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/) +{ + ASSERT(this); + LOGTRACE("%s", __PRETTY_FUNCTION__); + + // TEST UNIT READY Success + disk.code = DISK_NOERROR; + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Set Mode - enable broadcast messages +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDaynaPort::SetMode(const DWORD *cdb, BYTE *buffer) +{ + LOGTRACE("%s Setting mode", __PRETTY_FUNCTION__); + + for(size_t i=0; i= 0); - return Disk::Read(buf, block); + return Disk::Read(cdb, buf, block); } //--------------------------------------------------------------------------- diff --git a/src/raspberrypi/devices/scsicd.h b/src/raspberrypi/devices/scsicd.h index ca4b9070..2ccd9b52 100644 --- a/src/raspberrypi/devices/scsicd.h +++ b/src/raspberrypi/devices/scsicd.h @@ -122,7 +122,7 @@ private: // Wave path BOOL valid; // Open result (is it valid?) - DWORD *buf; + DWORD *m_buf; // Data buffer DWORD read; // Read pointer @@ -164,7 +164,7 @@ public: // commands int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command - int FASTCALL Read(BYTE *buf, DWORD block); + int FASTCALL Read(const DWORD *cdb, BYTE *buf, DWORD block) override; // READ command int FASTCALL ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC command diff --git a/src/raspberrypi/devices/scsihd.cpp b/src/raspberrypi/devices/scsihd.cpp index ed4c32b1..f7e7545b 100644 --- a/src/raspberrypi/devices/scsihd.cpp +++ b/src/raspberrypi/devices/scsihd.cpp @@ -100,7 +100,7 @@ BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/) // INQUIRY // //--------------------------------------------------------------------------- -int FASTCALL SCSIHD::Inquiry( +int FASTCALL SCSIHD:: Inquiry( const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) { char vendor[32]; @@ -241,7 +241,7 @@ BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length) case 0x08: // Debug code for Issue #2: // https://github.com/akuker/RASCSI/issues/2 - printf("[Unhandled page code] Received mode page code 8 with total length %d\n ", length); + LOGWARN("[Unhandled page code] Received mode page code 8 with total length %d\n ", length); for (int i = 0; i + + +//--------------------------------------------------------------------------- +// +// Run system command and wait for it to finish +// +//--------------------------------------------------------------------------- +int run_system_cmd(const char* command) +{ + pid_t pid; + int result; + int status = 0; + pid=fork(); + if(pid == 0){ + result = system(command); + exit(result); + } + waitpid(pid, &status, 0); + return status; +} \ No newline at end of file diff --git a/src/raspberrypi/os.h b/src/raspberrypi/os.h index e1da949e..9cb9f31e 100644 --- a/src/raspberrypi/os.h +++ b/src/raspberrypi/os.h @@ -5,10 +5,11 @@ // // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS +// Copyright (C) 2020 akuker // // Imported NetBSD support and some optimisation patch by Rin Okuyama. // -// [ OS固有 ] +// [ OS related definitions ] // //--------------------------------------------------------------------------- @@ -86,7 +87,7 @@ //--------------------------------------------------------------------------- // -// 基本マクロ +// Basic Macros // //--------------------------------------------------------------------------- #undef FASTCALL @@ -118,7 +119,7 @@ //--------------------------------------------------------------------------- // -// 基本型定義 +// Basic Type Definitions // //--------------------------------------------------------------------------- typedef unsigned char BYTE; @@ -154,4 +155,7 @@ typedef const char *LPCSTR; #define xstrcasecmp strcasecmp #define xstrncasecmp strncasecmp +// Run system command and wait for it to finish +extern int run_system_cmd(const char* command); + #endif // os_h diff --git a/src/raspberrypi/os_integration/rascsi.service b/src/raspberrypi/os_integration/rascsi.service index d5072387..62fe6528 100644 --- a/src/raspberrypi/os_integration/rascsi.service +++ b/src/raspberrypi/os_integration/rascsi.service @@ -9,7 +9,7 @@ ExecStart=/usr/local/bin/rascsi # Example: If you want to automatically attach a hard disk at startup, change # the ExecStart line to: # ExecStart=/usr/local/bin/rascsi -ID1 /home/pi/images/harddisk.hda -ExecStop=/usr/local/bin/rasctl -stop +# This functionality isn't implmented yet: ExecStop=/usr/local/bin/rasctl -stop StandardOutput=syslog StandardError=syslog SyslogIdentifier=RASCSI diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 8fc44ae1..9a622e60 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -21,11 +21,15 @@ #include "devices/scsicd.h" #include "devices/scsimo.h" #include "devices/scsi_host_bridge.h" +#include "devices/scsi_daynaport.h" #include "controllers/scsidev_ctrl.h" #include "controllers/sasidev_ctrl.h" #include "gpiobus.h" #include "rascsi_version.h" +#include "rasctl.h" #include "spdlog/spdlog.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include //--------------------------------------------------------------------------- // @@ -55,6 +59,7 @@ FATFS fatfs; // FatFS #else int monsocket; // Monitor Socket pthread_t monthread; // Monitor Thread +pthread_mutex_t ctrl_mutex; // Semaphore for the ctrl array static void *MonThread(void *param); #endif // BAREMETAL @@ -95,7 +100,7 @@ void Banner(int argc, char* argv[]) FPRT(stdout," FILE is disk image file.\n\n"); FPRT(stdout,"Usage: %s [-HDn FILE] ...\n\n", argv[0]); FPRT(stdout," n is X68000 SASI HD number(0-15).\n"); - FPRT(stdout," FILE is disk image file.\n\n"); + FPRT(stdout," FILE is disk image file, \"daynaport\", or \"bridge\".\n\n"); FPRT(stdout," Image type is detected based on file extension.\n"); FPRT(stdout," hdf : SASI HD image(XM6 SASI HD image)\n"); FPRT(stdout," hds : SCSI HD image(XM6 SCSI HD image)\n"); @@ -123,7 +128,13 @@ BOOL Init() #ifndef BAREMETAL struct sockaddr_in server; - int yes; + int yes, result; + + result = pthread_mutex_init(&ctrl_mutex,NULL); + if(result != EXIT_SUCCESS){ + LOGERROR("Unable to create a mutex. Err code: %d",result); + return FALSE; + } // Create socket for monitor monsocket = socket(PF_INET, SOCK_STREAM, 0); @@ -225,6 +236,8 @@ void Cleanup() if (monsocket >= 0) { close(monsocket); } + + pthread_mutex_destroy(&ctrl_mutex); #endif // BAREMETAL } @@ -262,10 +275,12 @@ void ListDevice(FILE *fp) Filepath filepath; BOOL find; char type[5]; + char dev_status[_MAX_FNAME+26]; find = FALSE; type[4] = 0; for (i = 0; i < CtrlMax * UnitNum; i++) { + strncpy(dev_status,"",sizeof(dev_status)); // Initialize ID and unit number id = i / UnitNum; un = i % UnitNum; @@ -280,7 +295,9 @@ void ListDevice(FILE *fp) if (!find) { FPRT(fp, "\n"); FPRT(fp, "+----+----+------+-------------------------------------\n"); + LOGINFO( "+----+----+------+-------------------------------------"); FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n"); + LOGINFO( "| ID | UN | TYPE | DEVICE STATUS\n"); FPRT(fp, "+----+----+------+-------------------------------------\n"); find = TRUE; } @@ -290,25 +307,26 @@ void ListDevice(FILE *fp) type[1] = (char)(pUnit->GetID() >> 16); type[2] = (char)(pUnit->GetID() >> 8); type[3] = (char)(pUnit->GetID()); - FPRT(fp, "| %d | %d | %s | ", id, un, type); // mount status output if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) { - FPRT(fp, "%s", "HOST BRIDGE"); + strncpy(dev_status,"X68000 HOST BRIDGE",sizeof(dev_status)); + } else if (pUnit->GetID() == MAKEID('S', 'C', 'D', 'P')) { + strncpy(dev_status,"DaynaPort SCSI/Link",sizeof(dev_status)); } else { pUnit->GetPath(filepath); - FPRT(fp, "%s", + snprintf(dev_status, sizeof(dev_status), "%s", (pUnit->IsRemovable() && !pUnit->IsReady()) ? "NO MEDIA" : filepath.GetPath()); } // Write protection status if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) { - FPRT(fp, "(WRITEPROTECT)"); + strcat(dev_status, "(WRITEPROTECT)"); } + FPRT(fp, "| %d | %d | %s | %s\n", id, un, type, dev_status); + LOGINFO( "| %d | %d | %s | %s", id, un, type, dev_status); - // Goto the next line - FPRT(fp, "\n"); } // If there is no controller, find will be null @@ -318,6 +336,7 @@ void ListDevice(FILE *fp) } FPRT(fp, "+----+----+------+-------------------------------------\n"); + LOGINFO( "+----+----+------+-------------------------------------"); } //--------------------------------------------------------------------------- @@ -333,6 +352,9 @@ void MapControler(FILE *fp, Disk **map) int sasi_num; int scsi_num; + // Take ownership of the ctrl data structure + pthread_mutex_lock(&ctrl_mutex); + // Replace the changed unit for (i = 0; i < CtrlMax; i++) { for (j = 0; j < UnitNum; j++) { @@ -433,6 +455,7 @@ void MapControler(FILE *fp, Disk **map) } } } + pthread_mutex_unlock(&ctrl_mutex); } //--------------------------------------------------------------------------- @@ -447,6 +470,7 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) char *ext; Filepath filepath; Disk *pUnit; + char type_str[5]; // Copy the Unit List memcpy(map, disk, sizeof(disk)); @@ -468,7 +492,7 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) // Distinguish between SASI and SCSI ext = NULL; pUnit = NULL; - if (type == 0) { + if (type == rasctl_dev_sasi_hd) { // Passed the check if (!file) { return FALSE; @@ -488,16 +512,16 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) // If the extension is not SASI type, replace with SCSI ext = &file[len - 3]; if (xstrcasecmp(ext, "hdf") != 0) { - type = 1; + type = rasctl_dev_scsi_hd; } } // Create a new drive, based upon type switch (type) { - case 0: // HDF + case rasctl_dev_sasi_hd: // HDF pUnit = new SASIHD(); break; - case 1: // HDS/HDN/HDI/NHD/HDA + case rasctl_dev_scsi_hd: // HDS/HDN/HDI/NHD/HDA if (ext == NULL) { break; } @@ -510,28 +534,37 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) pUnit = new SCSIHD(); } break; - case 2: // MO + case rasctl_dev_mo: // MO pUnit = new SCSIMO(); break; - case 3: // CD + case rasctl_dev_cd: // CD pUnit = new SCSICD(); break; - case 4: // BRIDGE + case rasctl_dev_br: // BRIDGE pUnit = new SCSIBR(); break; + // case rasctl_dev_nuvolink: // Nuvolink + // pUnit = new SCSINuvolink(); + // break; + case rasctl_dev_daynaport: // DaynaPort SCSI Link + pUnit = new SCSIDaynaPort(); + LOGTRACE("Done creating SCSIDayanPort"); + break; default: FPRT(fp, "Error : Invalid device type\n"); + LOGWARN("rasctl sent a command for an invalid drive type: %d", type); return FALSE; } // drive checks files - if (type <= 1 || (type <= 3 && xstrcasecmp(file, "-") != 0)) { + if (type <= rasctl_dev_scsi_hd || (type <= rasctl_dev_cd && xstrcasecmp(file, "-") != 0)) { // Set the Path filepath.SetPath(file); // Open the file path if (!pUnit->Open(filepath)) { FPRT(fp, "Error : File open error [%s]\n", file); + LOGWARN("rasctl tried to open an invalid file %s", file); delete pUnit; return FALSE; } @@ -545,18 +578,26 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) // Re-map the controller MapControler(fp, map); + type_str[0] = (char)(pUnit->GetID() >> 24); + type_str[1] = (char)(pUnit->GetID() >> 16); + type_str[2] = (char)(pUnit->GetID() >> 8); + type_str[3] = (char)(pUnit->GetID()); + type_str[4] = '\0'; + LOGINFO("rasctl added new %s device. ID: %d UN: %d", type_str, id, un); return TRUE; } // Is this a valid command? if (cmd > 4) { FPRT(fp, "Error : Invalid command\n"); + LOGINFO("rasctl sent an invalid command: %d",cmd); return FALSE; } // Does the controller exist? if (ctrl[id] == NULL) { FPRT(fp, "Error : No such device\n"); + LOGWARN("rasctl sent a command for invalid controller %d", id); return FALSE; } @@ -564,11 +605,24 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) pUnit = disk[id * UnitNum + un]; if (pUnit == NULL) { FPRT(fp, "Error : No such device\n"); + LOGWARN("rasctl sent a command for invalid unit ID %d UN %d", id, un); return FALSE; } + type_str[0] = (char)(map[id * UnitNum + un]->GetID() >> 24); + type_str[1] = (char)(map[id * UnitNum + un]->GetID() >> 16); + type_str[2] = (char)(map[id * UnitNum + un]->GetID() >> 8); + type_str[3] = (char)(map[id * UnitNum + un]->GetID()); + type_str[4] = '\0'; + // Disconnect Command if (cmd == 1) { // DETACH + type_str[0] = (char)(map[id * UnitNum + un]->GetID() >> 24); + type_str[1] = (char)(map[id * UnitNum + un]->GetID() >> 16); + type_str[2] = (char)(map[id * UnitNum + un]->GetID() >> 8); + type_str[3] = (char)(map[id * UnitNum + un]->GetID()); + type_str[4] = '\0'; + LOGINFO("rasctl command disconnect %s at ID: %d UN: %d", type_str, id, un); // Free the existing unit map[id * UnitNum + un] = NULL; @@ -580,7 +634,8 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) // Valid only for MO or CD if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O') && pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) { - FPRT(fp, "Error : Operation denied(Deveice isn't removable)\n"); + FPRT(fp, "Error : Operation denied (Device type %s isn't removable)\n", type_str); + LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, type_str); return FALSE; } @@ -588,6 +643,7 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) case 2: // INSERT // Set the file path filepath.SetPath(file); + LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", file, type_str, id, un); // Open the file if (!pUnit->Open(filepath)) { @@ -597,17 +653,21 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) break; case 3: // EJECT + LOGINFO("rasctl commands eject %s ID: %d UN: %d", type_str, id, un); pUnit->Eject(TRUE); break; case 4: // PROTECT if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) { FPRT(fp, "Error : Operation denied(Deveice isn't MO)\n"); + LOGWARN("rasctl sent an invalid PROTECT command for %s ID: %d UN: %d", type_str, id, un); return FALSE; } + LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), type_str, id, un); pUnit->WriteP(!pUnit->IsWriteP()); break; default: + LOGWARN("Received unknown command from rasctl: %d", cmd); ASSERT(FALSE); return FALSE; } @@ -1064,6 +1124,9 @@ int main(int argc, char* argv[]) #endif // BAREMETAL spdlog::set_level(spdlog::level::trace); + // Create a thread-safe stdout logger to process the log messages + auto logger = spdlog::stdout_color_mt("rascsi stdout logger"); + LOGTRACE("Entering the function %s with %d arguments", __PRETTY_FUNCTION__, argc); // Output the Banner Banner(argc, argv); @@ -1159,6 +1222,8 @@ int main(int argc, char* argv[]) continue; } + pthread_mutex_lock(&ctrl_mutex); + // Notify all controllers data = bus->GetDAT(); for (i = 0; i < CtrlMax; i++) { @@ -1179,6 +1244,7 @@ int main(int argc, char* argv[]) // Return to bus monitoring if the selection phase has not started if (phase != BUS::selection) { + pthread_mutex_unlock(&ctrl_mutex); continue; } @@ -1201,6 +1267,8 @@ int main(int argc, char* argv[]) break; } } + pthread_mutex_unlock(&ctrl_mutex); + #if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL) // Set the scheduling priority back to normal diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index c99e5d01..406b814f 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -11,6 +11,7 @@ #include "os.h" #include "rascsi_version.h" +#include "rasctl.h" //--------------------------------------------------------------------------- // @@ -95,7 +96,7 @@ int main(int argc, char* argv[]) fprintf(stderr, " where ID := {0|1|2|3|4|5|6|7}\n"); fprintf(stderr, " UNIT := {0|1} default setting is 0.\n"); fprintf(stderr, " CMD := {attach|detach|insert|eject|protect}\n"); - fprintf(stderr, " TYPE := {hd|mo|cd|bridge}\n"); + fprintf(stderr, " TYPE := {hd|mo|cd|bridge|daynaport}\n"); fprintf(stderr, " FILE := image file path\n"); fprintf(stderr, " CMD is 'attach' or 'insert' and FILE parameter is required.\n"); fprintf(stderr, "Usage: %s -l\n", argv[0]); @@ -146,19 +147,29 @@ int main(int argc, char* argv[]) case 'S': case 'h': // HD(SCSI) case 'H': - type = 0; + // rascsi will figure out if this should be SASI or + // SCSI later in the process.... + type = rasctl_dev_sasi_hd; break; case 'm': // MO case 'M': - type = 2; + type = rasctl_dev_mo; break; case 'c': // CD case 'C': - type = 3; + type = rasctl_dev_cd; break; case 'b': // BRIDGE case 'B': - type = 4; + type = rasctl_dev_br; + break; + // case 'n': // Nuvolink + // case 'N': + // type = rasctl_dev_nuvolink; + // break; + case 'd': // DaynaPort + case 'D': + type = rasctl_dev_daynaport; break; } break; @@ -182,13 +193,13 @@ int main(int argc, char* argv[]) // Check the ID number if (id < 0 || id > 7) { - fprintf(stderr, "Error : Invalid ID\n"); + fprintf(stderr, "%s Error : Invalid ID %d \n", __PRETTY_FUNCTION__, id); exit(EINVAL); } // Check the unit number if (un < 0 || un > 1) { - fprintf(stderr, "Error : Invalid UNIT\n"); + fprintf(stderr, "%s Error : Invalid UNIT %d \n", __PRETTY_FUNCTION__, un); exit(EINVAL); } diff --git a/src/raspberrypi/rasctl.h b/src/raspberrypi/rasctl.h new file mode 100644 index 00000000..a56e95dd --- /dev/null +++ b/src/raspberrypi/rasctl.h @@ -0,0 +1,24 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Powered by XM6 TypeG Technology. +// Copyright (C) 2016-2020 GIMONS +// Copyright (C) akuker +// +// [ Send Control Command ] +// +//--------------------------------------------------------------------------- + + +enum rasctl_dev_type : int { + rasctl_dev_invalid = -1, + rasctl_dev_sasi_hd = 0, + rasctl_dev_scsi_hd = 1, + rasctl_dev_mo = 2, + rasctl_dev_cd = 3, + rasctl_dev_br = 4, + rasctl_dev_nuvolink = 5, + rasctl_dev_daynaport = 6, +}; diff --git a/src/raspberrypi/rasdump.cpp b/src/raspberrypi/rasdump.cpp index 776103dc..4d6d60e0 100644 --- a/src/raspberrypi/rasdump.cpp +++ b/src/raspberrypi/rasdump.cpp @@ -5,7 +5,7 @@ // // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS -// [ HDDダンプユーティリティ(イニシーエタモード) ] +// [ HDD dump utility (initiator mode) ] // //--------------------------------------------------------------------------- @@ -18,46 +18,46 @@ //--------------------------------------------------------------------------- // -// 定数宣言 +// Constant Declaration // //--------------------------------------------------------------------------- -#define BUFSIZE 1024 * 64 // 64KBぐらいかなぁ +#define BUFSIZE 1024 * 64 // Buffer size of about 64KB //--------------------------------------------------------------------------- // -// 変数宣言 +// Variable Declaration // //--------------------------------------------------------------------------- -GPIOBUS bus; // バス -int targetid; // ターゲットデバイスID -int boardid; // ボードID(自身のID) -Filepath hdsfile; // HDSファイル -BOOL restore; // リストアフラグ -BYTE buffer[BUFSIZE]; // ワークバッファ -int result; // 結果コード +GPIOBUS bus; // Bus +int targetid; // Target ID +int boardid; // Board ID (own ID) +Filepath hdsfile; // HDS file +BOOL restore; // Restore flag +BYTE buffer[BUFSIZE]; // Work Buffer +int result; // Result Code //--------------------------------------------------------------------------- // -// 関数宣言 +// Cleanup() Function declaration // //--------------------------------------------------------------------------- void Cleanup(); //--------------------------------------------------------------------------- // -// シグナル処理 +// Signal processing // //--------------------------------------------------------------------------- void KillHandler(int sig) { - // 停止指示 + // Stop running Cleanup(); exit(0); } //--------------------------------------------------------------------------- // -// バナー出力 +// Banner Output // //--------------------------------------------------------------------------- BOOL Banner(int argc, char* argv[]) @@ -82,12 +82,12 @@ BOOL Banner(int argc, char* argv[]) //--------------------------------------------------------------------------- // -// 初期化 +// Initialization // //--------------------------------------------------------------------------- BOOL Init() { - // 割り込みハンドラ設定 + // Interrupt handler setting if (signal(SIGINT, KillHandler) == SIG_ERR) { return FALSE; } @@ -98,12 +98,12 @@ BOOL Init() return FALSE; } - // GPIO初期化 + // GPIO Initialization if (!bus.Init(BUS::INITIATOR)) { return FALSE; } - // ワーク初期化 + // Work Intitialization targetid = -1; boardid = 7; restore = FALSE; @@ -113,29 +113,29 @@ BOOL Init() //--------------------------------------------------------------------------- // -// クリーンアップ +// Cleanup // //--------------------------------------------------------------------------- void Cleanup() { - // バスをクリーンアップ + // Cleanup the bus bus.Cleanup(); } //--------------------------------------------------------------------------- // -// リセット +// Reset // //--------------------------------------------------------------------------- void Reset() { - // バス信号線をリセット + // Reset the bus signal line bus.Reset(); } //--------------------------------------------------------------------------- // -// 引数処理 +// Argument processing // //--------------------------------------------------------------------------- BOOL ParseArgument(int argc, char* argv[]) @@ -143,10 +143,10 @@ BOOL ParseArgument(int argc, char* argv[]) int opt; char *file; - // 初期化 + // Initialization file = NULL; - // 引数解析 + // Argument Parsing opterr = 0; while ((opt = getopt(argc, argv, "i:b:f:r")) != -1) { switch (opt) { @@ -168,28 +168,28 @@ BOOL ParseArgument(int argc, char* argv[]) } } - // TARGET IDチェック + // TARGET ID check if (targetid < 0 || targetid > 7) { fprintf(stderr, "Error : Invalid target id range\n"); return FALSE; } - // BOARD IDチェック + // BOARD ID check if (boardid < 0 || boardid > 7) { fprintf(stderr, "Error : Invalid board id range\n"); return FALSE; } - // TARGETとBOARDのID重複チェック + // Target and Board ID duplication check if (targetid == boardid) { fprintf(stderr, "Error : Invalid target or board id\n"); return FALSE; } - // ファイルチェック + // File Check if (!file) { fprintf(stderr, "Error : Invalid file path\n"); @@ -203,14 +203,14 @@ BOOL ParseArgument(int argc, char* argv[]) //--------------------------------------------------------------------------- // -// フェーズ待ち +// Wait Phase // //--------------------------------------------------------------------------- BOOL WaitPhase(BUS::phase_t phase) { DWORD now; - // タイムアウト(3000ms) + // Timeout (3000ms) now = SysTimer::GetTimerLow(); while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) { bus.Aquire(); @@ -224,18 +224,18 @@ BOOL WaitPhase(BUS::phase_t phase) //--------------------------------------------------------------------------- // -// バスフリーフェーズ実行 +// Bus Free Phase // //--------------------------------------------------------------------------- void BusFree() { - // バスリセット + // Bus Reset bus.Reset(); } //--------------------------------------------------------------------------- // -// セレクションフェーズ実行 +// Selection Phase // //--------------------------------------------------------------------------- BOOL Selection(int id) @@ -243,14 +243,14 @@ BOOL Selection(int id) BYTE data; int count; - // ID設定とSELアサート + // ID setting and SEL assert data = 0; data |= (1 << boardid); data |= (1 << id); bus.SetDAT(data); bus.SetSEL(TRUE); - // BSYを待つ + // wait for busy count = 10000; do { usleep(20); @@ -260,127 +260,128 @@ BOOL Selection(int id) } } while (count--); - // SELネゲート + // SEL negate bus.SetSEL(FALSE); - // ターゲットがビジー状態なら成功 + // Success if the target is busy return bus.GetBSY(); } //--------------------------------------------------------------------------- // -// コマンドフェーズ実行 +// Command Phase // //--------------------------------------------------------------------------- BOOL Command(BYTE *buf, int length) { int count; - // フェーズ待ち + // Waiting for Phase if (!WaitPhase(BUS::command)) { return FALSE; } - // コマンド送信 + // Send Command count = bus.SendHandShake(buf, length); - // 送信結果が依頼数と同じなら成功 + // Success if the transmission result is the same as the number + // of requests if (count == length) { return TRUE; } - // 送信エラー + // Return error return FALSE; } //--------------------------------------------------------------------------- // -// データインフェーズ実行 +// Data in phase // //--------------------------------------------------------------------------- int DataIn(BYTE *buf, int length) { - // フェーズ待ち + // Wait for phase if (!WaitPhase(BUS::datain)) { return -1; } - // データ受信 + // Data reception return bus.ReceiveHandShake(buf, length); } //--------------------------------------------------------------------------- // -// データアウトフェーズ実行 +// Data out phase // //--------------------------------------------------------------------------- int DataOut(BYTE *buf, int length) { - // フェーズ待ち + // Wait for phase if (!WaitPhase(BUS::dataout)) { return -1; } - // データ受信 + // Data transmission return bus.SendHandShake(buf, length); } //--------------------------------------------------------------------------- // -// ステータスフェーズ実行 +// Status Phase // //--------------------------------------------------------------------------- int Status() { BYTE buf[256]; - // フェーズ待ち + // Wait for phase if (!WaitPhase(BUS::status)) { return -2; } - // データ受信 + // Data reception if (bus.ReceiveHandShake(buf, 1) == 1) { return (int)buf[0]; } - // 受信エラー + // Return error return -1; } //--------------------------------------------------------------------------- // -// メッセージインフェーズ実行 +// Message in phase // //--------------------------------------------------------------------------- int MessageIn() { BYTE buf[256]; - // フェーズ待ち + // Wait for phase if (!WaitPhase(BUS::msgin)) { return -2; } - // データ受信 + // Data reception if (bus.ReceiveHandShake(buf, 1) == 1) { return (int)buf[0]; } - // 受信エラー + // Return error return -1; } //--------------------------------------------------------------------------- // -// TEST UNIT READY実行 +// TEST UNIT READY // //--------------------------------------------------------------------------- int TestUnitReady(int id) { BYTE cmd[256]; - // 結果コード初期化 + // Result code initialization result = 0; // SELECTION @@ -410,7 +411,7 @@ int TestUnitReady(int id) } exit: - // バスフリー + // Bus free BusFree(); return result; @@ -418,7 +419,7 @@ exit: //--------------------------------------------------------------------------- // -// REQUEST SENSE実行 +// REQUEST SENSE // //--------------------------------------------------------------------------- int RequestSense(int id, BYTE *buf) @@ -426,7 +427,7 @@ int RequestSense(int id, BYTE *buf) BYTE cmd[256]; int count; - // 結果コード初期化 + // Result code initialization result = 0; count = 0; @@ -466,10 +467,10 @@ int RequestSense(int id, BYTE *buf) } exit: - // バスフリー + // Bus Free BusFree(); - // 成功であれば転送数を返す + // Returns the number of transfers if successful if (result == 0) { return count; } @@ -479,7 +480,7 @@ exit: //--------------------------------------------------------------------------- // -// MODE SENSE実行 +// MODE SENSE // //--------------------------------------------------------------------------- int ModeSense(int id, BYTE *buf) @@ -487,7 +488,7 @@ int ModeSense(int id, BYTE *buf) BYTE cmd[256]; int count; - // 結果コード初期化 + // Result code initialization result = 0; count = 0; @@ -528,10 +529,10 @@ int ModeSense(int id, BYTE *buf) } exit: - // バスフリー + // Bus free BusFree(); - // 成功であれば転送数を返す + // Returns the number of transfers if successful if (result == 0) { return count; } @@ -541,7 +542,7 @@ exit: //--------------------------------------------------------------------------- // -// INQUIRY実行 +// INQUIRY // //--------------------------------------------------------------------------- int Inquiry(int id, BYTE *buf) @@ -549,7 +550,7 @@ int Inquiry(int id, BYTE *buf) BYTE cmd[256]; int count; - // 結果コード初期化 + // Result code initialization result = 0; count = 0; @@ -589,10 +590,10 @@ int Inquiry(int id, BYTE *buf) } exit: - // バスフリー + // Bus free BusFree(); - // 成功であれば転送数を返す + // Returns the number of transfers if successful if (result == 0) { return count; } @@ -602,7 +603,7 @@ exit: //--------------------------------------------------------------------------- // -// READ CAPACITY実行 +// READ CAPACITY // //--------------------------------------------------------------------------- int ReadCapacity(int id, BYTE *buf) @@ -610,7 +611,7 @@ int ReadCapacity(int id, BYTE *buf) BYTE cmd[256]; int count; - // 結果コード初期化 + // Result code initialization result = 0; count = 0; @@ -649,10 +650,10 @@ int ReadCapacity(int id, BYTE *buf) } exit: - // バスフリー + // Bus free BusFree(); - // 成功であれば転送数を返す + // Returns the number of transfers if successful if (result == 0) { return count; } @@ -662,7 +663,7 @@ exit: //--------------------------------------------------------------------------- // -// READ10実行 +// READ10 // //--------------------------------------------------------------------------- int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) @@ -670,7 +671,7 @@ int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) BYTE cmd[256]; int count; - // 結果コード初期化 + // Result code initialization result = 0; count = 0; @@ -714,10 +715,10 @@ int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) } exit: - // バスフリー + // Bus free BusFree(); - // 成功であれば転送数を返す + // Returns the number of transfers if successful if (result == 0) { return count; } @@ -727,7 +728,7 @@ exit: //--------------------------------------------------------------------------- // -// WRITE10実行 +// WRITE10 // //--------------------------------------------------------------------------- int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) @@ -735,7 +736,7 @@ int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) BYTE cmd[256]; int count; - // 結果コード初期化 + // Result code initialization result = 0; count = 0; @@ -779,10 +780,10 @@ int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf) } exit: - // バスフリー + // Bus free BusFree(); - // 成功であれば転送数を返す + // Returns the number of transfers if successful if (result == 0) { return count; } @@ -792,7 +793,7 @@ exit: //--------------------------------------------------------------------------- // -// 主処理 +// Main process // //--------------------------------------------------------------------------- int main(int argc, char* argv[]) @@ -809,32 +810,32 @@ int main(int argc, char* argv[]) Fileio::OpenMode omode; off64_t size; - // バナー出力 + // Banner output if (!Banner(argc, argv)) { exit(0); } - // 初期化 + // Initialization if (!Init()) { - fprintf(stderr, "Error : Initializing\n"); + fprintf(stderr, "Error : Initializing. Are you root?\n"); - // 恐らくrootでは無い? + // Probably not root exit(EPERM); } - // 構築 + // Prase Argument if (!ParseArgument(argc, argv)) { - // クリーンアップ + // Cleanup Cleanup(); - // 引数エラーで終了 + // Exit with invalid argument error exit(EINVAL); } - // リセット + // Reset the SCSI bus Reset(); - // ファイルオープン + // File Open if (restore) { omode = Fileio::ReadOnly; } else { @@ -843,20 +844,20 @@ int main(int argc, char* argv[]) if (!fio.Open(hdsfile.GetPath(), omode)) { fprintf(stderr, "Error : Can't open hds file\n"); - // クリーンアップ + // Cleanup Cleanup(); exit(EPERM); } - // バスフリー + // Bus free BusFree(); - // RESETシグナル発行 + // Assert reset signal bus.SetRST(TRUE); usleep(1000); bus.SetRST(FALSE); - // ダンプ開始 + // Start dump printf("TARGET ID : %d\n", targetid); printf("BORAD ID : %d\n", boardid); @@ -881,7 +882,7 @@ int main(int argc, char* argv[]) goto cleanup_exit; } - // INQUIRYの情報を表示 + // Display INQUIRY information memset(str, 0x00, sizeof(str)); memcpy(str, &buffer[8], 8); printf("Vendor : %s\n", str); @@ -892,14 +893,14 @@ int main(int argc, char* argv[]) memcpy(str, &buffer[32], 4); printf("Revison : %s\n", str); - // 容量取得 + // Get drive capacity count = ReadCapacity(targetid, buffer); if (count < 0) { fprintf(stderr, "READ CAPACITY ERROR %d\n", count); goto cleanup_exit; } - // ブロックサイズとブロック数の表示 + // Display block size and number of blocks bsiz = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; @@ -913,7 +914,7 @@ int main(int argc, char* argv[]) (int)(bsiz * bnum / 1024 / 1024), (int)(bsiz * bnum)); - // リストアファイルサイズの取得 + // Get the restore file size if (restore) { size = fio.GetFileSize(); printf("Restore file size : %d bytes", (int)size); @@ -926,7 +927,7 @@ int main(int argc, char* argv[]) printf("\n"); } - // バッファサイズ毎にダンプする + // Dump by buffer size duni = BUFSIZE; duni /= bsiz; dsiz = BUFSIZE; @@ -974,7 +975,7 @@ int main(int argc, char* argv[]) printf("\033[0K"); } - // 容量上の端数処理 + // Rounding on capacity dnum = bnum % duni; dsiz = dnum * bsiz; if (dnum > 0) { @@ -989,16 +990,16 @@ int main(int argc, char* argv[]) } } - // 完了メッセージ + // Completion Message printf("%3d%%(%7d/%7d)\n", 100, (int)bnum, (int)bnum); cleanup_exit: - // ファイルクローズ + // File close fio.Close(); - // クリーンアップ + // Cleanup Cleanup(); - // 終了 + // end exit(0); } diff --git a/src/raspberrypi/scsi.h b/src/raspberrypi/scsi.h index a1ee4259..906d0fd0 100644 --- a/src/raspberrypi/scsi.h +++ b/src/raspberrypi/scsi.h @@ -28,13 +28,13 @@ public: }; // Phase definition - enum phase_t { + enum phase_t : BYTE { busfree, // バスフリーフェーズ arbitration, // アービトレーションフェーズ selection, // セレクションフェーズ reselection, // リセレクションフェーズ command, // コマンドフェーズ - execute, // 実行フェーズ + execute, // 実行フェーズ Execute is an extension of the command phase datain, // データイン dataout, // データアウト status, // ステータスフェーズ @@ -128,6 +128,14 @@ public: virtual int FASTCALL SendHandShake(BYTE *buf, int count) = 0; // データ送信ハンドシェイク + + virtual BOOL FASTCALL GetSignal(int pin) = 0; + // Get SCSI input signal value + virtual void FASTCALL SetSignal(int pin, BOOL ast) = 0; + // Set SCSI output signal value +protected: + phase_t m_current_phase = phase_t::reserved; + private: static const phase_t phase_table[8]; // フェーズテーブル @@ -135,4 +143,84 @@ private: static const char* phase_str_table[]; }; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE misc_cdb_information; + BYTE page_code; + WORD length; + BYTE control; +} scsi_cdb_6_byte_t; + + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE service_action; + DWORD logical_block_address; + BYTE misc_cdb_information; + WORD length; + BYTE control; +} scsi_cdb_10_byte_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE service_action; + DWORD logical_block_address; + DWORD length; + BYTE misc_cdb_information; + BYTE control; +} scsi_cdb_12_byte_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE service_action; + DWORD logical_block_address; + DWORD length; + BYTE misc_cdb_information; + BYTE control; +} scsi_cdb_16_byte_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE reserved; + BYTE page_code; + WORD allocation_length; + BYTE control; +} scsi_cmd_inquiry_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE lba_msb_bits_4_0; + WORD logical_block_address; + BYTE transfer_length; + BYTE control; +} scsi_cmd_read_6_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE flags; + DWORD logical_block_address; + BYTE group_number; + WORD transfer_length; + BYTE control; +} scsi_cmd_read_10_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE flags; + DWORD logical_block_address; + DWORD transfer_length; + BYTE group_number; + BYTE control; +} scsi_cmd_read_12_t; + +typedef struct __attribute__((packed)) { + BYTE operation_code; + BYTE descriptor_format; + WORD reserved; + BYTE allocation_length; + BYTE control; +} scsi_cmd_request_sense_t; + + #endif // scsi_h diff --git a/src/raspberrypi/setup_bridge.sh b/src/raspberrypi/setup_bridge.sh new file mode 100755 index 00000000..d81e7358 --- /dev/null +++ b/src/raspberrypi/setup_bridge.sh @@ -0,0 +1,7 @@ +#!/bin/bash +sudo brctl addbr rascsi_bridge +sudo brctl addif rascsi_bridge eth0 +sudo ip link set dev rascsi_bridge up + +echo Bridge config: +brctl show