diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp index 5c6ce6408..4646cba6f 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp @@ -25,6 +25,17 @@ bool DirectAccessDevice::read(const Target::CommandState &state, Target::Respond return true; } +bool DirectAccessDevice::write(const Target::CommandState &state, Target::Responder &responder) { + if(!device_) return false; + + const auto target_address = state.address(); + responder.receive_data(device_->get_block_size(), [target_address] (const Target::CommandState &state, Target::Responder &responder) { + responder.terminate_command(Target::Responder::Status::Good); + }); + + 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(); @@ -50,3 +61,9 @@ bool DirectAccessDevice::read_capacity(const Target::CommandState &state, Target Target::Executor::Inquiry DirectAccessDevice::inquiry_values() { return Inquiry("Apple", "ProFile", "1"); // All just guesses. } + +bool DirectAccessDevice::format_unit(const Target::CommandState &state, Target::Responder &responder) { + // Formatting: immediate. + responder.terminate_command(Target::Responder::Status::Good); + return true; +} diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp index 1c94e3e6e..5f96a5747 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp @@ -26,8 +26,10 @@ class DirectAccessDevice: public Target::Executor { /* SCSI commands. */ bool read(const Target::CommandState &, Target::Responder &); + bool write(const Target::CommandState &, Target::Responder &); Inquiry inquiry_values(); bool read_capacity(const Target::CommandState &, Target::Responder &); + bool format_unit(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 c2fa81556..a576f1501 100644 --- a/Storage/MassStorage/SCSI/Target.cpp +++ b/Storage/MassStorage/SCSI/Target.cpp @@ -10,7 +10,7 @@ using namespace SCSI::Target; -CommandState::CommandState(const std::vector &data) : data_(data) {} +CommandState::CommandState(const std::vector &data, const std::vector &received) : data_(data), received_(received) {} uint32_t CommandState::address() const { switch(data_.size()) { @@ -68,3 +68,14 @@ CommandState::ReadBuffer CommandState::read_buffer_specs() const { return specs; } + +CommandState::ModeSelect CommandState::mode_select_specs() const { + ModeSelect specs; + + specs.parameter_list_length = number_of_blocks(); + specs.content_is_vendor_specific = !(data_[1] & 0x10); + specs.revert_to_default = (data_[1] & 0x02); + specs.save_pages = (data_[1] & 0x01); + + return specs; +} diff --git a/Storage/MassStorage/SCSI/Target.hpp b/Storage/MassStorage/SCSI/Target.hpp index eea1864cc..b7eb0c6a1 100644 --- a/Storage/MassStorage/SCSI/Target.hpp +++ b/Storage/MassStorage/SCSI/Target.hpp @@ -23,7 +23,7 @@ namespace Target { */ class CommandState { public: - CommandState(const std::vector &data); + CommandState(const std::vector &command, const std::vector &received); // For read and write commands. uint32_t address() const; @@ -47,6 +47,14 @@ class CommandState { }; ModeSense mode_sense_specs() const; + struct ModeSelect { + bool content_is_vendor_specific = true; + bool revert_to_default = false; + bool save_pages = false; + uint16_t parameter_list_length = 0; + }; + ModeSelect mode_select_specs() const; + struct ReadBuffer { enum class Mode { CombinedHeaderAndData = 0, @@ -60,8 +68,13 @@ class CommandState { }; ReadBuffer read_buffer_specs() const; + const std::vector &received_data() { + return received_; + } + private: const std::vector &data_; + const std::vector &received_; }; /*! @@ -179,6 +192,17 @@ struct Executor { return true; } + bool mode_select(const CommandState &state, Responder &responder) { + const auto specs = state.mode_select_specs(); + + responder.receive_data(specs.parameter_list_length, [] (const Target::CommandState &state, Target::Responder &responder) { + // TODO: parse data according to current sense mode. + responder.terminate_command(Target::Responder::Status::Good); + }); + + return true; + } + /// Inquiry: the default implementation will call the structured version and /// package appropriately. struct Inquiry { diff --git a/Storage/MassStorage/SCSI/TargetImplementation.hpp b/Storage/MassStorage/SCSI/TargetImplementation.hpp index 26184f9a0..20b1c0860 100644 --- a/Storage/MassStorage/SCSI/TargetImplementation.hpp +++ b/Storage/MassStorage/SCSI/TargetImplementation.hpp @@ -105,7 +105,7 @@ template void Target::scsi_bus_did_change(Bus *, B case 0: if(data_pointer_ == data_.size()) { - next_function_(CommandState(command_), *this); + next_function_(CommandState(command_, data_), *this); } else { bus_state_ |= Line::Request; } @@ -131,7 +131,7 @@ template void Target::scsi_bus_did_change(Bus *, B (phase_ == Phase::SendingStatus && data_pointer_ == 1) || (phase_ == Phase::SendingData && data_pointer_ == data_.size()) ) { - next_function_(CommandState(command_), *this); + next_function_(CommandState(command_, data_), *this); } else { bus_state_ |= Line::Request; bus_state_ &= ~0xff; @@ -168,7 +168,7 @@ template void Target::begin_command(uint8_t first_ template bool Target::dispatch_command() { - CommandState arguments(command_); + CommandState arguments(command_, data_); #define G0(x) x #define G1(x) (0x20|x) @@ -187,6 +187,7 @@ template bool Target::dispatch_command() { 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(0x15): return executor_.mode_select(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); @@ -202,6 +203,8 @@ template bool Target::dispatch_command() { 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 G1(0x15): return executor_.mode_select(arguments, *this); + case G5(0x09): return executor_.set_block_limits(arguments, *this); }