mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-23 06:30:04 +00:00
Improved handling of MO capacities
This commit is contained in:
parent
49211fda68
commit
9ff21626da
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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() {}
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user