From 00ce7f8ae0a194d7e58eb388dfcb1d5e01f106c1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 7 Sep 2019 22:04:44 -0400 Subject: [PATCH] Takes a first shot at INQUIRY. --- .../MassStorage/SCSI/DirectAccessDevice.cpp | 23 +++++++++++++ .../MassStorage/SCSI/DirectAccessDevice.hpp | 1 + Storage/MassStorage/SCSI/Target.cpp | 4 +++ Storage/MassStorage/SCSI/Target.hpp | 10 +++--- .../MassStorage/SCSI/TargetImplementation.hpp | 33 +++++++++++-------- 5 files changed, 51 insertions(+), 20 deletions(-) diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp index 6b2de9d68..bfbd382a0 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp @@ -24,3 +24,26 @@ bool DirectAccessDevice::read(const Target::CommandState &state, Target::Respond return true; } + +bool DirectAccessDevice::inquiry(const Target::CommandState &state, Target::Responder &responder) { + if(!device_) return false; + + std::vector response = { + 0x00, /* Peripheral device type: directly addressible. */ + 0x00, /* Non-removeable (0x80 = removeable). */ + 0x00, /* Version: does not claim conformance to any standard. */ + 0x00, /* Response data format: 0 for SCSI-1? */ + 0x00, /* Additional length. */ + }; + + const auto allocated_bytes = state.allocated_inquiry_bytes(); + if(allocated_bytes < response.size()) { + response.resize(allocated_bytes); + } + + responder.send_data(std::move(response), [] (const Target::CommandState &state, Target::Responder &responder) { + responder.terminate_command(Target::Responder::Status::Good); + }); + + return true; +} diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp index e3f18575f..fa755eb9f 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp @@ -26,6 +26,7 @@ class DirectAccessDevice: public Target::Executor { /* SCSI commands. */ bool read(const Target::CommandState &, Target::Responder &); + bool inquiry(const Target::CommandState &, Target::Responder &); private: std::shared_ptr device_; diff --git a/Storage/MassStorage/SCSI/Target.cpp b/Storage/MassStorage/SCSI/Target.cpp index dc0520e87..d901e50e1 100644 --- a/Storage/MassStorage/SCSI/Target.cpp +++ b/Storage/MassStorage/SCSI/Target.cpp @@ -39,3 +39,7 @@ uint16_t CommandState::number_of_blocks() const { return uint16_t((data_[7] << 8) | data_[8]); } } + +size_t CommandState::allocated_inquiry_bytes() const { + return size_t(((data_[4] - 1) & 0xff) + 1); +} diff --git a/Storage/MassStorage/SCSI/Target.hpp b/Storage/MassStorage/SCSI/Target.hpp index 5a8d8f618..f8e60b1cc 100644 --- a/Storage/MassStorage/SCSI/Target.hpp +++ b/Storage/MassStorage/SCSI/Target.hpp @@ -24,9 +24,13 @@ class CommandState { public: CommandState(const std::vector &data); + // For read and write commands. uint32_t address() const; uint16_t number_of_blocks() const; + // For inquiry commands. + size_t allocated_inquiry_bytes() const; + private: const std::vector &data_; }; @@ -88,12 +92,6 @@ struct Responder { responder.end_command(); }); }); - -// send_message(Target::Responder::Message::CommandComplete, [status] (const Target::CommandState &state, Target::Responder &responder) { -// responder.send_status(status, [] (const Target::CommandState &state, Target::Responder &responder) { -// responder.end_command(); -// }); -// }); } }; diff --git a/Storage/MassStorage/SCSI/TargetImplementation.hpp b/Storage/MassStorage/SCSI/TargetImplementation.hpp index 63f5958ea..8726bf948 100644 --- a/Storage/MassStorage/SCSI/TargetImplementation.hpp +++ b/Storage/MassStorage/SCSI/TargetImplementation.hpp @@ -73,9 +73,12 @@ template void Target::scsi_bus_did_change(Bus *, B command_[command_pointer_] = uint8_t(new_state); ++command_pointer_; if(command_pointer_ == command_.size()) { - dispatch_command(); - - // TODO: if(!dispatch_command()) signal_error_somehow(); + if(!dispatch_command()) { + // This is just a guess for now; I don't know how SCSI + // devices are supposed to respond if they don't support + // a command. + terminate_command(Responder::Status::TaskAborted); + } } } break; @@ -103,9 +106,9 @@ template void Target::scsi_bus_did_change(Bus *, B case 0: if(data_pointer_ == data_.size()) { next_function_(CommandState(command_), *this); + } else { + bus_state_ |= Line::Request; } - - bus_state_ |= Line::Request; break; } set_device_output(bus_state_); @@ -129,16 +132,16 @@ template void Target::scsi_bus_did_change(Bus *, B (phase_ == Phase::SendingData && data_pointer_ == data_.size()) ) { next_function_(CommandState(command_), *this); - } + } else { + bus_state_ |= Line::Request; + bus_state_ &= ~0xff; - bus_state_ |= Line::Request; - bus_state_ &= ~0xff; - - switch(phase_) { - case Phase::SendingData: bus_state_ |= data_[data_pointer_]; break; - case Phase::SendingStatus: bus_state_ |= BusState(status_); break; - default: - case Phase::SendingMessage: bus_state_ |= BusState(message_); break; + switch(phase_) { + case Phase::SendingData: bus_state_ |= data_[data_pointer_]; break; + case Phase::SendingStatus: bus_state_ |= BusState(status_); break; + default: + case Phase::SendingMessage: bus_state_ |= BusState(message_); break; + } } break; } @@ -171,6 +174,8 @@ template bool Target::dispatch_command() { #define G1(x) (0x20|x) #define G5(x) (0xa0|x) + printf("---Command %02x---\n", command_[0]); + switch(command_[0]) { default: return false;