diff --git a/doc/rascsi.1 b/doc/rascsi.1 index 1ce9523d..5a67f411 100644 --- a/doc/rascsi.1 +++ b/doc/rascsi.1 @@ -42,6 +42,9 @@ To quit RaSCSI, press Control + C. If it is running in the background, you can k .SH OPTIONS .TP +.BR \-b\fI " " \fIBLOCK_SIZE +The optional block size for SCSI hard disk drives, either 512, 1024, 2048 or 4096. The default size 512 bytes. +.TP .BR \-f\fI " " \fIFOLDER The default folder for image files. For files in this folder no absolute path needs to be specified. The initial default folder is '~/images'. .TP diff --git a/doc/rascsi_man_page.txt b/doc/rascsi_man_page.txt index 2ad09f86..b0c8bb35 100644 --- a/doc/rascsi_man_page.txt +++ b/doc/rascsi_man_page.txt @@ -49,31 +49,35 @@ DESCRIPTION you can kill it using an INT signal. OPTIONS + -b BLOCK_SIZE + The optional block size for SCSI hard disk drives, either 512, + 1024, 2048 or 4096. The default size 512 bytes. + -f FOLDER - The default folder for image files. For files in this folder no - absolute path needs to be specified. The initial default folder + The default folder for image files. For files in this folder no + absolute path needs to be specified. The initial default folder is '~/images'. -g LOG_LEVEL - The rascsi log level (trace, debug, info, warn, err, critical, + The rascsi log level (trace, debug, info, warn, err, critical, off). The default log level is 'info'. -h Show a help page. -n VENDOR:PRODUCT:REVISION - Set the vendor, product and revision for the device, to be re‐ - turned with the INQUIRY data. A complete set of name components + Set the vendor, product and revision for the device, to be re‐ + turned with the INQUIRY data. A complete set of name components must be provided. VENDOR may have up to 8, PRODUCT up to 16, RE‐ - VISION up to 4 characters. Padding with blanks to the maxium - length is automatically applied. Once set the name of a device + VISION up to 4 characters. Padding with blanks to the maxium + length is automatically applied. Once set the name of a device cannot be changed. -p PORT The rascsi server port, default is 6868. -p TYPE - The optional case-insensitive device type (SAHD, SCHD, SCRM, - SCCD, SCMO, SCBR, SCDP). If no type is specified for devices + The optional case-insensitive device type (SAHD, SCHD, SCRM, + SCCD, SCMO, SCBR, SCDP). If no type is specified for devices that support an image file, rascsi tries to derive the type from the file extension. @@ -82,8 +86,8 @@ OPTIONS -IDn FILE n is the SCSI ID number (0-7) - FILE is the name of the image file to use for the SCSI device. - For devices that do not support an image file (SCBR, SCDP) a + FILE is the name of the image file to use for the SCSI device. + For devices that do not support an image file (SCBR, SCDP) a dummy name must be provided. -HDn FILE @@ -91,7 +95,7 @@ OPTIONS FILE is the name of the image file to use for the SASI device. - Note: SASI usage is rare, and is typically limited to early + Note: SASI usage is rare, and is typically limited to early Sharp X68000 systems. EXAMPLES @@ -103,7 +107,7 @@ EXAMPLES rascsi -ID0 /path/to/harddrive.hda -ID2 /path/to/cdimage.iso Launch RaSCSI with a removable SCSI drive image as ID 0 and the raw de‐ - vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter + vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter as ID 6: rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp DUMMY_FILENAME diff --git a/doc/rasctl.1 b/doc/rasctl.1 index 3d91d38a..fc3f1ead 100644 --- a/doc/rasctl.1 +++ b/doc/rasctl.1 @@ -59,6 +59,9 @@ Command is the operation being requested. options are: .IP eject, protect and unprotect are idempotent. .TP +.BR \-b\fI " " \fIBLOCK_SIZE +The optional block size for SCSI hard disk drives, either 512, 1024, 2048 or 4096. The default size is 512 bytes. +.TP .BR \-f\fI " " \fIFILE Path to the disk image file. See the rascsi(1) man page for allowable file types. .TP diff --git a/doc/rasctl_man_page.txt b/doc/rasctl_man_page.txt index 1771b605..a8b681b0 100644 --- a/doc/rasctl_man_page.txt +++ b/doc/rasctl_man_page.txt @@ -52,32 +52,36 @@ OPTIONS eject, protect and unprotect are idempotent. + -b BLOCK_SIZE + The optional block size for SCSI hard disk drives, either 512, + 1024, 2048 or 4096. The default size is 512 bytes. + -f FILE - Path to the disk image file. See the rascsi(1) man page for al‐ + Path to the disk image file. See the rascsi(1) man page for al‐ lowable file types. -t TYPE - Specifies the device type. This type overrides the type derived + Specifies the device type. This type overrides the type derived from the file extension of the specified image. See the - rascsi(1) man page for the available device types. Legacy drive + rascsi(1) man page for the available device types. Legacy drive types are: hd: Hard disk (SCSI or SASI) mo: Magneto-Optical disk cd: CD-ROM - bridge: Bridge device (This is only applicable to the Sharp + bridge: Bridge device (This is only applicable to the Sharp X68000) -u VENDOR:PRODUCT:REVISION - The vendor, product and revision for the device, to be returned + The vendor, product and revision for the device, to be returned with the INQUIRY data. A complete set of name components must be provided. VENDOR may have up to 8, PRODUCT up to 16, REVISION up to 4 characters. Padding with blanks to the maxium length is au‐ - tomatically applied. Once set the name of a device cannot be + tomatically applied. Once set the name of a device cannot be changed. -u UNIT - Unit number (0 or 1). This will default to 0. This option is - only used when there are multiple SCSI devices on a shared SCSI + Unit number (0 or 1). This will default to 0. This option is + only used when there are multiple SCSI devices on a shared SCSI controller. (This is not common) EXAMPLES diff --git a/src/raspberrypi/devices/device.h b/src/raspberrypi/devices/device.h index 87a85c89..09df9099 100644 --- a/src/raspberrypi/devices/device.h +++ b/src/raspberrypi/devices/device.h @@ -70,6 +70,9 @@ private: bool lockable; bool locked; + // The block size is configurable + bool block_size_configurable; + // Device ID and LUN unsigned int id; unsigned int lun; diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index b0e5f8fc..817cd11d 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -702,6 +702,8 @@ void DiskCache::Update() Disk::Disk(const std::string id) : BlockDevice(id) { // Work initialization + sector_size_configurable = false; + configured_sector_size = 0; disk.size = 0; disk.blocks = 0; disk.dcache = NULL; @@ -1965,6 +1967,26 @@ void Disk::SetSectorSize(int size) disk.size = size; } +bool Disk::IsSectorSizeConfigurable() const +{ + return sector_size_configurable; +} + +void Disk::SetSectorSizeConfigurable(bool sector_size_configurable) +{ + this->sector_size_configurable = sector_size_configurable; +} + +int Disk::GetConfiguredSectorSize() const +{ + return configured_sector_size; +} + +void Disk::SetConfiguredSectorSize(int configured_sector_size) +{ + this->configured_sector_size = configured_sector_size; +} + DWORD Disk::GetBlockCount() const { return disk.blocks; diff --git a/src/raspberrypi/devices/disk.h b/src/raspberrypi/devices/disk.h index 8cb755e2..3cfd9987 100644 --- a/src/raspberrypi/devices/disk.h +++ b/src/raspberrypi/devices/disk.h @@ -36,8 +36,8 @@ public: // Internal data definition typedef struct { int track; // Track Number - int size; // Sector Size(8 or 9) - int sectors; // Number of sectors(<=0x100) + int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) + int sectors; // Number of sectors(<0x100) DWORD length; // Data buffer length BYTE *buffer; // Data buffer BOOL init; // Is it initilized? @@ -111,7 +111,7 @@ private: cache_t cache[CacheMax]; // Cache management DWORD serial; // Last serial number Filepath sec_path; // Path - int sec_size; // Sector size (8 or 9 or 11) + int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) int sec_blocks; // Blocks per sector BOOL cd_raw; // CD-ROM RAW mode off_t imgoffset; // Offset to actual data @@ -124,10 +124,14 @@ private: //=========================================================================== class Disk : public BlockDevice { +private: + bool sector_size_configurable; + int configured_sector_size; + protected: // Internal data structure typedef struct { - int size; // Sector Size + int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) DWORD blocks; // Total number of sectors DiskCache *dcache; // Disk cache off_t imgoffset; // Offset to actual data @@ -171,6 +175,10 @@ public: int ReportLuns(const DWORD *cdb, BYTE *buf); // REPORT LUNS command int GetSectorSize() const; void SetSectorSize(int); + bool IsSectorSizeConfigurable() const; + void SetSectorSizeConfigurable(bool); + int GetConfiguredSectorSize() const; + void SetConfiguredSectorSize(int); DWORD GetBlockCount() const; void SetBlockCount(DWORD); // TODO Currently not called diff --git a/src/raspberrypi/devices/scsihd.cpp b/src/raspberrypi/devices/scsihd.cpp index 5e1380bf..f3092707 100644 --- a/src/raspberrypi/devices/scsihd.cpp +++ b/src/raspberrypi/devices/scsihd.cpp @@ -34,6 +34,7 @@ SCSIHD::SCSIHD(bool removable) : Disk(removable ? "SCRM" : "SCHD") { SetRemovable(removable); SetProtectable(true); + SetSectorSizeConfigurable(true); } //--------------------------------------------------------------------------- @@ -81,9 +82,9 @@ void SCSIHD::Open(const Filepath& path) throw io_exception("File size must not exceed 2 TB"); } - // sector size 512 bytes and number of blocks - SetSectorSize(9); - SetBlockCount((DWORD)(size >> 9)); + // sector size (default 512 bytes) and number of blocks + SetSectorSize(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 9); + SetBlockCount((DWORD)(size >> GetSectorSize())); LOGINFO("Media capacity for image file '%s': %d blocks", path.GetPath(),GetBlockCount()); diff --git a/src/raspberrypi/devices/scsihd_nec.cpp b/src/raspberrypi/devices/scsihd_nec.cpp index 497a2cbf..0f8d0fb1 100644 --- a/src/raspberrypi/devices/scsihd_nec.cpp +++ b/src/raspberrypi/devices/scsihd_nec.cpp @@ -31,6 +31,8 @@ //--------------------------------------------------------------------------- SCSIHD_NEC::SCSIHD_NEC() : SCSIHD() { + SetSectorSizeConfigurable(false); + SetVendor("NEC"); // Work initialization diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index a3c4c5aa..ce92a5e8 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -590,7 +590,8 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pbDevice, const PbOperation cm ostringstream s; s << (dryRun ? "Validating: " : "Executing: "); s << "cmd=" << PbOperation_Name(cmd) << ", id=" << id << ", unit=" << unit << ", type=" << PbDeviceType_Name(type) - << ", filename='" << filename << "', device name='" << pbDevice.name() << "', params='" << params << "'"; + << ", filename='" << filename << "', device name='" << pbDevice.name() + << "', block size=" << pbDevice.block_size() << ", params='" << params << "'"; LOGINFO("%s", s.str().c_str()); // Check the Controller Number @@ -648,6 +649,36 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pbDevice, const PbOperation cm device->SetProtected(pbDevice.protected_()); } + if (pbDevice.block_size()) { + Disk *disk = dynamic_cast(device); + if (disk && disk->IsSectorSizeConfigurable()) { + switch (pbDevice.block_size()) { + case 512: + disk->SetConfiguredSectorSize(9); + break; + + case 1024: + disk->SetConfiguredSectorSize(10); + break; + + case 2048: + disk->SetConfiguredSectorSize(11); + break; + + case 4096: + disk->SetConfiguredSectorSize(12); + break; + + default: + error << "Invalid block size " << pbDevice.block_size(); + return ReturnStatus(fd, false, error); + } + } + else { + return ReturnStatus(fd, false, "Block size is not configurable for device type " + PbDeviceType_Name(type)); + } + } + FileSupport *fileSupport = dynamic_cast(device); // File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later) @@ -886,12 +917,13 @@ bool ParseArgument(int argc, char* argv[], int& port) bool is_sasi = false; int max_id = 7; PbDeviceType type = UNDEFINED; + int block_size = 0; string name; string log_level; opterr = 1; int opt; - while ((opt = getopt(argc, argv, "-IiHhG:g:D:d:N:n:T:t:P:p:f:Vv")) != -1) { + while ((opt = getopt(argc, argv, "-IiHhG:g:D:d:B:b:N:n:T:t:P:p:f:Vv")) != -1) { switch (tolower(opt)) { case 'i': is_sasi = false; @@ -905,6 +937,11 @@ bool ParseArgument(int argc, char* argv[], int& port) id = -1; continue; + case 'b': { + block_size = atoi(optarg); + continue; + } + case 'g': log_level = optarg; continue; @@ -976,11 +1013,14 @@ bool ParseArgument(int argc, char* argv[], int& port) device->set_id(id); device->set_unit(unit); device->set_type(type); + device->set_block_size(block_size); device->set_name(name); device->set_file(optarg); id = -1; type = UNDEFINED; + block_size = 0; + name = ""; } if (!log_level.empty() && !SetLogLevel(log_level)) { diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index 45842937..0ab7b1bd 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -61,10 +61,13 @@ message PbDeviceDefinition { int32 id = 1; int32 unit = 2; PbDeviceType type = 3; - string file = 4; + // The optional SCSI hard disk drive block size in bytes per sector, must be 512, 1024, 2048 or 4096 + int32 block_size = 4; + // The optional name of the image file + string file = 5; // The device name, format is VENDOR:PRODUCT:REVISION - string name = 5; - bool protected = 6; + string name = 6; + bool protected = 7; } message PbDeviceDefinitions { @@ -80,22 +83,23 @@ message PbDevice { string vendor = 5; string product = 6; string revision = 7; + int32 block_size = 8; // Read-only media (e.g. CD-ROMs) are not protectable but read-only all the time - bool read_only = 8; + bool read_only = 9; // Media can be write-protected - bool protectable = 9; + bool protectable = 10; // Media is write-protected - bool protected = 10; + bool protected = 11; // Media can be removed - bool removable = 11; + bool removable = 12; // Media is removed - bool removed = 12; + bool removed = 13; // Media can be locked - bool lockable = 13; + bool lockable = 14; // Media is locked - bool locked = 14; + bool locked = 15; // Device supports image file - bool supports_file = 15; + bool supports_file = 16; } message PbDevices { diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index 6a206861..f1954581 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -270,11 +270,12 @@ int main(int argc, char* argv[]) if (argc < 2) { cerr << "SCSI Target Emulator RaSCSI Controller" << endl; cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl; - cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-n NAME] [-f FILE] [-d DEFAULT_IMAGE_FOLDER] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v]" << endl; + cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE] [-d DEFAULT_IMAGE_FOLDER] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v]" << endl; cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl; - cerr << " UNIT := {0|1} default setting is 0." << endl; + cerr << " UNIT := {0|1}, default setting is 0." << endl; cerr << " CMD := {attach|detach|insert|eject|protect|unprotect}" << endl; cerr << " TYPE := {sahd|schd|scrm|sccd|scmo|scbr|scdp} or legacy types {hd|mo|cd|bridge}" << endl; + cerr << " BLOCK_SIZE := {512|1024|2048|4096) bytes per hard disk drive block" << endl; cerr << " NAME := name of device to attach (VENDOR:PRODUCT:REVISION)" << endl; cerr << " FILE := image file path" << endl; cerr << " DEFAULT_IMAGE_FOLDER := default location for image files, default is '~/images'" << endl; @@ -302,7 +303,7 @@ int main(int argc, char* argv[]) opterr = 1; int opt; - while ((opt = getopt(argc, argv, "i:u:c:t:f:d:h:n:p:u:g:lsv")) != -1) { + while ((opt = getopt(argc, argv, "b:i:u:c:t:f:d:h:n:p:u:g:lsv")) != -1) { switch (opt) { case 'i': device->set_id(optarg[0] - '0'); @@ -312,6 +313,10 @@ int main(int argc, char* argv[]) device->set_unit(optarg[0] - '0'); break; + case 'b': + device->set_block_size(atoi(optarg)); + break; + case 'c': command.set_cmd(ParseOperation(optarg)); break;