2019-08-23 03:16:58 +00:00
|
|
|
//
|
|
|
|
// DirectAccessDevice.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 22/08/2019.
|
|
|
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "DirectAccessDevice.hpp"
|
2019-09-19 01:41:29 +00:00
|
|
|
#include "../../../Outputs/Log.hpp"
|
2019-08-23 03:16:58 +00:00
|
|
|
|
|
|
|
using namespace SCSI;
|
|
|
|
|
2019-08-25 21:03:41 +00:00
|
|
|
void DirectAccessDevice::set_storage(const std::shared_ptr<Storage::MassStorage::MassStorageDevice> &device) {
|
|
|
|
device_ = device;
|
|
|
|
}
|
|
|
|
|
2019-08-23 03:16:58 +00:00
|
|
|
bool DirectAccessDevice::read(const Target::CommandState &state, Target::Responder &responder) {
|
2019-08-25 21:03:41 +00:00
|
|
|
if(!device_) return false;
|
2019-08-23 03:16:58 +00:00
|
|
|
|
2019-09-17 02:20:42 +00:00
|
|
|
const auto specs = state.read_write_specs();
|
2019-09-19 01:41:29 +00:00
|
|
|
LOG("Read: " << specs.number_of_blocks << " from " << specs.address);
|
2019-09-17 02:20:42 +00:00
|
|
|
|
|
|
|
std::vector<uint8_t> output = device_->get_block(specs.address);
|
|
|
|
for(uint32_t offset = 1; offset < specs.number_of_blocks; ++offset) {
|
|
|
|
const auto next_block = device_->get_block(specs.address + offset);
|
|
|
|
std::copy(next_block.begin(), next_block.end(), std::back_inserter(output));
|
|
|
|
}
|
|
|
|
|
|
|
|
responder.send_data(std::move(output), [] (const Target::CommandState &state, Target::Responder &responder) {
|
2019-09-04 02:40:18 +00:00
|
|
|
responder.terminate_command(Target::Responder::Status::Good);
|
2019-08-23 03:16:58 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-08 02:04:44 +00:00
|
|
|
|
2019-09-13 01:58:09 +00:00
|
|
|
bool DirectAccessDevice::write(const Target::CommandState &state, Target::Responder &responder) {
|
|
|
|
if(!device_) return false;
|
|
|
|
|
2019-09-17 02:20:42 +00:00
|
|
|
const auto specs = state.read_write_specs();
|
|
|
|
|
|
|
|
responder.receive_data(device_->get_block_size() * specs.number_of_blocks, [this, specs] (const Target::CommandState &state, Target::Responder &responder) {
|
|
|
|
const auto received_data = state.received_data();
|
2019-09-18 01:30:04 +00:00
|
|
|
const auto block_size = ssize_t(device_->get_block_size());
|
2019-09-17 02:20:42 +00:00
|
|
|
for(uint32_t offset = 0; offset < specs.number_of_blocks; ++offset) {
|
|
|
|
// TODO: clean up this gross inefficiency when std::span is standard.
|
2019-09-18 01:30:04 +00:00
|
|
|
std::vector<uint8_t> sub_vector(received_data.begin() + ssize_t(offset)*block_size, received_data.begin() + ssize_t(offset+1)*block_size);
|
2019-09-17 02:20:42 +00:00
|
|
|
this->device_->set_block(specs.address + offset, sub_vector);
|
|
|
|
}
|
2019-09-13 01:58:09 +00:00
|
|
|
responder.terminate_command(Target::Responder::Status::Good);
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-12 01:52:02 +00:00
|
|
|
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<uint8_t> 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;
|
|
|
|
}
|
|
|
|
|
2019-09-09 01:59:56 +00:00
|
|
|
Target::Executor::Inquiry DirectAccessDevice::inquiry_values() {
|
|
|
|
return Inquiry("Apple", "ProFile", "1"); // All just guesses.
|
2019-09-08 02:04:44 +00:00
|
|
|
}
|
2019-09-13 01:58:09 +00:00
|
|
|
|
|
|
|
bool DirectAccessDevice::format_unit(const Target::CommandState &state, Target::Responder &responder) {
|
|
|
|
// Formatting: immediate.
|
|
|
|
responder.terminate_command(Target::Responder::Status::Good);
|
|
|
|
return true;
|
|
|
|
}
|