Improved handling of MO capacities

This commit is contained in:
Uwe Seimet 2021-08-29 13:51:31 +02:00
parent 49211fda68
commit 9ff21626da
11 changed files with 182 additions and 99 deletions

View File

@ -17,6 +17,7 @@
#include "exceptions.h"
#include "device_factory.h"
#include <set>
#include <map>
using namespace std;
using namespace rascsi_interface;
@ -30,6 +31,15 @@ DeviceFactory::DeviceFactory()
sector_sizes_scsi.insert(1024);
sector_sizes_scsi.insert(2048);
sector_sizes_scsi.insert(4096);
// 128 MB, 512 bytes per block, 248826 blocks
geometries_mo[0x797f400] = make_pair(512, 248826);
// 230 MB, 512 bytes per sector, 446325 blocks
geometries_mo[0xd9eea00] = make_pair(512, 446325);
// 540 MB, 512 bytes per sector, 1041500 blocks
geometries_mo[0x1fc8b800] = make_pair(512, 1041500);
// 640 MB, 20248 bytes per sector, 310352 blocks
geometries_mo[0x25e28000] = make_pair(2048, 310352);
}
DeviceFactory::~DeviceFactory()
@ -104,6 +114,7 @@ Device *DeviceFactory::CreateDevice(PbDeviceType& type, const string& filename,
device->SetRemovable(true);
device->SetLockable(true);
device->SetProduct("SCSI MO");
((Disk *)device)->SetGeometries(geometries_mo);
break;
case SCCD:
@ -138,3 +149,14 @@ Device *DeviceFactory::CreateDevice(PbDeviceType& type, const string& filename,
return device;
}
const set<uint64_t> DeviceFactory::GetMoCapacities() const
{
set<uint64_t> keys;
for (const auto& geometry : geometries_mo) {
keys.insert(geometry.first);
}
return keys;
}

View File

@ -12,27 +12,37 @@
#pragma once
#include <set>
#include <map>
#include <string>
#include "rascsi_interface.pb.h"
using namespace std;
class Device;
class DeviceFactory
{
public:
typedef pair<uint32_t, uint32_t> Geometry;
DeviceFactory();
~DeviceFactory();
static DeviceFactory& instance();
const std::set<int>& GetSasiSectorSizes() const { return sector_sizes_sasi; };
const std::set<int>& GetScsiSectorSizes() const { return sector_sizes_scsi; };
const set<uint32_t>& GetSasiSectorSizes() const { return sector_sizes_sasi; };
const set<uint32_t>& GetScsiSectorSizes() const { return sector_sizes_scsi; };
Device *CreateDevice(rascsi_interface::PbDeviceType& type, const std::string& filename, const std::string& ext);
const set<uint64_t> GetMoCapacities() const;
Device *CreateDevice(rascsi_interface::PbDeviceType& type, const string& filename, const string& ext);
private:
std::set<int> sector_sizes_sasi;
std::set<int> sector_sizes_scsi;
set<uint32_t> sector_sizes_sasi;
set<uint32_t> sector_sizes_scsi;
// Mapping of supported MO capacities in bytes to the respective block sizes and block counts
map<uint64_t, Geometry> geometries_mo;
};

View File

@ -1746,14 +1746,14 @@ bool Disk::GetStartAndCount(SASIDEV *controller, uint64_t& start, uint32_t& coun
return true;
}
int Disk::GetSectorSizeInBytes() const
uint32_t Disk::GetSectorSizeInBytes() const
{
return disk.size ? 1 << disk.size : 0;
}
void Disk::SetSectorSizeInBytes(int size, bool sasi)
void Disk::SetSectorSizeInBytes(uint32_t size, bool sasi)
{
set<int> sector_sizes = sasi ? DeviceFactory::instance().GetSasiSectorSizes() : DeviceFactory::instance().GetScsiSectorSizes();
set<uint32_t> sector_sizes = sasi ? DeviceFactory::instance().GetSasiSectorSizes() : DeviceFactory::instance().GetScsiSectorSizes();
if (sector_sizes.find(size) == sector_sizes.end()) {
stringstream error;
error << "Invalid sector size of " << size << " bytes";
@ -1787,7 +1787,7 @@ void Disk::SetSectorSizeInBytes(int size, bool sasi)
}
}
int Disk::GetSectorSize() const
uint32_t Disk::GetSectorSize() const
{
return disk.size;
}
@ -1797,17 +1797,17 @@ bool Disk::IsSectorSizeConfigurable() const
return !sector_sizes.empty();
}
void Disk::SetSectorSizes(const set<int>& sector_sizes)
void Disk::SetSectorSizes(const set<uint32_t>& sector_sizes)
{
this->sector_sizes = sector_sizes;
}
int Disk::GetConfiguredSectorSize() const
uint32_t Disk::GetConfiguredSectorSize() const
{
return configured_sector_size;
}
bool Disk::SetConfiguredSectorSize(int configured_sector_size)
bool Disk::SetConfiguredSectorSize(uint32_t configured_sector_size)
{
if (configured_sector_size != 512 && configured_sector_size != 1024 &&
configured_sector_size != 2048 && configured_sector_size != 4096) {
@ -1819,12 +1819,45 @@ bool Disk::SetConfiguredSectorSize(int configured_sector_size)
return true;
}
bool Disk::SetGeometries(const map<uint64_t, DeviceFactory::Geometry>& geometries)
{
if (!IsMo()) {
return false;
}
this->geometries = geometries;
return true;
}
void Disk::SetGeometryForCapacity(uint64_t capacity) {
const auto& geometry = geometries.find(capacity);
if (geometry == geometries.end()) {
ostringstream error;
error << "Invalid file size of " << capacity << " bytes. Supported file sizes are ";
bool isFirst = true;
for (const auto& g : geometries) {
if (!isFirst) {
error << ", ";
}
error << g.first << " bytes";
isFirst = false;
}
error << ".";
throw io_exception(error.str());
}
SetSectorSizeInBytes(geometry->second.first, false);
SetBlockCount(geometry->second.second);
}
uint32_t Disk::GetBlockCount() const
{
return disk.blocks;
}
void Disk::SetBlockCount(DWORD blocks)
void Disk::SetBlockCount(uint32_t blocks)
{
disk.blocks = blocks;
}

View File

@ -21,6 +21,7 @@
#include "scsi.h"
#include "controllers/scsidev_ctrl.h"
#include "device.h"
#include "device_factory.h"
#include "disk_track_cache.h"
#include "file_support.h"
#include "filepath.h"
@ -37,8 +38,12 @@ class Disk : public Device, public ScsiPrimaryCommands, public ScsiBlockCommands
private:
enum access_mode { RW6, RW10, RW16 };
set<int> sector_sizes;
int configured_sector_size;
// The supported configurable block sizes, empty if not configurable
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, DeviceFactory::Geometry> geometries;
SASIDEV::ctrl_t *ctrl;
@ -46,7 +51,7 @@ protected:
// Internal data structure
typedef struct {
int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096)
DWORD blocks; // Total number of sectors
uint32_t blocks; // Total number of sectors
DiskCache *dcache; // Disk cache
off_t imgoffset; // Offset to actual data
} disk_t;
@ -124,16 +129,18 @@ public:
int SelectCheck(const DWORD *cdb); // SELECT check
int SelectCheck10(const DWORD *cdb); // SELECT(10) check
int GetSectorSizeInBytes() const;
void SetSectorSizeInBytes(int, bool);
int GetSectorSize() const;
uint32_t GetSectorSizeInBytes() const;
void SetSectorSizeInBytes(uint32_t, bool);
uint32_t GetSectorSize() const;
bool IsSectorSizeConfigurable() const;
set<int> GetSectorSizes() const;
void SetSectorSizes(const set<int>&);
int GetConfiguredSectorSize() const;
bool SetConfiguredSectorSize(int);
set<uint32_t> GetSectorSizes() const;
void SetSectorSizes(const set<uint32_t>&);
uint32_t GetConfiguredSectorSize() const;
bool SetConfiguredSectorSize(uint32_t);
bool SetGeometries(const map<uint64_t, DeviceFactory::Geometry>&);
void SetGeometryForCapacity(uint64_t);
uint32_t GetBlockCount() const;
void SetBlockCount(DWORD);
void SetBlockCount(uint32_t);
bool GetStartAndCount(SASIDEV *, uint64_t&, uint32_t&, access_mode);
// TODO Try to get rid of this method, which is called by SASIDEV (but must not)

View File

@ -304,7 +304,7 @@ void SCSICD::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw io_exception("Can't open CD-ROM file read-only");
throw file_not_found_exception("Can't open CD-ROM file read-only");
}
// Close and transfer for physical CD access

View File

@ -64,7 +64,7 @@ void SCSIHD::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw io_exception("Can't open hard disk file read-only");
throw file_not_found_exception("Can't open hard disk file read-only");
}
// Get file size

View File

@ -46,48 +46,16 @@ void SCSIMO::Open(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw io_exception("Can't open MO file read-only");
throw file_not_found_exception("Can't open MO file read-only");
}
// Get file size
off_t size = fio.GetFileSize();
fio.Close();
switch (size) {
// 128MB
case 0x797f400:
// 512 bytes per sector
SetSectorSizeInBytes(512, false);
SetBlockCount(248826);
break;
// 230MB
case 0xd9eea00:
// 512 bytes per sector
SetSectorSizeInBytes(512, false);
SetBlockCount(446325);
break;
// 540MB
case 0x1fc8b800:
// 512 bytes per sector
SetSectorSizeInBytes(512, false);
SetBlockCount(1041500);
break;
// 640MB
case 0x25e28000:
// 2048 bytes per sector
SetSectorSizeInBytes(2048, false);
SetBlockCount(310352);
break;
// Other (this is an error)
default:
throw io_exception("Invalid MO file size, supported sizes are 127398912 bytes (128 MB, 512 BPS), "
"228518400 bytes (230 MB, 512 BPS), 533248000 bytes (540 MB, 512 BPS), 635600896 bytes (640 MB, 2048 BPS)");
}
SetGeometryForCapacity(size);
Disk::Open(path);
FileSupport::SetPath(path);

View File

@ -35,9 +35,15 @@ private:
public:
io_exception(const string& _msg) : msg(_msg) {}
~io_exception() {}
virtual ~io_exception() {}
const string& getmsg() const {
return msg;
}
};
class file_not_found_exception : public io_exception {
public:
file_not_found_exception(const string& msg) : io_exception(msg) {}
~file_not_found_exception() {}
};

View File

@ -448,7 +448,7 @@ bool MapController(Device **map)
bool ReturnStatus(int fd, bool status = true, const string msg = "")
{
if (!status && !msg.empty()) {
LOGWARN("%s", msg.c_str());
LOGERROR("%s", msg.c_str());
}
if (fd == -1) {
@ -535,19 +535,18 @@ void GetDeviceTypeFeatures(PbServerInfo& serverInfo)
PbDeviceProperties *properties = new PbDeviceProperties();
types_properties->set_allocated_properties(properties);
properties->set_supports_file(true);
set<int> block_sizes = device_factory.GetSasiSectorSizes();
auto block_sizes = device_factory.GetSasiSectorSizes();
for (const auto& block_size : block_sizes) {
properties->add_block_sizes(block_size);
}
block_sizes = device_factory.GetScsiSectorSizes();
types_properties = serverInfo.add_types_properties();
types_properties->set_type(SCHD);
properties = new PbDeviceProperties();
types_properties->set_allocated_properties(properties);
properties->set_protectable(true);
properties->set_supports_file(true);
block_sizes = device_factory.GetScsiSectorSizes();
for (const auto& block_size : block_sizes) {
properties->add_block_sizes(block_size);
}
@ -572,6 +571,10 @@ void GetDeviceTypeFeatures(PbServerInfo& serverInfo)
properties->set_removable(true);
properties->set_lockable(true);
properties->set_supports_file(true);
auto capacities = device_factory.GetMoCapacities();
for (const auto& capacity : capacities) {
properties->add_capacities(capacity);
}
types_properties = serverInfo.add_types_properties();
types_properties->set_type(SCCD);
@ -755,21 +758,20 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pbDevice, const PbOperation op
filepath.SetPath(filename.c_str());
try {
fileSupport->Open(filepath);
}
catch(const io_exception& e) {
// If the file does not exist search for it in the default image folder
string default_file = default_image_folder + "/" + filename;
filepath.SetPath(default_file.c_str());
try {
fileSupport->Open(filepath);
}
catch(const io_exception&) {
delete device;
return ReturnStatus(fd, false, "Tried to open an invalid file '" + filename + "': " + e.getmsg());
catch(const file_not_found_exception&) {
// If the file does not exist search for it in the default image folder
filepath.SetPath(string(default_image_folder + "/" + filename).c_str());
fileSupport->Open(filepath);
}
}
catch(const io_exception& e) {
delete device;
return ReturnStatus(fd, false, "Tried to open an invalid file '" + string(filepath.GetPath()) + "': " + e.getmsg());
}
const string path = filepath.GetPath();
if (files_in_use.find(path) != files_in_use.end()) {
@ -897,31 +899,44 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pbDevice, const PbOperation op
LOGINFO("Insert file '%s' requested into %s ID %d, unit %d", filename.c_str(), device->GetType().c_str(), id, unit);
try {
fileSupport->Open(filepath);
}
catch(const io_exception& e) {
// If the file does not exist search for it in the default image folder
string default_file = default_image_folder + "/" + filename;
filepath.SetPath(default_file.c_str());
try {
fileSupport->Open(filepath);
}
catch(const io_exception&) {
return ReturnStatus(fd, false, "Tried to open an invalid file '" + filename + "': " + e.getmsg());
catch(const file_not_found_exception&) {
// If the file does not exist search for it in the default image folder
filepath.SetPath(string(default_image_folder + "/" + filename).c_str());
fileSupport->Open(filepath);
}
}
catch(const io_exception& e) {
return ReturnStatus(fd, false, "Tried to open an invalid file '" + string(filepath.GetPath()) + "': " + e.getmsg());
}
const string path = filepath.GetPath();
if (files_in_use.find(path) != files_in_use.end()) {
const auto& full_id = files_in_use[path];
error << "Image file '" << filename << "' is already used by ID " << full_id.first << ", unit " << full_id.second;
return ReturnStatus(fd, false, error);
}
files_in_use[path] = make_pair(device->GetId(), device->GetLun());
}
break;
case EJECT:
if (dryRun) {
return true;
case EJECT: {
if (dryRun) {
return true;
}
LOGINFO("Eject requested for %s ID %d, unit %d", device->GetType().c_str(), id, unit);
// EJECT is idempotent
if (device->Eject(true) && fileSupport) {
Filepath filepath;
fileSupport->GetPath(filepath);
files_in_use.erase(filepath.GetPath());
}
}
LOGINFO("Eject requested for %s ID %d, unit %d", device->GetType().c_str(), id, unit);
// EJECT is idempotent
device->Eject(true);
break;
case PROTECT:

View File

@ -63,8 +63,10 @@ message PbDeviceProperties {
bool supports_file = 5;
// Device supports parameters other than a filename
bool supports_params = 6;
// Unordered list of supported block sizes, empty if the block size is not configurable
// Unordered list of supported block sizes in bytes, empty if the block size is not configurable
repeated uint32 block_sizes = 7;
// Unordered list of supported capacities in bytes, empty if there is no capacity restriction
repeated uint64 capacities = 8;
}
// The status of a device

View File

@ -219,8 +219,6 @@ void CommandServerInfo(const string& hostname, int port)
PbDeviceTypeProperties types_properties = serverInfo.types_properties(i);
cout << " " << PbDeviceType_Name(types_properties.type());
list<int> block_sizes;
cout << " Properties: ";
bool has_property = false;
const PbDeviceProperties& properties = types_properties.properties();
@ -254,15 +252,15 @@ void CommandServerInfo(const string& hostname, int port)
}
cout << endl;
for (int k = 0 ; k < properties.block_sizes_size(); k++)
{
list<uint32_t> block_sizes;
for (int k = 0 ; k < properties.block_sizes_size(); k++) {
block_sizes.push_back(properties.block_sizes(k));
}
if (!block_sizes.empty()) {
block_sizes.sort([](const int& a, const int& b) { return a < b; });
block_sizes.sort([](const auto& a, const auto& b) { return a < b; });
cout << " Configurable block sizes: ";
cout << " Configurable block sizes in bytes: ";
bool isFirst = true;
for (const auto& block_size : block_sizes) {
@ -275,6 +273,28 @@ void CommandServerInfo(const string& hostname, int port)
}
cout << endl;
}
list<uint64_t> capacities;
for (int k = 0; k < properties.capacities_size(); k++) {
capacities.push_back(properties.capacities(k));
}
if (!capacities.empty()) {
capacities.sort([](const auto& a, const auto& b) { return a < b; });
cout << " Supported capacities in bytes: ";
bool isFirst = true;
for (const auto& capacity : capacities) {
if (!isFirst) {
cout << ", ";
}
cout << capacity;
isFirst = false;
}
cout << endl;
}
}
cout << "Attached devices:" << endl;