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:
Uwe Seimet 2022-03-02 03:25:22 +01:00 committed by GitHub
parent da02eccb2e
commit 1df7cdb1f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 345 additions and 538 deletions

View File

@ -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();

View File

@ -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

View File

@ -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);
}

View File

@ -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; }

View File

@ -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");

View File

@ -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:

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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 *))
{

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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 *);

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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 *);

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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);
}
//---------------------------------------------------------------------------

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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:

View File

@ -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) {

View File

@ -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;
};

View File

@ -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);

View File

@ -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();

View File

@ -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&);

View File

@ -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
};
};