From 87e8dade2f629c07ebed5c4179fc670beaa61954 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Sep 2019 21:52:02 -0400 Subject: [PATCH] Implements READ BUFFER to do, you know, *something*. Plus READ CAPACITY. The HD SC utility now offers up drive 6 for formatting. That's progress. --- .../MassStorage/SCSI/DirectAccessDevice.cpp | 22 ++++++++++++++++ .../MassStorage/SCSI/DirectAccessDevice.hpp | 1 + Storage/MassStorage/SCSI/Target.cpp | 14 ++++++++++- Storage/MassStorage/SCSI/Target.hpp | 25 ++++++++++++++++++- .../MassStorage/SCSI/TargetImplementation.hpp | 5 ++-- 5 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp index 7d391f59e..5c6ce6408 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp @@ -25,6 +25,28 @@ bool DirectAccessDevice::read(const Target::CommandState &state, Target::Respond return true; } +bool DirectAccessDevice::read_capacity(const Target::CommandState &state, Target::Responder &responder) { + const auto final_block = device_->get_number_of_blocks() - 1; + const auto block_size = device_->get_block_size(); + std::vector data = { + uint8_t(final_block >> 24), + uint8_t(final_block >> 16), + uint8_t(final_block >> 8), + uint8_t(final_block >> 0), + + uint8_t(block_size >> 24), + uint8_t(block_size >> 16), + uint8_t(block_size >> 8), + uint8_t(block_size >> 0), + }; + + responder.send_data(std::move(data), [] (const Target::CommandState &state, Target::Responder &responder) { + responder.terminate_command(Target::Responder::Status::Good); + }); + + return true; +} + Target::Executor::Inquiry DirectAccessDevice::inquiry_values() { return Inquiry("Apple", "ProFile", "1"); // All just guesses. } diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp index 192955c32..1c94e3e6e 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp @@ -27,6 +27,7 @@ class DirectAccessDevice: public Target::Executor { /* SCSI commands. */ bool read(const Target::CommandState &, Target::Responder &); Inquiry inquiry_values(); + bool read_capacity(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 f3fbbc329..c2fa81556 100644 --- a/Storage/MassStorage/SCSI/Target.cpp +++ b/Storage/MassStorage/SCSI/Target.cpp @@ -46,7 +46,7 @@ size_t CommandState::allocated_inquiry_bytes() const { } CommandState::ModeSense CommandState::mode_sense_specs() const { - CommandState::ModeSense specs; + ModeSense specs; specs.exclude_block_descriptors = (data_[1] & 0x08); specs.page_control_values = ModeSense::PageControlValues(data_[2] >> 5); @@ -56,3 +56,15 @@ CommandState::ModeSense CommandState::mode_sense_specs() const { return specs; } + +CommandState::ReadBuffer CommandState::read_buffer_specs() const { + ReadBuffer specs; + + specs.mode = ReadBuffer::Mode(data_[1]&7); + if(specs.mode > ReadBuffer::Mode::Reserved) specs.mode = ReadBuffer::Mode::Reserved; + specs.buffer_id = data_[2]; + specs.buffer_offset = uint32_t((data_[3] << 16) | (data_[4] << 8) | data_[5]); + specs.buffer_length = uint32_t((data_[6] << 16) | (data_[7] << 8) | data_[8]); + + return specs; +} diff --git a/Storage/MassStorage/SCSI/Target.hpp b/Storage/MassStorage/SCSI/Target.hpp index e514525cb..eea1864cc 100644 --- a/Storage/MassStorage/SCSI/Target.hpp +++ b/Storage/MassStorage/SCSI/Target.hpp @@ -47,6 +47,19 @@ class CommandState { }; ModeSense mode_sense_specs() const; + struct ReadBuffer { + enum class Mode { + CombinedHeaderAndData = 0, + VendorSpecific = 1, + Data = 2, + Descriptor = 3, + Reserved = 4 + } mode = Mode::CombinedHeaderAndData; + uint8_t buffer_id = 0; + uint32_t buffer_offset = 0, buffer_length = 0; + }; + ReadBuffer read_buffer_specs() const; + private: const std::vector &data_; }; @@ -137,7 +150,7 @@ struct Executor { bool write_diagnostic(const CommandState &, Responder &) { return false; } /// Mode sense: the default implementation will call into the appropriate - /// strucutred getter. + /// structured getter. bool mode_sense(const CommandState &state, Responder &responder) { const auto specs = state.mode_sense_specs(); std::vector response = { @@ -270,6 +283,16 @@ struct Executor { bool search_data_equal(const CommandState &, Responder &) { return false; } bool search_data_high(const CommandState &, Responder &) { return false; } bool search_data_low(const CommandState &, Responder &) { return false; } + bool read_buffer(const CommandState &state, Responder &responder) { + // Since I have no idea what earthly function READ BUFFER is meant to allow, + // the default implementation just returns an empty buffer of the requested size. + const auto specs = state.read_buffer_specs(); + responder.send_data(std::vector(specs.buffer_length), [] (const Target::CommandState &, Target::Responder &responder) { + responder.terminate_command(Target::Responder::Status::Good); + }); + + return true; + } /* Group 5 commands. */ bool set_block_limits(const CommandState &, Responder &) { return false; } diff --git a/Storage/MassStorage/SCSI/TargetImplementation.hpp b/Storage/MassStorage/SCSI/TargetImplementation.hpp index 0d75bcce8..26184f9a0 100644 --- a/Storage/MassStorage/SCSI/TargetImplementation.hpp +++ b/Storage/MassStorage/SCSI/TargetImplementation.hpp @@ -186,12 +186,12 @@ template bool Target::dispatch_command() { case G0(0x08): return executor_.read(arguments, *this); case G0(0x0a): return executor_.write(arguments, *this); case G0(0x0b): return executor_.seek(arguments, *this); + case G0(0x12): return executor_.inquiry(arguments, *this); case G0(0x16): return executor_.reserve_unit(arguments, *this); case G0(0x17): return executor_.release_unit(arguments, *this); + case G0(0x1a): return executor_.mode_sense(arguments, *this); case G0(0x1c): return executor_.read_diagnostic(arguments, *this); case G0(0x1d): return executor_.write_diagnostic(arguments, *this); - case G0(0x12): return executor_.inquiry(arguments, *this); - case G0(0x1a): return executor_.mode_sense(arguments, *this); case G1(0x05): return executor_.read_capacity(arguments, *this); case G1(0x08): return executor_.read(arguments, *this); @@ -201,6 +201,7 @@ template bool Target::dispatch_command() { case G1(0x11): return executor_.search_data_equal(arguments, *this); case G1(0x10): return executor_.search_data_high(arguments, *this); case G1(0x12): return executor_.search_data_low(arguments, *this); + case G1(0x1c): return executor_.read_buffer(arguments, *this); case G5(0x09): return executor_.set_block_limits(arguments, *this); }