mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-10 17:29:35 +00:00
Added arbitration and reselection logic. Seems to work. Also removed some conditional code for non-RASCSI applications
This commit is contained in:
parent
01b0fb0f35
commit
45426b5fb6
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
// フェーズテーブル
|
||||
|
|
Loading…
Reference in New Issue
Block a user