diff --git a/src/raspberrypi/controllers/sasidev_ctrl.cpp b/src/raspberrypi/controllers/sasidev_ctrl.cpp index 50ecf86..b19fae9 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.cpp +++ b/src/raspberrypi/controllers/sasidev_ctrl.cpp @@ -707,10 +707,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; @@ -724,36 +721,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 } //--------------------------------------------------------------------------- @@ -792,10 +765,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; @@ -809,33 +779,12 @@ 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 + LOGTRACE("%s Going 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 } //--------------------------------------------------------------------------- @@ -1394,7 +1343,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( @@ -1411,20 +1359,6 @@ 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; - } -#endif // RASCSI // Remove block and initialize the result ctrl.blocks--; @@ -1435,7 +1369,7 @@ 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); #ifndef RASCSI ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); diff --git a/src/raspberrypi/controllers/scsidev_ctrl.cpp b/src/raspberrypi/controllers/scsidev_ctrl.cpp index 2a0f435..7f7a55b 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.cpp +++ b/src/raspberrypi/controllers/scsidev_ctrl.cpp @@ -197,44 +197,56 @@ void FASTCALL SCSIDEV::BusFree() //--------------------------------------------------------------------------- void FASTCALL SCSIDEV::Arbitration() { - // TODO: See https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-06.html - // DWORD id; + DWORD id; + DWORD data_lines; ASSERT(this); - // // Phase change - // if (ctrl.phase != BUS::reselection) { - // // invalid if IDs do not match - // id = 1 << ctrl.id; - // if ((ctrl.bus->GetDAT() & id) == 0) { - // return; - // } + // We need to switch the tranceivers to be inputs.... + ctrl.bus->SetBSY(FALSE); // Make sure that we're not asserting the BSY signal + ctrl.bus->SetSEL(FALSE); // Make sure that we're not asserting the SEL signal - // // End if there is no valid unit - // if (!HasUnit()) { - // return; - // } + // If we arent' in the bus-free phase, we can't progress.... + // just return. + ctrl.bus->Aquire(); + if(ctrl.bus->GetBSY() || ctrl.bus->GetSEL()) + { + LOGWARN("Unable to start arbitration. BSY:%d SEL:%d",(int)ctrl.bus->GetBSY(), (int)ctrl.bus->GetSEL()); + } + + // Phase change + if (ctrl.phase != BUS::arbitration) { - // LOGDEBUG("Reselection phase ID=%d (with device)", ctrl.id); + ctrl.phase = BUS::arbitration; - // // Phase setting - // ctrl.phase = BUS::selection; + // Assert both the BSY signal and our own SCSI ID + id = 1 << ctrl.id; + ctrl.bus->SetDAT(id); + ctrl.bus->SetBSY(TRUE); - // // Raise BSY and respond - // ctrl.bus->SetBSY(TRUE); - // return; - // } + // Wait for an ARBITRATION DELAY + SysTimer::SleepNsec(SCSI_DELAY_ARBITRATION_DELAY_NS); + + // Check if a higher SCSI ID is asserted. If so, we lost arbitration + ctrl.bus->Aquire(); + data_lines = ctrl.bus->GetDAT(); + LOGDEBUG("After Arbitration, data lines are %04X", (int)data_lines); + data_lines >>= (ctrl.id + 1); + if(data_lines != 0) + { + LOGINFO("We LOST arbitration for ID %d", ctrl.id); + BusFree(); + return; + } - // // Reselection completed - // if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) { - // // Message out phase if ATN=1, otherwise command phase - // if (ctrl.bus->GetATN()) { - // MsgOut(); - // } else { - // Command(); - // } - // } + // If we won the arbitration, assert the SEL signal + ctrl.bus->SetSEL(TRUE); + + // Wait for BUS CLEAR delay + BUS SETTLE delay before changing any signals + SysTimer::SleepNsec(SCSI_DELAY_BUS_CLEAR_DELAY_NS + SCSI_DELAY_BUS_SETTLE_DELAY_NS); + } + return; } //--------------------------------------------------------------------------- @@ -292,42 +304,66 @@ void FASTCALL SCSIDEV::Selection() //--------------------------------------------------------------------------- void FASTCALL SCSIDEV::Reselection() { - // DWORD id; + DWORD id; ASSERT(this); - // // Phase change - // if (ctrl.phase != BUS::reselection) { - // // invalid if IDs do not match - // id = 1 << ctrl.id; - // if ((ctrl.bus->GetDAT() & id) == 0) { - // return; - // } + // Phase change + if (ctrl.phase != BUS::reselection) { + ctrl.phase = BUS::reselection; - // // End if there is no valid unit - // if (!HasUnit()) { - // return; - // } + // Assert the IO signal + ctrl.bus->SetIO(TRUE); - // LOGDEBUG("Reselection phase ID=%d (with device)", ctrl.id); + // Set the data bus to my SCSI ID or-ed with the Initiator's SCSI ID + // Assume this is 7, since that is what all Macintoshes use + id = (1 << ctrl.id) | (1 << 7); + LOGDEBUG("Reslection DAT set to %02X",(int)id); + ctrl.bus->SetDAT((BYTE)id); - // // Phase setting - // ctrl.phase = BUS::selection; + // Wait at least two deskew delays + SysTimer::SleepNsec(SCSI_DELAY_DESKEW_DELAY_NS); + // Release the BSY signal + ////////////////ctrl.bus->SetBSY(FALSE); + // We can't use the SetBSY() funciton, because that also reverses the direction of IC3 + ctrl.bus->SetSignal(PIN_BSY, FALSE); - // // Raise BSY and respond - // ctrl.bus->SetBSY(TRUE); - // return; - // } + // Initiater waits for (SEL && IO && ~BSY) with its DAT flag set + // to accept a reselect + SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); - // // Reselection completed - // if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) { - // // Message out phase if ATN=1, otherwise command phase - // if (ctrl.bus->GetATN()) { - // MsgOut(); - // } else { - // Command(); - // } - // } + // Normally, we should wait to ensure that the target asserts BSY, but we + // can't read the BSY signal while the IO line is being asserted. So, we just + // have to assume it worked + + // if(ctrl.bus->WaitSignalTimeoutUs(PIN_BSY, TRUE, SCSI_DELAY_SELECTION_ABORT_TIME_US*3)) + // { + LOGDEBUG("Initiator correctly asserted BSY"); + // After the Initiator asserts BSY, we need to take it over and also assert it + ////////////////////ctrl.bus->SetBSY(TRUE); + ctrl.bus->SetSignal(PIN_BSY, TRUE); + SysTimer::SleepNsec(SCSI_DELAY_DESKEW_DELAY_NS * 2); + + // Release the SEL signal + ctrl.bus->SetSEL(FALSE); + + // Transition to the Msg Out phase + MsgOut(); + // } + // else + // { + // ctrl.phase = BUS::busfree; + // BusFree(); + // // Timeout waiting for Intiaitor to reselect + // LOGERROR("Initiator did not assert PIN_BSY within the specified timeout. Aborting the Reselection"); + // // Reset the controller + // Reset(); + + // // Reset the bus + // ctrl.bus->Reset(); + // return; + // } + } } @@ -540,13 +576,12 @@ void FASTCALL SCSIDEV::Execute() void FASTCALL SCSIDEV::MsgOut() { ASSERT(this); + LOGTRACE("%s ID: %d",__PRETTY_FUNCTION__, this->GetID()); // 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 @@ -576,23 +611,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 } //--------------------------------------------------------------------------- @@ -1841,132 +1861,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("ctrl.phase: %d",(int)ctrl.phase); switch (ctrl.phase) { // Data out phase @@ -2007,10 +1947,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; } @@ -2018,7 +1954,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) { @@ -2027,11 +1962,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(); @@ -2045,10 +1977,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; } @@ -2061,20 +1990,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; @@ -2082,18 +2005,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) { @@ -2182,28 +2099,26 @@ BOOL FASTCALL SCSIDEV::XferMsg(DWORD msg) // //--------------------------------------------------------------------------- BOOL FASTCALL SCSIDEV::TransferPacketToHost(int packet_len){ + + SCSINuvolink *nuvolink; + + LOGTRACE("%s", __PRETTY_FUNCTION__); //***************************** // BUS FREE PHASE //***************************** // We should already be in bus free phase when we enter this function + BusFree(); //***************************** // ARBITRATION PHASE //***************************** - // Aquire the bus - // ctrl.bus->Aquire(); - // ctrl.bus->SetIO(); + Arbitration(); + -// if (bus->GetBUSY()) { -// #if !defined(BAREMETAL) -// usleep(0); -// #endif // !BAREMETAL -// continue; -// } -// #endif // USE_SEL_EVENT_ENABLE //***************************** // Reselection //***************************** + Reselection(); //***************************** // Message OUT (expect a "NO OPERATION") @@ -2211,15 +2126,34 @@ BOOL FASTCALL SCSIDEV::TransferPacketToHost(int packet_len){ // Transition to MESSAGE IN and send a DISCONNECT // then go to BUS FREE //***************************** + MsgOut(); + LOGTRACE("%s Done with MsgOut", __PRETTY_FUNCTION__); //***************************** // DATA IN // ... send the packet //***************************** + // The Nuvolink should always be unit 0. Unit 1 is only applicable + // to SASI devices + if(ctrl.unit[0]->GetID() == MAKEID('S','C','N','L')){ + ctrl.length = packet_len; + ctrl.buffer[0] = NUVOLINK_RSR_REG_PACKET_INTACT; + ctrl.buffer[1] = m_sequence_number++; + ctrl.buffer[2] = (packet_len & 0xFF); + ctrl.buffer[3] = (packet_len >> 8) & 0xFF; + nuvolink = (SCSINuvolink*)ctrl.unit[0]; + memcpy(&(ctrl.buffer[4]), nuvolink->packet_buf, packet_len); + }else{ + ctrl.buffer[2] = 0; + ctrl.buffer[3] = 0; + } + + DataIn(); //***************************** // MESSAGE OUT (expect a "NO OPERATION") //***************************** + MsgOut(); //***************************** // If more packets, go back to DATA IN @@ -2229,9 +2163,16 @@ BOOL FASTCALL SCSIDEV::TransferPacketToHost(int packet_len){ // Else // MESSAGE IN (sends DISCONNECT) //***************************** + ctrl.blocks = 1; + ctrl.length = sizeof(scsi_message_code); + ctrl.buffer[0] = eMsgCodeDisconnect; + ctrl.message = (DWORD)eMsgCodeDisconnect; // (This is probably redundant and unnecessary?) + MsgIn(); //***************************** // BUS FREE //***************************** BusFree(); + + return TRUE; } \ No newline at end of file diff --git a/src/raspberrypi/controllers/scsidev_ctrl.h b/src/raspberrypi/controllers/scsidev_ctrl.h index bf289fd..5bddae1 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.h +++ b/src/raspberrypi/controllers/scsidev_ctrl.h @@ -16,6 +16,16 @@ #pragma once #include "controllers/sasidev_ctrl.h" + +//=========================================================================== +// +// Nuvolink Register constants +// Bit 0: set when packet received intact, thus always set. +// Bit 5: set when the packet was a multicast/broadcast packet. +//=========================================================================== +#define NUVOLINK_RSR_REG_PACKET_INTACT (1 << 0) +#define NUVOLINK_RSR_REG_MCAST_OR_BCAST (1 << 5) + //=========================================================================== // // SCSI Device (Interits SASI device) @@ -38,6 +48,33 @@ 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, @@ -79,11 +116,7 @@ public: public: // Basic Functions -#ifdef RASCSI SCSIDEV(); -#else - SCSIDEV(Device *dev); -#endif // RASCSI // Constructor void FASTCALL Reset(); @@ -195,5 +228,9 @@ private: scsi_t scsi; // Internal data + + // Sequence number for the Nuvolink. This really belongs somewhere else, + // but it goes here for now. + BYTE m_sequence_number = 0; }; diff --git a/src/raspberrypi/devices/scsi_nuvolink.cpp b/src/raspberrypi/devices/scsi_nuvolink.cpp index 4ffa01e..04d2320 100644 --- a/src/raspberrypi/devices/scsi_nuvolink.cpp +++ b/src/raspberrypi/devices/scsi_nuvolink.cpp @@ -46,7 +46,7 @@ SCSINuvolink::SCSINuvolink() : Disk() // Nuvolink disk.id = MAKEID('S', 'C', 'N', 'L'); -#if defined(RASCSI) && defined(__linux__) && !defined(BAREMETAL) +#if defined(__linux__) && !defined(BAREMETAL) // TAP Driver Generation tap = new CTapDriver(); m_bTapEnable = tap->Init(); @@ -77,7 +77,7 @@ SCSINuvolink::SCSINuvolink() : Disk() SCSINuvolink::~SCSINuvolink() { LOGTRACE("SCSINuvolink Destructor"); -#if defined(RASCSI) && !defined(BAREMETAL) +#if !defined(BAREMETAL) // TAP driver release if (tap) { tap->Cleanup(); @@ -420,7 +420,7 @@ void FASTCALL SCSINuvolink::SetMulticastRegisters(BYTE *buffer, int len){ } -#if defined(RASCSI) && !defined(BAREMETAL) +#if !defined(BAREMETAL) //--------------------------------------------------------------------------- // // Get MAC Address @@ -479,14 +479,47 @@ int FASTCALL SCSINuvolink::ReceivePacket() if(packet_len){ LOGINFO("Received a packet of size %d",packet_len); + + for(int i=0; i< 48; i+=8) + { + LOGTRACE("%s %02X: %02X %02X %02X %02X %02X %02X %02X %02X", \ + __PRETTY_FUNCTION__,i, + (int)packet_buf[i+0], + (int)packet_buf[i+1], + (int)packet_buf[i+2], + (int)packet_buf[i+3], + (int)packet_buf[i+4], + (int)packet_buf[i+5], + (int)packet_buf[i+6], + (int)packet_buf[i+7]); + } + }else{ + return -1; } - // Check if received packet + // This is a very basic filter to prevent unnecessary packets from + // being sent to the SCSI initiator. + + // Check if received packet destination MAC address matches the + // Nuvolink MAC if (memcmp(packet_buf, mac_addr, 6) != 0) { + // If it doesn't match, check to see if this is a broadcast message if (memcmp(packet_buf, bcast_addr, 6) != 0) { + LOGINFO("%s Received a packet that's not for me: %02X %02X %02X %02X %02X %02X", \ + __PRETTY_FUNCTION__, + (int)packet_buf[0], + (int)packet_buf[1], + (int)packet_buf[2], + (int)packet_buf[3], + (int)packet_buf[4], + (int)packet_buf[5]); packet_len = 0; return -1; + }else{ + packet_is_bcast_or_mcast = TRUE; } + }else{ + packet_is_bcast_or_mcast = FALSE; } // Discard if it exceeds the buffer size @@ -496,13 +529,7 @@ int FASTCALL SCSINuvolink::ReceivePacket() return -1; } - // TransferPacket(packet_len, packet_buff); return packet_len; - - // // Store in receive buffer - // if (packet_len > 0) { - // packet_enable = TRUE; - // } } diff --git a/src/raspberrypi/devices/scsi_nuvolink.h b/src/raspberrypi/devices/scsi_nuvolink.h index 454bd25..921794a 100644 --- a/src/raspberrypi/devices/scsi_nuvolink.h +++ b/src/raspberrypi/devices/scsi_nuvolink.h @@ -56,7 +56,14 @@ public: // Send a packet int FASTCALL ReceivePacket(); // Receive a packet - + int packet_len; + // Receive packet size + BYTE packet_buf[0x1000]; + // Receive packet buffer + BOOL packet_is_bcast_or_mcast; + // Flag intidcating if the last packet is multicast/broadcast + // TRUE if multicast or broadcast + // FALSE if unicast private: enum nuvolink_command_enum : BYTE { @@ -95,10 +102,6 @@ private: // TAP valid flag BYTE mac_addr[6]; // MAC Addres - int packet_len; - // Receive packet size - BYTE packet_buf[0x1000]; - // Receive packet buffer BOOL packet_enable; // Received packet valid #endif // RASCSI && !BAREMETAL diff --git a/src/raspberrypi/gpiobus.cpp b/src/raspberrypi/gpiobus.cpp index 93c2c2b..74937a6 100644 --- a/src/raspberrypi/gpiobus.cpp +++ b/src/raspberrypi/gpiobus.cpp @@ -632,6 +632,29 @@ void FASTCALL GPIOBUS::SetSEL(BOOL ast) SetControl(PIN_ACT, ACT_ON); } + + // If we're trying to SET the SEL signal, we need to + // reverse directions on IC4 + if (actmode == TARGET) { + if (ast) { + // Set Target signal to output + SetControl(PIN_IND, IND_OUT); + + SetMode(PIN_SEL, OUT); + SetMode(PIN_RST, OUT); + SetMode(PIN_ACK, OUT); + SetMode(PIN_ATN, OUT); + } else { + // Set the target signal to input + SetControl(PIN_IND, IND_IN); + + SetMode(PIN_SEL, IN); + SetMode(PIN_RST, IN); + SetMode(PIN_ACK, IN); + SetMode(PIN_ATN, IN); + } + } + // Set SEL signal SetSignal(PIN_SEL, ast); } @@ -1532,15 +1555,25 @@ void FASTCALL GPIOBUS::SetSignal(int pin, BOOL ast) //--------------------------------------------------------------------------- BOOL FASTCALL GPIOBUS::WaitSignal(int pin, BOOL ast) { - DWORD now; DWORD timeout; + // Calculate default timeout (3000ms) + timeout = 3000 * 1000; + return WaitSignalTimeoutUs(pin, ast, timeout); +} + +//--------------------------------------------------------------------------- +// +// Wait for signal change +// +//--------------------------------------------------------------------------- +BOOL FASTCALL GPIOBUS::WaitSignalTimeoutUs(int pin, BOOL ast, DWORD timeout) +{ + DWORD now; + // Get current time now = SysTimer::GetTimerLow(); - // Calculate timeout (3000ms) - timeout = 3000 * 1000; - // end immediately if the signal has changed do { // Immediately upon receiving a reset diff --git a/src/raspberrypi/gpiobus.h b/src/raspberrypi/gpiobus.h index 9d269e1..8d66e6f 100644 --- a/src/raspberrypi/gpiobus.h +++ b/src/raspberrypi/gpiobus.h @@ -434,6 +434,30 @@ // //--------------------------------------------------------------------------- #define GPIO_DATA_SETTLING 100 // Data bus stabilization time (ns) +// SCSI Bus timings taken from: +// https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-05.html +#define SCSI_DELAY_ARBITRATION_DELAY_NS 2400 +#define SCSI_DELAY_ASSERTION_PERIOD_NS 90 +#define SCSI_DELAY_BUS_CLEAR_DELAY_NS 800 +#define SCSI_DELAY_BUS_FREE_DELAY_NS 800 +#define SCSI_DELAY_BUS_SET_DELAY_NS 1800 +#define SCSI_DELAY_BUS_SETTLE_DELAY_NS 400 +#define SCSI_DELAY_CABLE_SKEW_DELAY_NS 10 +#define SCSI_DELAY_DATA_RELEASE_DELAY_NS 400 +#define SCSI_DELAY_DESKEW_DELAY_NS 45 +#define SCSI_DELAY_DISCONNECTION_DELAY_US 200 +#define SCSI_DELAY_HOLD_TIME_NS 45 +#define SCSI_DELAY_NEGATION_PERIOD_NS 90 +#define SCSI_DELAY_POWER_ON_TO_SELECTION_TIME_S 10 // (recommended) +#define SCSI_DELAY_RESET_TO_SELECTION_TIME_US (250*1000) // (recommended) +#define SCSI_DELAY_RESET_HOLD_TIME_US 25 +#define SCSI_DELAY_SELECTION_ABORT_TIME_US 200 +#define SCSI_DELAY_SELECTION_TIMEOUT_DELAY_NS (250*1000) // (recommended) +#define SCSI_DELAY_FAST_ASSERTION_PERIOD_NS 30 +#define SCSI_DELAY_FAST_CABLE_SKEW_DELAY_NS 5 +#define SCSI_DELAY_FAST_DESKEW_DELAY_NS 20 +#define SCSI_DELAY_FAST_HOLD_TIME_NS 10 +#define SCSI_DELAY_FAST_NEGATION_PERIOD_NS 30 //--------------------------------------------------------------------------- // @@ -523,6 +547,15 @@ public: // Data receive handshake int FASTCALL SendHandShake(BYTE *buf, int count); // Data transmission handshake + BOOL FASTCALL WaitSignalTimeoutUs(int pin, BOOL ast, DWORD timeout); + // Wait for a specified number of + // microseconds for a signal to change + void FASTCALL SetControl(int pin, BOOL ast); + // Set Control Signal + BOOL FASTCALL GetSignal(int pin); + // Get SCSI input signal value + void FASTCALL SetSignal(int pin, BOOL ast); + // Set SCSI output signal value #ifdef USE_SEL_EVENT_ENABLE // SEL signal interrupt @@ -536,16 +569,10 @@ private: // SCSI I/O signal control void FASTCALL MakeTable(); // Create work data - void FASTCALL SetControl(int pin, BOOL ast); - // Set Control Signal void FASTCALL SetMode(int pin, int mode); // Set SCSI I/O mode - BOOL FASTCALL GetSignal(int pin); - // Get SCSI input signal value - void FASTCALL SetSignal(int pin, BOOL ast); - // Set SCSI output signal value BOOL FASTCALL WaitSignal(int pin, BOOL ast); - // Wait for a signal to change + // Wait up to 3s for a signal to change // Interrupt control void FASTCALL DisableIRQ(); // IRQ Disabled diff --git a/src/raspberrypi/scsi.h b/src/raspberrypi/scsi.h index 2ce4623..c0fbfcc 100644 --- a/src/raspberrypi/scsi.h +++ b/src/raspberrypi/scsi.h @@ -54,6 +54,11 @@ public: phase_t FASTCALL GetPhase(); // フェーズ取得 + virtual BOOL FASTCALL WaitSignalTimeoutUs(int pin, BOOL ast, DWORD timeout) = 0; + // Wait for a specified number of + // microseconds for a signal to change + + static phase_t FASTCALL GetPhase(DWORD mci) { return phase_table[mci]; @@ -122,6 +127,12 @@ 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 + private: static const phase_t phase_table[8]; // フェーズテーブル