mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-22 15:30:09 +00:00
* Fix issue with MODE SELECT (#818) * Replaced strncpy because it was causing a compilation issue
This commit is contained in:
parent
ccdb51b727
commit
4e4c5b205a
@ -625,6 +625,7 @@ void ScsiController::Receive()
|
||||
}
|
||||
|
||||
// If result FALSE, move to status phase
|
||||
// TODO Check whether we can raise scsi_exception here in order to simplify the error handling
|
||||
if (!result) {
|
||||
Error(sense_key::ABORTED_COMMAND);
|
||||
return;
|
||||
@ -648,7 +649,8 @@ void ScsiController::Receive()
|
||||
break;
|
||||
|
||||
case BUS::phase_t::dataout:
|
||||
FlushUnit();
|
||||
// Block-oriented data have been handled above
|
||||
DataOutNonBlockOriented();
|
||||
|
||||
Status();
|
||||
break;
|
||||
@ -769,47 +771,30 @@ bool ScsiController::XferOut(bool cont)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScsiController::FlushUnit()
|
||||
void ScsiController::DataOutNonBlockOriented()
|
||||
{
|
||||
assert(IsDataOut());
|
||||
|
||||
auto disk = dynamic_pointer_cast<Disk>(GetDeviceForLun(GetEffectiveLun()));
|
||||
if (disk == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// WRITE system only
|
||||
switch (GetOpcode()) {
|
||||
case scsi_command::eCmdWrite6:
|
||||
case scsi_command::eCmdWrite10:
|
||||
case scsi_command::eCmdWrite16:
|
||||
case scsi_command::eCmdWriteLong10:
|
||||
case scsi_command::eCmdWriteLong16:
|
||||
case scsi_command::eCmdVerify10:
|
||||
case scsi_command::eCmdVerify16:
|
||||
break;
|
||||
|
||||
case scsi_command::eCmdModeSelect6:
|
||||
case scsi_command::eCmdModeSelect10:
|
||||
// TODO What is this special handling of ModeSelect good for?
|
||||
// Without it we would not need this method at all.
|
||||
// ModeSelect is already handled in XferOutBlockOriented(). Why would it have to be handled once more?
|
||||
try {
|
||||
disk->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset());
|
||||
case scsi_command::eCmdModeSelect10: {
|
||||
// TODO Try to get rid of this cast
|
||||
if (auto device = dynamic_pointer_cast<ModePageDevice>(GetDeviceForLun(GetEffectiveLun()));
|
||||
device != nullptr) {
|
||||
device->ModeSelect(ctrl.cmd, GetBuffer(), GetOffset());
|
||||
}
|
||||
else {
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||
}
|
||||
}
|
||||
catch(const scsi_exception& e) {
|
||||
LOGWARN("Error occured while processing Mode Select command %02X\n", (int)GetOpcode())
|
||||
Error(e.get_sense_key(), e.get_asc(), e.get_status());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case scsi_command::eCmdSetMcastAddr:
|
||||
// TODO: Eventually, we should store off the multicast address configuration data here...
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGWARN("Received an unexpected flush command $%02X\n", (int)GetOpcode())
|
||||
LOGWARN("Unexpected Data Out phase for command $%02X", (int)GetOpcode())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ private:
|
||||
void ReceiveBytes();
|
||||
|
||||
void Execute();
|
||||
void FlushUnit();
|
||||
void DataOutNonBlockOriented();
|
||||
void Receive();
|
||||
|
||||
void ProcessCommand();
|
||||
|
@ -220,7 +220,7 @@ list<string> DeviceFactory::GetNetworkInterfaces() const
|
||||
const int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
|
||||
ifreq ifr = {};
|
||||
strncpy(ifr.ifr_name, tmp->ifa_name, IFNAMSIZ); //NOSONAR Using strncpy is safe here
|
||||
strcpy(ifr.ifr_name, tmp->ifa_name); //NOSONAR Using strcpy is safe here
|
||||
// Only list interfaces that are up
|
||||
if (!ioctl(fd, SIOCGIFFLAGS, &ifr) && (ifr.ifr_flags & IFF_UP)) {
|
||||
network_interfaces.emplace_back(tmp->ifa_name);
|
||||
|
@ -23,32 +23,30 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
// Skip block descriptors
|
||||
int offset;
|
||||
if ((scsi_command)cdb[0] == scsi_command::eCmdModeSelect10) {
|
||||
offset = 8 + GetInt16(buf, 6);
|
||||
}
|
||||
else {
|
||||
offset = 4 + buf[3];
|
||||
}
|
||||
length -= offset;
|
||||
|
||||
bool has_valid_page_code = false;
|
||||
|
||||
// Mode Parameter header
|
||||
int offset = 0;
|
||||
if (length >= 12) {
|
||||
// Check the block length
|
||||
if (buf[9] != (BYTE)(sector_size >> 16) || buf[10] != (BYTE)(sector_size >> 8) ||
|
||||
buf[11] != (BYTE)sector_size) {
|
||||
// See below for details
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
offset += 12;
|
||||
length -= 12;
|
||||
}
|
||||
|
||||
// Parsing the page
|
||||
// TODO The length handling is wrong in case of length < size
|
||||
// Parse the pages
|
||||
while (length > 0) {
|
||||
// Format device page
|
||||
if (int page = buf[offset]; page == 0x03) {
|
||||
if (length < 14) {
|
||||
throw scsi_exception(sense_key::ILLEGAL_REQUEST, asc::INVALID_FIELD_IN_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
// With this page the sector size for a subsequent FORMAT can be selected, but only very few
|
||||
// drives support this, e.g FUJITSU M2624S
|
||||
// We are fine as long as the current sector size remains unchanged
|
||||
if (buf[offset + 0xc] != (BYTE)(sector_size >> 8) || buf[offset + 0xd] != (BYTE)sector_size) {
|
||||
if (GetInt16(buf, offset + 12) != sector_size) {
|
||||
// With rascsi it is not possible to permanently (by formatting) change the sector size,
|
||||
// because the size is an externally configurable setting only
|
||||
LOGWARN("In order to change the sector size use the -b option when launching rascsi")
|
||||
@ -63,6 +61,7 @@ void scsi_command_util::ModeSelect(const vector<int>& cdb, const vector<BYTE>& b
|
||||
|
||||
// Advance to the next page
|
||||
int size = buf[offset + 1] + 2;
|
||||
|
||||
length -= size;
|
||||
offset += size;
|
||||
}
|
||||
@ -92,30 +91,45 @@ void scsi_command_util::AddAppleVendorModePage(map<int, vector<byte>>& pages, bo
|
||||
// No changeable area
|
||||
if (!changeable) {
|
||||
const char APPLE_DATA[] = "APPLE COMPUTER, INC ";
|
||||
memcpy(&buf[2], APPLE_DATA, sizeof(APPLE_DATA));
|
||||
memcpy(&buf.data()[2], APPLE_DATA, sizeof(APPLE_DATA));
|
||||
}
|
||||
|
||||
pages[48] = buf;
|
||||
}
|
||||
|
||||
int scsi_command_util::GetInt16(const vector<BYTE>& buf, int offset)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 1);
|
||||
|
||||
return ((int)buf[offset] << 8) | buf[offset + 1];
|
||||
}
|
||||
|
||||
int scsi_command_util::GetInt16(const vector<int>& buf, int offset)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 1);
|
||||
|
||||
return (buf[offset] << 8) | buf[offset + 1];
|
||||
}
|
||||
|
||||
int scsi_command_util::GetInt24(const vector<int>& buf, int offset)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 2);
|
||||
|
||||
return (buf[offset] << 16) | (buf[offset + 1] << 8) | buf[offset + 2];
|
||||
}
|
||||
|
||||
uint32_t scsi_command_util::GetInt32(const vector<int>& buf, int offset)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 3);
|
||||
|
||||
return ((uint32_t)buf[offset] << 24) | ((uint32_t)buf[offset + 1] << 16) |
|
||||
((uint32_t)buf[offset + 2] << 8) | (uint32_t)buf[offset + 3];
|
||||
}
|
||||
|
||||
uint64_t scsi_command_util::GetInt64(const vector<int>& buf, int offset)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 7);
|
||||
|
||||
return ((uint64_t)buf[offset] << 56) | ((uint64_t)buf[offset + 1] << 48) |
|
||||
((uint64_t)buf[offset + 2] << 40) | ((uint64_t)buf[offset + 3] << 32) |
|
||||
((uint64_t)buf[offset + 4] << 24) | ((uint64_t)buf[offset + 5] << 16) |
|
||||
@ -124,12 +138,16 @@ uint64_t scsi_command_util::GetInt64(const vector<int>& buf, int offset)
|
||||
|
||||
void scsi_command_util::SetInt16(vector<byte>& buf, int offset, int value)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 1);
|
||||
|
||||
buf[offset] = (byte)(value >> 8);
|
||||
buf[offset + 1] = (byte)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt32(vector<byte>& buf, int offset, uint32_t value)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 3);
|
||||
|
||||
buf[offset] = (byte)(value >> 24);
|
||||
buf[offset + 1] = (byte)(value >> 16);
|
||||
buf[offset + 2] = (byte)(value >> 8);
|
||||
@ -138,12 +156,16 @@ void scsi_command_util::SetInt32(vector<byte>& buf, int offset, uint32_t value)
|
||||
|
||||
void scsi_command_util::SetInt16(vector<BYTE>& buf, int offset, int value)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 1);
|
||||
|
||||
buf[offset] = (BYTE)(value >> 8);
|
||||
buf[offset + 1] = (BYTE)value;
|
||||
}
|
||||
|
||||
void scsi_command_util::SetInt32(vector<BYTE>& buf, int offset, uint32_t value)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 3);
|
||||
|
||||
buf[offset] = (BYTE)(value >> 24);
|
||||
buf[offset + 1] = (BYTE)(value >> 16);
|
||||
buf[offset + 2] = (BYTE)(value >> 8);
|
||||
@ -152,6 +174,8 @@ void scsi_command_util::SetInt32(vector<BYTE>& buf, int offset, uint32_t value)
|
||||
|
||||
void scsi_command_util::SetInt64(vector<BYTE>& buf, int offset, uint64_t value)
|
||||
{
|
||||
assert(buf.size() > (size_t)offset + 7);
|
||||
|
||||
buf[offset] = (BYTE)(value >> 56);
|
||||
buf[offset + 1] = (BYTE)(value >> 48);
|
||||
buf[offset + 2] = (BYTE)(value >> 40);
|
||||
|
@ -22,6 +22,7 @@ namespace scsi_command_util
|
||||
void EnrichFormatPage(map<int, vector<byte>>&, bool, int);
|
||||
void AddAppleVendorModePage(map<int, vector<byte>>&, bool);
|
||||
|
||||
int GetInt16(const vector<BYTE>&, int);
|
||||
int GetInt16(const vector<int>&, int);
|
||||
int GetInt24(const vector<int>&, int);
|
||||
uint32_t GetInt32(const vector<int>&, int);
|
||||
|
@ -13,18 +13,20 @@
|
||||
|
||||
using namespace scsi_command_util;
|
||||
|
||||
TEST(ScsiCommandUtilTest, ModeSelect)
|
||||
TEST(ScsiCommandUtilTest, ModeSelect6)
|
||||
{
|
||||
const int LENGTH = 12;
|
||||
const int LENGTH = 26;
|
||||
|
||||
vector<int> cdb(16);
|
||||
vector<BYTE> buf(255);
|
||||
vector<int> cdb(6);
|
||||
vector<BYTE> buf(LENGTH);
|
||||
|
||||
// PF (vendor-specific parameter format)
|
||||
cdb[1] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 0), scsi_exception)
|
||||
<< "Vendor-specific parameters are not supported";
|
||||
|
||||
cdb[0] = (int)scsi_command::eCmdModeSelect6;
|
||||
cdb[0] = 0x15;
|
||||
// PF (standard parameter format)
|
||||
cdb[1] = 0x10;
|
||||
// Request 512 bytes per sector
|
||||
@ -35,18 +37,61 @@ TEST(ScsiCommandUtilTest, ModeSelect)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Page 0
|
||||
buf[LENGTH] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_exception)
|
||||
buf[12] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 512), scsi_exception)
|
||||
<< "Unsupported page 0 was not rejected";
|
||||
|
||||
// Page 3 (Format Device Page)
|
||||
buf[LENGTH] = 0x03;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH + 2, 512), scsi_exception)
|
||||
buf[12] = 0x03;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 512), scsi_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Match the requested to the current sector size
|
||||
buf[LENGTH + 12] = 0x02;
|
||||
ModeSelect(cdb, buf, LENGTH + 2, 512);
|
||||
buf[24] = 0x02;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH - 1, 512), scsi_exception)
|
||||
<< "Not enough command parameters";
|
||||
|
||||
ModeSelect(cdb, buf, LENGTH, 512);
|
||||
}
|
||||
|
||||
TEST(ScsiCommandUtilTest, ModeSelect10)
|
||||
{
|
||||
const int LENGTH = 30;
|
||||
|
||||
vector<int> cdb(10);
|
||||
vector<BYTE> buf(LENGTH);
|
||||
|
||||
// PF (vendor-specific parameter format)
|
||||
cdb[1] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 0), scsi_exception)
|
||||
<< "Vendor-specific parameters are not supported";
|
||||
|
||||
cdb[0] = (int)scsi_command::eCmdModeSelect10;
|
||||
// PF (standard parameter format)
|
||||
cdb[1] = 0x10;
|
||||
// Request 512 bytes per sector
|
||||
buf[13] = 0x00;
|
||||
buf[14] = 0x02;
|
||||
buf[15] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 256), scsi_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Page 0
|
||||
buf[16] = 0x00;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 512), scsi_exception)
|
||||
<< "Unsupported page 0 was not rejected";
|
||||
|
||||
// Page 3 (Format Device Page)
|
||||
buf[16] = 0x03;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH, 512), scsi_exception)
|
||||
<< "Requested sector size does not match current sector size";
|
||||
|
||||
// Match the requested to the current sector size
|
||||
buf[28] = 0x02;
|
||||
EXPECT_THROW(ModeSelect(cdb, buf, LENGTH - 1, 512), scsi_exception)
|
||||
<< "Not enough command parameters";
|
||||
|
||||
ModeSelect(cdb, buf, LENGTH, 512);
|
||||
}
|
||||
|
||||
TEST(ScsiCommandUtilTest, EnrichFormatPage)
|
||||
@ -85,6 +130,9 @@ TEST(ScsiCommandUtilTest, AddAppleVendorModePage)
|
||||
|
||||
TEST(ScsiCommandUtilTest, GetInt16)
|
||||
{
|
||||
vector<BYTE> b = { 0xfe, 0xdc };
|
||||
EXPECT_EQ(0xfedc, GetInt16(b, 0));
|
||||
|
||||
vector<int> v = { 0x12, 0x34 };
|
||||
EXPECT_EQ(0x1234, GetInt16(v, 0));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user