From d239b8158430c022e517b536e434326a3449179d Mon Sep 17 00:00:00 2001 From: Uwe Seimet Date: Sat, 26 Oct 2024 18:29:14 +0200 Subject: [PATCH] Update handling of allocation length for SCSI-1-CCS, update tape error code --- cpp/base/primary_device.cpp | 6 +++++- cpp/devices/tape.cpp | 24 ++++++++++++++++++------ cpp/test/host_services_test.cpp | 9 ++++++++- cpp/test/mocks.h | 1 + cpp/test/tape_test.cpp | 4 ++-- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/cpp/base/primary_device.cpp b/cpp/base/primary_device.cpp index 2eab5b66..6c54dc42 100644 --- a/cpp/base/primary_device.cpp +++ b/cpp/base/primary_device.cpp @@ -191,7 +191,11 @@ void PrimaryDevice::RequestSense() const vector &buf = GetController()->GetDeviceForLun(effective_lun)->HandleRequestSense(); - const auto length = static_cast(min(buf.size(), static_cast(GetCdbByte(4)))); + int allocation_length = GetCdbByte(4); + if (!allocation_length && level == scsi_level::scsi_1_ccs) { + allocation_length = 4; + } + const auto length = static_cast(min(buf.size(), static_cast(allocation_length))); GetController()->CopyToBuffer(buf.data(), length); // Clear the previous status diff --git a/cpp/devices/tape.cpp b/cpp/devices/tape.cpp index b9307ab7..dc2c9f3e 100644 --- a/cpp/devices/tape.cpp +++ b/cpp/devices/tape.cpp @@ -203,7 +203,7 @@ int Tape::WriteData(span buf, scsi_command) const int length = GetController()->GetChunkSize(); if (static_cast(position + length) > GetFileSize()) { - throw scsi_exception(sense_key::blank_check); + throw scsi_exception(sense_key::volume_overflow); } if (!tar_mode) { @@ -291,7 +291,7 @@ void Tape::SetUpModePages(map> &pages, int page, bool changeab AddDeviceConfigurationPage(pages, changeable); } - // Page 17 (medium partition page) + // Page 17 (medium partition page 1) if (page == 0x11 || page == 0x3f) { AddMediumPartitionPage(pages, changeable); } @@ -342,11 +342,23 @@ void Tape::AddDeviceConfigurationPage(map> &pages, bool change void Tape::AddMediumPartitionPage(map > &pages, bool changeable) const { - vector buf(8); + vector buf(10); if (!changeable) { - // Fixed data partitions, PSUM (descriptor unit in MB) - buf[4] = (byte)0b10010000; + // Maximum additional partitions + buf[2] = (byte)1; + + // PSUM (descriptor unit in MB) + buf[4] = (byte)0b00010000; + + // Logical unit is capable of format and partition recognition + buf[5] = (byte)0x03; + + // Approximate partition size in MB + if (IsReady()) { + const auto capacity = static_cast(GetFileSize()) / 1048576; + SetInt16(buf, 8, capacity > 0 ? capacity : 1); + } } pages[17] = buf; @@ -560,7 +572,7 @@ void Tape::WriteMetaData(Tape::object_type type, uint32_t size) assert(size < 65536); if (static_cast(position + sizeof(meta_data_t)) > GetFileSize()) { - throw scsi_exception(sense_key::blank_check); + throw scsi_exception(sense_key::volume_overflow); } meta_data_t meta_data; diff --git a/cpp/test/host_services_test.cpp b/cpp/test/host_services_test.cpp index a2780b02..a3ebbec4 100644 --- a/cpp/test/host_services_test.cpp +++ b/cpp/test/host_services_test.cpp @@ -92,6 +92,9 @@ TEST(HostServicesTest, ExecuteOperation) controller->SetCdbByte(1, 0b001); TestShared::Dispatch(*services, scsi_command::execute_operation, sense_key::illegal_request, asc::invalid_field_in_cdb, "Illegal length"); + + controller->SetCdbByte(8, 1); + EXPECT_NO_THROW(services->Dispatch(scsi_command::execute_operation)); } TEST(HostServicesTest, ReceiveOperationResults) @@ -203,6 +206,10 @@ TEST(HostServicesTest, SetUpModePages) TEST(HostServicesTest, WriteData) { auto [controller, services] = CreateDevice(SCHS); + array buf = { }; + + EXPECT_EQ(0, services->WriteData(buf, scsi_command::execute_operation)); - EXPECT_EQ(0, services->WriteData( { }, scsi_command::execute_operation)); + controller->SetCdbByte(8, 1); + EXPECT_THROW(services->WriteData(buf, scsi_command::execute_operation), scsi_exception)<< "protobuf data are invalid"; } diff --git a/cpp/test/mocks.h b/cpp/test/mocks.h index 97c6c234..d561ad40 100644 --- a/cpp/test/mocks.h +++ b/cpp/test/mocks.h @@ -150,6 +150,7 @@ class MockAbstractController : public AbstractController // NOSONAR Having many FRIEND_TEST(HostServicesTest, StartStopUnit); FRIEND_TEST(HostServicesTest, ExecuteOperation); FRIEND_TEST(HostServicesTest, ReceiveOperationResults); + FRIEND_TEST(HostServicesTest, WriteData); FRIEND_TEST(HostServicesTest, ModeSense6); FRIEND_TEST(HostServicesTest, ModeSense10); FRIEND_TEST(HostServicesTest, SetUpModePages); diff --git a/cpp/test/tape_test.cpp b/cpp/test/tape_test.cpp index daeb73f6..186c5748 100644 --- a/cpp/test/tape_test.cpp +++ b/cpp/test/tape_test.cpp @@ -26,7 +26,7 @@ static void ValidateModePages(map> &pages) EXPECT_EQ(8U, pages[10].size()); EXPECT_EQ(14U, pages[15].size()); EXPECT_EQ(16U, pages[16].size()); - EXPECT_EQ(8U, pages[17].size()); + EXPECT_EQ(10U, pages[17].size()); } static void CheckPosition(AbstractController &controller, PrimaryDevice &tape, uint32_t position) @@ -278,7 +278,7 @@ TEST(TapeTest, WriteFileMarks6) // Count > 0 controller->SetCdbByte(2, 1); - TestShared::Dispatch(*tape, scsi_command::write_filemarks6, sense_key::blank_check, + TestShared::Dispatch(*tape, scsi_command::write_filemarks6, sense_key::volume_overflow, asc::no_additional_sense_information); tape->SetProtected(true);