diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index 71c0f07..a1df8e7 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -6,15 +6,17 @@ CXX = g++ DEBUG ?= 0 ifeq ($(DEBUG), 1) # Debug CFLAGS - CFLAGS = -DDISK_LOG -O0 -g -Wall -DDEBUG - CXXFLAGS = -DDISK_LOG -O0 -g -Wall -DDEBUG + CFLAGS += -DDISK_LOG -O0 -g -Wall -DDEBUG + CXXFLAGS += -DDISK_LOG -O0 -g -Wall -DDEBUG BUILD_TYPE = Debug else # Release CFLAGS - CFLAGS ?= -O3 -Wall -Werror - CXXFLAGS ?= -O3 -Wall -Werror + CFLAGS += -O3 -Wall -Werror + CXXFLAGS += -O3 -Wall -Werror BUILD_TYPE = Release endif +CFLAGS += -Idisks -Icontrollers -I. +CXXFLAGS += -Idisks -Icontrollers -I. # If its not specified, build for STANDARD configuration CONNECT_TYPE ?= STANDARD @@ -34,10 +36,13 @@ USR_LOCAL_BIN = /usr/local/bin MAN_PAGE_DIR = /usr/share/man/man1 DOC_DIR = ../../doc +OBJDIR := ./obj +BINDIR := ./bin + #BIN_ALL = $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP) $(SCSIMON) # Temporarily remove the RASDUMP and RASDUMP tools, since they're not needed # for my specific use case. If you need them - add them back in! -BIN_ALL = $(RASCSI) $(RASCTL) +BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL) SRC_RASCSI = \ @@ -49,6 +54,8 @@ SRC_RASCSI = \ cfilesystem.cpp \ filepath.cpp \ fileio.cpp +SRC_RASCSI += $(notdir $(shell find ./controllers -name '*.cpp')) +SRC_RASCSI += $(notdir $(shell find ./disks -name '*.cpp')) SRC_RASCTL = \ rasctl.cpp @@ -67,18 +74,33 @@ SRC_SASIDUMP = \ filepath.cpp \ fileio.cpp -OBJ_RASCSI := $(SRC_RASCSI:%.cpp=%.o) -OBJ_RASCTL := $(SRC_RASCTL:%.cpp=%.o) -OBJ_RASDUMP := $(SRC_RASDUMP:%.cpp=%.o) -OBJ_SASIDUMP := $(SRC_SASIDUMP:%.cpp=%.o) -OBJ_SCSIMON := $(SRC_SCSIMON:%.cpp=%.o) +vpath %.h ./ ./controllers ./disks +vpath %.cpp ./ ./controllers ./disks +vpath %.o ./$(OBJDIR) +vpath ./$(BINDIR) + + +OBJ_RASCSI := $(SRC_RASCSI:%.cpp=$(OBJDIR)/%.o) +OBJ_RASCTL := $(SRC_RASCTL:%.cpp=$(OBJDIR)/%.o) +OBJ_RASDUMP := $(SRC_RASDUMP:%.cpp=$(OBJDIR)/%.o) +OBJ_SASIDUMP := $(SRC_SASIDUMP:%.cpp=$(OBJDIR)/%.o) +OBJ_SCSIMON := $(SRC_SCSIMON:%.cpp=$(OBJDIR)/%.o) #OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP) $(OBJ_SCSIMON) OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP) -%.o: %.cpp +$(OBJDIR) $(BINDIR): + mkdir -p $@ + +$(OBJDIR)/%.o: %.cpp $(OBJDIR) + @echo "SRC_RASCSI: " $(SRC_RASCSI) + @echo "OBJ_RASCSI: " $(OBJ_RASCSI) $(CXX) $(CXXFLAGS) -c $< -o $@ +# $(OBJDIR)/%.o: %.c +# $(CXX) $(CXXFLAGS) -c $< -o $@ +# %.o: %.cpp +# $(CXX) $(CXXFLAGS) -c $(OBJDIR)/$< -o $@ .DEFAULT_GOAL := all .PHONY: all ALL docs @@ -87,23 +109,23 @@ ALL: all docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt -$(RASCSI): $(OBJ_RASCSI) +$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) $(BINDIR) $(CXX) -o $@ $(OBJ_RASCSI) -lpthread -$(RASCTL): $(OBJ_RASCTL) +$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) $(BINDIR) $(CXX) -o $@ $(OBJ_RASCTL) -$(RASDUMP): $(OBJ_RASDUMP) +$(RASDUMP): $(OBJ_RASDUMP) $(BINDIR) $(CXX) -o $@ $(OBJ_RASDUMP) -$(SASIDUMP): $(OBJ_SASIDUMP) +$(SASIDUMP): $(OBJ_SASIDUMP) $(BINDIR) $(CXX) -o $@ $(OBJ_SASIDUMP) -$(SCSIMON): $(OBJ_SCSIMON) +$(SCSIMON): $(OBJ_SCSIMON) $(BINDIR) $(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread clean: - rm -f $(OBJ_ALL) $(BIN_ALL) + rm -f $(OBJDIR) $(BINDIR) run: sudo ./$(RASCSI) -ID1 /home/pi/HARDDISK2.hda -ID6 /home/pi/marathon.iso diff --git a/src/raspberrypi/controllers/sasidev_ctrl.cpp b/src/raspberrypi/controllers/sasidev_ctrl.cpp new file mode 100644 index 0000000..3d5756f --- /dev/null +++ b/src/raspberrypi/controllers/sasidev_ctrl.cpp @@ -0,0 +1,1999 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SASI device controller ] +// +//--------------------------------------------------------------------------- +#include "sasidev_ctrl.h" +#include "filepath.h" +#include "gpiobus.h" +#include "scsi_host_bridge.h" + +//=========================================================================== +// +// SASI Device +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +#ifdef RASCSI +SASIDEV::SASIDEV() +#else +SASIDEV::SASIDEV(Device *dev) +#endif // RASCSI +{ + int i; + +#ifndef RASCSI + // Remember host device + host = dev; +#endif // RASCSI + + // Work initialization + ctrl.phase = BUS::busfree; + ctrl.id = -1; + ctrl.bus = NULL; + memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd)); + ctrl.status = 0x00; + ctrl.message = 0x00; +#ifdef RASCSI + ctrl.execstart = 0; +#endif // RASCSI + ctrl.bufsize = 0x800; + ctrl.buffer = (BYTE *)malloc(ctrl.bufsize); + memset(ctrl.buffer, 0x00, ctrl.bufsize); + ctrl.blocks = 0; + ctrl.next = 0; + ctrl.offset = 0; + ctrl.length = 0; + + // Logical unit initialization + for (i = 0; i < UnitMax; i++) { + ctrl.unit[i] = NULL; + } +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +SASIDEV::~SASIDEV() +{ + // Free the buffer + if (ctrl.buffer) { + free(ctrl.buffer); + ctrl.buffer = NULL; + } +} + +//--------------------------------------------------------------------------- +// +// Device reset +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Reset() +{ + int i; + + ASSERT(this); + + // Work initialization + memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd)); + ctrl.phase = BUS::busfree; + ctrl.status = 0x00; + ctrl.message = 0x00; +#ifdef RASCSI + ctrl.execstart = 0; +#endif // RASCSI + memset(ctrl.buffer, 0x00, ctrl.bufsize); + ctrl.blocks = 0; + ctrl.next = 0; + ctrl.offset = 0; + ctrl.length = 0; + + // Unit initialization + for (i = 0; i < UnitMax; i++) { + if (ctrl.unit[i]) { + ctrl.unit[i]->Reset(); + } + } +} + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Save +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SASIDEV::Save(Fileio *fio, int /*ver*/) +{ + DWORD sz; + + ASSERT(this); + ASSERT(fio); + + // Save size + sz = 2120; + if (!fio->Write(&sz, sizeof(sz))) { + return FALSE; + } + + // Save entity + PROP_EXPORT(fio, ctrl.phase); + PROP_EXPORT(fio, ctrl.id); + PROP_EXPORT(fio, ctrl.cmd); + PROP_EXPORT(fio, ctrl.status); + PROP_EXPORT(fio, ctrl.message); + if (!fio->Write(ctrl.buffer, 0x800)) { + return FALSE; + } + PROP_EXPORT(fio, ctrl.blocks); + PROP_EXPORT(fio, ctrl.next); + PROP_EXPORT(fio, ctrl.offset); + PROP_EXPORT(fio, ctrl.length); + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Load +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SASIDEV::Load(Fileio *fio, int ver) +{ + DWORD sz; + + ASSERT(this); + ASSERT(fio); + + // Not saved before version 3.11 + if (ver <= 0x0311) { + return TRUE; + } + + // Load size and check if the size matches + if (!fio->Read(&sz, sizeof(sz))) { + return FALSE; + } + if (sz != 2120) { + return FALSE; + } + + // Load the entity + PROP_IMPORT(fio, ctrl.phase); + PROP_IMPORT(fio, ctrl.id); + PROP_IMPORT(fio, ctrl.cmd); + PROP_IMPORT(fio, ctrl.status); + PROP_IMPORT(fio, ctrl.message); + if (!fio->Read(ctrl.buffer, 0x800)) { + return FALSE; + } + PROP_IMPORT(fio, ctrl.blocks); + PROP_IMPORT(fio, ctrl.next); + PROP_IMPORT(fio, ctrl.offset); + PROP_IMPORT(fio, ctrl.length); + + return TRUE; +} +#endif // RASCSI + +//--------------------------------------------------------------------------- +// +// Connect the controller +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Connect(int id, BUS *bus) +{ + ASSERT(this); + + ctrl.id = id; + ctrl.bus = bus; +} + +//--------------------------------------------------------------------------- +// +// Get the logical unit +// +//--------------------------------------------------------------------------- +Disk* FASTCALL SASIDEV::GetUnit(int no) +{ + ASSERT(this); + ASSERT(no < UnitMax); + + return ctrl.unit[no]; +} + +//--------------------------------------------------------------------------- +// +// Set the logical unit +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::SetUnit(int no, Disk *dev) +{ + ASSERT(this); + ASSERT(no < UnitMax); + + ctrl.unit[no] = dev; +} + +//--------------------------------------------------------------------------- +// +// Check to see if this has a valid logical unit +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SASIDEV::HasUnit() +{ + int i; + + ASSERT(this); + + for (i = 0; i < UnitMax; i++) { + if (ctrl.unit[i]) { + return TRUE; + } + } + + return FALSE; +} + +//--------------------------------------------------------------------------- +// +// Get internal data +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::GetCTRL(ctrl_t *buffer) +{ + ASSERT(this); + ASSERT(buffer); + + // reference the internal structure + *buffer = ctrl; +} + +//--------------------------------------------------------------------------- +// +// Get a busy unit +// +//--------------------------------------------------------------------------- +Disk* FASTCALL SASIDEV::GetBusyUnit() +{ + DWORD lun; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + return ctrl.unit[lun]; +} + +//--------------------------------------------------------------------------- +// +// Run +// +//--------------------------------------------------------------------------- +BUS::phase_t FASTCALL SASIDEV::Process() +{ + ASSERT(this); + + // Do nothing if not connected + if (ctrl.id < 0 || ctrl.bus == NULL) { + return ctrl.phase; + } + + // Get bus information + ctrl.bus->Aquire(); + + // For the monitor tool, we shouldn't need to reset. We're just logging information + // Reset + if (ctrl.bus->GetRST()) { +#if defined(DISK_LOG) + Log(Log::Normal, "RESET signal received"); +#endif // DISK_LOG + + // Reset the controller + Reset(); + + // Reset the bus + ctrl.bus->Reset(); + return ctrl.phase; + } + + // Phase processing + switch (ctrl.phase) { + // Bus free + case BUS::busfree: + BusFree(); + break; + + // Selection + case BUS::selection: + Selection(); + break; + + // Data out (MCI=000) + case BUS::dataout: + DataOut(); + break; + + // Data in (MCI=001) + case BUS::datain: + DataIn(); + break; + + // Command (MCI=010) + case BUS::command: + Command(); + break; + + // Status (MCI=011) + case BUS::status: + Status(); + break; + + // Msg in (MCI=111) + case BUS::msgin: + MsgIn(); + break; + + // Other + default: + ASSERT(FALSE); + break; + } + + return ctrl.phase; +} + +//--------------------------------------------------------------------------- +// +// Bus free phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::BusFree() +{ + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::busfree) { + +#if defined(DISK_LOG) + Log(Log::Normal, "Bus free phase"); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::busfree; + + // Set Signal lines + ctrl.bus->SetREQ(FALSE); + ctrl.bus->SetMSG(FALSE); + ctrl.bus->SetCD(FALSE); + ctrl.bus->SetIO(FALSE); + ctrl.bus->SetBSY(FALSE); + + // Initialize status and message + ctrl.status = 0x00; + ctrl.message = 0x00; + return; + } + + // Move to selection phase + if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) { + Selection(); + } +} + +//--------------------------------------------------------------------------- +// +// Selection phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Selection() +{ + DWORD id; + + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::selection) { + // Invalid if IDs do not match + id = 1 << ctrl.id; + if ((ctrl.bus->GetDAT() & id) == 0) { + return; + } + + // Return if there is no unit + if (!HasUnit()) { + return; + } + +#if defined(DISK_LOG) + Log(Log::Normal, + "Selection Phase ID=%d (with device)", ctrl.id); +#endif // DISK_LOG + + // Phase change + ctrl.phase = BUS::selection; + + // Raiase BSY and respond + ctrl.bus->SetBSY(TRUE); + return; + } + + // Command phase shifts when selection is completed + if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) { + Command(); + } +} + +//--------------------------------------------------------------------------- +// +// Command phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Command() +{ +#ifdef RASCSI + int count; + int i; +#endif // RASCSI + + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::command) { + +#if defined(DISK_LOG) + Log(Log::Normal, "Command Phase"); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::command; + + // Signal line operated by the target + ctrl.bus->SetMSG(FALSE); + ctrl.bus->SetCD(TRUE); + ctrl.bus->SetIO(FALSE); + + // Data transfer is 6 bytes x 1 block + ctrl.offset = 0; + ctrl.length = 6; + ctrl.blocks = 1; + +#ifdef RASCSI + // Command reception handshake (10 bytes are automatically received at the first command) + count = ctrl.bus->CommandHandShake(ctrl.buffer); + + // If no byte can be received move to the status phase + if (count == 0) { + Error(); + return; + } + + // Check 10-byte CDB + if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) { + ctrl.length = 10; + } + + // If not able to receive all, move to the status phase + if (count != (int)ctrl.length) { + Error(); + return; + } + + // Command data transfer + for (i = 0; i < (int)ctrl.length; i++) { + ctrl.cmd[i] = (DWORD)ctrl.buffer[i]; + } + + // Clear length and block + ctrl.length = 0; + ctrl.blocks = 0; + + // Execution Phase + Execute(); +#else + // Request the command + ctrl.bus->SetREQ(TRUE); + return; +#endif // RASCSI + } +#ifndef RASCSI + // Requesting + if (ctrl.bus->GetREQ()) { + // Sent by the initiator + if (ctrl.bus->GetACK()) { + Receive(); + } + } else { + // Request the initator to + if (!ctrl.bus->GetACK()) { + ReceiveNext(); + } + } +#endif // RASCSI +} + +//--------------------------------------------------------------------------- +// +// Execution Phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Execute() +{ + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "Execution Phase Command %02X", ctrl.cmd[0]); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::execute; + + // Initialization for data transfer + ctrl.offset = 0; + ctrl.blocks = 1; +#ifdef RASCSI + ctrl.execstart = SysTimer::GetTimerLow(); +#endif // RASCSI + + // Process by command + switch (ctrl.cmd[0]) { + // TEST UNIT READY + case 0x00: + CmdTestUnitReady(); + return; + + // REZERO UNIT + case 0x01: + CmdRezero(); + return; + + // REQUEST SENSE + case 0x03: + CmdRequestSense(); + return; + + // FORMAT UNIT + case 0x04: + CmdFormat(); + return; + + // FORMAT UNIT + case 0x06: + CmdFormat(); + return; + + // REASSIGN BLOCKS + case 0x07: + CmdReassign(); + return; + + // READ(6) + case 0x08: + CmdRead6(); + return; + + // WRITE(6) + case 0x0a: + CmdWrite6(); + return; + + // SEEK(6) + case 0x0b: + CmdSeek6(); + return; + + // ASSIGN(SASIのみ) + case 0x0e: + CmdAssign(); + return; + + // SPECIFY(SASIのみ) + case 0xc2: + CmdSpecify(); + return; + } + + // Unsupported command + Log(Log::Warning, "Unsupported command $%02X", ctrl.cmd[0]); + CmdInvalid(); +} + +//--------------------------------------------------------------------------- +// +// Status phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Status() +{ +#ifdef RASCSI + DWORD min_exec_time; + DWORD time; +#endif // RASCSI + + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::status) { + +#ifdef RASCSI + // Minimum execution time + if (ctrl.execstart > 0) { + min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi; + time = SysTimer::GetTimerLow() - ctrl.execstart; + if (time < min_exec_time) { + SysTimer::SleepUsec(min_exec_time - time); + } + ctrl.execstart = 0; + } else { + SysTimer::SleepUsec(5); + } +#endif // RASCSI + +#if defined(DISK_LOG) + Log(Log::Normal, "Status phase"); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::status; + + // Signal line operated by the target + ctrl.bus->SetMSG(FALSE); + ctrl.bus->SetCD(TRUE); + ctrl.bus->SetIO(TRUE); + + // Data transfer is 1 byte x 1 block + ctrl.offset = 0; + ctrl.length = 1; + ctrl.blocks = 1; + ctrl.buffer[0] = (BYTE)ctrl.status; + +#ifndef RASCSI + // Request status + ctrl.bus->SetDAT(ctrl.buffer[0]); + ctrl.bus->SetREQ(TRUE); + +#if defined(DISK_LOG) + Log(Log::Normal, "Status Phase $%02X", ctrl.status); +#endif // DISK_LOG +#endif // RASCSI + return; + } + +#ifdef RASCSI + // Send + Send(); +#else + // Requesting + if (ctrl.bus->GetREQ()) { + // Initiator received + if (ctrl.bus->GetACK()) { + SendNext(); + } + } else { + // Initiator requests next + if (!ctrl.bus->GetACK()) { + Send(); + } + } +#endif // RASCSI +} + +//--------------------------------------------------------------------------- +// +// Message in phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::MsgIn() +{ + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::msgin) { + +#if defined(DISK_LOG) + Log(Log::Normal, "Message in phase"); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::msgin; + + // Signal line operated by the target + ctrl.bus->SetMSG(TRUE); + ctrl.bus->SetCD(TRUE); + ctrl.bus->SetIO(TRUE); + + // length, blocks are already set + 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 + 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 +} + +//--------------------------------------------------------------------------- +// +// Data-in Phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::DataIn() +{ +#ifdef RASCSI + DWORD min_exec_time; + DWORD time; +#endif // RASCSI + + ASSERT(this); + ASSERT(ctrl.length >= 0); + + // Phase change + if (ctrl.phase != BUS::datain) { + +#ifdef RASCSI + // Minimum execution time + if (ctrl.execstart > 0) { + min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi; + time = SysTimer::GetTimerLow() - ctrl.execstart; + if (time < min_exec_time) { + SysTimer::SleepUsec(min_exec_time - time); + } + ctrl.execstart = 0; + } +#endif // RASCSI + + // If the length is 0, go to the status phase + if (ctrl.length == 0) { + Status(); + return; + } + +#if defined(DISK_LOG) + Log(Log::Normal, "Data-in Phase"); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::datain; + + // Signal line operated by the target + ctrl.bus->SetMSG(FALSE); + ctrl.bus->SetCD(FALSE); + ctrl.bus->SetIO(TRUE); + + // length, blocks are already set + ASSERT(ctrl.length > 0); + 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 +} + +//--------------------------------------------------------------------------- +// +// Data out phase +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::DataOut() +{ +#ifdef RASCSI + DWORD min_exec_time; + DWORD time; +#endif // RASCSI + + ASSERT(this); + ASSERT(ctrl.length >= 0); + + // Phase change + if (ctrl.phase != BUS::dataout) { + +#ifdef RASCSI + // Minimum execution time + if (ctrl.execstart > 0) { + min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi; + time = SysTimer::GetTimerLow() - ctrl.execstart; + if (time < min_exec_time) { + SysTimer::SleepUsec(min_exec_time - time); + } + ctrl.execstart = 0; + } +#endif // RASCSI + + // If the length is 0, go to the status phase + if (ctrl.length == 0) { + Status(); + return; + } + +#if defined(DISK_LOG) + Log(Log::Normal, "Data out phase"); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::dataout; + + // Signal line operated by the target + ctrl.bus->SetMSG(FALSE); + ctrl.bus->SetCD(FALSE); + ctrl.bus->SetIO(FALSE); + + // length, blocks are already calculated + ASSERT(ctrl.length > 0); + ASSERT(ctrl.blocks > 0); + ctrl.offset = 0; + +#ifndef RASCSI + // Request data + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + +#ifdef RASCSI + // Receive + Receive(); +#else + // Requesting + if (ctrl.bus->GetREQ()) { + // Sent by the initiator + if (ctrl.bus->GetACK()) { + Receive(); + } + } else { + // Request the initator to + if (!ctrl.bus->GetACK()) { + ReceiveNext(); + } + } +#endif // RASCSI +} + +//--------------------------------------------------------------------------- +// +// Error +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Error() +{ + DWORD lun; + + ASSERT(this); + + // Get bus information + ctrl.bus->Aquire(); + + // Reset check + if (ctrl.bus->GetRST()) { + // Reset the controller + Reset(); + + // Reset the bus + ctrl.bus->Reset(); + return; + } + + // Bus free for status phase and message in phase + if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) { + BusFree(); + return; + } + +#if defined(DISK_LOG) + Log(Log::Warning, "Error occured (going to status phase)"); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + + // Set status and message(CHECK CONDITION) + ctrl.status = (lun << 5) | 0x02; + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// TEST UNIT READY +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdTestUnitReady() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "TEST UNIT READY Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->TestUnitReady(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// REZERO UNIT +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdRezero() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "REZERO UNIT Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Rezero(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// REQUEST SENSE +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdRequestSense() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "REQUEST SENSE Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer); + ASSERT(ctrl.length > 0); + +#if defined(DISK_LOG) + Log(Log::Normal, "Sense key $%02X", ctrl.buffer[2]); +#endif // DISK_LOG + + // Read phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// FORMAT UNIT +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdFormat() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "FORMAT UNIT Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Format(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// REASSIGN BLOCKS +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdReassign() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "REASSIGN BLOCKS Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Reassign(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// READ(6) +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdRead6() +{ + DWORD lun; + DWORD record; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Get record number and block number + record = ctrl.cmd[1] & 0x1f; + record <<= 8; + record |= ctrl.cmd[2]; + record <<= 8; + record |= ctrl.cmd[3]; + ctrl.blocks = ctrl.cmd[4]; + if (ctrl.blocks == 0) { + ctrl.blocks = 0x100; + } + +#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.buffer, record); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.next = record + 1; + + // Read phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// WRITE(6) +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdWrite6() +{ + DWORD lun; + DWORD record; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Get record number and block number + record = ctrl.cmd[1] & 0x1f; + record <<= 8; + record |= ctrl.cmd[2]; + record <<= 8; + record |= ctrl.cmd[3]; + ctrl.blocks = ctrl.cmd[4]; + if (ctrl.blocks == 0) { + ctrl.blocks = 0x100; + } + +#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) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.next = record + 1; + + // Write phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// SEEK(6) +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdSeek6() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "SEEK(6) Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Seek(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// ASSIGN +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdAssign() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "ASSIGN Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Assign(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // Request 4 bytes of data + ctrl.length = 4; + + // Write phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// SPECIFY +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdSpecify() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "SPECIFY Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Assign(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // Request 10 bytes of data + ctrl.length = 10; + + // Write phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// Unsupported command +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::CmdInvalid() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "Command not supported"); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (ctrl.unit[lun]) { + // Command processing on drive + ctrl.unit[lun]->InvalidCmd(); + } + + // Failure (Error) + Error(); +} + +//=========================================================================== +// +// Data transfer +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Data transmission +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Send() +{ +#ifdef RASCSI + int len; +#endif // RASCSI + BOOL result; + + ASSERT(this); + 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( + &ctrl.buffer[ctrl.offset], ctrl.length); + + // If you can not send it all, move on to the status phase + if (len != (int)ctrl.length) { + Error(); + return; + } + + // Offset and Length + ctrl.offset += ctrl.length; + ctrl.length = 0; + return; + } +#else + // Offset and Length + ASSERT(ctrl.length >= 1); + ctrl.offset++; + ctrl.length--; + + // Immediately after ACK is asserted, if the data + // has been set by SendNext, raise the request + if (ctrl.length != 0) { + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); + return; + } +#endif // RASCSI + + // Remove block and initialize the result + ctrl.blocks--; + result = TRUE; + + // Process after data collection (read/data-in only) + if (ctrl.phase == BUS::datain) { + if (ctrl.blocks != 0) { + // Set next buffer (set offset, length) + result = XferIn(ctrl.buffer); + //** printf("xfer in: %d \n",result); + +#ifndef RASCSI + ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); +#endif // RASCSI + } + } + + // If result FALSE, move to the status phase + if (!result) { + Error(); + return; + } + + // Continue sending if block != 0 + if (ctrl.blocks != 0){ + ASSERT(ctrl.length > 0); + ASSERT(ctrl.offset == 0); +#ifndef RASCSI + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + + // Move to the next phase + switch (ctrl.phase) { + // Message in phase + case BUS::msgin: + // Bus free phase + BusFree(); + break; + + // Data-in Phase + case BUS::datain: + // status phase + Status(); + break; + + // Status phase + case BUS::status: + // Message in phase + ctrl.length = 1; + ctrl.blocks = 1; + ctrl.buffer[0] = (BYTE)ctrl.message; + MsgIn(); + break; + + // Other (impossible) + default: + ASSERT(FALSE); + break; + } +} + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Continue sending data +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::SendNext() +{ + ASSERT(this); + + // Req is up + ASSERT(ctrl.bus->GetREQ()); + ASSERT(ctrl.bus->GetIO()); + + // Signal line operated by the target + ctrl.bus->SetREQ(FALSE); + + // If there is data in the buffer, set it first. + if (ctrl.length > 1) { + ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset + 1]); + } +} +#endif // RASCSI + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Receive data +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Receive() +{ + DWORD data; + + ASSERT(this); + + // Req is up + ASSERT(ctrl.bus->GetREQ()); + ASSERT(!ctrl.bus->GetIO()); + + // Get data + data = (DWORD)ctrl.bus->GetDAT(); + + // Signal line operated by the target + ctrl.bus->SetREQ(FALSE); + + switch (ctrl.phase) { + // Command phase + case BUS::command: + ctrl.cmd[ctrl.offset] = data; +#if defined(DISK_LOG) + Log(Log::Normal, "Command phase $%02X", data); +#endif // DISK_LOG + + // Set the length again with the first data (offset 0) + if (ctrl.offset == 0) { + if (ctrl.cmd[0] >= 0x20 && ctrl.cmd[0] <= 0x7D) { + // 10 byte CDB + ctrl.length = 10; + } + } + break; + + // Data out phase + case BUS::dataout: + ctrl.buffer[ctrl.offset] = (BYTE)data; + break; + + // Other (impossible) + default: + ASSERT(FALSE); + break; + } +} +#endif // RASCSI + +#ifdef RASCSI +//--------------------------------------------------------------------------- +// +// Receive data +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::Receive() +#else +//--------------------------------------------------------------------------- +// +// Continue receiving data +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::ReceiveNext() +#endif // RASCSI +{ +#ifdef RASCSI + int len; +#endif // RASCSI + BOOL result; + + ASSERT(this); + + // REQ is low + ASSERT(!ctrl.bus->GetREQ()); + ASSERT(!ctrl.bus->GetIO()); + +#ifdef RASCSI + // Length != 0 if received + if (ctrl.length != 0) { + // Receive + len = ctrl.bus->ReceiveHandShake( + &ctrl.buffer[ctrl.offset], ctrl.length); + + // If not able to receive all, move to status phase + if (len != (int)ctrl.length) { + Error(); + return; + } + + // Offset and Length + ctrl.offset += ctrl.length; + ctrl.length = 0; + return; + } +#else + // Offset and Length + ASSERT(ctrl.length >= 1); + ctrl.offset++; + ctrl.length--; + + // If length != 0, set req again + if (ctrl.length != 0) { + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); + return; + } +#endif // RASCSI + + // Remove the control block and initialize the result + ctrl.blocks--; + result = TRUE; + + // Process the data out phase + if (ctrl.phase == BUS::dataout) { + if (ctrl.blocks == 0) { + // End with this buffer + result = XferOut(FALSE); + } else { + // Continue to next buffer (set offset, length) + result = XferOut(TRUE); + } + } + + // If result is false, move to the status phase + if (!result) { + Error(); + return; + } + + // Continue to receive is block != 0 + if (ctrl.blocks != 0){ + ASSERT(ctrl.length > 0); + ASSERT(ctrl.offset == 0); +#ifndef RASCSI + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + + // Move to the next phase + switch (ctrl.phase) { +#ifndef RASCSI + // Command phase + case BUS::command: + // Execution Phase + Execute(); + break; +#endif // RASCSI + + // Data out phase + case BUS::dataout: + // Flush + FlushUnit(); + + // status phase + Status(); + break; + + // Other (impossible) + default: + ASSERT(FALSE); + break; + } +} + +//--------------------------------------------------------------------------- +// +// Data transfer IN +// *Reset offset and length +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SASIDEV::XferIn(BYTE *buf) +{ + DWORD lun; + + ASSERT(this); + ASSERT(ctrl.phase == BUS::datain); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + return FALSE; + } + + // Limited to read commands + switch (ctrl.cmd[0]) { + // READ(6) + case 0x08: + // READ(10) + case 0x28: + // Read from disk + ctrl.length = ctrl.unit[lun]->Read(buf, ctrl.next); + ctrl.next++; + + // If there is an error, go to the status phase + if (ctrl.length <= 0) { + // Cancel data-in + return FALSE; + } + + // If things are normal, work setting + ctrl.offset = 0; + break; + + // Other (impossible) + default: + ASSERT(FALSE); + return FALSE; + } + + // Succeeded in setting the buffer + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Data transfer OUT +// *If cont=true, reset the offset and length +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SASIDEV::XferOut(BOOL cont) +{ + DWORD lun; + SCSIBR *bridge; + + ASSERT(this); + ASSERT(ctrl.phase == BUS::dataout); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + return FALSE; + } + + // 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 + return FALSE; + } + break; + + // 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)) { + // write failed + return FALSE; + } + + // If normal, work setting + ctrl.offset = 0; + break; + } + + // WRITE AND VERIFY + case 0x2e: + // Write + if (!ctrl.unit[lun]->Write(ctrl.buffer, ctrl.next - 1)) { + // Write failed + return FALSE; + } + + // If you do not need the next block, end here + ctrl.next++; + if (!cont) { + break; + } + + // Check the next block + ctrl.length = ctrl.unit[lun]->WriteCheck(ctrl.next - 1); + if (ctrl.length <= 0) { + // Cannot write + return FALSE; + } + + // If normal, work setting + ctrl.offset = 0; + break; + + // SPECIFY(SASI only) + case 0xc2: + break; + + default: + ASSERT(FALSE); + break; + } + + // Buffer saved successfully + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Logical unit flush +// +//--------------------------------------------------------------------------- +void FASTCALL SASIDEV::FlushUnit() +{ + DWORD lun; + + ASSERT(this); + ASSERT(ctrl.phase == BUS::dataout); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + return; + } + + // WRITE system only + 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; + // 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 + 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 + Log(Log::Warning, "Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]); + return; + } + break; + + default: + Log(Log::Warning, "Received an invalid flush command %02X!!!!!\n",ctrl.cmd[0]); + ASSERT(FALSE); + break; + } +} + +#ifdef DISK_LOG +//--------------------------------------------------------------------------- +// +// Get the current phase as a string +// +//--------------------------------------------------------------------------- +void SASIDEV::GetPhaseStr(char *str) +{ + switch(this->GetPhase()) + { + case BUS::busfree: + strcpy(str,"busfree "); + break; + case BUS::arbitration: + strcpy(str,"arbitration"); + break; + case BUS::selection: + strcpy(str,"selection "); + break; + case BUS::reselection: + strcpy(str,"reselection"); + break; + case BUS::command: + strcpy(str,"command "); + break; + case BUS::execute: + strcpy(str,"execute "); + break; + case BUS::datain: + strcpy(str,"datain "); + break; + case BUS::dataout: + strcpy(str,"dataout "); + break; + case BUS::status: + strcpy(str,"status "); + break; + case BUS::msgin: + strcpy(str,"msgin "); + break; + case BUS::msgout: + strcpy(str,"msgout "); + break; + case BUS::reserved: + strcpy(str,"reserved "); + break; + } +} +#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 +} diff --git a/src/raspberrypi/controllers/sasidev_ctrl.h b/src/raspberrypi/controllers/sasidev_ctrl.h new file mode 100644 index 0000000..e5bd28b --- /dev/null +++ b/src/raspberrypi/controllers/sasidev_ctrl.h @@ -0,0 +1,211 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SASI device controller ] +// +//--------------------------------------------------------------------------- +#pragma once + +#include "os.h" +#include "scsi.h" +#include "fileio.h" +#include "disk.h" +#include "log.h" +#include "xm6.h" + + +//=========================================================================== +// +// SASI Controller +// +//=========================================================================== +class SASIDEV +{ +public: + // Maximum number of logical units + enum { + UnitMax = 8 + }; + +#ifdef RASCSI + // For timing adjustments + enum { + min_exec_time_sasi = 100, // SASI BOOT/FORMAT 30:NG 35:OK + min_exec_time_scsi = 50 + }; +#endif // RASCSI + + // Internal data definition + typedef struct { + // 全般 + BUS::phase_t phase; // Transition phase + int id; // Controller ID (0-7) + BUS *bus; // Bus + + // commands + DWORD cmd[10]; // Command data + DWORD status; // Status data + DWORD message; // Message data + +#ifdef RASCSI + // Run + DWORD execstart; // Execution start time +#endif // RASCSI + + // Transfer + BYTE *buffer; // Transfer data buffer + int bufsize; // Transfer data buffer size + DWORD blocks; // Number of transfer block + DWORD next; // Next record + DWORD offset; // Transfer offset + DWORD length; // Transfer remaining length + + // Logical unit + Disk *unit[UnitMax]; + // Logical Unit + } ctrl_t; + +public: + // Basic Functions +#ifdef RASCSI + SASIDEV(); +#else + SASIDEV(Device *dev); +#endif //RASCSI + + // Constructor + virtual ~SASIDEV(); + // Destructor + virtual void FASTCALL Reset(); + // Device Reset +#ifndef RASCSI + virtual BOOL FASTCALL Save(Fileio *fio, int ver); + // Save + virtual BOOL FASTCALL Load(Fileio *fio, int ver); + // Load +#endif //RASCSI + + // External API + virtual BUS::phase_t FASTCALL Process(); + // Run + + // Connect + void FASTCALL Connect(int id, BUS *sbus); + // Controller connection + Disk* FASTCALL GetUnit(int no); + // Get logical unit + void FASTCALL SetUnit(int no, Disk *dev); + // Logical unit setting + BOOL FASTCALL HasUnit(); + // Has a valid logical unit + + // Other + BUS::phase_t FASTCALL GetPhase() {return ctrl.phase;} + // Get the phase +#ifdef DISK_LOG + // Function to get the current phase as a String. + void FASTCALL GetPhaseStr(char *str); +#endif + + int FASTCALL GetID() {return ctrl.id;} + // Get the ID + void FASTCALL GetCTRL(ctrl_t *buffer); + // Get the internal information + ctrl_t* FASTCALL GetWorkAddr() { return &ctrl; } + // Get the internal information address + virtual BOOL FASTCALL IsSASI() const {return TRUE;} + // SASI Check + virtual BOOL FASTCALL IsSCSI() const {return FALSE;} + // SCSI check + Disk* FASTCALL GetBusyUnit(); + // Get the busy unit + +protected: + // Phase processing + virtual void FASTCALL BusFree(); + // Bus free phase + virtual void FASTCALL Selection(); + // Selection phase + virtual void FASTCALL Command(); + // Command phase + virtual void FASTCALL Execute(); + // Execution phase + void FASTCALL Status(); + // Status phase + void FASTCALL MsgIn(); + // Message in phase + void FASTCALL DataIn(); + // Data in phase + void FASTCALL DataOut(); + // Data out phase + virtual void FASTCALL Error(); + // Common error handling + + // commands + void FASTCALL CmdTestUnitReady(); + // TEST UNIT READY command + void FASTCALL CmdRezero(); + // REZERO UNIT command + void FASTCALL CmdRequestSense(); + // REQUEST SENSE command + void FASTCALL CmdFormat(); + // FORMAT command + void FASTCALL CmdReassign(); + // REASSIGN BLOCKS command + void FASTCALL CmdRead6(); + // READ(6) command + void FASTCALL CmdWrite6(); + // WRITE(6) command + void FASTCALL CmdSeek6(); + // SEEK(6) command + void FASTCALL CmdAssign(); + // ASSIGN command + void FASTCALL CmdSpecify(); + // SPECIFY command + void FASTCALL CmdInvalid(); + // Unsupported command + + // データ転送 + virtual void FASTCALL Send(); + // Send data +#ifndef RASCSI + virtual void FASTCALL SendNext(); + // Continue sending data +#endif // RASCSI + virtual void FASTCALL Receive(); + // Receive data +#ifndef RASCSI + virtual void FASTCALL ReceiveNext(); + // Continue receiving data +#endif // RASCSI + BOOL FASTCALL XferIn(BYTE* buf); + // Data transfer IN + BOOL FASTCALL XferOut(BOOL cont); + // Data transfer OUT + + // Special operations + void FASTCALL FlushUnit(); + // Flush the logical unit + + // Log + void FASTCALL Log(Log::loglevel level, const char *format, ...); + // Log output + +protected: +#ifndef RASCSI + Device *host; + // Host device +#endif // RASCSI + + ctrl_t ctrl; + // Internal data +}; diff --git a/src/raspberrypi/controllers/scsidev_ctrl.cpp b/src/raspberrypi/controllers/scsidev_ctrl.cpp new file mode 100644 index 0000000..918c0af --- /dev/null +++ b/src/raspberrypi/controllers/scsidev_ctrl.cpp @@ -0,0 +1,1869 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI device controller ] +// +//--------------------------------------------------------------------------- +#include "scsidev_ctrl.h" +#include "gpiobus.h" +#include "scsi_host_bridge.h" + +//=========================================================================== +// +// SCSI Device +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +#ifdef RASCSI +SCSIDEV::SCSIDEV() : SASIDEV() +#else +SCSIDEV::SCSIDEV(Device *dev) : SASIDEV(dev) +#endif +{ + // Synchronous transfer work initialization + scsi.syncenable = FALSE; + scsi.syncperiod = 50; + scsi.syncoffset = 0; + scsi.atnmsg = FALSE; + scsi.msc = 0; + memset(scsi.msb, 0x00, sizeof(scsi.msb)); +} + +//--------------------------------------------------------------------------- +// +// Device reset +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Reset() +{ + ASSERT(this); + + // Work initialization + scsi.atnmsg = FALSE; + scsi.msc = 0; + memset(scsi.msb, 0x00, sizeof(scsi.msb)); + + // Base class + SASIDEV::Reset(); +} + +//--------------------------------------------------------------------------- +// +// Process +// +//--------------------------------------------------------------------------- +BUS::phase_t FASTCALL SCSIDEV::Process() +{ + ASSERT(this); + + // Do nothing if not connected + if (ctrl.id < 0 || ctrl.bus == NULL) { + return ctrl.phase; + } + + // Get bus information + ctrl.bus->Aquire(); + + // Reset + if (ctrl.bus->GetRST()) { +#if defined(DISK_LOG) + Log(Log::Normal, "RESET信号受信"); +#endif // DISK_LOG + + // Reset the controller + Reset(); + + // Reset the bus + ctrl.bus->Reset(); + return ctrl.phase; + } + + // Phase processing + switch (ctrl.phase) { + // Bus free phase + case BUS::busfree: + BusFree(); + break; + + // Selection phase + case BUS::selection: + Selection(); + break; + + // Data out (MCI=000) + case BUS::dataout: + DataOut(); + break; + + // Data in (MCI=001) + case BUS::datain: + DataIn(); + break; + + // Command (MCI=010) + case BUS::command: + Command(); + break; + + // Status (MCI=011) + case BUS::status: + Status(); + break; + + // Message out (MCI=110) + case BUS::msgout: + MsgOut(); + break; + + // Message in (MCI=111) + case BUS::msgin: + MsgIn(); + break; + + // Other + default: + ASSERT(FALSE); + break; + } + + return ctrl.phase; +} + +//--------------------------------------------------------------------------- +// +// Phaes +// +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// +// Bus free phase +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::BusFree() +{ + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::busfree) { + +#if defined(DISK_LOG) + Log(Log::Normal, "Bus free phase"); +#endif // DISK_LOG + + // Phase setting + ctrl.phase = BUS::busfree; + + // Signal line + ctrl.bus->SetREQ(FALSE); + ctrl.bus->SetMSG(FALSE); + ctrl.bus->SetCD(FALSE); + ctrl.bus->SetIO(FALSE); + ctrl.bus->SetBSY(FALSE); + + // Initialize status and message + ctrl.status = 0x00; + ctrl.message = 0x00; + + // Initialize ATN message reception status + scsi.atnmsg = FALSE; + return; + } + + // Move to selection phase + if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) { + Selection(); + } +} + +//--------------------------------------------------------------------------- +// +// Selection Phase +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Selection() +{ + DWORD id; + + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::selection) { + // invalid if IDs do not match + id = 1 << ctrl.id; + if ((ctrl.bus->GetDAT() & id) == 0) { + return; + } + + // End if there is no valid unit + if (!HasUnit()) { + return; + } + +#if defined(DISK_LOG) + Log(Log::Normal, + "Selection Phase ID=%d (with device)", ctrl.id); +#endif // DISK_LOG + + // Phase setting + ctrl.phase = BUS::selection; + + // Raise BSY and respond + ctrl.bus->SetBSY(TRUE); + return; + } + + // Selection completed + if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) { + // Message out phase if ATN=1, otherwise command phase + if (ctrl.bus->GetATN()) { + MsgOut(); + } else { + Command(); + } + } +} + +//--------------------------------------------------------------------------- +// +// Execution Phase +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Execute() +{ + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "Execution phase command $%02X", ctrl.cmd[0]); +#endif // DISK_LOG + + // Phase Setting + ctrl.phase = BUS::execute; + + // Initialization for data transfer + ctrl.offset = 0; + ctrl.blocks = 1; +#ifdef RASCSI + ctrl.execstart = SysTimer::GetTimerLow(); +#endif // RASCSI + + // Process by command + switch (ctrl.cmd[0]) { + // TEST UNIT READY + case 0x00: + CmdTestUnitReady(); + return; + + // REZERO + case 0x01: + CmdRezero(); + return; + + // REQUEST SENSE + case 0x03: + CmdRequestSense(); + return; + + // FORMAT UNIT + case 0x04: + CmdFormat(); + return; + + // REASSIGN BLOCKS + case 0x07: + CmdReassign(); + return; + + // READ(6) + case 0x08: + CmdRead6(); + return; + + // WRITE(6) + case 0x0a: + CmdWrite6(); + return; + + // SEEK(6) + case 0x0b: + CmdSeek6(); + return; + + // INQUIRY + case 0x12: + CmdInquiry(); + return; + + // MODE SELECT + case 0x15: + CmdModeSelect(); + return; + + // MDOE SENSE + case 0x1a: + CmdModeSense(); + return; + + // START STOP UNIT + case 0x1b: + CmdStartStop(); + return; + + // SEND DIAGNOSTIC + case 0x1d: + CmdSendDiag(); + return; + + // PREVENT/ALLOW MEDIUM REMOVAL + case 0x1e: + CmdRemoval(); + return; + + // READ CAPACITY + case 0x25: + CmdReadCapacity(); + return; + + // READ(10) + case 0x28: + CmdRead10(); + return; + + // WRITE(10) + case 0x2a: + CmdWrite10(); + return; + + // SEEK(10) + case 0x2b: + CmdSeek10(); + return; + + // WRITE and VERIFY + case 0x2e: + CmdWrite10(); + return; + + // VERIFY + case 0x2f: + CmdVerify(); + return; + + // SYNCHRONIZE CACHE + case 0x35: + CmdSynchronizeCache(); + return; + + // READ DEFECT DATA(10) + case 0x37: + CmdReadDefectData10(); + return; + + // READ TOC + case 0x43: + CmdReadToc(); + return; + + // PLAY AUDIO(10) + case 0x45: + CmdPlayAudio10(); + return; + + // PLAY AUDIO MSF + case 0x47: + CmdPlayAudioMSF(); + return; + + // PLAY AUDIO TRACK + case 0x48: + CmdPlayAudioTrack(); + return; + + // MODE SELECT(10) + case 0x55: + CmdModeSelect10(); + return; + + // MDOE SENSE(10) + case 0x5a: + CmdModeSense10(); + return; + + // SPECIFY (SASI only/Suppress warning when using SxSI) + case 0xc2: + CmdInvalid(); + return; + + } + + // No other support + Log(Log::Normal, "Unsupported command received: $%02X", ctrl.cmd[0]); + CmdInvalid(); +} + +//--------------------------------------------------------------------------- +// +// Message out phase +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::MsgOut() +{ + ASSERT(this); + + // Phase change + if (ctrl.phase != BUS::msgout) { + +#if defined(DISK_LOG) + Log(Log::Normal, "Message Out Phase"); +#endif // DISK_LOG + + // Message out phase after selection + // process the IDENTIFY message + if (ctrl.phase == BUS::selection) { + scsi.atnmsg = TRUE; + scsi.msc = 0; + memset(scsi.msb, 0x00, sizeof(scsi.msb)); + } + + // Phase Setting + ctrl.phase = BUS::msgout; + + // Signal line operated by the target + ctrl.bus->SetMSG(TRUE); + ctrl.bus->SetCD(TRUE); + ctrl.bus->SetIO(FALSE); + + // Data transfer is 1 byte x 1 block + ctrl.offset = 0; + ctrl.length = 1; + ctrl.blocks = 1; + +#ifndef RASCSI + // Request message + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + +#ifdef RASCSI + // Receive + Receive(); +#else + // Requesting + if (ctrl.bus->GetREQ()) { + // Sent by the initiator + if (ctrl.bus->GetACK()) { + Receive(); + } + } else { + // Request the initator to + if (!ctrl.bus->GetACK()) { + ReceiveNext(); + } + } +#endif // RASCSI +} + +//--------------------------------------------------------------------------- +// +// Common Error Handling +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Error() +{ + ASSERT(this); + + // Get bus information + ctrl.bus->Aquire(); + + // Reset check + if (ctrl.bus->GetRST()) { + // Reset the controller + Reset(); + + // Reset the bus + ctrl.bus->Reset(); + return; + } + + // Bus free for status phase and message in phase + if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) { + BusFree(); + return; + } + +#if defined(DISK_LOG) + Log(Log::Normal, "Error (to status phase)"); +#endif // DISK_LOG + + // Set status and message(CHECK CONDITION) + ctrl.status = 0x02; + ctrl.message = 0x00; + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// Command +// +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdInquiry() +{ + Disk *disk; + int lun; + DWORD major; + DWORD minor; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "INQUIRY Command"); +#endif // DISK_LOG + + // Find a valid unit + disk = NULL; + for (lun = 0; lun < UnitMax; lun++) { + if (ctrl.unit[lun]) { + disk = ctrl.unit[lun]; + break; + } + } + + // Processed on the disk side (it is originally processed by the controller) + if (disk) { +#ifdef RASCSI + major = (DWORD)(RASCSI >> 8); + minor = (DWORD)(RASCSI & 0xff); +#else + host->GetVM()->GetVersion(major, minor); +#endif // RASCSI + ctrl.length = + ctrl.unit[lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor); + } else { + ctrl.length = 0; + } + + if (ctrl.length <= 0) { + // failure (error) + Error(); + return; + } + + // Add synchronous transfer support information + if (scsi.syncenable) { + ctrl.buffer[7] |= (1 << 4); + } + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// MODE SELECT +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdModeSelect() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "MODE SELECT Command"); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->SelectCheck(ctrl.cmd); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Data out phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// MODE SENSE +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdModeSense() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "MODE SENSE Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->ModeSense(ctrl.cmd, ctrl.buffer); + ASSERT(ctrl.length >= 0); + if (ctrl.length == 0) { + Log(Log::Warning, + "Not supported MODE SENSE page $%02X", ctrl.cmd[2]); + + // Failure (Error) + Error(); + return; + } + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// START STOP UNIT +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdStartStop() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "START STOP UNIT Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->StartStop(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// SEND DIAGNOSTIC +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdSendDiag() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "SEND DIAGNOSTIC Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->SendDiag(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// PREVENT/ALLOW MEDIUM REMOVAL +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdRemoval() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "PREVENT/ALLOW MEDIUM REMOVAL Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Removal(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// READ CAPACITY +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdReadCapacity() +{ + DWORD lun; + int length; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "READ CAPACITY Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer); + ASSERT(length >= 0); + if (length <= 0) { + Error(); + return; + } + + // Length setting + ctrl.length = length; + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// READ(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdRead10() +{ + DWORD lun; + DWORD record; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Receive message if host bridge + if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) { + CmdGetMessage10(); + return; + } + + // Get record number and block number + record = ctrl.cmd[2]; + record <<= 8; + record |= ctrl.cmd[3]; + record <<= 8; + record |= ctrl.cmd[4]; + record <<= 8; + record |= ctrl.cmd[5]; + ctrl.blocks = ctrl.cmd[7]; + ctrl.blocks <<= 8; + ctrl.blocks |= ctrl.cmd[8]; + +#if defined(DISK_LOG) + Log(Log::Normal, "READ(10) command record=%08X block=%d", record, ctrl.blocks); +#endif // DISK_LOG + + // Do not process 0 blocks + if (ctrl.blocks == 0) { + Status(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.next = record + 1; + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// WRITE(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdWrite10() +{ + DWORD lun; + DWORD record; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Receive message with host bridge + if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) { + CmdSendMessage10(); + return; + } + + // Get record number and block number + record = ctrl.cmd[2]; + record <<= 8; + record |= ctrl.cmd[3]; + record <<= 8; + record |= ctrl.cmd[4]; + record <<= 8; + record |= ctrl.cmd[5]; + ctrl.blocks = ctrl.cmd[7]; + ctrl.blocks <<= 8; + ctrl.blocks |= ctrl.cmd[8]; + +#if defined(DISK_LOG) + Log(Log::Normal, + "WRTIE(10) command record=%08X blocks=%d", record, ctrl.blocks); +#endif // DISK_LOG + + // Do not process 0 blocks + if (ctrl.blocks == 0) { + Status(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->WriteCheck(record); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.next = record + 1; + + // Data out phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// SEEK(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdSeek10() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "SEEK(10) Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->Seek(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// VERIFY +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdVerify() +{ + DWORD lun; + BOOL status; + DWORD record; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Get record number and block number + record = ctrl.cmd[2]; + record <<= 8; + record |= ctrl.cmd[3]; + record <<= 8; + record |= ctrl.cmd[4]; + record <<= 8; + record |= ctrl.cmd[5]; + ctrl.blocks = ctrl.cmd[7]; + ctrl.blocks <<= 8; + ctrl.blocks |= ctrl.cmd[8]; + +#if defined(DISK_LOG) + Log(Log::Normal, + "VERIFY command record=%08X blocks=%d", record, ctrl.blocks); +#endif // DISK_LOG + + // Do not process 0 blocks + if (ctrl.blocks == 0) { + Status(); + return; + } + + // if BytChk=0 + if ((ctrl.cmd[1] & 0x02) == 0) { + // Command processing on drive + status = ctrl.unit[lun]->Seek(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); + return; + } + + // Test loading + ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.next = record + 1; + + // Data out phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// SYNCHRONIZE CACHE +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdSynchronizeCache() +{ + DWORD lun; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Make it do something (not implemented)... + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// READ DEFECT DATA(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdReadDefectData10() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "READ DEFECT DATA(10) Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->ReadDefectData10(ctrl.cmd, ctrl.buffer); + ASSERT(ctrl.length >= 0); + + if (ctrl.length <= 4) { + Error(); + return; + } + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// READ TOC +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdReadToc() +{ + DWORD lun; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->ReadToc(ctrl.cmd, ctrl.buffer); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// PLAY AUDIO(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdPlayAudio10() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->PlayAudio(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// PLAY AUDIO MSF +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdPlayAudioMSF() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// PLAY AUDIO TRACK +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdPlayAudioTrack() +{ + DWORD lun; + BOOL status; + + ASSERT(this); + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd); + if (!status) { + // Failure (Error) + Error(); + return; + } + + // status phase + Status(); +} + +//--------------------------------------------------------------------------- +// +// MODE SELECT10 +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdModeSelect10() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "MODE SELECT10 Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->SelectCheck10(ctrl.cmd); + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Data out phase + DataOut(); +} + +//--------------------------------------------------------------------------- +// +// MODE SENSE(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdModeSense10() +{ + DWORD lun; + + ASSERT(this); + +#if defined(DISK_LOG) + Log(Log::Normal, "MODE SENSE(10) Command "); +#endif // DISK_LOG + + // Logical Unit + lun = (ctrl.cmd[1] >> 5) & 0x07; + if (!ctrl.unit[lun]) { + Error(); + return; + } + + // Command processing on drive + ctrl.length = ctrl.unit[lun]->ModeSense10(ctrl.cmd, ctrl.buffer); + ASSERT(ctrl.length >= 0); + if (ctrl.length == 0) { + Log(Log::Warning, + "Not supported MODE SENSE(10) page $%02X", ctrl.cmd[2]); + + // Failure (Error) + Error(); + return; + } + + // Data-in Phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// GET MESSAGE(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdGetMessage10() +{ + DWORD lun; + SCSIBR *bridge; + + 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', 'B', 'R')) { + 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); + } + + // Process with drive + bridge = (SCSIBR*)ctrl.unit[lun]; + ctrl.length = bridge->GetMessage10(ctrl.cmd, ctrl.buffer); + + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.blocks = 1; + ctrl.next = 1; + + // Data in phase + DataIn(); +} + +//--------------------------------------------------------------------------- +// +// SEND MESSAGE(10) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::CmdSendMessage10() +{ + DWORD lun; + + 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', 'B', 'R')) { + 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); + } + + // Set transfer amount + ctrl.length = ctrl.cmd[6]; + ctrl.length <<= 8; + ctrl.length |= ctrl.cmd[7]; + ctrl.length <<= 8; + ctrl.length |= ctrl.cmd[8]; + + if (ctrl.length <= 0) { + // Failure (Error) + Error(); + return; + } + + // Set next block + ctrl.blocks = 1; + ctrl.next = 1; + + // Light phase + DataOut(); +} + +//=========================================================================== +// +// Data Transfer +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Send data +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Send() +{ +#ifdef RASCSI + int len; +#endif // RASCSI + BOOL result; + + ASSERT(this); + ASSERT(!ctrl.bus->GetREQ()); + ASSERT(ctrl.bus->GetIO()); + +#ifdef RASCSI + //if Length! = 0, send + if (ctrl.length != 0) { + len = ctrl.bus->SendHandShake( + &ctrl.buffer[ctrl.offset], ctrl.length); + + // If you cannot send all, move to status phase + if (len != (int)ctrl.length) { + Error(); + return; + } + + // offset and length + ctrl.offset += ctrl.length; + ctrl.length = 0; + return; + } +#else + // offset and length + ASSERT(ctrl.length >= 1); + ctrl.offset++; + ctrl.length--; + + // Immediately after ACK is asserted, if the data has been + // set by SendNext, raise the request + if (ctrl.length != 0) { + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); + return; + } +#endif // RASCSI + + // Block subtraction, result initialization + ctrl.blocks--; + result = TRUE; + + // Processing after data collection (read/data-in only) + if (ctrl.phase == BUS::datain) { + if (ctrl.blocks != 0) { + // // set next buffer (set offset, length) + result = XferIn(ctrl.buffer); +#ifndef RASCSI + ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); +#endif // RASCSI + } + } + + // If result FALSE, move to status phase + if (!result) { + Error(); + return; + } + + // Continue sending if block !=0 + if (ctrl.blocks != 0){ + ASSERT(ctrl.length > 0); + ASSERT(ctrl.offset == 0); +#ifndef RASCSI + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + + // Move to next phase + switch (ctrl.phase) { + // Message in phase + case BUS::msgin: + // Completed sending response to extended message of IDENTIFY message + if (scsi.atnmsg) { + // flag off + scsi.atnmsg = FALSE; + + // command phase + Command(); + } else { + // Bus free phase + BusFree(); + } + break; + + // Data-in Phase + case BUS::datain: + // status phase + Status(); + break; + + // status phase + case BUS::status: + // Message in phase + ctrl.length = 1; + ctrl.blocks = 1; + ctrl.buffer[0] = (BYTE)ctrl.message; + MsgIn(); + break; + + // Other (impossible) + default: + ASSERT(FALSE); + break; + } +} + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Continue data transmission..... +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::SendNext() +{ + ASSERT(this); + + // REQ is up + ASSERT(ctrl.bus->GetREQ()); + ASSERT(ctrl.bus->GetIO()); + + // Signal line operated by the target + ctrl.bus->SetREQ(FALSE); + + // If there is data in the buffer, set it first + if (ctrl.length > 1) { + ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset + 1]); + } +} +#endif // RASCSI + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Receive data +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Receive() +{ + DWORD data; + + ASSERT(this); + + // Req is up + ASSERT(ctrl.bus->GetREQ()); + ASSERT(!ctrl.bus->GetIO()); + + // Get data + data = (DWORD)ctrl.bus->GetDAT(); + + // Signal line operated by the target + ctrl.bus->SetREQ(FALSE); + + switch (ctrl.phase) { + // Command phase + case BUS::command: + ctrl.cmd[ctrl.offset] = data; +#if defined(DISK_LOG) + Log(Log::Normal, "Command phase $%02X", data); +#endif // DISK_LOG + + // Set the length again with the first data (offset 0) + if (ctrl.offset == 0) { + if (ctrl.cmd[0] >= 0x20) { + // 10バイトCDB + ctrl.length = 10; + } + } + break; + + // Message out phase + case BUS::msgout: + ctrl.message = data; +#if defined(DISK_LOG) + Log(Log::Normal, "Message out phase $%02X", data); +#endif // DISK_LOG + break; + + // Data out phase + case BUS::dataout: + ctrl.buffer[ctrl.offset] = (BYTE)data; + break; + + // Other (impossible) + default: + ASSERT(FALSE); + break; + } +} +#endif // RASCSI + +#ifdef RASCSI +//--------------------------------------------------------------------------- +// +// Receive Data +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::Receive() +#else +//--------------------------------------------------------------------------- +// +// Continue receiving data +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIDEV::ReceiveNext() +#endif // RASCSI +{ +#ifdef RASCSI + int len; +#endif // RASCSI + BOOL result; + int i; + BYTE data; + + ASSERT(this); + + // REQ is low + ASSERT(!ctrl.bus->GetREQ()); + ASSERT(!ctrl.bus->GetIO()); + +#ifdef RASCSI + // Length != 0 if received + if (ctrl.length != 0) { + // Receive + len = ctrl.bus->ReceiveHandShake( + &ctrl.buffer[ctrl.offset], ctrl.length); + + // If not able to receive all, move to status phase + if (len != (int)ctrl.length) { + Error(); + return; + } + + // Offset and Length + ctrl.offset += ctrl.length; + ctrl.length = 0;; + return; + } +#else + // Offset and Length + ASSERT(ctrl.length >= 1); + ctrl.offset++; + ctrl.length--; + + // If length!=0, set req again + if (ctrl.length != 0) { + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); + return; + } +#endif // RASCSI + + // Block subtraction, result initialization + ctrl.blocks--; + result = TRUE; + + // Processing after receiving data (by phase) + switch (ctrl.phase) { + + // Data out phase + case BUS::dataout: + if (ctrl.blocks == 0) { + // End with this buffer + result = XferOut(FALSE); + } else { + // Continue to next buffer (set offset, length) + result = XferOut(TRUE); + } + break; + + // Message out phase + case BUS::msgout: + ctrl.message = ctrl.buffer[0]; + if (!XferMsg(ctrl.message)) { + // Immediately free the bus if message output fails + BusFree(); + return; + } + + // Clear message data in preparation for message-in + ctrl.message = 0x00; + break; + + default: + break; + } + + // If result FALSE, move to status phase + if (!result) { + Error(); + return; + } + + // Continue to receive if block !=0 + if (ctrl.blocks != 0){ + ASSERT(ctrl.length > 0); + ASSERT(ctrl.offset == 0); +#ifndef RASCSI + // Signal line operated by the target + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + + // Move to next phase + switch (ctrl.phase) { + // Command phase + case BUS::command: +#ifdef RASCSI + // Command data transfer + len = 6; + if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) { + // 10 byte CDB + len = 10; + } + for (i = 0; i < len; i++) { + ctrl.cmd[i] = (DWORD)ctrl.buffer[i]; +#if defined(DISK_LOG) + Log(Log::Normal, "Command $%02X", ctrl.cmd[i]); +#endif // DISK_LOG + } +#endif // RASCSI + + // Execution Phase + Execute(); + break; + + // Message out phase + case BUS::msgout: + // Continue message out phase as long as ATN keeps asserting + if (ctrl.bus->GetATN()) { + // Data transfer is 1 byte x 1 block + ctrl.offset = 0; + ctrl.length = 1; + ctrl.blocks = 1; +#ifndef RASCSI + // Request message + ctrl.bus->SetREQ(TRUE); +#endif // RASCSI + return; + } + + // Parsing messages sent by ATN + if (scsi.atnmsg) { + i = 0; + while (i < scsi.msc) { + // Message type + data = scsi.msb[i]; + + // ABORT + if (data == 0x06) { +#if defined(DISK_LOG) + Log(Log::Normal, + "Message code ABORT $%02X", data); +#endif // DISK_LOG + BusFree(); + return; + } + + // BUS DEVICE RESET + if (data == 0x0C) { +#if defined(DISK_LOG) + Log(Log::Normal, + "Message code BUS DEVICE RESET $%02X", data); +#endif // DISK_LOG + scsi.syncoffset = 0; + BusFree(); + return; + } + + // IDENTIFY + if (data >= 0x80) { +#if defined(DISK_LOG) + Log(Log::Normal, + "Message code IDENTIFY $%02X", data); +#endif // DISK_LOG + } + + // Extended Message + if (data == 0x01) { +#if defined(DISK_LOG) + Log(Log::Normal, + "Message code EXTENDED MESSAGE $%02X", data); +#endif // DISK_LOG + + // Check only when synchronous transfer is possible + if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) { + ctrl.length = 1; + ctrl.blocks = 1; + ctrl.buffer[0] = 0x07; + MsgIn(); + return; + } + + // Transfer period factor (limited to 50 x 4 = 200ns) + scsi.syncperiod = scsi.msb[i + 3]; + if (scsi.syncperiod > 50) { + scsi.syncoffset = 50; + } + + // REQ/ACK offset(limited to 16) + scsi.syncoffset = scsi.msb[i + 4]; + if (scsi.syncoffset > 16) { + scsi.syncoffset = 16; + } + + // STDR response message generation + ctrl.length = 5; + ctrl.blocks = 1; + ctrl.buffer[0] = 0x01; + ctrl.buffer[1] = 0x03; + ctrl.buffer[2] = 0x01; + ctrl.buffer[3] = (BYTE)scsi.syncperiod; + ctrl.buffer[4] = (BYTE)scsi.syncoffset; + MsgIn(); + return; + } + + // next + i++; + } + } + + // Initialize ATN message reception status + scsi.atnmsg = FALSE; + + // Command phase + Command(); + break; + + // Data out phase + case BUS::dataout: + // Flush unit + FlushUnit(); + + // status phase + Status(); + break; + + // Other (impossible) + default: + ASSERT(FALSE); + break; + } +} + +//--------------------------------------------------------------------------- +// +// Transfer MSG +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIDEV::XferMsg(DWORD msg) +{ + ASSERT(this); + ASSERT(ctrl.phase == BUS::msgout); + + // Save message out data + if (scsi.atnmsg) { + scsi.msb[scsi.msc] = (BYTE)msg; + scsi.msc++; + scsi.msc %= 256; + } + + return TRUE; +} diff --git a/src/raspberrypi/controllers/scsidev_ctrl.h b/src/raspberrypi/controllers/scsidev_ctrl.h new file mode 100644 index 0000000..113cc73 --- /dev/null +++ b/src/raspberrypi/controllers/scsidev_ctrl.h @@ -0,0 +1,142 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI device controller ] +// +//--------------------------------------------------------------------------- +#pragma once +#include "sasidev_ctrl.h" + +//=========================================================================== +// +// SCSI Device (Interits SASI device) +// +//=========================================================================== +class SCSIDEV : public SASIDEV +{ +public: + // Internal data definition + typedef struct { + // Synchronous transfer + BOOL syncenable; // Synchronous transfer possible + int syncperiod; // Synchronous transfer period + int syncoffset; // Synchronous transfer offset + int syncack; // Number of synchronous transfer ACKs + + // ATN message + BOOL atnmsg; + int msc; + BYTE msb[256]; + } scsi_t; + +public: + // Basic Functions +#ifdef RASCSI + SCSIDEV(); +#else + SCSIDEV(Device *dev); +#endif // RASCSI + // Constructor + + void FASTCALL Reset(); + // Device Reset + + // 外部API + BUS::phase_t FASTCALL Process(); + // Run + + void FASTCALL SyncTransfer(BOOL enable) { scsi.syncenable = enable; } + // Synchronouse transfer enable setting + + // Other + BOOL FASTCALL IsSASI() const {return FALSE;} + // SASI Check + BOOL FASTCALL IsSCSI() const {return TRUE;} + // SCSI check + +private: + // Phase + void FASTCALL BusFree(); + // Bus free phase + void FASTCALL Selection(); + // Selection phase + void FASTCALL Execute(); + // Execution phase + void FASTCALL MsgOut(); + // Message out phase + void FASTCALL Error(); + // Common erorr handling + + // commands + void FASTCALL CmdInquiry(); + // INQUIRY command + void FASTCALL CmdModeSelect(); + // MODE SELECT command + void FASTCALL CmdModeSense(); + // MODE SENSE command + void FASTCALL CmdStartStop(); + // START STOP UNIT command + void FASTCALL CmdSendDiag(); + // SEND DIAGNOSTIC command + void FASTCALL CmdRemoval(); + // PREVENT/ALLOW MEDIUM REMOVAL command + void FASTCALL CmdReadCapacity(); + // READ CAPACITY command + void FASTCALL CmdRead10(); + // READ(10) command + void FASTCALL CmdWrite10(); + // WRITE(10) command + void FASTCALL CmdSeek10(); + // SEEK(10) command + void FASTCALL CmdVerify(); + // VERIFY command + void FASTCALL CmdSynchronizeCache(); + // SYNCHRONIZE CACHE command + void FASTCALL CmdReadDefectData10(); + // READ DEFECT DATA(10) command + void FASTCALL CmdReadToc(); + // READ TOC command + void FASTCALL CmdPlayAudio10(); + // PLAY AUDIO(10) command + void FASTCALL CmdPlayAudioMSF(); + // PLAY AUDIO MSF command + void FASTCALL CmdPlayAudioTrack(); + // PLAY AUDIO TRACK INDEX command + void FASTCALL CmdModeSelect10(); + // MODE SELECT(10) command + void FASTCALL CmdModeSense10(); + // MODE SENSE(10) command + void FASTCALL CmdGetMessage10(); + // GET MESSAGE(10) command + void FASTCALL CmdSendMessage10(); + // SEND MESSAGE(10) command + + // データ転送 + void FASTCALL Send(); + // Send data +#ifndef RASCSI + void FASTCALL SendNext(); + // Continue sending data +#endif // RASCSI + void FASTCALL Receive(); + // Receive data +#ifndef RASCSI + void FASTCALL ReceiveNext(); + // Continue receiving data +#endif // RASCSI + BOOL FASTCALL XferMsg(DWORD msg); + // Data transfer message + + scsi_t scsi; + // Internal data +}; + diff --git a/src/raspberrypi/disk.cpp b/src/raspberrypi/disk.cpp index 20e453b..64827ee 100644 --- a/src/raspberrypi/disk.cpp +++ b/src/raspberrypi/disk.cpp @@ -42,15 +42,7 @@ // Disk // //=========================================================================== -//#define DISK_LOG -#ifdef RASCSI -#define BENDER_SIGNATURE "RaSCSI" -// The following line was to mimic Apple's CDROM ID -// #define BENDER_SIGNATURE "SONY " -#else -#define BENDER_SIGNATURE "XM6" -#endif //=========================================================================== // @@ -2340,7533 +2332,3 @@ BOOL FASTCALL Disk::PlayAudioTrack(const DWORD *cdb) return FALSE; } -//=========================================================================== -// -// SASI Hard Disk -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -SASIHD::SASIHD() : Disk() -{ - // SASI ハードディスク - disk.id = MAKEID('S', 'A', 'H', 'D'); -} - -//--------------------------------------------------------------------------- -// -// リセット -// -//--------------------------------------------------------------------------- -void FASTCALL SASIHD::Reset() -{ - // ロック状態解除、アテンション解除 - disk.lock = FALSE; - disk.attn = FALSE; - - // Resetなし、コードをクリア - disk.reset = FALSE; - disk.code = 0x00; -} - -//--------------------------------------------------------------------------- -// -// オープン -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SASIHD::Open(const Filepath& path, BOOL /*attn*/) -{ - Fileio fio; - off64_t size; - - ASSERT(this); - ASSERT(!disk.ready); - - // Open as read-only - if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; - } - - // Get file size - size = fio.GetFileSize(); - fio.Close(); - -#if defined(USE_MZ1F23_1024_SUPPORT) - // MZ-2500/MZ-2800用 MZ-1F23(SASI 20M/セクタサイズ1024)専用 - // 20M(22437888 BS=1024 C=21912) - if (size == 0x1566000) { - // セクタサイズとブロック数 - disk.size = 10; - disk.blocks = (DWORD)(size >> 10); - - // Call the base class - return Disk::Open(path); - } -#endif // USE_MZ1F23_1024_SUPPORT - -#if defined(REMOVE_FIXED_SASIHD_SIZE) - // 256バイト単位であること - if (size & 0xff) { - return FALSE; - } - - // 10MB以上 - if (size < 0x9f5400) { - return FALSE; - } - - // 512MB程度に制限しておく - if (size > 512 * 1024 * 1024) { - return FALSE; - } -#else - // 10MB, 20MB, 40MBのみ - switch (size) { - // 10MB(10441728 BS=256 C=40788) - case 0x9f5400: - break; - - // 20MB(20748288 BS=256 C=81048) - case 0x13c9800: - break; - - // 40MB(41496576 BS=256 C=162096) - case 0x2793000: - break; - - // Other(サポートしない) - default: - return FALSE; - } -#endif // REMOVE_FIXED_SASIHD_SIZE - - // セクタサイズとブロック数 - disk.size = 8; - disk.blocks = (DWORD)(size >> 8); - - // Call the base class - return Disk::Open(path); -} - -//--------------------------------------------------------------------------- -// -// REQUEST SENSE -// -//--------------------------------------------------------------------------- -int FASTCALL SASIHD::RequestSense(const DWORD *cdb, BYTE *buf) -{ - int size; - - ASSERT(this); - ASSERT(cdb); - ASSERT(buf); - - // サイズ決定 - size = (int)cdb[4]; - ASSERT((size >= 0) && (size < 0x100)); - - // サイズ0のときに4バイト転送する(Shugart Associates System Interface仕様) - if (size == 0) { - size = 4; - } - - // SASIは非拡張フォーマットに固定 - memset(buf, 0, size); - buf[0] = (BYTE)(disk.code >> 16); - buf[1] = (BYTE)(disk.lun << 5); - - // コードをクリア - disk.code = 0x00; - - return size; -} - -//=========================================================================== -// -// SCSI ハードディスク -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -SCSIHD::SCSIHD() : Disk() -{ - // SCSI Hard Disk - disk.id = MAKEID('S', 'C', 'H', 'D'); -} - -//--------------------------------------------------------------------------- -// -// Reset -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIHD::Reset() -{ - // Unlock and release attention - disk.lock = FALSE; - disk.attn = FALSE; - - // No reset, clear code - disk.reset = FALSE; - disk.code = 0x00; -} - -//--------------------------------------------------------------------------- -// -// Open -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/) -{ - Fileio fio; - off64_t size; - - ASSERT(this); - ASSERT(!disk.ready); - - // read open required - if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; - } - - // Get file size - size = fio.GetFileSize(); - fio.Close(); - - // Must be 512 bytes - if (size & 0x1ff) { - return FALSE; - } - - // 10MB or more - if (size < 0x9f5400) { - return FALSE; - } - // 2TB according to xm6i - // There is a similar one in wxw/wxw_cfg.cpp - if (size > 2LL * 1024 * 1024 * 1024 * 1024) { - return FALSE; - } - - // sector size and number of blocks - disk.size = 9; - disk.blocks = (DWORD)(size >> 9); - - // Call base class - return Disk::Open(path); -} - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD::Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) -{ - char vendor[32]; - char product[32]; - char rev[32]; - int size; - - ASSERT(this); - ASSERT(cdb); - ASSERT(buf); - ASSERT(cdb[0] == 0x12); - - // EVPD check - if (cdb[1] & 0x01) { - disk.code = DISK_INVALIDCDB; - return 0; - } - - // Ready check (Error if no image file) - if (!disk.ready) { - disk.code = DISK_NOTREADY; - return 0; - } - - // Basic data - // buf[0] ... Direct Access Device - // buf[2] ... SCSI-2 compliant command system - // buf[3] ... SCSI-2 compliant Inquiry response - // buf[4] ... Inquiry additional data - memset(buf, 0, 8); - - // SCSI-2 p.104 4.4.3 Incorrect logical unit handling - if (((cdb[1] >> 5) & 0x07) != disk.lun) { - buf[0] = 0x7f; - } - - buf[2] = 0x02; - buf[3] = 0x02; - buf[4] = 122 + 3; // Value close to real HDD - - // Fill with blanks - memset(&buf[8], 0x20, buf[4] - 3); - - // Determine vendor name/product name - sprintf(vendor, BENDER_SIGNATURE); - size = disk.blocks >> 11; - if (size < 300) - sprintf(product, "PRODRIVE LPS%dS", size); - else if (size < 600) - sprintf(product, "MAVERICK%dS", size); - else if (size < 800) - sprintf(product, "LIGHTNING%dS", size); - else if (size < 1000) - sprintf(product, "TRAILBRAZER%dS", size); - else if (size < 2000) - sprintf(product, "FIREBALL%dS", size); - else - sprintf(product, "FBSE%d.%dS", size / 1000, (size % 1000) / 100); - - // Vendor name - memcpy(&buf[8], vendor, strlen(vendor)); - - // Product name - memcpy(&buf[16], product, strlen(product)); - - // Revision - sprintf(rev, "0%01d%01d%01d", - (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); - memcpy(&buf[32], rev, 4); - - // Size of data that can be returned - size = (buf[4] + 5); - - // Limit if the other buffer is small - if (size > (int)cdb[4]) { - size = (int)cdb[4]; - } - - // Success - disk.code = DISK_NOERROR; - return size; -} - -//--------------------------------------------------------------------------- -// -// MODE SELECT -// *Not affected by disk.code -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length) -{ - BYTE page; - int size; - - ASSERT(this); - ASSERT(buf); - ASSERT(length >= 0); - - // PF - if (cdb[1] & 0x10) { - // Mode Parameter header - if (length >= 12) { - // Check the block length bytes - size = 1 << disk.size; - if (buf[9] != (BYTE)(size >> 16) || - buf[10] != (BYTE)(size >> 8) || - buf[11] != (BYTE)size) { - // currently does not allow changing sector length - disk.code = DISK_INVALIDPRM; - return FALSE; - } - buf += 12; - length -= 12; - } - - // Parsing the page - while (length > 0) { - // Get page - page = buf[0]; - - switch (page) { - // format device - case 0x03: - // check the number of bytes in the physical sector - size = 1 << disk.size; - if (buf[0xc] != (BYTE)(size >> 8) || - buf[0xd] != (BYTE)size) { - // currently does not allow changing sector length - disk.code = DISK_INVALIDPRM; - return FALSE; - } - break; - - // CD-ROM Parameters - // According to the SONY CDU-541 manual, Page code 8 is supposed - // to set the Logical Block Adress Format, as well as the - // inactivity timer multiplier - case 0x08: - // Debug code for Issue #2: - // https://github.com/akuker/RASCSI/issues/2 - printf("[Unhandled page code] Received mode page code 8 with total length %d\n ", length); - for (int i = 0; i= (off64_t)sizeof(hdr)) { - if (!fio.Read(hdr, sizeof(hdr))) { - fio.Close(); - return FALSE; - } - } - fio.Close(); - - // 512バイト単位であること - if (size & 0x1ff) { - return FALSE; - } - - // 10MB以上 - if (size < 0x9f5400) { - return FALSE; - } - // xm6iに準じて2TB - // よく似たものが wxw/wxw_cfg.cpp にもある - if (size > 2LL * 1024 * 1024 * 1024 * 1024) { - return FALSE; - } - - // 拡張子別にパラメータを決定 - ext = path.GetFileExt(); - if (xstrcasecmp(ext, _T(".HDN")) == 0) { - // デフォルト設定としてセクタサイズ512,セクタ数25,ヘッド数8を想定 - imgoffset = 0; - imgsize = size; - sectorsize = 512; - sectors = 25; - heads = 8; - cylinders = (int)(size >> 9); - cylinders >>= 3; - cylinders /= 25; - } else if (xstrcasecmp(ext, _T(".HDI")) == 0) { // Anex86 HD image? - imgoffset = getDwordLE(&hdr[4 + 4]); - imgsize = getDwordLE(&hdr[4 + 4 + 4]); - sectorsize = getDwordLE(&hdr[4 + 4 + 4 + 4]); - sectors = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4]); - heads = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4]); - cylinders = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4 + 4]); - } else if (xstrcasecmp(ext, _T(".NHD")) == 0 && - memcmp(hdr, "T98HDDIMAGE.R0\0", 15) == 0) { // T98Next HD image? - imgoffset = getDwordLE(&hdr[0x10 + 0x100]); - cylinders = getDwordLE(&hdr[0x10 + 0x100 + 4]); - heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]); - sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]); - sectorsize = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2 + 2]); - imgsize = (off64_t)cylinders * heads * sectors * sectorsize; - } - - // セクタサイズは256または512をサポート - if (sectorsize != 256 && sectorsize != 512) { - return FALSE; - } - - // イメージサイズの整合性チェック - if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) { - return FALSE; - } - - // セクタサイズ - for(disk.size = 16; disk.size > 0; --(disk.size)) { - if ((1 << disk.size) == sectorsize) - break; - } - if (disk.size <= 0 || disk.size > 16) { - return FALSE; - } - - // ブロック数 - disk.blocks = (DWORD)(imgsize >> disk.size); - disk.imgoffset = imgoffset; - - // Call the base class - return Disk::Open(path); -} - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD_NEC::Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) -{ - int size; - - // 基底クラス - size = SCSIHD::Inquiry(cdb, buf, major, minor); - - // 基底クラスでエラーなら終了 - if (size == 0) { - return 0; - } - - // SCSI1相当に変更 - buf[2] = 0x01; - buf[3] = 0x01; - - // Replace Vendor name - buf[8] = 'N'; - buf[9] = 'E'; - buf[10] = 'C'; - - return size; -} - -//--------------------------------------------------------------------------- -// -// エラーページ追加 -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD_NEC::AddError(BOOL change, BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - // Set the message length - buf[0] = 0x01; - buf[1] = 0x06; - - // No changeable area - if (change) { - return 8; - } - - // リトライカウントは0、リミットタイムは装置内部のデフォルト値を使用 - return 8; -} - -//--------------------------------------------------------------------------- -// -// フォーマットページ追加 -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf) -{ - int size; - - ASSERT(this); - ASSERT(buf); - - // Set the message length - buf[0] = 0x80 | 0x03; - buf[1] = 0x16; - - // 物理セクタのバイト数は変更可能に見せる(実際には変更できないが) - if (change) { - buf[0xc] = 0xff; - buf[0xd] = 0xff; - return 24; - } - - if (disk.ready) { - // 1ゾーンのトラック数を設定(PC-9801-55はこの値を見ているようだ) - buf[0x2] = (BYTE)(heads >> 8); - buf[0x3] = (BYTE)heads; - - // 1トラックのセクタ数を設定 - buf[0xa] = (BYTE)(sectors >> 8); - buf[0xb] = (BYTE)sectors; - - // 物理セクタのバイト数を設定 - size = 1 << disk.size; - buf[0xc] = (BYTE)(size >> 8); - buf[0xd] = (BYTE)size; - } - - // リムーバブル属性を設定(昔の名残) - if (disk.removable) { - buf[20] = 0x20; - } - - return 24; -} - -//--------------------------------------------------------------------------- -// -// ドライブページ追加 -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - // Set the message length - buf[0] = 0x04; - buf[1] = 0x12; - - // No changeable area - if (change) { - return 20; - } - - if (disk.ready) { - // シリンダ数を設定 - buf[0x2] = (BYTE)(cylinders >> 16); - buf[0x3] = (BYTE)(cylinders >> 8); - buf[0x4] = (BYTE)cylinders; - - // ヘッド数を設定 - buf[0x5] = (BYTE)heads; - } - - return 20; -} - -//=========================================================================== -// -// SCSI hard disk (Macintosh Apple genuine) -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -SCSIHD_APPLE::SCSIHD_APPLE() : SCSIHD() -{ -} - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD_APPLE::Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) -{ - int size; - char vendor[32]; - char product[32]; - - // Call the base class - size = SCSIHD::Inquiry(cdb, buf, major, minor); - - // End if there is an error in the base class - if (size == 0) { - return 0; - } - - // Vendor name - sprintf(vendor, " SEAGATE"); - memcpy(&buf[8], vendor, strlen(vendor)); - - // Product name - sprintf(product, " ST225N"); - memcpy(&buf[16], product, strlen(product)); - - return size; -} - -//--------------------------------------------------------------------------- -// -// Add Vendor special page -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIHD_APPLE::AddVendor(int page, BOOL change, BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - // Page code 48 - if ((page != 0x30) && (page != 0x3f)) { - return 0; - } - - // Set the message length - buf[0] = 0x30; - buf[1] = 0x1c; - - // No changeable area - if (change) { - return 30; - } - - // APPLE COMPUTER, INC. - memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20); - - return 30; -} - -//=========================================================================== -// -// SCSI magneto-optical disk -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -SCSIMO::SCSIMO() : Disk() -{ - // SCSI magneto-optical disk - disk.id = MAKEID('S', 'C', 'M', 'O'); - - // Set as removable - disk.removable = TRUE; -} - -//--------------------------------------------------------------------------- -// -// Open -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIMO::Open(const Filepath& path, BOOL attn) -{ - Fileio fio; - off64_t size; - - ASSERT(this); - ASSERT(!disk.ready); - - // Open as read-only - if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; - } - - // Get file size - size = fio.GetFileSize(); - fio.Close(); - - switch (size) { - // 128MB - case 0x797f400: - disk.size = 9; - disk.blocks = 248826; - break; - - // 230MB - case 0xd9eea00: - disk.size = 9; - disk.blocks = 446325; - break; - - // 540MB - case 0x1fc8b800: - disk.size = 9; - disk.blocks = 1041500; - break; - - // 640MB - case 0x25e28000: - disk.size = 11; - disk.blocks = 310352; - break; - - // Other (this is an error) - default: - return FALSE; - } - - // Call the base class - Disk::Open(path); - - // Attention if ready - if (disk.ready && attn) { - disk.attn = TRUE; - } - - return TRUE; -} - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Load -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIMO::Load(Fileio *fio, int ver) -{ - DWORD sz; - disk_t buf; - DWORD padding; - Filepath path; - - ASSERT(this); - ASSERT(fio); - ASSERT(ver >= 0x0200); - - // Prior to version 2.03, the disk was not saved - if (ver <= 0x0202) { - return TRUE; - } - - // load size, match - if (!fio->Read(&sz, sizeof(sz))) { - return FALSE; - } - if (sz != 52) { - return FALSE; - } - - // load into buffer - PROP_IMPORT(fio, buf.id); - PROP_IMPORT(fio, buf.ready); - PROP_IMPORT(fio, buf.writep); - PROP_IMPORT(fio, buf.readonly); - PROP_IMPORT(fio, buf.removable); - PROP_IMPORT(fio, buf.lock); - PROP_IMPORT(fio, buf.attn); - PROP_IMPORT(fio, buf.reset); - PROP_IMPORT(fio, buf.size); - PROP_IMPORT(fio, buf.blocks); - PROP_IMPORT(fio, buf.lun); - PROP_IMPORT(fio, buf.code); - PROP_IMPORT(fio, padding); - - // Load path - if (!path.Load(fio, ver)) { - return FALSE; - } - - // Always eject - Eject(TRUE); - - // Move only if IDs match - if (disk.id != buf.id) { - // Not MO at the time of save. Maintain eject status - return TRUE; - } - - // Re-try opening - if (!Open(path, FALSE)) { - // Cannot reopen. Maintain eject status - return TRUE; - } - - // Disk cache is created in Open. Move property only - if (!disk.readonly) { - disk.writep = buf.writep; - } - disk.lock = buf.lock; - disk.attn = buf.attn; - disk.reset = buf.reset; - disk.lun = buf.lun; - disk.code = buf.code; - - // loaded successfully - return TRUE; -} -#endif // RASCSI - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIMO::Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) -{ - int size; - char rev[32]; - - ASSERT(this); - ASSERT(cdb); - ASSERT(buf); - ASSERT(cdb[0] == 0x12); - - // EVPD check - if (cdb[1] & 0x01) { - disk.code = DISK_INVALIDCDB; - return FALSE; - } - - // 基本データ - // buf[0] ... Optical Memory Device - // buf[1] ... Removable - // buf[2] ... SCSI-2 compliant command system - // buf[3] ... SCSI-2 compliant Inquiry response - // buf[4] ... Inquiry additional data - memset(buf, 0, 8); - buf[0] = 0x07; - - // SCSI-2 p.104 4.4.3 Incorrect logical unit handling - if (((cdb[1] >> 5) & 0x07) != disk.lun) { - buf[0] = 0x7f; - } - - buf[1] = 0x80; - buf[2] = 0x02; - buf[3] = 0x02; - buf[4] = 36 - 5; // required - - // Fill with blanks - memset(&buf[8], 0x20, buf[4] - 3); - - // Vendor name - memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); - - // Product name - memcpy(&buf[16], "M2513A", 6); - - // Revision (XM6 version number) - sprintf(rev, "0%01d%01d%01d", - (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); - memcpy(&buf[32], rev, 4); - - // Size return data - size = (buf[4] + 5); - - // Limit the size if the buffer is too small - if (size > (int)cdb[4]) { - size = (int)cdb[4]; - } - - // Success - disk.code = DISK_NOERROR; - return size; -} - -//--------------------------------------------------------------------------- -// -// MODE SELECT -// *Not affected by disk.code -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length) -{ - int page; - int size; - - ASSERT(this); - ASSERT(buf); - ASSERT(length >= 0); - - // PF - if (cdb[1] & 0x10) { - // Mode Parameter header - if (length >= 12) { - // Check the block length (in bytes) - size = 1 << disk.size; - if (buf[9] != (BYTE)(size >> 16) || - buf[10] != (BYTE)(size >> 8) || buf[11] != (BYTE)size) { - // Currently does not allow changing sector length - disk.code = DISK_INVALIDPRM; - return FALSE; - } - buf += 12; - length -= 12; - } - - // Parsing the page - while (length > 0) { - // Get the page - page = buf[0]; - - switch (page) { - // format device - case 0x03: - // Check the number of bytes in the physical sector - size = 1 << disk.size; - if (buf[0xc] != (BYTE)(size >> 8) || - buf[0xd] != (BYTE)size) { - // Currently does not allow changing sector length - disk.code = DISK_INVALIDPRM; - return FALSE; - } - break; - // vendor unique format - case 0x20: - // just ignore, for now - break; - - // Other page - default: - break; - } - - // Advance to the next page - size = buf[1] + 2; - length -= size; - buf += size; - } - } - - // Do not generate an error for the time being (MINIX) - disk.code = DISK_NOERROR; - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Vendor Unique Format Page 20h (MO) -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIMO::AddVendor(int page, BOOL change, BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - // Page code 20h - if ((page != 0x20) && (page != 0x3f)) { - return 0; - } - - // Set the message length - buf[0] = 0x20; - buf[1] = 0x0a; - - // No changeable area - if (change) { - return 12; - } - - /* - mode page code 20h - Vendor Unique Format Page - format mode XXh type 0 - information: http://h20628.www2.hp.com/km-ext/kmcsdirect/emr_na-lpg28560-1.pdf - - offset description - 02h format mode - 03h type of format (0) - 04~07h size of user band (total sectors?) - 08~09h size of spare band (spare sectors?) - 0A~0Bh number of bands - - actual value of each 3.5inches optical medium (grabbed by Fujitsu M2513EL) - - 128M 230M 540M 640M - --------------------------------------------------- - size of user band 3CBFAh 6CF75h FE45Ch 4BC50h - size of spare band 0400h 0401h 08CAh 08C4h - number of bands 0001h 000Ah 0012h 000Bh - - further information: http://r2089.blog36.fc2.com/blog-entry-177.html - */ - - if (disk.ready) { - unsigned spare = 0; - unsigned bands = 0; - - if (disk.size == 9) switch (disk.blocks) { - // 128MB - case 248826: - spare = 1024; - bands = 1; - break; - - // 230MB - case 446325: - spare = 1025; - bands = 10; - break; - - // 540MB - case 1041500: - spare = 2250; - bands = 18; - break; - } - - if (disk.size == 11) switch (disk.blocks) { - // 640MB - case 310352: - spare = 2244; - bands = 11; - break; - - // 1.3GB (lpproj: not tested with real device) - case 605846: - spare = 4437; - bands = 18; - break; - } - - buf[2] = 0; // format mode - buf[3] = 0; // type of format - buf[4] = (BYTE)(disk.blocks >> 24); - buf[5] = (BYTE)(disk.blocks >> 16); - buf[6] = (BYTE)(disk.blocks >> 8); - buf[7] = (BYTE)disk.blocks; - buf[8] = (BYTE)(spare >> 8); - buf[9] = (BYTE)spare; - buf[10] = (BYTE)(bands >> 8); - buf[11] = (BYTE)bands; - } - - return 12; -} - -//=========================================================================== -// -// CD Track -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -CDTrack::CDTrack(SCSICD *scsicd) -{ - ASSERT(scsicd); - - // Set parent CD-ROM device - cdrom = scsicd; - - // Track defaults to disabled - valid = FALSE; - - // Initialize other data - track_no = -1; - first_lba = 0; - last_lba = 0; - audio = FALSE; - raw = FALSE; -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -CDTrack::~CDTrack() -{ -} - -//--------------------------------------------------------------------------- -// -// Init -// -//--------------------------------------------------------------------------- -BOOL FASTCALL CDTrack::Init(int track, DWORD first, DWORD last) -{ - ASSERT(this); - ASSERT(!valid); - ASSERT(track >= 1); - ASSERT(first < last); - - // Set and enable track number - track_no = track; - valid = TRUE; - - // Remember LBA - first_lba = first; - last_lba = last; - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Set Path -// -//--------------------------------------------------------------------------- -void FASTCALL CDTrack::SetPath(BOOL cdda, const Filepath& path) -{ - ASSERT(this); - ASSERT(valid); - - // CD-DA or data - audio = cdda; - - // Remember the path - imgpath = path; -} - -//--------------------------------------------------------------------------- -// -// Get Path -// -//--------------------------------------------------------------------------- -void FASTCALL CDTrack::GetPath(Filepath& path) const -{ - ASSERT(this); - ASSERT(valid); - - // Return the path (by reference) - path = imgpath; -} - -//--------------------------------------------------------------------------- -// -// Add Index -// -//--------------------------------------------------------------------------- -void FASTCALL CDTrack::AddIndex(int index, DWORD lba) -{ - ASSERT(this); - ASSERT(valid); - ASSERT(index > 0); - ASSERT(first_lba <= lba); - ASSERT(lba <= last_lba); - - // Currently does not support indexes - ASSERT(FALSE); -} - -//--------------------------------------------------------------------------- -// -// Gets the start of LBA -// -//--------------------------------------------------------------------------- -DWORD FASTCALL CDTrack::GetFirst() const -{ - ASSERT(this); - ASSERT(valid); - ASSERT(first_lba < last_lba); - - return first_lba; -} - -//--------------------------------------------------------------------------- -// -// Get the end of LBA -// -//--------------------------------------------------------------------------- -DWORD FASTCALL CDTrack::GetLast() const -{ - ASSERT(this); - ASSERT(valid); - ASSERT(first_lba < last_lba); - - return last_lba; -} - -//--------------------------------------------------------------------------- -// -// Get the number of blocks -// -//--------------------------------------------------------------------------- -DWORD FASTCALL CDTrack::GetBlocks() const -{ - ASSERT(this); - ASSERT(valid); - ASSERT(first_lba < last_lba); - - // Calculate from start LBA and end LBA - return (DWORD)(last_lba - first_lba + 1); -} - -//--------------------------------------------------------------------------- -// -// Get track number -// -//--------------------------------------------------------------------------- -int FASTCALL CDTrack::GetTrackNo() const -{ - ASSERT(this); - ASSERT(valid); - ASSERT(track_no >= 1); - - return track_no; -} - -//--------------------------------------------------------------------------- -// -// Is valid block -// -//--------------------------------------------------------------------------- -BOOL FASTCALL CDTrack::IsValid(DWORD lba) const -{ - ASSERT(this); - - // FALSE if the track itself is invalid - if (!valid) { - return FALSE; - } - - // If the block is BEFORE the first block - if (lba < first_lba) { - return FALSE; - } - - // If the block is AFTER the last block - if (last_lba < lba) { - return FALSE; - } - - // This track is valid - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Is audio track -// -//--------------------------------------------------------------------------- -BOOL FASTCALL CDTrack::IsAudio() const -{ - ASSERT(this); - ASSERT(valid); - - return audio; -} - -//=========================================================================== -// -// CD-DA Buffer -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -CDDABuf::CDDABuf() -{ -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -CDDABuf::~CDDABuf() -{ -} - -//=========================================================================== -// -// SCSI CD-ROM -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -SCSICD::SCSICD() : Disk() -{ - int i; - - // SCSI CD-ROM - disk.id = MAKEID('S', 'C', 'C', 'D'); - - // removable, write protected - disk.removable = TRUE; - disk.writep = TRUE; - - // NOT in raw format - rawfile = FALSE; - - // Frame initialization - frame = 0; - - // Track initialization - for (i = 0; i < TrackMax; i++) { - track[i] = NULL; - } - tracks = 0; - dataindex = -1; - audioindex = -1; -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -SCSICD::~SCSICD() -{ - // Clear track - ClearTrack(); -} - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Load -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::Load(Fileio *fio, int ver) -{ - DWORD sz; - disk_t buf; - DWORD padding; - Filepath path; - - ASSERT(this); - ASSERT(fio); - ASSERT(ver >= 0x0200); - - // Prior to version 2.03, the disk was not saved - if (ver <= 0x0202) { - return TRUE; - } - - // load size, match - if (!fio->Read(&sz, sizeof(sz))) { - return FALSE; - } - if (sz != 52) { - return FALSE; - } - - // load into buffer - PROP_IMPORT(fio, buf.id); - PROP_IMPORT(fio, buf.ready); - PROP_IMPORT(fio, buf.writep); - PROP_IMPORT(fio, buf.readonly); - PROP_IMPORT(fio, buf.removable); - PROP_IMPORT(fio, buf.lock); - PROP_IMPORT(fio, buf.attn); - PROP_IMPORT(fio, buf.reset); - PROP_IMPORT(fio, buf.size); - PROP_IMPORT(fio, buf.blocks); - PROP_IMPORT(fio, buf.lun); - PROP_IMPORT(fio, buf.code); - PROP_IMPORT(fio, padding); - - // Load path - if (!path.Load(fio, ver)) { - return FALSE; - } - - // Always eject - Eject(TRUE); - - // move only if IDs match - if (disk.id != buf.id) { - // It was not a CD-ROM when saving. Maintain eject status - return TRUE; - } - - // Try to reopen - if (!Open(path, FALSE)) { - // Cannot reopen. Maintain eject status - return TRUE; - } - - // Disk cache is created in Open. Move property only - if (!disk.readonly) { - disk.writep = buf.writep; - } - disk.lock = buf.lock; - disk.attn = buf.attn; - disk.reset = buf.reset; - disk.lun = buf.lun; - disk.code = buf.code; - - // Discard the disk cache again - if (disk.dcache) { - delete disk.dcache; - disk.dcache = NULL; - } - disk.dcache = NULL; - - // Tentative - disk.blocks = track[0]->GetBlocks(); - if (disk.blocks > 0) { - // Recreate the disk cache - track[0]->GetPath(path); - disk.dcache = new DiskCache(path, disk.size, disk.blocks); - disk.dcache->SetRawMode(rawfile); - - // Reset data index - dataindex = 0; - } - - return TRUE; -} -#endif // RASCSI - -//--------------------------------------------------------------------------- -// -// Open -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::Open(const Filepath& path, BOOL attn) -{ - Fileio fio; - off64_t size; - TCHAR file[5]; - - ASSERT(this); - ASSERT(!disk.ready); - - // Initialization, track clear - disk.blocks = 0; - rawfile = FALSE; - ClearTrack(); - - // Open as read-only - if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; - } - - // Close and transfer for physical CD access - if (path.GetPath()[0] == _T('\\')) { - // Close - fio.Close(); - - // Open physical CD - if (!OpenPhysical(path)) { - return FALSE; - } - } else { - // Get file size - size = fio.GetFileSize(); - if (size <= 4) { - fio.Close(); - return FALSE; - } - - // Judge whether it is a CUE sheet or an ISO file - fio.Read(file, 4); - file[4] = '\0'; - fio.Close(); - - // If it starts with FILE, consider it as a CUE sheet - if (xstrncasecmp(file, _T("FILE"), 4) == 0) { - // Open as CUE - if (!OpenCue(path)) { - return FALSE; - } - } else { - // Open as ISO - if (!OpenIso(path)) { - return FALSE; - } - } - } - - // Successful opening - ASSERT(disk.blocks > 0); - disk.size = 11; - - // Call the base class - Disk::Open(path); - - // Set RAW flag - ASSERT(disk.dcache); - disk.dcache->SetRawMode(rawfile); - - // Since it is a ROM media, writing is not possible - disk.writep = TRUE; - - // Attention if ready - if (disk.ready && attn) { - disk.attn = TRUE; - } - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Open (CUE) -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::OpenCue(const Filepath& /*path*/) -{ - ASSERT(this); - - // Always fail - return FALSE; -} - -//--------------------------------------------------------------------------- -// -// オープン(ISO) -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::OpenIso(const Filepath& path) -{ - Fileio fio; - off64_t size; - BYTE header[12]; - BYTE sync[12]; - - ASSERT(this); - - // Open as read-only - if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; - } - - // Get file size - size = fio.GetFileSize(); - if (size < 0x800) { - fio.Close(); - return FALSE; - } - - // Read the first 12 bytes and close - if (!fio.Read(header, sizeof(header))) { - fio.Close(); - return FALSE; - } - - // Check if it is RAW format - memset(sync, 0xff, sizeof(sync)); - sync[0] = 0x00; - sync[11] = 0x00; - rawfile = FALSE; - if (memcmp(header, sync, sizeof(sync)) == 0) { - // 00,FFx10,00, so it is presumed to be RAW format - if (!fio.Read(header, 4)) { - fio.Close(); - return FALSE; - } - - // Supports MODE1/2048 or MODE1/2352 only - if (header[3] != 0x01) { - // Different mode - fio.Close(); - return FALSE; - } - - // Set to RAW file - rawfile = TRUE; - } - fio.Close(); - - if (rawfile) { - // Size must be a multiple of 2536 and less than 700MB - if (size % 0x930) { - return FALSE; - } - if (size > 912579600) { - return FALSE; - } - - // Set the number of blocks - disk.blocks = (DWORD)(size / 0x930); - } else { - // Size must be a multiple of 2048 and less than 700MB - if (size & 0x7ff) { - return FALSE; - } - if (size > 0x2bed5000) { - return FALSE; - } - - // Set the number of blocks - disk.blocks = (DWORD)(size >> 11); - } - - // Create only one data track - ASSERT(!track[0]); - track[0] = new CDTrack(this); - track[0]->Init(1, 0, disk.blocks - 1); - track[0]->SetPath(FALSE, path); - tracks = 1; - dataindex = 0; - - // Successful opening - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Open (Physical) -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::OpenPhysical(const Filepath& path) -{ - Fileio fio; - off64_t size; - - ASSERT(this); - - // Open as read-only - if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; - } - - // Get size - size = fio.GetFileSize(); - if (size < 0x800) { - fio.Close(); - return FALSE; - } - - // Close - fio.Close(); - - // Size must be a multiple of 2048 and less than 700MB - if (size & 0x7ff) { - return FALSE; - } - if (size > 0x2bed5000) { - return FALSE; - } - - // Set the number of blocks - disk.blocks = (DWORD)(size >> 11); - - // Create only one data track - ASSERT(!track[0]); - track[0] = new CDTrack(this); - track[0]->Init(1, 0, disk.blocks - 1); - track[0]->SetPath(FALSE, path); - tracks = 1; - dataindex = 0; - - // Successful opening - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int FASTCALL SCSICD::Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) -{ - char rev[32]; - int size; - - ASSERT(this); - ASSERT(cdb); - ASSERT(buf); - ASSERT(cdb[0] == 0x12); - - // EVPD check - if (cdb[1] & 0x01) { - disk.code = DISK_INVALIDCDB; - return FALSE; - } - - // 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 - memset(buf, 0, 8); - buf[0] = 0x05; - - // SCSI-2 p.104 4.4.3 Incorrect logical unit handling - if (((cdb[1] >> 5) & 0x07) != disk.lun) { - buf[0] = 0x7f; - } - - buf[1] = 0x80; - buf[2] = 0x02; - buf[3] = 0x02; - buf[4] = 36 - 5; // Required - - // Fill with blanks - memset(&buf[8], 0x20, buf[4] - 3); - - // Vendor name - memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); - - // Product name - memcpy(&buf[16], "CD-ROM CDU-55S", 14); - - // Revision (XM6 version number) - sprintf(rev, "0%01d%01d%01d", - (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); - memcpy(&buf[32], rev, 4); -// -// The following code worked with the modified Apple CD-ROM drivers. Need to -// test with the original code to see if it works as well.... -// buf[4] = 42; // Required -// -// // Fill with blanks -// memset(&buf[8], 0x20, buf[4] - 3); -// -// // Vendor name -// memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); -// -// // Product name -// memcpy(&buf[16], "CD-ROM CDU-8003A", 16); -// -// // Revision (XM6 version number) -//// sprintf(rev, "1.9a", -// //// (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); -// memcpy(&buf[32], "1.9a", 4); -// -// //strcpy(&buf[35],"A1.9a"); -// buf[36]=0x20; -// memcpy(&buf[37],"1999/01/01",10); - - // Size of data that can be returned - size = (buf[4] + 5); - - // Limit if the other buffer is small - if (size > (int)cdb[4]) { - size = (int)cdb[4]; - } - - // Success - disk.code = DISK_NOERROR; - return size; -} - -//--------------------------------------------------------------------------- -// -// READ -// -//--------------------------------------------------------------------------- -int FASTCALL SCSICD::Read(BYTE *buf, DWORD block) -{ - int index; - Filepath path; - - ASSERT(this); - ASSERT(buf); - - // Status check - if (!CheckReady()) { - return 0; - } - - // Search for the track - index = SearchTrack(block); - - // if invalid, out of range - if (index < 0) { - disk.code = DISK_INVALIDLBA; - return 0; - } - ASSERT(track[index]); - - // If different from the current data track - if (dataindex != index) { - // Delete current disk cache (no need to save) - delete disk.dcache; - disk.dcache = NULL; - - // Reset the number of blocks - disk.blocks = track[index]->GetBlocks(); - ASSERT(disk.blocks > 0); - - // Recreate the disk cache - track[index]->GetPath(path); - disk.dcache = new DiskCache(path, disk.size, disk.blocks); - disk.dcache->SetRawMode(rawfile); - - // Reset data index - dataindex = index; - } - - // Base class - ASSERT(dataindex >= 0); - return Disk::Read(buf, block); -} - -//--------------------------------------------------------------------------- -// -// READ TOC -// -//--------------------------------------------------------------------------- -int FASTCALL SCSICD::ReadToc(const DWORD *cdb, BYTE *buf) -{ - int last; - int index; - int length; - int loop; - int i; - BOOL msf; - DWORD lba; - - ASSERT(this); - ASSERT(cdb); - ASSERT(cdb[0] == 0x43); - ASSERT(buf); - - // Check if ready - if (!CheckReady()) { - return 0; - } - - // If ready, there is at least one track - ASSERT(tracks > 0); - ASSERT(track[0]); - - // Get allocation length, clear buffer - length = cdb[7] << 8; - length |= cdb[8]; - memset(buf, 0, length); - - // Get MSF Flag - if (cdb[1] & 0x02) { - msf = TRUE; - } else { - msf = FALSE; - } - - // Get and check the last track number - last = track[tracks - 1]->GetTrackNo(); - if ((int)cdb[6] > last) { - // Except for AA - if (cdb[6] != 0xaa) { - disk.code = DISK_INVALIDCDB; - return 0; - } - } - - // Check start index - index = 0; - if (cdb[6] != 0x00) { - // Advance the track until the track numbers match - while (track[index]) { - if ((int)cdb[6] == track[index]->GetTrackNo()) { - break; - } - index++; - } - - // AA if not found or internal error - if (!track[index]) { - if (cdb[6] == 0xaa) { - // Returns the final LBA+1 because it is AA - buf[0] = 0x00; - buf[1] = 0x0a; - buf[2] = (BYTE)track[0]->GetTrackNo(); - buf[3] = (BYTE)last; - buf[6] = 0xaa; - lba = track[tracks - 1]->GetLast() + 1; - if (msf) { - LBAtoMSF(lba, &buf[8]); - } else { - buf[10] = (BYTE)(lba >> 8); - buf[11] = (BYTE)lba; - } - return length; - } - - // Otherwise, error - disk.code = DISK_INVALIDCDB; - return 0; - } - } - - // Number of track descriptors returned this time (number of loops) - loop = last - track[index]->GetTrackNo() + 1; - ASSERT(loop >= 1); - - // Create header - buf[0] = (BYTE)(((loop << 3) + 2) >> 8); - buf[1] = (BYTE)((loop << 3) + 2); - buf[2] = (BYTE)track[0]->GetTrackNo(); - buf[3] = (BYTE)last; - buf += 4; - - // Loop.... - for (i = 0; i < loop; i++) { - // ADR and Control - if (track[index]->IsAudio()) { - // audio track - buf[1] = 0x10; - } else { - // data track - buf[1] = 0x14; - } - - // track number - buf[2] = (BYTE)track[index]->GetTrackNo(); - - // track address - if (msf) { - LBAtoMSF(track[index]->GetFirst(), &buf[4]); - } else { - buf[6] = (BYTE)(track[index]->GetFirst() >> 8); - buf[7] = (BYTE)(track[index]->GetFirst()); - } - - // Advance buffer pointer and index - buf += 8; - index++; - } - - // Always return only the allocation length - return length; -} - -//--------------------------------------------------------------------------- -// -// PLAY AUDIO -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::PlayAudio(const DWORD* /*cdb*/) -{ - ASSERT(this); - - disk.code = DISK_INVALIDCDB; - return FALSE; -} - -//--------------------------------------------------------------------------- -// -// PLAY AUDIO MSF -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::PlayAudioMSF(const DWORD* /*cdb*/) -{ - ASSERT(this); - - disk.code = DISK_INVALIDCDB; - return FALSE; -} - -//--------------------------------------------------------------------------- -// -// PLAY AUDIO TRACK -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::PlayAudioTrack(const DWORD* /*cdb*/) -{ - ASSERT(this); - - disk.code = DISK_INVALIDCDB; - return FALSE; -} - -//--------------------------------------------------------------------------- -// -// LBA→MSF Conversion -// -//--------------------------------------------------------------------------- -void FASTCALL SCSICD::LBAtoMSF(DWORD lba, BYTE *msf) const -{ - DWORD m; - DWORD s; - DWORD f; - - ASSERT(this); - - // 75 and 75*60 get the remainder - m = lba / (75 * 60); - s = lba % (75 * 60); - f = s % 75; - s /= 75; - - // The base point is M=0, S=2, F=0 - s += 2; - if (s >= 60) { - s -= 60; - m++; - } - - // Store - ASSERT(m < 0x100); - ASSERT(s < 60); - ASSERT(f < 75); - msf[0] = 0x00; - msf[1] = (BYTE)m; - msf[2] = (BYTE)s; - msf[3] = (BYTE)f; -} - -//--------------------------------------------------------------------------- -// -// MSF→LBA Conversion -// -//--------------------------------------------------------------------------- -DWORD FASTCALL SCSICD::MSFtoLBA(const BYTE *msf) const -{ - DWORD lba; - - ASSERT(this); - ASSERT(msf[2] < 60); - ASSERT(msf[3] < 75); - - // 1, 75, add up in multiples of 75*60 - lba = msf[1]; - lba *= 60; - lba += msf[2]; - lba *= 75; - lba += msf[3]; - - // Since the base point is M=0, S=2, F=0, subtract 150 - lba -= 150; - - return lba; -} - -//--------------------------------------------------------------------------- -// -// Clear Track -// -//--------------------------------------------------------------------------- -void FASTCALL SCSICD::ClearTrack() -{ - int i; - - ASSERT(this); - - // delete the track object - for (i = 0; i < TrackMax; i++) { - if (track[i]) { - delete track[i]; - track[i] = NULL; - } - } - - // Number of tracks is 0 - tracks = 0; - - // No settings for data and audio - dataindex = -1; - audioindex = -1; -} - -//--------------------------------------------------------------------------- -// -// Track Search -// * Returns -1 if not found -// -//--------------------------------------------------------------------------- -int FASTCALL SCSICD::SearchTrack(DWORD lba) const -{ - int i; - - ASSERT(this); - - // Track loop - for (i = 0; i < tracks; i++) { - // Listen to the track - ASSERT(track[i]); - if (track[i]->IsValid(lba)) { - return i; - } - } - - // Track wasn't found - return -1; -} - -//--------------------------------------------------------------------------- -// -// Next Frame -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSICD::NextFrame() -{ - ASSERT(this); - ASSERT((frame >= 0) && (frame < 75)); - - // set the frame in the range 0-74 - frame = (frame + 1) % 75; - - // FALSE after one lap - if (frame != 0) { - return TRUE; - } else { - return FALSE; - } -} - -//--------------------------------------------------------------------------- -// -// Get CD-DA buffer -// -//--------------------------------------------------------------------------- -void FASTCALL SCSICD::GetBuf( - DWORD* /*buffer*/, int /*samples*/, DWORD /*rate*/) -{ - ASSERT(this); -} - -//=========================================================================== -// -// SCSI Host Bridge -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -SCSIBR::SCSIBR() : Disk() -{ - // Host Bridge - disk.id = MAKEID('S', 'C', 'B', 'R'); - -#if defined(RASCSI) && !defined(BAREMETAL) - // TAP Driver Generation - tap = new CTapDriver(); - m_bTapEnable = tap->Init(); - - // Generate MAC Address - memset(mac_addr, 0x00, 6); - if (m_bTapEnable) { - tap->GetMacAddr(mac_addr); - mac_addr[5]++; - } - - // Packet reception flag OFF - packet_enable = FALSE; -#endif // RASCSI && !BAREMETAL - - // Create host file system - fs = new CFileSys(); - fs->Reset(); -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -SCSIBR::~SCSIBR() -{ -#if defined(RASCSI) && !defined(BAREMETAL) - // TAP driver release - if (tap) { - tap->Cleanup(); - delete tap; - } -#endif // RASCSI && !BAREMETAL - - // Release host file system - if (fs) { - fs->Reset(); - delete fs; - } -} - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIBR::Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) -{ - char rev[32]; - int size; - - ASSERT(this); - ASSERT(cdb); - ASSERT(buf); - ASSERT(cdb[0] == 0x12); - - // EVPD check - if (cdb[1] & 0x01) { - disk.code = DISK_INVALIDCDB; - return FALSE; - } - - // Basic data - // buf[0] ... Communication Device - // buf[2] ... SCSI-2 compliant command system - // buf[3] ... SCSI-2 compliant Inquiry response - // buf[4] ... Inquiry additional data - memset(buf, 0, 8); - buf[0] = 0x09; - - // SCSI-2 p.104 4.4.3 Incorrect logical unit handling - if (((cdb[1] >> 5) & 0x07) != disk.lun) { - buf[0] = 0x7f; - } - - buf[2] = 0x02; - buf[3] = 0x02; - buf[4] = 36 - 5 + 8; // required + 8 byte extension - - // Fill with blanks - memset(&buf[8], 0x20, buf[4] - 3); - - // Vendor name - memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); - - // Product name - memcpy(&buf[16], "RASCSI BRIDGE", 13); - - // Revision (XM6 version number) - sprintf(rev, "0%01d%01d%01d", - (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); - memcpy(&buf[32], rev, 4); - - // Optional function valid flag - buf[36] = '0'; - -#if defined(RASCSI) && !defined(BAREMETAL) - // TAP Enable - if (m_bTapEnable) { - buf[37] = '1'; - } -#endif // RASCSI && !BAREMETAL - - // CFileSys Enable - buf[38] = '1'; - - // Size of data that can be returned - size = (buf[4] + 5); - - // Limit if the other buffer is small - if (size > (int)cdb[4]) { - size = (int)cdb[4]; - } - - // Success - disk.code = DISK_NOERROR; - return size; -} - -//--------------------------------------------------------------------------- -// -// TEST UNIT READY -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIBR::TestUnitReady(const DWORD* /*cdb*/) -{ - ASSERT(this); - - // TEST UNIT READY Success - disk.code = DISK_NOERROR; - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// GET MESSAGE(10) -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf) -{ - int type; - int phase; -#if defined(RASCSI) && !defined(BAREMETAL) - int func; - int total_len; - int i; -#endif // RASCSI && !BAREMETAL - - ASSERT(this); - - // Type - type = cdb[2]; - -#if defined(RASCSI) && !defined(BAREMETAL) - // Function number - func = cdb[3]; -#endif // RASCSI && !BAREMETAL - - // Phase - phase = cdb[9]; - - switch (type) { -#if defined(RASCSI) && !defined(BAREMETAL) - case 1: // Ethernet - // Do not process if TAP is invalid - if (!m_bTapEnable) { - return 0; - } - - switch (func) { - case 0: // Get MAC address - return GetMacAddr(buf); - - case 1: // Received packet acquisition (size/buffer) - if (phase == 0) { - // Get packet size - ReceivePacket(); - buf[0] = (BYTE)(packet_len >> 8); - buf[1] = (BYTE)packet_len; - return 2; - } else { - // Get package data - GetPacketBuf(buf); - return packet_len; - } - - case 2: // Received packet acquisition (size + buffer simultaneously) - ReceivePacket(); - buf[0] = (BYTE)(packet_len >> 8); - buf[1] = (BYTE)packet_len; - GetPacketBuf(&buf[2]); - return packet_len + 2; - - case 3: // Simultaneous acquisition of multiple packets (size + buffer simultaneously) - // Currently the maximum number of packets is 10 - // Isn't it too fast if I increase more? - total_len = 0; - for (i = 0; i < 10; i++) { - ReceivePacket(); - *buf++ = (BYTE)(packet_len >> 8); - *buf++ = (BYTE)packet_len; - total_len += 2; - if (packet_len == 0) - break; - GetPacketBuf(buf); - buf += packet_len; - total_len += packet_len; - } - return total_len; - } - break; -#endif // RASCSI && !BAREMETAL - - case 2: // Host Drive - switch (phase) { - case 0: // Get result code - return ReadFsResult(buf); - - case 1: // Return data acquisition - return ReadFsOut(buf); - - case 2: // Return additional data acquisition - return ReadFsOpt(buf); - } - break; - } - - // Error - ASSERT(FALSE); - return 0; -} - -//--------------------------------------------------------------------------- -// -// SEND MESSAGE(10) -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIBR::SendMessage10(const DWORD *cdb, BYTE *buf) -{ - int type; - int func; - int phase; - int len; - - ASSERT(this); - ASSERT(cdb); - ASSERT(buf); - - // Type - type = cdb[2]; - - // Function number - func = cdb[3]; - - // Phase - phase = cdb[9]; - - // Get the number of lights - len = cdb[6]; - len <<= 8; - len |= cdb[7]; - len <<= 8; - len |= cdb[8]; - - switch (type) { -#if defined(RASCSI) && !defined(BAREMETAL) - case 1: // Ethernet - // Do not process if TAP is invalid - if (!m_bTapEnable) { - return FALSE; - } - - switch (func) { - case 0: // MAC address setting - SetMacAddr(buf); - return TRUE; - - case 1: // Send packet - SendPacket(buf, len); - return TRUE; - } - break; -#endif // RASCSI && !BAREMETAL - - case 2: // Host drive - switch (phase) { - case 0: // issue command - WriteFs(func, buf); - return TRUE; - - case 1: // additional data writing - WriteFsOpt(buf, len); - return TRUE; - } - break; - } - - // Error - ASSERT(FALSE); - return FALSE; -} - -#if defined(RASCSI) && !defined(BAREMETAL) -//--------------------------------------------------------------------------- -// -// Get MAC Address -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIBR::GetMacAddr(BYTE *mac) -{ - ASSERT(this); - ASSERT(mac); - - memcpy(mac, mac_addr, 6); - return 6; -} - -//--------------------------------------------------------------------------- -// -// Set MAC Address -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::SetMacAddr(BYTE *mac) -{ - ASSERT(this); - ASSERT(mac); - - memcpy(mac_addr, mac, 6); -} - -//--------------------------------------------------------------------------- -// -// Receive Packet -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::ReceivePacket() -{ - static const BYTE bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - ASSERT(this); - ASSERT(tap); - - // previous packet has not been received - if (packet_enable) { - return; - } - - // Receive packet - packet_len = tap->Rx(packet_buf); - - // Check if received packet - if (memcmp(packet_buf, mac_addr, 6) != 0) { - if (memcmp(packet_buf, bcast_addr, 6) != 0) { - packet_len = 0; - return; - } - } - - // Discard if it exceeds the buffer size - if (packet_len > 2048) { - packet_len = 0; - return; - } - - // Store in receive buffer - if (packet_len > 0) { - packet_enable = TRUE; - } -} - -//--------------------------------------------------------------------------- -// -// Get Packet -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::GetPacketBuf(BYTE *buf) -{ - int len; - - ASSERT(this); - ASSERT(tap); - ASSERT(buf); - - // Size limit - len = packet_len; - if (len > 2048) { - len = 2048; - } - - // Copy - memcpy(buf, packet_buf, len); - - // Received - packet_enable = FALSE; -} - -//--------------------------------------------------------------------------- -// -// Send Packet -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::SendPacket(BYTE *buf, int len) -{ - ASSERT(this); - ASSERT(tap); - ASSERT(buf); - - tap->Tx(buf, len); -} -#endif // RASCSI && !BAREMETAL - -//--------------------------------------------------------------------------- -// -// $40 - Device Boot -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_InitDevice(BYTE *buf) -{ - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - fs->Reset(); - fsresult = fs->InitDevice((Human68k::argument_t*)buf); -} - -//--------------------------------------------------------------------------- -// -// $41 - Directory Check -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_CheckDir(BYTE *buf) -{ - DWORD nUnit; - Human68k::namests_t *pNamests; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - fsresult = fs->CheckDir(nUnit, pNamests); -} - -//--------------------------------------------------------------------------- -// -// $42 - Create Directory -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_MakeDir(BYTE *buf) -{ - DWORD nUnit; - Human68k::namests_t *pNamests; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - fsresult = fs->MakeDir(nUnit, pNamests); -} - -//--------------------------------------------------------------------------- -// -// $43 - Remove Directory -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_RemoveDir(BYTE *buf) -{ - DWORD nUnit; - Human68k::namests_t *pNamests; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - fsresult = fs->RemoveDir(nUnit, pNamests); -} - -//--------------------------------------------------------------------------- -// -// $44 - Rename -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Rename(BYTE *buf) -{ - DWORD nUnit; - Human68k::namests_t *pNamests; - Human68k::namests_t* pNamestsNew; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - pNamestsNew = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - fsresult = fs->Rename(nUnit, pNamests, pNamestsNew); -} - -//--------------------------------------------------------------------------- -// -// $45 - Delete File -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Delete(BYTE *buf) -{ - DWORD nUnit; - Human68k::namests_t *pNamests; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - fsresult = fs->Delete(nUnit, pNamests); -} - -//--------------------------------------------------------------------------- -// -// $46 - Get / Set file attributes -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Attribute(BYTE *buf) -{ - DWORD nUnit; - Human68k::namests_t *pNamests; - DWORD nHumanAttribute; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - dp = (DWORD*)&buf[i]; - nHumanAttribute = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->Attribute(nUnit, pNamests, nHumanAttribute); -} - -//--------------------------------------------------------------------------- -// -// $47 - File Search -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Files(BYTE *buf) -{ - DWORD nUnit; - DWORD nKey; - Human68k::namests_t *pNamests; - Human68k::files_t *files; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - files = (Human68k::files_t*)&buf[i]; - i += sizeof(Human68k::files_t); - - files->sector = ntohl(files->sector); - files->offset = ntohs(files->offset); - files->time = ntohs(files->time); - files->date = ntohs(files->date); - files->size = ntohl(files->size); - - fsresult = fs->Files(nUnit, nKey, pNamests, files); - - files->sector = htonl(files->sector); - files->offset = htons(files->offset); - files->time = htons(files->time); - files->date = htons(files->date); - files->size = htonl(files->size); - - i = 0; - memcpy(&fsout[i], files, sizeof(Human68k::files_t)); - i += sizeof(Human68k::files_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $48 - File next search -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_NFiles(BYTE *buf) -{ - DWORD nUnit; - DWORD nKey; - Human68k::files_t *files; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - files = (Human68k::files_t*)&buf[i]; - i += sizeof(Human68k::files_t); - - files->sector = ntohl(files->sector); - files->offset = ntohs(files->offset); - files->time = ntohs(files->time); - files->date = ntohs(files->date); - files->size = ntohl(files->size); - - fsresult = fs->NFiles(nUnit, nKey, files); - - files->sector = htonl(files->sector); - files->offset = htons(files->offset); - files->time = htons(files->time); - files->date = htons(files->date); - files->size = htonl(files->size); - - i = 0; - memcpy(&fsout[i], files, sizeof(Human68k::files_t)); - i += sizeof(Human68k::files_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $49 - File Creation -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Create(BYTE *buf) -{ - DWORD nUnit; - DWORD nKey; - Human68k::namests_t *pNamests; - Human68k::fcb_t *pFcb; - DWORD nAttribute; - BOOL bForce; - DWORD *dp; - BOOL *bp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - dp = (DWORD*)&buf[i]; - nAttribute = ntohl(*dp); - i += sizeof(DWORD); - - bp = (BOOL*)&buf[i]; - bForce = ntohl(*bp); - i += sizeof(BOOL); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->Create(nUnit, nKey, pNamests, pFcb, nAttribute, bForce); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $4A - Open File -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Open(BYTE *buf) -{ - DWORD nUnit; - DWORD nKey; - Human68k::namests_t *pNamests; - Human68k::fcb_t *pFcb; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pNamests = (Human68k::namests_t*)&buf[i]; - i += sizeof(Human68k::namests_t); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->Open(nUnit, nKey, pNamests, pFcb); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $4B - Close File -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Close(BYTE *buf) -{ - DWORD nUnit; - DWORD nKey; - Human68k::fcb_t *pFcb; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->Close(nUnit, nKey, pFcb); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $4C - Read File -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Read(BYTE *buf) -{ - DWORD nKey; - Human68k::fcb_t *pFcb; - DWORD nSize; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - dp = (DWORD*)&buf[i]; - nSize = ntohl(*dp); - i += sizeof(DWORD); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->Read(nKey, pFcb, fsopt, nSize); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; - - fsoptlen = fsresult; -} - -//--------------------------------------------------------------------------- -// -// $4D - Write file -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Write(BYTE *buf) -{ - DWORD nKey; - Human68k::fcb_t *pFcb; - DWORD nSize; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - dp = (DWORD*)&buf[i]; - nSize = ntohl(*dp); - i += sizeof(DWORD); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->Write(nKey, pFcb, fsopt, nSize); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $4E - Seek file -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Seek(BYTE *buf) -{ - DWORD nKey; - Human68k::fcb_t *pFcb; - DWORD nMode; - int nOffset; - DWORD *dp; - int *ip; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - dp = (DWORD*)&buf[i]; - nMode = ntohl(*dp); - i += sizeof(DWORD); - - ip = (int*)&buf[i]; - nOffset = ntohl(*ip); - i += sizeof(int); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->Seek(nKey, pFcb, nMode, nOffset); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $4F - File Timestamp Get / Set -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_TimeStamp(BYTE *buf) -{ - DWORD nUnit; - DWORD nKey; - Human68k::fcb_t *pFcb; - DWORD nHumanTime; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nKey = ntohl(*dp); - i += sizeof(DWORD); - - pFcb = (Human68k::fcb_t*)&buf[i]; - i += sizeof(Human68k::fcb_t); - - dp = (DWORD*)&buf[i]; - nHumanTime = ntohl(*dp); - i += sizeof(DWORD); - - pFcb->fileptr = ntohl(pFcb->fileptr); - pFcb->mode = ntohs(pFcb->mode); - pFcb->time = ntohs(pFcb->time); - pFcb->date = ntohs(pFcb->date); - pFcb->size = ntohl(pFcb->size); - - fsresult = fs->TimeStamp(nUnit, nKey, pFcb, nHumanTime); - - pFcb->fileptr = htonl(pFcb->fileptr); - pFcb->mode = htons(pFcb->mode); - pFcb->time = htons(pFcb->time); - pFcb->date = htons(pFcb->date); - pFcb->size = htonl(pFcb->size); - - i = 0; - memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); - i += sizeof(Human68k::fcb_t); - - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $50 - Get Capacity -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_GetCapacity(BYTE *buf) -{ - DWORD nUnit; - Human68k::capacity_t cap; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->GetCapacity(nUnit, &cap); - - cap.freearea = htons(cap.freearea); - cap.clusters = htons(cap.clusters); - cap.sectors = htons(cap.sectors); - cap.bytes = htons(cap.bytes); - - memcpy(fsout, &cap, sizeof(Human68k::capacity_t)); - fsoutlen = sizeof(Human68k::capacity_t); -} - -//--------------------------------------------------------------------------- -// -// $51 - Drive status inspection/control -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_CtrlDrive(BYTE *buf) -{ - DWORD nUnit; - Human68k::ctrldrive_t *pCtrlDrive; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - pCtrlDrive = (Human68k::ctrldrive_t*)&buf[i]; - i += sizeof(Human68k::ctrldrive_t); - - fsresult = fs->CtrlDrive(nUnit, pCtrlDrive); - - memcpy(fsout, pCtrlDrive, sizeof(Human68k::ctrldrive_t)); - fsoutlen = sizeof(Human68k::ctrldrive_t); -} - -//--------------------------------------------------------------------------- -// -// $52 - Get DPB -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_GetDPB(BYTE *buf) -{ - DWORD nUnit; - Human68k::dpb_t dpb; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->GetDPB(nUnit, &dpb); - - dpb.sector_size = htons(dpb.sector_size); - dpb.fat_sector = htons(dpb.fat_sector); - dpb.file_max = htons(dpb.file_max); - dpb.data_sector = htons(dpb.data_sector); - dpb.cluster_max = htons(dpb.cluster_max); - dpb.root_sector = htons(dpb.root_sector); - - memcpy(fsout, &dpb, sizeof(Human68k::dpb_t)); - fsoutlen = sizeof(Human68k::dpb_t); -} - -//--------------------------------------------------------------------------- -// -// $53 - Read Sector -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_DiskRead(BYTE *buf) -{ - DWORD nUnit; - DWORD nSector; - DWORD nSize; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nSector = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nSize = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->DiskRead(nUnit, fsout, nSector, nSize); - fsoutlen = 0x200; -} - -//--------------------------------------------------------------------------- -// -// $54 - Write Sector -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_DiskWrite(BYTE *buf) -{ - DWORD nUnit; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->DiskWrite(nUnit); -} - -//--------------------------------------------------------------------------- -// -// $55 - IOCTRL -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Ioctrl(BYTE *buf) -{ - DWORD nUnit; - DWORD nFunction; - Human68k::ioctrl_t *pIoctrl; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - dp = (DWORD*)&buf[i]; - nFunction = ntohl(*dp); - i += sizeof(DWORD); - - pIoctrl = (Human68k::ioctrl_t*)&buf[i]; - i += sizeof(Human68k::ioctrl_t); - - switch (nFunction) { - case 2: - case -2: - pIoctrl->param = htonl(pIoctrl->param); - break; - } - - fsresult = fs->Ioctrl(nUnit, nFunction, pIoctrl); - - switch (nFunction) { - case 0: - pIoctrl->media = htons(pIoctrl->media); - break; - case 1: - case -3: - pIoctrl->param = htonl(pIoctrl->param); - break; - } - - i = 0; - memcpy(&fsout[i], pIoctrl, sizeof(Human68k::ioctrl_t)); - i += sizeof(Human68k::ioctrl_t); - fsoutlen = i; -} - -//--------------------------------------------------------------------------- -// -// $56 - Flush -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Flush(BYTE *buf) -{ - DWORD nUnit; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->Flush(nUnit); -} - -//--------------------------------------------------------------------------- -// -// $57 - Check Media -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_CheckMedia(BYTE *buf) -{ - DWORD nUnit; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->CheckMedia(nUnit); -} - -//--------------------------------------------------------------------------- -// -// $58 - Lock -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::FS_Lock(BYTE *buf) -{ - DWORD nUnit; - DWORD *dp; - int i; - - ASSERT(this); - ASSERT(fs); - ASSERT(buf); - - i = 0; - dp = (DWORD*)buf; - nUnit = ntohl(*dp); - i += sizeof(DWORD); - - fsresult = fs->Lock(nUnit); -} - -//--------------------------------------------------------------------------- -// -// Read Filesystem (result code) -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIBR::ReadFsResult(BYTE *buf) -{ - DWORD *dp; - - ASSERT(this); - ASSERT(buf); - - dp = (DWORD*)buf; - *dp = htonl(fsresult); - return sizeof(DWORD); -} - -//--------------------------------------------------------------------------- -// -// Read Filesystem (return data) -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIBR::ReadFsOut(BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - memcpy(buf, fsout, fsoutlen); - return fsoutlen; -} - -//--------------------------------------------------------------------------- -// -// Read file system (return option data) -// -//--------------------------------------------------------------------------- -int FASTCALL SCSIBR::ReadFsOpt(BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - memcpy(buf, fsopt, fsoptlen); - return fsoptlen; -} - -//--------------------------------------------------------------------------- -// -// Write Filesystem -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::WriteFs(int func, BYTE *buf) -{ - ASSERT(this); - ASSERT(buf); - - fsresult = FS_FATAL_INVALIDCOMMAND; - fsoutlen = 0; - fsoptlen = 0; - - // コマンド分岐 - func &= 0x1f; - switch (func) { - case 0x00: return FS_InitDevice(buf); // $40 - start device - case 0x01: return FS_CheckDir(buf); // $41 - directory check - case 0x02: return FS_MakeDir(buf); // $42 - create directory - case 0x03: return FS_RemoveDir(buf); // $43 - remove directory - case 0x04: return FS_Rename(buf); // $44 - change file name - case 0x05: return FS_Delete(buf); // $45 - delete file - case 0x06: return FS_Attribute(buf); // $46 - Get/set file attribute - case 0x07: return FS_Files(buf); // $47 - file search - case 0x08: return FS_NFiles(buf); // $48 - next file search - case 0x09: return FS_Create(buf); // $49 - create file - case 0x0A: return FS_Open(buf); // $4A - File open - case 0x0B: return FS_Close(buf); // $4B - File close - case 0x0C: return FS_Read(buf); // $4C - read file - case 0x0D: return FS_Write(buf); // $4D - write file - case 0x0E: return FS_Seek(buf); // $4E - File seek - case 0x0F: return FS_TimeStamp(buf); // $4F - Get/set file modification time - case 0x10: return FS_GetCapacity(buf); // $50 - get capacity - case 0x11: return FS_CtrlDrive(buf); // $51 - Drive control/state check - case 0x12: return FS_GetDPB(buf); // $52 - Get DPB - case 0x13: return FS_DiskRead(buf); // $53 - read sector - case 0x14: return FS_DiskWrite(buf); // $54 - write sector - case 0x15: return FS_Ioctrl(buf); // $55 - IOCTRL - case 0x16: return FS_Flush(buf); // $56 - flush - case 0x17: return FS_CheckMedia(buf); // $57 - check media exchange - case 0x18: return FS_Lock(buf); // $58 - exclusive control - } -} - -//--------------------------------------------------------------------------- -// -// File system write (input option data) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIBR::WriteFsOpt(BYTE *buf, int num) -{ - ASSERT(this); - - memcpy(fsopt, buf, num); -} - -//=========================================================================== -// -// SASI Device -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -#ifdef RASCSI -SASIDEV::SASIDEV() -#else -SASIDEV::SASIDEV(Device *dev) -#endif // RASCSI -{ - int i; - -#ifndef RASCSI - // Remember host device - host = dev; -#endif // RASCSI - - // Work initialization - ctrl.phase = BUS::busfree; - ctrl.id = -1; - ctrl.bus = NULL; - memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd)); - ctrl.status = 0x00; - ctrl.message = 0x00; -#ifdef RASCSI - ctrl.execstart = 0; -#endif // RASCSI - ctrl.bufsize = 0x800; - ctrl.buffer = (BYTE *)malloc(ctrl.bufsize); - memset(ctrl.buffer, 0x00, ctrl.bufsize); - ctrl.blocks = 0; - ctrl.next = 0; - ctrl.offset = 0; - ctrl.length = 0; - - // Logical unit initialization - for (i = 0; i < UnitMax; i++) { - ctrl.unit[i] = NULL; - } -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -SASIDEV::~SASIDEV() -{ - // Free the buffer - if (ctrl.buffer) { - free(ctrl.buffer); - ctrl.buffer = NULL; - } -} - -//--------------------------------------------------------------------------- -// -// Device reset -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Reset() -{ - int i; - - ASSERT(this); - - // Work initialization - memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd)); - ctrl.phase = BUS::busfree; - ctrl.status = 0x00; - ctrl.message = 0x00; -#ifdef RASCSI - ctrl.execstart = 0; -#endif // RASCSI - memset(ctrl.buffer, 0x00, ctrl.bufsize); - ctrl.blocks = 0; - ctrl.next = 0; - ctrl.offset = 0; - ctrl.length = 0; - - // Unit initialization - for (i = 0; i < UnitMax; i++) { - if (ctrl.unit[i]) { - ctrl.unit[i]->Reset(); - } - } -} - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Save -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SASIDEV::Save(Fileio *fio, int /*ver*/) -{ - DWORD sz; - - ASSERT(this); - ASSERT(fio); - - // Save size - sz = 2120; - if (!fio->Write(&sz, sizeof(sz))) { - return FALSE; - } - - // Save entity - PROP_EXPORT(fio, ctrl.phase); - PROP_EXPORT(fio, ctrl.id); - PROP_EXPORT(fio, ctrl.cmd); - PROP_EXPORT(fio, ctrl.status); - PROP_EXPORT(fio, ctrl.message); - if (!fio->Write(ctrl.buffer, 0x800)) { - return FALSE; - } - PROP_EXPORT(fio, ctrl.blocks); - PROP_EXPORT(fio, ctrl.next); - PROP_EXPORT(fio, ctrl.offset); - PROP_EXPORT(fio, ctrl.length); - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Load -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SASIDEV::Load(Fileio *fio, int ver) -{ - DWORD sz; - - ASSERT(this); - ASSERT(fio); - - // Not saved before version 3.11 - if (ver <= 0x0311) { - return TRUE; - } - - // Load size and check if the size matches - if (!fio->Read(&sz, sizeof(sz))) { - return FALSE; - } - if (sz != 2120) { - return FALSE; - } - - // Load the entity - PROP_IMPORT(fio, ctrl.phase); - PROP_IMPORT(fio, ctrl.id); - PROP_IMPORT(fio, ctrl.cmd); - PROP_IMPORT(fio, ctrl.status); - PROP_IMPORT(fio, ctrl.message); - if (!fio->Read(ctrl.buffer, 0x800)) { - return FALSE; - } - PROP_IMPORT(fio, ctrl.blocks); - PROP_IMPORT(fio, ctrl.next); - PROP_IMPORT(fio, ctrl.offset); - PROP_IMPORT(fio, ctrl.length); - - return TRUE; -} -#endif // RASCSI - -//--------------------------------------------------------------------------- -// -// Connect the controller -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Connect(int id, BUS *bus) -{ - ASSERT(this); - - ctrl.id = id; - ctrl.bus = bus; -} - -//--------------------------------------------------------------------------- -// -// Get the logical unit -// -//--------------------------------------------------------------------------- -Disk* FASTCALL SASIDEV::GetUnit(int no) -{ - ASSERT(this); - ASSERT(no < UnitMax); - - return ctrl.unit[no]; -} - -//--------------------------------------------------------------------------- -// -// Set the logical unit -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::SetUnit(int no, Disk *dev) -{ - ASSERT(this); - ASSERT(no < UnitMax); - - ctrl.unit[no] = dev; -} - -//--------------------------------------------------------------------------- -// -// Check to see if this has a valid logical unit -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SASIDEV::HasUnit() -{ - int i; - - ASSERT(this); - - for (i = 0; i < UnitMax; i++) { - if (ctrl.unit[i]) { - return TRUE; - } - } - - return FALSE; -} - -//--------------------------------------------------------------------------- -// -// Get internal data -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::GetCTRL(ctrl_t *buffer) -{ - ASSERT(this); - ASSERT(buffer); - - // reference the internal structure - *buffer = ctrl; -} - -//--------------------------------------------------------------------------- -// -// Get a busy unit -// -//--------------------------------------------------------------------------- -Disk* FASTCALL SASIDEV::GetBusyUnit() -{ - DWORD lun; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - return ctrl.unit[lun]; -} - -//--------------------------------------------------------------------------- -// -// Run -// -//--------------------------------------------------------------------------- -BUS::phase_t FASTCALL SASIDEV::Process() -{ - ASSERT(this); - - // Do nothing if not connected - if (ctrl.id < 0 || ctrl.bus == NULL) { - return ctrl.phase; - } - - // Get bus information - ctrl.bus->Aquire(); - - // For the monitor tool, we shouldn't need to reset. We're just logging information - // Reset - if (ctrl.bus->GetRST()) { -#if defined(DISK_LOG) - Log(Log::Normal, "RESET signal received"); -#endif // DISK_LOG - - // Reset the controller - Reset(); - - // Reset the bus - ctrl.bus->Reset(); - return ctrl.phase; - } - - // Phase processing - switch (ctrl.phase) { - // Bus free - case BUS::busfree: - BusFree(); - break; - - // Selection - case BUS::selection: - Selection(); - break; - - // Data out (MCI=000) - case BUS::dataout: - DataOut(); - break; - - // Data in (MCI=001) - case BUS::datain: - DataIn(); - break; - - // Command (MCI=010) - case BUS::command: - Command(); - break; - - // Status (MCI=011) - case BUS::status: - Status(); - break; - - // Msg in (MCI=111) - case BUS::msgin: - MsgIn(); - break; - - // Other - default: - ASSERT(FALSE); - break; - } - - return ctrl.phase; -} - -//--------------------------------------------------------------------------- -// -// Bus free phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::BusFree() -{ - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::busfree) { - -#if defined(DISK_LOG) - Log(Log::Normal, "Bus free phase"); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::busfree; - - // Set Signal lines - ctrl.bus->SetREQ(FALSE); - ctrl.bus->SetMSG(FALSE); - ctrl.bus->SetCD(FALSE); - ctrl.bus->SetIO(FALSE); - ctrl.bus->SetBSY(FALSE); - - // Initialize status and message - ctrl.status = 0x00; - ctrl.message = 0x00; - return; - } - - // Move to selection phase - if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) { - Selection(); - } -} - -//--------------------------------------------------------------------------- -// -// Selection phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Selection() -{ - DWORD id; - - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::selection) { - // Invalid if IDs do not match - id = 1 << ctrl.id; - if ((ctrl.bus->GetDAT() & id) == 0) { - return; - } - - // Return if there is no unit - if (!HasUnit()) { - return; - } - -#if defined(DISK_LOG) - Log(Log::Normal, - "Selection Phase ID=%d (with device)", ctrl.id); -#endif // DISK_LOG - - // Phase change - ctrl.phase = BUS::selection; - - // Raiase BSY and respond - ctrl.bus->SetBSY(TRUE); - return; - } - - // Command phase shifts when selection is completed - if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) { - Command(); - } -} - -//--------------------------------------------------------------------------- -// -// Command phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Command() -{ -#ifdef RASCSI - int count; - int i; -#endif // RASCSI - - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::command) { - -#if defined(DISK_LOG) - Log(Log::Normal, "Command Phase"); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::command; - - // Signal line operated by the target - ctrl.bus->SetMSG(FALSE); - ctrl.bus->SetCD(TRUE); - ctrl.bus->SetIO(FALSE); - - // Data transfer is 6 bytes x 1 block - ctrl.offset = 0; - ctrl.length = 6; - ctrl.blocks = 1; - -#ifdef RASCSI - // Command reception handshake (10 bytes are automatically received at the first command) - count = ctrl.bus->CommandHandShake(ctrl.buffer); - - // If no byte can be received move to the status phase - if (count == 0) { - Error(); - return; - } - - // Check 10-byte CDB - if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) { - ctrl.length = 10; - } - - // If not able to receive all, move to the status phase - if (count != (int)ctrl.length) { - Error(); - return; - } - - // Command data transfer - for (i = 0; i < (int)ctrl.length; i++) { - ctrl.cmd[i] = (DWORD)ctrl.buffer[i]; - } - - // Clear length and block - ctrl.length = 0; - ctrl.blocks = 0; - - // Execution Phase - Execute(); -#else - // Request the command - ctrl.bus->SetREQ(TRUE); - return; -#endif // RASCSI - } -#ifndef RASCSI - // Requesting - if (ctrl.bus->GetREQ()) { - // Sent by the initiator - if (ctrl.bus->GetACK()) { - Receive(); - } - } else { - // Request the initator to - if (!ctrl.bus->GetACK()) { - ReceiveNext(); - } - } -#endif // RASCSI -} - -//--------------------------------------------------------------------------- -// -// Execution Phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Execute() -{ - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "Execution Phase Command %02X", ctrl.cmd[0]); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::execute; - - // Initialization for data transfer - ctrl.offset = 0; - ctrl.blocks = 1; -#ifdef RASCSI - ctrl.execstart = SysTimer::GetTimerLow(); -#endif // RASCSI - - // Process by command - switch (ctrl.cmd[0]) { - // TEST UNIT READY - case 0x00: - CmdTestUnitReady(); - return; - - // REZERO UNIT - case 0x01: - CmdRezero(); - return; - - // REQUEST SENSE - case 0x03: - CmdRequestSense(); - return; - - // FORMAT UNIT - case 0x04: - CmdFormat(); - return; - - // FORMAT UNIT - case 0x06: - CmdFormat(); - return; - - // REASSIGN BLOCKS - case 0x07: - CmdReassign(); - return; - - // READ(6) - case 0x08: - CmdRead6(); - return; - - // WRITE(6) - case 0x0a: - CmdWrite6(); - return; - - // SEEK(6) - case 0x0b: - CmdSeek6(); - return; - - // ASSIGN(SASIのみ) - case 0x0e: - CmdAssign(); - return; - - // SPECIFY(SASIのみ) - case 0xc2: - CmdSpecify(); - return; - } - - // Unsupported command - Log(Log::Warning, "Unsupported command $%02X", ctrl.cmd[0]); - CmdInvalid(); -} - -//--------------------------------------------------------------------------- -// -// Status phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Status() -{ -#ifdef RASCSI - DWORD min_exec_time; - DWORD time; -#endif // RASCSI - - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::status) { - -#ifdef RASCSI - // Minimum execution time - if (ctrl.execstart > 0) { - min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi; - time = SysTimer::GetTimerLow() - ctrl.execstart; - if (time < min_exec_time) { - SysTimer::SleepUsec(min_exec_time - time); - } - ctrl.execstart = 0; - } else { - SysTimer::SleepUsec(5); - } -#endif // RASCSI - -#if defined(DISK_LOG) - Log(Log::Normal, "Status phase"); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::status; - - // Signal line operated by the target - ctrl.bus->SetMSG(FALSE); - ctrl.bus->SetCD(TRUE); - ctrl.bus->SetIO(TRUE); - - // Data transfer is 1 byte x 1 block - ctrl.offset = 0; - ctrl.length = 1; - ctrl.blocks = 1; - ctrl.buffer[0] = (BYTE)ctrl.status; - -#ifndef RASCSI - // Request status - ctrl.bus->SetDAT(ctrl.buffer[0]); - ctrl.bus->SetREQ(TRUE); - -#if defined(DISK_LOG) - Log(Log::Normal, "Status Phase $%02X", ctrl.status); -#endif // DISK_LOG -#endif // RASCSI - return; - } - -#ifdef RASCSI - // Send - Send(); -#else - // Requesting - if (ctrl.bus->GetREQ()) { - // Initiator received - if (ctrl.bus->GetACK()) { - SendNext(); - } - } else { - // Initiator requests next - if (!ctrl.bus->GetACK()) { - Send(); - } - } -#endif // RASCSI -} - -//--------------------------------------------------------------------------- -// -// Message in phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::MsgIn() -{ - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::msgin) { - -#if defined(DISK_LOG) - Log(Log::Normal, "Message in phase"); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::msgin; - - // Signal line operated by the target - ctrl.bus->SetMSG(TRUE); - ctrl.bus->SetCD(TRUE); - ctrl.bus->SetIO(TRUE); - - // length, blocks are already set - 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 - 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 -} - -//--------------------------------------------------------------------------- -// -// Data-in Phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::DataIn() -{ -#ifdef RASCSI - DWORD min_exec_time; - DWORD time; -#endif // RASCSI - - ASSERT(this); - ASSERT(ctrl.length >= 0); - - // Phase change - if (ctrl.phase != BUS::datain) { - -#ifdef RASCSI - // Minimum execution time - if (ctrl.execstart > 0) { - min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi; - time = SysTimer::GetTimerLow() - ctrl.execstart; - if (time < min_exec_time) { - SysTimer::SleepUsec(min_exec_time - time); - } - ctrl.execstart = 0; - } -#endif // RASCSI - - // If the length is 0, go to the status phase - if (ctrl.length == 0) { - Status(); - return; - } - -#if defined(DISK_LOG) - Log(Log::Normal, "Data-in Phase"); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::datain; - - // Signal line operated by the target - ctrl.bus->SetMSG(FALSE); - ctrl.bus->SetCD(FALSE); - ctrl.bus->SetIO(TRUE); - - // length, blocks are already set - ASSERT(ctrl.length > 0); - 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 -} - -//--------------------------------------------------------------------------- -// -// Data out phase -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::DataOut() -{ -#ifdef RASCSI - DWORD min_exec_time; - DWORD time; -#endif // RASCSI - - ASSERT(this); - ASSERT(ctrl.length >= 0); - - // Phase change - if (ctrl.phase != BUS::dataout) { - -#ifdef RASCSI - // Minimum execution time - if (ctrl.execstart > 0) { - min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi; - time = SysTimer::GetTimerLow() - ctrl.execstart; - if (time < min_exec_time) { - SysTimer::SleepUsec(min_exec_time - time); - } - ctrl.execstart = 0; - } -#endif // RASCSI - - // If the length is 0, go to the status phase - if (ctrl.length == 0) { - Status(); - return; - } - -#if defined(DISK_LOG) - Log(Log::Normal, "Data out phase"); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::dataout; - - // Signal line operated by the target - ctrl.bus->SetMSG(FALSE); - ctrl.bus->SetCD(FALSE); - ctrl.bus->SetIO(FALSE); - - // length, blocks are already calculated - ASSERT(ctrl.length > 0); - ASSERT(ctrl.blocks > 0); - ctrl.offset = 0; - -#ifndef RASCSI - // Request data - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - -#ifdef RASCSI - // Receive - Receive(); -#else - // Requesting - if (ctrl.bus->GetREQ()) { - // Sent by the initiator - if (ctrl.bus->GetACK()) { - Receive(); - } - } else { - // Request the initator to - if (!ctrl.bus->GetACK()) { - ReceiveNext(); - } - } -#endif // RASCSI -} - -//--------------------------------------------------------------------------- -// -// Error -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Error() -{ - DWORD lun; - - ASSERT(this); - - // Get bus information - ctrl.bus->Aquire(); - - // Reset check - if (ctrl.bus->GetRST()) { - // Reset the controller - Reset(); - - // Reset the bus - ctrl.bus->Reset(); - return; - } - - // Bus free for status phase and message in phase - if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) { - BusFree(); - return; - } - -#if defined(DISK_LOG) - Log(Log::Warning, "Error occured (going to status phase)"); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - - // Set status and message(CHECK CONDITION) - ctrl.status = (lun << 5) | 0x02; - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// TEST UNIT READY -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdTestUnitReady() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "TEST UNIT READY Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->TestUnitReady(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// REZERO UNIT -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdRezero() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "REZERO UNIT Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Rezero(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// REQUEST SENSE -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdRequestSense() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "REQUEST SENSE Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer); - ASSERT(ctrl.length > 0); - -#if defined(DISK_LOG) - Log(Log::Normal, "Sense key $%02X", ctrl.buffer[2]); -#endif // DISK_LOG - - // Read phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// FORMAT UNIT -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdFormat() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "FORMAT UNIT Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Format(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// REASSIGN BLOCKS -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdReassign() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "REASSIGN BLOCKS Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Reassign(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// READ(6) -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdRead6() -{ - DWORD lun; - DWORD record; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Get record number and block number - record = ctrl.cmd[1] & 0x1f; - record <<= 8; - record |= ctrl.cmd[2]; - record <<= 8; - record |= ctrl.cmd[3]; - ctrl.blocks = ctrl.cmd[4]; - if (ctrl.blocks == 0) { - ctrl.blocks = 0x100; - } - -#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.buffer, record); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.next = record + 1; - - // Read phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// WRITE(6) -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdWrite6() -{ - DWORD lun; - DWORD record; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Get record number and block number - record = ctrl.cmd[1] & 0x1f; - record <<= 8; - record |= ctrl.cmd[2]; - record <<= 8; - record |= ctrl.cmd[3]; - ctrl.blocks = ctrl.cmd[4]; - if (ctrl.blocks == 0) { - ctrl.blocks = 0x100; - } - -#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) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.next = record + 1; - - // Write phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// SEEK(6) -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdSeek6() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "SEEK(6) Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Seek(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// ASSIGN -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdAssign() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "ASSIGN Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Assign(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // Request 4 bytes of data - ctrl.length = 4; - - // Write phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// SPECIFY -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdSpecify() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "SPECIFY Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Assign(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // Request 10 bytes of data - ctrl.length = 10; - - // Write phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// Unsupported command -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::CmdInvalid() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "Command not supported"); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (ctrl.unit[lun]) { - // Command processing on drive - ctrl.unit[lun]->InvalidCmd(); - } - - // Failure (Error) - Error(); -} - -//=========================================================================== -// -// Data transfer -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Data transmission -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Send() -{ -#ifdef RASCSI - int len; -#endif // RASCSI - BOOL result; - - ASSERT(this); - 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( - &ctrl.buffer[ctrl.offset], ctrl.length); - - // If you can not send it all, move on to the status phase - if (len != (int)ctrl.length) { - Error(); - return; - } - - // Offset and Length - ctrl.offset += ctrl.length; - ctrl.length = 0; - return; - } -#else - // Offset and Length - ASSERT(ctrl.length >= 1); - ctrl.offset++; - ctrl.length--; - - // Immediately after ACK is asserted, if the data - // has been set by SendNext, raise the request - if (ctrl.length != 0) { - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); - return; - } -#endif // RASCSI - - // Remove block and initialize the result - ctrl.blocks--; - result = TRUE; - - // Process after data collection (read/data-in only) - if (ctrl.phase == BUS::datain) { - if (ctrl.blocks != 0) { - // Set next buffer (set offset, length) - result = XferIn(ctrl.buffer); - //** printf("xfer in: %d \n",result); - -#ifndef RASCSI - ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); -#endif // RASCSI - } - } - - // If result FALSE, move to the status phase - if (!result) { - Error(); - return; - } - - // Continue sending if block != 0 - if (ctrl.blocks != 0){ - ASSERT(ctrl.length > 0); - ASSERT(ctrl.offset == 0); -#ifndef RASCSI - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - - // Move to the next phase - switch (ctrl.phase) { - // Message in phase - case BUS::msgin: - // Bus free phase - BusFree(); - break; - - // Data-in Phase - case BUS::datain: - // status phase - Status(); - break; - - // Status phase - case BUS::status: - // Message in phase - ctrl.length = 1; - ctrl.blocks = 1; - ctrl.buffer[0] = (BYTE)ctrl.message; - MsgIn(); - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Continue sending data -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::SendNext() -{ - ASSERT(this); - - // Req is up - ASSERT(ctrl.bus->GetREQ()); - ASSERT(ctrl.bus->GetIO()); - - // Signal line operated by the target - ctrl.bus->SetREQ(FALSE); - - // If there is data in the buffer, set it first. - if (ctrl.length > 1) { - ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset + 1]); - } -} -#endif // RASCSI - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Receive data -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Receive() -{ - DWORD data; - - ASSERT(this); - - // Req is up - ASSERT(ctrl.bus->GetREQ()); - ASSERT(!ctrl.bus->GetIO()); - - // Get data - data = (DWORD)ctrl.bus->GetDAT(); - - // Signal line operated by the target - ctrl.bus->SetREQ(FALSE); - - switch (ctrl.phase) { - // Command phase - case BUS::command: - ctrl.cmd[ctrl.offset] = data; -#if defined(DISK_LOG) - Log(Log::Normal, "Command phase $%02X", data); -#endif // DISK_LOG - - // Set the length again with the first data (offset 0) - if (ctrl.offset == 0) { - if (ctrl.cmd[0] >= 0x20 && ctrl.cmd[0] <= 0x7D) { - // 10 byte CDB - ctrl.length = 10; - } - } - break; - - // Data out phase - case BUS::dataout: - ctrl.buffer[ctrl.offset] = (BYTE)data; - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} -#endif // RASCSI - -#ifdef RASCSI -//--------------------------------------------------------------------------- -// -// Receive data -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::Receive() -#else -//--------------------------------------------------------------------------- -// -// Continue receiving data -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::ReceiveNext() -#endif // RASCSI -{ -#ifdef RASCSI - int len; -#endif // RASCSI - BOOL result; - - ASSERT(this); - - // REQ is low - ASSERT(!ctrl.bus->GetREQ()); - ASSERT(!ctrl.bus->GetIO()); - -#ifdef RASCSI - // Length != 0 if received - if (ctrl.length != 0) { - // Receive - len = ctrl.bus->ReceiveHandShake( - &ctrl.buffer[ctrl.offset], ctrl.length); - - // If not able to receive all, move to status phase - if (len != (int)ctrl.length) { - Error(); - return; - } - - // Offset and Length - ctrl.offset += ctrl.length; - ctrl.length = 0; - return; - } -#else - // Offset and Length - ASSERT(ctrl.length >= 1); - ctrl.offset++; - ctrl.length--; - - // If length != 0, set req again - if (ctrl.length != 0) { - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); - return; - } -#endif // RASCSI - - // Remove the control block and initialize the result - ctrl.blocks--; - result = TRUE; - - // Process the data out phase - if (ctrl.phase == BUS::dataout) { - if (ctrl.blocks == 0) { - // End with this buffer - result = XferOut(FALSE); - } else { - // Continue to next buffer (set offset, length) - result = XferOut(TRUE); - } - } - - // If result is false, move to the status phase - if (!result) { - Error(); - return; - } - - // Continue to receive is block != 0 - if (ctrl.blocks != 0){ - ASSERT(ctrl.length > 0); - ASSERT(ctrl.offset == 0); -#ifndef RASCSI - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - - // Move to the next phase - switch (ctrl.phase) { -#ifndef RASCSI - // Command phase - case BUS::command: - // Execution Phase - Execute(); - break; -#endif // RASCSI - - // Data out phase - case BUS::dataout: - // Flush - FlushUnit(); - - // status phase - Status(); - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} - -//--------------------------------------------------------------------------- -// -// Data transfer IN -// *Reset offset and length -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SASIDEV::XferIn(BYTE *buf) -{ - DWORD lun; - - ASSERT(this); - ASSERT(ctrl.phase == BUS::datain); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - return FALSE; - } - - // Limited to read commands - switch (ctrl.cmd[0]) { - // READ(6) - case 0x08: - // READ(10) - case 0x28: - // Read from disk - ctrl.length = ctrl.unit[lun]->Read(buf, ctrl.next); - ctrl.next++; - - // If there is an error, go to the status phase - if (ctrl.length <= 0) { - // Cancel data-in - return FALSE; - } - - // If things are normal, work setting - ctrl.offset = 0; - break; - - // Other (impossible) - default: - ASSERT(FALSE); - return FALSE; - } - - // Succeeded in setting the buffer - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Data transfer OUT -// *If cont=true, reset the offset and length -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SASIDEV::XferOut(BOOL cont) -{ - DWORD lun; - SCSIBR *bridge; - - ASSERT(this); - ASSERT(ctrl.phase == BUS::dataout); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - return FALSE; - } - - // 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 - return FALSE; - } - break; - - // 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)) { - // write failed - return FALSE; - } - - // If normal, work setting - ctrl.offset = 0; - break; - } - - // WRITE AND VERIFY - case 0x2e: - // Write - if (!ctrl.unit[lun]->Write(ctrl.buffer, ctrl.next - 1)) { - // Write failed - return FALSE; - } - - // If you do not need the next block, end here - ctrl.next++; - if (!cont) { - break; - } - - // Check the next block - ctrl.length = ctrl.unit[lun]->WriteCheck(ctrl.next - 1); - if (ctrl.length <= 0) { - // Cannot write - return FALSE; - } - - // If normal, work setting - ctrl.offset = 0; - break; - - // SPECIFY(SASI only) - case 0xc2: - break; - - default: - ASSERT(FALSE); - break; - } - - // Buffer saved successfully - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Logical unit flush -// -//--------------------------------------------------------------------------- -void FASTCALL SASIDEV::FlushUnit() -{ - DWORD lun; - - ASSERT(this); - ASSERT(ctrl.phase == BUS::dataout); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - return; - } - - // WRITE system only - 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; - // 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 - 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 - Log(Log::Warning, "Error occured while processing Mode Select command %02X\n", (unsigned char)ctrl.cmd[0]); - return; - } - break; - - default: - Log(Log::Warning, "Received an invalid flush command %02X!!!!!\n",ctrl.cmd[0]); - ASSERT(FALSE); - break; - } -} - -#ifdef DISK_LOG -//--------------------------------------------------------------------------- -// -// Get the current phase as a string -// -//--------------------------------------------------------------------------- -void SASIDEV::GetPhaseStr(char *str) -{ - switch(this->GetPhase()) - { - case BUS::busfree: - strcpy(str,"busfree "); - break; - case BUS::arbitration: - strcpy(str,"arbitration"); - break; - case BUS::selection: - strcpy(str,"selection "); - break; - case BUS::reselection: - strcpy(str,"reselection"); - break; - case BUS::command: - strcpy(str,"command "); - break; - case BUS::execute: - strcpy(str,"execute "); - break; - case BUS::datain: - strcpy(str,"datain "); - break; - case BUS::dataout: - strcpy(str,"dataout "); - break; - case BUS::status: - strcpy(str,"status "); - break; - case BUS::msgin: - strcpy(str,"msgin "); - break; - case BUS::msgout: - strcpy(str,"msgout "); - break; - case BUS::reserved: - strcpy(str,"reserved "); - break; - } -} -#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 -} - -//=========================================================================== -// -// SCSI Device -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -#ifdef RASCSI -SCSIDEV::SCSIDEV() : SASIDEV() -#else -SCSIDEV::SCSIDEV(Device *dev) : SASIDEV(dev) -#endif -{ - // Synchronous transfer work initialization - scsi.syncenable = FALSE; - scsi.syncperiod = 50; - scsi.syncoffset = 0; - scsi.atnmsg = FALSE; - scsi.msc = 0; - memset(scsi.msb, 0x00, sizeof(scsi.msb)); -} - -//--------------------------------------------------------------------------- -// -// Device reset -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Reset() -{ - ASSERT(this); - - // Work initialization - scsi.atnmsg = FALSE; - scsi.msc = 0; - memset(scsi.msb, 0x00, sizeof(scsi.msb)); - - // Base class - SASIDEV::Reset(); -} - -//--------------------------------------------------------------------------- -// -// Process -// -//--------------------------------------------------------------------------- -BUS::phase_t FASTCALL SCSIDEV::Process() -{ - ASSERT(this); - - // Do nothing if not connected - if (ctrl.id < 0 || ctrl.bus == NULL) { - return ctrl.phase; - } - - // Get bus information - ctrl.bus->Aquire(); - - // Reset - if (ctrl.bus->GetRST()) { -#if defined(DISK_LOG) - Log(Log::Normal, "RESET信号受信"); -#endif // DISK_LOG - - // Reset the controller - Reset(); - - // Reset the bus - ctrl.bus->Reset(); - return ctrl.phase; - } - - // Phase processing - switch (ctrl.phase) { - // Bus free phase - case BUS::busfree: - BusFree(); - break; - - // Selection phase - case BUS::selection: - Selection(); - break; - - // Data out (MCI=000) - case BUS::dataout: - DataOut(); - break; - - // Data in (MCI=001) - case BUS::datain: - DataIn(); - break; - - // Command (MCI=010) - case BUS::command: - Command(); - break; - - // Status (MCI=011) - case BUS::status: - Status(); - break; - - // Message out (MCI=110) - case BUS::msgout: - MsgOut(); - break; - - // Message in (MCI=111) - case BUS::msgin: - MsgIn(); - break; - - // Other - default: - ASSERT(FALSE); - break; - } - - return ctrl.phase; -} - -//--------------------------------------------------------------------------- -// -// Phaes -// -//--------------------------------------------------------------------------- - -//--------------------------------------------------------------------------- -// -// Bus free phase -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::BusFree() -{ - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::busfree) { - -#if defined(DISK_LOG) - Log(Log::Normal, "Bus free phase"); -#endif // DISK_LOG - - // Phase setting - ctrl.phase = BUS::busfree; - - // Signal line - ctrl.bus->SetREQ(FALSE); - ctrl.bus->SetMSG(FALSE); - ctrl.bus->SetCD(FALSE); - ctrl.bus->SetIO(FALSE); - ctrl.bus->SetBSY(FALSE); - - // Initialize status and message - ctrl.status = 0x00; - ctrl.message = 0x00; - - // Initialize ATN message reception status - scsi.atnmsg = FALSE; - return; - } - - // Move to selection phase - if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) { - Selection(); - } -} - -//--------------------------------------------------------------------------- -// -// Selection Phase -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Selection() -{ - DWORD id; - - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::selection) { - // invalid if IDs do not match - id = 1 << ctrl.id; - if ((ctrl.bus->GetDAT() & id) == 0) { - return; - } - - // End if there is no valid unit - if (!HasUnit()) { - return; - } - -#if defined(DISK_LOG) - Log(Log::Normal, - "Selection Phase ID=%d (with device)", ctrl.id); -#endif // DISK_LOG - - // Phase setting - ctrl.phase = BUS::selection; - - // Raise BSY and respond - ctrl.bus->SetBSY(TRUE); - return; - } - - // Selection completed - if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) { - // Message out phase if ATN=1, otherwise command phase - if (ctrl.bus->GetATN()) { - MsgOut(); - } else { - Command(); - } - } -} - -//--------------------------------------------------------------------------- -// -// Execution Phase -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Execute() -{ - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "Execution phase command $%02X", ctrl.cmd[0]); -#endif // DISK_LOG - - // Phase Setting - ctrl.phase = BUS::execute; - - // Initialization for data transfer - ctrl.offset = 0; - ctrl.blocks = 1; -#ifdef RASCSI - ctrl.execstart = SysTimer::GetTimerLow(); -#endif // RASCSI - - // Process by command - switch (ctrl.cmd[0]) { - // TEST UNIT READY - case 0x00: - CmdTestUnitReady(); - return; - - // REZERO - case 0x01: - CmdRezero(); - return; - - // REQUEST SENSE - case 0x03: - CmdRequestSense(); - return; - - // FORMAT UNIT - case 0x04: - CmdFormat(); - return; - - // REASSIGN BLOCKS - case 0x07: - CmdReassign(); - return; - - // READ(6) - case 0x08: - CmdRead6(); - return; - - // WRITE(6) - case 0x0a: - CmdWrite6(); - return; - - // SEEK(6) - case 0x0b: - CmdSeek6(); - return; - - // INQUIRY - case 0x12: - CmdInquiry(); - return; - - // MODE SELECT - case 0x15: - CmdModeSelect(); - return; - - // MDOE SENSE - case 0x1a: - CmdModeSense(); - return; - - // START STOP UNIT - case 0x1b: - CmdStartStop(); - return; - - // SEND DIAGNOSTIC - case 0x1d: - CmdSendDiag(); - return; - - // PREVENT/ALLOW MEDIUM REMOVAL - case 0x1e: - CmdRemoval(); - return; - - // READ CAPACITY - case 0x25: - CmdReadCapacity(); - return; - - // READ(10) - case 0x28: - CmdRead10(); - return; - - // WRITE(10) - case 0x2a: - CmdWrite10(); - return; - - // SEEK(10) - case 0x2b: - CmdSeek10(); - return; - - // WRITE and VERIFY - case 0x2e: - CmdWrite10(); - return; - - // VERIFY - case 0x2f: - CmdVerify(); - return; - - // SYNCHRONIZE CACHE - case 0x35: - CmdSynchronizeCache(); - return; - - // READ DEFECT DATA(10) - case 0x37: - CmdReadDefectData10(); - return; - - // READ TOC - case 0x43: - CmdReadToc(); - return; - - // PLAY AUDIO(10) - case 0x45: - CmdPlayAudio10(); - return; - - // PLAY AUDIO MSF - case 0x47: - CmdPlayAudioMSF(); - return; - - // PLAY AUDIO TRACK - case 0x48: - CmdPlayAudioTrack(); - return; - - // MODE SELECT(10) - case 0x55: - CmdModeSelect10(); - return; - - // MDOE SENSE(10) - case 0x5a: - CmdModeSense10(); - return; - - // SPECIFY (SASI only/Suppress warning when using SxSI) - case 0xc2: - CmdInvalid(); - return; - - } - - // No other support - Log(Log::Normal, "Unsupported command received: $%02X", ctrl.cmd[0]); - CmdInvalid(); -} - -//--------------------------------------------------------------------------- -// -// Message out phase -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::MsgOut() -{ - ASSERT(this); - - // Phase change - if (ctrl.phase != BUS::msgout) { - -#if defined(DISK_LOG) - Log(Log::Normal, "Message Out Phase"); -#endif // DISK_LOG - - // Message out phase after selection - // process the IDENTIFY message - if (ctrl.phase == BUS::selection) { - scsi.atnmsg = TRUE; - scsi.msc = 0; - memset(scsi.msb, 0x00, sizeof(scsi.msb)); - } - - // Phase Setting - ctrl.phase = BUS::msgout; - - // Signal line operated by the target - ctrl.bus->SetMSG(TRUE); - ctrl.bus->SetCD(TRUE); - ctrl.bus->SetIO(FALSE); - - // Data transfer is 1 byte x 1 block - ctrl.offset = 0; - ctrl.length = 1; - ctrl.blocks = 1; - -#ifndef RASCSI - // Request message - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - -#ifdef RASCSI - // Receive - Receive(); -#else - // Requesting - if (ctrl.bus->GetREQ()) { - // Sent by the initiator - if (ctrl.bus->GetACK()) { - Receive(); - } - } else { - // Request the initator to - if (!ctrl.bus->GetACK()) { - ReceiveNext(); - } - } -#endif // RASCSI -} - -//--------------------------------------------------------------------------- -// -// Common Error Handling -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Error() -{ - ASSERT(this); - - // Get bus information - ctrl.bus->Aquire(); - - // Reset check - if (ctrl.bus->GetRST()) { - // Reset the controller - Reset(); - - // Reset the bus - ctrl.bus->Reset(); - return; - } - - // Bus free for status phase and message in phase - if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) { - BusFree(); - return; - } - -#if defined(DISK_LOG) - Log(Log::Normal, "Error (to status phase)"); -#endif // DISK_LOG - - // Set status and message(CHECK CONDITION) - ctrl.status = 0x02; - ctrl.message = 0x00; - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// Command -// -//--------------------------------------------------------------------------- - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdInquiry() -{ - Disk *disk; - int lun; - DWORD major; - DWORD minor; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "INQUIRY Command"); -#endif // DISK_LOG - - // Find a valid unit - disk = NULL; - for (lun = 0; lun < UnitMax; lun++) { - if (ctrl.unit[lun]) { - disk = ctrl.unit[lun]; - break; - } - } - - // Processed on the disk side (it is originally processed by the controller) - if (disk) { -#ifdef RASCSI - major = (DWORD)(RASCSI >> 8); - minor = (DWORD)(RASCSI & 0xff); -#else - host->GetVM()->GetVersion(major, minor); -#endif // RASCSI - ctrl.length = - ctrl.unit[lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor); - } else { - ctrl.length = 0; - } - - if (ctrl.length <= 0) { - // failure (error) - Error(); - return; - } - - // Add synchronous transfer support information - if (scsi.syncenable) { - ctrl.buffer[7] |= (1 << 4); - } - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// MODE SELECT -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdModeSelect() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SELECT Command"); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->SelectCheck(ctrl.cmd); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Data out phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// MODE SENSE -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdModeSense() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SENSE Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->ModeSense(ctrl.cmd, ctrl.buffer); - ASSERT(ctrl.length >= 0); - if (ctrl.length == 0) { - Log(Log::Warning, - "Not supported MODE SENSE page $%02X", ctrl.cmd[2]); - - // Failure (Error) - Error(); - return; - } - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// START STOP UNIT -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdStartStop() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "START STOP UNIT Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->StartStop(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// SEND DIAGNOSTIC -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdSendDiag() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "SEND DIAGNOSTIC Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->SendDiag(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// PREVENT/ALLOW MEDIUM REMOVAL -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdRemoval() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "PREVENT/ALLOW MEDIUM REMOVAL Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Removal(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// READ CAPACITY -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdReadCapacity() -{ - DWORD lun; - int length; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "READ CAPACITY Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer); - ASSERT(length >= 0); - if (length <= 0) { - Error(); - return; - } - - // Length setting - ctrl.length = length; - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// READ(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdRead10() -{ - DWORD lun; - DWORD record; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Receive message if host bridge - if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) { - CmdGetMessage10(); - return; - } - - // Get record number and block number - record = ctrl.cmd[2]; - record <<= 8; - record |= ctrl.cmd[3]; - record <<= 8; - record |= ctrl.cmd[4]; - record <<= 8; - record |= ctrl.cmd[5]; - ctrl.blocks = ctrl.cmd[7]; - ctrl.blocks <<= 8; - ctrl.blocks |= ctrl.cmd[8]; - -#if defined(DISK_LOG) - Log(Log::Normal, "READ(10) command record=%08X block=%d", record, ctrl.blocks); -#endif // DISK_LOG - - // Do not process 0 blocks - if (ctrl.blocks == 0) { - Status(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.next = record + 1; - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// WRITE(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdWrite10() -{ - DWORD lun; - DWORD record; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Receive message with host bridge - if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) { - CmdSendMessage10(); - return; - } - - // Get record number and block number - record = ctrl.cmd[2]; - record <<= 8; - record |= ctrl.cmd[3]; - record <<= 8; - record |= ctrl.cmd[4]; - record <<= 8; - record |= ctrl.cmd[5]; - ctrl.blocks = ctrl.cmd[7]; - ctrl.blocks <<= 8; - ctrl.blocks |= ctrl.cmd[8]; - -#if defined(DISK_LOG) - Log(Log::Normal, - "WRTIE(10) command record=%08X blocks=%d", record, ctrl.blocks); -#endif // DISK_LOG - - // Do not process 0 blocks - if (ctrl.blocks == 0) { - Status(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->WriteCheck(record); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.next = record + 1; - - // Data out phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// SEEK(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdSeek10() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "SEEK(10) Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->Seek(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// VERIFY -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdVerify() -{ - DWORD lun; - BOOL status; - DWORD record; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Get record number and block number - record = ctrl.cmd[2]; - record <<= 8; - record |= ctrl.cmd[3]; - record <<= 8; - record |= ctrl.cmd[4]; - record <<= 8; - record |= ctrl.cmd[5]; - ctrl.blocks = ctrl.cmd[7]; - ctrl.blocks <<= 8; - ctrl.blocks |= ctrl.cmd[8]; - -#if defined(DISK_LOG) - Log(Log::Normal, - "VERIFY command record=%08X blocks=%d", record, ctrl.blocks); -#endif // DISK_LOG - - // Do not process 0 blocks - if (ctrl.blocks == 0) { - Status(); - return; - } - - // if BytChk=0 - if ((ctrl.cmd[1] & 0x02) == 0) { - // Command processing on drive - status = ctrl.unit[lun]->Seek(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); - return; - } - - // Test loading - ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.next = record + 1; - - // Data out phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// SYNCHRONIZE CACHE -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdSynchronizeCache() -{ - DWORD lun; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Make it do something (not implemented)... - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// READ DEFECT DATA(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdReadDefectData10() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "READ DEFECT DATA(10) Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->ReadDefectData10(ctrl.cmd, ctrl.buffer); - ASSERT(ctrl.length >= 0); - - if (ctrl.length <= 4) { - Error(); - return; - } - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// READ TOC -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdReadToc() -{ - DWORD lun; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->ReadToc(ctrl.cmd, ctrl.buffer); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// PLAY AUDIO(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdPlayAudio10() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->PlayAudio(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// PLAY AUDIO MSF -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdPlayAudioMSF() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// PLAY AUDIO TRACK -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdPlayAudioTrack() -{ - DWORD lun; - BOOL status; - - ASSERT(this); - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd); - if (!status) { - // Failure (Error) - Error(); - return; - } - - // status phase - Status(); -} - -//--------------------------------------------------------------------------- -// -// MODE SELECT10 -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdModeSelect10() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SELECT10 Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->SelectCheck10(ctrl.cmd); - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Data out phase - DataOut(); -} - -//--------------------------------------------------------------------------- -// -// MODE SENSE(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdModeSense10() -{ - DWORD lun; - - ASSERT(this); - -#if defined(DISK_LOG) - Log(Log::Normal, "MODE SENSE(10) Command "); -#endif // DISK_LOG - - // Logical Unit - lun = (ctrl.cmd[1] >> 5) & 0x07; - if (!ctrl.unit[lun]) { - Error(); - return; - } - - // Command processing on drive - ctrl.length = ctrl.unit[lun]->ModeSense10(ctrl.cmd, ctrl.buffer); - ASSERT(ctrl.length >= 0); - if (ctrl.length == 0) { - Log(Log::Warning, - "Not supported MODE SENSE(10) page $%02X", ctrl.cmd[2]); - - // Failure (Error) - Error(); - return; - } - - // Data-in Phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// GET MESSAGE(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdGetMessage10() -{ - DWORD lun; - SCSIBR *bridge; - - 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', 'B', 'R')) { - 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); - } - - // Process with drive - bridge = (SCSIBR*)ctrl.unit[lun]; - ctrl.length = bridge->GetMessage10(ctrl.cmd, ctrl.buffer); - - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.blocks = 1; - ctrl.next = 1; - - // Data in phase - DataIn(); -} - -//--------------------------------------------------------------------------- -// -// SEND MESSAGE(10) -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::CmdSendMessage10() -{ - DWORD lun; - - 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', 'B', 'R')) { - 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); - } - - // Set transfer amount - ctrl.length = ctrl.cmd[6]; - ctrl.length <<= 8; - ctrl.length |= ctrl.cmd[7]; - ctrl.length <<= 8; - ctrl.length |= ctrl.cmd[8]; - - if (ctrl.length <= 0) { - // Failure (Error) - Error(); - return; - } - - // Set next block - ctrl.blocks = 1; - ctrl.next = 1; - - // Light phase - DataOut(); -} - -//=========================================================================== -// -// Data Transfer -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Send data -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Send() -{ -#ifdef RASCSI - int len; -#endif // RASCSI - BOOL result; - - ASSERT(this); - ASSERT(!ctrl.bus->GetREQ()); - ASSERT(ctrl.bus->GetIO()); - -#ifdef RASCSI - //if Length! = 0, send - if (ctrl.length != 0) { - len = ctrl.bus->SendHandShake( - &ctrl.buffer[ctrl.offset], ctrl.length); - - // If you cannot send all, move to status phase - if (len != (int)ctrl.length) { - Error(); - return; - } - - // offset and length - ctrl.offset += ctrl.length; - ctrl.length = 0; - return; - } -#else - // offset and length - ASSERT(ctrl.length >= 1); - ctrl.offset++; - ctrl.length--; - - // Immediately after ACK is asserted, if the data has been - // set by SendNext, raise the request - if (ctrl.length != 0) { - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); - return; - } -#endif // RASCSI - - // Block subtraction, result initialization - ctrl.blocks--; - result = TRUE; - - // Processing after data collection (read/data-in only) - if (ctrl.phase == BUS::datain) { - if (ctrl.blocks != 0) { - // // set next buffer (set offset, length) - result = XferIn(ctrl.buffer); -#ifndef RASCSI - ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]); -#endif // RASCSI - } - } - - // If result FALSE, move to status phase - if (!result) { - Error(); - return; - } - - // Continue sending if block !=0 - if (ctrl.blocks != 0){ - ASSERT(ctrl.length > 0); - ASSERT(ctrl.offset == 0); -#ifndef RASCSI - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - - // Move to next phase - switch (ctrl.phase) { - // Message in phase - case BUS::msgin: - // Completed sending response to extended message of IDENTIFY message - if (scsi.atnmsg) { - // flag off - scsi.atnmsg = FALSE; - - // command phase - Command(); - } else { - // Bus free phase - BusFree(); - } - break; - - // Data-in Phase - case BUS::datain: - // status phase - Status(); - break; - - // status phase - case BUS::status: - // Message in phase - ctrl.length = 1; - ctrl.blocks = 1; - ctrl.buffer[0] = (BYTE)ctrl.message; - MsgIn(); - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Continue data transmission..... -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::SendNext() -{ - ASSERT(this); - - // REQ is up - ASSERT(ctrl.bus->GetREQ()); - ASSERT(ctrl.bus->GetIO()); - - // Signal line operated by the target - ctrl.bus->SetREQ(FALSE); - - // If there is data in the buffer, set it first - if (ctrl.length > 1) { - ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset + 1]); - } -} -#endif // RASCSI - -#ifndef RASCSI -//--------------------------------------------------------------------------- -// -// Receive data -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Receive() -{ - DWORD data; - - ASSERT(this); - - // Req is up - ASSERT(ctrl.bus->GetREQ()); - ASSERT(!ctrl.bus->GetIO()); - - // Get data - data = (DWORD)ctrl.bus->GetDAT(); - - // Signal line operated by the target - ctrl.bus->SetREQ(FALSE); - - switch (ctrl.phase) { - // Command phase - case BUS::command: - ctrl.cmd[ctrl.offset] = data; -#if defined(DISK_LOG) - Log(Log::Normal, "Command phase $%02X", data); -#endif // DISK_LOG - - // Set the length again with the first data (offset 0) - if (ctrl.offset == 0) { - if (ctrl.cmd[0] >= 0x20) { - // 10バイトCDB - ctrl.length = 10; - } - } - break; - - // Message out phase - case BUS::msgout: - ctrl.message = data; -#if defined(DISK_LOG) - Log(Log::Normal, "Message out phase $%02X", data); -#endif // DISK_LOG - break; - - // Data out phase - case BUS::dataout: - ctrl.buffer[ctrl.offset] = (BYTE)data; - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} -#endif // RASCSI - -#ifdef RASCSI -//--------------------------------------------------------------------------- -// -// Receive Data -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::Receive() -#else -//--------------------------------------------------------------------------- -// -// Continue receiving data -// -//--------------------------------------------------------------------------- -void FASTCALL SCSIDEV::ReceiveNext() -#endif // RASCSI -{ -#ifdef RASCSI - int len; -#endif // RASCSI - BOOL result; - int i; - BYTE data; - - ASSERT(this); - - // REQ is low - ASSERT(!ctrl.bus->GetREQ()); - ASSERT(!ctrl.bus->GetIO()); - -#ifdef RASCSI - // Length != 0 if received - if (ctrl.length != 0) { - // Receive - len = ctrl.bus->ReceiveHandShake( - &ctrl.buffer[ctrl.offset], ctrl.length); - - // If not able to receive all, move to status phase - if (len != (int)ctrl.length) { - Error(); - return; - } - - // Offset and Length - ctrl.offset += ctrl.length; - ctrl.length = 0;; - return; - } -#else - // Offset and Length - ASSERT(ctrl.length >= 1); - ctrl.offset++; - ctrl.length--; - - // If length!=0, set req again - if (ctrl.length != 0) { - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); - return; - } -#endif // RASCSI - - // Block subtraction, result initialization - ctrl.blocks--; - result = TRUE; - - // Processing after receiving data (by phase) - switch (ctrl.phase) { - - // Data out phase - case BUS::dataout: - if (ctrl.blocks == 0) { - // End with this buffer - result = XferOut(FALSE); - } else { - // Continue to next buffer (set offset, length) - result = XferOut(TRUE); - } - break; - - // Message out phase - case BUS::msgout: - ctrl.message = ctrl.buffer[0]; - if (!XferMsg(ctrl.message)) { - // Immediately free the bus if message output fails - BusFree(); - return; - } - - // Clear message data in preparation for message-in - ctrl.message = 0x00; - break; - - default: - break; - } - - // If result FALSE, move to status phase - if (!result) { - Error(); - return; - } - - // Continue to receive if block !=0 - if (ctrl.blocks != 0){ - ASSERT(ctrl.length > 0); - ASSERT(ctrl.offset == 0); -#ifndef RASCSI - // Signal line operated by the target - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - - // Move to next phase - switch (ctrl.phase) { - // Command phase - case BUS::command: -#ifdef RASCSI - // Command data transfer - len = 6; - if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) { - // 10 byte CDB - len = 10; - } - for (i = 0; i < len; i++) { - ctrl.cmd[i] = (DWORD)ctrl.buffer[i]; -#if defined(DISK_LOG) - Log(Log::Normal, "Command $%02X", ctrl.cmd[i]); -#endif // DISK_LOG - } -#endif // RASCSI - - // Execution Phase - Execute(); - break; - - // Message out phase - case BUS::msgout: - // Continue message out phase as long as ATN keeps asserting - if (ctrl.bus->GetATN()) { - // Data transfer is 1 byte x 1 block - ctrl.offset = 0; - ctrl.length = 1; - ctrl.blocks = 1; -#ifndef RASCSI - // Request message - ctrl.bus->SetREQ(TRUE); -#endif // RASCSI - return; - } - - // Parsing messages sent by ATN - if (scsi.atnmsg) { - i = 0; - while (i < scsi.msc) { - // Message type - data = scsi.msb[i]; - - // ABORT - if (data == 0x06) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code ABORT $%02X", data); -#endif // DISK_LOG - BusFree(); - return; - } - - // BUS DEVICE RESET - if (data == 0x0C) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code BUS DEVICE RESET $%02X", data); -#endif // DISK_LOG - scsi.syncoffset = 0; - BusFree(); - return; - } - - // IDENTIFY - if (data >= 0x80) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code IDENTIFY $%02X", data); -#endif // DISK_LOG - } - - // Extended Message - if (data == 0x01) { -#if defined(DISK_LOG) - Log(Log::Normal, - "Message code EXTENDED MESSAGE $%02X", data); -#endif // DISK_LOG - - // Check only when synchronous transfer is possible - if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) { - ctrl.length = 1; - ctrl.blocks = 1; - ctrl.buffer[0] = 0x07; - MsgIn(); - return; - } - - // Transfer period factor (limited to 50 x 4 = 200ns) - scsi.syncperiod = scsi.msb[i + 3]; - if (scsi.syncperiod > 50) { - scsi.syncoffset = 50; - } - - // REQ/ACK offset(limited to 16) - scsi.syncoffset = scsi.msb[i + 4]; - if (scsi.syncoffset > 16) { - scsi.syncoffset = 16; - } - - // STDR response message generation - ctrl.length = 5; - ctrl.blocks = 1; - ctrl.buffer[0] = 0x01; - ctrl.buffer[1] = 0x03; - ctrl.buffer[2] = 0x01; - ctrl.buffer[3] = (BYTE)scsi.syncperiod; - ctrl.buffer[4] = (BYTE)scsi.syncoffset; - MsgIn(); - return; - } - - // next - i++; - } - } - - // Initialize ATN message reception status - scsi.atnmsg = FALSE; - - // Command phase - Command(); - break; - - // Data out phase - case BUS::dataout: - // Flush unit - FlushUnit(); - - // status phase - Status(); - break; - - // Other (impossible) - default: - ASSERT(FALSE); - break; - } -} - -//--------------------------------------------------------------------------- -// -// Transfer MSG -// -//--------------------------------------------------------------------------- -BOOL FASTCALL SCSIDEV::XferMsg(DWORD msg) -{ - ASSERT(this); - ASSERT(ctrl.phase == BUS::msgout); - - // Save message out data - if (scsi.atnmsg) { - scsi.msb[scsi.msc] = (BYTE)msg; - scsi.msc++; - scsi.msc %= 256; - } - - return TRUE; -} diff --git a/src/raspberrypi/disk.h b/src/raspberrypi/disk.h index 10593e6..7383028 100644 --- a/src/raspberrypi/disk.h +++ b/src/raspberrypi/disk.h @@ -15,11 +15,11 @@ // //--------------------------------------------------------------------------- -#if !defined(disk_h) -#define disk_h +#pragma once #include "log.h" #include "scsi.h" +#include "filepath.h" //--------------------------------------------------------------------------- // @@ -59,6 +59,15 @@ #define DISK_AUDIOCOMPLETE 0x00??0013 // AUDIO PLAY SUCCESSFULLY COMPLETED #endif + +#ifdef RASCSI +#define BENDER_SIGNATURE "RaSCSI" +// The following line was to mimic Apple's CDROM ID +// #define BENDER_SIGNATURE "SONY " +#else +#define BENDER_SIGNATURE "XM6" +#endif + //=========================================================================== // // Disk Track @@ -354,795 +363,3 @@ protected: BOOL cache_wb; // Cache mode }; - -//=========================================================================== -// -// SASI Hard Disk -// -//=========================================================================== -class SASIHD : public Disk -{ -public: - // Basic Functions - SASIHD(); - // Constructor - void FASTCALL Reset(); - // Reset - BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); - // Open - // commands - int FASTCALL RequestSense(const DWORD *cdb, BYTE *buf); - // REQUEST SENSE command -}; - -//=========================================================================== -// -// SCSI Hard Disk -// -//=========================================================================== -class SCSIHD : public Disk -{ -public: - // Basic Functions - SCSIHD(); - // Constructor - void FASTCALL Reset(); - // Reset - BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); - // Open - - // commands - int FASTCALL Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); - // INQUIRY command - BOOL FASTCALL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); - // MODE SELECT(6) command -}; - -//=========================================================================== -// -// SCSI hard disk (PC-9801-55 NEC genuine /Anex86/T98Next) -// -//=========================================================================== -class SCSIHD_NEC : public SCSIHD -{ -public: - // Basic Functions - SCSIHD_NEC(); - // Constructor - - BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); - // Open - - // commands - int FASTCALL Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); - // INQUIRY command - - // Internal processing - int FASTCALL AddError(BOOL change, BYTE *buf); - // Add error - int FASTCALL AddFormat(BOOL change, BYTE *buf); - // Add format - int FASTCALL AddDrive(BOOL change, BYTE *buf); - // Add drive - -private: - int cylinders; - // Number of cylinders - int heads; - // Number of heads - int sectors; - // Number of sectors - int sectorsize; - // Sector size - off64_t imgoffset; - // Image offset - off64_t imgsize; - // Image size -}; - -//=========================================================================== -// -// SCSI Hard Disk(Genuine Apple Macintosh) -// -//=========================================================================== -class SCSIHD_APPLE : public SCSIHD -{ -public: - // Basic Functions - SCSIHD_APPLE(); - // Constructor - // commands - int FASTCALL Inquiry( - const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); - // INQUIRY command - - // Internal processing - int FASTCALL AddVendor(int page, BOOL change, BYTE *buf); - // Add vendor special page -}; - -//=========================================================================== -// -// SCSI magneto-optical disk -// -//=========================================================================== -class SCSIMO : public Disk -{ -public: - // Basic Functions - SCSIMO(); - // Constructor - BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); - // Open -#ifndef RASCSI - BOOL FASTCALL Load(Fileio *fio, int ver); - // Load -#endif // RASCSI - - // commands - int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); - // INQUIRY command - BOOL FASTCALL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); - // MODE SELECT(6) command - - // Internal processing - int FASTCALL AddVendor(int page, BOOL change, BYTE *buf); - // Add vendor special page -}; - -//--------------------------------------------------------------------------- -// -// Class precedence definition -// -//--------------------------------------------------------------------------- -class SCSICD; - -//=========================================================================== -// -// CD-ROM Track -// -//=========================================================================== -class CDTrack -{ -public: - // Basic Functions - CDTrack(SCSICD *scsicd); - // Constructor - virtual ~CDTrack(); - // Destructor - BOOL FASTCALL Init(int track, DWORD first, DWORD last); - // Initialization - - // Properties - void FASTCALL SetPath(BOOL cdda, const Filepath& path); - // Set the path - void FASTCALL GetPath(Filepath& path) const; - // Get the path - void FASTCALL AddIndex(int index, DWORD lba); - // Add index - DWORD FASTCALL GetFirst() const; - // Get the start LBA - DWORD FASTCALL GetLast() const; - // Get the last LBA - DWORD FASTCALL GetBlocks() const; - // Get the number of blocks - int FASTCALL GetTrackNo() const; - // Get the track number - BOOL FASTCALL IsValid(DWORD lba) const; - // Is this a valid LBA? - BOOL FASTCALL IsAudio() const; - // Is this an audio track? - -private: - SCSICD *cdrom; - // Parent device - BOOL valid; - // Valid track - int track_no; - // Track number - DWORD first_lba; - // First LBA - DWORD last_lba; - // Last LBA - BOOL audio; - // Audio track flag - BOOL raw; - // RAW data flag - Filepath imgpath; - // Image file path -}; - -//=========================================================================== -// -// CD-DA Buffer -// -//=========================================================================== -class CDDABuf -{ -public: - // Basic Functions - CDDABuf(); - // Constructor - virtual ~CDDABuf(); - // Destructor -#if 0 - BOOL Init(); - // Initialization - BOOL FASTCALL Load(const Filepath& path); - // Load - BOOL FASTCALL Save(const Filepath& path); - // Save - - // API - void FASTCALL Clear(); - // Clear the buffer - BOOL FASTCALL Open(Filepath& path); - // File specification - BOOL FASTCALL GetBuf(DWORD *buffer, int frames); - // Get the buffer - BOOL FASTCALL IsValid(); - // Check if Valid - BOOL FASTCALL ReadReq(); - // Read Request - BOOL FASTCALL IsEnd() const; - // Finish check - -private: - Filepath wavepath; - // Wave path - BOOL valid; - // Open result (is it valid?) - DWORD *buf; - // Data buffer - DWORD read; - // Read pointer - DWORD write; - // Write pointer - DWORD num; - // Valid number of data - DWORD rest; - // Remaining file size -#endif -}; - -//=========================================================================== -// -// SCSI CD-ROM -// -//=========================================================================== -class SCSICD : public Disk -{ -public: - // Number of tracks - enum { - TrackMax = 96 // Maximum number of tracks - }; - -public: - // Basic Functions - SCSICD(); - // Constructor - virtual ~SCSICD(); - // Destructor - BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); - // Open -#ifndef RASCSI - BOOL FASTCALL Load(Fileio *fio, int ver); - // Load -#endif // RASCSI - - // commands - int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); - // INQUIRY command - int FASTCALL Read(BYTE *buf, DWORD block); - // READ command - int FASTCALL ReadToc(const DWORD *cdb, BYTE *buf); - // READ TOC command - BOOL FASTCALL PlayAudio(const DWORD *cdb); - // PLAY AUDIO command - BOOL FASTCALL PlayAudioMSF(const DWORD *cdb); - // PLAY AUDIO MSF command - BOOL FASTCALL PlayAudioTrack(const DWORD *cdb); - // PLAY AUDIO TRACK command - - // CD-DA - BOOL FASTCALL NextFrame(); - // Frame notification - void FASTCALL GetBuf(DWORD *buffer, int samples, DWORD rate); - // Get CD-DA buffer - - // LBA-MSF変換 - void FASTCALL LBAtoMSF(DWORD lba, BYTE *msf) const; - // LBA→MSF conversion - DWORD FASTCALL MSFtoLBA(const BYTE *msf) const; - // MSF→LBA conversion - -private: - // Open - BOOL FASTCALL OpenCue(const Filepath& path); - // Open(CUE) - BOOL FASTCALL OpenIso(const Filepath& path); - // Open(ISO) - BOOL FASTCALL OpenPhysical(const Filepath& path); - // Open(Physical) - BOOL rawfile; - // RAW flag - - // Track management - void FASTCALL ClearTrack(); - // Clear the track - int FASTCALL SearchTrack(DWORD lba) const; - // Track search - CDTrack* track[TrackMax]; - // Track opbject references - int tracks; - // Effective number of track objects - int dataindex; - // Current data track - int audioindex; - // Current audio track - - int frame; - // Frame number - -#if 0 - CDDABuf da_buf; - // CD-DA buffer - int da_num; - // Number of CD-DA tracks - int da_cur; - // CD-DA current track - int da_next; - // CD-DA next track - BOOL da_req; - // CD-DA data request -#endif -}; - -//=========================================================================== -// -// SCSI Host Bridge -// -//=========================================================================== -#if defined(RASCSI) && !defined(BAREMETAL) -class CTapDriver; -#endif // RASCSI && !BAREMETAL -class CFileSys; -class SCSIBR : public Disk -{ -public: - // Basic Functions - SCSIBR(); - // Constructor - virtual ~SCSIBR(); - // Destructor - - // commands - int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); - // INQUIRY command - BOOL FASTCALL TestUnitReady(const DWORD *cdb); - // TEST UNIT READY command - int FASTCALL GetMessage10(const DWORD *cdb, BYTE *buf); - // GET MESSAGE10 command - BOOL FASTCALL SendMessage10(const DWORD *cdb, BYTE *buf); - // SEND MESSAGE10 command - -private: -#if defined(RASCSI) && !defined(BAREMETAL) - int FASTCALL GetMacAddr(BYTE *buf); - // Get MAC address - void FASTCALL SetMacAddr(BYTE *buf); - // Set MAC address - void FASTCALL ReceivePacket(); - // Receive a packet - void FASTCALL GetPacketBuf(BYTE *buf); - // Get a packet - void FASTCALL SendPacket(BYTE *buf, int len); - // Send a packet - - CTapDriver *tap; - // TAP driver - BOOL m_bTapEnable; - // TAP valid flag - BYTE mac_addr[6]; - // MAC Addres - int packet_len; - // Receive packet size - BYTE packet_buf[0x1000]; - // Receive packet buffer - BOOL packet_enable; - // Received packet valid -#endif // RASCSI && !BAREMETAL - - int FASTCALL ReadFsResult(BYTE *buf); - // Read filesystem (result code) - int FASTCALL ReadFsOut(BYTE *buf); - // Read filesystem (return data) - int FASTCALL ReadFsOpt(BYTE *buf); - // Read file system (optional data) - void FASTCALL WriteFs(int func, BYTE *buf); - // File system write (execute) - void FASTCALL WriteFsOpt(BYTE *buf, int len); - // File system write (optional data) - // Command handlers - void FASTCALL FS_InitDevice(BYTE *buf); - // $40 - boot - void FASTCALL FS_CheckDir(BYTE *buf); - // $41 - directory check - void FASTCALL FS_MakeDir(BYTE *buf); - // $42 - create directory - void FASTCALL FS_RemoveDir(BYTE *buf); - // $43 - delete directory - void FASTCALL FS_Rename(BYTE *buf); - // $44 - change filename - void FASTCALL FS_Delete(BYTE *buf); - // $45 - delete file - void FASTCALL FS_Attribute(BYTE *buf); - // $46 - get/set file attributes - void FASTCALL FS_Files(BYTE *buf); - // $47 - file search - void FASTCALL FS_NFiles(BYTE *buf); - // $48 - find next file - void FASTCALL FS_Create(BYTE *buf); - // $49 - create file - void FASTCALL FS_Open(BYTE *buf); - // $4A - open file - void FASTCALL FS_Close(BYTE *buf); - // $4B - close file - void FASTCALL FS_Read(BYTE *buf); - // $4C - read file - void FASTCALL FS_Write(BYTE *buf); - // $4D - write file - void FASTCALL FS_Seek(BYTE *buf); - // $4E - seek file - void FASTCALL FS_TimeStamp(BYTE *buf); - // $4F - get/set file time - void FASTCALL FS_GetCapacity(BYTE *buf); - // $50 - get capacity - void FASTCALL FS_CtrlDrive(BYTE *buf); - // $51 - drive status check/control - void FASTCALL FS_GetDPB(BYTE *buf); - // $52 - get DPB - void FASTCALL FS_DiskRead(BYTE *buf); - // $53 - read sector - void FASTCALL FS_DiskWrite(BYTE *buf); - // $54 - write sector - void FASTCALL FS_Ioctrl(BYTE *buf); - // $55 - IOCTRL - void FASTCALL FS_Flush(BYTE *buf); - // $56 - flush cache - void FASTCALL FS_CheckMedia(BYTE *buf); - // $57 - check media - void FASTCALL FS_Lock(BYTE *buf); - // $58 - get exclusive control - - CFileSys *fs; - // File system accessor - DWORD fsresult; - // File system access result code - BYTE fsout[0x800]; - // File system access result buffer - DWORD fsoutlen; - // File system access result buffer size - BYTE fsopt[0x1000000]; - // File system access buffer - DWORD fsoptlen; - // File system access buffer size -}; - -//=========================================================================== -// -// SASI Controller -// -//=========================================================================== -class SASIDEV -{ -public: - // Maximum number of logical units - enum { - UnitMax = 8 - }; - -#ifdef RASCSI - // For timing adjustments - enum { - min_exec_time_sasi = 100, // SASI BOOT/FORMAT 30:NG 35:OK - min_exec_time_scsi = 50 - }; -#endif // RASCSI - - // Internal data definition - typedef struct { - // 全般 - BUS::phase_t phase; // Transition phase - int id; // Controller ID (0-7) - BUS *bus; // Bus - - // commands - DWORD cmd[10]; // Command data - DWORD status; // Status data - DWORD message; // Message data - -#ifdef RASCSI - // Run - DWORD execstart; // Execution start time -#endif // RASCSI - - // Transfer - BYTE *buffer; // Transfer data buffer - int bufsize; // Transfer data buffer size - DWORD blocks; // Number of transfer block - DWORD next; // Next record - DWORD offset; // Transfer offset - DWORD length; // Transfer remaining length - - // Logical unit - Disk *unit[UnitMax]; - // Logical Unit - } ctrl_t; - -public: - // Basic Functions -#ifdef RASCSI - SASIDEV(); -#else - SASIDEV(Device *dev); -#endif //RASCSI - - // Constructor - virtual ~SASIDEV(); - // Destructor - virtual void FASTCALL Reset(); - // Device Reset -#ifndef RASCSI - virtual BOOL FASTCALL Save(Fileio *fio, int ver); - // Save - virtual BOOL FASTCALL Load(Fileio *fio, int ver); - // Load -#endif //RASCSI - - // External API - virtual BUS::phase_t FASTCALL Process(); - // Run - - // Connect - void FASTCALL Connect(int id, BUS *sbus); - // Controller connection - Disk* FASTCALL GetUnit(int no); - // Get logical unit - void FASTCALL SetUnit(int no, Disk *dev); - // Logical unit setting - BOOL FASTCALL HasUnit(); - // Has a valid logical unit - - // Other - BUS::phase_t FASTCALL GetPhase() {return ctrl.phase;} - // Get the phase -#ifdef DISK_LOG - // Function to get the current phase as a String. - void FASTCALL GetPhaseStr(char *str); -#endif - - int FASTCALL GetID() {return ctrl.id;} - // Get the ID - void FASTCALL GetCTRL(ctrl_t *buffer); - // Get the internal information - ctrl_t* FASTCALL GetWorkAddr() { return &ctrl; } - // Get the internal information address - virtual BOOL FASTCALL IsSASI() const {return TRUE;} - // SASI Check - virtual BOOL FASTCALL IsSCSI() const {return FALSE;} - // SCSI check - Disk* FASTCALL GetBusyUnit(); - // Get the busy unit - -protected: - // Phase processing - virtual void FASTCALL BusFree(); - // Bus free phase - virtual void FASTCALL Selection(); - // Selection phase - virtual void FASTCALL Command(); - // Command phase - virtual void FASTCALL Execute(); - // Execution phase - void FASTCALL Status(); - // Status phase - void FASTCALL MsgIn(); - // Message in phase - void FASTCALL DataIn(); - // Data in phase - void FASTCALL DataOut(); - // Data out phase - virtual void FASTCALL Error(); - // Common error handling - - // commands - void FASTCALL CmdTestUnitReady(); - // TEST UNIT READY command - void FASTCALL CmdRezero(); - // REZERO UNIT command - void FASTCALL CmdRequestSense(); - // REQUEST SENSE command - void FASTCALL CmdFormat(); - // FORMAT command - void FASTCALL CmdReassign(); - // REASSIGN BLOCKS command - void FASTCALL CmdRead6(); - // READ(6) command - void FASTCALL CmdWrite6(); - // WRITE(6) command - void FASTCALL CmdSeek6(); - // SEEK(6) command - void FASTCALL CmdAssign(); - // ASSIGN command - void FASTCALL CmdSpecify(); - // SPECIFY command - void FASTCALL CmdInvalid(); - // Unsupported command - - // データ転送 - virtual void FASTCALL Send(); - // Send data -#ifndef RASCSI - virtual void FASTCALL SendNext(); - // Continue sending data -#endif // RASCSI - virtual void FASTCALL Receive(); - // Receive data -#ifndef RASCSI - virtual void FASTCALL ReceiveNext(); - // Continue receiving data -#endif // RASCSI - BOOL FASTCALL XferIn(BYTE* buf); - // Data transfer IN - BOOL FASTCALL XferOut(BOOL cont); - // Data transfer OUT - - // Special operations - void FASTCALL FlushUnit(); - // Flush the logical unit - - // Log - void FASTCALL Log(Log::loglevel level, const char *format, ...); - // Log output - -protected: -#ifndef RASCSI - Device *host; - // Host device -#endif // RASCSI - - ctrl_t ctrl; - // Internal data -}; - -//=========================================================================== -// -// SCSI Device (Interits SASI device) -// -//=========================================================================== -class SCSIDEV : public SASIDEV -{ -public: - // Internal data definition - typedef struct { - // Synchronous transfer - BOOL syncenable; // Synchronous transfer possible - int syncperiod; // Synchronous transfer period - int syncoffset; // Synchronous transfer offset - int syncack; // Number of synchronous transfer ACKs - - // ATN message - BOOL atnmsg; - int msc; - BYTE msb[256]; - } scsi_t; - -public: - // Basic Functions -#ifdef RASCSI - SCSIDEV(); -#else - SCSIDEV(Device *dev); -#endif // RASCSI - // Constructor - - void FASTCALL Reset(); - // Device Reset - - // 外部API - BUS::phase_t FASTCALL Process(); - // Run - - void FASTCALL SyncTransfer(BOOL enable) { scsi.syncenable = enable; } - // Synchronouse transfer enable setting - - // Other - BOOL FASTCALL IsSASI() const {return FALSE;} - // SASI Check - BOOL FASTCALL IsSCSI() const {return TRUE;} - // SCSI check - -private: - // Phase - void FASTCALL BusFree(); - // Bus free phase - void FASTCALL Selection(); - // Selection phase - void FASTCALL Execute(); - // Execution phase - void FASTCALL MsgOut(); - // Message out phase - void FASTCALL Error(); - // Common erorr handling - - // commands - void FASTCALL CmdInquiry(); - // INQUIRY command - void FASTCALL CmdModeSelect(); - // MODE SELECT command - void FASTCALL CmdModeSense(); - // MODE SENSE command - void FASTCALL CmdStartStop(); - // START STOP UNIT command - void FASTCALL CmdSendDiag(); - // SEND DIAGNOSTIC command - void FASTCALL CmdRemoval(); - // PREVENT/ALLOW MEDIUM REMOVAL command - void FASTCALL CmdReadCapacity(); - // READ CAPACITY command - void FASTCALL CmdRead10(); - // READ(10) command - void FASTCALL CmdWrite10(); - // WRITE(10) command - void FASTCALL CmdSeek10(); - // SEEK(10) command - void FASTCALL CmdVerify(); - // VERIFY command - void FASTCALL CmdSynchronizeCache(); - // SYNCHRONIZE CACHE command - void FASTCALL CmdReadDefectData10(); - // READ DEFECT DATA(10) command - void FASTCALL CmdReadToc(); - // READ TOC command - void FASTCALL CmdPlayAudio10(); - // PLAY AUDIO(10) command - void FASTCALL CmdPlayAudioMSF(); - // PLAY AUDIO MSF command - void FASTCALL CmdPlayAudioTrack(); - // PLAY AUDIO TRACK INDEX command - void FASTCALL CmdModeSelect10(); - // MODE SELECT(10) command - void FASTCALL CmdModeSense10(); - // MODE SENSE(10) command - void FASTCALL CmdGetMessage10(); - // GET MESSAGE(10) command - void FASTCALL CmdSendMessage10(); - // SEND MESSAGE(10) command - - // データ転送 - void FASTCALL Send(); - // Send data -#ifndef RASCSI - void FASTCALL SendNext(); - // Continue sending data -#endif // RASCSI - void FASTCALL Receive(); - // Receive data -#ifndef RASCSI - void FASTCALL ReceiveNext(); - // Continue receiving data -#endif // RASCSI - BOOL FASTCALL XferMsg(DWORD msg); - // Data transfer message - - scsi_t scsi; - // Internal data -}; - - - -#endif // disk_h diff --git a/src/raspberrypi/disks/sasihd.cpp b/src/raspberrypi/disks/sasihd.cpp new file mode 100644 index 0000000..ba0a8cb --- /dev/null +++ b/src/raspberrypi/disks/sasihd.cpp @@ -0,0 +1,164 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SASI hard disk ] +// +//--------------------------------------------------------------------------- +#include "sasihd.h" +#include "xm6.h" +#include "fileio.h" + + +//=========================================================================== +// +// SASI Hard Disk +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +SASIHD::SASIHD() : Disk() +{ + // SASI ハードディスク + disk.id = MAKEID('S', 'A', 'H', 'D'); +} + +//--------------------------------------------------------------------------- +// +// リセット +// +//--------------------------------------------------------------------------- +void FASTCALL SASIHD::Reset() +{ + // ロック状態解除、アテンション解除 + disk.lock = FALSE; + disk.attn = FALSE; + + // Resetなし、コードをクリア + disk.reset = FALSE; + disk.code = 0x00; +} + +//--------------------------------------------------------------------------- +// +// オープン +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SASIHD::Open(const Filepath& path, BOOL /*attn*/) +{ + Fileio fio; + off64_t size; + + ASSERT(this); + ASSERT(!disk.ready); + + // Open as read-only + if (!fio.Open(path, Fileio::ReadOnly)) { + return FALSE; + } + + // Get file size + size = fio.GetFileSize(); + fio.Close(); + +#if defined(USE_MZ1F23_1024_SUPPORT) + // MZ-2500/MZ-2800用 MZ-1F23(SASI 20M/セクタサイズ1024)専用 + // 20M(22437888 BS=1024 C=21912) + if (size == 0x1566000) { + // セクタサイズとブロック数 + disk.size = 10; + disk.blocks = (DWORD)(size >> 10); + + // Call the base class + return Disk::Open(path); + } +#endif // USE_MZ1F23_1024_SUPPORT + +#if defined(REMOVE_FIXED_SASIHD_SIZE) + // 256バイト単位であること + if (size & 0xff) { + return FALSE; + } + + // 10MB以上 + if (size < 0x9f5400) { + return FALSE; + } + + // 512MB程度に制限しておく + if (size > 512 * 1024 * 1024) { + return FALSE; + } +#else + // 10MB, 20MB, 40MBのみ + switch (size) { + // 10MB(10441728 BS=256 C=40788) + case 0x9f5400: + break; + + // 20MB(20748288 BS=256 C=81048) + case 0x13c9800: + break; + + // 40MB(41496576 BS=256 C=162096) + case 0x2793000: + break; + + // Other(サポートしない) + default: + return FALSE; + } +#endif // REMOVE_FIXED_SASIHD_SIZE + + // セクタサイズとブロック数 + disk.size = 8; + disk.blocks = (DWORD)(size >> 8); + + // Call the base class + return Disk::Open(path); +} + +//--------------------------------------------------------------------------- +// +// REQUEST SENSE +// +//--------------------------------------------------------------------------- +int FASTCALL SASIHD::RequestSense(const DWORD *cdb, BYTE *buf) +{ + int size; + + ASSERT(this); + ASSERT(cdb); + ASSERT(buf); + + // サイズ決定 + size = (int)cdb[4]; + ASSERT((size >= 0) && (size < 0x100)); + + // サイズ0のときに4バイト転送する(Shugart Associates System Interface仕様) + if (size == 0) { + size = 4; + } + + // SASIは非拡張フォーマットに固定 + memset(buf, 0, size); + buf[0] = (BYTE)(disk.code >> 16); + buf[1] = (BYTE)(disk.lun << 5); + + // コードをクリア + disk.code = 0x00; + + return size; +} diff --git a/src/raspberrypi/disks/sasihd.h b/src/raspberrypi/disks/sasihd.h new file mode 100644 index 0000000..eb305d2 --- /dev/null +++ b/src/raspberrypi/disks/sasihd.h @@ -0,0 +1,40 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SASI hard disk ] +// +//--------------------------------------------------------------------------- +#pragma once + +#include "os.h" +#include "disk.h" +#include "filepath.h" + +//=========================================================================== +// +// SASI Hard Disk +// +//=========================================================================== +class SASIHD : public Disk +{ +public: + // Basic Functions + SASIHD(); + // Constructor + void FASTCALL Reset(); + // Reset + BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); + // Open + // commands + int FASTCALL RequestSense(const DWORD *cdb, BYTE *buf); + // REQUEST SENSE command +}; \ No newline at end of file diff --git a/src/raspberrypi/disks/scsi_host_bridge.cpp b/src/raspberrypi/disks/scsi_host_bridge.cpp new file mode 100644 index 0000000..c0e0a12 --- /dev/null +++ b/src/raspberrypi/disks/scsi_host_bridge.cpp @@ -0,0 +1,1502 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI Host Bridge for the Sharp X68000 ] +// +// Note: This requires a special driver on the host system and will only +// work with the Sharp X68000 operating system. +//--------------------------------------------------------------------------- + +#include "scsi_host_bridge.h" +#include "xm6.h" +#include "ctapdriver.h" +#include "cfilesystem.h" + +//=========================================================================== +// +// SCSI Host Bridge +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +SCSIBR::SCSIBR() : Disk() +{ + // Host Bridge + disk.id = MAKEID('S', 'C', 'B', 'R'); + +#if defined(RASCSI) && !defined(BAREMETAL) + // TAP Driver Generation + tap = new CTapDriver(); + m_bTapEnable = tap->Init(); + + // Generate MAC Address + memset(mac_addr, 0x00, 6); + if (m_bTapEnable) { + tap->GetMacAddr(mac_addr); + mac_addr[5]++; + } + + // Packet reception flag OFF + packet_enable = FALSE; +#endif // RASCSI && !BAREMETAL + + // Create host file system + fs = new CFileSys(); + fs->Reset(); +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +SCSIBR::~SCSIBR() +{ +#if defined(RASCSI) && !defined(BAREMETAL) + // TAP driver release + if (tap) { + tap->Cleanup(); + delete tap; + } +#endif // RASCSI && !BAREMETAL + + // Release host file system + if (fs) { + fs->Reset(); + delete fs; + } +} + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIBR::Inquiry( + const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) +{ + char rev[32]; + int size; + + ASSERT(this); + ASSERT(cdb); + ASSERT(buf); + ASSERT(cdb[0] == 0x12); + + // EVPD check + if (cdb[1] & 0x01) { + disk.code = DISK_INVALIDCDB; + return FALSE; + } + + // Basic data + // buf[0] ... Communication Device + // buf[2] ... SCSI-2 compliant command system + // buf[3] ... SCSI-2 compliant Inquiry response + // buf[4] ... Inquiry additional data + memset(buf, 0, 8); + buf[0] = 0x09; + + // SCSI-2 p.104 4.4.3 Incorrect logical unit handling + if (((cdb[1] >> 5) & 0x07) != disk.lun) { + buf[0] = 0x7f; + } + + buf[2] = 0x02; + buf[3] = 0x02; + buf[4] = 36 - 5 + 8; // required + 8 byte extension + + // Fill with blanks + memset(&buf[8], 0x20, buf[4] - 3); + + // Vendor name + memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); + + // Product name + memcpy(&buf[16], "RASCSI BRIDGE", 13); + + // Revision (XM6 version number) + sprintf(rev, "0%01d%01d%01d", + (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); + memcpy(&buf[32], rev, 4); + + // Optional function valid flag + buf[36] = '0'; + +#if defined(RASCSI) && !defined(BAREMETAL) + // TAP Enable + if (m_bTapEnable) { + buf[37] = '1'; + } +#endif // RASCSI && !BAREMETAL + + // CFileSys Enable + buf[38] = '1'; + + // Size of data that can be returned + size = (buf[4] + 5); + + // Limit if the other buffer is small + if (size > (int)cdb[4]) { + size = (int)cdb[4]; + } + + // Success + disk.code = DISK_NOERROR; + return size; +} + +//--------------------------------------------------------------------------- +// +// TEST UNIT READY +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIBR::TestUnitReady(const DWORD* /*cdb*/) +{ + ASSERT(this); + + // TEST UNIT READY Success + disk.code = DISK_NOERROR; + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// GET MESSAGE(10) +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf) +{ + int type; + int phase; +#if defined(RASCSI) && !defined(BAREMETAL) + int func; + int total_len; + int i; +#endif // RASCSI && !BAREMETAL + + ASSERT(this); + + // Type + type = cdb[2]; + +#if defined(RASCSI) && !defined(BAREMETAL) + // Function number + func = cdb[3]; +#endif // RASCSI && !BAREMETAL + + // Phase + phase = cdb[9]; + + switch (type) { +#if defined(RASCSI) && !defined(BAREMETAL) + case 1: // Ethernet + // Do not process if TAP is invalid + if (!m_bTapEnable) { + return 0; + } + + switch (func) { + case 0: // Get MAC address + return GetMacAddr(buf); + + case 1: // Received packet acquisition (size/buffer) + if (phase == 0) { + // Get packet size + ReceivePacket(); + buf[0] = (BYTE)(packet_len >> 8); + buf[1] = (BYTE)packet_len; + return 2; + } else { + // Get package data + GetPacketBuf(buf); + return packet_len; + } + + case 2: // Received packet acquisition (size + buffer simultaneously) + ReceivePacket(); + buf[0] = (BYTE)(packet_len >> 8); + buf[1] = (BYTE)packet_len; + GetPacketBuf(&buf[2]); + return packet_len + 2; + + case 3: // Simultaneous acquisition of multiple packets (size + buffer simultaneously) + // Currently the maximum number of packets is 10 + // Isn't it too fast if I increase more? + total_len = 0; + for (i = 0; i < 10; i++) { + ReceivePacket(); + *buf++ = (BYTE)(packet_len >> 8); + *buf++ = (BYTE)packet_len; + total_len += 2; + if (packet_len == 0) + break; + GetPacketBuf(buf); + buf += packet_len; + total_len += packet_len; + } + return total_len; + } + break; +#endif // RASCSI && !BAREMETAL + + case 2: // Host Drive + switch (phase) { + case 0: // Get result code + return ReadFsResult(buf); + + case 1: // Return data acquisition + return ReadFsOut(buf); + + case 2: // Return additional data acquisition + return ReadFsOpt(buf); + } + break; + } + + // Error + ASSERT(FALSE); + return 0; +} + +//--------------------------------------------------------------------------- +// +// SEND MESSAGE(10) +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIBR::SendMessage10(const DWORD *cdb, BYTE *buf) +{ + int type; + int func; + int phase; + int len; + + ASSERT(this); + ASSERT(cdb); + ASSERT(buf); + + // Type + type = cdb[2]; + + // Function number + func = cdb[3]; + + // Phase + phase = cdb[9]; + + // Get the number of lights + len = cdb[6]; + len <<= 8; + len |= cdb[7]; + len <<= 8; + len |= cdb[8]; + + switch (type) { +#if defined(RASCSI) && !defined(BAREMETAL) + case 1: // Ethernet + // Do not process if TAP is invalid + if (!m_bTapEnable) { + return FALSE; + } + + switch (func) { + case 0: // MAC address setting + SetMacAddr(buf); + return TRUE; + + case 1: // Send packet + SendPacket(buf, len); + return TRUE; + } + break; +#endif // RASCSI && !BAREMETAL + + case 2: // Host drive + switch (phase) { + case 0: // issue command + WriteFs(func, buf); + return TRUE; + + case 1: // additional data writing + WriteFsOpt(buf, len); + return TRUE; + } + break; + } + + // Error + ASSERT(FALSE); + return FALSE; +} + +#if defined(RASCSI) && !defined(BAREMETAL) +//--------------------------------------------------------------------------- +// +// Get MAC Address +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIBR::GetMacAddr(BYTE *mac) +{ + ASSERT(this); + ASSERT(mac); + + memcpy(mac, mac_addr, 6); + return 6; +} + +//--------------------------------------------------------------------------- +// +// Set MAC Address +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::SetMacAddr(BYTE *mac) +{ + ASSERT(this); + ASSERT(mac); + + memcpy(mac_addr, mac, 6); +} + +//--------------------------------------------------------------------------- +// +// Receive Packet +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::ReceivePacket() +{ + static const BYTE bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + ASSERT(this); + ASSERT(tap); + + // previous packet has not been received + if (packet_enable) { + return; + } + + // Receive packet + packet_len = tap->Rx(packet_buf); + + // Check if received packet + if (memcmp(packet_buf, mac_addr, 6) != 0) { + if (memcmp(packet_buf, bcast_addr, 6) != 0) { + packet_len = 0; + return; + } + } + + // Discard if it exceeds the buffer size + if (packet_len > 2048) { + packet_len = 0; + return; + } + + // Store in receive buffer + if (packet_len > 0) { + packet_enable = TRUE; + } +} + +//--------------------------------------------------------------------------- +// +// Get Packet +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::GetPacketBuf(BYTE *buf) +{ + int len; + + ASSERT(this); + ASSERT(tap); + ASSERT(buf); + + // Size limit + len = packet_len; + if (len > 2048) { + len = 2048; + } + + // Copy + memcpy(buf, packet_buf, len); + + // Received + packet_enable = FALSE; +} + +//--------------------------------------------------------------------------- +// +// Send Packet +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::SendPacket(BYTE *buf, int len) +{ + ASSERT(this); + ASSERT(tap); + ASSERT(buf); + + tap->Tx(buf, len); +} +#endif // RASCSI && !BAREMETAL + +//--------------------------------------------------------------------------- +// +// $40 - Device Boot +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_InitDevice(BYTE *buf) +{ + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + fs->Reset(); + fsresult = fs->InitDevice((Human68k::argument_t*)buf); +} + +//--------------------------------------------------------------------------- +// +// $41 - Directory Check +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_CheckDir(BYTE *buf) +{ + DWORD nUnit; + Human68k::namests_t *pNamests; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + fsresult = fs->CheckDir(nUnit, pNamests); +} + +//--------------------------------------------------------------------------- +// +// $42 - Create Directory +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_MakeDir(BYTE *buf) +{ + DWORD nUnit; + Human68k::namests_t *pNamests; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + fsresult = fs->MakeDir(nUnit, pNamests); +} + +//--------------------------------------------------------------------------- +// +// $43 - Remove Directory +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_RemoveDir(BYTE *buf) +{ + DWORD nUnit; + Human68k::namests_t *pNamests; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + fsresult = fs->RemoveDir(nUnit, pNamests); +} + +//--------------------------------------------------------------------------- +// +// $44 - Rename +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Rename(BYTE *buf) +{ + DWORD nUnit; + Human68k::namests_t *pNamests; + Human68k::namests_t* pNamestsNew; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + pNamestsNew = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + fsresult = fs->Rename(nUnit, pNamests, pNamestsNew); +} + +//--------------------------------------------------------------------------- +// +// $45 - Delete File +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Delete(BYTE *buf) +{ + DWORD nUnit; + Human68k::namests_t *pNamests; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + fsresult = fs->Delete(nUnit, pNamests); +} + +//--------------------------------------------------------------------------- +// +// $46 - Get / Set file attributes +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Attribute(BYTE *buf) +{ + DWORD nUnit; + Human68k::namests_t *pNamests; + DWORD nHumanAttribute; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + dp = (DWORD*)&buf[i]; + nHumanAttribute = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->Attribute(nUnit, pNamests, nHumanAttribute); +} + +//--------------------------------------------------------------------------- +// +// $47 - File Search +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Files(BYTE *buf) +{ + DWORD nUnit; + DWORD nKey; + Human68k::namests_t *pNamests; + Human68k::files_t *files; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + files = (Human68k::files_t*)&buf[i]; + i += sizeof(Human68k::files_t); + + files->sector = ntohl(files->sector); + files->offset = ntohs(files->offset); + files->time = ntohs(files->time); + files->date = ntohs(files->date); + files->size = ntohl(files->size); + + fsresult = fs->Files(nUnit, nKey, pNamests, files); + + files->sector = htonl(files->sector); + files->offset = htons(files->offset); + files->time = htons(files->time); + files->date = htons(files->date); + files->size = htonl(files->size); + + i = 0; + memcpy(&fsout[i], files, sizeof(Human68k::files_t)); + i += sizeof(Human68k::files_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $48 - File next search +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_NFiles(BYTE *buf) +{ + DWORD nUnit; + DWORD nKey; + Human68k::files_t *files; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + files = (Human68k::files_t*)&buf[i]; + i += sizeof(Human68k::files_t); + + files->sector = ntohl(files->sector); + files->offset = ntohs(files->offset); + files->time = ntohs(files->time); + files->date = ntohs(files->date); + files->size = ntohl(files->size); + + fsresult = fs->NFiles(nUnit, nKey, files); + + files->sector = htonl(files->sector); + files->offset = htons(files->offset); + files->time = htons(files->time); + files->date = htons(files->date); + files->size = htonl(files->size); + + i = 0; + memcpy(&fsout[i], files, sizeof(Human68k::files_t)); + i += sizeof(Human68k::files_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $49 - File Creation +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Create(BYTE *buf) +{ + DWORD nUnit; + DWORD nKey; + Human68k::namests_t *pNamests; + Human68k::fcb_t *pFcb; + DWORD nAttribute; + BOOL bForce; + DWORD *dp; + BOOL *bp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + dp = (DWORD*)&buf[i]; + nAttribute = ntohl(*dp); + i += sizeof(DWORD); + + bp = (BOOL*)&buf[i]; + bForce = ntohl(*bp); + i += sizeof(BOOL); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->Create(nUnit, nKey, pNamests, pFcb, nAttribute, bForce); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $4A - Open File +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Open(BYTE *buf) +{ + DWORD nUnit; + DWORD nKey; + Human68k::namests_t *pNamests; + Human68k::fcb_t *pFcb; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pNamests = (Human68k::namests_t*)&buf[i]; + i += sizeof(Human68k::namests_t); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->Open(nUnit, nKey, pNamests, pFcb); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $4B - Close File +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Close(BYTE *buf) +{ + DWORD nUnit; + DWORD nKey; + Human68k::fcb_t *pFcb; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->Close(nUnit, nKey, pFcb); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $4C - Read File +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Read(BYTE *buf) +{ + DWORD nKey; + Human68k::fcb_t *pFcb; + DWORD nSize; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + dp = (DWORD*)&buf[i]; + nSize = ntohl(*dp); + i += sizeof(DWORD); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->Read(nKey, pFcb, fsopt, nSize); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; + + fsoptlen = fsresult; +} + +//--------------------------------------------------------------------------- +// +// $4D - Write file +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Write(BYTE *buf) +{ + DWORD nKey; + Human68k::fcb_t *pFcb; + DWORD nSize; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + dp = (DWORD*)&buf[i]; + nSize = ntohl(*dp); + i += sizeof(DWORD); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->Write(nKey, pFcb, fsopt, nSize); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $4E - Seek file +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Seek(BYTE *buf) +{ + DWORD nKey; + Human68k::fcb_t *pFcb; + DWORD nMode; + int nOffset; + DWORD *dp; + int *ip; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + dp = (DWORD*)&buf[i]; + nMode = ntohl(*dp); + i += sizeof(DWORD); + + ip = (int*)&buf[i]; + nOffset = ntohl(*ip); + i += sizeof(int); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->Seek(nKey, pFcb, nMode, nOffset); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $4F - File Timestamp Get / Set +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_TimeStamp(BYTE *buf) +{ + DWORD nUnit; + DWORD nKey; + Human68k::fcb_t *pFcb; + DWORD nHumanTime; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nKey = ntohl(*dp); + i += sizeof(DWORD); + + pFcb = (Human68k::fcb_t*)&buf[i]; + i += sizeof(Human68k::fcb_t); + + dp = (DWORD*)&buf[i]; + nHumanTime = ntohl(*dp); + i += sizeof(DWORD); + + pFcb->fileptr = ntohl(pFcb->fileptr); + pFcb->mode = ntohs(pFcb->mode); + pFcb->time = ntohs(pFcb->time); + pFcb->date = ntohs(pFcb->date); + pFcb->size = ntohl(pFcb->size); + + fsresult = fs->TimeStamp(nUnit, nKey, pFcb, nHumanTime); + + pFcb->fileptr = htonl(pFcb->fileptr); + pFcb->mode = htons(pFcb->mode); + pFcb->time = htons(pFcb->time); + pFcb->date = htons(pFcb->date); + pFcb->size = htonl(pFcb->size); + + i = 0; + memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t)); + i += sizeof(Human68k::fcb_t); + + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $50 - Get Capacity +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_GetCapacity(BYTE *buf) +{ + DWORD nUnit; + Human68k::capacity_t cap; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->GetCapacity(nUnit, &cap); + + cap.freearea = htons(cap.freearea); + cap.clusters = htons(cap.clusters); + cap.sectors = htons(cap.sectors); + cap.bytes = htons(cap.bytes); + + memcpy(fsout, &cap, sizeof(Human68k::capacity_t)); + fsoutlen = sizeof(Human68k::capacity_t); +} + +//--------------------------------------------------------------------------- +// +// $51 - Drive status inspection/control +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_CtrlDrive(BYTE *buf) +{ + DWORD nUnit; + Human68k::ctrldrive_t *pCtrlDrive; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + pCtrlDrive = (Human68k::ctrldrive_t*)&buf[i]; + i += sizeof(Human68k::ctrldrive_t); + + fsresult = fs->CtrlDrive(nUnit, pCtrlDrive); + + memcpy(fsout, pCtrlDrive, sizeof(Human68k::ctrldrive_t)); + fsoutlen = sizeof(Human68k::ctrldrive_t); +} + +//--------------------------------------------------------------------------- +// +// $52 - Get DPB +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_GetDPB(BYTE *buf) +{ + DWORD nUnit; + Human68k::dpb_t dpb; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->GetDPB(nUnit, &dpb); + + dpb.sector_size = htons(dpb.sector_size); + dpb.fat_sector = htons(dpb.fat_sector); + dpb.file_max = htons(dpb.file_max); + dpb.data_sector = htons(dpb.data_sector); + dpb.cluster_max = htons(dpb.cluster_max); + dpb.root_sector = htons(dpb.root_sector); + + memcpy(fsout, &dpb, sizeof(Human68k::dpb_t)); + fsoutlen = sizeof(Human68k::dpb_t); +} + +//--------------------------------------------------------------------------- +// +// $53 - Read Sector +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_DiskRead(BYTE *buf) +{ + DWORD nUnit; + DWORD nSector; + DWORD nSize; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nSector = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nSize = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->DiskRead(nUnit, fsout, nSector, nSize); + fsoutlen = 0x200; +} + +//--------------------------------------------------------------------------- +// +// $54 - Write Sector +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_DiskWrite(BYTE *buf) +{ + DWORD nUnit; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->DiskWrite(nUnit); +} + +//--------------------------------------------------------------------------- +// +// $55 - IOCTRL +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Ioctrl(BYTE *buf) +{ + DWORD nUnit; + DWORD nFunction; + Human68k::ioctrl_t *pIoctrl; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + dp = (DWORD*)&buf[i]; + nFunction = ntohl(*dp); + i += sizeof(DWORD); + + pIoctrl = (Human68k::ioctrl_t*)&buf[i]; + i += sizeof(Human68k::ioctrl_t); + + switch (nFunction) { + case 2: + case -2: + pIoctrl->param = htonl(pIoctrl->param); + break; + } + + fsresult = fs->Ioctrl(nUnit, nFunction, pIoctrl); + + switch (nFunction) { + case 0: + pIoctrl->media = htons(pIoctrl->media); + break; + case 1: + case -3: + pIoctrl->param = htonl(pIoctrl->param); + break; + } + + i = 0; + memcpy(&fsout[i], pIoctrl, sizeof(Human68k::ioctrl_t)); + i += sizeof(Human68k::ioctrl_t); + fsoutlen = i; +} + +//--------------------------------------------------------------------------- +// +// $56 - Flush +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Flush(BYTE *buf) +{ + DWORD nUnit; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->Flush(nUnit); +} + +//--------------------------------------------------------------------------- +// +// $57 - Check Media +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_CheckMedia(BYTE *buf) +{ + DWORD nUnit; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->CheckMedia(nUnit); +} + +//--------------------------------------------------------------------------- +// +// $58 - Lock +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::FS_Lock(BYTE *buf) +{ + DWORD nUnit; + DWORD *dp; + int i; + + ASSERT(this); + ASSERT(fs); + ASSERT(buf); + + i = 0; + dp = (DWORD*)buf; + nUnit = ntohl(*dp); + i += sizeof(DWORD); + + fsresult = fs->Lock(nUnit); +} + +//--------------------------------------------------------------------------- +// +// Read Filesystem (result code) +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIBR::ReadFsResult(BYTE *buf) +{ + DWORD *dp; + + ASSERT(this); + ASSERT(buf); + + dp = (DWORD*)buf; + *dp = htonl(fsresult); + return sizeof(DWORD); +} + +//--------------------------------------------------------------------------- +// +// Read Filesystem (return data) +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIBR::ReadFsOut(BYTE *buf) +{ + ASSERT(this); + ASSERT(buf); + + memcpy(buf, fsout, fsoutlen); + return fsoutlen; +} + +//--------------------------------------------------------------------------- +// +// Read file system (return option data) +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIBR::ReadFsOpt(BYTE *buf) +{ + ASSERT(this); + ASSERT(buf); + + memcpy(buf, fsopt, fsoptlen); + return fsoptlen; +} + +//--------------------------------------------------------------------------- +// +// Write Filesystem +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::WriteFs(int func, BYTE *buf) +{ + ASSERT(this); + ASSERT(buf); + + fsresult = FS_FATAL_INVALIDCOMMAND; + fsoutlen = 0; + fsoptlen = 0; + + // コマンド分岐 + func &= 0x1f; + switch (func) { + case 0x00: return FS_InitDevice(buf); // $40 - start device + case 0x01: return FS_CheckDir(buf); // $41 - directory check + case 0x02: return FS_MakeDir(buf); // $42 - create directory + case 0x03: return FS_RemoveDir(buf); // $43 - remove directory + case 0x04: return FS_Rename(buf); // $44 - change file name + case 0x05: return FS_Delete(buf); // $45 - delete file + case 0x06: return FS_Attribute(buf); // $46 - Get/set file attribute + case 0x07: return FS_Files(buf); // $47 - file search + case 0x08: return FS_NFiles(buf); // $48 - next file search + case 0x09: return FS_Create(buf); // $49 - create file + case 0x0A: return FS_Open(buf); // $4A - File open + case 0x0B: return FS_Close(buf); // $4B - File close + case 0x0C: return FS_Read(buf); // $4C - read file + case 0x0D: return FS_Write(buf); // $4D - write file + case 0x0E: return FS_Seek(buf); // $4E - File seek + case 0x0F: return FS_TimeStamp(buf); // $4F - Get/set file modification time + case 0x10: return FS_GetCapacity(buf); // $50 - get capacity + case 0x11: return FS_CtrlDrive(buf); // $51 - Drive control/state check + case 0x12: return FS_GetDPB(buf); // $52 - Get DPB + case 0x13: return FS_DiskRead(buf); // $53 - read sector + case 0x14: return FS_DiskWrite(buf); // $54 - write sector + case 0x15: return FS_Ioctrl(buf); // $55 - IOCTRL + case 0x16: return FS_Flush(buf); // $56 - flush + case 0x17: return FS_CheckMedia(buf); // $57 - check media exchange + case 0x18: return FS_Lock(buf); // $58 - exclusive control + } +} + +//--------------------------------------------------------------------------- +// +// File system write (input option data) +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIBR::WriteFsOpt(BYTE *buf, int num) +{ + ASSERT(this); + + memcpy(fsopt, buf, num); +} diff --git a/src/raspberrypi/disks/scsi_host_bridge.h b/src/raspberrypi/disks/scsi_host_bridge.h new file mode 100644 index 0000000..e79e933 --- /dev/null +++ b/src/raspberrypi/disks/scsi_host_bridge.h @@ -0,0 +1,153 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI Host Bridge for the Sharp X68000 ] +// +// Note: This requires a special driver on the host system and will only +// work with the Sharp X68000 operating system. +//--------------------------------------------------------------------------- +#pragma once + +#include "xm6.h" +#include "os.h" +#include "disk.h" + +//=========================================================================== +// +// SCSI Host Bridge +// +//=========================================================================== +#if defined(RASCSI) && !defined(BAREMETAL) +class CTapDriver; +#endif // RASCSI && !BAREMETAL +class CFileSys; +class SCSIBR : public Disk +{ +public: + // Basic Functions + SCSIBR(); + // Constructor + virtual ~SCSIBR(); + // Destructor + + // commands + int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); + // INQUIRY command + BOOL FASTCALL TestUnitReady(const DWORD *cdb); + // TEST UNIT READY command + int FASTCALL GetMessage10(const DWORD *cdb, BYTE *buf); + // GET MESSAGE10 command + BOOL FASTCALL SendMessage10(const DWORD *cdb, BYTE *buf); + // SEND MESSAGE10 command + +private: +#if defined(RASCSI) && !defined(BAREMETAL) + int FASTCALL GetMacAddr(BYTE *buf); + // Get MAC address + void FASTCALL SetMacAddr(BYTE *buf); + // Set MAC address + void FASTCALL ReceivePacket(); + // Receive a packet + void FASTCALL GetPacketBuf(BYTE *buf); + // Get a packet + void FASTCALL SendPacket(BYTE *buf, int len); + // Send a packet + + CTapDriver *tap; + // TAP driver + BOOL m_bTapEnable; + // TAP valid flag + BYTE mac_addr[6]; + // MAC Addres + int packet_len; + // Receive packet size + BYTE packet_buf[0x1000]; + // Receive packet buffer + BOOL packet_enable; + // Received packet valid +#endif // RASCSI && !BAREMETAL + + int FASTCALL ReadFsResult(BYTE *buf); + // Read filesystem (result code) + int FASTCALL ReadFsOut(BYTE *buf); + // Read filesystem (return data) + int FASTCALL ReadFsOpt(BYTE *buf); + // Read file system (optional data) + void FASTCALL WriteFs(int func, BYTE *buf); + // File system write (execute) + void FASTCALL WriteFsOpt(BYTE *buf, int len); + // File system write (optional data) + // Command handlers + void FASTCALL FS_InitDevice(BYTE *buf); + // $40 - boot + void FASTCALL FS_CheckDir(BYTE *buf); + // $41 - directory check + void FASTCALL FS_MakeDir(BYTE *buf); + // $42 - create directory + void FASTCALL FS_RemoveDir(BYTE *buf); + // $43 - delete directory + void FASTCALL FS_Rename(BYTE *buf); + // $44 - change filename + void FASTCALL FS_Delete(BYTE *buf); + // $45 - delete file + void FASTCALL FS_Attribute(BYTE *buf); + // $46 - get/set file attributes + void FASTCALL FS_Files(BYTE *buf); + // $47 - file search + void FASTCALL FS_NFiles(BYTE *buf); + // $48 - find next file + void FASTCALL FS_Create(BYTE *buf); + // $49 - create file + void FASTCALL FS_Open(BYTE *buf); + // $4A - open file + void FASTCALL FS_Close(BYTE *buf); + // $4B - close file + void FASTCALL FS_Read(BYTE *buf); + // $4C - read file + void FASTCALL FS_Write(BYTE *buf); + // $4D - write file + void FASTCALL FS_Seek(BYTE *buf); + // $4E - seek file + void FASTCALL FS_TimeStamp(BYTE *buf); + // $4F - get/set file time + void FASTCALL FS_GetCapacity(BYTE *buf); + // $50 - get capacity + void FASTCALL FS_CtrlDrive(BYTE *buf); + // $51 - drive status check/control + void FASTCALL FS_GetDPB(BYTE *buf); + // $52 - get DPB + void FASTCALL FS_DiskRead(BYTE *buf); + // $53 - read sector + void FASTCALL FS_DiskWrite(BYTE *buf); + // $54 - write sector + void FASTCALL FS_Ioctrl(BYTE *buf); + // $55 - IOCTRL + void FASTCALL FS_Flush(BYTE *buf); + // $56 - flush cache + void FASTCALL FS_CheckMedia(BYTE *buf); + // $57 - check media + void FASTCALL FS_Lock(BYTE *buf); + // $58 - get exclusive control + + CFileSys *fs; + // File system accessor + DWORD fsresult; + // File system access result code + BYTE fsout[0x800]; + // File system access result buffer + DWORD fsoutlen; + // File system access result buffer size + BYTE fsopt[0x1000000]; + // File system access buffer + DWORD fsoptlen; + // File system access buffer size +}; diff --git a/src/raspberrypi/disks/scsicd.cpp b/src/raspberrypi/disks/scsicd.cpp new file mode 100644 index 0000000..d898f04 --- /dev/null +++ b/src/raspberrypi/disks/scsicd.cpp @@ -0,0 +1,1089 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI Hard Disk for Apple Macintosh ] +// +//--------------------------------------------------------------------------- + +#include "xm6.h" +#include "scsicd.h" +#include "fileio.h" + +//=========================================================================== +// +// CD Track +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +CDTrack::CDTrack(SCSICD *scsicd) +{ + ASSERT(scsicd); + + // Set parent CD-ROM device + cdrom = scsicd; + + // Track defaults to disabled + valid = FALSE; + + // Initialize other data + track_no = -1; + first_lba = 0; + last_lba = 0; + audio = FALSE; + raw = FALSE; +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +CDTrack::~CDTrack() +{ +} + +//--------------------------------------------------------------------------- +// +// Init +// +//--------------------------------------------------------------------------- +BOOL FASTCALL CDTrack::Init(int track, DWORD first, DWORD last) +{ + ASSERT(this); + ASSERT(!valid); + ASSERT(track >= 1); + ASSERT(first < last); + + // Set and enable track number + track_no = track; + valid = TRUE; + + // Remember LBA + first_lba = first; + last_lba = last; + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Set Path +// +//--------------------------------------------------------------------------- +void FASTCALL CDTrack::SetPath(BOOL cdda, const Filepath& path) +{ + ASSERT(this); + ASSERT(valid); + + // CD-DA or data + audio = cdda; + + // Remember the path + imgpath = path; +} + +//--------------------------------------------------------------------------- +// +// Get Path +// +//--------------------------------------------------------------------------- +void FASTCALL CDTrack::GetPath(Filepath& path) const +{ + ASSERT(this); + ASSERT(valid); + + // Return the path (by reference) + path = imgpath; +} + +//--------------------------------------------------------------------------- +// +// Add Index +// +//--------------------------------------------------------------------------- +void FASTCALL CDTrack::AddIndex(int index, DWORD lba) +{ + ASSERT(this); + ASSERT(valid); + ASSERT(index > 0); + ASSERT(first_lba <= lba); + ASSERT(lba <= last_lba); + + // Currently does not support indexes + ASSERT(FALSE); +} + +//--------------------------------------------------------------------------- +// +// Gets the start of LBA +// +//--------------------------------------------------------------------------- +DWORD FASTCALL CDTrack::GetFirst() const +{ + ASSERT(this); + ASSERT(valid); + ASSERT(first_lba < last_lba); + + return first_lba; +} + +//--------------------------------------------------------------------------- +// +// Get the end of LBA +// +//--------------------------------------------------------------------------- +DWORD FASTCALL CDTrack::GetLast() const +{ + ASSERT(this); + ASSERT(valid); + ASSERT(first_lba < last_lba); + + return last_lba; +} + +//--------------------------------------------------------------------------- +// +// Get the number of blocks +// +//--------------------------------------------------------------------------- +DWORD FASTCALL CDTrack::GetBlocks() const +{ + ASSERT(this); + ASSERT(valid); + ASSERT(first_lba < last_lba); + + // Calculate from start LBA and end LBA + return (DWORD)(last_lba - first_lba + 1); +} + +//--------------------------------------------------------------------------- +// +// Get track number +// +//--------------------------------------------------------------------------- +int FASTCALL CDTrack::GetTrackNo() const +{ + ASSERT(this); + ASSERT(valid); + ASSERT(track_no >= 1); + + return track_no; +} + +//--------------------------------------------------------------------------- +// +// Is valid block +// +//--------------------------------------------------------------------------- +BOOL FASTCALL CDTrack::IsValid(DWORD lba) const +{ + ASSERT(this); + + // FALSE if the track itself is invalid + if (!valid) { + return FALSE; + } + + // If the block is BEFORE the first block + if (lba < first_lba) { + return FALSE; + } + + // If the block is AFTER the last block + if (last_lba < lba) { + return FALSE; + } + + // This track is valid + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Is audio track +// +//--------------------------------------------------------------------------- +BOOL FASTCALL CDTrack::IsAudio() const +{ + ASSERT(this); + ASSERT(valid); + + return audio; +} + +//=========================================================================== +// +// CD-DA Buffer +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +CDDABuf::CDDABuf() +{ +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +CDDABuf::~CDDABuf() +{ +} + +//=========================================================================== +// +// SCSI CD-ROM +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +SCSICD::SCSICD() : Disk() +{ + int i; + + // SCSI CD-ROM + disk.id = MAKEID('S', 'C', 'C', 'D'); + + // removable, write protected + disk.removable = TRUE; + disk.writep = TRUE; + + // NOT in raw format + rawfile = FALSE; + + // Frame initialization + frame = 0; + + // Track initialization + for (i = 0; i < TrackMax; i++) { + track[i] = NULL; + } + tracks = 0; + dataindex = -1; + audioindex = -1; +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +SCSICD::~SCSICD() +{ + // Clear track + ClearTrack(); +} + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Load +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::Load(Fileio *fio, int ver) +{ + DWORD sz; + disk_t buf; + DWORD padding; + Filepath path; + + ASSERT(this); + ASSERT(fio); + ASSERT(ver >= 0x0200); + + // Prior to version 2.03, the disk was not saved + if (ver <= 0x0202) { + return TRUE; + } + + // load size, match + if (!fio->Read(&sz, sizeof(sz))) { + return FALSE; + } + if (sz != 52) { + return FALSE; + } + + // load into buffer + PROP_IMPORT(fio, buf.id); + PROP_IMPORT(fio, buf.ready); + PROP_IMPORT(fio, buf.writep); + PROP_IMPORT(fio, buf.readonly); + PROP_IMPORT(fio, buf.removable); + PROP_IMPORT(fio, buf.lock); + PROP_IMPORT(fio, buf.attn); + PROP_IMPORT(fio, buf.reset); + PROP_IMPORT(fio, buf.size); + PROP_IMPORT(fio, buf.blocks); + PROP_IMPORT(fio, buf.lun); + PROP_IMPORT(fio, buf.code); + PROP_IMPORT(fio, padding); + + // Load path + if (!path.Load(fio, ver)) { + return FALSE; + } + + // Always eject + Eject(TRUE); + + // move only if IDs match + if (disk.id != buf.id) { + // It was not a CD-ROM when saving. Maintain eject status + return TRUE; + } + + // Try to reopen + if (!Open(path, FALSE)) { + // Cannot reopen. Maintain eject status + return TRUE; + } + + // Disk cache is created in Open. Move property only + if (!disk.readonly) { + disk.writep = buf.writep; + } + disk.lock = buf.lock; + disk.attn = buf.attn; + disk.reset = buf.reset; + disk.lun = buf.lun; + disk.code = buf.code; + + // Discard the disk cache again + if (disk.dcache) { + delete disk.dcache; + disk.dcache = NULL; + } + disk.dcache = NULL; + + // Tentative + disk.blocks = track[0]->GetBlocks(); + if (disk.blocks > 0) { + // Recreate the disk cache + track[0]->GetPath(path); + disk.dcache = new DiskCache(path, disk.size, disk.blocks); + disk.dcache->SetRawMode(rawfile); + + // Reset data index + dataindex = 0; + } + + return TRUE; +} +#endif // RASCSI + +//--------------------------------------------------------------------------- +// +// Open +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::Open(const Filepath& path, BOOL attn) +{ + Fileio fio; + off64_t size; + TCHAR file[5]; + + ASSERT(this); + ASSERT(!disk.ready); + + // Initialization, track clear + disk.blocks = 0; + rawfile = FALSE; + ClearTrack(); + + // Open as read-only + if (!fio.Open(path, Fileio::ReadOnly)) { + return FALSE; + } + + // Close and transfer for physical CD access + if (path.GetPath()[0] == _T('\\')) { + // Close + fio.Close(); + + // Open physical CD + if (!OpenPhysical(path)) { + return FALSE; + } + } else { + // Get file size + size = fio.GetFileSize(); + if (size <= 4) { + fio.Close(); + return FALSE; + } + + // Judge whether it is a CUE sheet or an ISO file + fio.Read(file, 4); + file[4] = '\0'; + fio.Close(); + + // If it starts with FILE, consider it as a CUE sheet + if (xstrncasecmp(file, _T("FILE"), 4) == 0) { + // Open as CUE + if (!OpenCue(path)) { + return FALSE; + } + } else { + // Open as ISO + if (!OpenIso(path)) { + return FALSE; + } + } + } + + // Successful opening + ASSERT(disk.blocks > 0); + disk.size = 11; + + // Call the base class + Disk::Open(path); + + // Set RAW flag + ASSERT(disk.dcache); + disk.dcache->SetRawMode(rawfile); + + // Since it is a ROM media, writing is not possible + disk.writep = TRUE; + + // Attention if ready + if (disk.ready && attn) { + disk.attn = TRUE; + } + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Open (CUE) +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::OpenCue(const Filepath& /*path*/) +{ + ASSERT(this); + + // Always fail + return FALSE; +} + +//--------------------------------------------------------------------------- +// +// オープン(ISO) +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::OpenIso(const Filepath& path) +{ + Fileio fio; + off64_t size; + BYTE header[12]; + BYTE sync[12]; + + ASSERT(this); + + // Open as read-only + if (!fio.Open(path, Fileio::ReadOnly)) { + return FALSE; + } + + // Get file size + size = fio.GetFileSize(); + if (size < 0x800) { + fio.Close(); + return FALSE; + } + + // Read the first 12 bytes and close + if (!fio.Read(header, sizeof(header))) { + fio.Close(); + return FALSE; + } + + // Check if it is RAW format + memset(sync, 0xff, sizeof(sync)); + sync[0] = 0x00; + sync[11] = 0x00; + rawfile = FALSE; + if (memcmp(header, sync, sizeof(sync)) == 0) { + // 00,FFx10,00, so it is presumed to be RAW format + if (!fio.Read(header, 4)) { + fio.Close(); + return FALSE; + } + + // Supports MODE1/2048 or MODE1/2352 only + if (header[3] != 0x01) { + // Different mode + fio.Close(); + return FALSE; + } + + // Set to RAW file + rawfile = TRUE; + } + fio.Close(); + + if (rawfile) { + // Size must be a multiple of 2536 and less than 700MB + if (size % 0x930) { + return FALSE; + } + if (size > 912579600) { + return FALSE; + } + + // Set the number of blocks + disk.blocks = (DWORD)(size / 0x930); + } else { + // Size must be a multiple of 2048 and less than 700MB + if (size & 0x7ff) { + return FALSE; + } + if (size > 0x2bed5000) { + return FALSE; + } + + // Set the number of blocks + disk.blocks = (DWORD)(size >> 11); + } + + // Create only one data track + ASSERT(!track[0]); + track[0] = new CDTrack(this); + track[0]->Init(1, 0, disk.blocks - 1); + track[0]->SetPath(FALSE, path); + tracks = 1; + dataindex = 0; + + // Successful opening + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Open (Physical) +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::OpenPhysical(const Filepath& path) +{ + Fileio fio; + off64_t size; + + ASSERT(this); + + // Open as read-only + if (!fio.Open(path, Fileio::ReadOnly)) { + return FALSE; + } + + // Get size + size = fio.GetFileSize(); + if (size < 0x800) { + fio.Close(); + return FALSE; + } + + // Close + fio.Close(); + + // Size must be a multiple of 2048 and less than 700MB + if (size & 0x7ff) { + return FALSE; + } + if (size > 0x2bed5000) { + return FALSE; + } + + // Set the number of blocks + disk.blocks = (DWORD)(size >> 11); + + // Create only one data track + ASSERT(!track[0]); + track[0] = new CDTrack(this); + track[0]->Init(1, 0, disk.blocks - 1); + track[0]->SetPath(FALSE, path); + tracks = 1; + dataindex = 0; + + // Successful opening + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +int FASTCALL SCSICD::Inquiry( + const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) +{ + char rev[32]; + int size; + + ASSERT(this); + ASSERT(cdb); + ASSERT(buf); + ASSERT(cdb[0] == 0x12); + + // EVPD check + if (cdb[1] & 0x01) { + disk.code = DISK_INVALIDCDB; + return FALSE; + } + + // 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 + memset(buf, 0, 8); + buf[0] = 0x05; + + // SCSI-2 p.104 4.4.3 Incorrect logical unit handling + if (((cdb[1] >> 5) & 0x07) != disk.lun) { + buf[0] = 0x7f; + } + + buf[1] = 0x80; + buf[2] = 0x02; + buf[3] = 0x02; + buf[4] = 36 - 5; // Required + + // Fill with blanks + memset(&buf[8], 0x20, buf[4] - 3); + + // Vendor name + memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); + + // Product name + memcpy(&buf[16], "CD-ROM CDU-55S", 14); + + // Revision (XM6 version number) + sprintf(rev, "0%01d%01d%01d", + (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); + memcpy(&buf[32], rev, 4); +// +// The following code worked with the modified Apple CD-ROM drivers. Need to +// test with the original code to see if it works as well.... +// buf[4] = 42; // Required +// +// // Fill with blanks +// memset(&buf[8], 0x20, buf[4] - 3); +// +// // Vendor name +// memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); +// +// // Product name +// memcpy(&buf[16], "CD-ROM CDU-8003A", 16); +// +// // Revision (XM6 version number) +//// sprintf(rev, "1.9a", +// //// (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); +// memcpy(&buf[32], "1.9a", 4); +// +// //strcpy(&buf[35],"A1.9a"); +// buf[36]=0x20; +// memcpy(&buf[37],"1999/01/01",10); + + // Size of data that can be returned + size = (buf[4] + 5); + + // Limit if the other buffer is small + if (size > (int)cdb[4]) { + size = (int)cdb[4]; + } + + // Success + disk.code = DISK_NOERROR; + return size; +} + +//--------------------------------------------------------------------------- +// +// READ +// +//--------------------------------------------------------------------------- +int FASTCALL SCSICD::Read(BYTE *buf, DWORD block) +{ + int index; + Filepath path; + + ASSERT(this); + ASSERT(buf); + + // Status check + if (!CheckReady()) { + return 0; + } + + // Search for the track + index = SearchTrack(block); + + // if invalid, out of range + if (index < 0) { + disk.code = DISK_INVALIDLBA; + return 0; + } + ASSERT(track[index]); + + // If different from the current data track + if (dataindex != index) { + // Delete current disk cache (no need to save) + delete disk.dcache; + disk.dcache = NULL; + + // Reset the number of blocks + disk.blocks = track[index]->GetBlocks(); + ASSERT(disk.blocks > 0); + + // Recreate the disk cache + track[index]->GetPath(path); + disk.dcache = new DiskCache(path, disk.size, disk.blocks); + disk.dcache->SetRawMode(rawfile); + + // Reset data index + dataindex = index; + } + + // Base class + ASSERT(dataindex >= 0); + return Disk::Read(buf, block); +} + +//--------------------------------------------------------------------------- +// +// READ TOC +// +//--------------------------------------------------------------------------- +int FASTCALL SCSICD::ReadToc(const DWORD *cdb, BYTE *buf) +{ + int last; + int index; + int length; + int loop; + int i; + BOOL msf; + DWORD lba; + + ASSERT(this); + ASSERT(cdb); + ASSERT(cdb[0] == 0x43); + ASSERT(buf); + + // Check if ready + if (!CheckReady()) { + return 0; + } + + // If ready, there is at least one track + ASSERT(tracks > 0); + ASSERT(track[0]); + + // Get allocation length, clear buffer + length = cdb[7] << 8; + length |= cdb[8]; + memset(buf, 0, length); + + // Get MSF Flag + if (cdb[1] & 0x02) { + msf = TRUE; + } else { + msf = FALSE; + } + + // Get and check the last track number + last = track[tracks - 1]->GetTrackNo(); + if ((int)cdb[6] > last) { + // Except for AA + if (cdb[6] != 0xaa) { + disk.code = DISK_INVALIDCDB; + return 0; + } + } + + // Check start index + index = 0; + if (cdb[6] != 0x00) { + // Advance the track until the track numbers match + while (track[index]) { + if ((int)cdb[6] == track[index]->GetTrackNo()) { + break; + } + index++; + } + + // AA if not found or internal error + if (!track[index]) { + if (cdb[6] == 0xaa) { + // Returns the final LBA+1 because it is AA + buf[0] = 0x00; + buf[1] = 0x0a; + buf[2] = (BYTE)track[0]->GetTrackNo(); + buf[3] = (BYTE)last; + buf[6] = 0xaa; + lba = track[tracks - 1]->GetLast() + 1; + if (msf) { + LBAtoMSF(lba, &buf[8]); + } else { + buf[10] = (BYTE)(lba >> 8); + buf[11] = (BYTE)lba; + } + return length; + } + + // Otherwise, error + disk.code = DISK_INVALIDCDB; + return 0; + } + } + + // Number of track descriptors returned this time (number of loops) + loop = last - track[index]->GetTrackNo() + 1; + ASSERT(loop >= 1); + + // Create header + buf[0] = (BYTE)(((loop << 3) + 2) >> 8); + buf[1] = (BYTE)((loop << 3) + 2); + buf[2] = (BYTE)track[0]->GetTrackNo(); + buf[3] = (BYTE)last; + buf += 4; + + // Loop.... + for (i = 0; i < loop; i++) { + // ADR and Control + if (track[index]->IsAudio()) { + // audio track + buf[1] = 0x10; + } else { + // data track + buf[1] = 0x14; + } + + // track number + buf[2] = (BYTE)track[index]->GetTrackNo(); + + // track address + if (msf) { + LBAtoMSF(track[index]->GetFirst(), &buf[4]); + } else { + buf[6] = (BYTE)(track[index]->GetFirst() >> 8); + buf[7] = (BYTE)(track[index]->GetFirst()); + } + + // Advance buffer pointer and index + buf += 8; + index++; + } + + // Always return only the allocation length + return length; +} + +//--------------------------------------------------------------------------- +// +// PLAY AUDIO +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::PlayAudio(const DWORD* /*cdb*/) +{ + ASSERT(this); + + disk.code = DISK_INVALIDCDB; + return FALSE; +} + +//--------------------------------------------------------------------------- +// +// PLAY AUDIO MSF +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::PlayAudioMSF(const DWORD* /*cdb*/) +{ + ASSERT(this); + + disk.code = DISK_INVALIDCDB; + return FALSE; +} + +//--------------------------------------------------------------------------- +// +// PLAY AUDIO TRACK +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::PlayAudioTrack(const DWORD* /*cdb*/) +{ + ASSERT(this); + + disk.code = DISK_INVALIDCDB; + return FALSE; +} + +//--------------------------------------------------------------------------- +// +// LBA→MSF Conversion +// +//--------------------------------------------------------------------------- +void FASTCALL SCSICD::LBAtoMSF(DWORD lba, BYTE *msf) const +{ + DWORD m; + DWORD s; + DWORD f; + + ASSERT(this); + + // 75 and 75*60 get the remainder + m = lba / (75 * 60); + s = lba % (75 * 60); + f = s % 75; + s /= 75; + + // The base point is M=0, S=2, F=0 + s += 2; + if (s >= 60) { + s -= 60; + m++; + } + + // Store + ASSERT(m < 0x100); + ASSERT(s < 60); + ASSERT(f < 75); + msf[0] = 0x00; + msf[1] = (BYTE)m; + msf[2] = (BYTE)s; + msf[3] = (BYTE)f; +} + +//--------------------------------------------------------------------------- +// +// MSF→LBA Conversion +// +//--------------------------------------------------------------------------- +DWORD FASTCALL SCSICD::MSFtoLBA(const BYTE *msf) const +{ + DWORD lba; + + ASSERT(this); + ASSERT(msf[2] < 60); + ASSERT(msf[3] < 75); + + // 1, 75, add up in multiples of 75*60 + lba = msf[1]; + lba *= 60; + lba += msf[2]; + lba *= 75; + lba += msf[3]; + + // Since the base point is M=0, S=2, F=0, subtract 150 + lba -= 150; + + return lba; +} + +//--------------------------------------------------------------------------- +// +// Clear Track +// +//--------------------------------------------------------------------------- +void FASTCALL SCSICD::ClearTrack() +{ + int i; + + ASSERT(this); + + // delete the track object + for (i = 0; i < TrackMax; i++) { + if (track[i]) { + delete track[i]; + track[i] = NULL; + } + } + + // Number of tracks is 0 + tracks = 0; + + // No settings for data and audio + dataindex = -1; + audioindex = -1; +} + +//--------------------------------------------------------------------------- +// +// Track Search +// * Returns -1 if not found +// +//--------------------------------------------------------------------------- +int FASTCALL SCSICD::SearchTrack(DWORD lba) const +{ + int i; + + ASSERT(this); + + // Track loop + for (i = 0; i < tracks; i++) { + // Listen to the track + ASSERT(track[i]); + if (track[i]->IsValid(lba)) { + return i; + } + } + + // Track wasn't found + return -1; +} + +//--------------------------------------------------------------------------- +// +// Next Frame +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSICD::NextFrame() +{ + ASSERT(this); + ASSERT((frame >= 0) && (frame < 75)); + + // set the frame in the range 0-74 + frame = (frame + 1) % 75; + + // FALSE after one lap + if (frame != 0) { + return TRUE; + } else { + return FALSE; + } +} + +//--------------------------------------------------------------------------- +// +// Get CD-DA buffer +// +//--------------------------------------------------------------------------- +void FASTCALL SCSICD::GetBuf( + DWORD* /*buffer*/, int /*samples*/, DWORD /*rate*/) +{ + ASSERT(this); +} diff --git a/src/raspberrypi/disks/scsicd.h b/src/raspberrypi/disks/scsicd.h new file mode 100644 index 0000000..ca4b907 --- /dev/null +++ b/src/raspberrypi/disks/scsicd.h @@ -0,0 +1,230 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI Hard Disk for Apple Macintosh ] +// +//--------------------------------------------------------------------------- +#pragma once + +#include "os.h" +#include "disk.h" +#include "filepath.h" + + +//--------------------------------------------------------------------------- +// +// Class precedence definition +// +//--------------------------------------------------------------------------- +class SCSICD; + +//=========================================================================== +// +// CD-ROM Track +// +//=========================================================================== +class CDTrack +{ +public: + // Basic Functions + CDTrack(SCSICD *scsicd); + // Constructor + virtual ~CDTrack(); + // Destructor + BOOL FASTCALL Init(int track, DWORD first, DWORD last); + // Initialization + + // Properties + void FASTCALL SetPath(BOOL cdda, const Filepath& path); + // Set the path + void FASTCALL GetPath(Filepath& path) const; + // Get the path + void FASTCALL AddIndex(int index, DWORD lba); + // Add index + DWORD FASTCALL GetFirst() const; + // Get the start LBA + DWORD FASTCALL GetLast() const; + // Get the last LBA + DWORD FASTCALL GetBlocks() const; + // Get the number of blocks + int FASTCALL GetTrackNo() const; + // Get the track number + BOOL FASTCALL IsValid(DWORD lba) const; + // Is this a valid LBA? + BOOL FASTCALL IsAudio() const; + // Is this an audio track? + +private: + SCSICD *cdrom; + // Parent device + BOOL valid; + // Valid track + int track_no; + // Track number + DWORD first_lba; + // First LBA + DWORD last_lba; + // Last LBA + BOOL audio; + // Audio track flag + BOOL raw; + // RAW data flag + Filepath imgpath; + // Image file path +}; + +//=========================================================================== +// +// CD-DA Buffer +// +//=========================================================================== +class CDDABuf +{ +public: + // Basic Functions + CDDABuf(); + // Constructor + virtual ~CDDABuf(); + // Destructor +#if 0 + BOOL Init(); + // Initialization + BOOL FASTCALL Load(const Filepath& path); + // Load + BOOL FASTCALL Save(const Filepath& path); + // Save + + // API + void FASTCALL Clear(); + // Clear the buffer + BOOL FASTCALL Open(Filepath& path); + // File specification + BOOL FASTCALL GetBuf(DWORD *buffer, int frames); + // Get the buffer + BOOL FASTCALL IsValid(); + // Check if Valid + BOOL FASTCALL ReadReq(); + // Read Request + BOOL FASTCALL IsEnd() const; + // Finish check + +private: + Filepath wavepath; + // Wave path + BOOL valid; + // Open result (is it valid?) + DWORD *buf; + // Data buffer + DWORD read; + // Read pointer + DWORD write; + // Write pointer + DWORD num; + // Valid number of data + DWORD rest; + // Remaining file size +#endif +}; + +//=========================================================================== +// +// SCSI CD-ROM +// +//=========================================================================== +class SCSICD : public Disk +{ +public: + // Number of tracks + enum { + TrackMax = 96 // Maximum number of tracks + }; + +public: + // Basic Functions + SCSICD(); + // Constructor + virtual ~SCSICD(); + // Destructor + BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); + // Open +#ifndef RASCSI + BOOL FASTCALL Load(Fileio *fio, int ver); + // Load +#endif // RASCSI + + // commands + int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); + // INQUIRY command + int FASTCALL Read(BYTE *buf, DWORD block); + // READ command + int FASTCALL ReadToc(const DWORD *cdb, BYTE *buf); + // READ TOC command + BOOL FASTCALL PlayAudio(const DWORD *cdb); + // PLAY AUDIO command + BOOL FASTCALL PlayAudioMSF(const DWORD *cdb); + // PLAY AUDIO MSF command + BOOL FASTCALL PlayAudioTrack(const DWORD *cdb); + // PLAY AUDIO TRACK command + + // CD-DA + BOOL FASTCALL NextFrame(); + // Frame notification + void FASTCALL GetBuf(DWORD *buffer, int samples, DWORD rate); + // Get CD-DA buffer + + // LBA-MSF変換 + void FASTCALL LBAtoMSF(DWORD lba, BYTE *msf) const; + // LBA→MSF conversion + DWORD FASTCALL MSFtoLBA(const BYTE *msf) const; + // MSF→LBA conversion + +private: + // Open + BOOL FASTCALL OpenCue(const Filepath& path); + // Open(CUE) + BOOL FASTCALL OpenIso(const Filepath& path); + // Open(ISO) + BOOL FASTCALL OpenPhysical(const Filepath& path); + // Open(Physical) + BOOL rawfile; + // RAW flag + + // Track management + void FASTCALL ClearTrack(); + // Clear the track + int FASTCALL SearchTrack(DWORD lba) const; + // Track search + CDTrack* track[TrackMax]; + // Track opbject references + int tracks; + // Effective number of track objects + int dataindex; + // Current data track + int audioindex; + // Current audio track + + int frame; + // Frame number + +#if 0 + CDDABuf da_buf; + // CD-DA buffer + int da_num; + // Number of CD-DA tracks + int da_cur; + // CD-DA current track + int da_next; + // CD-DA next track + BOOL da_req; + // CD-DA data request +#endif +}; diff --git a/src/raspberrypi/disks/scsihd.cpp b/src/raspberrypi/disks/scsihd.cpp new file mode 100644 index 0000000..ed4c32b --- /dev/null +++ b/src/raspberrypi/disks/scsihd.cpp @@ -0,0 +1,268 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI hard disk ] +// +//--------------------------------------------------------------------------- +#include "scsihd.h" +#include "xm6.h" +#include "fileio.h" + +//=========================================================================== +// +// SCSI Hard Disk +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +SCSIHD::SCSIHD() : Disk() +{ + // SCSI Hard Disk + disk.id = MAKEID('S', 'C', 'H', 'D'); +} + +//--------------------------------------------------------------------------- +// +// Reset +// +//--------------------------------------------------------------------------- +void FASTCALL SCSIHD::Reset() +{ + // Unlock and release attention + disk.lock = FALSE; + disk.attn = FALSE; + + // No reset, clear code + disk.reset = FALSE; + disk.code = 0x00; +} + +//--------------------------------------------------------------------------- +// +// Open +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/) +{ + Fileio fio; + off64_t size; + + ASSERT(this); + ASSERT(!disk.ready); + + // read open required + if (!fio.Open(path, Fileio::ReadOnly)) { + return FALSE; + } + + // Get file size + size = fio.GetFileSize(); + fio.Close(); + + // Must be 512 bytes + if (size & 0x1ff) { + return FALSE; + } + + // 10MB or more + if (size < 0x9f5400) { + return FALSE; + } + // 2TB according to xm6i + // There is a similar one in wxw/wxw_cfg.cpp + if (size > 2LL * 1024 * 1024 * 1024 * 1024) { + return FALSE; + } + + // sector size and number of blocks + disk.size = 9; + disk.blocks = (DWORD)(size >> 9); + + // Call base class + return Disk::Open(path); +} + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIHD::Inquiry( + const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) +{ + char vendor[32]; + char product[32]; + char rev[32]; + int size; + + ASSERT(this); + ASSERT(cdb); + ASSERT(buf); + ASSERT(cdb[0] == 0x12); + + // EVPD check + if (cdb[1] & 0x01) { + disk.code = DISK_INVALIDCDB; + return 0; + } + + // Ready check (Error if no image file) + if (!disk.ready) { + disk.code = DISK_NOTREADY; + return 0; + } + + // Basic data + // buf[0] ... Direct Access Device + // buf[2] ... SCSI-2 compliant command system + // buf[3] ... SCSI-2 compliant Inquiry response + // buf[4] ... Inquiry additional data + memset(buf, 0, 8); + + // SCSI-2 p.104 4.4.3 Incorrect logical unit handling + if (((cdb[1] >> 5) & 0x07) != disk.lun) { + buf[0] = 0x7f; + } + + buf[2] = 0x02; + buf[3] = 0x02; + buf[4] = 122 + 3; // Value close to real HDD + + // Fill with blanks + memset(&buf[8], 0x20, buf[4] - 3); + + // Determine vendor name/product name + sprintf(vendor, BENDER_SIGNATURE); + size = disk.blocks >> 11; + if (size < 300) + sprintf(product, "PRODRIVE LPS%dS", size); + else if (size < 600) + sprintf(product, "MAVERICK%dS", size); + else if (size < 800) + sprintf(product, "LIGHTNING%dS", size); + else if (size < 1000) + sprintf(product, "TRAILBRAZER%dS", size); + else if (size < 2000) + sprintf(product, "FIREBALL%dS", size); + else + sprintf(product, "FBSE%d.%dS", size / 1000, (size % 1000) / 100); + + // Vendor name + memcpy(&buf[8], vendor, strlen(vendor)); + + // Product name + memcpy(&buf[16], product, strlen(product)); + + // Revision + sprintf(rev, "0%01d%01d%01d", + (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); + memcpy(&buf[32], rev, 4); + + // Size of data that can be returned + size = (buf[4] + 5); + + // Limit if the other buffer is small + if (size > (int)cdb[4]) { + size = (int)cdb[4]; + } + + // Success + disk.code = DISK_NOERROR; + return size; +} + +//--------------------------------------------------------------------------- +// +// MODE SELECT +// *Not affected by disk.code +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length) +{ + BYTE page; + int size; + + ASSERT(this); + ASSERT(buf); + ASSERT(length >= 0); + + // PF + if (cdb[1] & 0x10) { + // Mode Parameter header + if (length >= 12) { + // Check the block length bytes + size = 1 << disk.size; + if (buf[9] != (BYTE)(size >> 16) || + buf[10] != (BYTE)(size >> 8) || + buf[11] != (BYTE)size) { + // currently does not allow changing sector length + disk.code = DISK_INVALIDPRM; + return FALSE; + } + buf += 12; + length -= 12; + } + + // Parsing the page + while (length > 0) { + // Get page + page = buf[0]; + + switch (page) { + // format device + case 0x03: + // check the number of bytes in the physical sector + size = 1 << disk.size; + if (buf[0xc] != (BYTE)(size >> 8) || + buf[0xd] != (BYTE)size) { + // currently does not allow changing sector length + disk.code = DISK_INVALIDPRM; + return FALSE; + } + break; + + // CD-ROM Parameters + // According to the SONY CDU-541 manual, Page code 8 is supposed + // to set the Logical Block Adress Format, as well as the + // inactivity timer multiplier + case 0x08: + // Debug code for Issue #2: + // https://github.com/akuker/RASCSI/issues/2 + printf("[Unhandled page code] Received mode page code 8 with total length %d\n ", length); + for (int i = 0; i= (off64_t)sizeof(hdr)) { + if (!fio.Read(hdr, sizeof(hdr))) { + fio.Close(); + return FALSE; + } + } + fio.Close(); + + // 512バイト単位であること + if (size & 0x1ff) { + return FALSE; + } + + // 10MB以上 + if (size < 0x9f5400) { + return FALSE; + } + // xm6iに準じて2TB + // よく似たものが wxw/wxw_cfg.cpp にもある + if (size > 2LL * 1024 * 1024 * 1024 * 1024) { + return FALSE; + } + + // 拡張子別にパラメータを決定 + ext = path.GetFileExt(); + if (xstrcasecmp(ext, _T(".HDN")) == 0) { + // デフォルト設定としてセクタサイズ512,セクタ数25,ヘッド数8を想定 + imgoffset = 0; + imgsize = size; + sectorsize = 512; + sectors = 25; + heads = 8; + cylinders = (int)(size >> 9); + cylinders >>= 3; + cylinders /= 25; + } else if (xstrcasecmp(ext, _T(".HDI")) == 0) { // Anex86 HD image? + imgoffset = getDwordLE(&hdr[4 + 4]); + imgsize = getDwordLE(&hdr[4 + 4 + 4]); + sectorsize = getDwordLE(&hdr[4 + 4 + 4 + 4]); + sectors = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4]); + heads = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4]); + cylinders = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4 + 4]); + } else if (xstrcasecmp(ext, _T(".NHD")) == 0 && + memcmp(hdr, "T98HDDIMAGE.R0\0", 15) == 0) { // T98Next HD image? + imgoffset = getDwordLE(&hdr[0x10 + 0x100]); + cylinders = getDwordLE(&hdr[0x10 + 0x100 + 4]); + heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]); + sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]); + sectorsize = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2 + 2]); + imgsize = (off64_t)cylinders * heads * sectors * sectorsize; + } + + // セクタサイズは256または512をサポート + if (sectorsize != 256 && sectorsize != 512) { + return FALSE; + } + + // イメージサイズの整合性チェック + if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) { + return FALSE; + } + + // セクタサイズ + for(disk.size = 16; disk.size > 0; --(disk.size)) { + if ((1 << disk.size) == sectorsize) + break; + } + if (disk.size <= 0 || disk.size > 16) { + return FALSE; + } + + // ブロック数 + disk.blocks = (DWORD)(imgsize >> disk.size); + disk.imgoffset = imgoffset; + + // Call the base class + return Disk::Open(path); +} + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIHD_NEC::Inquiry( + const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) +{ + int size; + + // 基底クラス + size = SCSIHD::Inquiry(cdb, buf, major, minor); + + // 基底クラスでエラーなら終了 + if (size == 0) { + return 0; + } + + // SCSI1相当に変更 + buf[2] = 0x01; + buf[3] = 0x01; + + // Replace Vendor name + buf[8] = 'N'; + buf[9] = 'E'; + buf[10] = 'C'; + + return size; +} + +//--------------------------------------------------------------------------- +// +// エラーページ追加 +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIHD_NEC::AddError(BOOL change, BYTE *buf) +{ + ASSERT(this); + ASSERT(buf); + + // Set the message length + buf[0] = 0x01; + buf[1] = 0x06; + + // No changeable area + if (change) { + return 8; + } + + // リトライカウントは0、リミットタイムは装置内部のデフォルト値を使用 + return 8; +} + +//--------------------------------------------------------------------------- +// +// フォーマットページ追加 +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf) +{ + int size; + + ASSERT(this); + ASSERT(buf); + + // Set the message length + buf[0] = 0x80 | 0x03; + buf[1] = 0x16; + + // 物理セクタのバイト数は変更可能に見せる(実際には変更できないが) + if (change) { + buf[0xc] = 0xff; + buf[0xd] = 0xff; + return 24; + } + + if (disk.ready) { + // 1ゾーンのトラック数を設定(PC-9801-55はこの値を見ているようだ) + buf[0x2] = (BYTE)(heads >> 8); + buf[0x3] = (BYTE)heads; + + // 1トラックのセクタ数を設定 + buf[0xa] = (BYTE)(sectors >> 8); + buf[0xb] = (BYTE)sectors; + + // 物理セクタのバイト数を設定 + size = 1 << disk.size; + buf[0xc] = (BYTE)(size >> 8); + buf[0xd] = (BYTE)size; + } + + // リムーバブル属性を設定(昔の名残) + if (disk.removable) { + buf[20] = 0x20; + } + + return 24; +} + +//--------------------------------------------------------------------------- +// +// ドライブページ追加 +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf) +{ + ASSERT(this); + ASSERT(buf); + + // Set the message length + buf[0] = 0x04; + buf[1] = 0x12; + + // No changeable area + if (change) { + return 20; + } + + if (disk.ready) { + // シリンダ数を設定 + buf[0x2] = (BYTE)(cylinders >> 16); + buf[0x3] = (BYTE)(cylinders >> 8); + buf[0x4] = (BYTE)cylinders; + + // ヘッド数を設定 + buf[0x5] = (BYTE)heads; + } + + return 20; +} diff --git a/src/raspberrypi/disks/scsihd_nec.h b/src/raspberrypi/disks/scsihd_nec.h new file mode 100644 index 0000000..270bf6b --- /dev/null +++ b/src/raspberrypi/disks/scsihd_nec.h @@ -0,0 +1,61 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI NEC "Genuine" Hard Disk] +// +//--------------------------------------------------------------------------- +#pragma once + +#include "scsihd.h" + +//=========================================================================== +// +// SCSI hard disk (PC-9801-55 NEC genuine /Anex86/T98Next) +// +//=========================================================================== +class SCSIHD_NEC : public SCSIHD +{ +public: + // Basic Functions + SCSIHD_NEC(); + // Constructor + + BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); + // Open + + // commands + int FASTCALL Inquiry( + const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); + // INQUIRY command + + // Internal processing + int FASTCALL AddError(BOOL change, BYTE *buf); + // Add error + int FASTCALL AddFormat(BOOL change, BYTE *buf); + // Add format + int FASTCALL AddDrive(BOOL change, BYTE *buf); + // Add drive + +private: + int cylinders; + // Number of cylinders + int heads; + // Number of heads + int sectors; + // Number of sectors + int sectorsize; + // Sector size + off64_t imgoffset; + // Image offset + off64_t imgsize; + // Image size +}; \ No newline at end of file diff --git a/src/raspberrypi/disks/scsimo.cpp b/src/raspberrypi/disks/scsimo.cpp new file mode 100644 index 0000000..64d363c --- /dev/null +++ b/src/raspberrypi/disks/scsimo.cpp @@ -0,0 +1,421 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI Magneto-Optical Disk] +// +//--------------------------------------------------------------------------- + +#include "scsimo.h" +#include "xm6.h" +#include "fileio.h" + +//=========================================================================== +// +// SCSI magneto-optical disk +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +SCSIMO::SCSIMO() : Disk() +{ + // SCSI magneto-optical disk + disk.id = MAKEID('S', 'C', 'M', 'O'); + + // Set as removable + disk.removable = TRUE; +} + +//--------------------------------------------------------------------------- +// +// Open +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIMO::Open(const Filepath& path, BOOL attn) +{ + Fileio fio; + off64_t size; + + ASSERT(this); + ASSERT(!disk.ready); + + // Open as read-only + if (!fio.Open(path, Fileio::ReadOnly)) { + return FALSE; + } + + // Get file size + size = fio.GetFileSize(); + fio.Close(); + + switch (size) { + // 128MB + case 0x797f400: + disk.size = 9; + disk.blocks = 248826; + break; + + // 230MB + case 0xd9eea00: + disk.size = 9; + disk.blocks = 446325; + break; + + // 540MB + case 0x1fc8b800: + disk.size = 9; + disk.blocks = 1041500; + break; + + // 640MB + case 0x25e28000: + disk.size = 11; + disk.blocks = 310352; + break; + + // Other (this is an error) + default: + return FALSE; + } + + // Call the base class + Disk::Open(path); + + // Attention if ready + if (disk.ready && attn) { + disk.attn = TRUE; + } + + return TRUE; +} + +#ifndef RASCSI +//--------------------------------------------------------------------------- +// +// Load +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIMO::Load(Fileio *fio, int ver) +{ + DWORD sz; + disk_t buf; + DWORD padding; + Filepath path; + + ASSERT(this); + ASSERT(fio); + ASSERT(ver >= 0x0200); + + // Prior to version 2.03, the disk was not saved + if (ver <= 0x0202) { + return TRUE; + } + + // load size, match + if (!fio->Read(&sz, sizeof(sz))) { + return FALSE; + } + if (sz != 52) { + return FALSE; + } + + // load into buffer + PROP_IMPORT(fio, buf.id); + PROP_IMPORT(fio, buf.ready); + PROP_IMPORT(fio, buf.writep); + PROP_IMPORT(fio, buf.readonly); + PROP_IMPORT(fio, buf.removable); + PROP_IMPORT(fio, buf.lock); + PROP_IMPORT(fio, buf.attn); + PROP_IMPORT(fio, buf.reset); + PROP_IMPORT(fio, buf.size); + PROP_IMPORT(fio, buf.blocks); + PROP_IMPORT(fio, buf.lun); + PROP_IMPORT(fio, buf.code); + PROP_IMPORT(fio, padding); + + // Load path + if (!path.Load(fio, ver)) { + return FALSE; + } + + // Always eject + Eject(TRUE); + + // Move only if IDs match + if (disk.id != buf.id) { + // Not MO at the time of save. Maintain eject status + return TRUE; + } + + // Re-try opening + if (!Open(path, FALSE)) { + // Cannot reopen. Maintain eject status + return TRUE; + } + + // Disk cache is created in Open. Move property only + if (!disk.readonly) { + disk.writep = buf.writep; + } + disk.lock = buf.lock; + disk.attn = buf.attn; + disk.reset = buf.reset; + disk.lun = buf.lun; + disk.code = buf.code; + + // loaded successfully + return TRUE; +} +#endif // RASCSI + +//--------------------------------------------------------------------------- +// +// INQUIRY +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIMO::Inquiry( + const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor) +{ + int size; + char rev[32]; + + ASSERT(this); + ASSERT(cdb); + ASSERT(buf); + ASSERT(cdb[0] == 0x12); + + // EVPD check + if (cdb[1] & 0x01) { + disk.code = DISK_INVALIDCDB; + return FALSE; + } + + // 基本データ + // buf[0] ... Optical Memory Device + // buf[1] ... Removable + // buf[2] ... SCSI-2 compliant command system + // buf[3] ... SCSI-2 compliant Inquiry response + // buf[4] ... Inquiry additional data + memset(buf, 0, 8); + buf[0] = 0x07; + + // SCSI-2 p.104 4.4.3 Incorrect logical unit handling + if (((cdb[1] >> 5) & 0x07) != disk.lun) { + buf[0] = 0x7f; + } + + buf[1] = 0x80; + buf[2] = 0x02; + buf[3] = 0x02; + buf[4] = 36 - 5; // required + + // Fill with blanks + memset(&buf[8], 0x20, buf[4] - 3); + + // Vendor name + memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE)); + + // Product name + memcpy(&buf[16], "M2513A", 6); + + // Revision (XM6 version number) + sprintf(rev, "0%01d%01d%01d", + (int)major, (int)(minor >> 4), (int)(minor & 0x0f)); + memcpy(&buf[32], rev, 4); + + // Size return data + size = (buf[4] + 5); + + // Limit the size if the buffer is too small + if (size > (int)cdb[4]) { + size = (int)cdb[4]; + } + + // Success + disk.code = DISK_NOERROR; + return size; +} + +//--------------------------------------------------------------------------- +// +// MODE SELECT +// *Not affected by disk.code +// +//--------------------------------------------------------------------------- +BOOL FASTCALL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length) +{ + int page; + int size; + + ASSERT(this); + ASSERT(buf); + ASSERT(length >= 0); + + // PF + if (cdb[1] & 0x10) { + // Mode Parameter header + if (length >= 12) { + // Check the block length (in bytes) + size = 1 << disk.size; + if (buf[9] != (BYTE)(size >> 16) || + buf[10] != (BYTE)(size >> 8) || buf[11] != (BYTE)size) { + // Currently does not allow changing sector length + disk.code = DISK_INVALIDPRM; + return FALSE; + } + buf += 12; + length -= 12; + } + + // Parsing the page + while (length > 0) { + // Get the page + page = buf[0]; + + switch (page) { + // format device + case 0x03: + // Check the number of bytes in the physical sector + size = 1 << disk.size; + if (buf[0xc] != (BYTE)(size >> 8) || + buf[0xd] != (BYTE)size) { + // Currently does not allow changing sector length + disk.code = DISK_INVALIDPRM; + return FALSE; + } + break; + // vendor unique format + case 0x20: + // just ignore, for now + break; + + // Other page + default: + break; + } + + // Advance to the next page + size = buf[1] + 2; + length -= size; + buf += size; + } + } + + // Do not generate an error for the time being (MINIX) + disk.code = DISK_NOERROR; + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Vendor Unique Format Page 20h (MO) +// +//--------------------------------------------------------------------------- +int FASTCALL SCSIMO::AddVendor(int page, BOOL change, BYTE *buf) +{ + ASSERT(this); + ASSERT(buf); + + // Page code 20h + if ((page != 0x20) && (page != 0x3f)) { + return 0; + } + + // Set the message length + buf[0] = 0x20; + buf[1] = 0x0a; + + // No changeable area + if (change) { + return 12; + } + + /* + mode page code 20h - Vendor Unique Format Page + format mode XXh type 0 + information: http://h20628.www2.hp.com/km-ext/kmcsdirect/emr_na-lpg28560-1.pdf + + offset description + 02h format mode + 03h type of format (0) + 04~07h size of user band (total sectors?) + 08~09h size of spare band (spare sectors?) + 0A~0Bh number of bands + + actual value of each 3.5inches optical medium (grabbed by Fujitsu M2513EL) + + 128M 230M 540M 640M + --------------------------------------------------- + size of user band 3CBFAh 6CF75h FE45Ch 4BC50h + size of spare band 0400h 0401h 08CAh 08C4h + number of bands 0001h 000Ah 0012h 000Bh + + further information: http://r2089.blog36.fc2.com/blog-entry-177.html + */ + + if (disk.ready) { + unsigned spare = 0; + unsigned bands = 0; + + if (disk.size == 9) switch (disk.blocks) { + // 128MB + case 248826: + spare = 1024; + bands = 1; + break; + + // 230MB + case 446325: + spare = 1025; + bands = 10; + break; + + // 540MB + case 1041500: + spare = 2250; + bands = 18; + break; + } + + if (disk.size == 11) switch (disk.blocks) { + // 640MB + case 310352: + spare = 2244; + bands = 11; + break; + + // 1.3GB (lpproj: not tested with real device) + case 605846: + spare = 4437; + bands = 18; + break; + } + + buf[2] = 0; // format mode + buf[3] = 0; // type of format + buf[4] = (BYTE)(disk.blocks >> 24); + buf[5] = (BYTE)(disk.blocks >> 16); + buf[6] = (BYTE)(disk.blocks >> 8); + buf[7] = (BYTE)disk.blocks; + buf[8] = (BYTE)(spare >> 8); + buf[9] = (BYTE)spare; + buf[10] = (BYTE)(bands >> 8); + buf[11] = (BYTE)bands; + } + + return 12; +} diff --git a/src/raspberrypi/disks/scsimo.h b/src/raspberrypi/disks/scsimo.h new file mode 100644 index 0000000..f8aa299 --- /dev/null +++ b/src/raspberrypi/disks/scsimo.h @@ -0,0 +1,49 @@ +//--------------------------------------------------------------------------- +// +// SCSI Target Emulator RaSCSI (*^..^*) +// for Raspberry Pi +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// Copyright (C) akuker +// +// Licensed under the BSD 3-Clause License. +// See LICENSE file in the project root folder. +// +// [ SCSI Magneto-Optical Disk] +// +//--------------------------------------------------------------------------- +#pragma once + +#include "os.h" +#include "disk.h" +#include "filepath.h" + +//=========================================================================== +// +// SCSI magneto-optical disk +// +//=========================================================================== +class SCSIMO : public Disk +{ +public: + // Basic Functions + SCSIMO(); + // Constructor + BOOL FASTCALL Open(const Filepath& path, BOOL attn = TRUE); + // Open +#ifndef RASCSI + BOOL FASTCALL Load(Fileio *fio, int ver); + // Load +#endif // RASCSI + + // commands + int FASTCALL Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); + // INQUIRY command + BOOL FASTCALL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); + // MODE SELECT(6) command + + // Internal processing + int FASTCALL AddVendor(int page, BOOL change, BYTE *buf); + // Add vendor special page +}; \ No newline at end of file diff --git a/src/raspberrypi/fileio.h b/src/raspberrypi/fileio.h index fd9c5ce..da57471 100644 --- a/src/raspberrypi/fileio.h +++ b/src/raspberrypi/fileio.h @@ -11,6 +11,8 @@ #if !defined(fileio_h) #define fileio_h +#include "filepath.h" + #ifdef BAREMETAL #include "ff.h" #endif // BAREMETAL diff --git a/src/raspberrypi/filepath.h b/src/raspberrypi/filepath.h index b7a1ced..0bcdb2e 100644 --- a/src/raspberrypi/filepath.h +++ b/src/raspberrypi/filepath.h @@ -7,9 +7,7 @@ // [ ファイルパス(サブセット) ] // //--------------------------------------------------------------------------- - -#if !defined(filepath_h) -#define filepath_h +#pragma once //--------------------------------------------------------------------------- // @@ -18,6 +16,8 @@ //--------------------------------------------------------------------------- #define FILEPATH_MAX _MAX_PATH +class Fileio; + //=========================================================================== // // ファイルパス @@ -77,5 +77,3 @@ private: static TCHAR FileExt[_MAX_FNAME + _MAX_DIR]; // ショート名(TCHAR) }; - -#endif // filepath_h diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 3c24eee..c96be26 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -16,6 +16,17 @@ #include "disk.h" #include "gpiobus.h" +#include "sasidev_ctrl.h" +#include "scsidev_ctrl.h" + +#include "sasihd.h" +#include "scsihd.h" +#include "scsihd_apple.h" +#include "scsihd_nec.h" +#include "scsicd.h" +#include "scsimo.h" +#include "scsi_host_bridge.h" + //--------------------------------------------------------------------------- // // Constant declarations