mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-25 20:33:35 +00:00
Added DaynaPort SCSI/Link emulation functionality
This commit is contained in:
parent
bac4f4a80b
commit
788b2a3b46
@ -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)
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "filepath.h"
|
||||
#include "gpiobus.h"
|
||||
#include "devices/scsi_host_bridge.h"
|
||||
#include "controllers/scsidev_ctrl.h"
|
||||
#include "devices/scsi_daynaport.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
@ -44,7 +46,7 @@ SASIDEV::SASIDEV(Device *dev)
|
||||
|
||||
// Work initialization
|
||||
ctrl.phase = BUS::busfree;
|
||||
ctrl.id = -1;
|
||||
ctrl.m_scsi_id = -1;
|
||||
ctrl.bus = NULL;
|
||||
memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd));
|
||||
ctrl.status = 0x00;
|
||||
@ -52,7 +54,7 @@ SASIDEV::SASIDEV(Device *dev)
|
||||
#ifdef RASCSI
|
||||
ctrl.execstart = 0;
|
||||
#endif // RASCSI
|
||||
ctrl.bufsize = 0x800;
|
||||
ctrl.bufsize = ETH_FRAME_LEN + 16 + ETH_FCS_LEN;
|
||||
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
|
||||
memset(ctrl.buffer, 0x00, ctrl.bufsize);
|
||||
ctrl.blocks = 0;
|
||||
@ -201,7 +203,7 @@ void FASTCALL SASIDEV::Connect(int id, BUS *bus)
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
ctrl.id = id;
|
||||
ctrl.m_scsi_id = id;
|
||||
ctrl.bus = bus;
|
||||
}
|
||||
|
||||
@ -291,7 +293,7 @@ BUS::phase_t FASTCALL SASIDEV::Process()
|
||||
ASSERT(this);
|
||||
|
||||
// Do nothing if not connected
|
||||
if (ctrl.id < 0 || ctrl.bus == NULL) {
|
||||
if (ctrl.m_scsi_id < 0 || ctrl.bus == NULL) {
|
||||
return ctrl.phase;
|
||||
}
|
||||
|
||||
@ -301,9 +303,7 @@ BUS::phase_t FASTCALL SASIDEV::Process()
|
||||
// For the monitor tool, we shouldn't need to reset. We're just logging information
|
||||
// Reset
|
||||
if (ctrl.bus->GetRST()) {
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "RESET signal received");
|
||||
#endif // DISK_LOG
|
||||
LOGINFO("RESET signal received");
|
||||
|
||||
// Reset the controller
|
||||
Reset();
|
||||
@ -371,9 +371,7 @@ void FASTCALL SASIDEV::BusFree()
|
||||
// Phase change
|
||||
if (ctrl.phase != BUS::busfree) {
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Bus free phase");
|
||||
#endif // DISK_LOG
|
||||
LOGINFO("Bus free phase");
|
||||
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::busfree;
|
||||
@ -411,7 +409,7 @@ void FASTCALL SASIDEV::Selection()
|
||||
// Phase change
|
||||
if (ctrl.phase != BUS::selection) {
|
||||
// Invalid if IDs do not match
|
||||
id = 1 << ctrl.id;
|
||||
id = 1 << ctrl.m_scsi_id;
|
||||
if ((ctrl.bus->GetDAT() & id) == 0) {
|
||||
return;
|
||||
}
|
||||
@ -421,10 +419,7 @@ void FASTCALL SASIDEV::Selection()
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal,
|
||||
"Selection Phase ID=%d (with device)", ctrl.id);
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s Selection Phase ID=%d (with device)", __PRETTY_FUNCTION__, (int)ctrl.m_scsi_id);
|
||||
|
||||
// Phase change
|
||||
ctrl.phase = BUS::selection;
|
||||
@ -457,9 +452,7 @@ void FASTCALL SASIDEV::Command()
|
||||
// Phase change
|
||||
if (ctrl.phase != BUS::command) {
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Command Phase");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__);
|
||||
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::command;
|
||||
@ -537,9 +530,7 @@ void FASTCALL SASIDEV::Execute()
|
||||
{
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Execution Phase Command %02X", ctrl.cmd[0]);
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s Execution Phase Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]);
|
||||
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::execute;
|
||||
@ -552,65 +543,68 @@ void FASTCALL SASIDEV::Execute()
|
||||
#endif // RASCSI
|
||||
|
||||
// Process by command
|
||||
switch (ctrl.cmd[0]) {
|
||||
switch ((SCSIDEV::scsi_command)ctrl.cmd[0]) {
|
||||
// TEST UNIT READY
|
||||
case 0x00:
|
||||
case SCSIDEV::eCmdTestUnitReady:
|
||||
CmdTestUnitReady();
|
||||
return;
|
||||
|
||||
// REZERO UNIT
|
||||
case 0x01:
|
||||
case SCSIDEV::eCmdRezero:
|
||||
CmdRezero();
|
||||
return;
|
||||
|
||||
// REQUEST SENSE
|
||||
case 0x03:
|
||||
case SCSIDEV::eCmdRequestSense:
|
||||
CmdRequestSense();
|
||||
return;
|
||||
|
||||
// FORMAT UNIT
|
||||
case 0x04:
|
||||
CmdFormat();
|
||||
return;
|
||||
|
||||
// FORMAT UNIT
|
||||
case 0x06:
|
||||
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
|
||||
// leaving it here for now....
|
||||
case SCSIDEV::eCmdFormat:
|
||||
CmdFormat();
|
||||
return;
|
||||
|
||||
// REASSIGN BLOCKS
|
||||
case 0x07:
|
||||
case SCSIDEV::eCmdReassign:
|
||||
CmdReassign();
|
||||
return;
|
||||
|
||||
// READ(6)
|
||||
case 0x08:
|
||||
case SCSIDEV::eCmdRead6:
|
||||
CmdRead6();
|
||||
return;
|
||||
|
||||
// WRITE(6)
|
||||
case 0x0a:
|
||||
case SCSIDEV::eCmdWrite6:
|
||||
CmdWrite6();
|
||||
return;
|
||||
|
||||
// SEEK(6)
|
||||
case 0x0b:
|
||||
case SCSIDEV::eCmdSeek6:
|
||||
CmdSeek6();
|
||||
return;
|
||||
|
||||
// ASSIGN(SASIのみ)
|
||||
case 0x0e:
|
||||
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
|
||||
// leaving it here for now....
|
||||
case SCSIDEV::eCmdSasiCmdAssign:
|
||||
CmdAssign();
|
||||
return;
|
||||
|
||||
// SPECIFY(SASIのみ)
|
||||
case 0xc2:
|
||||
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
|
||||
// leaving it here for now....
|
||||
case SCSIDEV::eCmdInvalid:
|
||||
CmdSpecify();
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Unsupported command
|
||||
Log(Log::Warning, "Unsupported command $%02X", ctrl.cmd[0]);
|
||||
LOGWARN("%s Unsupported command $%02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]);
|
||||
CmdInvalid();
|
||||
}
|
||||
|
||||
@ -645,9 +639,7 @@ void FASTCALL SASIDEV::Status()
|
||||
}
|
||||
#endif // RASCSI
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Status phase");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s Status phase", __PRETTY_FUNCTION__);
|
||||
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::status;
|
||||
@ -668,9 +660,7 @@ void FASTCALL SASIDEV::Status()
|
||||
ctrl.bus->SetDAT(ctrl.buffer[0]);
|
||||
ctrl.bus->SetREQ(TRUE);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Status Phase $%02X", ctrl.status);
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE( "%s Status Phase $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.status);
|
||||
#endif // RASCSI
|
||||
return;
|
||||
}
|
||||
@ -705,10 +695,7 @@ void FASTCALL SASIDEV::MsgIn()
|
||||
|
||||
// Phase change
|
||||
if (ctrl.phase != BUS::msgin) {
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Message in phase");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s Starting Message in phase", __PRETTY_FUNCTION__);
|
||||
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::msgin;
|
||||
@ -722,36 +709,12 @@ void FASTCALL SASIDEV::MsgIn()
|
||||
ASSERT(ctrl.length > 0);
|
||||
ASSERT(ctrl.blocks > 0);
|
||||
ctrl.offset = 0;
|
||||
|
||||
#ifndef RASCSI
|
||||
// Request message
|
||||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||||
ctrl.bus->SetREQ(TRUE);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Message in phase $%02X", ctrl.buffer[ctrl.offset]);
|
||||
#endif // DISK_LOG
|
||||
#endif // RASCSI
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RASCSI
|
||||
//Send
|
||||
LOGTRACE("%s Transitioning to Send()", __PRETTY_FUNCTION__);
|
||||
Send();
|
||||
#else
|
||||
// Requesting
|
||||
if (ctrl.bus->GetREQ()) {
|
||||
// Initator received
|
||||
if (ctrl.bus->GetACK()) {
|
||||
SendNext();
|
||||
}
|
||||
} else {
|
||||
// Initiator requests next
|
||||
if (!ctrl.bus->GetACK()) {
|
||||
Send();
|
||||
}
|
||||
}
|
||||
#endif // RASCSI
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -790,10 +753,7 @@ void FASTCALL SASIDEV::DataIn()
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Data-in Phase");
|
||||
#endif // DISK_LOG
|
||||
|
||||
LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__);
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::datain;
|
||||
|
||||
@ -807,33 +767,11 @@ void FASTCALL SASIDEV::DataIn()
|
||||
ASSERT(ctrl.blocks > 0);
|
||||
ctrl.offset = 0;
|
||||
|
||||
#ifndef RASCSI
|
||||
// Assert the DAT signal
|
||||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||||
|
||||
// Request data
|
||||
ctrl.bus->SetREQ(TRUE);
|
||||
#endif // RASCSI
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RASCSI
|
||||
// Send
|
||||
Send();
|
||||
#else
|
||||
// Requesting
|
||||
if (ctrl.bus->GetREQ()) {
|
||||
// Initator received
|
||||
if (ctrl.bus->GetACK()) {
|
||||
SendNext();
|
||||
}
|
||||
} else {
|
||||
// Initiator requests next
|
||||
if (!ctrl.bus->GetACK()) {
|
||||
Send();
|
||||
}
|
||||
}
|
||||
#endif // RASCSI
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -872,9 +810,7 @@ void FASTCALL SASIDEV::DataOut()
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Data out phase");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__);
|
||||
|
||||
// Phase Setting
|
||||
ctrl.phase = BUS::dataout;
|
||||
@ -946,7 +882,7 @@ void FASTCALL SASIDEV::Error()
|
||||
}
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Warning, "Error occured (going to status phase)");
|
||||
LOGWARN("Error occured (going to status phase)");
|
||||
#endif // DISK_LOG
|
||||
|
||||
// Logical Unit
|
||||
@ -971,9 +907,7 @@ void FASTCALL SASIDEV::CmdTestUnitReady()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "TEST UNIT READY Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1006,9 +940,7 @@ void FASTCALL SASIDEV::CmdRezero()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "REZERO UNIT Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE( "%s REZERO UNIT Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1040,9 +972,7 @@ void FASTCALL SASIDEV::CmdRequestSense()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "REQUEST SENSE Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1051,13 +981,11 @@ void FASTCALL SASIDEV::CmdRequestSense()
|
||||
return;
|
||||
}
|
||||
|
||||
// Command processing on drive
|
||||
ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
|
||||
ASSERT(ctrl.length > 0);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Sense key $%02X", ctrl.buffer[2]);
|
||||
#endif // DISK_LOG
|
||||
|
||||
LOGTRACE("%s Sense key $%02X",__PRETTY_FUNCTION__, (WORD)ctrl.buffer[2]);
|
||||
|
||||
// Read phase
|
||||
DataIn();
|
||||
@ -1075,9 +1003,7 @@ void FASTCALL SASIDEV::CmdFormat()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "FORMAT UNIT Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE( "%s FORMAT UNIT Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1110,9 +1036,7 @@ void FASTCALL SASIDEV::CmdReassign()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "REASSIGN BLOCKS Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s REASSIGN BLOCKS Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1163,13 +1087,82 @@ void FASTCALL SASIDEV::CmdRead6()
|
||||
ctrl.blocks = 0x100;
|
||||
}
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal,
|
||||
"READ(6) command record=%06X blocks=%d", record, ctrl.blocks);
|
||||
#endif // DISK_LOG
|
||||
if(ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'D', 'P')){
|
||||
// The DaynaPort only wants one block.
|
||||
// ctrl.cmd[4] and ctrl.cmd[5] are used to specify the maximum buffer size for the DaynaPort
|
||||
ctrl.blocks=1;
|
||||
}
|
||||
|
||||
LOGTRACE("%s READ(6) command record=%06X blocks=%d ID %08X", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks, (unsigned int)ctrl.unit[lun]->GetID());
|
||||
|
||||
// Command processing on drive
|
||||
ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record);
|
||||
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, ctrl.buffer, record);
|
||||
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl.length);
|
||||
|
||||
// The DaynaPort will respond a status of 0x02 when a read of size 1 occurs.
|
||||
if ((ctrl.length <= 0) && (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P'))) {
|
||||
// Failure (Error)
|
||||
Error();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set next block
|
||||
ctrl.next = record + 1;
|
||||
|
||||
// Read phase
|
||||
DataIn();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// This Send Message command is used by the DaynaPort SCSI/Link
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL SASIDEV::DaynaPortWrite()
|
||||
{
|
||||
DWORD lun;
|
||||
DWORD data_format;
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
if (!ctrl.unit[lun]) {
|
||||
Error();
|
||||
return;
|
||||
}
|
||||
|
||||
// Error if not a host bridge
|
||||
if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'D', 'P')) {
|
||||
LOGERROR("Received DaynaPortWrite for a non-DaynaPort device");
|
||||
Error();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reallocate buffer (because it is not transfer for each block)
|
||||
if (ctrl.bufsize < 0x1000000) {
|
||||
free(ctrl.buffer);
|
||||
ctrl.bufsize = 0x1000000;
|
||||
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
|
||||
}
|
||||
|
||||
|
||||
data_format = ctrl.cmd[5];
|
||||
|
||||
|
||||
if(data_format == 0x00){
|
||||
ctrl.length = (WORD)ctrl.cmd[4] + ((WORD)ctrl.cmd[3] << 8);
|
||||
}
|
||||
else if (data_format == 0x80){
|
||||
ctrl.length = (WORD)ctrl.cmd[4] + ((WORD)ctrl.cmd[3] << 8) + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format);
|
||||
}
|
||||
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.length, (int)ctrl.length, (unsigned int)data_format);
|
||||
|
||||
if (ctrl.length <= 0) {
|
||||
// Failure (Error)
|
||||
Error();
|
||||
@ -1177,12 +1170,14 @@ void FASTCALL SASIDEV::CmdRead6()
|
||||
}
|
||||
|
||||
// Set next block
|
||||
ctrl.next = record + 1;
|
||||
ctrl.blocks = 1;
|
||||
ctrl.next = 1;
|
||||
|
||||
// Read phase
|
||||
DataIn();
|
||||
// Light phase
|
||||
DataOut();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// WRITE(6)
|
||||
@ -1202,6 +1197,12 @@ void FASTCALL SASIDEV::CmdWrite6()
|
||||
return;
|
||||
}
|
||||
|
||||
// Special receive function for the DaynaPort
|
||||
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'D', 'P')){
|
||||
DaynaPortWrite();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get record number and block number
|
||||
record = ctrl.cmd[1] & 0x1f;
|
||||
record <<= 8;
|
||||
@ -1213,14 +1214,12 @@ void FASTCALL SASIDEV::CmdWrite6()
|
||||
ctrl.blocks = 0x100;
|
||||
}
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal,
|
||||
"WRITE(6) command record=%06X blocks=%d", record, ctrl.blocks);
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s WRITE(6) command record=%06X blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks);
|
||||
|
||||
// Command processing on drive
|
||||
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
|
||||
if (ctrl.length <= 0) {
|
||||
LOGDEBUG("WriteCheck failed");
|
||||
// Failure (Error)
|
||||
Error();
|
||||
return;
|
||||
@ -1245,9 +1244,7 @@ void FASTCALL SASIDEV::CmdSeek6()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "SEEK(6) Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s SEEK(6) Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1280,9 +1277,7 @@ void FASTCALL SASIDEV::CmdAssign()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "ASSIGN Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1318,9 +1313,7 @@ void FASTCALL SASIDEV::CmdSpecify()
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "SPECIFY Command ");
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1354,10 +1347,7 @@ void FASTCALL SASIDEV::CmdInvalid()
|
||||
DWORD lun;
|
||||
|
||||
ASSERT(this);
|
||||
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Command not supported");
|
||||
#endif // DISK_LOG
|
||||
LOGWARN("%s Command not supported", __PRETTY_FUNCTION__);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1392,7 +1382,6 @@ void FASTCALL SASIDEV::Send()
|
||||
ASSERT(!ctrl.bus->GetREQ());
|
||||
ASSERT(ctrl.bus->GetIO());
|
||||
|
||||
#ifdef RASCSI
|
||||
// Check that the length isn't 0
|
||||
if (ctrl.length != 0) {
|
||||
len = ctrl.bus->SendHandShake(
|
||||
@ -1400,6 +1389,7 @@ void FASTCALL SASIDEV::Send()
|
||||
|
||||
// If you can not send it all, move on to the status phase
|
||||
if (len != (int)ctrl.length) {
|
||||
LOGERROR("%s ctrl.length (%d) did not match the amount of data sent (%d)",__PRETTY_FUNCTION__, (int)ctrl.length, len);
|
||||
Error();
|
||||
return;
|
||||
}
|
||||
@ -1409,20 +1399,9 @@ void FASTCALL SASIDEV::Send()
|
||||
ctrl.length = 0;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// Offset and Length
|
||||
ASSERT(ctrl.length >= 1);
|
||||
ctrl.offset++;
|
||||
ctrl.length--;
|
||||
|
||||
// Immediately after ACK is asserted, if the data
|
||||
// has been set by SendNext, raise the request
|
||||
if (ctrl.length != 0) {
|
||||
// Signal line operated by the target
|
||||
ctrl.bus->SetREQ(TRUE);
|
||||
return;
|
||||
else{
|
||||
LOGINFO("%s ctrl.length was 0", __PRETTY_FUNCTION__);
|
||||
}
|
||||
#endif // RASCSI
|
||||
|
||||
// Remove block and initialize the result
|
||||
ctrl.blocks--;
|
||||
@ -1433,8 +1412,8 @@ void FASTCALL SASIDEV::Send()
|
||||
if (ctrl.blocks != 0) {
|
||||
// Set next buffer (set offset, length)
|
||||
result = XferIn(ctrl.buffer);
|
||||
//** printf("xfer in: %d \n",result);
|
||||
|
||||
LOGTRACE("%s xfer in: %d",__PRETTY_FUNCTION__, result);
|
||||
LOGTRACE("%s processing after data collection", __PRETTY_FUNCTION__);
|
||||
#ifndef RASCSI
|
||||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||||
#endif // RASCSI
|
||||
@ -1443,6 +1422,7 @@ void FASTCALL SASIDEV::Send()
|
||||
|
||||
// If result FALSE, move to the status phase
|
||||
if (!result) {
|
||||
LOGERROR("%s Send result was false", __PRETTY_FUNCTION__);
|
||||
Error();
|
||||
return;
|
||||
}
|
||||
@ -1538,9 +1518,7 @@ void FASTCALL SASIDEV::Receive()
|
||||
// Command phase
|
||||
case BUS::command:
|
||||
ctrl.cmd[ctrl.offset] = data;
|
||||
#if defined(DISK_LOG)
|
||||
Log(Log::Normal, "Command phase $%02X", data);
|
||||
#endif // DISK_LOG
|
||||
LOGTRACE( "%s Command phase $%02X", __PRETTY_FUNCTION__, data);
|
||||
|
||||
// Set the length again with the first data (offset 0)
|
||||
if (ctrl.offset == 0) {
|
||||
@ -1597,6 +1575,7 @@ void FASTCALL SASIDEV::ReceiveNext()
|
||||
// Receive
|
||||
len = ctrl.bus->ReceiveHandShake(
|
||||
&ctrl.buffer[ctrl.offset], ctrl.length);
|
||||
LOGDEBUG("%s Received %d bytes", __PRETTY_FUNCTION__, len);
|
||||
|
||||
// If not able to receive all, move to status phase
|
||||
if (len != (int)ctrl.length) {
|
||||
@ -1609,6 +1588,10 @@ void FASTCALL SASIDEV::ReceiveNext()
|
||||
ctrl.length = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGDEBUG("%s ctrl.length was 0", __PRETTY_FUNCTION__);
|
||||
}
|
||||
#else
|
||||
// Offset and Length
|
||||
ASSERT(ctrl.length >= 1);
|
||||
@ -1667,6 +1650,7 @@ void FASTCALL SASIDEV::ReceiveNext()
|
||||
|
||||
// Data out phase
|
||||
case BUS::dataout:
|
||||
LOGTRACE("%s transitioning to FlushUnit()",__PRETTY_FUNCTION__);
|
||||
// Flush
|
||||
FlushUnit();
|
||||
|
||||
@ -1693,6 +1677,7 @@ BOOL FASTCALL SASIDEV::XferIn(BYTE *buf)
|
||||
|
||||
ASSERT(this);
|
||||
ASSERT(ctrl.phase == BUS::datain);
|
||||
LOGTRACE("%s ctrl.cmd[0]=%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0]);
|
||||
|
||||
// Logical Unit
|
||||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||||
@ -1707,7 +1692,7 @@ BOOL FASTCALL SASIDEV::XferIn(BYTE *buf)
|
||||
// READ(10)
|
||||
case 0x28:
|
||||
// Read from disk
|
||||
ctrl.length = ctrl.unit[lun]->Read(buf, ctrl.next);
|
||||
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, buf, ctrl.next);
|
||||
ctrl.next++;
|
||||
|
||||
// If there is an error, go to the status phase
|
||||
@ -1750,12 +1735,9 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// MODE SELECT or WRITE system
|
||||
switch (ctrl.cmd[0]) {
|
||||
// MODE SELECT
|
||||
case 0x15:
|
||||
// MODE SELECT(10)
|
||||
case 0x55:
|
||||
switch ((SCSIDEV::scsi_command) ctrl.cmd[0]) {
|
||||
case SCSIDEV::eCmdModeSelect:
|
||||
case SCSIDEV::eCmdModeSelect10:
|
||||
if (!ctrl.unit[lun]->ModeSelect(
|
||||
ctrl.cmd, ctrl.buffer, ctrl.offset)) {
|
||||
// MODE SELECT failed
|
||||
@ -1763,11 +1745,11 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
|
||||
}
|
||||
break;
|
||||
|
||||
// WRITE(6)
|
||||
case 0x0a:
|
||||
// WRITE(10)
|
||||
case 0x2a:
|
||||
// Replace the host bridge with SEND MESSAGE 10
|
||||
case SCSIDEV::eCmdWrite6:
|
||||
case SCSIDEV::eCmdWrite10:
|
||||
case SCSIDEV::eCmdWriteAndVerify10:
|
||||
// If we're a host bridge, use the host bridge's SendMessage10
|
||||
// function
|
||||
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||||
bridge = (SCSIBR*)ctrl.unit[lun];
|
||||
if (!bridge->SendMessage10(ctrl.cmd, ctrl.buffer)) {
|
||||
@ -1780,10 +1762,23 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
|
||||
break;
|
||||
}
|
||||
|
||||
// WRITE AND VERIFY
|
||||
case 0x2e:
|
||||
// Write
|
||||
if (!ctrl.unit[lun]->Write(ctrl.buffer, ctrl.next - 1)) {
|
||||
// Special case Write function for DaynaPort
|
||||
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'D', 'P')) {
|
||||
LOGTRACE("%s Doing special case write for DayanPort", __PRETTY_FUNCTION__);
|
||||
if (!(SCSIDaynaPort*)ctrl.unit[lun]->Write(ctrl.cmd, ctrl.buffer, ctrl.length)) {
|
||||
// write failed
|
||||
return FALSE;
|
||||
}
|
||||
LOGTRACE("%s Done with DaynaPort Write", __PRETTY_FUNCTION__);
|
||||
|
||||
// If normal, work setting
|
||||
ctrl.offset = 0;
|
||||
ctrl.blocks = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
LOGTRACE("%s eCmdWriteAndVerify10 Calling Write... cmd: %02X next: %d", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd, (int)ctrl.next);
|
||||
if (!ctrl.unit[lun]->Write(ctrl.cmd, ctrl.buffer, ctrl.next - 1)) {
|
||||
// Write failed
|
||||
return FALSE;
|
||||
}
|
||||
@ -1806,10 +1801,14 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
|
||||
break;
|
||||
|
||||
// SPECIFY(SASI only)
|
||||
case 0xc2:
|
||||
case SCSIDEV::eCmdInvalid:
|
||||
break;
|
||||
|
||||
case SCSIDEV::eCmdSetMcastAddr:
|
||||
LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__);
|
||||
break;
|
||||
default:
|
||||
LOGWARN("Received an unexpected command (%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__)
|
||||
ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
@ -1837,45 +1836,49 @@ void FASTCALL SASIDEV::FlushUnit()
|
||||
}
|
||||
|
||||
// WRITE system only
|
||||
switch (ctrl.cmd[0]) {
|
||||
// WRITE(6)
|
||||
case 0x0a:
|
||||
// WRITE(10)
|
||||
case 0x2a:
|
||||
// WRITE AND VERIFY
|
||||
case 0x2e:
|
||||
switch ((SCSIDEV::scsi_command)ctrl.cmd[0]) {
|
||||
case SCSIDEV::eCmdWrite6:
|
||||
case SCSIDEV::eCmdWrite10:
|
||||
case SCSIDEV::eCmdWriteAndVerify10:
|
||||
// Flush
|
||||
if (!ctrl.unit[lun]->IsCacheWB()) {
|
||||
ctrl.unit[lun]->Flush();
|
||||
}
|
||||
break;
|
||||
// Mode Select (6)
|
||||
case 0x15:
|
||||
// MODE SELECT(10)
|
||||
case 0x55:
|
||||
case SCSIDEV::eCmdModeSelect:
|
||||
case SCSIDEV::eCmdModeSelect10:
|
||||
// Debug code related to Issue #2 on github, where we get an unhandled Model select when
|
||||
// the mac is rebooted
|
||||
// https://github.com/akuker/RASCSI/issues/2
|
||||
Log(Log::Warning, "Received \'Mode Select\'\n");
|
||||
Log(Log::Warning, " Operation Code: [%02X]\n", ctrl.cmd[0]);
|
||||
Log(Log::Warning, " Logical Unit %01X, PF %01X, SP %01X [%02X]\n", ctrl.cmd[1] >> 5, 1 & (ctrl.cmd[1] >> 4), ctrl.cmd[1] & 1, ctrl.cmd[1]);
|
||||
Log(Log::Warning, " Reserved: %02X\n", ctrl.cmd[2]);
|
||||
Log(Log::Warning, " Reserved: %02X\n", ctrl.cmd[3]);
|
||||
Log(Log::Warning, " Parameter List Len %02X\n", ctrl.cmd[4]);
|
||||
Log(Log::Warning, " Reserved: %02X\n", ctrl.cmd[5]);
|
||||
Log(Log::Warning, " Ctrl Len: %08X\n",ctrl.length);
|
||||
LOGWARN("Received \'Mode Select\'\n");
|
||||
LOGWARN(" Operation Code: [%02X]\n", (WORD)ctrl.cmd[0]);
|
||||
LOGWARN(" Logical Unit %01X, PF %01X, SP %01X [%02X]\n",\
|
||||
(WORD)ctrl.cmd[1] >> 5, 1 & ((WORD)ctrl.cmd[1] >> 4), \
|
||||
(WORD)ctrl.cmd[1] & 1, (WORD)ctrl.cmd[1]);
|
||||
LOGWARN(" Reserved: %02X\n", (WORD)ctrl.cmd[2]);
|
||||
LOGWARN(" Reserved: %02X\n", (WORD)ctrl.cmd[3]);
|
||||
LOGWARN(" Parameter List Len %02X\n", (WORD)ctrl.cmd[4]);
|
||||
LOGWARN(" Reserved: %02X\n",(WORD)ctrl.cmd[5]);
|
||||
LOGWARN(" Ctrl Len: %08X\n",(WORD)ctrl.length);
|
||||
|
||||
if (!ctrl.unit[lun]->ModeSelect(
|
||||
ctrl.cmd, ctrl.buffer, ctrl.offset)) {
|
||||
// MODE SELECT failed
|
||||
Log(Log::Warning, "Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]);
|
||||
LOGWARN("Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCSIDEV::eCmdSetIfaceMode:
|
||||
LOGWARN("%s Trying to flush a command set interface mode. This should be a daynaport?", __PRETTY_FUNCTION__);
|
||||
break;
|
||||
case SCSIDEV::eCmdSetMcastAddr:
|
||||
// TODO: Eventually, we should store off the multicast address configuration data here...
|
||||
break;
|
||||
default:
|
||||
Log(Log::Warning, "Received an invalid flush command %02X!!!!!\n",ctrl.cmd[0]);
|
||||
ASSERT(FALSE);
|
||||
LOGWARN("Received an unexpected flush command %02X!!!!!\n",(WORD)ctrl.cmd[0]);
|
||||
// The following statement makes debugging a huge pain. You can un-comment it
|
||||
// if you're not trying to add new devices....
|
||||
// ASSERT(FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1929,71 +1932,3 @@ void SASIDEV::GetPhaseStr(char *str)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Log output
|
||||
//
|
||||
// TODO: This function needs some cleanup. Its very kludgey
|
||||
//---------------------------------------------------------------------------
|
||||
void FASTCALL SASIDEV::Log(Log::loglevel level, const char *format, ...)
|
||||
{
|
||||
#if !defined(BAREMETAL)
|
||||
#ifdef DISK_LOG
|
||||
char buffer[0x200];
|
||||
char buffer2[0x250];
|
||||
char buffer3[0x250];
|
||||
char phase_str[20];
|
||||
#endif
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
if(this->GetID() != 6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RASCSI
|
||||
#ifndef DISK_LOG
|
||||
if (level == Log::Warning) {
|
||||
return;
|
||||
}
|
||||
#endif // DISK_LOG
|
||||
#endif // RASCSI
|
||||
|
||||
#ifdef DISK_LOG
|
||||
// format
|
||||
vsprintf(buffer, format, args);
|
||||
|
||||
// end variable length argument
|
||||
va_end(args);
|
||||
|
||||
// Add the date/timestamp
|
||||
// current date/time based on current system
|
||||
time_t now = time(0);
|
||||
// convert now to string form
|
||||
char* dt = ctime(&now);
|
||||
|
||||
|
||||
strcpy(buffer2, "[");
|
||||
strcat(buffer2, dt);
|
||||
// Get rid of the carriage return
|
||||
buffer2[strlen(buffer2)-1] = '\0';
|
||||
strcat(buffer2, "] ");
|
||||
|
||||
// Get the phase
|
||||
this->GetPhaseStr(phase_str);
|
||||
sprintf(buffer3, "[%d][%s] ", this->GetID(), phase_str);
|
||||
strcat(buffer2,buffer3);
|
||||
strcat(buffer2, buffer);
|
||||
|
||||
|
||||
// Log output
|
||||
#ifdef RASCSI
|
||||
printf("%s\n", buffer2);
|
||||
#else
|
||||
host->GetVM()->GetLog()->Format(level, host, buffer);
|
||||
#endif // RASCSI
|
||||
#endif // BAREMETAL
|
||||
#endif // DISK_LOG
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
544
src/raspberrypi/devices/scsi_daynaport.cpp
Normal file
544
src/raspberrypi/devices/scsi_daynaport.cpp
Normal 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 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ Emulation of the DaynaPort SCSI Link Ethernet interface ]
|
||||
//
|
||||
// This design is derived from the SLINKCMD.TXT file, as well as David Kuder's
|
||||
// Tiny SCSI Emulator
|
||||
// - SLINKCMD: http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/SLINKCMD.TXT
|
||||
// - Tiny SCSI : https://hackaday.io/project/18974-tiny-scsi-emulator
|
||||
//
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
199
src/raspberrypi/devices/scsi_daynaport.h
Normal file
199
src/raspberrypi/devices/scsi_daynaport.h
Normal 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 PI.(ytanaka@ipc-tokai.or.jp)
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ Emulation of the DaynaPort SCSI Link Ethernet interface ]
|
||||
//
|
||||
// This design is derived from the SLINKCMD.TXT file, as well as David Kuder's
|
||||
// Tiny SCSI Emulator
|
||||
// - SLINKCMD: http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/SLINKCMD.TXT
|
||||
// - Tiny SCSI : https://hackaday.io/project/18974-tiny-scsi-emulator
|
||||
//
|
||||
// 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
|
||||
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@ -544,7 +568,7 @@ public:
|
||||
// Data transmission handshake
|
||||
|
||||
static BUS::phase_t FASTCALL GetPhaseRaw(DWORD raw_data);
|
||||
// Get the phase based on raw data
|
||||
// Get the phase based on raw data
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal interrupt
|
||||
|
3
src/raspberrypi/launch_sudo.sh
Executable file
3
src/raspberrypi/launch_sudo.sh
Executable 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 "$@"
|
@ -16,40 +16,26 @@
|
||||
#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)
|
||||
#define LOGDEBUG(...) ((void)0)
|
||||
#define LOGTRACE(...) ((void)0)
|
||||
#define LOGDEBUG(...) ((void)0)
|
||||
#else
|
||||
#define LOGTRACE(...) SPDLOGWRAPPER(spdlog::level::trace, __VA_ARGS__)
|
||||
#define LOGDEBUG(...) SPDLOGWRAPPER(spdlog::level::debug, __VA_ARGS__)
|
||||
#define LOGTRACE(...) SPDLOGWRAPPER(spdlog::level::trace, __VA_ARGS__)
|
||||
#define LOGDEBUG(...) SPDLOGWRAPPER(spdlog::level::debug, __VA_ARGS__)
|
||||
#endif
|
||||
#define LOGINFO(...) SPDLOGWRAPPER(spdlog::level::info, __VA_ARGS__)
|
||||
#define LOGWARN(...) SPDLOGWRAPPER(spdlog::level::warn, __VA_ARGS__)
|
||||
#define LOGERROR(...) SPDLOGWRAPPER(spdlog::level::err, __VA_ARGS__)
|
||||
#define LOGCRITICAL(...) SPDLOGWRAPPER(spdlog::level::critical, __VA_ARGS__)
|
||||
#define LOGINFO(...) SPDLOGWRAPPER(spdlog::level::info, __VA_ARGS__)
|
||||
#define LOGWARN(...) SPDLOGWRAPPER(spdlog::level::warn, __VA_ARGS__)
|
||||
#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
|
||||
#endif // log_h
|
||||
|
@ -5,10 +5,11 @@
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) 2020 akuker
|
||||
//
|
||||
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
|
||||
//
|
||||
// [ OS固有 ]
|
||||
// [ OS related definitions ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@ -86,7 +87,7 @@
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 基本マクロ
|
||||
// Basic Macros
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#undef FASTCALL
|
||||
@ -118,7 +119,7 @@
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// 基本型定義
|
||||
// Basic Type Definitions
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
typedef unsigned char BYTE;
|
||||
|
@ -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;
|
||||
|
@ -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
24
src/raspberrypi/rasctl.h
Normal 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,
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
7
src/raspberrypi/setup_bridge.sh
Executable file
7
src/raspberrypi/setup_bridge.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user