2022-02-10 18:54:48 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2022-08-26 01:01:39 +00:00
|
|
|
// SCSI Target Emulator RaSCSI Reloaded
|
2022-02-10 18:54:48 +00:00
|
|
|
// for Raspberry Pi
|
|
|
|
//
|
|
|
|
// Copyright (C) 2022 Uwe Seimet
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "controllers/scsidev_ctrl.h"
|
2022-02-13 19:30:02 +00:00
|
|
|
#include "dispatcher.h"
|
2022-02-10 18:54:48 +00:00
|
|
|
#include "primary_device.h"
|
|
|
|
|
|
|
|
using namespace std;
|
2022-02-13 19:30:02 +00:00
|
|
|
using namespace scsi_defs;
|
2022-02-10 18:54:48 +00:00
|
|
|
|
2022-02-13 19:30:02 +00:00
|
|
|
PrimaryDevice::PrimaryDevice(const string& id) : ScsiPrimaryCommands(), Device(id)
|
2022-02-10 18:54:48 +00:00
|
|
|
{
|
|
|
|
ctrl = NULL;
|
|
|
|
|
|
|
|
// Mandatory SCSI primary commands
|
2022-02-13 19:30:02 +00:00
|
|
|
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &PrimaryDevice::TestUnitReady);
|
|
|
|
dispatcher.AddCommand(eCmdInquiry, "Inquiry", &PrimaryDevice::Inquiry);
|
|
|
|
dispatcher.AddCommand(eCmdReportLuns, "ReportLuns", &PrimaryDevice::ReportLuns);
|
2022-02-10 18:54:48 +00:00
|
|
|
|
|
|
|
// Optional commands used by all RaSCSI devices
|
2022-02-13 19:30:02 +00:00
|
|
|
dispatcher.AddCommand(eCmdRequestSense, "RequestSense", &PrimaryDevice::RequestSense);
|
2022-02-10 18:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PrimaryDevice::Dispatch(SCSIDEV *controller)
|
|
|
|
{
|
2022-02-13 19:30:02 +00:00
|
|
|
return dispatcher.Dispatch(this, controller);
|
2022-02-10 18:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PrimaryDevice::TestUnitReady(SASIDEV *controller)
|
|
|
|
{
|
|
|
|
if (!CheckReady()) {
|
|
|
|
controller->Error();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller->Status();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PrimaryDevice::Inquiry(SASIDEV *controller)
|
|
|
|
{
|
2022-03-02 02:25:22 +00:00
|
|
|
// EVPD and page code check
|
|
|
|
if ((ctrl->cmd[1] & 0x01) || ctrl->cmd[2]) {
|
|
|
|
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_CDB);
|
2022-02-10 18:54:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
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;
|
|
|
|
|
2022-02-18 20:04:07 +00:00
|
|
|
int lun = controller->GetEffectiveLun();
|
|
|
|
|
2022-02-10 18:54:48 +00:00
|
|
|
// Report if the device does not support the requested LUN
|
|
|
|
if (!ctrl->unit[lun]) {
|
2022-02-13 19:30:02 +00:00
|
|
|
LOGTRACE("Reporting LUN %d for device ID %d as not supported", lun, ctrl->device->GetId());
|
2022-02-10 18:54:48 +00:00
|
|
|
|
2022-02-18 20:04:07 +00:00
|
|
|
// Signal that the requested LUN does not exist
|
2022-02-10 18:54:48 +00:00
|
|
|
ctrl->buffer[0] |= 0x7f;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller->DataIn();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PrimaryDevice::ReportLuns(SASIDEV *controller)
|
|
|
|
{
|
|
|
|
int allocation_length = (ctrl->cmd[6] << 24) + (ctrl->cmd[7] << 16) + (ctrl->cmd[8] << 8) + ctrl->cmd[9];
|
2022-03-02 02:25:22 +00:00
|
|
|
|
|
|
|
BYTE *buf = ctrl->buffer;
|
2022-02-10 18:54:48 +00:00
|
|
|
memset(buf, 0, allocation_length);
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
int size = 0;
|
2022-03-03 18:53:11 +00:00
|
|
|
|
|
|
|
// Only SELECT REPORT mode 0 is supported
|
|
|
|
if (!ctrl->cmd[2]) {
|
|
|
|
for (int lun = 0; lun < controller->GetCtrl()->device->GetSupportedLuns(); lun++) {
|
|
|
|
if (controller->GetCtrl()->unit[lun]) {
|
|
|
|
size += 8;
|
|
|
|
buf[size + 7] = lun;
|
|
|
|
}
|
2022-02-10 18:54:48 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 18:53:11 +00:00
|
|
|
buf[2] = size >> 8;
|
|
|
|
buf[3] = size;
|
|
|
|
}
|
2022-03-02 02:25:22 +00:00
|
|
|
|
|
|
|
size += 8;
|
2022-02-10 18:54:48 +00:00
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
ctrl->length = allocation_length < size ? allocation_length : size;
|
2022-02-10 18:54:48 +00:00
|
|
|
|
|
|
|
controller->DataIn();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PrimaryDevice::RequestSense(SASIDEV *controller)
|
|
|
|
{
|
|
|
|
int lun = controller->GetEffectiveLun();
|
|
|
|
|
|
|
|
// Note: According to the SCSI specs the LUN handling for REQUEST SENSE non-existing LUNs do *not* result
|
|
|
|
// in CHECK CONDITION. Only the Sense Key and ASC are set in order to signal the non-existing LUN.
|
|
|
|
if (!ctrl->unit[lun]) {
|
|
|
|
// LUN 0 can be assumed to be present (required to call RequestSense() below)
|
|
|
|
lun = 0;
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
controller->Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
|
2022-02-10 18:54:48 +00:00
|
|
|
ctrl->status = 0x00;
|
|
|
|
}
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
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;
|
2022-02-10 18:54:48 +00:00
|
|
|
|
|
|
|
controller->DataIn();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrimaryDevice::CheckReady()
|
|
|
|
{
|
|
|
|
// Not ready if reset
|
|
|
|
if (IsReset()) {
|
|
|
|
SetStatusCode(STATUS_DEVRESET);
|
|
|
|
SetReset(false);
|
2022-02-27 21:58:01 +00:00
|
|
|
LOGTRACE("%s Device in reset", __PRETTY_FUNCTION__);
|
2022-02-10 18:54:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not ready if it needs attention
|
|
|
|
if (IsAttn()) {
|
|
|
|
SetStatusCode(STATUS_ATTENTION);
|
|
|
|
SetAttn(false);
|
2022-02-27 21:58:01 +00:00
|
|
|
LOGTRACE("%s Device in needs attention", __PRETTY_FUNCTION__);
|
2022-02-10 18:54:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return status if not ready
|
|
|
|
if (!IsReady()) {
|
|
|
|
SetStatusCode(STATUS_NOTREADY);
|
2022-02-27 21:58:01 +00:00
|
|
|
LOGTRACE("%s Device not ready", __PRETTY_FUNCTION__);
|
2022-02-10 18:54:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialization with no error
|
2022-02-27 21:58:01 +00:00
|
|
|
LOGTRACE("%s Device is ready", __PRETTY_FUNCTION__);
|
2022-02-10 18:54:48 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-03-02 17:31:42 +00:00
|
|
|
vector<BYTE> PrimaryDevice::Inquiry(device_type type, scsi_level level, bool is_removable) const
|
2022-02-13 19:30:02 +00:00
|
|
|
{
|
2022-03-02 02:25:22 +00:00
|
|
|
vector<BYTE> buf = vector<BYTE>(0x1F + 5);
|
|
|
|
|
|
|
|
// Basic data
|
2022-03-02 17:31:42 +00:00
|
|
|
// buf[0] ... SCSI device type
|
2022-03-02 02:25:22 +00:00
|
|
|
// buf[1] ... Bit 7: Removable/not removable
|
2022-03-02 17:31:42 +00:00
|
|
|
// buf[2] ... SCSI compliance level of command system
|
|
|
|
// buf[3] ... SCSI compliance level of Inquiry response
|
2022-03-02 02:25:22 +00:00
|
|
|
// buf[4] ... Inquiry additional data
|
|
|
|
buf[0] = type;
|
|
|
|
buf[1] = is_removable ? 0x80 : 0x00;
|
2022-03-02 17:31:42 +00:00
|
|
|
buf[2] = level;
|
|
|
|
buf[3] = level >= scsi_level::SCSI_2 ? scsi_level::SCSI_2 : scsi_level::SCSI_1_CCS;
|
2022-03-02 02:25:22 +00:00
|
|
|
buf[4] = 0x1F;
|
|
|
|
|
|
|
|
// Padded vendor, product, revision
|
|
|
|
memcpy(&buf[8], GetPaddedName().c_str(), 28);
|
|
|
|
|
|
|
|
return buf;
|
2022-02-13 19:30:02 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
vector<BYTE> PrimaryDevice::RequestSense(int)
|
2022-02-10 18:54:48 +00:00
|
|
|
{
|
|
|
|
// Return not ready only if there are no errors
|
2022-02-27 21:58:01 +00:00
|
|
|
if (GetStatusCode() == STATUS_NOERROR && !IsReady()) {
|
|
|
|
SetStatusCode(STATUS_NOTREADY);
|
2022-02-10 18:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set 18 bytes including extended sense data
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
vector<BYTE> buf(18);
|
|
|
|
|
2022-02-10 18:54:48 +00:00
|
|
|
// Current error
|
|
|
|
buf[0] = 0x70;
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
buf[2] = GetStatusCode() >> 16;
|
2022-02-10 18:54:48 +00:00
|
|
|
buf[7] = 10;
|
2022-03-02 02:25:22 +00:00
|
|
|
buf[12] = GetStatusCode() >> 8;
|
|
|
|
buf[13] = GetStatusCode();
|
2022-02-10 18:54:48 +00:00
|
|
|
|
2022-03-06 15:17:23 +00:00
|
|
|
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
|
|
|
|
|
2022-03-02 02:25:22 +00:00
|
|
|
return buf;
|
2022-02-10 18:54:48 +00:00
|
|
|
}
|
|
|
|
|
2022-02-17 02:04:42 +00:00
|
|
|
bool PrimaryDevice::WriteBytes(BYTE *buf, uint32_t length)
|
|
|
|
{
|
|
|
|
LOGERROR("%s Writing bytes is not supported by this device", __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|