mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-21 08:29:59 +00:00
Use vector for INQUIRY data, LUN list can have gaps, made methods const (#713)
* Use vector for INQUIRY data, Inquiry() is const, moved EVPD check
* Moved code
* Fixed warning
* Updated memcpy
* Set length
* Limit result vector size
* Limit result buffer size
* Inquiry() result buffer handling update
* Logging update
* Inquiry cleanup
* NEC drive can also use PrimaryDevice::Inquiry()
* NEC drive is never removable
* Comment update
* Bridge can also use PrimaryDevice::Inquiry()
* Removed unused method argument
* Comment update
* Updated comment
* Updated REQUEST SENSE buffer handling
* Fixed typo
* Fixed typo
* Re-added comment
* Updated additional length handling
* Check for INQUIRY command support first
* Added assertion
* Size handling update
* Renaming
* Renaming
* Removed obsolete casts
* Cleanup
* Moved error codes to scsi_defs namespace
* Fixed ReadDefectData10
* Comment update
* Updated buffer handling
* Data type update
* SendDiagnostic is now const
* Removed obsolete forward declaration
* removed unused enum
* Reduced method visibility
* Renaming
* GetSendDelay() can be const
* Made method const
* Made method const
* Added TODO
* Use iterator
* Made method const
* Revert "Made method const"
This reverts commit 38412b8ddd
.
* No need to sort all set/maps
* Do not sort all sets
* Removed more unnecessary sorting
* Cleaned up includes
* More include cleanups
* Updated REPORT LUNS
* LUNs must not be consecutive anymore
* Updated detaching of LUN
* Improvements for devices without LUN 0
* Assume LUN 0 is always present
* Enforce presence of LUN 0
* Updated error handling
This commit is contained in:
parent
da02eccb2e
commit
1df7cdb1f3
@ -623,7 +623,7 @@ void SASIDEV::DataOut()
|
||||
// Error
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SASIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc, ERROR_CODES::status status)
|
||||
void SASIDEV::Error(sense_key sense_key, asc asc, status status)
|
||||
{
|
||||
// Get bus information
|
||||
ctrl.bus->Aquire();
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "scsi.h"
|
||||
#include "fileio.h"
|
||||
|
||||
class Device;
|
||||
class PrimaryDevice;
|
||||
|
||||
//===========================================================================
|
||||
@ -31,30 +30,6 @@ class PrimaryDevice;
|
||||
class SASIDEV
|
||||
{
|
||||
protected:
|
||||
enum scsi_message_code : BYTE {
|
||||
eMsgCodeAbort = 0x06,
|
||||
eMsgCodeAbortTag = 0x0D,
|
||||
eMsgCodeBusDeviceReset = 0x0C,
|
||||
eMsgCodeClearQueue = 0x0E,
|
||||
eMsgCodeCommandComplete = 0x00,
|
||||
eMsgCodeDisconnect = 0x04,
|
||||
eMsgCodeIdentify = 0x80,
|
||||
eMsgCodeIgnoreWideResidue = 0x23, // (Two Bytes)
|
||||
eMsgCodeInitiateRecovery = 0x0F,
|
||||
eMsgCodeInitiatorDetectedError = 0x05,
|
||||
eMsgCodeLinkedCommandComplete = 0x0A,
|
||||
eMsgCodeLinkedCommandCompleteWithFlag = 0x0B,
|
||||
eMsgCodeMessageParityError = 0x09,
|
||||
eMsgCodeMessageReject = 0x07,
|
||||
eMsgCodeNoOperation = 0x08,
|
||||
eMsgCodeHeadOfQueueTag = 0x21,
|
||||
eMsgCodeOrderedQueueTag = 0x22,
|
||||
eMsgCodeSimpleQueueTag = 0x20,
|
||||
eMsgCodeReleaseRecovery = 0x10,
|
||||
eMsgCodeRestorePointers = 0x03,
|
||||
eMsgCodeSaveDataPointer = 0x02,
|
||||
eMsgCodeTerminateIOProcess = 0x11
|
||||
};
|
||||
|
||||
private:
|
||||
enum sasi_command : int {
|
||||
@ -123,7 +98,7 @@ public:
|
||||
DWORD offset; // Transfer offset
|
||||
DWORD length; // Transfer remaining length
|
||||
|
||||
// Logical unit
|
||||
// Logical units
|
||||
PrimaryDevice *unit[UnitMax];
|
||||
|
||||
// The current device
|
||||
@ -144,7 +119,7 @@ public:
|
||||
|
||||
// Connect
|
||||
void Connect(int id, BUS *sbus); // Controller connection
|
||||
Device* GetUnit(int no); // Get logical unit
|
||||
PrimaryDevice* GetUnit(int no); // Get logical unit
|
||||
void SetUnit(int no, PrimaryDevice *dev); // Logical unit setting
|
||||
bool HasUnit(); // Has a valid logical unit
|
||||
|
||||
@ -165,9 +140,9 @@ public:
|
||||
// Get LUN based on IDENTIFY message, with LUN from the CDB as fallback
|
||||
int GetEffectiveLun() const;
|
||||
|
||||
virtual void Error(ERROR_CODES::sense_key sense_key = ERROR_CODES::sense_key::NO_SENSE,
|
||||
ERROR_CODES::asc = ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
ERROR_CODES::status = ERROR_CODES::status::CHECK_CONDITION); // Common error handling
|
||||
virtual void Error(scsi_defs::sense_key sense_key = scsi_defs::sense_key::NO_SENSE,
|
||||
scsi_defs::asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status = scsi_defs::status::CHECK_CONDITION); // Common error handling
|
||||
|
||||
protected:
|
||||
// Phase processing
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "devices/scsi_daynaport.h"
|
||||
#include "devices/scsi_printer.h"
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// SCSI Device
|
||||
@ -264,7 +266,7 @@ void SCSIDEV::Execute()
|
||||
ctrl.execstart = SysTimer::GetTimerLow();
|
||||
|
||||
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
||||
if ((scsi_defs::scsi_command)ctrl.cmd[0] != scsi_defs::eCmdRequestSense) {
|
||||
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||
ctrl.status = 0;
|
||||
}
|
||||
|
||||
@ -272,11 +274,11 @@ void SCSIDEV::Execute()
|
||||
|
||||
int lun = GetEffectiveLun();
|
||||
if (!ctrl.unit[lun]) {
|
||||
if ((scsi_defs::scsi_command)ctrl.cmd[0] != scsi_defs::eCmdInquiry &&
|
||||
(scsi_defs::scsi_command)ctrl.cmd[0] != scsi_defs::eCmdRequestSense) {
|
||||
if ((scsi_command)ctrl.cmd[0] != eCmdInquiry &&
|
||||
(scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||
LOGDEBUG("Invalid LUN %d for ID %d", lun, GetSCSIID());
|
||||
|
||||
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
|
||||
Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
|
||||
return;
|
||||
}
|
||||
// Use LUN 0 for INQUIRY and REQUEST SENSE because LUN0 is assumed to be always available.
|
||||
@ -291,18 +293,18 @@ void SCSIDEV::Execute()
|
||||
ctrl.device = ctrl.unit[lun];
|
||||
|
||||
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
||||
if ((scsi_defs::scsi_command)ctrl.cmd[0] != scsi_defs::eCmdRequestSense) {
|
||||
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||
ctrl.device->SetStatusCode(0);
|
||||
}
|
||||
|
||||
if (!ctrl.device->Dispatch(this)) {
|
||||
LOGTRACE("ID %d LUN %d received unsupported command: $%02X", GetSCSIID(), lun, (BYTE)ctrl.cmd[0]);
|
||||
|
||||
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
|
||||
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
|
||||
if ((scsi_defs::scsi_command)ctrl.cmd[0] == scsi_defs::eCmdInquiry && !ctrl.unit[lun]) {
|
||||
if ((scsi_command)ctrl.cmd[0] == scsi_command::eCmdInquiry && !ctrl.unit[lun]) {
|
||||
lun = GetEffectiveLun();
|
||||
|
||||
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, ctrl.device->GetId());
|
||||
@ -355,7 +357,7 @@ void SCSIDEV::MsgOut()
|
||||
// Common Error Handling
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc, ERROR_CODES::status status)
|
||||
void SCSIDEV::Error(sense_key sense_key, asc asc, status status)
|
||||
{
|
||||
// Get bus information
|
||||
ctrl.bus->Aquire();
|
||||
@ -377,8 +379,10 @@ void SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc, ERRO
|
||||
}
|
||||
|
||||
int lun = GetEffectiveLun();
|
||||
if (!ctrl.unit[lun] || asc == ERROR_CODES::INVALID_LUN) {
|
||||
if (!ctrl.unit[lun] || asc == INVALID_LUN) {
|
||||
lun = 0;
|
||||
|
||||
assert(ctrl.unit[lun]);
|
||||
}
|
||||
|
||||
if (sense_key || asc) {
|
||||
@ -408,7 +412,9 @@ void SCSIDEV::Send()
|
||||
LOGTRACE("%s%s", __PRETTY_FUNCTION__, (" Sending handhake with offset " + to_string(ctrl.offset) + ", length "
|
||||
+ to_string(ctrl.length)).c_str());
|
||||
|
||||
int len = ctrl.bus->SendHandShake(&ctrl.buffer[ctrl.offset], ctrl.length, ctrl.unit[0]->GetSendDelay());
|
||||
// TODO The delay has to be taken from ctrl.unit[lun], but as there are no Daynaport drivers for
|
||||
// LUNs other than 0 this work-around works.
|
||||
int len = ctrl.bus->SendHandShake(&ctrl.buffer[ctrl.offset], ctrl.length, ctrl.unit[0] ? ctrl.unit[0]->GetSendDelay() : 0);
|
||||
|
||||
// If you cannot send all, move to status phase
|
||||
if (len != (int)ctrl.length) {
|
||||
@ -896,7 +902,7 @@ bool SCSIDEV::XferOut(bool cont)
|
||||
scsi.is_byte_transfer = false;
|
||||
|
||||
PrimaryDevice *device = dynamic_cast<PrimaryDevice *>(ctrl.unit[GetEffectiveLun()]);
|
||||
if (device && ctrl.cmd[0] == scsi_defs::eCmdWrite6) {
|
||||
if (device && ctrl.cmd[0] == scsi_command::eCmdWrite6) {
|
||||
return device->WriteBytes(ctrl.buffer, scsi.bytes_to_transfer);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "controllers/sasidev_ctrl.h"
|
||||
#include <map>
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
@ -67,9 +66,9 @@ public:
|
||||
bool IsSCSI() const override { return true; }
|
||||
|
||||
// Common error handling
|
||||
void Error(ERROR_CODES::sense_key sense_key = ERROR_CODES::sense_key::NO_SENSE,
|
||||
ERROR_CODES::asc asc = ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
ERROR_CODES::status status = ERROR_CODES::status::CHECK_CONDITION) override;
|
||||
void Error(scsi_defs::sense_key sense_key = scsi_defs::sense_key::NO_SENSE,
|
||||
scsi_defs::asc asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status status = scsi_defs::status::CHECK_CONDITION) override;
|
||||
|
||||
void ScheduleShutDown(rascsi_shutdown_mode shutdown_mode) { this->shutdown_mode = shutdown_mode; }
|
||||
|
||||
|
@ -96,9 +96,9 @@ static bool is_interface_up(const string& interface) {
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CTapDriver::Init(const map<string, string>& const_params)
|
||||
bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
{
|
||||
map<string, string> params = const_params;
|
||||
unordered_map<string, string> params = const_params;
|
||||
if (params.count("interfaces")) {
|
||||
LOGWARN("You are using the deprecated 'interfaces' parameter. "
|
||||
"Provide the interface list and the IP address/netmask with the 'interface' and 'inet' parameters");
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
#include "filepath.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
@ -40,7 +40,7 @@ private:
|
||||
CTapDriver();
|
||||
~CTapDriver() {}
|
||||
|
||||
bool Init(const map<string, string>&);
|
||||
bool Init(const unordered_map<string, string>&);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "exceptions.h"
|
||||
#include "device.h"
|
||||
|
||||
set<Device *> Device::devices;
|
||||
unordered_set<Device *> Device::devices;
|
||||
|
||||
Device::Device(const string& type)
|
||||
{
|
||||
@ -121,7 +121,7 @@ const string Device::GetParam(const string& key)
|
||||
return params.find(key) != params.end() ? params[key] : "";
|
||||
}
|
||||
|
||||
void Device::SetParams(const map<string, string>& params)
|
||||
void Device::SetParams(const unordered_map<string, string>& params)
|
||||
{
|
||||
this->params = GetDefaultParams();
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
@ -97,17 +97,17 @@ private:
|
||||
string revision;
|
||||
|
||||
// The parameters the device was created with
|
||||
map<string, string> params;
|
||||
unordered_map<string, string> params;
|
||||
|
||||
// The default parameters
|
||||
map<string, string> default_params;
|
||||
unordered_map<string, string> default_params;
|
||||
|
||||
// Sense Key, ASC and ASCQ
|
||||
int status_code;
|
||||
|
||||
protected:
|
||||
|
||||
static set<Device *> devices;
|
||||
static unordered_set<Device *> devices;
|
||||
|
||||
public:
|
||||
|
||||
@ -115,7 +115,7 @@ public:
|
||||
virtual ~Device();
|
||||
|
||||
// Override for device specific initializations, to be called after all device properties have been set
|
||||
virtual bool Init(const map<string, string>&) { return true; };
|
||||
virtual bool Init(const unordered_map<string, string>&) { return true; };
|
||||
|
||||
virtual bool Dispatch(SCSIDEV *) = 0;
|
||||
|
||||
@ -169,11 +169,11 @@ public:
|
||||
bool SupportsParams() const { return supports_params; }
|
||||
bool SupportsFile() const { return !supports_params; }
|
||||
void SupportsParams(bool supports_paams) { this->supports_params = supports_paams; }
|
||||
const map<string, string> GetParams() const { return params; }
|
||||
const unordered_map<string, string> GetParams() const { return params; }
|
||||
const string GetParam(const string&);
|
||||
void SetParams(const map<string, string>&);
|
||||
const map<string, string> GetDefaultParams() const { return default_params; }
|
||||
void SetDefaultParams(const map<string, string>& default_params) { this->default_params = default_params; }
|
||||
void SetParams(const unordered_map<string, string>&);
|
||||
const unordered_map<string, string> GetDefaultParams() const { return default_params; }
|
||||
void SetDefaultParams(const unordered_map<string, string>& default_params) { this->default_params = default_params; }
|
||||
|
||||
int GetStatusCode() const { return status_code; }
|
||||
void SetStatusCode(int);
|
||||
|
@ -18,8 +18,6 @@
|
||||
#include "exceptions.h"
|
||||
#include "device_factory.h"
|
||||
#include <ifaddrs.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include "host_services.h"
|
||||
|
||||
using namespace std;
|
||||
@ -86,12 +84,13 @@ string DeviceFactory::GetExtension(const string& filename) const
|
||||
return ext;
|
||||
}
|
||||
|
||||
PbDeviceType DeviceFactory::GetTypeForFile(const string& filename)
|
||||
PbDeviceType DeviceFactory::GetTypeForFile(const string& filename) const
|
||||
{
|
||||
string ext = GetExtension(filename);
|
||||
|
||||
if (extension_mapping.find(ext) != extension_mapping.end()) {
|
||||
return extension_mapping[ext];
|
||||
const auto& it = extension_mapping.find(ext);
|
||||
if (it != extension_mapping.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else if (filename == "bridge") {
|
||||
return SCBR;
|
||||
@ -216,19 +215,19 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
|
||||
return device;
|
||||
}
|
||||
|
||||
const set<uint32_t>& DeviceFactory::GetSectorSizes(const string& type)
|
||||
const unordered_set<uint32_t>& DeviceFactory::GetSectorSizes(const string& type)
|
||||
{
|
||||
PbDeviceType t = UNDEFINED;
|
||||
PbDeviceType_Parse(type, &t);
|
||||
return sector_sizes[t];
|
||||
}
|
||||
|
||||
const set<uint64_t> DeviceFactory::GetCapacities(PbDeviceType type)
|
||||
const unordered_set<uint64_t> DeviceFactory::GetCapacities(PbDeviceType type) const
|
||||
{
|
||||
set<uint64_t> keys;
|
||||
unordered_set<uint64_t> keys;
|
||||
|
||||
for (const auto& geometry : geometries[type]) {
|
||||
keys.insert(geometry.first);
|
||||
for (auto it = geometries.begin(); it != geometries.end(); ++it) {
|
||||
keys.insert(it->first);
|
||||
}
|
||||
|
||||
return keys;
|
||||
|
@ -11,9 +11,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "rascsi_interface.pb.h"
|
||||
|
||||
@ -28,31 +28,31 @@ class DeviceFactory
|
||||
{
|
||||
private:
|
||||
DeviceFactory();
|
||||
~DeviceFactory() {};
|
||||
~DeviceFactory() {}
|
||||
|
||||
public:
|
||||
|
||||
static DeviceFactory& instance();
|
||||
|
||||
Device *CreateDevice(PbDeviceType, const string&);
|
||||
PbDeviceType GetTypeForFile(const string&);
|
||||
const set<uint32_t>& GetSectorSizes(PbDeviceType type) { return sector_sizes[type]; }
|
||||
const set<uint32_t>& GetSectorSizes(const string&);
|
||||
const set<uint64_t> GetCapacities(PbDeviceType);
|
||||
const map<string, string>& GetDefaultParams(PbDeviceType type) { return default_params[type]; }
|
||||
PbDeviceType GetTypeForFile(const string&) const;
|
||||
const unordered_set<uint32_t>& GetSectorSizes(PbDeviceType type) { return sector_sizes[type]; }
|
||||
const unordered_set<uint32_t>& GetSectorSizes(const string&);
|
||||
const unordered_set<uint64_t> GetCapacities(PbDeviceType) const;
|
||||
const unordered_map<string, string>& GetDefaultParams(PbDeviceType type) { return default_params[type]; }
|
||||
const list<string> GetNetworkInterfaces() const;
|
||||
const map<string, PbDeviceType> GetExtensionMapping() const { return extension_mapping; }
|
||||
const unordered_map<string, PbDeviceType> GetExtensionMapping() const { return extension_mapping; }
|
||||
|
||||
private:
|
||||
|
||||
map<PbDeviceType, set<uint32_t>> sector_sizes;
|
||||
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes;
|
||||
|
||||
// Optional mapping of drive capacities to drive geometries
|
||||
map<PbDeviceType, map<uint64_t, Geometry>> geometries;
|
||||
unordered_map<PbDeviceType, unordered_map<uint64_t, Geometry>> geometries;
|
||||
|
||||
map<PbDeviceType, map<string, string>> default_params;
|
||||
unordered_map<PbDeviceType, unordered_map<string, string>> default_params;
|
||||
|
||||
map<string, PbDeviceType> extension_mapping;
|
||||
unordered_map<string, PbDeviceType> extension_mapping;
|
||||
|
||||
string GetExtension(const string&) const;
|
||||
};
|
||||
|
@ -85,7 +85,7 @@ bool Disk::Dispatch(SCSIDEV *controller)
|
||||
|
||||
disk.is_medium_changed = false;
|
||||
|
||||
controller->Error(ERROR_CODES::sense_key::UNIT_ATTENTION, ERROR_CODES::asc::NOT_READY_TO_READY_CHANGE);
|
||||
controller->Error(sense_key::UNIT_ATTENTION, asc::NOT_READY_TO_READY_CHANGE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -207,11 +207,11 @@ void Disk::ReadWriteLong10(SASIDEV *controller)
|
||||
{
|
||||
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
|
||||
if (ctrl->cmd[7] || ctrl->cmd[8]) {
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckBlockAddress(controller, RW10)) {
|
||||
if (ValidateBlockAddress(controller, RW10)) {
|
||||
controller->Status();
|
||||
}
|
||||
}
|
||||
@ -225,11 +225,11 @@ void Disk::ReadWriteLong16(SASIDEV *controller)
|
||||
{
|
||||
// Transfer lengths other than 0 are not supported, which is compliant with the SCSI standard
|
||||
if (ctrl->cmd[12] || ctrl->cmd[13]) {
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckBlockAddress(controller, RW16)) {
|
||||
if (ValidateBlockAddress(controller, RW16)) {
|
||||
controller->Status();
|
||||
}
|
||||
}
|
||||
@ -243,11 +243,11 @@ void Disk::Write(SASIDEV *controller, uint64_t record)
|
||||
{
|
||||
ctrl->length = WriteCheck(record);
|
||||
if (ctrl->length == 0) {
|
||||
controller->Error(ERROR_CODES::sense_key::NOT_READY, ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION);
|
||||
controller->Error(sense_key::NOT_READY, asc::NO_ADDITIONAL_SENSE_INFORMATION);
|
||||
return;
|
||||
}
|
||||
else if (ctrl->length < 0) {
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::WRITE_PROTECTED);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::WRITE_PROTECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ void Disk::StartStopUnit(SASIDEV *controller)
|
||||
void Disk::SendDiagnostic(SASIDEV *controller)
|
||||
{
|
||||
if (!SendDiag(ctrl->cmd)) {
|
||||
controller->Error();
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -380,12 +380,15 @@ void Disk::SynchronizeCache16(SASIDEV *controller)
|
||||
|
||||
void Disk::ReadDefectData10(SASIDEV *controller)
|
||||
{
|
||||
ctrl->length = ReadDefectData10(ctrl->cmd, ctrl->buffer, ctrl->bufsize);
|
||||
if (ctrl->length <= 4) {
|
||||
controller->Error();
|
||||
return;
|
||||
int allocation_length = (ctrl->cmd[7] << 8) | ctrl->cmd[8];
|
||||
if (allocation_length > 4) {
|
||||
allocation_length = 4;
|
||||
}
|
||||
|
||||
// The defect list is empty
|
||||
memset(ctrl->buffer, 0, allocation_length);
|
||||
ctrl->length = allocation_length;
|
||||
|
||||
controller->DataIn();
|
||||
}
|
||||
|
||||
@ -675,34 +678,6 @@ void Disk::AddVendorPage(map<int, vector<BYTE>>&, int, bool) const
|
||||
// Nothing to add by default
|
||||
}
|
||||
|
||||
int Disk::ReadDefectData10(const DWORD *cdb, BYTE *buf, int max_length)
|
||||
{
|
||||
// Get length, clear buffer
|
||||
int length = (cdb[7] << 8) | cdb[8];
|
||||
if (length > max_length) {
|
||||
length = max_length;
|
||||
}
|
||||
memset(buf, 0, length);
|
||||
|
||||
// P/G/FORMAT
|
||||
buf[1] = (cdb[1] & 0x18) | 5;
|
||||
buf[3] = 8;
|
||||
|
||||
buf[4] = 0xff;
|
||||
buf[5] = 0xff;
|
||||
buf[6] = 0xff;
|
||||
buf[7] = 0xff;
|
||||
|
||||
buf[8] = 0xff;
|
||||
buf[9] = 0xff;
|
||||
buf[10] = 0xff;
|
||||
buf[11] = 0xff;
|
||||
|
||||
// no list
|
||||
SetStatusCode(STATUS_NODEFECT);
|
||||
return 4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FORMAT UNIT
|
||||
@ -868,17 +843,15 @@ bool Disk::StartStop(const DWORD *cdb)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Disk::SendDiag(const DWORD *cdb)
|
||||
bool Disk::SendDiag(const DWORD *cdb) const
|
||||
{
|
||||
// Do not support PF bit
|
||||
if (cdb[1] & 0x10) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not support parameter list
|
||||
if ((cdb[3] != 0) || (cdb[4] != 0)) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -888,7 +861,7 @@ bool Disk::SendDiag(const DWORD *cdb)
|
||||
void Disk::ReadCapacity10(SASIDEV *controller)
|
||||
{
|
||||
if (!CheckReady() || disk.blocks <= 0) {
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -917,7 +890,7 @@ void Disk::ReadCapacity10(SASIDEV *controller)
|
||||
void Disk::ReadCapacity16(SASIDEV *controller)
|
||||
{
|
||||
if (!CheckReady() || disk.blocks <= 0) {
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::MEDIUM_NOT_PRESENT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -965,7 +938,7 @@ void Disk::ReadCapacity16_ReadLong16(SASIDEV *controller)
|
||||
break;
|
||||
|
||||
default:
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -996,7 +969,7 @@ void Disk::Release(SASIDEV *controller)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool Disk::CheckBlockAddress(SASIDEV *controller, access_mode mode)
|
||||
bool Disk::ValidateBlockAddress(SASIDEV *controller, access_mode mode)
|
||||
{
|
||||
uint64_t block = ctrl->cmd[2];
|
||||
block <<= 8;
|
||||
@ -1021,7 +994,7 @@ bool Disk::CheckBlockAddress(SASIDEV *controller, access_mode mode)
|
||||
if (block > capacity) {
|
||||
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " blocks exceeded: Trying to access block "
|
||||
+ to_string(block)).c_str());
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1078,14 +1051,14 @@ bool Disk::GetStartAndCount(SASIDEV *controller, uint64_t& start, uint32_t& coun
|
||||
}
|
||||
}
|
||||
|
||||
LOGDEBUG("%s READ/WRITE/VERIFY command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, count);
|
||||
LOGTRACE("%s READ/WRITE/VERIFY command record=$%08X blocks=%d", __PRETTY_FUNCTION__, (uint32_t)start, count);
|
||||
|
||||
// Check capacity
|
||||
uint64_t capacity = GetBlockCount();
|
||||
if (start > capacity || start + count > capacity) {
|
||||
LOGTRACE("%s", ("Capacity of " + to_string(capacity) + " blocks exceeded: Trying to access block "
|
||||
+ to_string(start) + ", block count " + to_string(ctrl->blocks)).c_str());
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::LBA_OUT_OF_RANGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1106,7 +1079,7 @@ uint32_t Disk::GetSectorSizeInBytes() const
|
||||
|
||||
void Disk::SetSectorSizeInBytes(uint32_t size, bool sasi)
|
||||
{
|
||||
set<uint32_t> sector_sizes = DeviceFactory::instance().GetSectorSizes(GetType());
|
||||
unordered_set<uint32_t> sector_sizes = DeviceFactory::instance().GetSectorSizes(GetType());
|
||||
if (!sector_sizes.empty() && sector_sizes.find(size) == sector_sizes.end()) {
|
||||
throw io_exception("Invalid block size of " + to_string(size) + " bytes");
|
||||
}
|
||||
@ -1153,7 +1126,7 @@ bool Disk::IsSectorSizeConfigurable() const
|
||||
return !sector_sizes.empty();
|
||||
}
|
||||
|
||||
void Disk::SetSectorSizes(const set<uint32_t>& sector_sizes)
|
||||
void Disk::SetSectorSizes(const unordered_set<uint32_t>& sector_sizes)
|
||||
{
|
||||
this->sector_sizes = sector_sizes;
|
||||
}
|
||||
@ -1167,7 +1140,7 @@ bool Disk::SetConfiguredSectorSize(uint32_t configured_sector_size)
|
||||
{
|
||||
DeviceFactory& device_factory = DeviceFactory::instance();
|
||||
|
||||
set<uint32_t> sector_sizes = device_factory.GetSectorSizes(GetType());
|
||||
unordered_set<uint32_t> sector_sizes = device_factory.GetSectorSizes(GetType());
|
||||
if (sector_sizes.find(configured_sector_size) == sector_sizes.end()) {
|
||||
return false;
|
||||
}
|
||||
@ -1177,7 +1150,7 @@ bool Disk::SetConfiguredSectorSize(uint32_t configured_sector_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Disk::SetGeometries(const map<uint64_t, Geometry>& geometries)
|
||||
void Disk::SetGeometries(const unordered_map<uint64_t, Geometry>& geometries)
|
||||
{
|
||||
this->geometries = geometries;
|
||||
}
|
||||
|
@ -28,8 +28,8 @@
|
||||
#include "interfaces/scsi_block_commands.h"
|
||||
#include "mode_page_device.h"
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -39,11 +39,11 @@ private:
|
||||
enum access_mode { RW6, RW10, RW16 };
|
||||
|
||||
// The supported configurable block sizes, empty if not configurable
|
||||
set<uint32_t> sector_sizes;
|
||||
unordered_set<uint32_t> sector_sizes;
|
||||
uint32_t configured_sector_size;
|
||||
|
||||
// The mapping of supported capacities to block sizes and block counts, empty if there is no capacity restriction
|
||||
map<uint64_t, Geometry> geometries;
|
||||
unordered_map<uint64_t, Geometry> geometries;
|
||||
|
||||
typedef struct {
|
||||
uint32_t size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
|
||||
@ -108,33 +108,30 @@ public:
|
||||
void Seek6(SASIDEV *);
|
||||
|
||||
// Command helpers
|
||||
virtual int Inquiry(const DWORD *cdb, BYTE *buf) = 0; // INQUIRY command
|
||||
virtual int WriteCheck(DWORD block); // WRITE check
|
||||
virtual bool Write(const DWORD *cdb, const BYTE *buf, DWORD block); // WRITE command
|
||||
bool StartStop(const DWORD *cdb); // START STOP UNIT command
|
||||
bool SendDiag(const DWORD *cdb); // SEND DIAGNOSTIC command
|
||||
virtual int WriteCheck(DWORD block);
|
||||
virtual bool Write(const DWORD *cdb, const BYTE *buf, DWORD block);
|
||||
bool StartStop(const DWORD *cdb);
|
||||
bool SendDiag(const DWORD *cdb) const;
|
||||
|
||||
virtual int Read(const DWORD *cdb, BYTE *buf, uint64_t block);
|
||||
int ReadDefectData10(const DWORD *, BYTE *, int);
|
||||
|
||||
uint32_t GetSectorSizeInBytes() const;
|
||||
void SetSectorSizeInBytes(uint32_t, bool);
|
||||
uint32_t GetSectorSizeShiftCount() const;
|
||||
void SetSectorSizeShiftCount(uint32_t);
|
||||
bool IsSectorSizeConfigurable() const;
|
||||
set<uint32_t> GetSectorSizes() const;
|
||||
void SetSectorSizes(const set<uint32_t>&);
|
||||
unordered_set<uint32_t> GetSectorSizes() const;
|
||||
void SetSectorSizes(const unordered_set<uint32_t>&);
|
||||
uint32_t GetConfiguredSectorSize() const;
|
||||
bool SetConfiguredSectorSize(uint32_t);
|
||||
void SetGeometries(const map<uint64_t, Geometry>&);
|
||||
void SetGeometries(const unordered_map<uint64_t, Geometry>&);
|
||||
bool SetGeometryForCapacity(uint64_t);
|
||||
uint64_t GetBlockCount() const;
|
||||
void SetBlockCount(uint32_t);
|
||||
bool CheckBlockAddress(SASIDEV *, access_mode);
|
||||
bool GetStartAndCount(SASIDEV *, uint64_t&, uint32_t&, access_mode);
|
||||
void FlushCache();
|
||||
|
||||
protected:
|
||||
|
||||
int ModeSense6(const DWORD *cdb, BYTE *buf);
|
||||
int ModeSense10(const DWORD *cdb, BYTE *buf, int);
|
||||
virtual void SetDeviceParameters(BYTE *);
|
||||
@ -149,6 +146,7 @@ protected:
|
||||
disk_t disk;
|
||||
|
||||
private:
|
||||
|
||||
void Read(SASIDEV *, uint64_t);
|
||||
void Write(SASIDEV *, uint64_t);
|
||||
void Verify(SASIDEV *, uint64_t);
|
||||
@ -156,4 +154,7 @@ private:
|
||||
void ReadWriteLong16(SASIDEV *);
|
||||
void ReadCapacity16_ReadLong16(SASIDEV *);
|
||||
bool Format(const DWORD *cdb);
|
||||
|
||||
bool ValidateBlockAddress(SASIDEV *, access_mode);
|
||||
bool GetStartAndCount(SASIDEV *, uint64_t&, uint32_t&, access_mode);
|
||||
};
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "scsi.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
class SASIDEV;
|
||||
class SCSIDEV;
|
||||
@ -40,7 +40,7 @@ public:
|
||||
|
||||
_command_t(const char* _name, void (T::*_execute)(U *)) : name(_name), execute(_execute) { };
|
||||
} command_t;
|
||||
map<scsi_command, command_t*> commands;
|
||||
unordered_map<scsi_command, command_t*> commands;
|
||||
|
||||
void AddCommand(scsi_command opcode, const char* name, void (T::*execute)(U *))
|
||||
{
|
||||
|
@ -7,13 +7,11 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "file_support.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
map<string, id_set> FileSupport::reserved_files;
|
||||
unordered_map<string, id_set> FileSupport::reserved_files;
|
||||
|
||||
void FileSupport::ReserveFile(const Filepath& path, int id, int lun)
|
||||
{
|
||||
@ -27,8 +25,9 @@ void FileSupport::UnreserveFile()
|
||||
|
||||
bool FileSupport::GetIdsForReservedFile(const Filepath& path, int& id, int& unit)
|
||||
{
|
||||
if (reserved_files.find(path.GetPath()) != reserved_files.end()) {
|
||||
const id_set ids = reserved_files[path.GetPath()];
|
||||
const auto& it = reserved_files.find(path.GetPath());
|
||||
if (it != reserved_files.end()) {
|
||||
const id_set ids = it->second;
|
||||
id = ids.first;
|
||||
unit = ids.second;
|
||||
return true;
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "filepath.h"
|
||||
|
||||
@ -25,20 +25,21 @@ private:
|
||||
Filepath diskpath;
|
||||
|
||||
// The list of image files in use and the IDs and LUNs using these files
|
||||
static map<string, id_set> reserved_files;
|
||||
static unordered_map<string, id_set> reserved_files;
|
||||
|
||||
public:
|
||||
|
||||
FileSupport() {};
|
||||
virtual ~FileSupport() {};
|
||||
FileSupport() {}
|
||||
virtual ~FileSupport() {}
|
||||
|
||||
void GetPath(Filepath& path) const { path = diskpath; }
|
||||
void SetPath(const Filepath& path) { diskpath = path; }
|
||||
static const map<string, id_set> GetReservedFiles(){ return reserved_files; }
|
||||
static void SetReservedFiles(const map<string, id_set>& files_in_use) { FileSupport::reserved_files = files_in_use; }
|
||||
void ReserveFile(const Filepath&, int, int);
|
||||
void UnreserveFile();
|
||||
|
||||
static const unordered_map<string, id_set> GetReservedFiles() { return reserved_files; }
|
||||
static void SetReservedFiles(const unordered_map<string, id_set>& files_in_use)
|
||||
{ FileSupport::reserved_files = files_in_use; }
|
||||
static bool GetIdsForReservedFile(const Filepath&, int&, int&);
|
||||
static void UnreserveAll();
|
||||
|
||||
|
@ -57,10 +57,10 @@ void HostServices::TestUnitReady(SCSIDEV *controller)
|
||||
controller->Status();
|
||||
}
|
||||
|
||||
int HostServices::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> HostServices::Inquiry() const
|
||||
{
|
||||
// Processor device, SPC-5, not removable
|
||||
return PrimaryDevice::Inquiry(3, 7, false, cdb, buf);
|
||||
return PrimaryDevice::Inquiry(3, 7, false);
|
||||
}
|
||||
|
||||
void HostServices::StartStopUnit(SCSIDEV *controller)
|
||||
@ -96,7 +96,7 @@ void HostServices::StartStopUnit(SCSIDEV *controller)
|
||||
}
|
||||
}
|
||||
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf)
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
|
||||
virtual bool Dispatch(SCSIDEV *) override;
|
||||
|
||||
int Inquiry(const DWORD *, BYTE *) override;
|
||||
vector<BYTE> Inquiry() const override;
|
||||
void TestUnitReady(SCSIDEV *);
|
||||
void StartStopUnit(SCSIDEV *);
|
||||
|
||||
|
@ -45,12 +45,22 @@ void PrimaryDevice::TestUnitReady(SASIDEV *controller)
|
||||
|
||||
void PrimaryDevice::Inquiry(SASIDEV *controller)
|
||||
{
|
||||
ctrl->length = Inquiry(ctrl->cmd, ctrl->buffer);
|
||||
if (ctrl->length <= 0) {
|
||||
controller->Error();
|
||||
// EVPD and page code check
|
||||
if ((ctrl->cmd[1] & 0x01) || ctrl->cmd[2]) {
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
vector<BYTE> buf = Inquiry();
|
||||
|
||||
size_t allocation_length = ctrl->cmd[4] + (ctrl->cmd[3] << 8);
|
||||
if (allocation_length > buf.size()) {
|
||||
allocation_length = buf.size();
|
||||
}
|
||||
|
||||
memcpy(ctrl->buffer, buf.data(), allocation_length);
|
||||
ctrl->length = allocation_length;
|
||||
|
||||
int lun = controller->GetEffectiveLun();
|
||||
|
||||
// Report if the device does not support the requested LUN
|
||||
@ -66,27 +76,25 @@ void PrimaryDevice::Inquiry(SASIDEV *controller)
|
||||
|
||||
void PrimaryDevice::ReportLuns(SASIDEV *controller)
|
||||
{
|
||||
BYTE *buf = ctrl->buffer;
|
||||
|
||||
int allocation_length = (ctrl->cmd[6] << 24) + (ctrl->cmd[7] << 16) + (ctrl->cmd[8] << 8) + ctrl->cmd[9];
|
||||
|
||||
BYTE *buf = ctrl->buffer;
|
||||
memset(buf, 0, allocation_length);
|
||||
|
||||
// Count number of available LUNs for the current device
|
||||
int luns;
|
||||
for (luns = 0; luns < controller->GetCtrl()->device->GetSupportedLuns(); luns++) {
|
||||
if (!controller->GetCtrl()->unit[luns]) {
|
||||
break;
|
||||
int size = 0;
|
||||
for (int lun = 0; lun < controller->GetCtrl()->device->GetSupportedLuns(); lun++) {
|
||||
if (controller->GetCtrl()->unit[lun]) {
|
||||
size += 8;
|
||||
buf[size + 7] = lun;
|
||||
}
|
||||
}
|
||||
|
||||
// LUN list length, 8 bytes per LUN
|
||||
// SCSI standard: The contents of the LUN LIST LENGTH field are not altered based on the allocation length
|
||||
buf[0] = (luns * 8) >> 24;
|
||||
buf[1] = (luns * 8) >> 16;
|
||||
buf[2] = (luns * 8) >> 8;
|
||||
buf[3] = luns * 8;
|
||||
buf[2] = size >> 8;
|
||||
buf[3] = size;
|
||||
|
||||
ctrl->length = allocation_length < 8 + luns * 8 ? allocation_length : 8 + luns * 8;
|
||||
size += 8;
|
||||
|
||||
ctrl->length = allocation_length < size ? allocation_length : size;
|
||||
|
||||
controller->DataIn();
|
||||
}
|
||||
@ -101,12 +109,21 @@ void PrimaryDevice::RequestSense(SASIDEV *controller)
|
||||
// LUN 0 can be assumed to be present (required to call RequestSense() below)
|
||||
lun = 0;
|
||||
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
|
||||
ctrl->status = 0x00;
|
||||
return;
|
||||
}
|
||||
|
||||
ctrl->length = ((PrimaryDevice *)ctrl->unit[lun])->RequestSense(ctrl->cmd, ctrl->buffer);
|
||||
assert(ctrl->length > 0);
|
||||
size_t allocation_length = ctrl->cmd[4];
|
||||
|
||||
vector<BYTE> buf = ((PrimaryDevice *)ctrl->unit[lun])->RequestSense(allocation_length);
|
||||
|
||||
if (allocation_length > buf.size()) {
|
||||
allocation_length = buf.size();
|
||||
}
|
||||
|
||||
memcpy(ctrl->buffer, buf.data(), allocation_length);
|
||||
ctrl->length = allocation_length;
|
||||
|
||||
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
|
||||
|
||||
@ -144,71 +161,49 @@ bool PrimaryDevice::CheckReady()
|
||||
return true;
|
||||
}
|
||||
|
||||
int PrimaryDevice::Inquiry(int type, int scsi_level, bool is_removable, const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> PrimaryDevice::Inquiry(int type, int scsi_level, bool is_removable) const
|
||||
{
|
||||
// EVPD and page code check
|
||||
if ((cdb[1] & 0x01) || cdb[2]) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return 0;
|
||||
}
|
||||
vector<BYTE> buf = vector<BYTE>(0x1F + 5);
|
||||
|
||||
int allocation_length = cdb[4] + (cdb[3] << 8);
|
||||
if (allocation_length > 4) {
|
||||
if (allocation_length > 44) {
|
||||
allocation_length = 44;
|
||||
}
|
||||
// Basic data
|
||||
// buf[0] ... SCSI Device type
|
||||
// buf[1] ... Bit 7: Removable/not removable
|
||||
// buf[2] ... SCSI-2 compliant command system
|
||||
// buf[3] ... SCSI-2 compliant Inquiry response
|
||||
// buf[4] ... Inquiry additional data
|
||||
buf[0] = type;
|
||||
buf[1] = is_removable ? 0x80 : 0x00;
|
||||
buf[2] = scsi_level;
|
||||
// Response data format is SCSI-2 for devices supporting SCSI-2 or newer, otherwise it is SCSI-1-CCS
|
||||
buf[3] = scsi_level >= 2 ? 2 : 1;
|
||||
buf[4] = 0x1F;
|
||||
|
||||
// Basic data
|
||||
// buf[0] ... SCSI Device type
|
||||
// buf[1] ... Bit 7: Removable/not removable
|
||||
// buf[2] ... SCSI-2 compliant command system
|
||||
// buf[3] ... SCSI-2 compliant Inquiry response
|
||||
// buf[4] ... Inquiry additional data
|
||||
memset(buf, 0, allocation_length);
|
||||
buf[0] = type;
|
||||
buf[1] = is_removable ? 0x80 : 0x00;
|
||||
buf[2] = scsi_level;
|
||||
// Response data format is SCSI-2 for devices supporting SCSI-2 or newer, otherwise it is SCSI-1-CCS
|
||||
buf[3] = scsi_level >= 2 ? 2 : 0;
|
||||
buf[4] = 0x1F;
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
}
|
||||
|
||||
return allocation_length;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int PrimaryDevice::RequestSense(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> PrimaryDevice::RequestSense(int)
|
||||
{
|
||||
// Return not ready only if there are no errors
|
||||
if (GetStatusCode() == STATUS_NOERROR && !IsReady()) {
|
||||
SetStatusCode(STATUS_NOTREADY);
|
||||
}
|
||||
|
||||
// Size determination (according to allocation length)
|
||||
int size = (int)cdb[4];
|
||||
assert(size >= 0 && size < 0x100);
|
||||
|
||||
// For SCSI-1, transfer 4 bytes when the size is 0
|
||||
if (size == 0) {
|
||||
size = 4;
|
||||
}
|
||||
|
||||
// Clear the buffer
|
||||
memset(buf, 0, size);
|
||||
|
||||
// Set 18 bytes including extended sense data
|
||||
|
||||
vector<BYTE> buf(18);
|
||||
|
||||
// Current error
|
||||
buf[0] = 0x70;
|
||||
|
||||
buf[2] = (BYTE)(GetStatusCode() >> 16);
|
||||
buf[2] = GetStatusCode() >> 16;
|
||||
buf[7] = 10;
|
||||
buf[12] = (BYTE)(GetStatusCode() >> 8);
|
||||
buf[13] = (BYTE)GetStatusCode();
|
||||
buf[12] = GetStatusCode() >> 8;
|
||||
buf[13] = GetStatusCode();
|
||||
|
||||
return size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool PrimaryDevice::WriteBytes(BYTE *buf, uint32_t length)
|
||||
|
@ -34,14 +34,14 @@ public:
|
||||
void SetCtrl(SASIDEV::ctrl_t *ctrl) { this->ctrl = ctrl; }
|
||||
|
||||
bool CheckReady();
|
||||
virtual int Inquiry(const DWORD *, BYTE *) = 0;
|
||||
virtual int RequestSense(const DWORD *, BYTE *);
|
||||
virtual vector<BYTE> Inquiry() const = 0;
|
||||
virtual vector<BYTE> RequestSense(int);
|
||||
virtual bool WriteBytes(BYTE *, uint32_t);
|
||||
virtual int GetSendDelay() { return BUS::SEND_NO_DELAY; }
|
||||
virtual int GetSendDelay() const { return BUS::SEND_NO_DELAY; }
|
||||
|
||||
protected:
|
||||
|
||||
int Inquiry(int, int, bool, const DWORD *, BYTE *);
|
||||
vector<BYTE> Inquiry(int, int, bool) const;
|
||||
|
||||
SASIDEV::ctrl_t *ctrl;
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "exceptions.h"
|
||||
#include "../config.h"
|
||||
|
||||
SASIHD::SASIHD(const set<uint32_t>& sector_sizes) : Disk("SAHD")
|
||||
SASIHD::SASIHD(const unordered_set<uint32_t>& sector_sizes) : Disk("SAHD")
|
||||
{
|
||||
SetSectorSizes(sector_sizes);
|
||||
}
|
||||
@ -81,27 +81,20 @@ void SASIHD::Open(const Filepath& path)
|
||||
FileSupport::SetPath(path);
|
||||
}
|
||||
|
||||
int SASIHD::Inquiry(const DWORD* /*cdb*/, BYTE* /*buf*/)
|
||||
vector<BYTE> SASIHD::Inquiry() const
|
||||
{
|
||||
SetStatusCode(STATUS_INVALIDCMD);
|
||||
return 0;
|
||||
assert(false);
|
||||
return vector<BYTE>(0);
|
||||
}
|
||||
|
||||
int SASIHD::RequestSense(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SASIHD::RequestSense(int allocation_length)
|
||||
{
|
||||
// Size decision
|
||||
int size = (int)cdb[4];
|
||||
assert(size >= 0 && size < 0x100);
|
||||
|
||||
// Transfer 4 bytes when size 0 (Shugart Associates System Interface specification)
|
||||
if (size == 0) {
|
||||
size = 4;
|
||||
}
|
||||
// Transfer 4 bytes when size is 0 (Shugart Associates System Interface specification)
|
||||
vector<BYTE> buf(allocation_length ? allocation_length : 4);
|
||||
|
||||
// SASI fixed to non-extended format
|
||||
memset(buf, 0, size);
|
||||
buf[0] = (BYTE)(GetStatusCode() >> 16);
|
||||
buf[1] = (BYTE)(GetLun() << 5);
|
||||
|
||||
return size;
|
||||
return buf;
|
||||
}
|
||||
|
@ -27,13 +27,12 @@
|
||||
class SASIHD : public Disk, public FileSupport
|
||||
{
|
||||
public:
|
||||
SASIHD(const set<uint32_t>&);
|
||||
SASIHD(const unordered_set<uint32_t>&);
|
||||
~SASIHD() {}
|
||||
|
||||
void Reset();
|
||||
void Open(const Filepath& path) override;
|
||||
void Open(const Filepath&) override;
|
||||
|
||||
// Commands
|
||||
int RequestSense(const DWORD *cdb, BYTE *buf) override;
|
||||
int Inquiry(const DWORD *cdb, BYTE *buf) override;
|
||||
vector<BYTE> RequestSense(int) override;
|
||||
vector<BYTE> Inquiry() const override;
|
||||
};
|
||||
|
@ -64,7 +64,7 @@ bool SCSIDaynaPort::Dispatch(SCSIDEV *controller)
|
||||
return dispatcher.Dispatch(this, controller) ? true : super::Dispatch(controller);
|
||||
}
|
||||
|
||||
bool SCSIDaynaPort::Init(const map<string, string>& params)
|
||||
bool SCSIDaynaPort::Init(const unordered_map<string, string>& params)
|
||||
{
|
||||
SetParams(params);
|
||||
|
||||
@ -112,10 +112,10 @@ void SCSIDaynaPort::Open(const Filepath& path)
|
||||
m_tap->OpenDump(path);
|
||||
}
|
||||
|
||||
int SCSIDaynaPort::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSIDaynaPort::Inquiry() const
|
||||
{
|
||||
// Processor device, SCSI-2, not removable
|
||||
return PrimaryDevice::Inquiry(3, 2, false, cdb, buf);
|
||||
return PrimaryDevice::Inquiry(3, 2, false);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@ -444,7 +444,7 @@ void SCSIDaynaPort::Read6(SASIDEV *controller)
|
||||
// generated by the DaynaPort driver so ignore them
|
||||
if (ctrl->cmd[5] != 0xc0 && ctrl->cmd[5] != 0x80) {
|
||||
LOGTRACE("%s Control value %d, (%04X), returning invalid CDB", __PRETTY_FUNCTION__, ctrl->cmd[5], ctrl->cmd[5]);
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -584,7 +584,7 @@ void SCSIDaynaPort::EnableInterface(SASIDEV *controller)
|
||||
controller->Status();
|
||||
}
|
||||
|
||||
int SCSIDaynaPort::GetSendDelay()
|
||||
int SCSIDaynaPort::GetSendDelay() const
|
||||
{
|
||||
// The Daynaport needs to have a delay after the size/flags field
|
||||
// of the read response. In the MacOS driver, it looks like the
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "os.h"
|
||||
#include "disk.h"
|
||||
#include "ctapdriver.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
//===========================================================================
|
||||
@ -46,11 +45,11 @@ public:
|
||||
SCSIDaynaPort();
|
||||
~SCSIDaynaPort();
|
||||
|
||||
bool Init(const map<string, string>&) override;
|
||||
bool Init(const unordered_map<string, string>&) override;
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
// Commands
|
||||
int Inquiry(const DWORD *cdb, BYTE *buffer) override;
|
||||
vector<BYTE> Inquiry() const override;
|
||||
int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override;
|
||||
bool Write(const DWORD *cdb, const BYTE *buf, DWORD block) override;
|
||||
int WriteCheck(DWORD block) override; // WRITE check
|
||||
@ -67,7 +66,7 @@ public:
|
||||
void SetInterfaceMode(SASIDEV *);
|
||||
void SetMcastAddr(SASIDEV *);
|
||||
void EnableInterface(SASIDEV *);
|
||||
int GetSendDelay() override;
|
||||
int GetSendDelay() const override;
|
||||
|
||||
bool Dispatch(SCSIDEV *) override;
|
||||
|
||||
|
@ -59,7 +59,7 @@ SCSIBR::~SCSIBR()
|
||||
}
|
||||
}
|
||||
|
||||
bool SCSIBR::Init(const map<string, string>& params)
|
||||
bool SCSIBR::Init(const unordered_map<string, string>& params)
|
||||
{
|
||||
SetParams(params);
|
||||
|
||||
@ -99,32 +99,16 @@ bool SCSIBR::Dispatch(SCSIDEV *controller)
|
||||
return dispatcher.Dispatch(this, controller) ? true : super::Dispatch(controller);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// INQUIRY
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIBR::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSIBR::Inquiry() const
|
||||
{
|
||||
// EVPD check
|
||||
if (cdb[1] & 0x01) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return 0;
|
||||
}
|
||||
// Communications device, SCSI-2, not removable
|
||||
vector<BYTE> b = PrimaryDevice::Inquiry(9, 2, 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;
|
||||
buf[2] = 0x02;
|
||||
buf[3] = 0x02;
|
||||
buf[4] = 0x1F + 8; // required + 8 byte extension
|
||||
// The bridge returns 6 more additional bytes than the other devices
|
||||
vector<BYTE> buf = vector<BYTE>(0x1F + 8 + 5);
|
||||
memcpy(buf.data(), b.data(), b.size());
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
buf[4] = 0x1F + 8;
|
||||
|
||||
// Optional function valid flag
|
||||
buf[36] = '0';
|
||||
@ -137,16 +121,7 @@ int SCSIBR::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
// CFileSys Enable
|
||||
buf[38] = '1';
|
||||
|
||||
// Size of data that can be returned
|
||||
int size = (buf[4] + 5);
|
||||
|
||||
// Limit if the other buffer is small
|
||||
if (size > (int)cdb[4]) {
|
||||
size = (int)cdb[4];
|
||||
}
|
||||
|
||||
// Success
|
||||
return size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void SCSIBR::TestUnitReady(SASIDEV *controller)
|
||||
|
@ -36,13 +36,13 @@ public:
|
||||
SCSIBR();
|
||||
~SCSIBR();
|
||||
|
||||
bool Init(const map<string, string>&) override;
|
||||
bool Init(const unordered_map<string, string>&) override;
|
||||
bool Dispatch(SCSIDEV *) override;
|
||||
|
||||
// Commands
|
||||
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
|
||||
int GetMessage10(const DWORD *cdb, BYTE *buf); // GET MESSAGE10 command
|
||||
bool SendMessage10(const DWORD *cdb, BYTE *buf); // SEND MESSAGE10 command
|
||||
vector<BYTE> Inquiry() const override;
|
||||
int GetMessage10(const DWORD *cdb, BYTE *buf);
|
||||
bool SendMessage10(const DWORD *cdb, BYTE *buf);
|
||||
void TestUnitReady(SASIDEV *) override;
|
||||
void GetMessage10(SASIDEV *);
|
||||
void SendMessage10(SASIDEV *);
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "controllers/scsidev_ctrl.h"
|
||||
#include "../rasutil.h"
|
||||
#include "scsi_printer.h"
|
||||
#include <string>
|
||||
|
||||
#define NOT_RESERVED -2
|
||||
|
||||
@ -72,7 +71,7 @@ SCSIPrinter::~SCSIPrinter()
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
bool SCSIPrinter::Init(const map<string, string>& params)
|
||||
bool SCSIPrinter::Init(const unordered_map<string, string>& params)
|
||||
{
|
||||
SetParams(params);
|
||||
|
||||
@ -104,10 +103,10 @@ void SCSIPrinter::TestUnitReady(SCSIDEV *controller)
|
||||
controller->Status();
|
||||
}
|
||||
|
||||
int SCSIPrinter::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSIPrinter::Inquiry() const
|
||||
{
|
||||
// Printer device, SCSI-2, not removable
|
||||
return PrimaryDevice::Inquiry(2, 2, false, cdb, buf);
|
||||
return PrimaryDevice::Inquiry(2, 2, false);
|
||||
}
|
||||
|
||||
void SCSIPrinter::ReserveUnit(SCSIDEV *controller)
|
||||
@ -172,7 +171,7 @@ void SCSIPrinter::Print(SCSIDEV *controller)
|
||||
if (length > (uint32_t)ctrl->bufsize) {
|
||||
LOGERROR("Transfer buffer overflow");
|
||||
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -279,8 +278,8 @@ bool SCSIPrinter::CheckReservation(SCSIDEV *controller)
|
||||
LOGTRACE("Unknown initiator tries to access reserved device ID %d, LUN %d", GetId(), GetLun());
|
||||
}
|
||||
|
||||
controller->Error(ERROR_CODES::sense_key::ABORTED_COMMAND, ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
ERROR_CODES::status::RESERVATION_CONFLICT);
|
||||
controller->Error(sense_key::ABORTED_COMMAND, asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
status::RESERVATION_CONFLICT);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "interfaces/scsi_printer_commands.h"
|
||||
#include "primary_device.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -29,9 +29,9 @@ public:
|
||||
|
||||
virtual bool Dispatch(SCSIDEV *) override;
|
||||
|
||||
bool Init(const map<string, string>&);
|
||||
bool Init(const unordered_map<string, string>&);
|
||||
|
||||
int Inquiry(const DWORD *, BYTE *) override;
|
||||
vector<BYTE> Inquiry() const override;
|
||||
void TestUnitReady(SCSIDEV *);
|
||||
void ReserveUnit(SCSIDEV *);
|
||||
void ReleaseUnit(SCSIDEV *);
|
||||
|
@ -176,7 +176,7 @@ bool CDTrack::IsAudio() const
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
SCSICD::SCSICD(const set<uint32_t>& sector_sizes) : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
|
||||
SCSICD::SCSICD(const unordered_set<uint32_t>& sector_sizes) : Disk("SCCD"), ScsiMmcCommands(), FileSupport()
|
||||
{
|
||||
SetSectorSizes(sector_sizes);
|
||||
|
||||
@ -397,32 +397,10 @@ void SCSICD::ReadToc(SASIDEV *controller)
|
||||
controller->DataIn();
|
||||
}
|
||||
|
||||
int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSICD::Inquiry() const
|
||||
{
|
||||
// EVPD check
|
||||
if (cdb[1] & 0x01) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
buf[1] = 0x80;
|
||||
buf[2] = 0x02;
|
||||
buf[3] = 0x02;
|
||||
buf[4] = 0x1F;
|
||||
|
||||
// Fill with blanks
|
||||
memset(&buf[8], 0x20, buf[4] - 3);
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
// CD-ROM device, SCSI-2, removable
|
||||
return PrimaryDevice::Inquiry(5, 2, true);
|
||||
|
||||
//
|
||||
// The following code worked with the modified Apple CD-ROM drivers. Need to
|
||||
@ -446,16 +424,6 @@ int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
// //strcpy(&buf[35],"A1.9a");
|
||||
// buf[36]=0x20;
|
||||
// memcpy(&buf[37],"1999/01/01",10);
|
||||
|
||||
// Size of data that can be returned
|
||||
int size = (buf[4] + 5);
|
||||
|
||||
// Limit if the other buffer is small
|
||||
if (size > (int)cdb[4]) {
|
||||
size = (int)cdb[4];
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void SCSICD::AddModePages(map<int, vector<BYTE>>& pages, int page, bool changeable) const
|
||||
@ -658,12 +626,12 @@ void SCSICD::GetEventStatusNotification(SASIDEV *controller)
|
||||
{
|
||||
if (!(ctrl->cmd[1] & 0x01)) {
|
||||
// Asynchronous notification is optional and not supported by rascsi
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGTRACE("Received request for event polling, which is currently not supported");
|
||||
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
||||
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -76,7 +76,7 @@ public:
|
||||
TrackMax = 96 // Maximum number of tracks
|
||||
};
|
||||
|
||||
SCSICD(const set<uint32_t>&);
|
||||
SCSICD(const unordered_set<uint32_t>&);
|
||||
~SCSICD();
|
||||
|
||||
bool Dispatch(SCSIDEV *) override;
|
||||
@ -84,9 +84,9 @@ public:
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
// Commands
|
||||
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
|
||||
int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override; // READ command
|
||||
int ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC command
|
||||
vector<BYTE> Inquiry() const override;
|
||||
int Read(const DWORD *cdb, BYTE *buf, uint64_t block) override;
|
||||
int ReadToc(const DWORD *cdb, BYTE *buf);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
SCSIHD::SCSIHD(const set<uint32_t>& sector_sizes, bool removable) : Disk(removable ? "SCRM" : "SCHD")
|
||||
SCSIHD::SCSIHD(const unordered_set<uint32_t>& sector_sizes, bool removable) : Disk(removable ? "SCRM" : "SCHD")
|
||||
{
|
||||
SetSectorSizes(sector_sizes);
|
||||
}
|
||||
@ -98,38 +98,10 @@ void SCSIHD::Open(const Filepath& path)
|
||||
FinalizeSetup(path, size);
|
||||
}
|
||||
|
||||
int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSIHD::Inquiry() const
|
||||
{
|
||||
// EVPD check
|
||||
if (cdb[1] & 0x01) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Basic data
|
||||
// buf[0] ... Direct Access Device
|
||||
// buf[1] ... Bit 7 set means 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[1] = IsRemovable() ? 0x80 : 0x00;
|
||||
buf[2] = 0x02;
|
||||
buf[3] = 0x02;
|
||||
buf[4] = 0x1F;
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
|
||||
// Size of data that can be returned
|
||||
int size = (buf[4] + 5);
|
||||
|
||||
// Limit if the other buffer is small
|
||||
if (size > (int)cdb[4]) {
|
||||
size = (int)cdb[4];
|
||||
}
|
||||
|
||||
return size;
|
||||
// Direct access device, SCSI-2
|
||||
return PrimaryDevice::Inquiry(0, 2, IsRemovable());
|
||||
}
|
||||
|
||||
bool SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
||||
@ -221,7 +193,7 @@ void SCSIHD::AddVendorPage(map<int, vector<BYTE>>& pages, int page, bool changea
|
||||
|
||||
// No changeable area
|
||||
if (!changeable) {
|
||||
memcpy(&buf.data()[0xa], "APPLE COMPUTER, INC.", 20);
|
||||
memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20);
|
||||
}
|
||||
|
||||
pages[48] = buf;
|
||||
|
@ -22,7 +22,7 @@
|
||||
class SCSIHD : public Disk, public FileSupport
|
||||
{
|
||||
public:
|
||||
SCSIHD(const set<uint32_t>&, bool);
|
||||
SCSIHD(const unordered_set<uint32_t>&, bool);
|
||||
virtual ~SCSIHD() {}
|
||||
|
||||
void FinalizeSetup(const Filepath&, off_t);
|
||||
@ -31,7 +31,7 @@ public:
|
||||
virtual void Open(const Filepath&) override;
|
||||
|
||||
// Commands
|
||||
virtual int Inquiry(const DWORD *cdb, BYTE *buf) override;
|
||||
virtual vector<BYTE> Inquiry() const override;
|
||||
bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
|
||||
|
||||
void AddVendorPage(map<int, vector<BYTE>>&, int, bool) const override;
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "fileio.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
SCSIHD_NEC::SCSIHD_NEC(const set<uint32_t>& sector_sizes) : SCSIHD(sector_sizes, false)
|
||||
SCSIHD_NEC::SCSIHD_NEC(const unordered_set<uint32_t>& sector_sizes) : SCSIHD(sector_sizes, false)
|
||||
{
|
||||
// Work initialization
|
||||
cylinders = 0;
|
||||
@ -135,15 +135,10 @@ void SCSIHD_NEC::Open(const Filepath& path)
|
||||
FinalizeSetup(path, size);
|
||||
}
|
||||
|
||||
int SCSIHD_NEC::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSIHD_NEC::Inquiry() const
|
||||
{
|
||||
int size = SCSIHD::Inquiry(cdb, buf);
|
||||
|
||||
// This drive is a SCSI-1 SCCS drive
|
||||
buf[2] = 0x01;
|
||||
buf[3] = 0x01;
|
||||
|
||||
return size;
|
||||
// Direct access device, SCSI-1-CCS, not removable
|
||||
return PrimaryDevice::Inquiry(0, 1, false);
|
||||
}
|
||||
|
||||
void SCSIHD_NEC::AddErrorPage(map<int, vector<BYTE>>& pages, bool) const
|
||||
|
@ -25,13 +25,13 @@
|
||||
class SCSIHD_NEC : public SCSIHD
|
||||
{
|
||||
public:
|
||||
SCSIHD_NEC(const set<uint32_t>&);
|
||||
SCSIHD_NEC(const unordered_set<uint32_t>&);
|
||||
~SCSIHD_NEC() {}
|
||||
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
// Commands
|
||||
int Inquiry(const DWORD *cdb, BYTE *buf) override;
|
||||
vector<BYTE> Inquiry() const override;
|
||||
|
||||
void AddErrorPage(map<int, vector<BYTE>>&, bool) const override;
|
||||
void AddFormatPage(map<int, vector<BYTE>>&, bool) const override;
|
||||
|
@ -14,12 +14,11 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "scsimo.h"
|
||||
|
||||
#include "fileio.h"
|
||||
#include "exceptions.h"
|
||||
#include "scsimo.h"
|
||||
|
||||
SCSIMO::SCSIMO(const set<uint32_t>& sector_sizes, const map<uint64_t, Geometry>& geometries) : Disk("SCMO")
|
||||
SCSIMO::SCSIMO(const unordered_set<uint32_t>& sector_sizes, const unordered_map<uint64_t, Geometry>& geometries) : Disk("SCMO")
|
||||
{
|
||||
SetSectorSizes(sector_sizes);
|
||||
SetGeometries(geometries);
|
||||
@ -41,6 +40,7 @@ void SCSIMO::Open(const Filepath& path)
|
||||
fio.Close();
|
||||
|
||||
// For some priorities there are hard-coded, well-defined sector sizes and block counts
|
||||
// TODO Find a more flexible solution
|
||||
if (!SetGeometryForCapacity(size)) {
|
||||
// Sector size (default 512 bytes) and number of blocks
|
||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 512, true);
|
||||
@ -63,39 +63,10 @@ void SCSIMO::Open(const Filepath& path)
|
||||
}
|
||||
}
|
||||
|
||||
int SCSIMO::Inquiry(const DWORD *cdb, BYTE *buf)
|
||||
vector<BYTE> SCSIMO::Inquiry() const
|
||||
{
|
||||
// EVPD check
|
||||
if (cdb[1] & 0x01) {
|
||||
SetStatusCode(STATUS_INVALIDCDB);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Basic data
|
||||
// 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;
|
||||
buf[1] = 0x80;
|
||||
buf[2] = 0x02;
|
||||
buf[3] = 0x02;
|
||||
buf[4] = 0x1F;
|
||||
|
||||
// Padded vendor, product, revision
|
||||
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
||||
|
||||
// Size return data
|
||||
int size = (buf[4] + 5);
|
||||
|
||||
// Limit the size if the buffer is too small
|
||||
if (size > (int)cdb[4]) {
|
||||
size = (int)cdb[4];
|
||||
}
|
||||
|
||||
return size;
|
||||
// Optical memory device, SCSI-2, removable
|
||||
return PrimaryDevice::Inquiry(7, 2, true);
|
||||
}
|
||||
|
||||
void SCSIMO::SetDeviceParameters(BYTE *buf)
|
||||
|
@ -22,13 +22,13 @@
|
||||
class SCSIMO : public Disk, public FileSupport
|
||||
{
|
||||
public:
|
||||
SCSIMO(const set<uint32_t>&, const map<uint64_t, Geometry>&);
|
||||
SCSIMO(const unordered_set<uint32_t>&, const unordered_map<uint64_t, Geometry>&);
|
||||
~SCSIMO() {}
|
||||
|
||||
void Open(const Filepath& path) override;
|
||||
|
||||
// Commands
|
||||
int Inquiry(const DWORD *cdb, BYTE *buf) override;
|
||||
vector<BYTE> Inquiry() const override;
|
||||
bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;
|
||||
|
||||
protected:
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "localizer.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
|
||||
@ -146,7 +145,7 @@ string Localizer::Localize(LocalizationKey key, const string& locale, const stri
|
||||
string locale_lower = locale;
|
||||
transform(locale_lower.begin(), locale_lower.end(), locale_lower.begin(), ::tolower);
|
||||
|
||||
map<LocalizationKey, string> messages = localized_messages[locale_lower];
|
||||
unordered_map<LocalizationKey, string> messages = localized_messages[locale_lower];
|
||||
if (messages.empty()) {
|
||||
// Try to fall back to country-indepedent locale (e.g. "en" instead of "en_US")
|
||||
if (locale_lower.length() > 2) {
|
||||
|
@ -12,8 +12,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -53,7 +53,7 @@ public:
|
||||
private:
|
||||
|
||||
void Add(LocalizationKey, const string&, const string&);
|
||||
map<string, map<LocalizationKey, string>> localized_messages;
|
||||
unordered_map<string, unordered_map<LocalizationKey, string>> localized_messages;
|
||||
|
||||
set<string> supported_languages;
|
||||
unordered_set<string> supported_languages;
|
||||
};
|
||||
|
@ -68,7 +68,7 @@ pthread_mutex_t ctrl_mutex; // Semaphore for the ctrl array
|
||||
static void *MonThread(void *param);
|
||||
string current_log_level; // Some versions of spdlog do not support get_log_level()
|
||||
string access_token;
|
||||
set<int> reserved_ids;
|
||||
unordered_set<int> reserved_ids;
|
||||
DeviceFactory& device_factory = DeviceFactory::instance();
|
||||
RascsiImage rascsi_image;
|
||||
RascsiResponse rascsi_response(&device_factory, &rascsi_image);
|
||||
@ -428,22 +428,10 @@ string ValidateLunSetup(const PbCommand& command, const vector<Device *>& existi
|
||||
}
|
||||
}
|
||||
|
||||
// LUNs must be consecutive
|
||||
// LUN 0 must exist for all devices
|
||||
for (auto const& [id, lun]: luns) {
|
||||
bool is_consecutive = false;
|
||||
|
||||
uint32_t lun_vector = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
lun_vector |= 1 << i;
|
||||
|
||||
if (lun == lun_vector) {
|
||||
is_consecutive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_consecutive) {
|
||||
return "LUNs for device ID " + to_string(id) + " are not consecutive";
|
||||
if (!(lun & 0x01)) {
|
||||
return "LUN 0 is missing for device ID " + to_string(id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,7 +493,7 @@ string SetReservedIds(const string& ids)
|
||||
}
|
||||
}
|
||||
|
||||
set<int> reserved;
|
||||
unordered_set<int> reserved;
|
||||
for (string id_to_reserve : ids_to_reserve) {
|
||||
int id;
|
||||
if (!GetAsInt(id_to_reserve, id) || id > 7) {
|
||||
@ -694,7 +682,7 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<string, string> params = { pb_device.params().begin(), pb_device.params().end() };
|
||||
unordered_map<string, string> params = { pb_device.params().begin(), pb_device.params().end() };
|
||||
if (!device->SupportsFile()) {
|
||||
params.erase("file");
|
||||
}
|
||||
@ -728,20 +716,24 @@ bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device,
|
||||
|
||||
bool Detach(const CommandContext& context, Device *device, Device *map[], bool dryRun)
|
||||
{
|
||||
if (!dryRun) {
|
||||
if (!device->GetLun()) {
|
||||
for (auto const& d : devices) {
|
||||
// Detach all LUNs equal to or higher than the LUN specified
|
||||
if (d && d->GetId() == device->GetId() && d->GetLun() >= device->GetLun()) {
|
||||
map[d->GetId() * UnitNum + d->GetLun()] = NULL;
|
||||
|
||||
FileSupport *file_support = dynamic_cast<FileSupport *>(d);
|
||||
if (file_support) {
|
||||
file_support->UnreserveFile();
|
||||
}
|
||||
|
||||
LOGINFO("Detached %s device with ID %d, unit %d", d->GetType().c_str(), d->GetId(), d->GetLun());
|
||||
// LUN 0 can only be detached if there is no other lUN anymore
|
||||
if (d && d->GetId() == device->GetId() && d->GetLun()) {
|
||||
return ReturnStatus(context, false, "LUN 0 cannot be detached as long as there is still another LUN");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
map[device->GetId() * UnitNum + device->GetLun()] = NULL;
|
||||
|
||||
FileSupport *file_support = dynamic_cast<FileSupport *>(device);
|
||||
if (file_support) {
|
||||
file_support->UnreserveFile();
|
||||
}
|
||||
|
||||
LOGINFO("Detached %s device with ID %d, unit %d", device->GetType().c_str(), device->GetId(), device->GetLun());
|
||||
|
||||
// Re-map the controller
|
||||
MapController(map);
|
||||
|
@ -220,7 +220,7 @@ void RascsiResponse::GetAvailableImages(PbResult& result, PbServerInfo& server_i
|
||||
result.set_status(true);
|
||||
}
|
||||
|
||||
PbReservedIdsInfo *RascsiResponse::GetReservedIds(PbResult& result, const set<int>& ids)
|
||||
PbReservedIdsInfo *RascsiResponse::GetReservedIds(PbResult& result, const unordered_set<int>& ids)
|
||||
{
|
||||
PbReservedIdsInfo *reserved_ids_info = new PbReservedIdsInfo();
|
||||
for (int id : ids) {
|
||||
@ -289,8 +289,9 @@ PbDeviceTypesInfo *RascsiResponse::GetDeviceTypesInfo(PbResult& result, const Pb
|
||||
return device_types_info;
|
||||
}
|
||||
|
||||
PbServerInfo *RascsiResponse::GetServerInfo(PbResult& result, const vector<Device *>& devices, const set<int>& reserved_ids,
|
||||
const string& current_log_level, const string& folder_pattern, const string& file_pattern, int scan_depth)
|
||||
PbServerInfo *RascsiResponse::GetServerInfo(PbResult& result, const vector<Device *>& devices,
|
||||
const unordered_set<int>& reserved_ids, const string& current_log_level, const string& folder_pattern,
|
||||
const string& file_pattern, int scan_depth)
|
||||
{
|
||||
PbServerInfo *server_info = new PbServerInfo();
|
||||
|
||||
|
@ -30,13 +30,13 @@ public:
|
||||
|
||||
bool GetImageFile(PbImageFile *, const string&);
|
||||
PbImageFilesInfo *GetAvailableImages(PbResult&, const string&, const string&, int);
|
||||
PbReservedIdsInfo *GetReservedIds(PbResult&, const set<int>&);
|
||||
PbReservedIdsInfo *GetReservedIds(PbResult&, const unordered_set<int>&);
|
||||
void GetDevices(PbServerInfo&, const vector<Device *>&);
|
||||
void GetDevicesInfo(PbResult&, const PbCommand&, const vector<Device *>&, int);
|
||||
PbDeviceTypesInfo *GetDeviceTypesInfo(PbResult&, const PbCommand&);
|
||||
PbVersionInfo *GetVersionInfo(PbResult&);
|
||||
PbServerInfo *GetServerInfo(PbResult&, const vector<Device *>&, const set<int>&, const string&, const string&,
|
||||
const string&, int);
|
||||
PbServerInfo *GetServerInfo(PbResult&, const vector<Device *>&, const unordered_set<int>&, const string&,
|
||||
const string&, const string&, int);
|
||||
PbNetworkInterfacesInfo *GetNetworkInterfacesInfo(PbResult&);
|
||||
PbMappingInfo *GetMappingInfo(PbResult&);
|
||||
PbLogLevelInfo *GetLogLevelInfo(PbResult&, const string&);
|
||||
|
@ -12,57 +12,6 @@
|
||||
#pragma once
|
||||
#include "os.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Status byte codes, Sense Keys and Additional Sense Codes
|
||||
// (See https://www.t10.org/lists/1spc-lst.htm)
|
||||
//
|
||||
//===========================================================================
|
||||
class ERROR_CODES
|
||||
{
|
||||
public:
|
||||
enum status : int {
|
||||
GOOD = 0x00,
|
||||
CHECK_CONDITION = 0x02,
|
||||
CONDITION_MET = 0x04,
|
||||
BUSY = 0x08,
|
||||
INTERMEDIATE = 0x10,
|
||||
INTERMEDIATE_CONDITION_MET = 0x14,
|
||||
RESERVATION_CONFLICT = 0x18,
|
||||
COMMAND_TERMINATED = 0x22,
|
||||
QUEUE_FULL = 0x28
|
||||
};
|
||||
|
||||
enum sense_key : int {
|
||||
NO_SENSE = 0x00,
|
||||
RECOVERED_ERROR = 0x01,
|
||||
NOT_READY = 0x02,
|
||||
MEDIUM_ERROR = 0x03,
|
||||
HARDWARE_ERROR = 0x04,
|
||||
ILLEGAL_REQUEST = 0x05,
|
||||
UNIT_ATTENTION = 0x06,
|
||||
DATA_PROTECT = 0x07,
|
||||
BLANK_CHECK = 0x08,
|
||||
VENDOR_SPECIFIC = 0x09,
|
||||
COPY_ABORTED = 0x0a,
|
||||
ABORTED_COMMAND = 0x0b,
|
||||
VOLUME_OVERFLOW = 0x0d,
|
||||
MISCOMPARE = 0x0e,
|
||||
COMPLETED = 0x0f
|
||||
};
|
||||
|
||||
enum asc : int {
|
||||
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
|
||||
INVALID_COMMAND_OPERATION_CODE = 0x20,
|
||||
LBA_OUT_OF_RANGE = 0x21,
|
||||
INVALID_FIELD_IN_CDB = 0x24,
|
||||
INVALID_LUN = 0x25,
|
||||
WRITE_PROTECTED = 0x27,
|
||||
NOT_READY_TO_READY_CHANGE = 0x28,
|
||||
MEDIUM_NOT_PRESENT = 0x3a
|
||||
};
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// SASI/SCSI Bus
|
||||
@ -94,8 +43,8 @@ public:
|
||||
reserved // Unused
|
||||
};
|
||||
|
||||
BUS() { };
|
||||
virtual ~BUS() { };
|
||||
BUS() {}
|
||||
virtual ~BUS() {}
|
||||
|
||||
// Basic Functions
|
||||
virtual BOOL Init(mode_e mode) = 0;
|
||||
@ -108,8 +57,8 @@ public:
|
||||
return phase_table[mci];
|
||||
}
|
||||
|
||||
// Get the string phase name, based upon the raw data
|
||||
static const char* GetPhaseStrRaw(phase_t current_phase);
|
||||
// Get the string phase name, based upon the raw data
|
||||
|
||||
// Extract as specific pin field from a raw data capture
|
||||
static inline DWORD GetPinRaw(DWORD raw_data, DWORD pin_num)
|
||||
@ -168,6 +117,12 @@ private:
|
||||
static const char* phase_str_table[];
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// For Status byte codes, Sense Keys and Additional Sense Codes
|
||||
// See https://www.t10.org/lists/1spc-lst.htm
|
||||
//
|
||||
//===========================================================================
|
||||
namespace scsi_defs {
|
||||
enum scsi_command : int {
|
||||
eCmdTestUnitReady = 0x00,
|
||||
@ -220,4 +175,45 @@ namespace scsi_defs {
|
||||
eCmdWriteLong16 = 0x9F,
|
||||
eCmdReportLuns = 0xA0
|
||||
};
|
||||
|
||||
enum status : int {
|
||||
GOOD = 0x00,
|
||||
CHECK_CONDITION = 0x02,
|
||||
CONDITION_MET = 0x04,
|
||||
BUSY = 0x08,
|
||||
INTERMEDIATE = 0x10,
|
||||
INTERMEDIATE_CONDITION_MET = 0x14,
|
||||
RESERVATION_CONFLICT = 0x18,
|
||||
COMMAND_TERMINATED = 0x22,
|
||||
QUEUE_FULL = 0x28
|
||||
};
|
||||
|
||||
enum sense_key : int {
|
||||
NO_SENSE = 0x00,
|
||||
RECOVERED_ERROR = 0x01,
|
||||
NOT_READY = 0x02,
|
||||
MEDIUM_ERROR = 0x03,
|
||||
HARDWARE_ERROR = 0x04,
|
||||
ILLEGAL_REQUEST = 0x05,
|
||||
UNIT_ATTENTION = 0x06,
|
||||
DATA_PROTECT = 0x07,
|
||||
BLANK_CHECK = 0x08,
|
||||
VENDOR_SPECIFIC = 0x09,
|
||||
COPY_ABORTED = 0x0a,
|
||||
ABORTED_COMMAND = 0x0b,
|
||||
VOLUME_OVERFLOW = 0x0d,
|
||||
MISCOMPARE = 0x0e,
|
||||
COMPLETED = 0x0f
|
||||
};
|
||||
|
||||
enum asc : int {
|
||||
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
|
||||
INVALID_COMMAND_OPERATION_CODE = 0x20,
|
||||
LBA_OUT_OF_RANGE = 0x21,
|
||||
INVALID_FIELD_IN_CDB = 0x24,
|
||||
INVALID_LUN = 0x25,
|
||||
WRITE_PROTECTED = 0x27,
|
||||
NOT_READY_TO_READY_CHANGE = 0x28,
|
||||
MEDIUM_NOT_PRESENT = 0x3a
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user