merge in latest develop

This commit is contained in:
akuker 2021-02-06 19:48:11 -06:00
commit 0ef9ff72de
28 changed files with 748 additions and 1939 deletions

View File

@ -8,15 +8,13 @@
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/fullspec/rascsi",
"program": "${workspaceFolder}/bin/rascsi",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"targetArchitecture": "arm",
"miDebuggerPath": "${workspaceFolder}/launch_sudo.sh",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",

View File

@ -5,7 +5,7 @@
"type": "shell",
"label": "g++ build active file",
"command": "make",
"args": ["all", "DEBUG=1", "-j4"],
"args": ["all", "DEBUG=1"],
"options": {
"cwd": "${workspaceFolder}/"
},

View File

@ -33,9 +33,9 @@ endif
CFLAGS += -iquote . -MD -MP
CXXFLAGS += -std=c++14 -iquote . -MD -MP
## CONNECT_TYPE=FULLSPEC : Specify the type of RaSCSI board type
## CONNECT_TYPE=STANDARD : Specify the type of RaSCSI board type
## that you are using. The typical options are
## STANDARD or FULLSPEC. The default is FULLSPEC
## STANDARD or FULLSPEC. The default is STANDARD
## * THIS IS TYPICALLY THE ONLY COMPILE OPTION YOU
## * NEED TO SPECIFY
# If its not specified, build for FULLSPEC configuration
@ -75,7 +75,6 @@ SRC_RASCSI = \
gpiobus.cpp \
filepath.cpp \
fileio.cpp\
os.cpp\
rascsi_version.cpp
# os.cpp
# rasctl_command.cpp
@ -89,8 +88,11 @@ 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\
@ -152,7 +154,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 -lz
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL)

View File

@ -17,8 +17,6 @@
#include "filepath.h"
#include "gpiobus.h"
#include "devices/scsi_host_bridge.h"
#include "controllers/scsidev_ctrl.h"
#include "devices/scsi_daynaport.h"
//===========================================================================
//
@ -46,7 +44,7 @@ SASIDEV::SASIDEV(Device *dev)
// Work initialization
ctrl.phase = BUS::busfree;
ctrl.m_scsi_id = -1;
ctrl.id = -1;
ctrl.bus = NULL;
memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd));
ctrl.status = 0x00;
@ -54,7 +52,7 @@ SASIDEV::SASIDEV(Device *dev)
#ifdef RASCSI
ctrl.execstart = 0;
#endif // RASCSI
ctrl.bufsize = ETH_FRAME_LEN + 16 + ETH_FCS_LEN;
ctrl.bufsize = 0x800;
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
memset(ctrl.buffer, 0x00, ctrl.bufsize);
ctrl.blocks = 0;
@ -203,7 +201,7 @@ void FASTCALL SASIDEV::Connect(int id, BUS *bus)
{
ASSERT(this);
ctrl.m_scsi_id = id;
ctrl.id = id;
ctrl.bus = bus;
}
@ -293,7 +291,7 @@ BUS::phase_t FASTCALL SASIDEV::Process()
ASSERT(this);
// Do nothing if not connected
if (ctrl.m_scsi_id < 0 || ctrl.bus == NULL) {
if (ctrl.id < 0 || ctrl.bus == NULL) {
return ctrl.phase;
}
@ -303,7 +301,9 @@ 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()) {
LOGINFO("RESET signal received");
#if defined(DISK_LOG)
Log(Log::Normal, "RESET signal received");
#endif // DISK_LOG
// Reset the controller
Reset();
@ -371,7 +371,9 @@ void FASTCALL SASIDEV::BusFree()
// Phase change
if (ctrl.phase != BUS::busfree) {
LOGINFO("Bus free phase");
#if defined(DISK_LOG)
Log(Log::Normal, "Bus free phase");
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::busfree;
@ -409,7 +411,7 @@ void FASTCALL SASIDEV::Selection()
// Phase change
if (ctrl.phase != BUS::selection) {
// Invalid if IDs do not match
id = 1 << ctrl.m_scsi_id;
id = 1 << ctrl.id;
if ((ctrl.bus->GetDAT() & id) == 0) {
return;
}
@ -419,7 +421,10 @@ void FASTCALL SASIDEV::Selection()
return;
}
LOGTRACE("%s Selection Phase ID=%d (with device)", __PRETTY_FUNCTION__, (int)ctrl.m_scsi_id);
#if defined(DISK_LOG)
Log(Log::Normal,
"Selection Phase ID=%d (with device)", ctrl.id);
#endif // DISK_LOG
// Phase change
ctrl.phase = BUS::selection;
@ -452,7 +457,9 @@ void FASTCALL SASIDEV::Command()
// Phase change
if (ctrl.phase != BUS::command) {
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "Command Phase");
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::command;
@ -530,7 +537,9 @@ void FASTCALL SASIDEV::Execute()
{
ASSERT(this);
LOGTRACE("%s Execution Phase Command %02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]);
#if defined(DISK_LOG)
Log(Log::Normal, "Execution Phase Command %02X", ctrl.cmd[0]);
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::execute;
@ -543,68 +552,65 @@ void FASTCALL SASIDEV::Execute()
#endif // RASCSI
// Process by command
switch ((SCSIDEV::scsi_command)ctrl.cmd[0]) {
switch (ctrl.cmd[0]) {
// TEST UNIT READY
case SCSIDEV::eCmdTestUnitReady:
case 0x00:
CmdTestUnitReady();
return;
// REZERO UNIT
case SCSIDEV::eCmdRezero:
case 0x01:
CmdRezero();
return;
// REQUEST SENSE
case SCSIDEV::eCmdRequestSense:
case 0x03:
CmdRequestSense();
return;
// FORMAT UNIT
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
// leaving it here for now....
case SCSIDEV::eCmdFormat:
case 0x04:
CmdFormat();
return;
// FORMAT UNIT
case 0x06:
CmdFormat();
return;
// REASSIGN BLOCKS
case SCSIDEV::eCmdReassign:
case 0x07:
CmdReassign();
return;
// READ(6)
case SCSIDEV::eCmdRead6:
case 0x08:
CmdRead6();
return;
// WRITE(6)
case SCSIDEV::eCmdWrite6:
case 0x0a:
CmdWrite6();
return;
// SEEK(6)
case SCSIDEV::eCmdSeek6:
case 0x0b:
CmdSeek6();
return;
// ASSIGN(SASIのみ)
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
// leaving it here for now....
case SCSIDEV::eCmdSasiCmdAssign:
case 0x0e:
CmdAssign();
return;
// SPECIFY(SASIのみ)
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
// leaving it here for now....
case SCSIDEV::eCmdInvalid:
case 0xc2:
CmdSpecify();
return;
default:
break;
}
// Unsupported command
LOGWARN("%s Unsupported command $%02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]);
Log(Log::Warning, "Unsupported command $%02X", ctrl.cmd[0]);
CmdInvalid();
}
@ -639,7 +645,9 @@ void FASTCALL SASIDEV::Status()
}
#endif // RASCSI
LOGTRACE("%s Status phase", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "Status phase");
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::status;
@ -660,7 +668,9 @@ void FASTCALL SASIDEV::Status()
ctrl.bus->SetDAT(ctrl.buffer[0]);
ctrl.bus->SetREQ(TRUE);
LOGTRACE( "%s Status Phase $%02X",__PRETTY_FUNCTION__, (unsigned int)ctrl.status);
#if defined(DISK_LOG)
Log(Log::Normal, "Status Phase $%02X", ctrl.status);
#endif // DISK_LOG
#endif // RASCSI
return;
}
@ -695,7 +705,10 @@ void FASTCALL SASIDEV::MsgIn()
// Phase change
if (ctrl.phase != BUS::msgin) {
LOGTRACE("%s Starting Message in phase", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "Message in phase");
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::msgin;
@ -709,12 +722,36 @@ 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
}
//---------------------------------------------------------------------------
@ -753,7 +790,10 @@ void FASTCALL SASIDEV::DataIn()
return;
}
LOGTRACE("%s Going into Data-in Phase", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "Data-in Phase");
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::datain;
@ -767,11 +807,33 @@ 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
}
//---------------------------------------------------------------------------
@ -810,7 +872,9 @@ void FASTCALL SASIDEV::DataOut()
return;
}
LOGTRACE("%s Data out phase", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "Data out phase");
#endif // DISK_LOG
// Phase Setting
ctrl.phase = BUS::dataout;
@ -882,7 +946,7 @@ void FASTCALL SASIDEV::Error()
}
#if defined(DISK_LOG)
LOGWARN("Error occured (going to status phase)");
Log(Log::Warning, "Error occured (going to status phase)");
#endif // DISK_LOG
// Logical Unit
@ -907,7 +971,9 @@ void FASTCALL SASIDEV::CmdTestUnitReady()
ASSERT(this);
LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "TEST UNIT READY Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -940,7 +1006,9 @@ void FASTCALL SASIDEV::CmdRezero()
ASSERT(this);
LOGTRACE( "%s REZERO UNIT Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "REZERO UNIT Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -972,7 +1040,9 @@ void FASTCALL SASIDEV::CmdRequestSense()
ASSERT(this);
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "REQUEST SENSE Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -981,11 +1051,13 @@ void FASTCALL SASIDEV::CmdRequestSense()
return;
}
// Command processing on drive
ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
ASSERT(ctrl.length > 0);
LOGTRACE("%s Sense key $%02X",__PRETTY_FUNCTION__, (WORD)ctrl.buffer[2]);
#if defined(DISK_LOG)
Log(Log::Normal, "Sense key $%02X", ctrl.buffer[2]);
#endif // DISK_LOG
// Read phase
DataIn();
@ -1003,7 +1075,9 @@ void FASTCALL SASIDEV::CmdFormat()
ASSERT(this);
LOGTRACE( "%s FORMAT UNIT Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "FORMAT UNIT Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -1036,7 +1110,9 @@ void FASTCALL SASIDEV::CmdReassign()
ASSERT(this);
LOGTRACE("%s REASSIGN BLOCKS Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "REASSIGN BLOCKS Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -1087,82 +1163,13 @@ void FASTCALL SASIDEV::CmdRead6()
ctrl.blocks = 0x100;
}
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());
#if defined(DISK_LOG)
Log(Log::Normal,
"READ(6) command record=%06X blocks=%d", record, ctrl.blocks);
#endif // DISK_LOG
// Command processing on drive
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);
ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record);
if (ctrl.length <= 0) {
// Failure (Error)
Error();
@ -1170,14 +1177,12 @@ void FASTCALL SASIDEV::DaynaPortWrite()
}
// Set next block
ctrl.blocks = 1;
ctrl.next = 1;
ctrl.next = record + 1;
// Light phase
DataOut();
// Read phase
DataIn();
}
//---------------------------------------------------------------------------
//
// WRITE(6)
@ -1197,12 +1202,6 @@ 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;
@ -1214,12 +1213,14 @@ void FASTCALL SASIDEV::CmdWrite6()
ctrl.blocks = 0x100;
}
LOGTRACE("%s WRITE(6) command record=%06X blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks);
#if defined(DISK_LOG)
Log(Log::Normal,
"WRITE(6) command record=%06X blocks=%d", record, ctrl.blocks);
#endif // DISK_LOG
// Command processing on drive
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
if (ctrl.length <= 0) {
LOGDEBUG("WriteCheck failed");
// Failure (Error)
Error();
return;
@ -1244,7 +1245,9 @@ void FASTCALL SASIDEV::CmdSeek6()
ASSERT(this);
LOGTRACE("%s SEEK(6) Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "SEEK(6) Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -1277,7 +1280,9 @@ void FASTCALL SASIDEV::CmdAssign()
ASSERT(this);
LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "ASSIGN Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -1313,7 +1318,9 @@ void FASTCALL SASIDEV::CmdSpecify()
ASSERT(this);
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "SPECIFY Command ");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -1347,7 +1354,10 @@ void FASTCALL SASIDEV::CmdInvalid()
DWORD lun;
ASSERT(this);
LOGWARN("%s Command not supported", __PRETTY_FUNCTION__);
#if defined(DISK_LOG)
Log(Log::Normal, "Command not supported");
#endif // DISK_LOG
// Logical Unit
lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -1382,6 +1392,7 @@ 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(
@ -1389,7 +1400,6 @@ 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;
}
@ -1399,9 +1409,20 @@ void FASTCALL SASIDEV::Send()
ctrl.length = 0;
return;
}
else{
LOGINFO("%s ctrl.length was 0", __PRETTY_FUNCTION__);
#else
// Offset and Length
ASSERT(ctrl.length >= 1);
ctrl.offset++;
ctrl.length--;
// Immediately after ACK is asserted, if the data
// has been set by SendNext, raise the request
if (ctrl.length != 0) {
// Signal line operated by the target
ctrl.bus->SetREQ(TRUE);
return;
}
#endif // RASCSI
// Remove block and initialize the result
ctrl.blocks--;
@ -1412,8 +1433,8 @@ void FASTCALL SASIDEV::Send()
if (ctrl.blocks != 0) {
// Set next buffer (set offset, length)
result = XferIn(ctrl.buffer);
LOGTRACE("%s xfer in: %d",__PRETTY_FUNCTION__, result);
LOGTRACE("%s processing after data collection", __PRETTY_FUNCTION__);
//** printf("xfer in: %d \n",result);
#ifndef RASCSI
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
#endif // RASCSI
@ -1422,7 +1443,6 @@ void FASTCALL SASIDEV::Send()
// If result FALSE, move to the status phase
if (!result) {
LOGERROR("%s Send result was false", __PRETTY_FUNCTION__);
Error();
return;
}
@ -1518,7 +1538,9 @@ void FASTCALL SASIDEV::Receive()
// Command phase
case BUS::command:
ctrl.cmd[ctrl.offset] = data;
LOGTRACE( "%s Command phase $%02X", __PRETTY_FUNCTION__, data);
#if defined(DISK_LOG)
Log(Log::Normal, "Command phase $%02X", data);
#endif // DISK_LOG
// Set the length again with the first data (offset 0)
if (ctrl.offset == 0) {
@ -1575,7 +1597,6 @@ 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) {
@ -1588,10 +1609,6 @@ 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);
@ -1650,7 +1667,6 @@ void FASTCALL SASIDEV::ReceiveNext()
// Data out phase
case BUS::dataout:
LOGTRACE("%s transitioning to FlushUnit()",__PRETTY_FUNCTION__);
// Flush
FlushUnit();
@ -1677,7 +1693,6 @@ 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;
@ -1692,7 +1707,7 @@ BOOL FASTCALL SASIDEV::XferIn(BYTE *buf)
// READ(10)
case 0x28:
// Read from disk
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, buf, ctrl.next);
ctrl.length = ctrl.unit[lun]->Read(buf, ctrl.next);
ctrl.next++;
// If there is an error, go to the status phase
@ -1735,9 +1750,12 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
return FALSE;
}
switch ((SCSIDEV::scsi_command) ctrl.cmd[0]) {
case SCSIDEV::eCmdModeSelect:
case SCSIDEV::eCmdModeSelect10:
// MODE SELECT or WRITE system
switch (ctrl.cmd[0]) {
// MODE SELECT
case 0x15:
// MODE SELECT(10)
case 0x55:
if (!ctrl.unit[lun]->ModeSelect(
ctrl.cmd, ctrl.buffer, ctrl.offset)) {
// MODE SELECT failed
@ -1745,11 +1763,11 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
}
break;
case SCSIDEV::eCmdWrite6:
case SCSIDEV::eCmdWrite10:
case SCSIDEV::eCmdWriteAndVerify10:
// If we're a host bridge, use the host bridge's SendMessage10
// function
// WRITE(6)
case 0x0a:
// WRITE(10)
case 0x2a:
// Replace the host bridge with SEND MESSAGE 10
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) {
bridge = (SCSIBR*)ctrl.unit[lun];
if (!bridge->SendMessage10(ctrl.cmd, ctrl.buffer)) {
@ -1762,23 +1780,10 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
break;
}
// 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 AND VERIFY
case 0x2e:
// Write
if (!ctrl.unit[lun]->Write(ctrl.buffer, ctrl.next - 1)) {
// Write failed
return FALSE;
}
@ -1801,14 +1806,10 @@ BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
break;
// SPECIFY(SASI only)
case SCSIDEV::eCmdInvalid:
case 0xc2:
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;
}
@ -1836,49 +1837,45 @@ void FASTCALL SASIDEV::FlushUnit()
}
// WRITE system only
switch ((SCSIDEV::scsi_command)ctrl.cmd[0]) {
case SCSIDEV::eCmdWrite6:
case SCSIDEV::eCmdWrite10:
case SCSIDEV::eCmdWriteAndVerify10:
switch (ctrl.cmd[0]) {
// WRITE(6)
case 0x0a:
// WRITE(10)
case 0x2a:
// WRITE AND VERIFY
case 0x2e:
// Flush
if (!ctrl.unit[lun]->IsCacheWB()) {
ctrl.unit[lun]->Flush();
}
break;
case SCSIDEV::eCmdModeSelect:
case SCSIDEV::eCmdModeSelect10:
// Mode Select (6)
case 0x15:
// MODE SELECT(10)
case 0x55:
// 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
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);
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);
if (!ctrl.unit[lun]->ModeSelect(
ctrl.cmd, ctrl.buffer, ctrl.offset)) {
// MODE SELECT failed
LOGWARN("Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]);
Log(Log::Warning, "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:
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);
Log(Log::Warning, "Received an invalid flush command %02X!!!!!\n",ctrl.cmd[0]);
ASSERT(FALSE);
break;
}
}
@ -1932,3 +1929,71 @@ void SASIDEV::GetPhaseStr(char *str)
}
}
#endif
//---------------------------------------------------------------------------
//
// Log output
//
// TODO: This function needs some cleanup. Its very kludgey
//---------------------------------------------------------------------------
void FASTCALL SASIDEV::Log(Log::loglevel level, const char *format, ...)
{
#if !defined(BAREMETAL)
#ifdef DISK_LOG
char buffer[0x200];
char buffer2[0x250];
char buffer3[0x250];
char phase_str[20];
#endif
va_list args;
va_start(args, format);
if(this->GetID() != 6)
{
return;
}
#ifdef RASCSI
#ifndef DISK_LOG
if (level == Log::Warning) {
return;
}
#endif // DISK_LOG
#endif // RASCSI
#ifdef DISK_LOG
// format
vsprintf(buffer, format, args);
// end variable length argument
va_end(args);
// Add the date/timestamp
// current date/time based on current system
time_t now = time(0);
// convert now to string form
char* dt = ctime(&now);
strcpy(buffer2, "[");
strcat(buffer2, dt);
// Get rid of the carriage return
buffer2[strlen(buffer2)-1] = '\0';
strcat(buffer2, "] ");
// Get the phase
this->GetPhaseStr(phase_str);
sprintf(buffer3, "[%d][%s] ", this->GetID(), phase_str);
strcat(buffer2,buffer3);
strcat(buffer2, buffer);
// Log output
#ifdef RASCSI
printf("%s\n", buffer2);
#else
host->GetVM()->GetLog()->Format(level, host, buffer);
#endif // RASCSI
#endif // BAREMETAL
#endif // DISK_LOG
}

View File

@ -46,9 +46,9 @@ public:
// Internal data definition
typedef struct {
// General
// 全般
BUS::phase_t phase; // Transition phase
int m_scsi_id; // Controller ID (0-7)
int id; // Controller ID (0-7)
BUS *bus; // Bus
// commands
@ -116,7 +116,7 @@ public:
void FASTCALL GetPhaseStr(char *str);
#endif
int FASTCALL GetSCSIID() {return ctrl.m_scsi_id;}
int FASTCALL GetID() {return ctrl.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
virtual void FASTCALL CmdRead6();
void FASTCALL CmdRead6();
// READ(6) command
virtual void FASTCALL CmdWrite6();
void FASTCALL CmdWrite6();
// WRITE(6) command
void FASTCALL CmdSeek6();
// SEEK(6) command
@ -173,8 +173,6 @@ protected:
// SPECIFY command
void FASTCALL CmdInvalid();
// Unsupported command
void FASTCALL DaynaPortWrite();
// DaynaPort specific 'write' operation
// データ転送
virtual void FASTCALL Send();
@ -198,6 +196,10 @@ protected:
void FASTCALL FlushUnit();
// Flush the logical unit
// Log
void FASTCALL Log(Log::loglevel level, const char *format, ...);
// Log output
protected:
#ifndef RASCSI
Device *host;

File diff suppressed because it is too large Load Diff

View File

@ -38,74 +38,13 @@ 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();
@ -180,16 +119,8 @@ private:
// GET MESSAGE(10) command
void FASTCALL CmdSendMessage10();
// SEND MESSAGE(10) command
void FASTCALL CmdRetrieveStats();
// DaynaPort specific command
void FASTCALL CmdSetIfaceMode();
// DaynaPort specific command
void FASTCALL CmdSetMcastAddr();
// DaynaPort specific command
void FASTCALL CmdEnableInterface();
// DaynaPort specific command
// Data transfer
// データ転送
void FASTCALL Send();
// Send data
#ifndef RASCSI

View File

@ -5,19 +5,16 @@
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) akuker
//
// Imported NetBSD support and some optimisation patches by Rin Okuyama.
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
//
// [ TAP Driver ]
//
//---------------------------------------------------------------------------
#include <zlib.h> // For crc32()
#include "os.h"
#include "xm6.h"
#include "ctapdriver.h"
#include "log.h"
//---------------------------------------------------------------------------
//
@ -26,7 +23,6 @@
//---------------------------------------------------------------------------
CTapDriver::CTapDriver()
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
// Initialization
m_hTAP = -1;
memset(&m_MacAddr, 0, sizeof(m_MacAddr));
@ -40,56 +36,38 @@ CTapDriver::CTapDriver()
#ifdef __linux__
BOOL FASTCALL CTapDriver::Init()
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
char dev[IFNAMSIZ] = "ras0";
struct ifreq ifr;
int ret;
ASSERT(this);
LOGTRACE("Opening Tap device");
// TAP device initilization
if ((m_hTAP = open("/dev/net/tun", O_RDWR)) < 0) {
LOGERROR("Error: can't open tun. Errno: %d %s", errno, strerror(errno));
printf("Error: can't open tun\n");
return FALSE;
}
LOGTRACE("Opened tap device %d",m_hTAP);
// IFF_NO_PI for no extra packet information
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
LOGTRACE("Going to open %s", ifr.ifr_name);
if ((ret = ioctl(m_hTAP, TUNSETIFF, (void *)&ifr)) < 0) {
LOGERROR("Error: can't ioctl TUNSETIFF. Errno: %d %s", errno, strerror(errno));
printf("Error: can't ioctl TUNSETIFF\n");
close(m_hTAP);
return FALSE;
}
LOGTRACE("return code from ioctl was %d", ret);
LOGDEBUG("ip link set ras0 up");
ret = run_system_cmd("ip link set ras0 up");
LOGTRACE("return code from ip link set ras0 up was %d", ret);
LOGDEBUG("brctl addif rascsi_bridge ras0");
ret = run_system_cmd("brctl addif rascsi_bridge ras0");
LOGTRACE("return code from brctl addif rascsi_bridge ras0 was %d", ret);
// Get MAC address
LOGTRACE("Getting the MAC address");
ifr.ifr_addr.sa_family = AF_INET;
if ((ret = ioctl(m_hTAP, SIOCGIFHWADDR, &ifr)) < 0) {
LOGERROR("Error: can't ioctl SIOCGIFHWADDR. Errno: %d %s", errno, strerror(errno));
printf("Error: can't ioctl SIOCGIFHWADDR\n");
close(m_hTAP);
return FALSE;
}
LOGTRACE("got the mac");
// Save MAC address
memcpy(m_MacAddr, ifr.ifr_hwaddr.sa_data, sizeof(m_MacAddr));
LOGINFO("Tap device %s created", ifr.ifr_name);
return TRUE;
}
#endif // __linux__
@ -104,20 +82,20 @@ BOOL FASTCALL CTapDriver::Init()
// TAP Device Initialization
if ((m_hTAP = open("/dev/tap", O_RDWR)) < 0) {
LOGERROR("Error: can't open tap. Errno: %d %s", errno, strerror(errno));
printf("Error: can't open tap\n");
return FALSE;
}
// Get device name
if (ioctl(m_hTAP, TAPGIFNAME, (void *)&ifr) < 0) {
LOGERROR("Error: can't ioctl TAPGIFNAME. Errno: %d %s", errno, strerror(errno));
printf("Error: can't ioctl TAPGIFNAME\n");
close(m_hTAP);
return FALSE;
}
// Get MAC address
if (getifaddrs(&ifa) == -1) {
LOGERROR("Error: can't getifaddrs. Errno: %d %s", errno, strerror(errno));
printf("Error: can't getifaddrs\n");
close(m_hTAP);
return FALSE;
}
@ -126,7 +104,7 @@ BOOL FASTCALL CTapDriver::Init()
a->ifa_addr->sa_family == AF_LINK)
break;
if (a == NULL) {
LOGERROR("Error: can't get MAC addressErrno: %d %s", errno, strerror(errno));
printf("Error: can't get MAC address\n");
close(m_hTAP);
return FALSE;
}
@ -136,7 +114,7 @@ BOOL FASTCALL CTapDriver::Init()
sizeof(m_MacAddr));
freeifaddrs(ifa);
LOGINFO("Tap device : %s\n", ifr.ifr_name);
printf("Tap device : %s\n", ifr.ifr_name);
return TRUE;
}
@ -150,59 +128,14 @@ BOOL FASTCALL CTapDriver::Init()
void FASTCALL CTapDriver::Cleanup()
{
ASSERT(this);
int result;
LOGDEBUG("brctl delif rascsi_bridge ras0");
result = run_system_cmd("brctl delif rascsi_bridge ras0");
if(result != EXIT_SUCCESS){
LOGWARN("Warning: The brctl delif command failed.");
LOGWARN("You may need to manually remove the ras0 tap device from the bridge");
}
// Release TAP defice
// TAPデバイス解放
if (m_hTAP != -1) {
close(m_hTAP);
m_hTAP = -1;
}
}
//---------------------------------------------------------------------------
//
// Enable
//
//---------------------------------------------------------------------------
BOOL FASTCALL CTapDriver::Enable(){
int result;
LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__);
result = run_system_cmd("ip link set ras0 up");
return (result == EXIT_SUCCESS);
}
//---------------------------------------------------------------------------
//
// Disable
//
//---------------------------------------------------------------------------
BOOL FASTCALL CTapDriver::Disable(){
int result;
LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__);
result = run_system_cmd("ip link set ras0 down");
return (result == EXIT_SUCCESS);
}
//---------------------------------------------------------------------------
//
// Flush
//
//---------------------------------------------------------------------------
BOOL FASTCALL CTapDriver::Flush(){
LOGTRACE("%s", __PRETTY_FUNCTION__);
while(PendingPackets()){
(void)Rx(m_garbage_buffer);
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// MGet MAC Address
@ -221,9 +154,10 @@ void FASTCALL CTapDriver::GetMacAddr(BYTE *mac)
// Receive
//
//---------------------------------------------------------------------------
BOOL FASTCALL CTapDriver::PendingPackets()
int FASTCALL CTapDriver::Rx(BYTE *buf)
{
struct pollfd fds;
DWORD dwReceived;
ASSERT(this);
ASSERT(m_hTAP != -1);
@ -233,29 +167,7 @@ BOOL FASTCALL CTapDriver::PendingPackets()
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;
}
@ -267,23 +179,14 @@ int FASTCALL CTapDriver::Rx(BYTE *buf)
// If reception is enabled
if (dwReceived > 0) {
// 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.
// Pad to the maximum frame size (60 bytes) excluding FCS
if (dwReceived < 60) {
memset(buf + dwReceived, 0, 60 - dwReceived);
dwReceived = 60;
}
// 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
// Add a dummy FCS
memset(buf + dwReceived, 0, 4);
dwReceived += 4;
}
@ -296,7 +199,7 @@ int FASTCALL CTapDriver::Rx(BYTE *buf)
// Send
//
//---------------------------------------------------------------------------
int FASTCALL CTapDriver::Tx(const BYTE *buf, int len)
int FASTCALL CTapDriver::Tx(BYTE *buf, int len)
{
ASSERT(this);
ASSERT(m_hTAP != -1);

View File

@ -5,7 +5,6 @@
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) akuker
//
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
//
@ -39,16 +38,8 @@ public:
// Get Mac Address
int FASTCALL Rx(BYTE *buf);
// Receive
int FASTCALL Tx(const BYTE *buf, int len);
int FASTCALL Tx(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];
@ -57,7 +48,6 @@ private:
// Send Valid Flag
int m_hTAP;
// File handle
BYTE m_garbage_buffer[ETH_FRAME_LEN];
};
#endif // ctapdriver_h

View File

@ -357,7 +357,6 @@ 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;
@ -975,47 +974,6 @@ BOOL FASTCALL Disk::IsNULL() const
return FALSE;
}
//---------------------------------------------------------------------------
//
// Retrieve the disk's ID
//
//---------------------------------------------------------------------------
DWORD FASTCALL Disk::GetID() const
{
return disk.id;
}
//---------------------------------------------------------------------------
//
// Get cache writeback mode
//
//---------------------------------------------------------------------------
BOOL FASTCALL Disk::IsCacheWB()
{
return cache_wb;
}
//---------------------------------------------------------------------------
//
// Set cache writeback mode
//
//---------------------------------------------------------------------------
void FASTCALL Disk::SetCacheWB(BOOL enable)
{
cache_wb = enable;
}
//---------------------------------------------------------------------------
//
// Set unsupported command
//
//---------------------------------------------------------------------------
void FASTCALL Disk::InvalidCmd()
{
disk.code = DISK_INVALIDCMD;
}
//---------------------------------------------------------------------------
//
// SASI Check
@ -1204,7 +1162,6 @@ BOOL FASTCALL Disk::CheckReady()
if (disk.reset) {
disk.code = DISK_DEVRESET;
disk.reset = FALSE;
LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__);
return FALSE;
}
@ -1212,21 +1169,17 @@ 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;
}
@ -1269,7 +1222,6 @@ 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
@ -2014,7 +1966,7 @@ BOOL FASTCALL Disk::Reassign(const DWORD* /*cdb*/)
// READ
//
//---------------------------------------------------------------------------
int FASTCALL Disk::Read(const DWORD *cdb, BYTE *buf, DWORD block)
int FASTCALL Disk::Read(BYTE *buf, DWORD block)
{
ASSERT(this);
ASSERT(buf);
@ -2074,12 +2026,11 @@ int FASTCALL Disk::WriteCheck(DWORD block)
// WRITE
//
//---------------------------------------------------------------------------
BOOL FASTCALL Disk::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
BOOL FASTCALL Disk::Write(const BYTE *buf, DWORD block)
{
ASSERT(this);
ASSERT(buf);
LOGTRACE("%s", __PRETTY_FUNCTION__);
// Error if not ready
if (!disk.ready) {
disk.code = DISK_NOTREADY;

View File

@ -233,7 +233,7 @@ public:
#endif // RASCSI
// ID
DWORD FASTCALL GetID() const;
DWORD FASTCALL GetID() const { return disk.id; }
// 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(const DWORD *cdb, BYTE *buf, DWORD block);
virtual int FASTCALL Read(BYTE *buf, DWORD block);
// READ command
virtual int FASTCALL WriteCheck(DWORD block);
int FASTCALL WriteCheck(DWORD block);
// WRITE check
virtual BOOL FASTCALL Write(const DWORD *cdb, const BYTE *buf, DWORD block);
BOOL FASTCALL Write(const BYTE *buf, DWORD block);
// WRITE command
BOOL FASTCALL Seek(const DWORD *cdb);
// SEEK command
@ -328,13 +328,13 @@ public:
// PLAY AUDIO MSF command
virtual BOOL FASTCALL PlayAudioTrack(const DWORD *cdb);
// PLAY AUDIO TRACK command
void FASTCALL InvalidCmd();
void FASTCALL InvalidCmd() { disk.code = DISK_INVALIDCMD; }
// Unsupported command
// Other
BOOL FASTCALL IsCacheWB();
BOOL IsCacheWB() { return cache_wb; }
// Get cache writeback mode
void FASTCALL SetCacheWB(BOOL enable);
void SetCacheWB(BOOL enable) { cache_wb = enable; }
// Set cache writeback mode
protected:

View File

@ -1,540 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2020 akuker
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ Emulation of the DaynaPort SCSI Link Ethernet interface ]
//
// This design is derived from the SLINKCMD.TXT file, as well as David Kuder's
// Tiny SCSI Emulator
// - SLINKCMD: http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/SLINKCMD.TXT
// - Tiny SCSI : https://hackaday.io/project/18974-tiny-scsi-emulator
//
// Additional documentation and clarification is available at the
// following link:
// - https://github.com/akuker/RASCSI/wiki/Dayna-Port-SCSI-Link
//
// This does NOT include the file system functionality that is present
// in the Sharp X68000 host bridge.
//
// Note: This requires the DaynaPort SCSI Link driver.
//---------------------------------------------------------------------------
#include "scsi_daynaport.h"
//===========================================================================
//
// DaynaPort SCSI Link Ethernet Adapter
//
//===========================================================================
const char* SCSIDaynaPort::m_vendor_name = "DAYNA ";
const char* SCSIDaynaPort::m_device_name = "SCSI/Link ";
const char* SCSIDaynaPort::m_revision = "1.4a";
const char* SCSIDaynaPort::m_firmware_version = "01.00.00";
const BYTE SCSIDaynaPort::m_bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff };
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIDaynaPort::SCSIDaynaPort() : Disk()
{
LOGTRACE("SCSI DaynaPort Constructor");
// DaynaPort
disk.id = MAKEID('S', 'C', 'D', 'P');
#if defined(__linux__) && !defined(BAREMETAL)
// TAP Driver Generation
m_tap = new CTapDriver();
m_bTapEnable = m_tap->Init();
if(!m_bTapEnable){
LOGERROR("Unable to open the TAP interface");
}else {
LOGDEBUG("Tap interface created");
}
LOGTRACE("%s this->reset()", __PRETTY_FUNCTION__);
this->Reset();
disk.ready = true;
disk.reset = false;
// Generate MAC Address
LOGTRACE("%s memset(m_mac_addr, 0x00, 6);", __PRETTY_FUNCTION__);
memset(m_mac_addr, 0x00, 6);
// if (m_bTapEnable) {
// tap->GetMacAddr(m_mac_addr);
// m_mac_addr[5]++;
// }
// !!!!!!!!!!!!!!!!! For now, hard code the MAC address. Its annoying when it keeps changing during development!
// TODO: Remove this hard-coded address
LOGTRACE("%s m_mac_addr[0]=0x00;", __PRETTY_FUNCTION__);
m_mac_addr[0]=0x00;
m_mac_addr[1]=0x80;
m_mac_addr[2]=0x19;
m_mac_addr[3]=0x10;
m_mac_addr[4]=0x98;
m_mac_addr[5]=0xE3;
#endif // RASCSI && !BAREMETAL
LOGTRACE("SCSIDaynaPort Constructor End");
}
//---------------------------------------------------------------------------
//
// Destructor
//
//---------------------------------------------------------------------------
SCSIDaynaPort::~SCSIDaynaPort()
{
LOGTRACE("SCSIDaynaPort Destructor");
// TAP driver release
if (m_tap) {
m_tap->Cleanup();
delete m_tap;
}
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIDaynaPort::Inquiry(
const DWORD *cdb, BYTE *buffer, DWORD major, DWORD minor)
{
DWORD allocation_length;
// scsi_cdb_6_byte_t command;
// memcpy(&command,cdb,sizeof(command));
ASSERT(this);
ASSERT(cdb);
ASSERT(buffer);
ASSERT(cdb[0] == 0x12);
//allocation_length = command->length;
allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8);
// if(allocation_length != command.length){
// LOGDEBUG("%s CDB: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, (unsigned int)cdb[0], (unsigned int)cdb[1], (unsigned int)cdb[2], (unsigned int)cdb[3], (unsigned int)cdb[4], (unsigned int)cdb[5] );
// LOGWARN(":::::::::: Expected allocation length %04X but found %04X", (unsigned int)allocation_length, (unsigned int)command.length);
// LOGWARN(":::::::::: Doing runtime pointer conversion: %04X", ((scsi_cdb_6_byte_t*)cdb)->length);
// }
LOGTRACE("%s Inquiry with major %ld, minor %ld. Allocaiton length: %d",__PRETTY_FUNCTION__, major, minor, (int)allocation_length);
if(cdb[1] & 0x3) {
LOGWARN("Tiny SCSI Emulator says this is an invalid request");
}
if(allocation_length > 4){
// Copy the pre-canned response
memcpy(buffer, m_target_ethernet_inquiry_response, allocation_length);
// Set the size
//buffer[4] = (BYTE)((allocation_length - 7) & 0xFF);
// The inquiry response format only allows for a 1 byte 'additional size' field
if(allocation_length > 0xFF){
LOGWARN("%s The inquiry format only allows for a maximum of %d (0xFF + 4) bytes",\
__PRETTY_FUNCTION__, (int)0xFF + 4)
}
}
LOGTRACE("response size is %d", (int)allocation_length);
// Success
disk.code = DISK_NOERROR;
return allocation_length;
}
//---------------------------------------------------------------------------
//
// RequestSense
//
//---------------------------------------------------------------------------
int FASTCALL SCSIDaynaPort::RequestSense(const DWORD *cdb, BYTE *buffer)
{
// The DaynaPort RequestSense response will always be 9 bytes.
int size = 9;
LOGTRACE("%s size of sense data = %d", __PRETTY_FUNCTION__, size);
// Clear the buffer
memset(buffer, 0, size);
// Only set the response code (70h)
buffer[0] = 0x70;
// Clear the code
disk.code = 0x00;
return size;
}
//---------------------------------------------------------------------------
//
// READ
//
//---------------------------------------------------------------------------
int FASTCALL SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, DWORD block)
{
WORD requested_length = 0;
int rx_packet_size = 0;
BOOL send_message_to_host;
scsi_resp_read_t *response = (scsi_resp_read_t*)buf;
scsi_cmd_read_6_t *command = (scsi_cmd_read_6_t*)cdb;
int read_count = 0;
ASSERT(this);
ASSERT(buf);
LOGTRACE("%s reading DaynaPort block %lu", __PRETTY_FUNCTION__, block);
if(command->operation_code != 0x08){
LOGERROR("Received unexpected cdb command: %02X. Expected 0x08", (unsigned int)command->operation_code);
}
requested_length = (WORD)command->transfer_length;
LOGTRACE("%s Read maximum length %d, (%04X)", __PRETTY_FUNCTION__, (unsigned int)requested_length, (unsigned int)requested_length);
// At host startup, it will send a READ(6) command with a length of 1. We should
// respond by going into the status mode with a code of 0x02
if(requested_length == 1){
return 0;
}
// Some of the packets we receive will not be for us. So, we'll keep pulling messages
// until the buffer is empty, or we've read X times. (X is just a made up number)
while(read_count < 50)
{
read_count++;
// The first 2 bytes are reserved for the length of the packet
// The next 4 bytes are reserved for a flag field
//rx_packet_size = m_tap->Rx(response->data);
rx_packet_size = m_tap->Rx(&buf[m_read_header_size]);
// If we didn't receive anything, return size of 0
if(rx_packet_size <= 0){
LOGTRACE("%s No packet received", __PRETTY_FUNCTION__);
response->length = 0;
response->flags = e_no_more_data;
return m_read_header_size;
}
LOGTRACE("%s Packet Sz %d (%08X) read: %d", __PRETTY_FUNCTION__, (unsigned int) rx_packet_size, (unsigned int) rx_packet_size, read_count);
// This is a very basic filter to prevent unnecessary packets from
// being sent to the SCSI initiator.
send_message_to_host = FALSE;
// Check if received packet destination MAC address matches the
// DaynaPort MAC. For IP packets, the mac_address will be the first 6 bytes
// of the data.
if (memcmp(response->data, m_mac_addr, 6) == 0) {
send_message_to_host = TRUE;
}
// Check to see if this is a broadcast message
if (memcmp(response->data, m_bcast_addr, 6) == 0) {
send_message_to_host = TRUE;
}
// Check to see if this is an AppleTalk Message
if (memcmp(response->data, m_apple_talk_addr, 6) == 0) {
send_message_to_host = TRUE;
}
// TODO: We should check to see if this message is in the multicast
// configuration from SCSI command 0x0D
if(!send_message_to_host){
LOGDEBUG("%s Received a packet that's not for me: %02X %02X %02X %02X %02X %02X", \
__PRETTY_FUNCTION__,
(int)response->data[0],
(int)response->data[1],
(int)response->data[2],
(int)response->data[3],
(int)response->data[4],
(int)response->data[5]);
// If there are pending packets to be processed, we'll tell the host that the read
// length was 0.
if(!m_tap->PendingPackets())
{
response->length = 0;
response->flags = e_no_more_data;
return m_read_header_size;
}
}
else
{
// TODO: Need to do some sort of size checking. The buffer can easily overflow, probably.
// response->length = rx_packet_size;
// if(m_tap->PendingPackets()){
// response->flags = e_more_data_available;
// } else {
// response->flags = e_no_more_data;
// }
buf[0] = (BYTE)((rx_packet_size >> 8) & 0xFF);
buf[1] = (BYTE)(rx_packet_size & 0xFF);
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
if(m_tap->PendingPackets()){
buf[5] = 0x10;
} else {
buf[5] = 0;
}
// Return the packet size + 2 for the length + 4 for the flag field
// The CRC was already appended by the ctapdriver
return rx_packet_size + m_read_header_size;
}
// If we got to this point, there are still messages in the queue, so
// we should loop back and get the next one.
} // end while
response->length = 0;
response->flags = e_no_more_data;
return m_read_header_size;
}
//---------------------------------------------------------------------------
//
// WRITE check
//
//---------------------------------------------------------------------------
int FASTCALL SCSIDaynaPort::WriteCheck(DWORD block)
{
LOGTRACE("%s block: %lu", __PRETTY_FUNCTION__, block);
// Status check
if (!CheckReady()) {
return 0;
}
if(!m_bTapEnable){
disk.code = DISK_NOTREADY;
return 0;
}
// Success
return 1;
}
//---------------------------------------------------------------------------
//
// Write
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIDaynaPort::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
{
BYTE data_format;
WORD data_length;
// const scsi_cmd_daynaport_write_t* command = (const scsi_cmd_daynaport_write_t*)cdb;
data_format = cdb[5];
data_length = (WORD)cdb[4] + ((WORD)cdb[3] << 8);
// if(data_format != command->format){
// LOGDEBUG("%s CDB: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, (unsigned int)cdb[0], (unsigned int)cdb[1], (unsigned int)cdb[2], (unsigned int)cdb[3], (unsigned int)cdb[4], (unsigned int)cdb[5] );
// LOGWARN("Expected data_format: %02X, but found %02X", (unsigned int)cdb[5], (unsigned int)command->format);
// }
// if(data_length != command->length){
// LOGDEBUG("%s CDB: %02X %02X %02X %02X %02X %02X", __PRETTY_FUNCTION__, (unsigned int)cdb[0], (unsigned int)cdb[1], (unsigned int)cdb[2], (unsigned int)cdb[3], (unsigned int)cdb[4], (unsigned int)cdb[5] );
// LOGWARN("Expected data_length: %04X, but found %04X", data_length, (unsigned int)command->length);
// }
if(data_format == 0x00){
m_tap->Tx(buf, data_length);
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length);
return TRUE;
}
else if (data_format == 0x80){
// The data length is actuall specified in the first 2 bytes of the payload
data_length=(WORD)buf[1] + ((WORD)buf[0] << 8);
m_tap->Tx(&buf[4], data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length);
return TRUE;
}
else
{
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format);
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format);
return FALSE;
}
}
//---------------------------------------------------------------------------
//
// RetrieveStats
//
//---------------------------------------------------------------------------
int FASTCALL SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer)
{
DWORD response_size;
DWORD allocation_length;
// DWORD frame_alignment_errors;
// DWORD crc_errors;
// DWORD frames_lost;
LOGTRACE("%s RetrieveStats ", __PRETTY_FUNCTION__);
ASSERT(this);
ASSERT(cdb);
ASSERT(buffer);
allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8);
LOGTRACE("%s Retrieve Stats buffer size was %d", __PRETTY_FUNCTION__, (int)allocation_length);
// // ASSERT(cdb[0] == 0x09);
// if(cdb[0] != 0x09)
// {
// LOGWARN("%s cdb[0] was not 0x09, as I expected. It was %02X.", __PRETTY_FUNCTION__, (unsigned int)cdb[0]);
// }
// if(cdb[4] != 0x12)
// {
// LOGWARN("%s cdb[4] was not 0x12, as I expected. It was %02X.", __PRETTY_FUNCTION__, (unsigned int)cdb[4]);
// }
// memset(buffer,0,18);
// memcpy(&buffer[0],m_mac_addr,sizeof(m_mac_addr));
// // frame alignment errors
// frame_alignment_errors = htonl(0);
// memcpy(&(buffer[6]),&frame_alignment_errors,sizeof(frame_alignment_errors));
// // CRC errors
// crc_errors = htonl(0);
// memcpy(&(buffer[10]),&crc_errors,sizeof(crc_errors));
// // frames lost
// frames_lost = htonl(0);
// memcpy(&(buffer[14]),&frames_lost,sizeof(frames_lost));
for(int i=0; i< 6; i++)
{
LOGTRACE("%s CDB byte %d: %02X",__PRETTY_FUNCTION__, i, (unsigned int)cdb[i]);
}
response_size = 18;
response_size = sizeof(m_scsi_link_stats);
memcpy(buffer, &m_scsi_link_stats, sizeof(m_scsi_link_stats));
LOGTRACE("%s response size is %d", __PRETTY_FUNCTION__, (int)response_size);
if(response_size > allocation_length)
{
response_size = allocation_length;
LOGINFO("%s Truncating the inquiry response", __PRETTY_FUNCTION__)
}
// Success
disk.code = DISK_NOERROR;
return response_size;
// scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb;
// scsi_resp_link_stats_t *response = (scsi_resp_link_stats_t*) buffer;
// LOGTRACE("%s Retrieve Stats buffer size was %d", __PRETTY_FUNCTION__, command->length);
// ASSERT(sizeof(scsi_resp_link_stats_t) == 18);
// memcpy(response->mac_address, m_mac_addr, sizeof(m_mac_addr));
// response->crc_errors = 0;
// response->frames_lost = 0;
// response->frame_alignment_errors = 0;
// // Success
// disk.code = DISK_NOERROR;
// return sizeof(scsi_resp_link_stats_t);
}
//---------------------------------------------------------------------------
//
// Enable or Disable the interface
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIDaynaPort::EnableInterface(const DWORD *cdb)
{
int result;
// scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb;
// if(command->control & 0x80)
if(cdb[5] & 0x80)
{
result = m_tap->Enable();
if(result){
LOGINFO("The DaynaPort interface has been ENABLED.");
}
else{
LOGWARN("Unable to enable the DaynaPort Interface");
}
m_tap->Flush();
}
else
{
result = m_tap->Disable();
if(result){
LOGINFO("The DaynaPort interface has been DISABLED.");
}
else{
LOGWARN("Unable to disable the DaynaPort Interface");
}
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// TEST UNIT READY
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/)
{
ASSERT(this);
LOGTRACE("%s", __PRETTY_FUNCTION__);
// TEST UNIT READY Success
disk.code = DISK_NOERROR;
return TRUE;
}
//---------------------------------------------------------------------------
//
// Set Mode - enable broadcast messages
//
//---------------------------------------------------------------------------
void FASTCALL SCSIDaynaPort::SetMode(const DWORD *cdb, BYTE *buffer)
{
LOGTRACE("%s Setting mode", __PRETTY_FUNCTION__);
for(size_t i=0; i<sizeof(6); i++)
{
LOGTRACE("%s %d: %02X",__PRETTY_FUNCTION__, i,(WORD)cdb[i]);
}
}

View File

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

View File

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

View File

@ -122,7 +122,7 @@ private:
// Wave path
BOOL valid;
// Open result (is it valid?)
DWORD *m_buf;
DWORD *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(const DWORD *cdb, BYTE *buf, DWORD block) override;
int FASTCALL Read(BYTE *buf, DWORD block);
// READ command
int FASTCALL ReadToc(const DWORD *cdb, BYTE *buf);
// READ TOC command

View File

@ -100,7 +100,7 @@ BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD:: Inquiry(
int FASTCALL SCSIHD::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
char vendor[32];
@ -241,7 +241,7 @@ BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
case 0x08:
// Debug code for Issue #2:
// https://github.com/akuker/RASCSI/issues/2
LOGWARN("[Unhandled page code] Received mode page code 8 with total length %d\n ", length);
printf("[Unhandled page code] Received mode page code 8 with total length %d\n ", length);
for (int i = 0; i<length; i++)
{
printf("%02X ", buf[i]);

View File

@ -433,30 +433,6 @@
//
//---------------------------------------------------------------------------
#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
//---------------------------------------------------------------------------
//
@ -568,7 +544,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

View File

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

View File

@ -16,26 +16,40 @@
#include "spdlog/spdlog.h"
#include "spdlog/sinks/sink.h"
#define SPDLOGWRAPPER(loglevel, ...) \
do \
{ \
char logbuf[_MAX_FNAME*2]; \
snprintf(logbuf, sizeof(logbuf), __VA_ARGS__); \
spdlog::log(loglevel, logbuf); \
} while (0);
#define SPDLOGWRAPPER(loglevel, ...)\
do{ char buf[256]; \
snprintf(buf, sizeof(buf),__VA_ARGS__); \
spdlog::log(loglevel,buf);}while(0);
#ifdef NDEBUG
#ifndef DEBUG
// 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__)
#endif // log_h
//===========================================================================
//
// ログ
//
//===========================================================================
class Log
{
public:
enum loglevel {
Detail, // 詳細レベル
Normal, // 通常レベル
Warning, // 警告レベル
Debug // デバッグレベル
};
};
#endif // log_h

View File

@ -1,35 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020-2021 akuker
//
// [ OS related definitions ]
//
//---------------------------------------------------------------------------
#include "os.h"
#include <sys/wait.h>
//---------------------------------------------------------------------------
//
// Run system command and wait for it to finish
//
//---------------------------------------------------------------------------
int run_system_cmd(const char* command)
{
pid_t pid;
int result;
int status = 0;
pid=fork();
if(pid == 0){
result = system(command);
exit(result);
}
waitpid(pid, &status, 0);
return status;
}

View File

@ -5,11 +5,10 @@
//
// 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 related definitions ]
// [ OS固有 ]
//
//---------------------------------------------------------------------------
@ -87,7 +86,7 @@
//---------------------------------------------------------------------------
//
// Basic Macros
// 基本マクロ
//
//---------------------------------------------------------------------------
#undef FASTCALL
@ -119,7 +118,7 @@
//---------------------------------------------------------------------------
//
// Basic Type Definitions
// 基本型定義
//
//---------------------------------------------------------------------------
typedef unsigned char BYTE;
@ -155,7 +154,4 @@ typedef const char *LPCSTR;
#define xstrcasecmp strcasecmp
#define xstrncasecmp strncasecmp
// Run system command and wait for it to finish
extern int run_system_cmd(const char* command);
#endif // os_h

View File

@ -9,7 +9,7 @@ ExecStart=/usr/local/bin/rascsi
# Example: If you want to automatically attach a hard disk at startup, change
# the ExecStart line to:
# ExecStart=/usr/local/bin/rascsi -ID1 /home/pi/images/harddisk.hda
# This functionality isn't implmented yet: ExecStop=/usr/local/bin/rasctl -stop
ExecStop=/usr/local/bin/rasctl -stop
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=RASCSI

View File

@ -21,15 +21,11 @@
#include "devices/scsicd.h"
#include "devices/scsimo.h"
#include "devices/scsi_host_bridge.h"
#include "devices/scsi_daynaport.h"
#include "controllers/scsidev_ctrl.h"
#include "controllers/sasidev_ctrl.h"
#include "gpiobus.h"
#include "rascsi_version.h"
#include "rasctl.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include <spdlog/async.h>
//---------------------------------------------------------------------------
//
@ -99,7 +95,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, \"daynaport\", or \"bridge\".\n\n");
FPRT(stdout," FILE is disk image file.\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");
@ -266,12 +262,10 @@ void ListDevice(FILE *fp)
Filepath filepath;
BOOL find;
char type[5];
char dev_status[_MAX_FNAME+26];
find = FALSE;
type[4] = 0;
for (i = 0; i < CtrlMax * UnitNum; i++) {
strncpy(dev_status,"",sizeof(dev_status));
// Initialize ID and unit number
id = i / UnitNum;
un = i % UnitNum;
@ -286,9 +280,7 @@ void ListDevice(FILE *fp)
if (!find) {
FPRT(fp, "\n");
FPRT(fp, "+----+----+------+-------------------------------------\n");
LOGINFO( "+----+----+------+-------------------------------------");
FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n");
LOGINFO( "| ID | UN | TYPE | DEVICE STATUS\n");
FPRT(fp, "+----+----+------+-------------------------------------\n");
find = TRUE;
}
@ -298,26 +290,25 @@ void ListDevice(FILE *fp)
type[1] = (char)(pUnit->GetID() >> 16);
type[2] = (char)(pUnit->GetID() >> 8);
type[3] = (char)(pUnit->GetID());
FPRT(fp, "| %d | %d | %s | ", id, un, type);
// mount status output
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
strncpy(dev_status,"X68000 HOST BRIDGE",sizeof(dev_status));
} else if (pUnit->GetID() == MAKEID('S', 'C', 'D', 'P')) {
strncpy(dev_status,"DaynaPort SCSI/Link",sizeof(dev_status));
FPRT(fp, "%s", "HOST BRIDGE");
} else {
pUnit->GetPath(filepath);
snprintf(dev_status, sizeof(dev_status), "%s",
FPRT(fp, "%s",
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
"NO MEDIA" : filepath.GetPath());
}
// Write protection status
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
strcat(dev_status, "(WRITEPROTECT)");
FPRT(fp, "(WRITEPROTECT)");
}
FPRT(fp, "| %d | %d | %s | %s\n", id, un, type, dev_status);
LOGINFO( "| %d | %d | %s | %s", id, un, type, dev_status);
// Goto the next line
FPRT(fp, "\n");
}
// If there is no controller, find will be null
@ -327,7 +318,6 @@ void ListDevice(FILE *fp)
}
FPRT(fp, "+----+----+------+-------------------------------------\n");
LOGINFO( "+----+----+------+-------------------------------------");
}
//---------------------------------------------------------------------------
@ -457,7 +447,6 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
char *ext;
Filepath filepath;
Disk *pUnit;
char type_str[5];
// Copy the Unit List
memcpy(map, disk, sizeof(disk));
@ -479,7 +468,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 == rasctl_dev_sasi_hd) {
if (type == 0) {
// Passed the check
if (!file) {
return FALSE;
@ -499,16 +488,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 = rasctl_dev_scsi_hd;
type = 1;
}
}
// Create a new drive, based upon type
switch (type) {
case rasctl_dev_sasi_hd: // HDF
case 0: // HDF
pUnit = new SASIHD();
break;
case rasctl_dev_scsi_hd: // HDS/HDN/HDI/NHD/HDA
case 1: // HDS/HDN/HDI/NHD/HDA
if (ext == NULL) {
break;
}
@ -521,37 +510,28 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
pUnit = new SCSIHD();
}
break;
case rasctl_dev_mo: // MO
case 2: // MO
pUnit = new SCSIMO();
break;
case rasctl_dev_cd: // CD
case 3: // CD
pUnit = new SCSICD();
break;
case rasctl_dev_br: // BRIDGE
case 4: // BRIDGE
pUnit = new SCSIBR();
break;
// case rasctl_dev_nuvolink: // Nuvolink
// pUnit = new SCSINuvolink();
// break;
case rasctl_dev_daynaport: // DaynaPort SCSI Link
pUnit = new SCSIDaynaPort();
LOGTRACE("Done creating SCSIDayanPort");
break;
default:
FPRT(fp, "Error : Invalid device type\n");
LOGWARN("rasctl sent a command for an invalid drive type: %d", type);
return FALSE;
}
// drive checks files
if (type <= rasctl_dev_scsi_hd || (type <= rasctl_dev_cd && xstrcasecmp(file, "-") != 0)) {
if (type <= 1 || (type <= 3 && xstrcasecmp(file, "-") != 0)) {
// Set the Path
filepath.SetPath(file);
// Open the file path
if (!pUnit->Open(filepath)) {
FPRT(fp, "Error : File open error [%s]\n", file);
LOGWARN("rasctl tried to open an invalid file %s", file);
delete pUnit;
return FALSE;
}
@ -565,26 +545,18 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
// Re-map the controller
MapControler(fp, map);
type_str[0] = (char)(pUnit->GetID() >> 24);
type_str[1] = (char)(pUnit->GetID() >> 16);
type_str[2] = (char)(pUnit->GetID() >> 8);
type_str[3] = (char)(pUnit->GetID());
type_str[4] = '\0';
LOGINFO("rasctl added new %s device. ID: %d UN: %d", type_str, id, un);
return TRUE;
}
// Is this a valid command?
if (cmd > 4) {
FPRT(fp, "Error : Invalid command\n");
LOGINFO("rasctl sent an invalid command: %d",cmd);
return FALSE;
}
// Does the controller exist?
if (ctrl[id] == NULL) {
FPRT(fp, "Error : No such device\n");
LOGWARN("rasctl sent a command for invalid controller %d", id);
return FALSE;
}
@ -592,24 +564,11 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
pUnit = disk[id * UnitNum + un];
if (pUnit == NULL) {
FPRT(fp, "Error : No such device\n");
LOGWARN("rasctl sent a command for invalid unit ID %d UN %d", id, un);
return FALSE;
}
type_str[0] = (char)(map[id * UnitNum + un]->GetID() >> 24);
type_str[1] = (char)(map[id * UnitNum + un]->GetID() >> 16);
type_str[2] = (char)(map[id * UnitNum + un]->GetID() >> 8);
type_str[3] = (char)(map[id * UnitNum + un]->GetID());
type_str[4] = '\0';
// Disconnect Command
if (cmd == 1) { // DETACH
type_str[0] = (char)(map[id * UnitNum + un]->GetID() >> 24);
type_str[1] = (char)(map[id * UnitNum + un]->GetID() >> 16);
type_str[2] = (char)(map[id * UnitNum + un]->GetID() >> 8);
type_str[3] = (char)(map[id * UnitNum + un]->GetID());
type_str[4] = '\0';
LOGINFO("rasctl command disconnect %s at ID: %d UN: %d", type_str, id, un);
// Free the existing unit
map[id * UnitNum + un] = NULL;
@ -621,8 +580,7 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
// Valid only for MO or CD
if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O') &&
pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) {
FPRT(fp, "Error : Operation denied (Device type %s isn't removable)\n", type_str);
LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, type_str);
FPRT(fp, "Error : Operation denied(Deveice isn't removable)\n");
return FALSE;
}
@ -630,7 +588,6 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
case 2: // INSERT
// Set the file path
filepath.SetPath(file);
LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", file, type_str, id, un);
// Open the file
if (!pUnit->Open(filepath)) {
@ -640,21 +597,17 @@ BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
break;
case 3: // EJECT
LOGINFO("rasctl commands eject %s ID: %d UN: %d", type_str, id, un);
pUnit->Eject(TRUE);
break;
case 4: // PROTECT
if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) {
FPRT(fp, "Error : Operation denied(Deveice isn't MO)\n");
LOGWARN("rasctl sent an invalid PROTECT command for %s ID: %d UN: %d", type_str, id, un);
return FALSE;
}
LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), type_str, id, un);
pUnit->WriteP(!pUnit->IsWriteP());
break;
default:
LOGWARN("Received unknown command from rasctl: %d", cmd);
ASSERT(FALSE);
return FALSE;
}
@ -1111,9 +1064,6 @@ int main(int argc, char* argv[])
#endif // BAREMETAL
spdlog::set_level(spdlog::level::trace);
// Create a thread-safe stdout logger to process the log messages
auto logger = spdlog::stdout_color_mt("rascsi stdout logger");
LOGTRACE("Entering the function %s with %d arguments", __PRETTY_FUNCTION__, argc);
// Output the Banner
Banner(argc, argv);

View File

@ -11,7 +11,6 @@
#include "os.h"
#include "rascsi_version.h"
#include "rasctl.h"
//---------------------------------------------------------------------------
//
@ -96,7 +95,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|daynaport}\n");
fprintf(stderr, " TYPE := {hd|mo|cd|bridge}\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]);
@ -147,29 +146,19 @@ int main(int argc, char* argv[])
case 'S':
case 'h': // HD(SCSI)
case 'H':
// rascsi will figure out if this should be SASI or
// SCSI later in the process....
type = rasctl_dev_sasi_hd;
type = 0;
break;
case 'm': // MO
case 'M':
type = rasctl_dev_mo;
type = 2;
break;
case 'c': // CD
case 'C':
type = rasctl_dev_cd;
type = 3;
break;
case 'b': // BRIDGE
case 'B':
type = rasctl_dev_br;
break;
// case 'n': // Nuvolink
// case 'N':
// type = rasctl_dev_nuvolink;
// break;
case 'd': // DaynaPort
case 'D':
type = rasctl_dev_daynaport;
type = 4;
break;
}
break;
@ -193,13 +182,13 @@ int main(int argc, char* argv[])
// Check the ID number
if (id < 0 || id > 7) {
fprintf(stderr, "%s Error : Invalid ID %d \n", __PRETTY_FUNCTION__, id);
fprintf(stderr, "Error : Invalid ID\n");
exit(EINVAL);
}
// Check the unit number
if (un < 0 || un > 1) {
fprintf(stderr, "%s Error : Invalid UNIT %d \n", __PRETTY_FUNCTION__, un);
fprintf(stderr, "Error : Invalid UNIT\n");
exit(EINVAL);
}

View File

@ -1,24 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) akuker
//
// [ Send Control Command ]
//
//---------------------------------------------------------------------------
enum rasctl_dev_type : int {
rasctl_dev_invalid = -1,
rasctl_dev_sasi_hd = 0,
rasctl_dev_scsi_hd = 1,
rasctl_dev_mo = 2,
rasctl_dev_cd = 3,
rasctl_dev_br = 4,
rasctl_dev_nuvolink = 5,
rasctl_dev_daynaport = 6,
};

View File

@ -5,7 +5,7 @@
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// [ HDD dump utility (initiator mode) ]
// [ HDDダンプユーティリティ(イニシーエタモード) ]
//
//---------------------------------------------------------------------------
@ -18,46 +18,46 @@
//---------------------------------------------------------------------------
//
// Constant Declaration
// 定数宣言
//
//---------------------------------------------------------------------------
#define BUFSIZE 1024 * 64 // Buffer size of about 64KB
#define BUFSIZE 1024 * 64 // 64KBぐらいかなぁ
//---------------------------------------------------------------------------
//
// Variable Declaration
// 変数宣言
//
//---------------------------------------------------------------------------
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
GPIOBUS bus; // バス
int targetid; // ターゲットデバイスID
int boardid; // ボードID(自身のID)
Filepath hdsfile; // HDSファイル
BOOL restore; // リストアフラグ
BYTE buffer[BUFSIZE]; // ワークバッファ
int result; // 結果コード
//---------------------------------------------------------------------------
//
// 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 Initialization
// GPIO初期化
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 check
// TARGET IDチェック
if (targetid < 0 || targetid > 7) {
fprintf(stderr,
"Error : Invalid target id range\n");
return FALSE;
}
// BOARD ID check
// BOARD IDチェック
if (boardid < 0 || boardid > 7) {
fprintf(stderr,
"Error : Invalid board id range\n");
return FALSE;
}
// Target and Board ID duplication check
// TARGETとBOARDのID重複チェック
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;
// Timeout (3000ms)
// タイムアウト(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 setting and SEL assert
// ID設定とSELアサート
data = 0;
data |= (1 << boardid);
data |= (1 << id);
bus.SetDAT(data);
bus.SetSEL(TRUE);
// wait for busy
// BSYを待つ
count = 10000;
do {
usleep(20);
@ -260,128 +260,127 @@ BOOL Selection(int id)
}
} while (count--);
// SEL negate
// SELネゲート
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
@ -411,7 +410,7 @@ int TestUnitReady(int id)
}
exit:
// Bus free
// バスフリー
BusFree();
return result;
@ -419,7 +418,7 @@ exit:
//---------------------------------------------------------------------------
//
// REQUEST SENSE
// REQUEST SENSE実行
//
//---------------------------------------------------------------------------
int RequestSense(int id, BYTE *buf)
@ -427,7 +426,7 @@ int RequestSense(int id, BYTE *buf)
BYTE cmd[256];
int count;
// Result code initialization
// 結果コード初期化
result = 0;
count = 0;
@ -467,10 +466,10 @@ int RequestSense(int id, BYTE *buf)
}
exit:
// Bus Free
// バスフリー
BusFree();
// Returns the number of transfers if successful
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
@ -480,7 +479,7 @@ exit:
//---------------------------------------------------------------------------
//
// MODE SENSE
// MODE SENSE実行
//
//---------------------------------------------------------------------------
int ModeSense(int id, BYTE *buf)
@ -488,7 +487,7 @@ int ModeSense(int id, BYTE *buf)
BYTE cmd[256];
int count;
// Result code initialization
// 結果コード初期化
result = 0;
count = 0;
@ -529,10 +528,10 @@ int ModeSense(int id, BYTE *buf)
}
exit:
// Bus free
// バスフリー
BusFree();
// Returns the number of transfers if successful
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
@ -542,7 +541,7 @@ exit:
//---------------------------------------------------------------------------
//
// INQUIRY
// INQUIRY実行
//
//---------------------------------------------------------------------------
int Inquiry(int id, BYTE *buf)
@ -550,7 +549,7 @@ int Inquiry(int id, BYTE *buf)
BYTE cmd[256];
int count;
// Result code initialization
// 結果コード初期化
result = 0;
count = 0;
@ -590,10 +589,10 @@ int Inquiry(int id, BYTE *buf)
}
exit:
// Bus free
// バスフリー
BusFree();
// Returns the number of transfers if successful
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
@ -603,7 +602,7 @@ exit:
//---------------------------------------------------------------------------
//
// READ CAPACITY
// READ CAPACITY実行
//
//---------------------------------------------------------------------------
int ReadCapacity(int id, BYTE *buf)
@ -611,7 +610,7 @@ int ReadCapacity(int id, BYTE *buf)
BYTE cmd[256];
int count;
// Result code initialization
// 結果コード初期化
result = 0;
count = 0;
@ -650,10 +649,10 @@ int ReadCapacity(int id, BYTE *buf)
}
exit:
// Bus free
// バスフリー
BusFree();
// Returns the number of transfers if successful
// 成功であれば転送数を返す
if (result == 0) {
return count;
}
@ -663,7 +662,7 @@ exit:
//---------------------------------------------------------------------------
//
// READ10
// READ10実行
//
//---------------------------------------------------------------------------
int Read10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
@ -671,7 +670,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;
@ -715,10 +714,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;
}
@ -728,7 +727,7 @@ exit:
//---------------------------------------------------------------------------
//
// WRITE10
// WRITE10実行
//
//---------------------------------------------------------------------------
int Write10(int id, DWORD bstart, DWORD blength, DWORD length, BYTE *buf)
@ -736,7 +735,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;
@ -780,10 +779,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;
}
@ -793,7 +792,7 @@ exit:
//---------------------------------------------------------------------------
//
// Main process
// 主処理
//
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
@ -810,32 +809,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. Are you root?\n");
fprintf(stderr, "Error : Initializing\n");
// Probably not root
// 恐らく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 {
@ -844,20 +843,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();
// Assert reset signal
// RESETシグナル発行
bus.SetRST(TRUE);
usleep(1000);
bus.SetRST(FALSE);
// Start dump
// ダンプ開始
printf("TARGET ID : %d\n", targetid);
printf("BORAD ID : %d\n", boardid);
@ -882,7 +881,7 @@ int main(int argc, char* argv[])
goto cleanup_exit;
}
// Display INQUIRY information
// INQUIRYの情報を表示
memset(str, 0x00, sizeof(str));
memcpy(str, &buffer[8], 8);
printf("Vendor : %s\n", str);
@ -893,14 +892,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];
@ -914,7 +913,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);
@ -927,7 +926,7 @@ int main(int argc, char* argv[])
printf("\n");
}
// Dump by buffer size
// バッファサイズ毎にダンプする
duni = BUFSIZE;
duni /= bsiz;
dsiz = BUFSIZE;
@ -975,7 +974,7 @@ int main(int argc, char* argv[])
printf("\033[0K");
}
// Rounding on capacity
// 容量上の端数処理
dnum = bnum % duni;
dsiz = dnum * bsiz;
if (dnum > 0) {
@ -990,16 +989,16 @@ int main(int argc, char* argv[])
}
}
// Completion Message
// 完了メッセージ
printf("%3d%%(%7d/%7d)\n", 100, (int)bnum, (int)bnum);
cleanup_exit:
// File close
// ファイルクローズ
fio.Close();
// Cleanup
// クリーンアップ
Cleanup();
// end
// 終了
exit(0);
}

View File

@ -28,13 +28,13 @@ public:
};
// Phase definition
enum phase_t : BYTE {
enum phase_t {
busfree, // バスフリーフェーズ
arbitration, // アービトレーションフェーズ
selection, // セレクションフェーズ
reselection, // リセレクションフェーズ
command, // コマンドフェーズ
execute, // 実行フェーズ Execute is an extension of the command phase
execute, // 実行フェーズ
datain, // データイン
dataout, // データアウト
status, // ステータスフェーズ
@ -128,14 +128,6 @@ 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];
// フェーズテーブル
@ -143,84 +135,4 @@ private:
static const char* phase_str_table[];
};
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE misc_cdb_information;
BYTE page_code;
WORD length;
BYTE control;
} scsi_cdb_6_byte_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE service_action;
DWORD logical_block_address;
BYTE misc_cdb_information;
WORD length;
BYTE control;
} scsi_cdb_10_byte_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE service_action;
DWORD logical_block_address;
DWORD length;
BYTE misc_cdb_information;
BYTE control;
} scsi_cdb_12_byte_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE service_action;
DWORD logical_block_address;
DWORD length;
BYTE misc_cdb_information;
BYTE control;
} scsi_cdb_16_byte_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE reserved;
BYTE page_code;
WORD allocation_length;
BYTE control;
} scsi_cmd_inquiry_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE lba_msb_bits_4_0;
WORD logical_block_address;
BYTE transfer_length;
BYTE control;
} scsi_cmd_read_6_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE flags;
DWORD logical_block_address;
BYTE group_number;
WORD transfer_length;
BYTE control;
} scsi_cmd_read_10_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE flags;
DWORD logical_block_address;
DWORD transfer_length;
BYTE group_number;
BYTE control;
} scsi_cmd_read_12_t;
typedef struct __attribute__((packed)) {
BYTE operation_code;
BYTE descriptor_format;
WORD reserved;
BYTE allocation_length;
BYTE control;
} scsi_cmd_request_sense_t;
#endif // scsi_h

View File

@ -1,8 +0,0 @@
#!/bin/bash
set -e # Fail if any command fails
sudo brctl addbr rascsi_bridge
sudo brctl addif rascsi_bridge eth0
sudo ip link set dev rascsi_bridge up
echo Bridge config:
brctl show