Added DaynaPort SCSI/Link emulation functionality

This commit is contained in:
Tony Kuker 2021-01-27 15:16:52 -06:00
parent bac4f4a80b
commit 788b2a3b46
24 changed files with 1803 additions and 733 deletions

View File

@ -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
@ -88,11 +88,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 +151,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)

View File

@ -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,14 +1087,20 @@ 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);
if (ctrl.length <= 0) {
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;
@ -1183,6 +1113,71 @@ void FASTCALL SASIDEV::CmdRead6()
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();
return;
}
// Set next block
ctrl.blocks = 1;
ctrl.next = 1;
// 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
}

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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 <zlib.h> // 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,6 +40,8 @@ CTapDriver::CTapDriver()
#ifdef __linux__
BOOL FASTCALL CTapDriver::Init()
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
char dev[IFNAMSIZ] = "ras0";
struct ifreq ifr;
int ret;
@ -44,7 +50,7 @@ BOOL FASTCALL CTapDriver::Init()
// 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;
}
@ -53,21 +59,28 @@ BOOL FASTCALL CTapDriver::Init()
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
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;
}
// Force the tap interface up
LOGDEBUG("ip link set ras0 up");
system("ip link set ras0 up");
LOGDEBUG("brctl addif rascsi_bridge ras0");
system("brctl addif rascsi_bridge ras0");
// Get 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;
}
// 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 +95,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 +117,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 +127,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;
}
@ -129,11 +142,56 @@ void FASTCALL CTapDriver::Cleanup()
{
ASSERT(this);
// TAPデバイス解放
LOGDEBUG("brctl delif rascsi_bridge ras0");
system("brctl delif rascsi_bridge ras0");
// Release TAP device
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 = system("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 = system("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;
}
//---------------------------------------------------------------------------
@ -154,10 +212,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 +224,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 +258,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 +287,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);

View File

@ -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

View File

@ -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;
@ -973,6 +974,15 @@ BOOL FASTCALL Disk::IsNULL() const
}
return FALSE;
}
//---------------------------------------------------------------------------
//
// Retrieve the disk's ID
//
//---------------------------------------------------------------------------
DWORD FASTCALL Disk::GetID() const
{
return disk.id;
}
//---------------------------------------------------------------------------
//
@ -1162,6 +1172,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 +1180,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 +1237,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 +1982,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 +2042,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;

View File

@ -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

View File

@ -0,0 +1,544 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2020 akuker
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2001-2006 (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
//
// 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 };
#ifndef NDEBUG
static DWORD file_counter = 0;
#endif
//---------------------------------------------------------------------------
//
// 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 {
LOGINFO("Tap interface created")
}
this->Reset();
disk.ready = true;
disk.reset = false;
// Generate MAC Address
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
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;
}
LOGTRACE("%s Packet of size %d received [Counter: %d]", __PRETTY_FUNCTION__, (int)rx_packet_size, (int)file_counter);
// 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++)
{
LOGINFO("%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);
// // SendMessage6 is 18 bytes
// for(int i=0; i< 18; i++)
// {
// LOGDEBUG("%s Byte %d: %02X",__PRETTY_FUNCTION__, i, (int)buffer[i]);
// }
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<sizeof(6); i++)
{
LOGTRACE("%s %d: %02X",__PRETTY_FUNCTION__, i,(WORD)cdb[i]);
}
}

View File

@ -0,0 +1,199 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2020 akuker
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2001-2006 (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
//
// Special thanks to @PotatoFi for loaning me his Farallon EtherMac for
// this development. (Farallon's EtherMac is a re-branded DaynaPort
// SCSI/Link-T).
//
// 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.
//---------------------------------------------------------------------------
#pragma once
#include "xm6.h"
#include "os.h"
#include "disk.h"
#include "ctapdriver.h"
//===========================================================================
//
// DaynaPort SCSI Link
//
//===========================================================================
class SCSIDaynaPort: public Disk
{
public:
// Basic Functions
SCSIDaynaPort();
// Constructor
virtual ~SCSIDaynaPort();
// Destructor
// commands
int FASTCALL Inquiry(const DWORD *cdb, BYTE *buffer, DWORD major, DWORD minor);
// INQUIRY command
BOOL FASTCALL TestUnitReady(const DWORD *cdb);
// TEST UNIT READY command
int FASTCALL Read(const DWORD *cdb, BYTE *buf, DWORD block) override;
// READ command
BOOL FASTCALL Write(const DWORD *cdb, const BYTE *buf, DWORD block) override;
// WRITE command
int FASTCALL WriteCheck(DWORD block) override;
// WRITE check
int FASTCALL RetrieveStats(const DWORD *cdb, BYTE *buffer);
// Retrieve DaynaPort statistics
BOOL FASTCALL EnableInterface(const DWORD *cdb);
// Enable/Disable Interface command
void FASTCALL SetMacAddr(const DWORD *cdb, BYTE *buffer);
// Set MAC address
void FASTCALL SetMode(const DWORD *cdb, BYTE *buffer);
// Set the mode: whether broadcast traffic is enabled or not
int FASTCALL RequestSense(const DWORD *cdb, BYTE *buf) override;
static const BYTE CMD_SCSILINK_STATS = 0x09;
static const BYTE CMD_SCSILINK_ENABLE = 0x0E;
static const BYTE CMD_SCSILINK_SET = 0x0C;
static const BYTE CMD_SCSILINK_SETMODE = 0x80;
static const BYTE CMD_SCSILINK_SETMAC = 0x40;
private:
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE reserved;
WORD pad;
BYTE transfer_length;
BYTE control;
} scsi_cmd_config_multicast_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE reserved;
BYTE pad2;
BYTE pad3;
BYTE pad4;
BYTE control;
} scsi_cmd_enable_disable_iface_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE misc_cdb_information;
BYTE logical_block_address;
WORD length;
BYTE format;
} scsi_cmd_daynaport_write_t;
enum read_data_flags_t : DWORD {
e_no_more_data = 0x00000000,
e_more_data_available = 0x00000001,
e_dropped_packets = 0xFFFFFFFF,
};
typedef struct __attribute__((packed)) {
WORD length;
read_data_flags_t flags;
BYTE pad;
BYTE data[ETH_FRAME_LEN + sizeof(DWORD)]; // Frame length + 4 byte CRC
} scsi_resp_read_t;
typedef struct __attribute__((packed)) {
BYTE mac_address[6];
DWORD frame_alignment_errors;
DWORD crc_errors;
DWORD frames_lost;
} scsi_resp_link_stats_t;
static const char* m_vendor_name;
static const char* m_device_name;
static const char* m_revision;
static const char* m_firmware_version;
scsi_resp_link_stats_t m_scsi_link_stats = {
.mac_address = { 0x00, 0x80, 0x19, 0x10, 0x98, 0xE3 },//MAC address of @PotatoFi's DayanPort
.frame_alignment_errors = 0,
.crc_errors = 0,
.frames_lost = 0,
};
const BYTE m_daynacom_mac_prefix[3] = {0x00,0x80,0x19};
// Basic data
// buf[0] ... CD-ROM Device
// buf[1] ... Removable
// buf[2] ... SCSI-2 compliant command system
// buf[3] ... SCSI-2 compliant Inquiry response
// buf[4] ... Inquiry additional data
//http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/pocket_scsiLINK/pocketscsilink_inq.png
const uint8_t m_target_ethernet_inquiry_response[255] = {
0x03, 0x00, 0x01, 0x00, // 4 bytes
0x1E, 0x00, 0x00, 0x00, // 4 bytes
// Vendor ID (8 Bytes)
'D','a','y','n','a',' ',' ',' ',
//'D','A','Y','N','A','T','R','N',
// Product ID (16 Bytes)
'S','C','S','I','/','L','i','n',
'k',' ',' ',' ',' ',' ',' ',' ',
// Revision Number (4 Bytes)
'1','.','4','a',
// Firmware Version (8 Bytes)
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// Data
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x80,0x80,0xBA, //16 bytes
0x00,0x00,0xC0,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x81, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, //16 bytes
0x00,0x00,0x00 //3 bytes
};
#if defined(RASCSI) && !defined(BAREMETAL)
CTapDriver *m_tap;
// TAP driver
BOOL m_bTapEnable;
// TAP valid flag
BYTE m_mac_addr[6];
// MAC Address
static const BYTE m_bcast_addr[6];
static const BYTE m_apple_talk_addr[6];
// The READ response has a header which consists of:
// 2 bytes - payload size
// 4 bytes - status flags
// 1 byte - magic pad bit, that I don't know why it works.....
const DWORD m_read_header_size = 2 + 4 + 1;
#endif // RASCSI && !BAREMETAL
};

View File

@ -727,7 +727,7 @@ int FASTCALL SCSICD::Inquiry(
// READ
//
//---------------------------------------------------------------------------
int FASTCALL SCSICD::Read(BYTE *buf, DWORD block)
int FASTCALL SCSICD::Read(const DWORD *cdb, BYTE *buf, DWORD block)
{
int index;
Filepath path;
@ -771,7 +771,7 @@ int FASTCALL SCSICD::Read(BYTE *buf, DWORD block)
// Base class
ASSERT(dataindex >= 0);
return Disk::Read(buf, block);
return Disk::Read(cdb, buf, block);
}
//---------------------------------------------------------------------------

View File

@ -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

View File

@ -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];

View File

@ -433,6 +433,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
//---------------------------------------------------------------------------
//

3
src/raspberrypi/launch_sudo.sh Executable file
View File

@ -0,0 +1,3 @@
# This is used for debugging. VisualStudio code will call this file when launching
# the debugger, instead of directly calling GDB. That way we can add the pkexec
sudo /usr/bin/gdb "$@"

View File

@ -16,12 +16,15 @@
#include "spdlog/spdlog.h"
#include "spdlog/sinks/sink.h"
#define SPDLOGWRAPPER(loglevel, ...)\
do{ char buf[256]; \
snprintf(buf, sizeof(buf),__VA_ARGS__); \
spdlog::log(loglevel,buf);}while(0);
#define SPDLOGWRAPPER(loglevel, ...) \
do \
{ \
char logbuf[256]; \
snprintf(logbuf, sizeof(logbuf), __VA_ARGS__); \
spdlog::log(loglevel, logbuf); \
} while (0);
#ifndef DEBUG
#ifdef NDEBUG
// If we're doing a non-debug build, we want to skip the overhead of
// formatting the string, then calling the logger
#define LOGTRACE(...) ((void)0)
@ -35,21 +38,4 @@
#define LOGERROR(...) SPDLOGWRAPPER(spdlog::level::err, __VA_ARGS__)
#define LOGCRITICAL(...) SPDLOGWRAPPER(spdlog::level::critical, __VA_ARGS__)
//===========================================================================
//
// ログ
//
//===========================================================================
class Log
{
public:
enum loglevel {
Detail, // 詳細レベル
Normal, // 通常レベル
Warning, // 警告レベル
Debug // デバッグレベル
};
};
#endif // log_h

View File

@ -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;

View File

@ -21,10 +21,12 @@
#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"
//---------------------------------------------------------------------------
@ -95,7 +97,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");
@ -468,7 +470,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 +490,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,15 +512,21 @@ 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();
break;
default:
FPRT(fp, "Error : Invalid device type\n");
return FALSE;

View File

@ -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);
}

24
src/raspberrypi/rasctl.h Normal file
View File

@ -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,
};

View File

@ -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);
}

View File

@ -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

View File

@ -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