Refactoring, device handling extensions, additional settings, improved error handling, 64 bit OS support, fixed issues (#184)

* Device type unification, support of removable media

* Added support for .hdr extension

* Removable flag cleanup

* Manpage update

* Enriched PbOperation with PbDevice

* Added file size to PbImageFile

* Added device list support

* Set image_file

* Make remote interface more robust by ignoring SIGPIPE

* Return status only once

* Fixed typo

* Error handling update

* When starting rascsi parse everything before attaching devices

* Added dry run mode

* Comment update

* Updated logging

* Added Device base class, Disk class inherits from it

* Renaming

* Use vectors for controllers and disks, as preparation for using maps

* Updated file support handling

* Comment update

* DaynaPort and Bridge inherit from Device instead of Disk

* ProcessCmd() now works with devices instead of disks

* Renaming

* Added DeviceFactory

* Improved factory

* Comment update

* protected disk_t

* Code cleanup, added translations

* Device name can be set for rascsi

* rasctl can set device name

* Manpage update

* Manpage update

* Formatting update

* Check for missing name

* Initialize fd

* Initialize type

* Fixed string length issue

* Updated capacity formatting

* Fixed typo

* Split PbDevice into device and device definition

* Added TODO

* Renaming

* Renaming

* Device types can be explicitly specified with -t (no FILE:TYPE syntax anymore)

* Fixed compile-time issue

* Removed unused Append mode, updated read-only handling

* Type handling and manpage update

* Cleanup

* rasctl parser cleanup

* Review

* Constructor update

* Added .hdr (SCRM) support to web interface, tested web interface

* Default folder can be set remotely

* Removed deprecated operation

* DETACH supports all parameters in order to detach all devices

* include cleanup

* Logging should not depend on NDEBUG, for RaSCSI it is not peformance-critical

* INFO is default log level

* Exception renaming

* Updated GetPaddedName()

* Inheritance update

* Added BlockDevice class

* Removed unused code

* Updated typedefs

* Revert "Updated typedefs"

This reverts commit 546b46215a.

* Removed unused code

* Fixed warnign

* Use standard C++ integer types, use streams to resolve printf data type issues

* Added TODOs

* Added TODO

* Renaming

* Added TODO

* Added TODO

* Improved dry-run

* Code cleanup

* Updated handling of unknown options, code review and cleanup

* Manpage update

* Added PrimaryDevice

* Include cleanup

* Added pure virtual methods

* Comment updates

* Split rasutil

* Replaced some occurrences of BOOL

* Removed obsolete RASCSI definition in xm6.h

* Removed unused code, updated TODOs, replaced BOOL

* Added capacity check (issue #192)

* Fixed (most likely) https://github.com/akuker/RASCSI/issues/191

* Fixed wrong error messages

* For root the default image folder is /home/pi/images, updated error handling

* Dynaport code review

* Improved error handling

* Implemented READ CAPACITY(16)

* Comment update

* Commands can be 16 bytes long

* Implemented READ/WRITE/VERIFY(16)

* Comment update

* Renamed method to reflect the name of the respective SCSI command

* Do not created devices during dryRun

* Fixed padding of SCSIHD_APPLE vendor and product

* Initial implementation

* Updated ReportLuns

* Byte count update

* Fixed typo

* Finalized REPORT LUNS

* Removed TODO

* Updated TODO

* TODO update

* Updated device factory

* Comment update

* 64 bit update, tested on Ubuntu 64 bit system

* Removed assertion

* SCSI hard disks always have Apple specific mode pages (resolves issue #193)

* Error messsage update, 64 bit cleanup

* Reduced streams usage

* Updated handling of device flags

* MOs are protectable

* Removed duplicate error code handling

* Removed duplicate code

* Fixed CmdReadToc buffer overflow (https://github.com/akuker/RASCSI/issues/194)

* Added naive implementation of GET EVENT STATUS NOTIFICATION to avoid wranings

* HD must set removable device bit if the media is removable

* Removed duplicate logging

* Updated daynaport additional length

* Removed broken daynaport REQUEST SENSE. Successfully tested with my Mac.

* EnableInterface should not always return TRUE

* Updated Inquiry

* Updated LUN handling

* Replaced incorrect free by delete

* Updated comments and write-protection handling

* Made default HD name consistent

* STATUS_NOERROR is default

* Fixed Eject

* More eject handling updates

* Manpage updates

* Logging update

* Changed debug level

* Logging update

* Log capacity of all media types

* Logging update

* Encapsulated disk.blocks

* Encapsulated sector size

* Added overrides

* Added more overrides

* Fixed error message

* Fixed typos

* Fixed logging

* Added logging

* Use PrimaryDevice when calling Inquiry

* Comment update

* Changed default buffer size for testing

* Reverted last change

* Removed debug output

* De-inlined methods because optimized code did not work with them inlined

* Web interface can attach Daynaport again

* Improved handling of read-only hard disks

* Fixed issue with "all" semantics of DETACH

* rasctl supports adding removable media devices without providing a filename

* Removed unused flag in PbDeviceDefinition

* Updated rasctl output for ecjected media (resolves issue #199)

* Validate default folder name when changing default folder
This commit is contained in:
Uwe Seimet 2021-08-21 23:45:30 +02:00 committed by GitHub
parent 1c8c3600a7
commit 0bd12e93f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 2744 additions and 2360 deletions

View File

@ -6,7 +6,9 @@ rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins
[\fB\-f\f® \fIFOLDER\fR]
[\fB\-g\f® \fILOG_LEVEL\fR]
[\fB\-h\fR]
[\fB\-n\fR \fIVENDOR:PRODUCT:REVISION\fR]
[\fB\-p\f® \fIPORT\fR]
[\fB\-n\fR \fITYPE\fR]
[\fB\-v\fR]
[\fB\-IDn\fR \fIFILE\fR]
[\fB\-HDn\fR \fIFILE\fR]...
@ -20,7 +22,8 @@ For SCSI: The ID is limited from 0-7. However, typically SCSI ID 7 is reserved f
.PP
RaSCSI will determine the type of device based upon the file extension of the FILE argument.
hdf: SASI Hard Disk image (XM6 SASI HD image - typically only used with X68000)
hds: SCSI Hard Disk image (generic)
hds: SCSI Hard Disk image (generic, non-removable)
hdr: SCSI Hard Disk image (generic, removable)
hdn: SCSI Hard Disk image (NEC GENUINE)
hdi: SCSI Hard Disk image (Anex86 HD image)
nhd: SCSI Hard Disk image (T98Next HD image)
@ -40,29 +43,35 @@ To quit RaSCSI, press Control + C. If it is running in the background, you can k
.SH OPTIONS
.TP
.BR \-f\fI " " \fIFOLDER
The default folder for image files. For files in this folder no absolute path needs to be specified. The default folder is '/home/pi/images'.
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
.BR \-g\fI " " \fILOG_LEVEL
The rascsi log level (trace, debug, info, warn, err, critical, off). The default log level is 'trace'.
The rascsi log level (trace, debug, info, warn, err, critical, off). The default log level is 'info'.
.TP
.BR \-h\fI " " \fI
Show a help page.
.TP
.BR \-n\fI " " \fIVENDOR:PRODUCT:REVISION
Set 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 automatically applied. Once set the name of a device cannot be changed.
.TP
.BR \-p\fI " " \fIPORT
The rascsi server port, default is 6868.
.TP
.BR \-p\fI " " \fITYPE
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.
.TP
.BR \-v\fI " " \fI
Display the rascsi version.
.TP
.BR \-ID\fIn " " \fIFILE[:TYPE]
.BR \-ID\fIn " " \fIFILE
n is the SCSI ID number (0-7)
.IP
FILE is the name of the image file to attach to that ID. An optional explicit device type (SASI_HD, SCSI_HD, CD, MO, BR, NUVOLINK, DAYNAPORT) can be provided after a colon.
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.
.TP
.BR \-HD\fIn " " \fIFILE
n is the SASI ID number (0-15)
.IP
FILE is the name of the image file to attach to that ID. If FILE starts with '/dev/' the extension, which encodes the device type, is stripped, so that device files can conveniently be used as image files.
FILE is the name of the image file to use for the SASI device.
.IP
Note: SASI usage is rare, and is typically limited to early Sharp X68000 systems.
@ -73,8 +82,8 @@ Launch RaSCSI with no emulated drives attached:
Launch RaSCSI with an Apple hard drive image as ID 0 and a CD-ROM as ID 2
rascsi -ID0 /path/to/harddrive.hda -ID2 /path/to/cdimage.iso
Launch RaSCSI with a SCSI hard drive image as ID 0 and the raw device file /dev/hdb (e.g. a USB stick) as a SCSI hard disk image file:
rascsi -ID0 /dev/hdb:SCSI_HD
Launch RaSCSI with a removable SCSI drive image as ID 0 and the raw device 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
To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800

View File

@ -6,82 +6,92 @@ NAME
rascsi - Emulates SCSI devices using the Raspberry Pi GPIO pins
SYNOPSIS
rascsi [-f[u00AE] FOLDER] [-g[u00AE] LOG_LEVEL] [-h] [-p[u00AE] PORT]
[-v] [-IDn FILE] [-HDn FILE]...
rascsi [-f[u00AE] FOLDER] [-g[u00AE] LOG_LEVEL] [-h] [-n VENDOR:PROD
UCT:REVISION] [-p[u00AE] PORT] [-n TYPE] [-v] [-IDn FILE] [-HDn
FILE]...
DESCRIPTION
rascsi Emulates SCSI devices using the Raspberry Pi GPIO pins.
In the arguments to RaSCSI, one or more SCSI (-IDn) or SASI (-HDn) de
vices can be specified. The number (n) after the ID or HD identifier
specifies the ID number for that device. For SCSI: The ID is limited
from 0-7. However, typically SCSI ID 7 is reserved for the "initiator"
In the arguments to RaSCSI, one or more SCSI (-IDn) or SASI (-HDn) de
vices can be specified. The number (n) after the ID or HD identifier
specifies the ID number for that device. For SCSI: The ID is limited
from 0-7. However, typically SCSI ID 7 is reserved for the "initiator"
(the host computer). Note that SASI is considered rare and only used on
very early Sharp X68000 computers.
RaSCSI will determine the type of device based upon the file extension
RaSCSI will determine the type of device based upon the file extension
of the FILE argument.
hdf: SASI Hard Disk image (XM6 SASI HD image - typically only used
hdf: SASI Hard Disk image (XM6 SASI HD image - typically only used
with X68000)
hds: SCSI Hard Disk image (generic)
hds: SCSI Hard Disk image (generic, non-removable)
hdr: SCSI Hard Disk image (generic, removable)
hdn: SCSI Hard Disk image (NEC GENUINE)
hdi: SCSI Hard Disk image (Anex86 HD image)
nhd: SCSI Hard Disk image (T98Next HD image)
hda: SCSI Hard Disk image (APPLE GENUINE - typically used with Mac
hda: SCSI Hard Disk image (APPLE GENUINE - typically used with Mac
SCSI emulation)
mos: SCSI Magneto-optical image (XM6 SCSI MO image - typically only
used with X68000)
iso: SCSI CD-ROM image (ISO 9660 image)
For example, if you want to specify an Apple-compatible HD image on ID
For example, if you want to specify an Apple-compatible HD image on ID
0, you can use the following command:
sudo rascsi -ID0 /path/to/drive/hdimage.hda
Once RaSCSI starts, it will open a socket (default port is 6868) to al
low external management commands. If another process is using the
low external management commands. If another process is using the
rascsi port, RaSCSI will terminate, since it is likely another instance
of RaSCSI. Once RaSCSI has initialized, the rasctl utility can be used
to send commands.
To quit RaSCSI, press Control + C. If it is running in the background,
To quit RaSCSI, press Control + C. If it is running in the background,
you can kill it using an INT signal.
OPTIONS
-f FOLDER
The default folder for image files. For files in this folder no
absolute path needs to be specified. The default folder is
'/home/pi/images'.
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,
off). The default log level is 'trace'.
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
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
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
that support an image file, rascsi tries to derive the type from
the file extension.
-v Display the rascsi version.
-IDn FILE[:TYPE]
-IDn FILE
n is the SCSI ID number (0-7)
FILE is the name of the image file to attach to that ID. If FILE
starts with '/dev/' the extension, which encodes the device
type, is stripped, so that device files can conveniently be used
as image files. An optional explicit device type (SASI_HD,
SCSI_HD, CD, MO, BR, NUVOLINK, DAYNAPORT) can be provided after
a colon.
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
n is the SASI ID number (0-15)
FILE is the name of the image file to attach to that ID. If FILE
starts with '/dev/' the extension, which encodes the device
type, is stripped, so that device files can conveniently be used
as image files.
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
@ -92,9 +102,10 @@ EXAMPLES
2
rascsi -ID0 /path/to/harddrive.hda -ID2 /path/to/cdimage.iso
Launch RaSCSI with a SCSI hard drive image as ID 0 and the raw device
file /dev/hdb (e.g. a USB stick) as an image file:
rascsi -ID0 /dev/hdb.hds
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
as ID 6:
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp DUMMY_FILENAME
To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800

View File

@ -12,6 +12,7 @@ rasctl \- Sends management commands to the rascsi process
\fB\-i\fR \fIID\fR
[\fB\-c\fR \fICMD\fR]
[\fB\-f\fR \fIFILE\fR]
[\fB\-n\fR \fINAME\fR]
[\fB\-t\fR \fITYPE\fR]
[\fB\-u\fR \fIUNIT\fR]
.SH DESCRIPTION
@ -51,23 +52,26 @@ ID is the SCSI ID that you want to control. (0-7)
Command is the operation being requested. options are:
attach: attach disk
detach: detach disk
insert: insert media (Magneto-Optical and CD only)
eject: eject media (Magneto-Optical and CD only)
protect: Write protect the media (Magneto-Optical only)
unprotect: Remove write protection from the media (Magneto-Optical only)
insert: insert media (removable media devices only)
eject: eject media (removable media devices only)
protect: write protect the media (not for CD-ROMs, which are always read-only)
unprotect: remove write protection from the media (not for CD-ROMs, which are always read-only)
.IP
When the command is omitted, rasctl will default to the 'attach' command.
eject, protect and unprotect are idempotent.
.TP
.BR \-f\fI " " \fIFILE
Path to the disk image file. See the rascsi(1) man page for allowable file types.
.TP
.BR \-t\fI " " \fITYPE
Specifies the type of disk. If this disagrees with the file extension of the specified image, the TYPE argument is ignored. Available drive types are:
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 types are:
hd: Hard disk (SCSI or SASI)
mo: Magneto-Optical disk)
mo: Magneto-Optical disk
cd: CD-ROM
bridge: Bridge device (This is only applicable to the Sharp X68000)
.TP
.BR \-u\fI " " \fIVENDOR:PRODUCT:REVISION
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 automatically applied. Once set the name of a device cannot be changed.
.TP
.BR \-u\fI " " \fIUNIT
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)

View File

@ -7,7 +7,7 @@ NAME
SYNOPSIS
rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v] -i ID [-c CMD]
[-f FILE] [-t TYPE] [-u UNIT]
[-f FILE] [-n NAME] [-t TYPE] [-u UNIT]
DESCRIPTION
rasctl Sends commands to the rascsi process to make configuration ad
@ -43,29 +43,38 @@ OPTIONS
-c CMD Command is the operation being requested. options are:
attach: attach disk
detach: detach disk
insert: insert media (Magneto-Optical and CD only)
eject: eject media (Magneto-Optical and CD only)
protect: Write protect the media (Magneto-Optical only)
unprotect: Remove write protection from the media (Magneto-
Optical only)
insert: insert media (removable media devices only)
eject: eject media (removable media devices only)
protect: write protect the media (not for CD-ROMs, which are
always read-only)
unprotect: remove write protection from the media (not for
CD-ROMs, which are always read-only)
When the command is omitted, rasctl will default to the 'attach'
command.
eject, protect and unprotect are idempotent.
-f FILE
Path to the disk image file. See the rascsi(1) man page for al
lowable file types.
-t TYPE
Specifies the type of disk. If this disagrees with the file ex
tension of the specified image, the TYPE argument is ignored.
Available drive types are:
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
types are:
hd: Hard disk (SCSI or SASI)
mo: Magneto-Optical disk)
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
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
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

View File

@ -82,7 +82,8 @@ SRC_RASCSI = \
filepath.cpp \
fileio.cpp\
rascsi_version.cpp \
rasutil.cpp
rasutil.cpp \
protobuf_util.cpp
SRC_RASCSI += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI += $(shell find ./devices -name '*.cpp')
SRC_RASCSI += $(SRC_PROTOBUF)
@ -98,7 +99,8 @@ SRC_SCSIMON = \
SRC_RASCTL = \
rasctl.cpp\
rascsi_version.cpp \
rasutil.cpp
rasutil.cpp \
protobuf_util.cpp
SRC_RASCTL += $(SRC_PROTOBUF)
SRC_RASDUMP = \

View File

@ -19,6 +19,7 @@
#include "devices/scsi_host_bridge.h"
#include "devices/scsi_daynaport.h"
#include "exceptions.h"
#include <sstream>
//===========================================================================
//
@ -33,8 +34,6 @@
//---------------------------------------------------------------------------
SASIDEV::SASIDEV()
{
int i;
// Work initialization
ctrl.phase = BUS::busfree;
ctrl.m_scsi_id = UNKNOWN_SCSI_ID;
@ -54,7 +53,7 @@ SASIDEV::SASIDEV()
ctrl.length = 0;
// Logical unit initialization
for (i = 0; i < UnitMax; i++) {
for (int i = 0; i < UnitMax; i++) {
ctrl.unit[i] = NULL;
}
}
@ -269,7 +268,7 @@ void SASIDEV::BusFree()
ctrl.bus->SetMSG(FALSE);
ctrl.bus->SetCD(FALSE);
ctrl.bus->SetIO(FALSE);
ctrl.bus->SetBSY(FALSE);
ctrl.bus->SetBSY(false);
// Initialize status and message
ctrl.status = 0x00;
@ -309,7 +308,7 @@ void SASIDEV::Selection()
ctrl.phase = BUS::selection;
// Raiase BSY and respond
ctrl.bus->SetBSY(TRUE);
ctrl.bus->SetBSY(true);
return;
}
@ -326,9 +325,6 @@ void SASIDEV::Selection()
//---------------------------------------------------------------------------
void SASIDEV::Command()
{
int count;
int i;
// Phase change
if (ctrl.phase != BUS::command) {
LOGTRACE("%s Command Phase", __PRETTY_FUNCTION__);
@ -347,7 +343,7 @@ void SASIDEV::Command()
ctrl.blocks = 1;
// Command reception handshake (10 bytes are automatically received at the first command)
count = ctrl.bus->CommandHandShake(ctrl.buffer);
int count = ctrl.bus->CommandHandShake(ctrl.buffer);
// If no byte can be received move to the status phase
if (count == 0) {
@ -355,10 +351,7 @@ void SASIDEV::Command()
return;
}
// Check 10-byte CDB
if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) {
ctrl.length = 10;
}
ctrl.length = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
// If not able to receive all, move to the status phase
if (count != (int)ctrl.length) {
@ -367,7 +360,7 @@ void SASIDEV::Command()
}
// Command data transfer
for (i = 0; i < (int)ctrl.length; i++) {
for (int i = 0; i < (int)ctrl.length; i++) {
ctrl.cmd[i] = (DWORD)ctrl.buffer[i];
}
@ -376,14 +369,14 @@ void SASIDEV::Command()
ctrl.blocks = 0;
// Execution Phase
try {
Execute();
}
catch (lunexception& e) {
LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
try {
Execute();
}
catch (lun_exception& e) {
LOGINFO("%s Invalid LUN %d for ID %d", __PRETTY_FUNCTION__, e.getlun(), GetSCSIID());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
}
}
@ -406,11 +399,11 @@ void SASIDEV::Execute()
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((SASIDEV::scsi_command)ctrl.cmd[0] != eCmdRequestSense) {
ctrl.sense_key = 0;
ctrl.asc = 0;
ctrl.status = 0;
}
// Process by command
// TODO This code does not belong here. Each device type needs such a dispatcher, which the controller has to call.
switch ((SASIDEV::scsi_command)ctrl.cmd[0]) {
// TEST UNIT READY
case SASIDEV::eCmdTestUnitReady:
@ -427,9 +420,7 @@ void SASIDEV::Execute()
CmdRequestSense();
return;
// FORMAT UNIT
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
// leaving it here for now....
// FORMAT
case SASIDEV::eCmdFormat:
CmdFormat();
return;
@ -454,7 +445,7 @@ void SASIDEV::Execute()
CmdSeek6();
return;
// ASSIGN(SASIのみ)
// ASSIGN (SASI only)
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
// leaving it here for now....
case SASIDEV::eCmdSasiCmdAssign:
@ -471,7 +462,7 @@ void SASIDEV::Execute()
CmdReleaseUnit();
return;
// SPECIFY(SASIのみ)
// SPECIFY (SASI only)
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
// leaving it here for now....
case SASIDEV::eCmdInvalid:
@ -482,7 +473,6 @@ void SASIDEV::Execute()
}
// Unsupported command
LOGWARN("%s Unsupported command $%02X", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0]);
CmdInvalid();
}
@ -493,15 +483,12 @@ void SASIDEV::Execute()
//---------------------------------------------------------------------------
void SASIDEV::Status()
{
DWORD min_exec_time;
DWORD time;
// Phase change
if (ctrl.phase != BUS::status) {
// Minimum execution time
if (ctrl.execstart > 0) {
min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
time = SysTimer::GetTimerLow() - ctrl.execstart;
DWORD min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
DWORD time = SysTimer::GetTimerLow() - ctrl.execstart;
if (time < min_exec_time) {
SysTimer::SleepUsec(min_exec_time - time);
}
@ -571,17 +558,14 @@ void SASIDEV::MsgIn()
//---------------------------------------------------------------------------
void SASIDEV::DataIn()
{
DWORD min_exec_time;
DWORD time;
ASSERT(ctrl.length >= 0);
// Phase change
if (ctrl.phase != BUS::datain) {
// Minimum execution time
if (ctrl.execstart > 0) {
min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
time = SysTimer::GetTimerLow() - ctrl.execstart;
DWORD min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
DWORD time = SysTimer::GetTimerLow() - ctrl.execstart;
if (time < min_exec_time) {
SysTimer::SleepUsec(min_exec_time - time);
}
@ -622,17 +606,14 @@ void SASIDEV::DataIn()
//---------------------------------------------------------------------------
void SASIDEV::DataOut()
{
DWORD min_exec_time;
DWORD time;
ASSERT(ctrl.length >= 0);
// Phase change
if (ctrl.phase != BUS::dataout) {
// Minimum execution time
if (ctrl.execstart > 0) {
min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
time = SysTimer::GetTimerLow() - ctrl.execstart;
DWORD min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
DWORD time = SysTimer::GetTimerLow() - ctrl.execstart;
if (time < min_exec_time) {
SysTimer::SleepUsec(min_exec_time - time);
}
@ -692,14 +673,18 @@ void SASIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
return;
}
LOGTRACE("%s Sense Key and ASC for subsequent REQUEST SENSE: $%02X, $%02X", __PRETTY_FUNCTION__, sense_key, asc);
// Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.sense_key = sense_key;
ctrl.asc = asc;
// Logical Unit
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
if (!ctrl.unit[lun] || asc == ERROR_CODES::INVALID_LUN) {
lun = 0;
}
LOGTRACE("%s Sense Key and ASC for subsequent REQUEST SENSE: $%02X, $%02X", __PRETTY_FUNCTION__, sense_key, asc);
if (sense_key || asc) {
// Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.unit[lun]->SetStatusCode((sense_key << 16) | (asc << 8));
}
// Set status and message(CHECK CONDITION)
ctrl.status = (lun << 5) | 0x02;
@ -721,7 +706,7 @@ void SASIDEV::CmdTestUnitReady()
{
LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->TestUnitReady(ctrl.cmd);
@ -744,7 +729,7 @@ void SASIDEV::CmdRezero()
{
LOGTRACE( "%s REZERO UNIT Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->Rezero(ctrl.cmd);
@ -771,9 +756,7 @@ void SASIDEV::CmdRequestSense()
try {
lun = GetLun();
}
catch(const lunexception& e) {
LOGINFO("%s Non-existing LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
catch(const lun_exception& e) {
// Note: According to the SCSI specs the LUN handling for REQUEST SENSE is special.
// Non-existing LUNs do *not* result in CHECK CONDITION.
// Only the Sense Key and ASC are set in order to signal the non-existing LUN.
@ -781,22 +764,13 @@ void SASIDEV::CmdRequestSense()
// LUN 0 can be assumed to be present (required to call RequestSense() below)
lun = 0;
ctrl.sense_key = ERROR_CODES::sense_key::ILLEGAL_REQUEST;
ctrl.asc = ERROR_CODES::asc::INVALID_LUN;
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
ASSERT(ctrl.length > 0);
LOGTRACE("%s Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl.sense_key, ctrl.asc);
// REQUEST SENSE returns the sense data set by the previous (failed) command
ctrl.buffer[2] = ctrl.sense_key;
ctrl.buffer[12] = ctrl.asc;
// The sense data are only valid once
ctrl.sense_key = 0;
ctrl.asc = 0;
LOGTRACE("%s Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl.buffer[2], ctrl.buffer[12]);
// Read phase
DataIn();
@ -811,7 +785,7 @@ void SASIDEV::CmdFormat()
{
LOGTRACE( "%s FORMAT UNIT Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->Format(ctrl.cmd);
@ -834,7 +808,7 @@ void SASIDEV::CmdReassign()
{
LOGTRACE("%s REASSIGN BLOCKS Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->Reassign(ctrl.cmd);
@ -891,7 +865,7 @@ void SASIDEV::CmdReleaseUnit()
//---------------------------------------------------------------------------
void SASIDEV::CmdRead6()
{
DWORD lun = GetLun();
DWORD lun = GetLun();
// Get record number and block number
DWORD record = ctrl.cmd[1] & 0x1f;
@ -904,13 +878,26 @@ void SASIDEV::CmdRead6()
ctrl.blocks = 0x100;
}
// TODO This class must not know about SCDP
if(ctrl.unit[lun]->IsDaynaPort()){
// The DaynaPort only wants one block.
// ctrl.cmd[4] and ctrl.cmd[5] are used to specify the maximum buffer size for the DaynaPort
ctrl.blocks=1;
}
else {
// Check capacity
DWORD capacity = ctrl.unit[lun]->GetBlockCount();
if (record > capacity || record + ctrl.blocks > capacity) {
ostringstream s;
s << "ID " << GetSCSIID() << ": Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl.blocks;
LOGWARN("%s", s.str().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
}
LOGTRACE("%s READ(6) command record=%06X blocks=%d ID %s", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks, ctrl.unit[lun]->GetID().c_str());
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
// Command processing on drive
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, ctrl.buffer, record);
@ -933,13 +920,14 @@ void SASIDEV::CmdRead6()
//---------------------------------------------------------------------------
//
// This Send Message command is used by the DaynaPort SCSI/Link
// TODO This class must not know about SCDP
//
//---------------------------------------------------------------------------
void SASIDEV::DaynaPortWrite()
{
DWORD lun = GetLun();
DWORD lun = GetLun();
// Error if not a host bridge
// Error if not a DaynaPort device
if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGERROR("Received DaynaPortWrite for a non-DaynaPort device");
Error();
@ -1008,14 +996,24 @@ void SASIDEV::CmdWrite6()
ctrl.blocks = 0x100;
}
LOGTRACE("%s WRITE(6) command record=%06X blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks);
// Check capacity
DWORD capacity = ctrl.unit[lun]->GetBlockCount();
if (record > capacity || record + ctrl.blocks > capacity) {
ostringstream s;
s << "ID " << GetSCSIID() << ": Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to write block " << record << ", block count " << ctrl.blocks;
LOGWARN("%s", s.str().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
LOGTRACE("%s WRITE(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks);
// Command processing on drive
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
if (ctrl.length <= 0) {
LOGDEBUG("WriteCheck failed");
// Failure (Error)
Error();
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::WRITE_PROTECTED);
return;
}
@ -1035,7 +1033,7 @@ void SASIDEV::CmdSeek6()
{
LOGTRACE("%s SEEK(6) Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->Seek(ctrl.cmd);
@ -1084,7 +1082,7 @@ void SASIDEV::CmdSpecify()
{
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->Assign(ctrl.cmd);
@ -1108,7 +1106,7 @@ void SASIDEV::CmdSpecify()
//---------------------------------------------------------------------------
void SASIDEV::CmdInvalid()
{
LOGWARN("%s Command not supported", __PRETTY_FUNCTION__);
LOGWARN("%s ID %d received unsupported command: $%02X", __PRETTY_FUNCTION__, GetSCSIID(), (BYTE)ctrl.cmd[0]);
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
}
@ -1314,10 +1312,9 @@ BOOL SASIDEV::XferIn(BYTE *buf)
// Limited to read commands
switch (ctrl.cmd[0]) {
// READ(6)
case eCmdRead6:
// READ(10)
case eCmdRead10:
case eCmdRead16:
// Read from disk
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, buf, ctrl.next);
ctrl.next++;
@ -1350,8 +1347,6 @@ BOOL SASIDEV::XferIn(BYTE *buf)
//---------------------------------------------------------------------------
BOOL SASIDEV::XferOut(BOOL cont)
{
SCSIBR *bridge;
ASSERT(ctrl.phase == BUS::dataout);
// Logical Unit
@ -1372,12 +1367,13 @@ BOOL SASIDEV::XferOut(BOOL cont)
case SASIDEV::eCmdWrite6:
case SASIDEV::eCmdWrite10:
case SASIDEV::eCmdWriteAndVerify10:
// If we're a host bridge, use the host bridge's SendMessage10
// function
case SASIDEV::eCmdWrite16:
case SASIDEV::eCmdVerify10:
case SASIDEV::eCmdVerify16:
// If we're a host bridge, use the host bridge's SendMessage10 function
// TODO This class must not know about SCSIBR
if (ctrl.unit[lun]->IsBridge()) {
bridge = (SCSIBR*)ctrl.unit[lun];
if (!bridge->SendMessage10(ctrl.cmd, ctrl.buffer)) {
if (!((SCSIBR*)ctrl.unit[lun])->SendMessage10(ctrl.cmd, ctrl.buffer)) {
// write failed
return FALSE;
}
@ -1388,6 +1384,7 @@ BOOL SASIDEV::XferOut(BOOL cont)
}
// Special case Write function for DaynaPort
// TODO This class must not know about SCSIDP
if (ctrl.unit[lun]->IsDaynaPort()) {
LOGTRACE("%s Doing special case write for DaynaPort", __PRETTY_FUNCTION__);
if (!(SCSIDaynaPort*)ctrl.unit[lun]->Write(ctrl.cmd, ctrl.buffer, ctrl.length)) {
@ -1402,7 +1399,7 @@ BOOL SASIDEV::XferOut(BOOL cont)
break;
}
LOGTRACE("%s eCmdWriteAndVerify10 Calling Write... cmd: %02X next: %d", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0], (int)ctrl.next);
LOGTRACE("%s eCmdVerify Calling Write... cmd: %02X next: %d", __PRETTY_FUNCTION__, (WORD)ctrl.cmd[0], (int)ctrl.next);
if (!ctrl.unit[lun]->Write(ctrl.cmd, ctrl.buffer, ctrl.next - 1)) {
// Write failed
return FALSE;
@ -1432,6 +1429,7 @@ BOOL SASIDEV::XferOut(BOOL cont)
case SASIDEV::eCmdSetMcastAddr:
LOGTRACE("%s Done with DaynaPort Set Multicast Address", __PRETTY_FUNCTION__);
break;
default:
LOGWARN("Received an unexpected command (%02X) in %s", (WORD)ctrl.cmd[0] , __PRETTY_FUNCTION__)
ASSERT(FALSE);
@ -1461,15 +1459,14 @@ void SASIDEV::FlushUnit()
switch ((SASIDEV::scsi_command)ctrl.cmd[0]) {
case SASIDEV::eCmdWrite6:
case SASIDEV::eCmdWrite10:
case SASIDEV::eCmdWriteAndVerify10:
// Flush
if (!ctrl.unit[lun]->IsCacheWB()) {
ctrl.unit[lun]->Flush();
}
case SASIDEV::eCmdWrite16:
case SASIDEV::eCmdVerify10:
case SASIDEV::eCmdVerify16:
break;
case SASIDEV::eCmdModeSelect:
case SASIDEV::eCmdModeSelect10:
// Debug code related to Issue #2 on github, where we get an unhandled Model select when
// Debug code related to Issue #2 on github, where we get an unhandled Mode Select when
// the mac is rebooted
// https://github.com/akuker/RASCSI/issues/2
LOGWARN("Received \'Mode Select\'\n");
@ -1562,10 +1559,10 @@ void SASIDEV::GetPhaseStr(char *str)
//---------------------------------------------------------------------------
DWORD SASIDEV::GetLun()
{
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
if (!ctrl.unit[lun]) {
throw lunexception(lun);
}
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
if (!ctrl.unit[lun]) {
throw lun_exception(lun);
}
return lun;
return lun;
}

View File

@ -77,11 +77,11 @@ protected:
eCmdStartStop = 0x1B,
eCmdSendDiag = 0x1D,
eCmdRemoval = 0x1E,
eCmdReadCapacity = 0x25,
eCmdReadCapacity10 = 0x25,
eCmdRead10 = 0x28,
eCmdWrite10 = 0x2A,
eCmdSeek10 = 0x2B,
eCmdWriteAndVerify10 = 0x2E,
eCmdVerify10 = 0x2E,
eCmdVerify = 0x2F,
eCmdSynchronizeCache = 0x35,
eCmdReadDefectData10 = 0x37,
@ -89,12 +89,18 @@ protected:
eCmdPlayAudio10 = 0x45,
eCmdPlayAudioMSF = 0x47,
eCmdPlayAudioTrack = 0x48,
eCmdGetEventStatusNotification = 0x4a,
eCmdModeSelect10 = 0x55,
eCmdReserve10 = 0x56,
eCmdRelease10 = 0x57,
eCmdModeSense10 = 0x5A,
eCmdRead16 = 0x88,
eCmdWrite16 = 0x8A,
eCmdVerify16 = 0x8F,
eCmdReadCapacity16 = 0x9E,
eCmdReportLuns = 0xA0,
eCmdInvalid = 0xC2, // (SASI only/Suppress warning when using SxSI)
eCmdSasiCmdAssign = 0x0e, // This isn't used by SCSI, and can probably be removed.
eCmdSasiCmdAssign = 0x0E, // This isn't used by SCSI, and can probably be removed.
};
public:
@ -103,7 +109,7 @@ public:
};
const int UNKNOWN_SCSI_ID = -1;
const int DEFAULT_BUFFER_SIZE = 0x800;
const int DEFAULT_BUFFER_SIZE = 0x1000;
const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
// For timing adjustments
@ -120,7 +126,7 @@ public:
BUS *bus; // Bus
// commands
DWORD cmd[10]; // Command data
DWORD cmd[16]; // Command data
DWORD status; // Status data
DWORD message; // Message data
@ -137,10 +143,6 @@ public:
// Logical unit
Disk *unit[UnitMax];
// Sense Key and Additional Sense Code (ASC) of the previous command
int sense_key;
int asc;
} ctrl_t;
public:
@ -154,7 +156,7 @@ public:
// Connect
void Connect(int id, BUS *sbus); // Controller connection
Disk* GetUnit(int no); // Get logical unit
Disk* GetUnit(int no); // Get logical unit
void SetUnit(int no, Disk *dev); // Logical unit setting
BOOL HasUnit(); // Has a valid logical unit
@ -171,7 +173,7 @@ public:
ctrl_t* GetWorkAddr() { return &ctrl; } // Get the internal information address
virtual BOOL IsSASI() const {return TRUE;} // SASI Check
virtual BOOL IsSCSI() const {return FALSE;} // SCSI check
Disk* GetBusyUnit(); // Get the busy unit
Disk* GetBusyUnit(); // Get the busy unit
protected:
// Phase processing

View File

@ -19,6 +19,7 @@
#include "devices/scsi_host_bridge.h"
#include "devices/scsi_daynaport.h"
#include "exceptions.h"
#include <sstream>
//===========================================================================
//
@ -41,46 +42,52 @@ SCSIDEV::SCSIDEV() : SASIDEV()
scsi.msc = 0;
memset(scsi.msb, 0x00, sizeof(scsi.msb));
SetupCommand(eCmdTestUnitReady, "CmdTestUnitReady", &SCSIDEV::CmdTestUnitReady);
SetupCommand(eCmdRezero, "CmdRezero", &SCSIDEV::CmdRezero);
SetupCommand(eCmdRequestSense, "CmdRequestSense", &SCSIDEV::CmdRequestSense);
SetupCommand(eCmdFormat, "CmdFormat", &SCSIDEV::CmdFormat);
SetupCommand(eCmdReassign, "CmdReassign", &SCSIDEV::CmdReassign);
SetupCommand(eCmdRead6, "CmdRead6", &SCSIDEV::CmdRead6);
SetupCommand(eCmdWrite6, "CmdWrite6", &SCSIDEV::CmdWrite6);
SetupCommand(eCmdSeek6, "CmdSeek6", &SCSIDEV::CmdSeek6);
SetupCommand(eCmdInquiry, "CmdInquiry", &SCSIDEV::CmdInquiry);
SetupCommand(eCmdModeSelect, "CmdModeSelect", &SCSIDEV::CmdModeSelect);
SetupCommand(eCmdReserve6, "CmdReserve6", &SCSIDEV::CmdReserve6);
SetupCommand(eCmdRelease6, "CmdRelease6", &SCSIDEV::CmdRelease6);
SetupCommand(eCmdModeSense, "CmdModeSense", &SCSIDEV::CmdModeSense);
SetupCommand(eCmdStartStop, "CmdStartStop", &SCSIDEV::CmdStartStop);
SetupCommand(eCmdSendDiag, "CmdSendDiag", &SCSIDEV::CmdSendDiag);
SetupCommand(eCmdRemoval, "CmdRemoval", &SCSIDEV::CmdRemoval);
SetupCommand(eCmdReadCapacity, "CmdReadCapacity", &SCSIDEV::CmdReadCapacity);
SetupCommand(eCmdRead10, "CmdRead10", &SCSIDEV::CmdRead10);
SetupCommand(eCmdWrite10, "CmdWrite10", &SCSIDEV::CmdWrite10);
SetupCommand(eCmdWriteAndVerify10, "CmdWriteAndVerify10", &SCSIDEV::CmdWrite10);
SetupCommand(eCmdSeek10, "CmdSeek10", &SCSIDEV::CmdSeek10);
SetupCommand(eCmdVerify, "CmdVerify", &SCSIDEV::CmdVerify);
SetupCommand(eCmdSynchronizeCache, "CmdSynchronizeCache", &SCSIDEV::CmdSynchronizeCache);
SetupCommand(eCmdReadDefectData10, "CmdReadDefectData10", &SCSIDEV::CmdReadDefectData10);
SetupCommand(eCmdModeSelect10, "CmdModeSelect10", &SCSIDEV::CmdModeSelect10);
SetupCommand(eCmdReserve10, "CmdReserve10", &SCSIDEV::CmdReserve10);
SetupCommand(eCmdRelease10, "CmdRelease10", &SCSIDEV::CmdRelease10);
SetupCommand(eCmdModeSense10, "CmdModeSense10", &SCSIDEV::CmdModeSense10);
SetUpCommand(eCmdTestUnitReady, "CmdTestUnitReady", &SCSIDEV::CmdTestUnitReady);
SetUpCommand(eCmdRezero, "CmdRezero", &SCSIDEV::CmdRezero);
SetUpCommand(eCmdRequestSense, "CmdRequestSense", &SCSIDEV::CmdRequestSense);
SetUpCommand(eCmdFormat, "CmdFormat", &SCSIDEV::CmdFormat);
SetUpCommand(eCmdReassign, "CmdReassign", &SCSIDEV::CmdReassign);
SetUpCommand(eCmdRead6, "CmdRead6", &SCSIDEV::CmdRead6);
SetUpCommand(eCmdWrite6, "CmdWrite6", &SCSIDEV::CmdWrite6);
SetUpCommand(eCmdSeek6, "CmdSeek6", &SCSIDEV::CmdSeek6);
SetUpCommand(eCmdInquiry, "CmdInquiry", &SCSIDEV::CmdInquiry);
SetUpCommand(eCmdModeSelect, "CmdModeSelect", &SCSIDEV::CmdModeSelect);
SetUpCommand(eCmdReserve6, "CmdReserve6", &SCSIDEV::CmdReserve6);
SetUpCommand(eCmdRelease6, "CmdRelease6", &SCSIDEV::CmdRelease6);
SetUpCommand(eCmdModeSense, "CmdModeSense", &SCSIDEV::CmdModeSense);
SetUpCommand(eCmdStartStop, "CmdStartStop", &SCSIDEV::CmdStartStop);
SetUpCommand(eCmdSendDiag, "CmdSendDiag", &SCSIDEV::CmdSendDiag);
SetUpCommand(eCmdRemoval, "CmdRemoval", &SCSIDEV::CmdRemoval);
SetUpCommand(eCmdReadCapacity10, "CmdReadCapacity10", &SCSIDEV::CmdReadCapacity10);
SetUpCommand(eCmdRead10, "CmdRead10", &SCSIDEV::CmdRead10);
SetUpCommand(eCmdWrite10, "CmdWrite10", &SCSIDEV::CmdWrite10);
SetUpCommand(eCmdVerify10, "CmdVerify10", &SCSIDEV::CmdWrite10);
SetUpCommand(eCmdSeek10, "CmdSeek10", &SCSIDEV::CmdSeek10);
SetUpCommand(eCmdVerify, "CmdVerify", &SCSIDEV::CmdVerify);
SetUpCommand(eCmdSynchronizeCache, "CmdSynchronizeCache", &SCSIDEV::CmdSynchronizeCache);
SetUpCommand(eCmdReadDefectData10, "CmdReadDefectData10", &SCSIDEV::CmdReadDefectData10);
SetUpCommand(eCmdModeSelect10, "CmdModeSelect10", &SCSIDEV::CmdModeSelect10);
SetUpCommand(eCmdReserve10, "CmdReserve10", &SCSIDEV::CmdReserve10);
SetUpCommand(eCmdRelease10, "CmdRelease10", &SCSIDEV::CmdRelease10);
SetUpCommand(eCmdModeSense10, "CmdModeSense10", &SCSIDEV::CmdModeSense10);
SetUpCommand(eCmdRead16, "CmdRead16", &SCSIDEV::CmdRead16);
SetUpCommand(eCmdWrite16, "CmdWrite16", &SCSIDEV::CmdWrite16);
SetUpCommand(eCmdVerify16, "CmdVerify16", &SCSIDEV::CmdWrite16);
SetUpCommand(eCmdReadCapacity16, "CmdReadCapacity16", &SCSIDEV::CmdReadCapacity16);
SetUpCommand(eCmdReportLuns, "CmdReportLuns", &SCSIDEV::CmdReportLuns);
// MMC specific. TODO Move to separate class
SetupCommand(eCmdReadToc, "CmdReadToc", &SCSIDEV::CmdReadToc);
SetupCommand(eCmdPlayAudio10, "CmdPlayAudio10", &SCSIDEV::CmdPlayAudio10);
SetupCommand(eCmdPlayAudioMSF, "CmdPlayAudioMSF", &SCSIDEV::CmdPlayAudioMSF);
SetupCommand(eCmdPlayAudioTrack, "CmdPlayAudioTrack", &SCSIDEV::CmdPlayAudioTrack);
SetUpCommand(eCmdReadToc, "CmdReadToc", &SCSIDEV::CmdReadToc);
SetUpCommand(eCmdPlayAudio10, "CmdPlayAudio10", &SCSIDEV::CmdPlayAudio10);
SetUpCommand(eCmdPlayAudioMSF, "CmdPlayAudioMSF", &SCSIDEV::CmdPlayAudioMSF);
SetUpCommand(eCmdPlayAudioTrack, "CmdPlayAudioTrack", &SCSIDEV::CmdPlayAudioTrack);
SetUpCommand(eCmdGetEventStatusNotification, "CmdGetEventStatusNotification", &SCSIDEV::CmdGetEventStatusNotification);
// DaynaPort specific. TODO Move to separate class
SetupCommand(eCmdRetrieveStats, "CmdRetrieveStats", &SCSIDEV::CmdRetrieveStats);
SetupCommand(eCmdSetIfaceMode, "CmdSetIfaceMode", &SCSIDEV::CmdSetIfaceMode);
SetupCommand(eCmdSetMcastAddr, "CmdSetMcastAddr", &SCSIDEV::CmdSetMcastAddr);
SetupCommand(eCmdEnableInterface, "CmdEnableInterface", &SCSIDEV::CmdEnableInterface);
SetUpCommand(eCmdRetrieveStats, "CmdRetrieveStats", &SCSIDEV::CmdRetrieveStats);
SetUpCommand(eCmdSetIfaceMode, "CmdSetIfaceMode", &SCSIDEV::CmdSetIfaceMode);
SetUpCommand(eCmdSetMcastAddr, "CmdSetMcastAddr", &SCSIDEV::CmdSetMcastAddr);
SetUpCommand(eCmdEnableInterface, "CmdEnableInterface", &SCSIDEV::CmdEnableInterface);
}
SCSIDEV::~SCSIDEV()
@ -90,7 +97,7 @@ SCSIDEV::~SCSIDEV()
}
}
void SCSIDEV::SetupCommand(scsi_command opcode, const char* name, void (SCSIDEV::*execute)(void))
void SCSIDEV::SetUpCommand(scsi_command opcode, const char* name, void (SCSIDEV::*execute)(void))
{
scsi_commands[opcode] = new command_t(name, execute);
}
@ -204,7 +211,6 @@ void SCSIDEV::BusFree()
{
// Phase change
if (ctrl.phase != BUS::busfree) {
LOGTRACE( "%s Bus free phase", __PRETTY_FUNCTION__);
// Phase setting
@ -215,7 +221,7 @@ void SCSIDEV::BusFree()
ctrl.bus->SetMSG(FALSE);
ctrl.bus->SetCD(FALSE);
ctrl.bus->SetIO(FALSE);
ctrl.bus->SetBSY(FALSE);
ctrl.bus->SetBSY(false);
// Initialize status and message
ctrl.status = 0x00;
@ -258,7 +264,7 @@ void SCSIDEV::Selection()
ctrl.phase = BUS::selection;
// Raise BSY and respond
ctrl.bus->SetBSY(TRUE);
ctrl.bus->SetBSY(true);
return;
}
@ -280,7 +286,7 @@ void SCSIDEV::Selection()
//---------------------------------------------------------------------------
void SCSIDEV::Execute()
{
LOGTRACE( "%s Execution phase command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0]);
LOGTRACE("%s Execution phase command $%02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.cmd[0]);
// Phase Setting
ctrl.phase = BUS::execute;
@ -292,20 +298,13 @@ void SCSIDEV::Execute()
// If the command is valid it must be contained in the command map
if (!scsi_commands.count(static_cast<scsi_command>(ctrl.cmd[0]))) {
LOGWARN("%s Received unsupported command: $%02X", __PRETTY_FUNCTION__, (BYTE)ctrl.cmd[0]);
CmdInvalid();
return;
}
command_t* command = scsi_commands[static_cast<scsi_command>(ctrl.cmd[0])];
LOGDEBUG("++++ CMD ++++ %s Received %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl.cmd[0]);
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((unsigned int)ctrl.cmd[0] != 0x03) {
ctrl.sense_key = 0;
ctrl.asc = 0;
}
LOGDEBUG("++++ CMD ++++ %s ID %d received %s ($%02X)", __PRETTY_FUNCTION__, GetSCSIID(), command->name, (unsigned int)ctrl.cmd[0]);
// Process by command
(this->*command->execute)();
@ -318,14 +317,13 @@ void SCSIDEV::Execute()
//---------------------------------------------------------------------------
void SCSIDEV::MsgOut()
{
LOGTRACE("%s ID: %d",__PRETTY_FUNCTION__, this->GetSCSIID());
LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetSCSIID());
// Phase change
if (ctrl.phase != BUS::msgout) {
LOGTRACE("Message Out Phase");
// process the IDENTIFY message
// process the IDENTIFY message
if (ctrl.phase == BUS::selection) {
scsi.atnmsg = TRUE;
scsi.msc = 0;
@ -378,14 +376,22 @@ void SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
return;
}
// Logical Unit
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
if (!ctrl.unit[lun] || asc == ERROR_CODES::INVALID_LUN) {
lun = 0;
}
LOGTRACE("%s Sense Key and ASC for subsequent REQUEST SENSE: $%02X, $%02X", __PRETTY_FUNCTION__, sense_key, asc);
// Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.sense_key = sense_key;
ctrl.asc = asc;
if (sense_key || asc) {
// Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.unit[lun]->SetStatusCode((sense_key << 16) | (asc << 8));
}
// Set status (CHECK CONDITION only for valid LUNs for non-REQUEST SENSE)
ctrl.status = (ctrl.cmd[0] == eCmdRequestSense && asc == ERROR_CODES::asc::INVALID_LUN) ? 0x00 : 0x02;
// Set status and message(CHECK CONDITION)
ctrl.status = 0x02;
ctrl.message = 0x00;
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__);
@ -410,24 +416,19 @@ void SCSIDEV::CmdInquiry()
LOGTRACE("%s INQUIRY Command", __PRETTY_FUNCTION__);
// Find a valid unit
// TODO The code below is most likely wrong. It results in the same INQUIRY data being
// TODO The code below is probably wrong. It results in the same INQUIRY data being
// used for all LUNs, even though each LUN has its individual set of INQUIRY data.
Disk *disk = NULL;
int valid_lun;
for (valid_lun = 0; valid_lun < UnitMax; valid_lun++) {
PrimaryDevice *device = NULL;
for (int valid_lun = 0; valid_lun < UnitMax; valid_lun++) {
if (ctrl.unit[valid_lun]) {
disk = ctrl.unit[valid_lun];
device = ctrl.unit[valid_lun];
break;
}
}
// Processed on the disk side (it is originally processed by the controller)
if (disk) {
DWORD major = (DWORD)(RASCSI >> 8);
DWORD minor = (DWORD)(RASCSI & 0xff);
LOGTRACE("%s Buffer size is %d",__PRETTY_FUNCTION__, ctrl.bufsize);
ctrl.length =
ctrl.unit[valid_lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor);
if (device) {
ctrl.length = device->Inquiry(ctrl.cmd, ctrl.buffer);
} else {
ctrl.length = 0;
}
@ -586,7 +587,7 @@ void SCSIDEV::CmdStartStop()
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->StartStop(ctrl.cmd);
bool status = ctrl.unit[lun]->StartStop(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
@ -609,7 +610,7 @@ void SCSIDEV::CmdSendDiag()
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->SendDiag(ctrl.cmd);
bool status = ctrl.unit[lun]->SendDiag(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
@ -632,7 +633,7 @@ void SCSIDEV::CmdRemoval()
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->Removal(ctrl.cmd);
bool status = ctrl.unit[lun]->Removal(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
@ -648,15 +649,34 @@ void SCSIDEV::CmdRemoval()
// READ CAPACITY
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdReadCapacity()
void SCSIDEV::CmdReadCapacity10()
{
LOGTRACE( "%s READ CAPACITY Command ", __PRETTY_FUNCTION__);
LOGTRACE( "%s READ CAPACITY(10) Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
// Command processing on drive
int length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer);
ASSERT(length >= 0);
int length = ctrl.unit[lun]->ReadCapacity10(ctrl.cmd, ctrl.buffer);
if (length <= 0) {
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return;
}
// Length setting
ctrl.length = length;
// Data-in Phase
DataIn();
}
void SCSIDEV::CmdReadCapacity16()
{
LOGTRACE( "%s READ CAPACITY(16) Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
// Command processing on drive
int length = ctrl.unit[lun]->ReadCapacity16(ctrl.cmd, ctrl.buffer);
if (length <= 0) {
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return;
@ -696,7 +716,90 @@ void SCSIDEV::CmdRead10()
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[8];
LOGTRACE("%s READ(10) command record=%08X block=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
// Check capacity
DWORD capacity = ctrl.unit[lun]->GetBlockCount();
if (record > capacity || record + ctrl.blocks > capacity) {
ostringstream s;
s << "ID " << GetSCSIID() << ": Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl.blocks;
LOGWARN("%s", s.str().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
LOGTRACE("%s READ(10) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
// Do not process 0 blocks
if (ctrl.blocks == 0) {
Status();
return;
}
// Command processing on drive
ctrl.length = ctrl.unit[lun]->Read(ctrl.cmd, ctrl.buffer, record);
if (ctrl.length <= 0) {
// Failure (Error)
Error();
return;
}
// Set next block
ctrl.next = record + 1;
// Data-in Phase
DataIn();
}
//---------------------------------------------------------------------------
//
// READ(16)
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdRead16()
{
DWORD lun = GetLun();
// Receive message if host bridge
if (ctrl.unit[lun]->IsBridge()) {
Error();
return;
}
// Report an error as long as big drives are not supported
if (ctrl.cmd[2] || ctrl.cmd[3] || ctrl.cmd[4] || ctrl.cmd[5]) {
LOGWARN("Can't execute READ(16) with 64 bit sector number");
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
// Get record number and block number
DWORD record = ctrl.cmd[6];
record <<= 8;
record |= ctrl.cmd[7];
record <<= 8;
record |= ctrl.cmd[8];
record <<= 8;
record |= ctrl.cmd[9];
ctrl.blocks = ctrl.cmd[10];
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[11];
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[12];
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[13];
// Check capacity
DWORD capacity = ctrl.unit[lun]->GetBlockCount();
if (record > capacity || record + ctrl.blocks > capacity) {
ostringstream s;
s << "ID " << GetSCSIID() << ": Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl.blocks;
LOGWARN("%s", s.str().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
LOGTRACE("%s READ(16) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
// Do not process 0 blocks
if (ctrl.blocks == 0) {
@ -746,7 +849,18 @@ void SCSIDEV::CmdWrite10()
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[8];
LOGTRACE("%s WRTIE(10) command record=%08X blocks=%d",__PRETTY_FUNCTION__, (unsigned int)record, (unsigned int)ctrl.blocks);
// Check capacity
DWORD capacity = ctrl.unit[lun]->GetBlockCount();
if (record > capacity || record + ctrl.blocks > capacity) {
ostringstream s;
s << "ID " << GetSCSIID() << ": Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl.blocks;
LOGWARN("%s", s.str().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
LOGTRACE("%s WRITE(10) command record=%d blocks=%d",__PRETTY_FUNCTION__, (unsigned int)record, (unsigned int)ctrl.blocks);
// Do not process 0 blocks
if (ctrl.blocks == 0) {
@ -758,10 +872,82 @@ void SCSIDEV::CmdWrite10()
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
if (ctrl.length <= 0) {
// Failure (Error)
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::WRITE_PROTECTED);
return;
}
// Set next block
ctrl.next = record + 1;
// Data out phase
DataOut();
}
//---------------------------------------------------------------------------
//
// WRITE(16)
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdWrite16()
{
DWORD lun = GetLun();
// Receive message if host bridge
if (ctrl.unit[lun]->IsBridge()) {
Error();
return;
}
// Report an error as long as big drives are not supported
if (ctrl.cmd[2] || ctrl.cmd[3] || ctrl.cmd[4] || ctrl.cmd[5]) {
LOGWARN("Can't execute WRITE(16) with 64 bit sector number");
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
// Get record number and block number
DWORD record = ctrl.cmd[6];
record <<= 8;
record |= ctrl.cmd[7];
record <<= 8;
record |= ctrl.cmd[8];
record <<= 8;
record |= ctrl.cmd[9];
ctrl.blocks = ctrl.cmd[10];
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[11];
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[12];
ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[13];
// Check capacity
DWORD capacity = ctrl.unit[lun]->GetBlockCount();
if (record > capacity || record + ctrl.blocks > capacity) {
ostringstream s;
s << "ID " << GetSCSIID() << ": Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl.blocks;
LOGWARN("%s", s.str().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
LOGTRACE("%s WRITE(16) command record=%d blocks=%d",__PRETTY_FUNCTION__, (unsigned int)record, (unsigned int)ctrl.blocks);
// Do not process 0 blocks
if (ctrl.blocks == 0) {
Status();
return;
}
// Command processing on drive
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
if (ctrl.length <= 0) {
// Failure (Error)
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::WRITE_PROTECTED);
return;
}
// Set next block
ctrl.next = record + 1;
@ -853,6 +1039,28 @@ void SCSIDEV::CmdVerify()
DataOut();
}
//---------------------------------------------------------------------------
//
// REPORT LUNS
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdReportLuns()
{
DWORD lun = GetLun();
int length = ctrl.unit[lun]->ReportLuns(ctrl.cmd, ctrl.buffer);
if (length <= 0) {
// Failure (Error)
Error();
return;
}
ctrl.length = length;
// Data in phase
DataIn();
}
//---------------------------------------------------------------------------
//
// SYNCHRONIZE CACHE
@ -923,7 +1131,7 @@ void SCSIDEV::CmdPlayAudio10()
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->PlayAudio(ctrl.cmd);
bool status = ctrl.unit[lun]->PlayAudio(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
@ -944,7 +1152,7 @@ void SCSIDEV::CmdPlayAudioMSF()
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd);
bool status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
@ -965,7 +1173,7 @@ void SCSIDEV::CmdPlayAudioTrack()
DWORD lun = GetLun();
// Command processing on drive
BOOL status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd);
bool status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
@ -976,6 +1184,19 @@ void SCSIDEV::CmdPlayAudioTrack()
Status();
}
//---------------------------------------------------------------------------
//
// GET EVENT STATUS NOTIFICATION
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdGetEventStatusNotification()
{
GetLun();
// This naive (but legal) implementation avoids constant warnings in the logs
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
}
//---------------------------------------------------------------------------
//
// MODE SELECT10
@ -1037,7 +1258,7 @@ void SCSIDEV::CmdGetMessage10()
DWORD lun = GetLun();
// Error if not a host bridge
if (!ctrl.unit[lun]->IsBridge() && !ctrl.unit[lun]->IsNuvolink()) {
if (!ctrl.unit[lun]->IsBridge()) {
LOGWARN("Received a GetMessage10 command for a non-bridge unit");
Error();
return;
@ -1124,9 +1345,9 @@ void SCSIDEV::CmdRetrieveStats()
DWORD lun = GetLun();
// Error if not a DaynaPort SCSI Link
if (ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("Received a CmdRetrieveStats command for a non-daynaport unit %s", ctrl.unit[lun]->GetID().c_str());
Error();
if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("Received a CmdRetrieveStats command for a non-daynaport unit %s", ctrl.unit[lun]->GetType().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return;
}
@ -1161,15 +1382,14 @@ void SCSIDEV::CmdSetIfaceMode()
// Error if not a DaynaPort SCSI Link
if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("%s Received a CmdRetrieveStats command for a non-daynaport unit %s", __PRETTY_FUNCTION__, ctrl.unit[lun]->GetID().c_str());
Error();
LOGWARN("%s Received a CmdSetIfaceMode command for a non-daynaport unit %s", __PRETTY_FUNCTION__, ctrl.unit[lun]->GetType().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return;
}
SCSIDaynaPort *dayna_port = (SCSIDaynaPort*)ctrl.unit[lun];
// Check whether this command is telling us to "Set Interface Mode"
// or "Set MAC Address"
// Check whether this command is telling us to "Set Interface Mode" or "Set MAC Address"
ctrl.length = dayna_port->RetrieveStats(ctrl.cmd, ctrl.buffer);
switch(ctrl.cmd[5]){
@ -1201,7 +1421,7 @@ void SCSIDEV::CmdSetMcastAddr()
if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("Received a SetMcastAddress command for a non-daynaport unit");
Error();
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return;
}
@ -1233,8 +1453,8 @@ void SCSIDEV::CmdEnableInterface()
// Error if not a DaynaPort SCSI Link
if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("%s Received a CmdRetrieveStats command for a non-daynaport unit %s", __PRETTY_FUNCTION__, ctrl.unit[lun]->GetID().c_str());
Error();
LOGWARN("%s Received a CmdEnableInterface command for a non-daynaport unit %s", __PRETTY_FUNCTION__, ctrl.unit[lun]->GetType().c_str());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return;
}
@ -1274,7 +1494,9 @@ void SCSIDEV::Send()
//if Length! = 0, send
if (ctrl.length != 0) {
LOGTRACE("%s sending handhake with offset %lu, length %lu", __PRETTY_FUNCTION__, ctrl.offset, ctrl.length);
ostringstream s;
s << __PRETTY_FUNCTION__ << " sending handhake with offset " << ctrl.offset << ", length " << ctrl.length;
LOGTRACE("%s", s.str().c_str());
// The Daynaport needs to have a delay after the size/flags field
// of the read response. In the MacOS driver, it looks like the
@ -1310,7 +1532,9 @@ void SCSIDEV::Send()
if (ctrl.blocks != 0) {
// set next buffer (set offset, length)
result = XferIn(ctrl.buffer);
LOGTRACE("%s processing after data collection. Blocks: %lu", __PRETTY_FUNCTION__, ctrl.blocks);
ostringstream s;
s << __PRETTY_FUNCTION__ << " processing after data collection. Blocks: " << ctrl.blocks;
LOGTRACE("%s", s.str().c_str());
}
}
@ -1322,7 +1546,9 @@ void SCSIDEV::Send()
// Continue sending if block !=0
if (ctrl.blocks != 0){
LOGTRACE("%s Continuing to send. blocks = %lu", __PRETTY_FUNCTION__, ctrl.blocks);
ostringstream s;
s << __PRETTY_FUNCTION__ << " Continuing to send. blocks = " << ctrl.blocks;
LOGTRACE("%s", s.str().c_str());
ASSERT(ctrl.length > 0);
ASSERT(ctrl.offset == 0);
return;
@ -1376,7 +1602,6 @@ void SCSIDEV::Send()
void SCSIDEV::Receive()
{
int len;
int i;
BYTE data;
LOGTRACE("%s",__PRETTY_FUNCTION__);
@ -1389,8 +1614,7 @@ void SCSIDEV::Receive()
if (ctrl.length != 0) {
LOGTRACE("%s length was != 0", __PRETTY_FUNCTION__);
// Receive
len = ctrl.bus->ReceiveHandShake(
&ctrl.buffer[ctrl.offset], ctrl.length);
len = ctrl.bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
// If not able to receive all, move to status phase
if (len != (int)ctrl.length) {
@ -1458,26 +1682,22 @@ void SCSIDEV::Receive()
switch (ctrl.phase) {
// Command phase
case BUS::command:
// Command data transfer
len = 6;
if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) {
// 10 byte CDB
len = 10;
}
for (i = 0; i < len; i++) {
len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
for (int i = 0; i < len; i++) {
ctrl.cmd[i] = (DWORD)ctrl.buffer[i];
LOGTRACE("%s Command $%02X",__PRETTY_FUNCTION__, (int)ctrl.cmd[i]);
LOGTRACE("%s Command $%02X",__PRETTY_FUNCTION__, ctrl.cmd[i]);
}
// Execution Phase
try {
Execute();
}
catch (const lunexception& e) {
LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
try {
Execute();
}
catch (const lun_exception& e) {
LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, e.getlun());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
break;
// Message out phase
@ -1493,7 +1713,7 @@ void SCSIDEV::Receive()
// Parsing messages sent by ATN
if (scsi.atnmsg) {
i = 0;
int i = 0;
while (i < scsi.msc) {
// Message type
data = scsi.msb[i];

View File

@ -67,7 +67,7 @@ public:
BOOL IsSCSI() const {return TRUE;} // SCSI check
private:
void SetupCommand(scsi_command, const char*, void (SCSIDEV::*)(void));
void SetUpCommand(scsi_command, const char*, void (SCSIDEV::*)(void));
// Phase
void BusFree(); // Bus free phase
@ -88,7 +88,7 @@ private:
void CmdStartStop(); // START STOP UNIT command
void CmdSendDiag(); // SEND DIAGNOSTIC command
void CmdRemoval(); // PREVENT/ALLOW MEDIUM REMOVAL command
void CmdReadCapacity(); // READ CAPACITY command
void CmdReadCapacity10(); // READ CAPACITY(10) command
void CmdRead10(); // READ(10) command
void CmdWrite10(); // WRITE(10) command
void CmdSeek10(); // SEEK(10) command
@ -99,8 +99,13 @@ private:
void CmdPlayAudio10(); // PLAY AUDIO(10) command
void CmdPlayAudioMSF(); // PLAY AUDIO MSF command
void CmdPlayAudioTrack(); // PLAY AUDIO TRACK INDEX command
void CmdGetEventStatusNotification();
void CmdModeSelect10(); // MODE SELECT(10) command
void CmdModeSense10(); // MODE SENSE(10) command
void CmdReadCapacity16(); // READ CAPACITY(16) command
void CmdRead16(); // READ(16) command
void CmdWrite16(); // WRITE(16) command
void CmdReportLuns(); // REPORT LUNS command
void CmdGetMessage10(); // GET MESSAGE(10) command
void CmdSendMessage10(); // SEND MESSAGE(10) command
void CmdRetrieveStats(); // DaynaPort specific command

View File

@ -0,0 +1,46 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
// A BlockDevice supports SCSI block commands (see https://www.t10.org/drafts.htm, SBC-5)
//
//---------------------------------------------------------------------------
#pragma once
#include "primary_device.h"
class BlockDevice : public PrimaryDevice
{
public:
BlockDevice(const string& id) : PrimaryDevice(id) {};
virtual ~BlockDevice() {};
// Mandatory commands
virtual bool TestUnitReady(const DWORD *cdb) = 0;
virtual int Inquiry(const DWORD *cdb, BYTE *buf) = 0;
virtual int ReportLuns(const DWORD *cdb, BYTE *buf) = 0;
virtual bool Format(const DWORD *cdb) = 0;
// READ(6), READ(10)
virtual int Read(const DWORD *cdb, BYTE *buf, DWORD block) = 0;
// WRITE(6), WRITE(10)
virtual bool Write(const DWORD *cdb, const BYTE *buf, DWORD block) = 0;
virtual int ReadCapacity10(const DWORD *cdb, BYTE *buf) = 0;
virtual int ReadCapacity16(const DWORD *cdb, BYTE *buf) = 0;
// TODO Uncomment as soon as there is a clean separation between controllers and devices
//virtual int Read16(const DWORD *cdb, BYTE *buf, DWORD block) = 0;
//virtual int Write16(const DWORD *cdb, BYTE *buf, DWORD block) = 0;
//virtual int Verify16(const DWORD *cdb, BYTE *buf, DWORD block) = 0;
// Implemented optional commands
virtual int RequestSense(const DWORD *cdb, BYTE *buf) = 0;
virtual int ModeSense(const DWORD *cdb, BYTE *buf) = 0;
virtual int ModeSense10(const DWORD *cdb, BYTE *buf) = 0;
virtual bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) = 0;
// TODO Add the other optional commands currently implemented
};

View File

@ -26,7 +26,7 @@
//---------------------------------------------------------------------------
//
// 漢字コード変換
// Kanji code conversion
//
//---------------------------------------------------------------------------
#define IC_BUF_SIZE 1024
@ -46,28 +46,23 @@ static void convert(char const *src, char const *dest,
#endif
{
#ifndef __APPLE__
iconv_t cd;
size_t in;
size_t out;
size_t ret;
*outbuf = '\0';
in = strlen(inbuf);
out = outsize - 1;
size_t in = strlen(inbuf);
size_t out = outsize - 1;
cd = iconv_open(dest, src);
iconv_t cd = iconv_open(dest, src);
if (cd == (iconv_t)-1) {
return;
}
ret = iconv(cd, &inbuf, &in, &outbuf, &out);
size_t ret = iconv(cd, &inbuf, &in, &outbuf, &out);
if (ret == (size_t)-1) {
return;
}
iconv_close(cd);
*outbuf = '\0';
#endif //ifndef __macintosh__
#endif //ifndef __APPLE__
}
//---------------------------------------------------------------------------
@ -202,33 +197,33 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
if (ext[j] != ' ')
goto next_ext;
}
// 拡張子終端なら転送終了
// If the extension ends, the transfer ends
break;
}
next_ext:
*p++ = c;
}
// 全ての文字を読み込むと、ここで i >= 3 となる
// When all the characters are read, here i >= 3
}
// 番兵追加
// Add sentinel
*p = '\0';
}
//===========================================================================
//
// ホスト側ドライブ
// Host side drive
//
//===========================================================================
//---------------------------------------------------------------------------
//
/// デフォルトコンストラクタ
// Default constructor
//
//---------------------------------------------------------------------------
CHostDrv::CHostDrv()
{
// 初期化
// Initialization
m_bWriteProtect = FALSE;
m_bEnable = FALSE;
m_capCache.sectors = 0;
@ -240,7 +235,7 @@ CHostDrv::CHostDrv()
//---------------------------------------------------------------------------
//
/// デストラクタ final
// Final destructor
//
//---------------------------------------------------------------------------
CHostDrv::~CHostDrv()
@ -252,7 +247,7 @@ CHostDrv::~CHostDrv()
m_nRing--;
}
// 実体が存在しないことを確認 (念のため)
// Confirm that the entity does not exist (just in case)
ASSERT(m_cRing.Next() == &m_cRing);
ASSERT(m_cRing.Prev() == &m_cRing);
ASSERT(m_nRing == 0);
@ -260,7 +255,7 @@ CHostDrv::~CHostDrv()
//---------------------------------------------------------------------------
//
/// 初期化 (デバイス起動とロード)
// Initialization (device boot and load)
//
//---------------------------------------------------------------------------
void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
@ -273,18 +268,18 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
ASSERT(m_bVolumeCache == FALSE);
ASSERT(m_szVolumeCache[0] == _T('\0'));
// 実体が存在しないことを確認 (念のため)
// Confirm that the entity does not exist (just in case)
ASSERT(m_cRing.Next() == &m_cRing);
ASSERT(m_cRing.Prev() == &m_cRing);
ASSERT(m_nRing == 0);
// パラメータを受け取る
// Receive parameters
if (nFlag & FSFLAG_WRITE_PROTECT)
m_bWriteProtect = TRUE;
strcpy(m_szBase, szBase);
// ベースパスの最後のパス区切りマークを削除する
/// @warning Unicode利用時は修正が必要
// Remove the last path delimiter in the base path
// @warning needs to be modified when using Unicode
TCHAR* pClear = NULL;
TCHAR* p = m_szBase;
for (;;) {
@ -306,56 +301,52 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
if (pClear)
*pClear = _T('\0');
// 状態更新
// Status update
m_bEnable = TRUE;
}
//---------------------------------------------------------------------------
//
/// メディアチェック
// Media check
//
//---------------------------------------------------------------------------
BOOL CHostDrv::isMediaOffline()
{
// オフライン状態チェック
// Offline status check
return m_bEnable == FALSE;
}
//---------------------------------------------------------------------------
//
/// メディアバイトの取得
// Get media bytes
//
//---------------------------------------------------------------------------
BYTE CHostDrv::GetMediaByte() const
{
return Human68k::MEDIA_REMOTE;
}
//---------------------------------------------------------------------------
//
/// ドライブ状態の取得
// Get drive status
//
//---------------------------------------------------------------------------
DWORD CHostDrv::GetStatus() const
{
return 0x40 | (m_bEnable ? (m_bWriteProtect ? 0x08 : 0) | 0x02 : 0);
}
//---------------------------------------------------------------------------
//
/// メディア状態設定
// Media status settings
//
//---------------------------------------------------------------------------
void CHostDrv::SetEnable(BOOL bEnable)
{
m_bEnable = bEnable;
if (bEnable == FALSE) {
// キャッシュ消去
// Clear cache
m_capCache.sectors = 0;
m_bVolumeCache = FALSE;
m_szVolumeCache[0] = _T('\0');
@ -364,13 +355,12 @@ void CHostDrv::SetEnable(BOOL bEnable)
//---------------------------------------------------------------------------
//
/// メディア交換チェック
// Media change check
//
//---------------------------------------------------------------------------
BOOL CHostDrv::CheckMedia()
{
// 状態更新
// Status update
Update();
if (m_bEnable == FALSE)
CleanCache();
@ -380,38 +370,36 @@ BOOL CHostDrv::CheckMedia()
//---------------------------------------------------------------------------
//
/// メディア状態更新
// Media status update
//
//---------------------------------------------------------------------------
void CHostDrv::Update()
{
// メディア挿入とみなす
// Considered as media insertion
BOOL bEnable = TRUE;
// メディア状態反映
// Media status reflected
SetEnable(bEnable);
}
//---------------------------------------------------------------------------
//
/// イジェクト
// Eject
//
//---------------------------------------------------------------------------
void CHostDrv::Eject()
{
// メディア排出
// Media discharge
CleanCache();
SetEnable(FALSE);
// 状態更新
// Status update
Update();
}
//---------------------------------------------------------------------------
//
/// ボリュームラベルの取得
// Get volume label
//
//---------------------------------------------------------------------------
void CHostDrv::GetVolume(TCHAR* szLabel)
@ -419,7 +407,7 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
ASSERT(szLabel);
ASSERT(m_bEnable);
// ボリュームラベルの取得
// Get volume label
strcpy(m_szVolumeCache, "RASDRV ");
if (m_szBase[0]) {
strcat(m_szVolumeCache, m_szBase);
@ -427,10 +415,10 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
strcat(m_szVolumeCache, "/");
}
// キャッシュ更新
// Cache update
m_bVolumeCache = TRUE;
// 内容を転送
// Transfer content
strcpy(szLabel, m_szVolumeCache);
}
@ -513,7 +501,6 @@ BOOL CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
//---------------------------------------------------------------------------
void CHostDrv::CleanCache()
{
Lock();
for (CHostPath* p = (CHostPath*)m_cRing.Next(); p != &m_cRing;) {
p->Release();
@ -4002,7 +3989,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
case 1:
// Human68k互換のためのダミー
pIoctrl->param = (unsigned long)-1;
pIoctrl->param = -1;
return 0;
case 2:

View File

@ -66,9 +66,8 @@ static BOOL br_setif(int br_socket_fd, const char* bridgename, const char* ifnam
static BOOL ip_link(int fd, const char* ifname, BOOL up) {
struct ifreq ifr;
int err;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); // Need to save room for null terminator
err = ioctl(fd, SIOCGIFFLAGS, &ifr);
int err = ioctl(fd, SIOCGIFFLAGS, &ifr);
if (err) {
LOGERROR("Error: can't ioctl SIOCGIFFLAGS. Errno: %d %s", errno, strerror(errno));
return FALSE;
@ -257,7 +256,7 @@ void CTapDriver::OpenDump(const Filepath& path) {
m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath());
if (m_pcap_dumper == NULL) {
LOGERROR("Error: can't open pcap file: %s", pcap_geterr(m_pcap));
throw ioexception("Can't open pcap file");
throw io_exception("Can't open pcap file");
}
LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.GetPath());
@ -302,10 +301,10 @@ void CTapDriver::Cleanup()
// Enable
//
//---------------------------------------------------------------------------
BOOL CTapDriver::Enable(){
bool CTapDriver::Enable(){
int fd = socket(PF_INET, SOCK_DGRAM, 0);
LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__);
BOOL result = ip_link(fd, "ras0", TRUE);
bool result = ip_link(fd, "ras0", TRUE);
close(fd);
return result;
}
@ -315,10 +314,10 @@ BOOL CTapDriver::Enable(){
// Disable
//
//---------------------------------------------------------------------------
BOOL CTapDriver::Disable(){
bool CTapDriver::Disable(){
int fd = socket(PF_INET, SOCK_DGRAM, 0);
LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__);
BOOL result = ip_link(fd, "ras0", FALSE);
bool result = ip_link(fd, "ras0", FALSE);
close(fd);
return result;
}
@ -409,7 +408,7 @@ int CTapDriver::Rx(BYTE *buf)
buf[dwReceived + 2] = (BYTE)((crc >> 16) & 0xFF);
buf[dwReceived + 3] = (BYTE)((crc >> 24) & 0xFF);
LOGDEBUG("%s CRC is %08lX - %02X %02X %02X %02X\n", __PRETTY_FUNCTION__, crc, buf[dwReceived+0], buf[dwReceived+1], buf[dwReceived+2], buf[dwReceived+3]);
LOGDEBUG("%s CRC is %08X - %02X %02X %02X %02X\n", __PRETTY_FUNCTION__, crc, buf[dwReceived+0], buf[dwReceived+1], buf[dwReceived+2], buf[dwReceived+3]);
// Add FCS size to the received message size
dwReceived += 4;

View File

@ -41,8 +41,8 @@ public:
int Rx(BYTE *buf); // Receive
int Tx(const BYTE *buf, int len); // Send
BOOL PendingPackets(); // Check if there are IP packets available
BOOL Enable(); // Enable the ras0 interface
BOOL Disable(); // Disable the ras0 interface
bool Enable(); // Enable the ras0 interface
bool Disable(); // Disable the ras0 interface
BOOL Flush(); // Purge all of the packets that are waiting to be processed
private:

View File

@ -0,0 +1,140 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <cassert>
#include <sstream>
#include "rascsi_version.h"
#include "os.h"
#include "log.h"
#include "exceptions.h"
#include "device.h"
Device::Device(const string& type)
{
assert(type.length() == 4);
this->type = type;
vendor = DEFAULT_VENDOR;
char rev[5];
sprintf(rev, "%02d%02d", rascsi_major_version, rascsi_minor_version);
revision = rev;
ready = false;
reset = false;
attn = false;
protectable = false;
write_protected = false;
read_only = false;
removable = false;
removed = false;
lockable = false;
locked = false;
id = 0;
lun = 0;
status_code = STATUS_NOERROR;
}
void Device::Reset()
{
locked = false;
attn = false;
reset = false;
}
void Device::SetProtected(bool write_protected)
{
if (!read_only) {
this->write_protected = write_protected;
}
}
void Device::SetVendor(const string& vendor)
{
if (vendor.empty() || vendor.length() > 8) {
ostringstream error;
error << "Vendor '" << vendor << "' must be between 1 and 8 characters";
throw illegal_argument_exception(error.str());
}
this->vendor = vendor;
}
void Device::SetProduct(const string& product, bool force)
{
// Changing the device name is not SCSI compliant
if (!this->product.empty() && !force) {
return;
}
if (product.empty() || product.length() > 16) {
ostringstream error;
error << "Product '" << product << "' must be between 1 and 16 characters";
throw illegal_argument_exception(error.str());
}
this->product = product;
}
void Device::SetRevision(const string& revision)
{
if (revision.empty() || revision.length() > 4) {
ostringstream error;
error << "Revision '" << revision << "' must be between 1 and 4 characters";
throw illegal_argument_exception(error.str());
}
this->revision = revision;
}
const string Device::GetPaddedName() const
{
string name = vendor;
name.append(8 - vendor.length(), ' ');
name += product;
name.append(16 - product.length(), ' ');
name += revision;
name.append(4 - revision.length(), ' ');
assert(name.length() == 28);
return name;
}
void Device::SetStatusCode(int status_code)
{
LOGTRACE("Setting status: Sense Key: $%02X, ASC: $%02X, ASCQ: $%02X", status_code >> 16, (status_code >> 8 &0xff), status_code & 0xff);
this->status_code = status_code;
}
// TODO This implementation appears to be wrong: If a device is locked there
// is no way to eject the medium without unlocking. In other words, there is
// no "force" mode.
bool Device::Eject(bool force)
{
if (!ready || !removable) {
return false;
}
// Must be unlocked if there is no force flag
if (!force && locked) {
return false;
}
ready = false;
attn = false;
removed = true;
write_protected = false;
locked = false;
return true;
}

View File

@ -0,0 +1,137 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include <string>
using namespace std;
#define DEFAULT_VENDOR "RaSCSI"
//---------------------------------------------------------------------------
//
// Error definition (sense code returned by REQUEST SENSE)
//
// MSB Reserved (0x00)
// Sense Key
// Additional Sense Code (ASC)
// LSB Additional Sense Code Qualifier(ASCQ)
//
//---------------------------------------------------------------------------
#define STATUS_NOERROR 0x00000000 // NO ADDITIONAL SENSE INFO.
#define STATUS_DEVRESET 0x00062900 // POWER ON OR RESET OCCURED
#define STATUS_NOTREADY 0x00023a00 // MEDIUM NOT PRESENT
#define STATUS_ATTENTION 0x00062800 // MEDIUM MAY HAVE CHANGED
#define STATUS_PREVENT 0x00045302 // MEDIUM REMOVAL PREVENTED
#define STATUS_READFAULT 0x00031100 // UNRECOVERED READ ERROR
#define STATUS_WRITEFAULT 0x00030300 // PERIPHERAL DEVICE WRITE FAULT
#define STATUS_WRITEPROTECT 0x00042700 // WRITE PROTECTED
#define STATUS_MISCOMPARE 0x000e1d00 // MISCOMPARE DURING VERIFY
#define STATUS_INVALIDCMD 0x00052000 // INVALID COMMAND OPERATION CODE
#define STATUS_INVALIDLBA 0x00052100 // LOGICAL BLOCK ADDR. OUT OF RANGE
#define STATUS_INVALIDCDB 0x00052400 // INVALID FIELD IN CDB
#define STATUS_INVALIDLUN 0x00052500 // LOGICAL UNIT NOT SUPPORTED
#define STATUS_INVALIDPRM 0x00052600 // INVALID FIELD IN PARAMETER LIST
#define STATUS_INVALIDMSG 0x00054900 // INVALID MESSAGE ERROR
#define STATUS_PARAMLEN 0x00051a00 // PARAMETERS LIST LENGTH ERROR
#define STATUS_PARAMNOT 0x00052601 // PARAMETERS NOT SUPPORTED
#define STATUS_PARAMVALUE 0x00052602 // PARAMETERS VALUE INVALID
#define STATUS_PARAMSAVE 0x00053900 // SAVING PARAMETERS NOT SUPPORTED
#define STATUS_NODEFECT 0x00010000 // DEFECT LIST NOT FOUND
class Device
{
private:
string type;
bool ready;
bool reset;
bool attn;
// Device is protectable/write-protected
bool protectable;
bool write_protected;
// Device is permanently read-only
bool read_only;
// Device is removable/removed
bool removable;
bool removed;
// Device is lockable/locked
bool lockable;
bool locked;
// Device ID and LUN
unsigned int id;
unsigned int lun;
string vendor;
string product;
string revision;
// Sense Key, ASC and ASCQ
int status_code;
public:
Device(const string&);
virtual ~Device() {};
const string& GetType() const { return type; }
bool IsReady() const { return ready; }
void SetReady(bool ready) { this->ready = ready; }
bool IsReset() const { return reset; }
void SetReset(bool reset) { this->reset = reset; }
void Reset();
bool IsAttn() const { return attn; }
void SetAttn(bool attn) { this->attn = attn; }
bool IsProtectable() const { return protectable; }
void SetProtectable(bool protectable) { this->protectable = protectable; }
bool IsProtected() const { return write_protected; }
void SetProtected(bool);
bool IsReadOnly() const { return read_only; }
void SetReadOnly(bool read_only) { this->read_only = read_only; }
bool IsRemovable() const { return removable; }
void SetRemovable(bool removable) { this->removable = removable; }
bool IsRemoved() const { return removed; }
void SetRemoved(bool removed) { this->removed = removed; }
bool IsLockable() const { return lockable; }
void SetLockable(bool lockable) { this->lockable = lockable; }
bool IsLocked() const { return locked; }
void SetLocked(bool locked) { this->locked = locked; }
unsigned int GetId() const { return id; }
void SetId(unsigned int id) { this->id = id; }
unsigned int GetLun() const { return lun; }
void SetLun(unsigned int lun) { this->lun = lun; }
void SetVendor(const string&);
void SetProduct(const string&, bool = true);
void SetRevision(const string&);
const string GetPaddedName() const;
int GetStatusCode() const { return status_code; }
void SetStatusCode(int status_code);
virtual bool Eject(bool);
bool IsSASI() const { return type == "SAHD"; }
bool IsSCSI() const { return type == "SCHD" || type == "SCRM"; }
bool IsCdRom() const { return type == "SCCD"; }
bool IsMo() const { return type == "SCMO"; }
bool IsBridge() const { return type == "SCBR"; }
bool IsDaynaPort() const { return type == "SCDP"; }
};

View File

@ -0,0 +1,76 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "sasihd.h"
#include "scsihd.h"
#include "scsihd_nec.h"
#include "scsimo.h"
#include "scsicd.h"
#include "scsi_host_bridge.h"
#include "scsi_daynaport.h"
#include "device_factory.h"
using namespace std;
using namespace rascsi_interface;
Device *DeviceFactory::CreateDevice(PbDeviceType& type, const string& filename, const string& ext)
{
// If no type was specified try to derive the device type from the filename and extension
if (type == UNDEFINED) {
if (ext == "hdf") {
type = SAHD;
}
else if (ext == "hds" || ext == "hdn" || ext == "hdi" || ext == "nhd" || ext == "hda") {
type = SCHD;
}
else if (ext == "hdr") {
type = SCRM;
} else if (ext == "mos") {
type = SCMO;
} else if (ext == "iso") {
type = SCCD;
}
else if (filename == "bridge") {
type = SCBR;
}
else if (filename == "daynaport") {
type = SCDP;
}
}
switch (type) {
case SAHD:
return new SASIHD();
case SCHD:
if (ext == "hdn" || ext == "hdi" || ext == "nhd") {
return new SCSIHD_NEC();
} else {
return new SCSIHD();
}
case SCRM:
return new SCSIHD(true);
case SCMO:
return new SCSIMO();
case SCCD:
return new SCSICD();
case SCBR:
return new SCSIBR();
case SCDP:
return new SCSIDaynaPort();
default:
return NULL;
}
}

View File

@ -0,0 +1,27 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
// A DeviceFactory creates devices based on their type and the extension of their image file
//
//---------------------------------------------------------------------------
#pragma once
#include <string>
#include "rascsi_interface.pb.h"
class Device;
class DeviceFactory
{
public:
DeviceFactory() { };
~DeviceFactory() { };
static Device *CreateDevice(rascsi_interface::PbDeviceType& type, const std::string& filename, const std::string& ext);
};

File diff suppressed because it is too large Load Diff

View File

@ -20,49 +20,11 @@
#include "xm6.h"
#include "log.h"
#include "scsi.h"
#include "block_device.h"
#include "file_support.h"
#include "filepath.h"
#include <string>
//---------------------------------------------------------------------------
//
// Error definition (sense code returned by REQUEST SENSE)
//
// MSB Reserved (0x00)
// Sense Key
// Additional Sense Code (ASC)
// LSB Additional Sense Code Qualifier(ASCQ)
//
//---------------------------------------------------------------------------
#define DISK_NOERROR 0x00000000 // NO ADDITIONAL SENSE INFO.
#define DISK_DEVRESET 0x00062900 // POWER ON OR RESET OCCURED
#define DISK_NOTREADY 0x00023a00 // MEDIUM NOT PRESENT
#define DISK_ATTENTION 0x00062800 // MEDIUM MAY HAVE CHANGED
#define DISK_PREVENT 0x00045302 // MEDIUM REMOVAL PREVENTED
#define DISK_READFAULT 0x00031100 // UNRECOVERED READ ERROR
#define DISK_WRITEFAULT 0x00030300 // PERIPHERAL DEVICE WRITE FAULT
#define DISK_WRITEPROTECT 0x00042700 // WRITE PROTECTED
#define DISK_MISCOMPARE 0x000e1d00 // MISCOMPARE DURING VERIFY
#define DISK_INVALIDCMD 0x00052000 // INVALID COMMAND OPERATION CODE
#define DISK_INVALIDLBA 0x00052100 // LOGICAL BLOCK ADDR. OUT OF RANGE
#define DISK_INVALIDCDB 0x00052400 // INVALID FIELD IN CDB
#define DISK_INVALIDLUN 0x00052500 // LOGICAL UNIT NOT SUPPORTED
#define DISK_INVALIDPRM 0x00052600 // INVALID FIELD IN PARAMETER LIST
#define DISK_INVALIDMSG 0x00054900 // INVALID MESSAGE ERROR
#define DISK_PARAMLEN 0x00051a00 // PARAMETERS LIST LENGTH ERROR
#define DISK_PARAMNOT 0x00052601 // PARAMETERS NOT SUPPORTED
#define DISK_PARAMVALUE 0x00052602 // PARAMETERS VALUE INVALID
#define DISK_PARAMSAVE 0x00053900 // SAVING PARAMETERS NOT SUPPORTED
#define DISK_NODEFECT 0x00010000 // DEFECT LIST NOT FOUND
#if 0
#define DISK_AUDIOPROGRESS 0x00??0011 // AUDIO PLAY IN PROGRESS
#define DISK_AUDIOPAUSED 0x00??0012 // AUDIO PLAY PAUSED
#define DISK_AUDIOSTOPPED 0x00??0014 // AUDIO PLAY STOPPED DUE TO ERROR
#define DISK_AUDIOCOMPLETE 0x00??0013 // AUDIO PLAY SUCCESSFULLY COMPLETED
#endif
#define BENDER_SIGNATURE "RaSCSI"
//===========================================================================
//
// Disk Track
@ -83,14 +45,14 @@ public:
DWORD maplen; // Changed map length
BOOL *changemap; // Changed map
BOOL raw; // RAW mode flag
off64_t imgoffset; // Offset to actual data
off_t imgoffset; // Offset to actual data
} disktrk_t;
public:
// Basic Functions
DiskTrack(); // Constructor
virtual ~DiskTrack(); // Destructor
void Init(int track, int size, int sectors, BOOL raw = FALSE, off64_t imgoff = 0);// Initialization
void Init(int track, int size, int sectors, BOOL raw = FALSE, off_t imgoff = 0);// Initialization
BOOL Load(const Filepath& path); // Load
BOOL Save(const Filepath& path); // Save
@ -128,7 +90,7 @@ public:
public:
// Basic Functions
DiskCache(const Filepath& path, int size, int blocks,off64_t imgoff = 0);// Constructor
DiskCache(const Filepath& path, int size, int blocks,off_t imgoff = 0);// Constructor
virtual ~DiskCache(); // Destructor
void SetRawMode(BOOL raw); // CD-ROM raw mode setting
@ -152,7 +114,7 @@ private:
int sec_size; // Sector size (8 or 9 or 11)
int sec_blocks; // Blocks per sector
BOOL cd_raw; // CD-ROM RAW mode
off64_t imgoffset; // Offset to actual data
off_t imgoffset; // Offset to actual data
};
//===========================================================================
@ -160,116 +122,77 @@ private:
// Disk
//
//===========================================================================
class Disk
class Disk : public BlockDevice
{
public:
protected:
// Internal data structure
typedef struct {
std::string id; // Media ID
BOOL ready; // Valid Disk
bool readonly; // Read only
bool protectable;
bool writep; // Write protected
bool removable; // Removable
bool removed;
bool lockable;
bool locked; // Locked
// TODO Non-disk devices must not inherit from Disk class
bool supports_file;
bool attn; // Attention
bool reset; // Reset
int size; // Sector Size
DWORD blocks; // Total number of sectors
DWORD lun; // LUN
DWORD code; // Status code
DiskCache *dcache; // Disk cache
off64_t imgoffset; // Offset to actual data
off_t imgoffset; // Offset to actual data
} disk_t;
public:
// Basic Functions
Disk(std::string); // Constructor
virtual ~Disk(); // Destructor
virtual void Reset(); // Device Reset
// ID
const std::string& GetID() const; // Get media ID
bool IsSASI() const; // SASI Check
bool IsSCSI() const; // SASI Check
bool IsCdRom() const;
bool IsMo() const;
bool IsBridge() const;
bool IsDaynaPort() const;
bool IsNuvolink() const;
// Media Operations
virtual void Open(const Filepath& path, BOOL attn = TRUE); // Open
virtual void Open(const Filepath& path); // Open
void GetPath(Filepath& path) const; // Get the path
bool Eject(bool); // Eject
bool IsReady() const { return disk.ready; } // Ready check
bool IsProtectable() const { return disk.protectable; }
bool WriteP(bool); // Set Write Protect flag
bool IsWriteP() const { return disk.writep; } // Get write protect flag
bool IsReadOnly() const { return disk.readonly; } // Get read only flag
bool IsRemovable() const { return disk.removable; } // Get is removable flag
bool IsRemoved() const { return disk.removed; }
bool IsLockable() const { return disk.lockable; }
bool IsLocked() const { return disk.locked; } // Get locked status
bool SupportsFile() const { return disk.supports_file; }
bool IsAttn() const { return disk.attn; } // Get attention flag
bool Eject(bool) override; // Eject
bool Flush(); // Flush the cache
// Properties
void SetLUN(DWORD lun) { disk.lun = lun; } // LUN set
DWORD GetLUN() { return disk.lun; } // LUN get
// commands
virtual int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);// INQUIRY command
virtual int RequestSense(const DWORD *cdb, BYTE *buf); // REQUEST SENSE command
virtual bool TestUnitReady(const DWORD *cdb) override; // TEST UNIT READY command
virtual int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
virtual int RequestSense(const DWORD *cdb, BYTE *buf) override; // REQUEST SENSE command
int SelectCheck(const DWORD *cdb); // SELECT check
int SelectCheck10(const DWORD *cdb); // SELECT(10) check
virtual BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length);// MODE SELECT command
virtual int ModeSense(const DWORD *cdb, BYTE *buf); // MODE SENSE command
virtual int ModeSense10(const DWORD *cdb, BYTE *buf); // MODE SENSE(10) command
virtual bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;// MODE SELECT command
virtual int ModeSense(const DWORD *cdb, BYTE *buf) override; // MODE SENSE command
virtual int ModeSense10(const DWORD *cdb, BYTE *buf) override; // MODE SENSE(10) command
int ReadDefectData10(const DWORD *cdb, BYTE *buf); // READ DEFECT DATA(10) command
virtual BOOL TestUnitReady(const DWORD *cdb); // TEST UNIT READY command
BOOL Rezero(const DWORD *cdb); // REZERO command
BOOL Format(const DWORD *cdb); // FORMAT UNIT command
BOOL Reassign(const DWORD *cdb); // REASSIGN UNIT command
virtual int Read(const DWORD *cdb, BYTE *buf, DWORD block); // READ command
bool Rezero(const DWORD *cdb); // REZERO command
bool Format(const DWORD *cdb) override; // FORMAT UNIT command
bool Reassign(const DWORD *cdb); // REASSIGN UNIT command
virtual int Read(const DWORD *cdb, BYTE *buf, DWORD block) override; // READ command
virtual int WriteCheck(DWORD block); // WRITE check
virtual BOOL Write(const DWORD *cdb, const BYTE *buf, DWORD block); // WRITE command
BOOL Seek(const DWORD *cdb); // SEEK command
BOOL Assign(const DWORD *cdb); // ASSIGN command
BOOL Specify(const DWORD *cdb); // SPECIFY command
BOOL StartStop(const DWORD *cdb); // START STOP UNIT command
BOOL SendDiag(const DWORD *cdb); // SEND DIAGNOSTIC command
BOOL Removal(const DWORD *cdb); // PREVENT/ALLOW MEDIUM REMOVAL command
int ReadCapacity(const DWORD *cdb, BYTE *buf); // READ CAPACITY command
BOOL Verify(const DWORD *cdb); // VERIFY command
virtual bool Write(const DWORD *cdb, const BYTE *buf, DWORD block) override; // WRITE command
bool Seek(const DWORD *cdb); // SEEK command
bool Assign(const DWORD *cdb); // ASSIGN command
bool Specify(const DWORD *cdb); // SPECIFY command
bool StartStop(const DWORD *cdb); // START STOP UNIT command
bool SendDiag(const DWORD *cdb); // SEND DIAGNOSTIC command
bool Removal(const DWORD *cdb); // PREVENT/ALLOW MEDIUM REMOVAL command
int ReadCapacity10(const DWORD *cdb, BYTE *buf) override; // READ CAPACITY(10) command
int ReadCapacity16(const DWORD *cdb, BYTE *buf) override; // READ CAPACITY(16) command
int ReportLuns(const DWORD *cdb, BYTE *buf); // REPORT LUNS command
int GetSectorSize() const;
void SetSectorSize(int);
DWORD GetBlockCount() const;
void SetBlockCount(DWORD);
// TODO Currently not called
bool Verify(const DWORD *cdb); // VERIFY command
virtual int ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC command
virtual BOOL PlayAudio(const DWORD *cdb); // PLAY AUDIO command
virtual BOOL PlayAudioMSF(const DWORD *cdb); // PLAY AUDIO MSF command
virtual BOOL PlayAudioTrack(const DWORD *cdb); // PLAY AUDIO TRACK command
// Other
bool IsCacheWB(); // Get cache writeback mode
void SetCacheWB(BOOL enable); // Set cache writeback mode
virtual bool PlayAudio(const DWORD *cdb); // PLAY AUDIO command
virtual bool PlayAudioMSF(const DWORD *cdb); // PLAY AUDIO MSF command
virtual bool PlayAudioTrack(const DWORD *cdb); // PLAY AUDIO TRACK command
protected:
// Internal processing
virtual int AddError(BOOL change, BYTE *buf); // Add error
virtual int AddFormat(BOOL change, BYTE *buf); // Add format
virtual int AddDrive(BOOL change, BYTE *buf); // Add drive
int AddOpt(BOOL change, BYTE *buf); // Add optical
int AddCache(BOOL change, BYTE *buf); // Add cache
int AddCDROM(BOOL change, BYTE *buf); // Add CD-ROM
int AddCDDA(BOOL change, BYTE *buf); // Add CD_DA
virtual int AddVendor(int page, BOOL change, BYTE *buf); // Add vendor special info
virtual int AddError(bool change, BYTE *buf); // Add error
virtual int AddFormat(bool change, BYTE *buf); // Add format
virtual int AddDrive(bool change, BYTE *buf); // Add drive
int AddOpt(bool change, BYTE *buf); // Add optical
int AddCache(bool change, BYTE *buf); // Add cache
int AddCDROM(bool change, BYTE *buf); // Add CD-ROM
int AddCDDA(bool, BYTE *buf); // Add CD_DA
virtual int AddVendor(int page, bool change, BYTE *buf); // Add vendor special info
BOOL CheckReady(); // Check if ready
// Internal data
disk_t disk; // Internal disk data
Filepath diskpath; // File path (for GetPath)
BOOL cache_wb; // Cache mode
};

View File

@ -0,0 +1,30 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
// Devices inheriting from FileSupport support device image files
//
//---------------------------------------------------------------------------
#pragma once
#include "filepath.h"
class FileSupport
{
private:
Filepath diskpath;
public:
FileSupport() {};
virtual ~FileSupport() {};
void GetPath(Filepath& path) const { path = diskpath; }
void SetPath(const Filepath& path) { diskpath = path; }
virtual void Open(const Filepath&) = 0;
};

View File

@ -0,0 +1,33 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
// A PrimaryDevice supports SCSI primary commands (see https://www.t10.org/drafts.htm, SPC-6)
//
//---------------------------------------------------------------------------
#pragma once
#include "device.h"
class PrimaryDevice : public Device
{
public:
PrimaryDevice(const string& id) : Device(id) {};
virtual ~PrimaryDevice() {};
// Mandatory commands
virtual bool TestUnitReady(const DWORD *cdb) = 0;
virtual int Inquiry(const DWORD *cdb, BYTE *buf) = 0;
virtual int ReportLuns(const DWORD *cdb, BYTE *buf) = 0;
// Implemented optional commands
virtual int RequestSense(const DWORD *cdb, BYTE *buf) = 0;
virtual int ModeSense(const DWORD *cdb, BYTE *buf) = 0;
virtual int ModeSense10(const DWORD *cdb, BYTE *buf) = 0;
virtual bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) = 0;
};

View File

@ -31,7 +31,7 @@
//---------------------------------------------------------------------------
SASIHD::SASIHD() : Disk("SAHD")
{
disk.protectable = true;
SetProtectable(true);
}
//---------------------------------------------------------------------------
@ -42,12 +42,12 @@ SASIHD::SASIHD() : Disk("SAHD")
void SASIHD::Reset()
{
// Unlock, clear attention
disk.locked = FALSE;
disk.attn = FALSE;
SetLocked(false);
SetAttn(false);
// Reset, clear the code
disk.reset = FALSE;
disk.code = 0x00;
SetReset(false);
SetStatusCode(STATUS_NOERROR);
}
//---------------------------------------------------------------------------
@ -55,18 +55,18 @@ void SASIHD::Reset()
// Open
//
//---------------------------------------------------------------------------
void SASIHD::Open(const Filepath& path, BOOL /*attn*/)
void SASIHD::Open(const Filepath& path)
{
ASSERT(!disk.ready);
ASSERT(!IsReady());
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open hard disk file read-only");
throw io_exception("Can't open hard disk file read-only");
}
// Get file size
off64_t size = fio.GetFileSize();
off_t size = fio.GetFileSize();
fio.Close();
#if defined(USE_MZ1F23_1024_SUPPORT)
@ -74,28 +74,28 @@ void SASIHD::Open(const Filepath& path, BOOL /*attn*/)
// 20M(22437888 BS=1024 C=21912)
if (size == 0x1566000) {
// Sector size and number of blocks
disk.size = 10;
disk.blocks = (DWORD)(size >> 10);
SetSectorSize(10);
SetBlockCount((DWORD)(size >> 10));
// Call the base class
Disk::Open(path);
FileSupport::SetPath(path);
}
#endif // USE_MZ1F23_1024_SUPPORT
#if defined(REMOVE_FIXED_SASIHD_SIZE)
// Must be in 256-byte units
if (size & 0xff) {
throw ioexception("File size must be a multiple of 512 bytes");
throw io_exception("File size must be a multiple of 256 bytes");
}
// 10MB or more
if (size < 0x9f5400) {
throw ioexception("File size must be at least 10 MB");
throw io_exception("File size must be at least 10 MB");
}
// Limit to about 512MB
if (size > 512 * 1024 * 1024) {
throw ioexception("File size must not exceed 512 MB");
throw io_exception("File size must not exceed 512 MB");
}
#else
// 10MB, 20MB, 40MBのみ
@ -114,13 +114,13 @@ void SASIHD::Open(const Filepath& path, BOOL /*attn*/)
// Other (Not supported )
default:
throw ioexception("Unsupported file size");
throw io_exception("Unsupported file size");
}
#endif // REMOVE_FIXED_SASIHD_SIZE
// Sector size and number of blocks
disk.size = 8;
disk.blocks = (DWORD)(size >> 8);
// Sector size 256 bytes and number of blocks
SetSectorSize(8);
SetBlockCount((DWORD)(size >> 8));
// Call the base class
Disk::Open(path);
@ -147,11 +147,8 @@ int SASIHD::RequestSense(const DWORD *cdb, BYTE *buf)
// SASI fixed to non-extended format
memset(buf, 0, size);
buf[0] = (BYTE)(disk.code >> 16);
buf[1] = (BYTE)(disk.lun << 5);
// Clear the code
disk.code = 0x00;
buf[0] = (BYTE)(GetStatusCode() >> 16);
buf[1] = (BYTE)(GetLun() << 5);
return size;
}

View File

@ -24,13 +24,13 @@
// SASI Hard Disk
//
//===========================================================================
class SASIHD : public Disk
class SASIHD : public Disk, public FileSupport
{
public:
// Basic Functions
SASIHD(); // Constructor
void Reset(); // Reset
void Open(const Filepath& path, BOOL attn = TRUE); // Open
void Open(const Filepath& path); // Open
// commands
int RequestSense(const DWORD *cdb, BYTE *buf); // REQUEST SENSE command

View File

@ -28,6 +28,7 @@
//---------------------------------------------------------------------------
#include "scsi_daynaport.h"
#include <sstream>
//===========================================================================
//
@ -49,9 +50,12 @@ const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff,
//---------------------------------------------------------------------------
SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
{
disk.supports_file = false;
SetRemovable(false);
#ifdef __linux__
SetVendor("Dayna");
SetProduct("SCSI/Link");
#ifdef __linux__
// TAP Driver Generation
m_tap = new CTapDriver();
m_bTapEnable = m_tap->Init();
@ -63,8 +67,8 @@ SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
LOGTRACE("%s this->reset()", __PRETTY_FUNCTION__);
this->Reset();
disk.ready = true;
disk.reset = false;
SetReady(true);
SetReset(false);
// Generate MAC Address
LOGTRACE("%s memset(m_mac_addr, 0x00, 6);", __PRETTY_FUNCTION__);
@ -115,14 +119,13 @@ SCSIDaynaPort::~SCSIDaynaPort()
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIDaynaPort::Inquiry(const DWORD *cdb, BYTE *buffer, DWORD major, DWORD minor)
int SCSIDaynaPort::Inquiry(const DWORD *cdb, BYTE *buffer)
{
// scsi_cdb_6_byte_t command;
// memcpy(&command,cdb,sizeof(command));
ASSERT(cdb);
ASSERT(buffer);
ASSERT(cdb[0] == 0x12);
//allocation_length = command->length;
DWORD allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8);
@ -132,19 +135,7 @@ int SCSIDaynaPort::Inquiry(const DWORD *cdb, BYTE *buffer, DWORD major, DWORD mi
// LOGWARN(":::::::::: Doing runtime pointer conversion: %04X", ((scsi_cdb_6_byte_t*)cdb)->length);
// }
LOGTRACE("%s Inquiry with major %ld, minor %ld. Allocation length: %d",__PRETTY_FUNCTION__, major, minor, (int)allocation_length);
// Work-around in order to report an error for LUNs > 0
DWORD lun = (cdb[1] >> 5) & 0x07;
if (lun) {
disk.code = DISK_INVALIDLUN;
return -1;
}
if(cdb[1] & 0x1) {
LOGERROR("EVPD bit is not supported");
return -1;
}
LOGTRACE("%s Inquiry, allocation length: %d",__PRETTY_FUNCTION__, (int)allocation_length);
if (allocation_length > 4){
if (allocation_length > sizeof(m_daynaport_inquiry_response)) {
@ -153,39 +144,21 @@ int SCSIDaynaPort::Inquiry(const DWORD *cdb, BYTE *buffer, DWORD major, DWORD mi
// Copy the pre-canned response
memcpy(buffer, m_daynaport_inquiry_response, allocation_length);
// Padded vendor, product, revision
memcpy(&buffer[8], GetPaddedName().c_str(), 28);
}
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if ((cdb[1] >> 5) & 0x07) {
buffer[0] |= 0x7f;
}
LOGTRACE("response size is %d", (int)allocation_length);
// Success
disk.code = DISK_NOERROR;
return allocation_length;
}
//---------------------------------------------------------------------------
//
// RequestSense
//
//---------------------------------------------------------------------------
int SCSIDaynaPort::RequestSense(const DWORD *cdb, BYTE *buffer)
{
// The DaynaPort RequestSense response will always be 9 bytes.
int size = 9;
LOGTRACE("%s size of sense data = %d", __PRETTY_FUNCTION__, size);
// Clear the buffer
memset(buffer, 0, size);
// Only set the response code (70h)
buffer[0] = 0x70;
// Clear the code
disk.code = 0x00;
return size;
}
//---------------------------------------------------------------------------
//
// READ
@ -202,7 +175,9 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, DWORD block)
ASSERT(buf);
LOGTRACE("%s reading DaynaPort block %lu", __PRETTY_FUNCTION__, block);
ostringstream s;
s << __PRETTY_FUNCTION__ << " reading DaynaPort block " << block;
LOGTRACE("%s", s.str().c_str());
if(command->operation_code != 0x08){
LOGERROR("Received unexpected cdb command: %02X. Expected 0x08", (unsigned int)command->operation_code);
@ -329,7 +304,9 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, DWORD block)
//---------------------------------------------------------------------------
int SCSIDaynaPort::WriteCheck(DWORD block)
{
LOGTRACE("%s block: %lu", __PRETTY_FUNCTION__, block);
ostringstream s;
s << __PRETTY_FUNCTION__ << " block: " << block;
LOGTRACE("%s", s.str().c_str());
// Status check
if (!CheckReady()) {
@ -337,7 +314,7 @@ int SCSIDaynaPort::WriteCheck(DWORD block)
}
if(!m_bTapEnable){
disk.code = DISK_NOTREADY;
SetStatusCode(STATUS_NOTREADY);
return 0;
}
@ -345,13 +322,12 @@ int SCSIDaynaPort::WriteCheck(DWORD block)
return 1;
}
//---------------------------------------------------------------------------
//
// Write
//
//---------------------------------------------------------------------------
BOOL SCSIDaynaPort::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
bool SCSIDaynaPort::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
{
BYTE data_format;
WORD data_length;
@ -372,22 +348,21 @@ BOOL SCSIDaynaPort::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
if(data_format == 0x00){
m_tap->Tx(buf, data_length);
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length);
return TRUE;
return true;
}
else if (data_format == 0x80){
// The data length is actuall specified in the first 2 bytes of the payload
data_length=(WORD)buf[1] + ((WORD)buf[0] << 8);
m_tap->Tx(&buf[4], data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length);
return TRUE;
return true;
}
else
{
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format);
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format);
return FALSE;
return true;
}
}
@ -444,7 +419,6 @@ int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer)
response_size = 18;
response_size = sizeof(m_scsi_link_stats);
memcpy(buffer, &m_scsi_link_stats, sizeof(m_scsi_link_stats));
@ -457,7 +431,6 @@ int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer)
}
// Success
disk.code = DISK_NOERROR;
return response_size;
// scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb;
// scsi_resp_link_stats_t *response = (scsi_resp_link_stats_t*) buffer;
@ -481,17 +454,12 @@ int SCSIDaynaPort::RetrieveStats(const DWORD *cdb, BYTE *buffer)
// Enable or Disable the interface
//
//---------------------------------------------------------------------------
BOOL SCSIDaynaPort::EnableInterface(const DWORD *cdb)
bool SCSIDaynaPort::EnableInterface(const DWORD *cdb)
{
int result;
// scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb;
// if(command->control & 0x80)
if(cdb[5] & 0x80)
{
bool result;
if (cdb[5] & 0x80) {
result = m_tap->Enable();
if(result){
if (result) {
LOGINFO("The DaynaPort interface has been ENABLED.");
}
else{
@ -499,10 +467,9 @@ BOOL SCSIDaynaPort::EnableInterface(const DWORD *cdb)
}
m_tap->Flush();
}
else
{
else {
result = m_tap->Disable();
if(result){
if (result) {
LOGINFO("The DaynaPort interface has been DISABLED.");
}
else{
@ -510,7 +477,7 @@ BOOL SCSIDaynaPort::EnableInterface(const DWORD *cdb)
}
}
return TRUE;
return result;
}
//---------------------------------------------------------------------------
@ -518,13 +485,12 @@ BOOL SCSIDaynaPort::EnableInterface(const DWORD *cdb)
// TEST UNIT READY
//
//---------------------------------------------------------------------------
BOOL SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/)
bool SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/)
{
LOGTRACE("%s", __PRETTY_FUNCTION__);
// TEST UNIT READY Success
disk.code = DISK_NOERROR;
return TRUE;
return true;
}
//---------------------------------------------------------------------------

View File

@ -44,34 +44,32 @@ public:
// Basic Functions
SCSIDaynaPort();
// Constructor
virtual ~SCSIDaynaPort();
~SCSIDaynaPort();
// Destructor
void Open(const Filepath& path, BOOL attn = TRUE);
// Capture packets
// commands
int Inquiry(const DWORD *cdb, BYTE *buffer, DWORD major, DWORD minor);
int Inquiry(const DWORD *cdb, BYTE *buffer) override;
// INQUIRY command
BOOL TestUnitReady(const DWORD *cdb);
bool TestUnitReady(const DWORD *cdb) override;
// TEST UNIT READY command
int Read(const DWORD *cdb, BYTE *buf, DWORD block) override;
// READ command
BOOL Write(const DWORD *cdb, const BYTE *buf, DWORD block) override;
bool Write(const DWORD *cdb, const BYTE *buf, DWORD block) override;
// WRITE command
int WriteCheck(DWORD block) override;
int WriteCheck(DWORD block);
// WRITE check
int RetrieveStats(const DWORD *cdb, BYTE *buffer);
// Retrieve DaynaPort statistics
BOOL EnableInterface(const DWORD *cdb);
bool EnableInterface(const DWORD *cdb);
// Enable/Disable Interface command
void SetMacAddr(const DWORD *cdb, BYTE *buffer);
// Set MAC address
void SetMode(const DWORD *cdb, BYTE *buffer);
// Set the mode: whether broadcast traffic is enabled or not
int RequestSense(const DWORD *cdb, BYTE *buf) override;
static const BYTE CMD_SCSILINK_STATS = 0x09;
static const BYTE CMD_SCSILINK_ENABLE = 0x0E;
static const BYTE CMD_SCSILINK_SET = 0x0C;
@ -161,7 +159,7 @@ private:
//http://www.bitsavers.org/pdf/apple/scsi/dayna/daynaPORT/pocket_scsiLINK/pocketscsilink_inq.png
const uint8_t m_daynaport_inquiry_response[44] = {
0x03, 0x00, 0x01, 0x00, // 4 bytes
0x1E, 0x00, 0x00, 0x00, // 4 bytes
0x1F, 0x00, 0x00, 0x00, // 4 bytes
// Vendor ID (8 Bytes)
'D','a','y','n','a',' ',' ',' ',
// Product ID (16 Bytes)

View File

@ -34,14 +34,16 @@
//---------------------------------------------------------------------------
SCSIBR::SCSIBR() : Disk("SCBR")
{
disk.supports_file = false;
SetRemovable(false);
SetProduct("RASCSI BRIDGE");
fsoptlen = 0;
fsoutlen = 0;
fsresult = 0;
packet_len = 0;
#ifdef __linux__
#ifdef __linux__
// TAP Driver Generation
tap = new CTapDriver();
m_bTapEnable = tap->Init();
@ -55,7 +57,7 @@ SCSIBR::SCSIBR() : Disk("SCBR")
// Packet reception flag OFF
packet_enable = FALSE;
#endif
#endif
// Create host file system
fs = new CFileSys();
@ -87,18 +89,15 @@ SCSIBR::~SCSIBR()
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIBR::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
int SCSIBR::Inquiry(const DWORD *cdb, BYTE *buf)
{
char rev[32];
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
SetStatusCode(STATUS_INVALIDCDB);
return FALSE;
}
@ -111,7 +110,7 @@ int SCSIBR::Inquiry(
buf[0] = 0x09;
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
if (((cdb[1] >> 5) & 0x07) != GetLun()) {
buf[0] = 0x7f;
}
@ -119,19 +118,8 @@ int SCSIBR::Inquiry(
buf[3] = 0x02;
buf[4] = 36 - 5 + 8; // required + 8 byte extension
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Vendor name
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
// Product name
memcpy(&buf[16], "RASCSI BRIDGE", 13);
// Revision (XM6 version number)
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
// Optional function valid flag
buf[36] = '0';
@ -153,7 +141,7 @@ int SCSIBR::Inquiry(
}
// Success
disk.code = DISK_NOERROR;
SetStatusCode(STATUS_NOERROR);
return size;
}
@ -162,11 +150,11 @@ int SCSIBR::Inquiry(
// TEST UNIT READY
//
//---------------------------------------------------------------------------
BOOL SCSIBR::TestUnitReady(const DWORD* /*cdb*/)
bool SCSIBR::TestUnitReady(const DWORD* /*cdb*/)
{
// TEST UNIT READY Success
disk.code = DISK_NOERROR;
return TRUE;
SetStatusCode(STATUS_NOERROR);
return true;
}
//---------------------------------------------------------------------------

View File

@ -33,11 +33,11 @@ class SCSIBR : public Disk
public:
// Basic Functions
SCSIBR(); // Constructor
virtual ~SCSIBR(); // Destructor
~SCSIBR(); // Destructor
// commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
BOOL TestUnitReady(const DWORD *cdb); // TEST UNIT READY command
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
bool TestUnitReady(const DWORD *cdb) override; // TEST UNIT READY command
int GetMessage10(const DWORD *cdb, BYTE *buf); // GET MESSAGE10 command
BOOL SendMessage10(const DWORD *cdb, BYTE *buf); // SEND MESSAGE10 command

View File

@ -62,7 +62,7 @@ CDTrack::~CDTrack()
// Init
//
//---------------------------------------------------------------------------
BOOL CDTrack::Init(int track, DWORD first, DWORD last)
void CDTrack::Init(int track, DWORD first, DWORD last)
{
ASSERT(!valid);
ASSERT(track >= 1);
@ -75,8 +75,6 @@ BOOL CDTrack::Init(int track, DWORD first, DWORD last)
// Remember LBA
first_lba = first;
last_lba = last;
return TRUE;
}
//---------------------------------------------------------------------------
@ -215,30 +213,6 @@ BOOL CDTrack::IsAudio() const
return audio;
}
//===========================================================================
//
// CD-DA Buffer
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
CDDABuf::CDDABuf()
{
}
//---------------------------------------------------------------------------
//
// Destructor
//
//---------------------------------------------------------------------------
CDDABuf::~CDDABuf()
{
}
//===========================================================================
//
// SCSI CD-ROM
@ -252,9 +226,10 @@ CDDABuf::~CDDABuf()
//---------------------------------------------------------------------------
SCSICD::SCSICD() : Disk("SCCD")
{
disk.removable = true;
disk.lockable = true;
disk.writep = true;
SetRemovable(true);
SetReadOnly(true);
SetProduct("CD-ROM CDU-55S");
// NOT in raw format
rawfile = FALSE;
@ -287,22 +262,22 @@ SCSICD::~SCSICD()
// Open
//
//---------------------------------------------------------------------------
void SCSICD::Open(const Filepath& path, BOOL attn)
void SCSICD::Open(const Filepath& path)
{
Fileio fio;
off64_t size;
off_t size;
TCHAR file[5];
ASSERT(!disk.ready);
ASSERT(!IsReady());
// Initialization, track clear
disk.blocks = 0;
SetBlockCount(0);
rawfile = FALSE;
ClearTrack();
// Open as read-only
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open CD-ROM file read-only");
throw io_exception("Can't open CD-ROM file read-only");
}
// Close and transfer for physical CD access
@ -317,7 +292,7 @@ void SCSICD::Open(const Filepath& path, BOOL attn)
size = fio.GetFileSize();
if (size <= 4) {
fio.Close();
throw ioexception("CD-ROM file size must be at least 4 bytes");
throw io_exception("CD-ROM file size must be at least 4 bytes");
}
// Judge whether it is a CUE sheet or an ISO file
@ -336,22 +311,21 @@ void SCSICD::Open(const Filepath& path, BOOL attn)
}
// Successful opening
ASSERT(disk.blocks > 0);
disk.size = 11;
ASSERT(GetBlockCount() > 0);
// Sector size 2048 bytes
SetSectorSize(11);
// Call the base class
Disk::Open(path);
FileSupport::SetPath(path);
// Set RAW flag
ASSERT(disk.dcache);
disk.dcache->SetRawMode(rawfile);
// Since it is a ROM media, writing is not possible
disk.writep = TRUE;
// Attention if ready
if (disk.ready && attn) {
disk.attn = TRUE;
if (IsReady()) {
SetAttn(true);
}
}
@ -362,7 +336,7 @@ void SCSICD::Open(const Filepath& path, BOOL attn)
//---------------------------------------------------------------------------
void SCSICD::OpenCue(const Filepath& /*path*/)
{
throw ioexception("Opening CUE CD-ROM files is not supported");
throw io_exception("Opening CUE CD-ROM files is not supported");
}
//---------------------------------------------------------------------------
@ -378,20 +352,20 @@ void SCSICD::OpenIso(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open ISO CD-ROM file read-only");
throw io_exception("Can't open ISO CD-ROM file read-only");
}
// Get file size
off64_t size = fio.GetFileSize();
off_t size = fio.GetFileSize();
if (size < 0x800) {
fio.Close();
throw ioexception("ISO CD-ROM file size must be at least 2048 bytes");
throw io_exception("ISO CD-ROM file size must be at least 2048 bytes");
}
// Read the first 12 bytes and close
if (!fio.Read(header, sizeof(header))) {
fio.Close();
throw ioexception("Can't read header of ISO CD-ROM file");
throw io_exception("Can't read header of ISO CD-ROM file");
}
// Check if it is RAW format
@ -403,14 +377,14 @@ void SCSICD::OpenIso(const Filepath& path)
// 00,FFx10,00, so it is presumed to be RAW format
if (!fio.Read(header, 4)) {
fio.Close();
throw ioexception("Can't read header of raw ISO CD-ROM file");
throw io_exception("Can't read header of raw ISO CD-ROM file");
}
// Supports MODE1/2048 or MODE1/2352 only
if (header[3] != 0x01) {
// Different mode
fio.Close();
throw ioexception("Illegal raw ISO CD-ROM file header");
throw io_exception("Illegal raw ISO CD-ROM file header");
}
// Set to RAW file
@ -421,31 +395,33 @@ void SCSICD::OpenIso(const Filepath& path)
if (rawfile) {
// Size must be a multiple of 2536 and less than 700MB
if (size % 0x930) {
throw ioexception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes");
throw io_exception("Raw ISO CD-ROM file size must be a multiple of 2536 bytes");
}
if (size > 912579600) {
throw ioexception("Raw ISO CD-ROM file size must not exceed 700 MB");
throw io_exception("Raw ISO CD-ROM file size must not exceed 700 MB");
}
// Set the number of blocks
disk.blocks = (DWORD)(size / 0x930);
SetBlockCount((DWORD)(size / 0x930));
} else {
// Size must be a multiple of 2048 and less than 700MB
if (size & 0x7ff) {
throw ioexception("ISO CD-ROM file size must be a multiple of 2048 bytes");
throw io_exception("ISO CD-ROM file size must be a multiple of 2048 bytes");
}
if (size > 0x2bed5000) {
throw ioexception("ISO CD-ROM file size must not exceed 700 MB");
throw io_exception("ISO CD-ROM file size must not exceed 700 MB");
}
// Set the number of blocks
disk.blocks = (DWORD)(size >> 11);
SetBlockCount((DWORD)(size >> 11));
}
LOGINFO("Media capacity for image file '%s': %d blocks", path.GetPath(), GetBlockCount());
// Create only one data track
ASSERT(!track[0]);
track[0] = new CDTrack(this);
track[0]->Init(1, 0, disk.blocks - 1);
track[0]->Init(1, 0, GetBlockCount() - 1);
track[0]->SetPath(FALSE, path);
tracks = 1;
dataindex = 0;
@ -461,14 +437,14 @@ void SCSICD::OpenPhysical(const Filepath& path)
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open CD-ROM file read-only");
throw io_exception("Can't open CD-ROM file read-only");
}
// Get size
off64_t size = fio.GetFileSize();
off_t size = fio.GetFileSize();
if (size < 0x800) {
fio.Close();
throw ioexception("CD-ROM file size must be at least 2048 bytes");
throw io_exception("CD-ROM file size must be at least 2048 bytes");
}
// Close
@ -476,19 +452,19 @@ void SCSICD::OpenPhysical(const Filepath& path)
// Size must be a multiple of 2048 and less than 700MB
if (size & 0x7ff) {
throw ioexception("CD-ROM file size must be a multiple of 2048 bytes");
throw io_exception("CD-ROM file size must be a multiple of 2048 bytes");
}
if (size > 0x2bed5000) {
throw ioexception("CD-ROM file size must not exceed 700 MB");
throw io_exception("CD-ROM file size must not exceed 700 MB");
}
// Set the number of blocks
disk.blocks = (DWORD)(size >> 11);
SetBlockCount((DWORD)(size >> 11));
// Create only one data track
ASSERT(!track[0]);
track[0] = new CDTrack(this);
track[0]->Init(1, 0, disk.blocks - 1);
track[0]->Init(1, 0, GetBlockCount() - 1);
track[0]->SetPath(FALSE, path);
tracks = 1;
dataindex = 0;
@ -499,18 +475,14 @@ void SCSICD::OpenPhysical(const Filepath& path)
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSICD::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf)
{
char rev[32];
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
SetStatusCode(STATUS_INVALIDCDB);
return FALSE;
}
@ -524,7 +496,7 @@ int SCSICD::Inquiry(
buf[0] = 0x05;
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
if (((cdb[1] >> 5) & 0x07) != GetLun()) {
buf[0] = 0x7f;
}
@ -536,16 +508,9 @@ int SCSICD::Inquiry(
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Vendor name
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
// Product name
memcpy(&buf[16], "CD-ROM CDU-55S", 14);
// Revision (XM6 version number)
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
//
// The following code worked with the modified Apple CD-ROM drivers. Need to
// test with the original code to see if it works as well....
@ -577,8 +542,6 @@ int SCSICD::Inquiry(
size = (int)cdb[4];
}
// Success
disk.code = DISK_NOERROR;
return size;
}
@ -589,8 +552,6 @@ int SCSICD::Inquiry(
//---------------------------------------------------------------------------
int SCSICD::Read(const DWORD *cdb, BYTE *buf, DWORD block)
{
Filepath path;
ASSERT(buf);
// Status check
@ -603,7 +564,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, DWORD block)
// if invalid, out of range
if (index < 0) {
disk.code = DISK_INVALIDLBA;
SetStatusCode(STATUS_INVALIDLBA);
return 0;
}
ASSERT(track[index]);
@ -615,12 +576,13 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, DWORD block)
disk.dcache = NULL;
// Reset the number of blocks
disk.blocks = track[index]->GetBlocks();
ASSERT(disk.blocks > 0);
SetBlockCount(track[index]->GetBlocks());
ASSERT(GetBlockCount() > 0);
// Recreate the disk cache
Filepath path;
track[index]->GetPath(path);
disk.dcache = new DiskCache(path, disk.size, disk.blocks);
disk.dcache = new DiskCache(path, GetSectorSize(), GetBlockCount());
disk.dcache->SetRawMode(rawfile);
// Reset data index
@ -639,13 +601,7 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, DWORD block)
//---------------------------------------------------------------------------
int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
{
int loop;
int i;
BOOL msf;
DWORD lba;
ASSERT(cdb);
ASSERT(cdb[0] == 0x43);
ASSERT(buf);
// Check if ready
@ -663,18 +619,14 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
memset(buf, 0, length);
// Get MSF Flag
if (cdb[1] & 0x02) {
msf = TRUE;
} else {
msf = FALSE;
}
bool msf = cdb[1] & 0x02;
// Get and check the last track number
int last = track[tracks - 1]->GetTrackNo();
if ((int)cdb[6] > last) {
// Except for AA
if (cdb[6] != 0xaa) {
disk.code = DISK_INVALIDCDB;
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
}
@ -699,7 +651,7 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
buf[2] = (BYTE)track[0]->GetTrackNo();
buf[3] = (BYTE)last;
buf[6] = 0xaa;
lba = track[tracks - 1]->GetLast() + 1;
DWORD lba = track[tracks - 1]->GetLast() + 1;
if (msf) {
LBAtoMSF(lba, &buf[8]);
} else {
@ -710,13 +662,13 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
}
// Otherwise, error
disk.code = DISK_INVALIDCDB;
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
}
// Number of track descriptors returned this time (number of loops)
loop = last - track[index]->GetTrackNo() + 1;
int loop = last - track[index]->GetTrackNo() + 1;
ASSERT(loop >= 1);
// Create header
@ -727,7 +679,7 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
buf += 4;
// Loop....
for (i = 0; i < loop; i++) {
for (int i = 0; i < loop; i++) {
// ADR and Control
if (track[index]->IsAudio()) {
// audio track
@ -757,39 +709,6 @@ int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
return length;
}
//---------------------------------------------------------------------------
//
// PLAY AUDIO
//
//---------------------------------------------------------------------------
BOOL SCSICD::PlayAudio(const DWORD* /*cdb*/)
{
disk.code = DISK_INVALIDCDB;
return FALSE;
}
//---------------------------------------------------------------------------
//
// PLAY AUDIO MSF
//
//---------------------------------------------------------------------------
BOOL SCSICD::PlayAudioMSF(const DWORD* /*cdb*/)
{
disk.code = DISK_INVALIDCDB;
return FALSE;
}
//---------------------------------------------------------------------------
//
// PLAY AUDIO TRACK
//
//---------------------------------------------------------------------------
BOOL SCSICD::PlayAudioTrack(const DWORD* /*cdb*/)
{
disk.code = DISK_INVALIDCDB;
return FALSE;
}
//---------------------------------------------------------------------------
//
// LBA→MSF Conversion
@ -892,7 +811,7 @@ int SCSICD::SearchTrack(DWORD lba) const
// Next Frame
//
//---------------------------------------------------------------------------
BOOL SCSICD::NextFrame()
bool SCSICD::NextFrame()
{
ASSERT((frame >= 0) && (frame < 75));
@ -900,20 +819,5 @@ BOOL SCSICD::NextFrame()
frame = (frame + 1) % 75;
// FALSE after one lap
if (frame != 0) {
return TRUE;
} else {
return FALSE;
}
}
//---------------------------------------------------------------------------
//
// Get CD-DA buffer
//
//---------------------------------------------------------------------------
void SCSICD::GetBuf(
DWORD* /*buffer*/, int /*samples*/, DWORD /*rate*/)
{
// TODO Missing implementation?
return frame != 0;
}

View File

@ -38,7 +38,7 @@ public:
// Basic Functions
CDTrack(SCSICD *scsicd); // Constructor
virtual ~CDTrack(); // Destructor
BOOL Init(int track, DWORD first, DWORD last); // Initialization
void Init(int track, DWORD first, DWORD last); // Initialization
// Properties
void SetPath(BOOL cdda, const Filepath& path); // Set the path
@ -62,47 +62,12 @@ private:
Filepath imgpath; // Image file path
};
//===========================================================================
//
// CD-DA Buffer
//
//===========================================================================
class CDDABuf
{
public:
// Basic Functions
CDDABuf(); // Constructor
virtual ~CDDABuf(); // Destructor
#if 0
BOOL Init(); // Initialization
BOOL Load(const Filepath& path); // Load
BOOL Save(const Filepath& path); // Save
// API
void Clear(); // Clear the buffer
BOOL Open(Filepath& path); // File specification
BOOL GetBuf(DWORD *buffer, int frames); // Get the buffer
BOOL IsValid(); // Check if Valid
BOOL ReadReq(); // Read Request
BOOL IsEnd() const; // Finish check
private:
Filepath wavepath; // Wave path
BOOL valid; // Open result (is it valid?)
DWORD *buf; // Data buffer
DWORD read; // Read pointer
DWORD write; // Write pointer
DWORD num; // Valid number of data
DWORD rest; // Remaining file size
#endif
};
//===========================================================================
//
// SCSI CD-ROM
//
//===========================================================================
class SCSICD : public Disk
class SCSICD : public Disk, public FileSupport
{
public:
// Number of tracks
@ -113,19 +78,18 @@ public:
public:
// Basic Functions
SCSICD(); // Constructor
virtual ~SCSICD(); // Destructor
void Open(const Filepath& path, BOOL attn = TRUE); // Open
~SCSICD(); // Destructor
void Open(const Filepath& path); // Open
// commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
int Read(const DWORD *cdb, BYTE *buf, DWORD block) override; // READ command
int ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC command
BOOL PlayAudio(const DWORD *cdb); // PLAY AUDIO command
BOOL PlayAudioMSF(const DWORD *cdb); // PLAY AUDIO MSF command
BOOL PlayAudioTrack(const DWORD *cdb); // PLAY AUDIO TRACK command
// CD-DA
BOOL NextFrame(); // Frame notification
// TODO Never called
bool NextFrame(); // Frame notification
// TODO Never called
void GetBuf(DWORD *buffer, int samples, DWORD rate); // Get CD-DA buffer
// LBA-MSF変換
@ -148,12 +112,4 @@ private:
int audioindex; // Current audio track
int frame; // Frame number
#if 0
CDDABuf da_buf; // CD-DA buffer
int da_num; // Number of CD-DA tracks
int da_cur; // CD-DA current track
int da_next; // CD-DA next track
BOOL da_req; // CD-DA data request
#endif
};

View File

@ -17,6 +17,7 @@
#include "xm6.h"
#include "fileio.h"
#include "exceptions.h"
#include <sstream>
//===========================================================================
//
@ -29,9 +30,10 @@
// Constructor
//
//---------------------------------------------------------------------------
SCSIHD::SCSIHD() : Disk("SCHD")
SCSIHD::SCSIHD(bool removable) : Disk(removable ? "SCRM" : "SCHD")
{
disk.protectable = true;
SetRemovable(removable);
SetProtectable(true);
}
//---------------------------------------------------------------------------
@ -42,12 +44,12 @@ SCSIHD::SCSIHD() : Disk("SCHD")
void SCSIHD::Reset()
{
// Unlock and release attention
disk.locked = FALSE;
disk.attn = FALSE;
SetLocked(false);
SetAttn(false);
// No reset, clear code
disk.reset = FALSE;
disk.code = 0x00;
SetReset(false);
SetStatusCode(STATUS_NOERROR);
}
//---------------------------------------------------------------------------
@ -55,38 +57,43 @@ void SCSIHD::Reset()
// Open
//
//---------------------------------------------------------------------------
void SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
void SCSIHD::Open(const Filepath& path)
{
ASSERT(!disk.ready);
ASSERT(!IsReady());
// read open required
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open hard disk file read-only");
throw io_exception("Can't open hard disk file read-only");
}
// Get file size
off64_t size = fio.GetFileSize();
off_t size = fio.GetFileSize();
fio.Close();
// Must be 512 bytes
// Must be a multiple of 512 bytes
if (size & 0x1ff) {
throw ioexception("File size must be a multiple of 512 bytes");
throw io_exception("File size must be a multiple of 512 bytes");
}
// 2TB according to xm6i
// There is a similar one in wxw/wxw_cfg.cpp
// Bigger files/drives require READ/WRITE(16) to be implemented
// 2TB is the current maximum
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
throw ioexception("File size must not exceed 2 TB");
throw io_exception("File size must not exceed 2 TB");
}
// sector size and number of blocks
disk.size = 9;
disk.blocks = (DWORD)(size >> 9);
// sector size 512 bytes and number of blocks
SetSectorSize(9);
SetBlockCount((DWORD)(size >> 9));
LOGINFO("Media capacity for image file '%s': %d blocks", path.GetPath(),GetBlockCount());
// Set the default product name based on the drive capacity
stringstream product;
product << DEFAULT_PRODUCT << " " << (GetBlockCount() >> 11) << " MB";
SetProduct(product.str(), false);
// Call base class
Disk::Open(path);
FileSupport::SetPath(path);
}
//---------------------------------------------------------------------------
@ -94,85 +101,52 @@ void SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIHD:: Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf)
{
char vendor[32];
char product[32];
char rev[32];
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
SetStatusCode(STATUS_INVALIDCDB);
return 0;
}
// Ready check (Error if no image file)
if (!disk.ready) {
disk.code = DISK_NOTREADY;
if (!IsReady()) {
SetStatusCode(STATUS_NOTREADY);
return 0;
}
// Basic data
// buf[0] ... Direct Access Device
// buf[1] ... Bit 7 set means removable
// buf[2] ... SCSI-2 compliant command system
// buf[3] ... SCSI-2 compliant Inquiry response
// buf[4] ... Inquiry additional data
memset(buf, 0, 8);
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
if (((cdb[1] >> 5) & 0x07) != GetLun()) {
buf[0] = 0x7f;
}
buf[1] = IsRemovable() ? 0x80 : 0x00;
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 122 + 3; // Value close to real HDD
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Determine vendor name/product name
sprintf(vendor, BENDER_SIGNATURE);
int size = disk.blocks >> 11;
if (size < 300)
sprintf(product, "PRODRIVE LPS%dS", size);
else if (size < 600)
sprintf(product, "MAVERICK%dS", size);
else if (size < 800)
sprintf(product, "LIGHTNING%dS", size);
else if (size < 1000)
sprintf(product, "TRAILBRAZER%dS", size);
else if (size < 2000)
sprintf(product, "FIREBALL%dS", size);
else
sprintf(product, "FBSE%d.%dS", size / 1000, (size % 1000) / 100);
// Vendor name
memcpy(&buf[8], vendor, strlen(vendor));
// Product name
memcpy(&buf[16], product, strlen(product));
// Revision
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
// Size of data that can be returned
size = (buf[4] + 5);
int size = (buf[4] + 5);
// Limit if the other buffer is small
if (size > (int)cdb[4]) {
size = (int)cdb[4];
}
// Success
disk.code = DISK_NOERROR;
return size;
}
@ -182,7 +156,7 @@ int SCSIHD:: Inquiry(
// *Not affected by disk.code
//
//---------------------------------------------------------------------------
BOOL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
bool SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
BYTE page;
int size;
@ -195,13 +169,13 @@ BOOL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// Mode Parameter header
if (length >= 12) {
// Check the block length bytes
size = 1 << disk.size;
size = 1 << GetSectorSize();
if (buf[9] != (BYTE)(size >> 16) ||
buf[10] != (BYTE)(size >> 8) ||
buf[11] != (BYTE)size) {
// currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
SetStatusCode(STATUS_INVALIDPRM);
return false;
}
buf += 12;
length -= 12;
@ -216,12 +190,12 @@ BOOL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// format device
case 0x03:
// check the number of bytes in the physical sector
size = 1 << disk.size;
size = 1 << GetSectorSize();
if (buf[0xc] != (BYTE)(size >> 8) ||
buf[0xd] != (BYTE)size) {
// currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
SetStatusCode(STATUS_INVALIDPRM);
return false;
}
break;
@ -253,7 +227,31 @@ BOOL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
}
// Do not generate an error for the time being (MINIX)
disk.code = DISK_NOERROR;
return TRUE;
return true;
}
//---------------------------------------------------------------------------
//
// Add Vendor special page to make drive Apple compatible
//
//---------------------------------------------------------------------------
int SCSIHD::AddVendor(int page, bool change, BYTE *buf)
{
ASSERT(buf);
// Page code 48 or 63
if (page != 0x30 && page != 0x3f) {
return 0;
}
// Set the message length
buf[0] = 0x30;
buf[1] = 0x1c;
// No changeable area
if (!change) {
memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20);
}
return 30;
}

View File

@ -19,20 +19,25 @@
#include "disk.h"
#include "filepath.h"
#define DEFAULT_PRODUCT "SCSI HD"
//===========================================================================
//
// SCSI Hard Disk
//
//===========================================================================
class SCSIHD : public Disk
class SCSIHD : public Disk, public FileSupport
{
public:
// Basic Functions
SCSIHD(); // Constructor
SCSIHD(bool = false); // Constructor
void Reset(); // Reset
void Open(const Filepath& path, BOOL attn = TRUE); // Open
void Open(const Filepath& path); // Open
// commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); // MODE SELECT(6) command
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override; // MODE SELECT(6) command
// Internal processing
int AddVendor(int page, bool change, BYTE *buf) override; // Add vendor special page
};

View File

@ -1,91 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Hard Disk for Apple Macintosh ]
//
//---------------------------------------------------------------------------
#include "scsihd_apple.h"
//===========================================================================
//
// SCSI hard disk (Macintosh Apple genuine)
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIHD_APPLE::SCSIHD_APPLE() : SCSIHD()
{
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIHD_APPLE::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
char vendor[32];
char product[32];
// Call the base class
int size = SCSIHD::Inquiry(cdb, buf, major, minor);
// End if there is an error in the base class
if (size == 0) {
return 0;
}
// Vendor name
sprintf(vendor, " SEAGATE");
memcpy(&buf[8], vendor, strlen(vendor));
// Product name
sprintf(product, " ST225N");
memcpy(&buf[16], product, strlen(product));
return size;
}
//---------------------------------------------------------------------------
//
// Add Vendor special page
//
//---------------------------------------------------------------------------
int SCSIHD_APPLE::AddVendor(int page, BOOL change, BYTE *buf)
{
ASSERT(buf);
// Page code 48
if ((page != 0x30) && (page != 0x3f)) {
return 0;
}
// Set the message length
buf[0] = 0x30;
buf[1] = 0x1c;
// No changeable area
if (change) {
return 30;
}
// APPLE COMPUTER, INC.
memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20);
return 30;
}

View File

@ -1,35 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI Hard Disk for Apple Macintosh ]
//
//---------------------------------------------------------------------------
#pragma once
#include "scsihd.h"
//===========================================================================
//
// SCSI Hard Disk(Genuine Apple Macintosh)
//
//===========================================================================
class SCSIHD_APPLE : public SCSIHD
{
public:
// Basic Functions
SCSIHD_APPLE(); // Constructor
// commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
// Internal processing
int AddVendor(int page, BOOL change, BYTE *buf); // Add vendor special page
};

View File

@ -31,6 +31,8 @@
//---------------------------------------------------------------------------
SCSIHD_NEC::SCSIHD_NEC() : SCSIHD()
{
SetVendor("NEC");
// Work initialization
cylinders = 0;
heads = 0;
@ -68,42 +70,39 @@ static inline DWORD getDwordLE(const BYTE *b)
//---------------------------------------------------------------------------
void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
{
Fileio fio;
off64_t size;
BYTE hdr[512];
LPCTSTR ext;
ASSERT(!disk.ready);
ASSERT(!IsReady());
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open hard disk file read-only");
throw io_exception("Can't open hard disk file read-only");
}
// Get file size
size = fio.GetFileSize();
off_t size = fio.GetFileSize();
// Read header
if (size >= (off64_t)sizeof(hdr)) {
BYTE hdr[512];
if (size >= (off_t)sizeof(hdr)) {
if (!fio.Read(hdr, sizeof(hdr))) {
fio.Close();
throw ioexception("Can't read hard disk file header");
throw io_exception("Can't read NEC hard disk file header");
}
}
fio.Close();
// Must be in 512 byte units
if (size & 0x1ff) {
throw ioexception("File size must be a multiple of 512 bytes");
throw io_exception("File size must be a multiple of 512 bytes");
}
// 2TB according to xm6i
// 2TB is the current maximum
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
throw ioexception("File size must not exceed 2 TB");
throw io_exception("File size must not exceed 2 TB");
}
// Determine parameters by extension
ext = path.GetFileExt();
LPCTSTR ext = path.GetFileExt();
if (strcasecmp(ext, _T(".HDN")) == 0) {
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
imgoffset = 0;
@ -128,34 +127,37 @@ void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]);
sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]);
sectorsize = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2 + 2]);
imgsize = (off64_t)cylinders * heads * sectors * sectorsize;
imgsize = (off_t)cylinders * heads * sectors * sectorsize;
}
// Supports 256 or 512 sector sizes
if (sectorsize != 256 && sectorsize != 512) {
throw ioexception("Sector size must be 256 or 512 bytes");
throw io_exception("Sector size must be 256 or 512 bytes");
}
// Image size consistency check
if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) {
throw ioexception("Image size consistency check failed");
throw io_exception("Image size consistency check failed");
}
// Sector size
// TODO Do not use disk.size directly
for(disk.size = 16; disk.size > 0; --(disk.size)) {
if ((1 << disk.size) == sectorsize)
break;
}
if (disk.size <= 0 || disk.size > 16) {
throw ioexception("Invalid disk size");
throw io_exception("Invalid disk size");
}
// Number of blocks
disk.blocks = (DWORD)(imgsize >> disk.size);
SetBlockCount((DWORD)(imgsize >> disk.size));
disk.imgoffset = imgoffset;
// Call the base class
LOGINFO("Media capacity for image file '%s': %d blocks", path.GetPath(), GetBlockCount());
Disk::Open(path);
FileSupport::SetPath(path);
}
//---------------------------------------------------------------------------
@ -163,28 +165,14 @@ void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIHD_NEC::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
int SCSIHD_NEC::Inquiry(const DWORD *cdb, BYTE *buf)
{
int size;
int size = SCSIHD::Inquiry(cdb, buf);
// Base class
size = SCSIHD::Inquiry(cdb, buf, major, minor);
// Exit if there is an error in the base class
if (size == 0) {
return 0;
}
// Changed to equivalent to SCSI-1
// This drive is a SCSI-1 SCCS drive
buf[2] = 0x01;
buf[3] = 0x01;
// Replace Vendor name
buf[8] = 'N';
buf[9] = 'E';
buf[10] = 'C';
return size;
}
@ -193,7 +181,7 @@ int SCSIHD_NEC::Inquiry(
// Error page added
//
//---------------------------------------------------------------------------
int SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
int SCSIHD_NEC::AddError(bool change, BYTE *buf)
{
ASSERT(buf);
@ -201,11 +189,6 @@ int SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
buf[0] = 0x01;
buf[1] = 0x06;
// No changeable area
if (change) {
return 8;
}
// The retry count is 0, and the limit time uses the default value inside the device.
return 8;
}
@ -215,7 +198,7 @@ int SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
// Format page added
//
//---------------------------------------------------------------------------
int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
int SCSIHD_NEC::AddFormat(bool change, BYTE *buf)
{
ASSERT(buf);
@ -230,7 +213,7 @@ int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
return 24;
}
if (disk.ready) {
if (IsReady()) {
// Set the number of tracks in one zone (PC-9801-55 seems to see this value)
buf[0x2] = (BYTE)(heads >> 8);
buf[0x3] = (BYTE)heads;
@ -246,7 +229,7 @@ int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
}
// Set removable attributes (remains of the old days)
if (disk.removable) {
if (IsRemovable()) {
buf[20] = 0x20;
}
@ -258,7 +241,7 @@ int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
// Drive page added
//
//---------------------------------------------------------------------------
int SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf)
int SCSIHD_NEC::AddDrive(bool change, BYTE *buf)
{
ASSERT(buf);
@ -267,11 +250,7 @@ int SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf)
buf[1] = 0x12;
// No changeable area
if (change) {
return 20;
}
if (disk.ready) {
if (!change && IsReady()) {
// Set the number of cylinders
buf[0x2] = (BYTE)(cylinders >> 16);
buf[0x3] = (BYTE)(cylinders >> 8);

View File

@ -26,22 +26,22 @@ class SCSIHD_NEC : public SCSIHD
{
public:
// Basic Functions
SCSIHD_NEC(); // Constructor
SCSIHD_NEC(); // Constructor
void Open(const Filepath& path, BOOL attn = TRUE); // Open
// commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
// Internal processing
int AddError(BOOL change, BYTE *buf); // Add error
int AddFormat(BOOL change, BYTE *buf); // Add format
int AddDrive(BOOL change, BYTE *buf); // Add drive
int AddError(bool change, BYTE *buf) override; // Add error
int AddFormat(bool change, BYTE *buf) override; // Add format
int AddDrive(bool change, BYTE *buf) override; // Add drive
private:
int cylinders; // Number of cylinders
int heads; // Number of heads
int sectors; // Number of sectors
int sectorsize; // Sector size
off64_t imgoffset; // Image offset
off64_t imgsize; // Image size
off_t imgoffset; // Image offset
off_t imgsize; // Image size
};

View File

@ -32,9 +32,10 @@
//---------------------------------------------------------------------------
SCSIMO::SCSIMO() : Disk("SCMO")
{
disk.removable = true;
disk.lockable = true;
disk.protectable = true;
SetRemovable(true);
SetProtectable(true);
SetProduct("M2513A");
}
//---------------------------------------------------------------------------
@ -42,56 +43,61 @@ SCSIMO::SCSIMO() : Disk("SCMO")
// Open
//
//---------------------------------------------------------------------------
void SCSIMO::Open(const Filepath& path, BOOL attn)
void SCSIMO::Open(const Filepath& path)
{
ASSERT(!disk.ready);
ASSERT(!IsReady());
// Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) {
throw ioexception("Can't open MO file read-only");
throw io_exception("Can't open MO file read-only");
}
// Get file size
off64_t size = fio.GetFileSize();
off_t size = fio.GetFileSize();
fio.Close();
switch (size) {
// 128MB
case 0x797f400:
disk.size = 9;
disk.blocks = 248826;
// 512 bytes per sector
SetSectorSize(9);
SetBlockCount(248826);
break;
// 230MB
case 0xd9eea00:
disk.size = 9;
disk.blocks = 446325;
// 512 bytes per sector
SetSectorSize(9);
SetBlockCount(446325);
break;
// 540MB
case 0x1fc8b800:
disk.size = 9;
disk.blocks = 1041500;
// 512 bytes per sector
SetSectorSize(9);
SetBlockCount(1041500);
break;
// 640MB
case 0x25e28000:
disk.size = 11;
disk.blocks = 310352;
// 2048 bytes per sector
SetSectorSize(11);
SetBlockCount(310352);
break;
// Other (this is an error)
default:
throw ioexception("Invalid MO file size");
throw io_exception("Invalid MO file size, supported sizes are 127398912 bytes (128 MB), "
"228518400 bytes (230 MB), 533248000 bytes (540 MB), 635600896 bytes (640 MB)");
}
// Call the base class
Disk::Open(path);
FileSupport::SetPath(path);
// Attention if ready
if (disk.ready && attn) {
disk.attn = TRUE;
if (IsReady()) {
SetAttn(true);
}
}
@ -100,19 +106,14 @@ void SCSIMO::Open(const Filepath& path, BOOL attn)
// INQUIRY
//
//---------------------------------------------------------------------------
int SCSIMO::Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
int SCSIMO::Inquiry(const DWORD *cdb, BYTE *buf)
{
int size;
char rev[32];
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
SetStatusCode(STATUS_INVALIDCDB);
return FALSE;
}
@ -126,7 +127,7 @@ int SCSIMO::Inquiry(
buf[0] = 0x07;
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
if (((cdb[1] >> 5) & 0x07) != GetLun()) {
buf[0] = 0x7f;
}
@ -135,30 +136,17 @@ int SCSIMO::Inquiry(
buf[3] = 0x02;
buf[4] = 36 - 5; // required
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Vendor name
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
// Product name
memcpy(&buf[16], "M2513A", 6);
// Revision (XM6 version number)
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
// Padded vendor, product, revision
memcpy(&buf[8], GetPaddedName().c_str(), 28);
// Size return data
size = (buf[4] + 5);
int size = (buf[4] + 5);
// Limit the size if the buffer is too small
if (size > (int)cdb[4]) {
size = (int)cdb[4];
}
// Success
disk.code = DISK_NOERROR;
return size;
}
@ -168,7 +156,7 @@ int SCSIMO::Inquiry(
// *Not affected by disk.code
//
//---------------------------------------------------------------------------
BOOL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
bool SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
int page;
int size;
@ -181,12 +169,12 @@ BOOL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// Mode Parameter header
if (length >= 12) {
// Check the block length (in bytes)
size = 1 << disk.size;
size = 1 << GetSectorSize();
if (buf[9] != (BYTE)(size >> 16) ||
buf[10] != (BYTE)(size >> 8) || buf[11] != (BYTE)size) {
// Currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
SetStatusCode(STATUS_INVALIDPRM);
return false;
}
buf += 12;
length -= 12;
@ -201,12 +189,12 @@ BOOL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// format device
case 0x03:
// Check the number of bytes in the physical sector
size = 1 << disk.size;
size = 1 << GetSectorSize();
if (buf[0xc] != (BYTE)(size >> 8) ||
buf[0xd] != (BYTE)size) {
// Currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
SetStatusCode(STATUS_INVALIDPRM);
return false;
}
break;
// vendor unique format
@ -227,9 +215,7 @@ BOOL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
}
// Do not generate an error for the time being (MINIX)
disk.code = DISK_NOERROR;
return TRUE;
return true;
}
//---------------------------------------------------------------------------
@ -278,11 +264,12 @@ int SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
further information: http://r2089.blog36.fc2.com/blog-entry-177.html
*/
if (disk.ready) {
if (IsReady()) {
unsigned spare = 0;
unsigned bands = 0;
DWORD blocks = GetBlockCount();
if (disk.size == 9) switch (disk.blocks) {
if (GetSectorSize() == 9) switch (blocks) {
// 128MB
case 248826:
spare = 1024;
@ -302,7 +289,7 @@ int SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
break;
}
if (disk.size == 11) switch (disk.blocks) {
if (GetSectorSize() == 11) switch (blocks) {
// 640MB
case 310352:
spare = 2244;
@ -318,10 +305,10 @@ int SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
buf[2] = 0; // format mode
buf[3] = 0; // type of format
buf[4] = (BYTE)(disk.blocks >> 24);
buf[5] = (BYTE)(disk.blocks >> 16);
buf[6] = (BYTE)(disk.blocks >> 8);
buf[7] = (BYTE)disk.blocks;
buf[4] = (BYTE)(blocks >> 24);
buf[5] = (BYTE)(blocks >> 16);
buf[6] = (BYTE)(blocks >> 8);
buf[7] = (BYTE)blocks;
buf[8] = (BYTE)(spare >> 8);
buf[9] = (BYTE)spare;
buf[10] = (BYTE)(bands >> 8);

View File

@ -24,16 +24,16 @@
// SCSI magneto-optical disk
//
//===========================================================================
class SCSIMO : public Disk
class SCSIMO : public Disk, public FileSupport
{
public:
// Basic Functions
SCSIMO(); // Constructor
void Open(const Filepath& path, BOOL attn = TRUE); // Open
void Open(const Filepath& path); // Open
// commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); // MODE SELECT(6) command
int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override; // MODE SELECT(6) command
// Internal processing
int AddVendor(int page, BOOL change, BYTE *buf); // Add vendor special page

View File

@ -1,48 +1,56 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// [ Exceptions ]
// Copyright (C) 2021 Uwe Seimet
//
// Various exceptions
//
//---------------------------------------------------------------------------
#if !defined(exceptions_h)
#define exceptions_h
#pragma once
#include <exception>
#include <string>
using namespace std;
class lunexception final : public exception {
private:
int lun;
public:
lunexception(int _lun) : lun(_lun) { }
~lunexception() { }
int getlun() const {
return lun;
}
};
class ioexception : public exception {
class illegal_argument_exception final : public exception {
private:
string msg;
public:
ioexception(const string& _msg) : msg(_msg) { }
~ioexception() { }
illegal_argument_exception(const string& _msg) : msg(_msg) {}
illegal_argument_exception() {};
const string& getmsg() const {
return msg;
}
};
#endif
class lun_exception final : public exception {
private:
int lun;
public:
lun_exception(int _lun) : lun(_lun) {}
~lun_exception() {}
int getlun() const {
return lun;
}
};
class io_exception : public exception {
private:
string msg;
public:
io_exception(const string& _msg) : msg(_msg) {}
~io_exception() {}
const string& getmsg() const {
return msg;
}
};

View File

@ -141,11 +141,6 @@ BOOL Fileio::Open(LPCTSTR fname, OpenMode mode, BOOL directIO)
handle = open(fname, O_RDWR | omode);
break;
// アペンド
case Append:
handle = open(fname, O_CREAT | O_WRONLY | O_APPEND | omode, 0666);
break;
// それ以外
default:
ASSERT(FALSE);
@ -260,7 +255,7 @@ BOOL Fileio::Write(const void *buffer, int size)
// シーク
//
//---------------------------------------------------------------------------
BOOL Fileio::Seek(off64_t offset, BOOL relative)
BOOL Fileio::Seek(off_t offset, BOOL relative)
{
ASSERT(handle >= 0);
ASSERT(offset >= 0);
@ -282,10 +277,10 @@ BOOL Fileio::Seek(off64_t offset, BOOL relative)
// ファイルサイズ取得
//
//---------------------------------------------------------------------------
off64_t Fileio::GetFileSize()
off_t Fileio::GetFileSize()
{
off64_t cur;
off64_t end;
off_t cur;
off_t end;
ASSERT(handle >= 0);
@ -306,9 +301,9 @@ off64_t Fileio::GetFileSize()
// ファイル位置取得
//
//---------------------------------------------------------------------------
off64_t Fileio::GetFilePos() const
off_t Fileio::GetFilePos() const
{
off64_t pos;
off_t pos;
ASSERT(handle >= 0);

View File

@ -39,8 +39,7 @@ public:
enum OpenMode {
ReadOnly, // 読み込みのみ
WriteOnly, // 書き込みのみ
ReadWrite, // 読み書き両方
Append // アペンド
ReadWrite // 読み書き両方
};
public:
@ -61,15 +60,15 @@ public:
// オープン
BOOL OpenDIO(const Filepath& path, OpenMode mode);
// オープン
BOOL Seek(off64_t offset, BOOL relative = FALSE);
BOOL Seek(off_t offset, BOOL relative = FALSE);
// シーク
BOOL Read(void *buffer, int size);
// 読み込み
BOOL Write(const void *buffer, int size);
// 書き込み
off64_t GetFileSize();
off_t GetFileSize();
// ファイルサイズ取得
off64_t GetFilePos() const;
off_t GetFilePos() const;
// ファイル位置取得
void Close();
// クローズ

View File

@ -487,7 +487,7 @@ void GPIOBUS::SetENB(BOOL ast)
// Get BSY signal
//
//---------------------------------------------------------------------------
BOOL GPIOBUS::GetBSY()
bool GPIOBUS::GetBSY()
{
return GetSignal(PIN_BSY);
}
@ -497,7 +497,7 @@ BOOL GPIOBUS::GetBSY()
// Set BSY signal
//
//---------------------------------------------------------------------------
void GPIOBUS::SetBSY(BOOL ast)
void GPIOBUS::SetBSY(bool ast)
{
// Set BSY signal
SetSignal(PIN_BSY, ast);
@ -898,12 +898,7 @@ int GPIOBUS::CommandHandShake(BYTE *buf)
goto irq_enable_exit;
}
// Distinguise whether the command is 6 bytes or 10 bytes
if (*buf >= 0x20 && *buf <= 0x7D) {
count = 10;
} else {
count = 6;
}
count = GetCommandByteCount(*buf);
// Increment buffer pointer
buf++;
@ -1609,6 +1604,26 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
return GetPhase(mci);
}
//---------------------------------------------------------------------------
//
// Get the number of bytes for a command
//
// TODO The command length should be determined based on the bytes transferred in the COMMAND phase
//
//---------------------------------------------------------------------------
int GPIOBUS::GetCommandByteCount(BYTE opcode) {
if (opcode == 0x88 || opcode == 0x8A || opcode == 0x8F || opcode == 0x9E) {
return 16;
}
else if (opcode == 0xA0) {
return 12;
}
else if (opcode >= 0x20 && opcode <= 0x7D) {
return 10;
} else {
return 6;
}
}
//---------------------------------------------------------------------------
//

View File

@ -509,9 +509,9 @@ public:
void SetENB(BOOL ast);
// Set ENB signal
BOOL GetBSY();
bool GetBSY();
// Get BSY signal
void SetBSY(BOOL ast);
void SetBSY(bool ast);
// Set BSY signal
BOOL GetSEL();
@ -575,7 +575,9 @@ public:
static BUS::phase_t GetPhaseRaw(DWORD raw_data);
// Get the phase based on raw data
#ifdef USE_SEL_EVENT_ENABLE
static int GetCommandByteCount(BYTE opcode);
#ifdef USE_SEL_EVENT_ENABLE
// SEL signal interrupt
int PollSelectEvent();
// SEL signal event polling

View File

@ -23,18 +23,11 @@
spdlog::log(loglevel, logbuf); \
};
#ifdef NDEBUG
// If we're doing a non-debug build, we want to skip the overhead of
// formatting the string, then calling the logger
#define LOGTRACE(...) ((void)0)
#define LOGDEBUG(...) ((void)0)
#else
#define LOGTRACE(...) SPDLOGWRAPPER(spdlog::level::trace, __VA_ARGS__)
#define LOGDEBUG(...) SPDLOGWRAPPER(spdlog::level::debug, __VA_ARGS__)
#endif
#define LOGINFO(...) SPDLOGWRAPPER(spdlog::level::info, __VA_ARGS__)
#define LOGWARN(...) SPDLOGWRAPPER(spdlog::level::warn, __VA_ARGS__)
#define LOGERROR(...) SPDLOGWRAPPER(spdlog::level::err, __VA_ARGS__)
#define LOGCRITICAL(...) SPDLOGWRAPPER(spdlog::level::critical, __VA_ARGS__)
#endif // log_h
#endif

View File

@ -55,6 +55,7 @@
#include <poll.h>
#include <dirent.h>
#include <pwd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/epoll.h>
@ -102,9 +103,9 @@
//
//---------------------------------------------------------------------------
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned long long QWORD;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
typedef int BOOL;
typedef char TCHAR;
typedef char *LPTSTR;
@ -128,6 +129,4 @@ typedef const char *LPCSTR;
#define _MAX_FNAME 256
#define _MAX_EXT 256
#define off64_t off_t
#endif // os_h

View File

@ -0,0 +1,80 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <unistd.h>
#include <sstream>
#include "rascsi_interface.pb.h"
#include "exceptions.h"
#include "protobuf_util.h"
using namespace std;
using namespace rascsi_interface;
//---------------------------------------------------------------------------
//
// Serialize/Deserialize protobuf message: Length followed by the actual data.
// Little endian is assumed.
//
//---------------------------------------------------------------------------
void SerializeMessage(int fd, const google::protobuf::MessageLite& message)
{
string data;
message.SerializeToString(&data);
// Write the size of the protobuf data as a header
int32_t size = data.length();
if (write(fd, &size, sizeof(size)) != sizeof(size)) {
throw io_exception("Can't write protobuf header");
}
// Write the actual protobuf data
uint8_t buf[size];
memcpy(buf, data.data(), size);
if (write(fd, buf, size) != size) {
throw io_exception("Can't write protobuf data");
}
}
void DeserializeMessage(int fd, google::protobuf::MessageLite& message)
{
// Read the header with the size of the protobuf data
uint8_t header_buf[4];
int bytes_read = ReadNBytes(fd, header_buf, 4);
if (bytes_read < 4) {
return;
}
int32_t size = (header_buf[3] << 24) + (header_buf[2] << 16) + (header_buf[1] << 8) + header_buf[0];
// Read the binary protobuf data
uint8_t data_buf[size];
bytes_read = ReadNBytes(fd, data_buf, size);
if (bytes_read < size) {
throw io_exception("Missing protobuf data");
}
// Create protobuf message
string data((const char *)data_buf, size);
message.ParseFromString(data);
}
int ReadNBytes(int fd, uint8_t *buf, int n)
{
int offset = 0;
while (offset < n) {
ssize_t len = read(fd, buf + offset, n - offset);
if (!len) {
break;
}
offset += len;
}
return offset;
}

View File

@ -0,0 +1,19 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
// Helper methods for serializing/deserializing protobuf messages
//
//---------------------------------------------------------------------------
#pragma once
#include "google/protobuf/message_lite.h"
#include "rascsi_interface.pb.h"
void SerializeMessage(int, const google::protobuf::MessageLite&);
void DeserializeMessage(int, google::protobuf::MessageLite&);
int ReadNBytes(int, uint8_t *, int);

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +1,124 @@
//
// Each rascsi remote interface message is preceded by a little endian 32 bit header,
// which contains the protobuf message size.
//
syntax = "proto3";
package rascsi_interface;
// The supported device types
// The available device types
enum PbDeviceType {
UNDEFINED = 0;
SASI_HD = 1;
SCSI_HD = 2;
MO = 3;
CD = 4;
BR = 5;
NUVOLINK = 6;
DAYNAPORT = 7;
// Non-removable SASI drive
SAHD = 1;
// Non-removable SCSI drive
SCHD = 2;
// Removable SCSI drive
SCRM = 3;
// Magnoto-Optical drive
SCMO = 4;
// CD-ROM drive
SCCD = 5;
// Network bridge
SCBR = 6;
// DaynaPort network adapter
SCDP = 7;
}
// rascsi remote operations
enum PbOperation {
NONE = 0;
// Returns the full server information
// Returns the server information
SERVER_INFO = 1;
// Returns the device list only (required for rasctl/logging semantics compatibility)
LIST = 2 [deprecated = true];
// Set the default folder for image files, PbCommand.params contains the folder name
DEFAULT_FOLDER = 2;
// Set server log level, PbCommand.params contains the log level
LOG_LEVEL = 3;
// Attach new device
ATTACH = 4;
// Detach device. Detach all devices if PbCommand.params == "all". In this case ID and unit are ignored.
DETACH = 5;
// Insert media
INSERT = 6;
// Eject media
EJECT = 7;
// Write-protect media (not possible for read-only media)
PROTECT = 8;
// Make media writable (not possible for read-only media)
UNPROTECT = 9;
}
// Commands rascsi can execute
message PbCommand {
PbOperation cmd = 1;
int32 id = 2;
int32 un = 3;
PbDeviceType type = 4;
string params = 5;
// The image file data
message PbImageFile {
string name = 1;
bool read_only = 2;
int64 size = 3;
}
// The result of a command
message PbResult {
bool status = 1;
string msg = 2;
}
// The device meta data
message PbDevice {
// The device definition, sent from the client to the server
message PbDeviceDefinition {
int32 id = 1;
int32 un = 2;
int32 unit = 2;
PbDeviceType type = 3;
string file = 4;
bool read_only = 5;
// Note: Read-only media (e.g. CD-ROMs) are not protectable
bool protectable = 6;
// Note: Read-only media (e.g. CD-ROMs) are not protected but just read-only
bool protected = 7;
bool removable = 8;
bool removed = 9;
bool lockable = 10;
bool locked = 11;
bool supports_file = 12;
// The device name, format is VENDOR:PRODUCT:REVISION
string name = 5;
bool protected = 6;
}
message PbDeviceDefinitions {
repeated PbDeviceDefinition devices = 1;
}
// The device data, sent from the server to the client
message PbDevice {
int32 id = 1;
int32 unit = 2;
PbDeviceType type = 3;
PbImageFile file = 4;
string vendor = 5;
string product = 6;
string revision = 7;
// Read-only media (e.g. CD-ROMs) are not protectable but read-only all the time
bool read_only = 8;
// Media can be write-protected
bool protectable = 9;
// Media is write-protected
bool protected = 10;
// Media can be removed
bool removable = 11;
// Media is removed
bool removed = 12;
// Media can be locked
bool lockable = 13;
// Media is locked
bool locked = 14;
// Device supports image file
bool supports_file = 15;
}
message PbDevices {
repeated PbDevice devices = 1;
}
// Commands rascsi can execute and their parameters
message PbCommand {
PbOperation cmd = 1;
// The optional device list
PbDeviceDefinitions devices = 2;
// The optional parameters, depending on the operation
string params = 3;
}
// The result of a command
message PbResult {
// false means that an error occurred
bool status = 1;
// The (error) message
string msg = 2;
}
// The rascsi server information
message PbServerInfo {
string rascsi_version = 1;
@ -75,7 +127,7 @@ message PbServerInfo {
string current_log_level = 3;
string default_image_folder = 4;
// Files in the default folder
repeated string available_image_files = 5;
repeated PbImageFile available_image_files = 5;
// The attached devices
PbDevices devices = 6;
}

View File

@ -24,7 +24,7 @@ static char rascsi_version_string[30]; // Allow for string up to "XX.XX.XXX" + n
// Get the RaSCSI version string
//
//---------------------------------------------------------------------------
char* rascsi_get_version_string()
const char* rascsi_get_version_string()
{
if(rascsi_patch_version < 0)
{
@ -42,3 +42,5 @@ char* rascsi_get_version_string()
}
return rascsi_version_string;
}

View File

@ -18,4 +18,4 @@ extern const int rascsi_patch_version; // Patch number
// Fetch the version string
//
//---------------------------------------------------------------------------
extern char* rascsi_get_version_string();
const char* rascsi_get_version_string();

View File

@ -10,10 +10,10 @@
//---------------------------------------------------------------------------
#include <netdb.h>
#include "google/protobuf/message_lite.h"
#include "os.h"
#include "rascsi_version.h"
#include "exceptions.h"
#include "protobuf_util.h"
#include "rasutil.h"
#include "rascsi_interface.pb.h"
#include <sstream>
@ -35,12 +35,12 @@ int SendCommand(const string& hostname, int port, const PbCommand& command)
try {
struct hostent *host = gethostbyname(hostname.c_str());
if (!host) {
throw ioexception("Can't resolve hostname '" + hostname + "'");
throw io_exception("Can't resolve hostname '" + hostname + "'");
}
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
throw ioexception("Can't create socket");
throw io_exception("Can't create socket");
}
struct sockaddr_in server;
@ -53,19 +53,19 @@ int SendCommand(const string& hostname, int port, const PbCommand& command)
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
ostringstream error;
error << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
throw ioexception(error.str());
throw io_exception(error.str());
}
SerializeMessage(fd, command);
}
catch(const ioexception& e) {
catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl;
if (fd >= 0) {
close(fd);
}
exit(fd < 0 ? ENOTCONN : -1);
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
}
return fd;
@ -84,12 +84,14 @@ bool ReceiveResult(int fd)
close(fd);
if (!result.status()) {
throw ioexception(result.msg());
throw io_exception(result.msg());
}
cout << result.msg() << endl;
if (!result.msg().empty()) {
cout << result.msg() << endl;
}
}
catch(const ioexception& e) {
catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl;
return false;
@ -107,25 +109,25 @@ bool ReceiveResult(int fd)
void CommandList(const string& hostname, int port)
{
PbCommand command;
command.set_cmd(LIST);
command.set_cmd(SERVER_INFO);
int fd = SendCommand(hostname.c_str(), port, command);
PbDevices devices;
PbServerInfo serverInfo;
try {
DeserializeMessage(fd, devices);
DeserializeMessage(fd, serverInfo);
}
catch(const ioexception& e) {
catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl;
close(fd);
exit(-1);
exit(EXIT_FAILURE);
}
close (fd);
close(fd);
cout << ListDevices(devices) << endl;
cout << ListDevices(serverInfo.devices()) << endl;
}
void CommandLogLevel(const string& hostname, int port, const string& log_level)
@ -139,6 +141,17 @@ void CommandLogLevel(const string& hostname, int port, const string& log_level)
close(fd);
}
void CommandDefaultImageFolder(const string& hostname, int port, const string& folder)
{
PbCommand command;
command.set_cmd(DEFAULT_FOLDER);
command.set_params(folder);
int fd = SendCommand(hostname.c_str(), port, command);
ReceiveResult(fd);
close(fd);
}
void CommandServerInfo(const string& hostname, int port)
{
PbCommand command;
@ -150,12 +163,12 @@ void CommandServerInfo(const string& hostname, int port)
try {
DeserializeMessage(fd, serverInfo);
}
catch(const ioexception& e) {
catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl;
close(fd);
exit(-1);
exit(EXIT_FAILURE);
}
close(fd);
@ -179,19 +192,71 @@ void CommandServerInfo(const string& hostname, int port)
cout << " No image files available in the default folder" << endl;
}
else {
list<string> sorted_image_files;
list<string> sorted_files;
for (int i = 0; i < serverInfo.available_image_files_size(); i++) {
sorted_image_files.push_back(serverInfo.available_image_files(i));
sorted_files.push_back(serverInfo.available_image_files(i).name());
}
sorted_image_files.sort();
sorted_files.sort();
cout << "Image files available in the default folder:" << endl;
for (auto it = sorted_image_files.begin(); it != sorted_image_files.end(); ++it) {
for (auto it = sorted_files.begin(); it != sorted_files.end(); ++it) {
cout << " " << *it << endl;
}
}
}
PbOperation ParseOperation(const char *optarg)
{
switch (tolower(optarg[0])) {
case 'a':
return ATTACH;
case 'd':
return DETACH;
case 'i':
return INSERT;
case 'e':
return EJECT;
case 'p':
return PROTECT;
case 'u':
return UNPROTECT;
default:
return NONE;
}
}
PbDeviceType ParseType(const char *optarg)
{
string t = optarg;
transform(t.begin(), t.end(), t.begin(), ::toupper);
PbDeviceType type;
if (PbDeviceType_Parse(t, &type)) {
return type;
}
else {
// Parse legacy types
switch (tolower(optarg[0])) {
case 'm':
return SCMO;
case 'c':
return SCCD;
case 'b':
return SCBR;
}
}
return UNDEFINED;
}
//---------------------------------------------------------------------------
//
// Main processing
@ -205,12 +270,14 @@ 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] [-f FILE] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v]" << 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 << " where ID := {0|1|2|3|4|5|6|7}" << endl;
cerr << " UNIT := {0|1} default setting is 0." << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect}" << endl;
cerr << " TYPE := {hd|mo|cd|bridge|daynaport}" << endl;
cerr << " TYPE := {sahd|schd|scrm|sccd|scmo|scbr|scdp} or legacy types {hd|mo|cd|bridge}" << 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;
cerr << " HOST := rascsi host to connect to, default is 'localhost'" << endl;
cerr << " PORT := rascsi port to connect to, default is 6868" << endl;
cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'trace'" << endl;
@ -218,155 +285,115 @@ int main(int argc, char* argv[])
cerr << "Usage: " << argv[0] << " -l" << endl;
cerr << " Print device list." << endl;
exit(0);
exit(EXIT_SUCCESS);
}
// Parse the arguments
int opt;
int id = -1;
int un = 0;
PbOperation cmd = LIST;
PbDeviceType type = UNDEFINED;
PbCommand command;
PbDeviceDefinitions devices;
command.set_allocated_devices(&devices);
PbDeviceDefinition *device = devices.add_devices();
device->set_id(-1);
const char *hostname = "localhost";
int port = 6868;
string params;
opterr = 0;
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:u:g:lsv")) != -1) {
string log_level;
string default_folder;
bool list = false;
opterr = 1;
int opt;
while ((opt = getopt(argc, argv, "i:u:c:t:f:d:h:n:p:u:g:lsv")) != -1) {
switch (opt) {
case 'i':
id = optarg[0] - '0';
device->set_id(optarg[0] - '0');
break;
case 'u':
un = optarg[0] - '0';
device->set_unit(optarg[0] - '0');
break;
case 'c':
switch (tolower(optarg[0])) {
case 'a':
cmd = ATTACH;
break;
case 'd':
cmd = DETACH;
break;
case 'i':
cmd = INSERT;
break;
case 'e':
cmd = EJECT;
break;
case 'p':
cmd = PROTECT;
break;
case 'u':
cmd = UNPROTECT;
break;
}
command.set_cmd(ParseOperation(optarg));
break;
case 't':
switch (tolower(optarg[0])) {
case 's':
type = SASI_HD;
break;
case 'h':
type = SCSI_HD;
break;
case 'm':
type = MO;
break;
case 'c':
type = CD;
break;
case 'b':
type = BR;
break;
// case 'n':
// type = NUVOLINK;
// break;
case 'd':
type = DAYNAPORT;
break;
}
device->set_type(ParseType(optarg));
break;
case 'f':
params = optarg;
device->set_file(optarg);
break;
case 'l':
cmd = LIST;
case 'd':
command.set_cmd(DEFAULT_FOLDER);
default_folder = optarg;
break;
case 'h':
hostname = optarg;
break;
case 'l':
list = true;
break;
case 'n':
device->set_name(optarg);
break;
case 'p':
port = atoi(optarg);
if (port <= 0 || port > 65535) {
cerr << "Invalid port " << optarg << ", port must be between 1 and 65535" << endl;
exit(-1);
exit(EXIT_FAILURE);
}
break;
case 'g':
cmd = LOG_LEVEL;
params = optarg;
command.set_cmd(LOG_LEVEL);
log_level = optarg;
break;
case 's':
cmd = SERVER_INFO;
command.set_cmd(SERVER_INFO);
break;
case 'v':
cout << rascsi_get_version_string() << endl;
exit(0);
exit(EXIT_SUCCESS);
break;
}
}
if (cmd == LOG_LEVEL) {
CommandLogLevel(hostname, port, params);
exit(0);
if (optopt) {
exit(EXIT_FAILURE);
}
if (cmd == SERVER_INFO) {
if (command.cmd() == LOG_LEVEL) {
CommandLogLevel(hostname, port, log_level);
exit(EXIT_SUCCESS);
}
if (command.cmd() == DEFAULT_FOLDER) {
CommandDefaultImageFolder(hostname, port, default_folder);
exit(EXIT_SUCCESS);
}
if (command.cmd() == SERVER_INFO) {
CommandServerInfo(hostname, port);
exit(0);
exit(EXIT_SUCCESS);
}
// List display only
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
if (list) {
CommandList(hostname, port);
exit(0);
}
// Generate the command and send it
PbCommand command;
command.set_id(id);
command.set_un(un);
command.set_cmd(cmd);
command.set_type(type);
if (!params.empty()) {
command.set_params(params);
exit(EXIT_SUCCESS);
}
// Send the command
int fd = SendCommand(hostname, port, command);
bool status = ReceiveResult(fd);
close(fd);
// All done!
exit(status ? 0 : -1);
exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@ -32,7 +32,7 @@ GPIOBUS bus; // Bus
int targetid; // Target ID
int boardid; // Board ID (own ID)
Filepath hdsfile; // HDS file
BOOL restore; // Restore flag
bool restore; // Restore flag
BYTE buffer[BUFSIZE]; // Work Buffer
int result; // Result Code
@ -60,7 +60,7 @@ void KillHandler(int sig)
// Banner Output
//
//---------------------------------------------------------------------------
BOOL Banner(int argc, char* argv[])
bool Banner(int argc, char* argv[])
{
printf("RaSCSI hard disk dump utility ");
printf("version %s (%s, %s)\n",
@ -74,10 +74,10 @@ BOOL Banner(int argc, char* argv[])
printf(" BID is rascsi board SCSI ID {0|1|2|3|4|5|6|7}. Default is 7.\n");
printf(" FILE is HDS file path.\n");
printf(" -r is restore operation.\n");
return FALSE;
return false;
}
return TRUE;
return true;
}
//---------------------------------------------------------------------------
@ -85,30 +85,30 @@ BOOL Banner(int argc, char* argv[])
// Initialization
//
//---------------------------------------------------------------------------
BOOL Init()
bool Init()
{
// Interrupt handler setting
if (signal(SIGINT, KillHandler) == SIG_ERR) {
return FALSE;
return false;
}
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
return FALSE;
return false;
}
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
return FALSE;
return false;
}
// GPIO Initialization
if (!bus.Init(BUS::INITIATOR)) {
return FALSE;
return false;
}
// Work Intitialization
targetid = -1;
boardid = 7;
restore = FALSE;
restore = false;
return TRUE;
return true;
}
//---------------------------------------------------------------------------
@ -138,7 +138,7 @@ void Reset()
// Argument processing
//
//---------------------------------------------------------------------------
BOOL ParseArgument(int argc, char* argv[])
bool ParseArgument(int argc, char* argv[])
{
int opt;
char *file;
@ -163,7 +163,7 @@ BOOL ParseArgument(int argc, char* argv[])
break;
case 'r':
restore = TRUE;
restore = true;
break;
}
}
@ -172,33 +172,33 @@ BOOL ParseArgument(int argc, char* argv[])
if (targetid < 0 || targetid > 7) {
fprintf(stderr,
"Error : Invalid target id range\n");
return FALSE;
return false;
}
// BOARD ID check
if (boardid < 0 || boardid > 7) {
fprintf(stderr,
"Error : Invalid board id range\n");
return FALSE;
return false;
}
// Target and Board ID duplication check
if (targetid == boardid) {
fprintf(stderr,
"Error : Invalid target or board id\n");
return FALSE;
return false;
}
// File Check
if (!file) {
fprintf(stderr,
"Error : Invalid file path\n");
return FALSE;
return false;
}
hdsfile.SetPath(file);
return TRUE;
return true;
}
//---------------------------------------------------------------------------
@ -206,7 +206,7 @@ BOOL ParseArgument(int argc, char* argv[])
// Wait Phase
//
//---------------------------------------------------------------------------
BOOL WaitPhase(BUS::phase_t phase)
bool WaitPhase(BUS::phase_t phase)
{
DWORD now;
@ -215,11 +215,11 @@ BOOL WaitPhase(BUS::phase_t phase)
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Aquire();
if (bus.GetREQ() && bus.GetPhase() == phase) {
return TRUE;
return true;
}
}
return FALSE;
return false;
}
//---------------------------------------------------------------------------
@ -238,7 +238,7 @@ void BusFree()
// Selection Phase
//
//---------------------------------------------------------------------------
BOOL Selection(int id)
bool Selection(int id)
{
BYTE data;
int count;
@ -272,13 +272,13 @@ BOOL Selection(int id)
// Command Phase
//
//---------------------------------------------------------------------------
BOOL Command(BYTE *buf, int length)
bool Command(BYTE *buf, int length)
{
int count;
// Waiting for Phase
if (!WaitPhase(BUS::command)) {
return FALSE;
return false;
}
// Send Command
@ -287,11 +287,11 @@ BOOL Command(BYTE *buf, int length)
// Success if the transmission result is the same as the number
// of requests
if (count == length) {
return TRUE;
return true;
}
// Return error
return FALSE;
return false;
}
//---------------------------------------------------------------------------
@ -808,7 +808,7 @@ int main(int argc, char* argv[])
DWORD dnum;
Fileio fio;
Fileio::OpenMode omode;
off64_t size;
off_t size;
// Banner output
if (!Banner(argc, argv)) {
@ -918,9 +918,9 @@ int main(int argc, char* argv[])
if (restore) {
size = fio.GetFileSize();
printf("Restore file size : %d bytes", (int)size);
if (size > (off64_t)(bsiz * bnum)) {
if (size > (off_t)(bsiz * bnum)) {
printf("(WARNING : File size is larger than disk size)");
} else if (size < (off64_t)(bsiz * bnum)) {
} else if (size < (off_t)(bsiz * bnum)) {
printf("(ERROR : File size is smaller than disk size)\n");
goto cleanup_exit;
}

View File

@ -1,86 +1,19 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020 akuker
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <unistd.h>
#include <sstream>
#include "rascsi_interface.pb.h"
#include "exceptions.h"
#include "rasutil.h"
using namespace std;
using namespace rascsi_interface;
//---------------------------------------------------------------------------
//
// Serialize/Deserialize protobuf message: Length followed by the actual data.
// Little endian is assumed.
//
//---------------------------------------------------------------------------
void SerializeMessage(int fd, const google::protobuf::MessageLite& message)
{
string data;
message.SerializeToString(&data);
// Write the size of the protobuf data as a header
int32_t size = data.length();
if (write(fd, &size, sizeof(size)) != sizeof(size)) {
throw ioexception("Can't write protobuf header");
}
// Write the actual protobuf data
uint8_t buf[size];
memcpy(buf, data.data(), size);
if (write(fd, buf, size) != size) {
throw ioexception("Can't write protobuf data");
}
}
void DeserializeMessage(int fd, google::protobuf::MessageLite& message)
{
// Read the header with the size of the protobuf data
uint8_t header_buf[4];
int bytes_read = ReadNBytes(fd, header_buf, 4);
if (bytes_read < 4) {
return;
}
int32_t size = (header_buf[3] << 24) + (header_buf[2] << 16) + (header_buf[1] << 8) + header_buf[0];
// Read the binary protobuf data
uint8_t data_buf[size];
bytes_read = ReadNBytes(fd, data_buf, size);
if (bytes_read < size) {
throw ioexception("Missing protobuf data");
}
// Create protobuf message
string data((const char *)data_buf, size);
message.ParseFromString(data);
}
int ReadNBytes(int fd, uint8_t *buf, int n)
{
int offset = 0;
while (offset < n) {
ssize_t len = read(fd, buf + offset, n - offset);
if (!len) {
break;
}
offset += len;
}
return offset;
}
//---------------------------------------------------------------------------
//
// List devices
@ -91,82 +24,38 @@ string ListDevices(const PbDevices& devices)
ostringstream s;
if (devices.devices_size()) {
s << endl
<< "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
s << "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl;
}
else {
return "No images currently attached.\n";
return "No images currently attached.";
}
for (int i = 0; i < devices.devices_size() ; i++) {
PbDevice device = devices.devices(i);
s << "| " << device.id() << " | " << device.un() << " | " << MapTypeToId(device.type()) << " | "
<< (device.file().empty() ? "NO MEDIA" : device.file())
<< (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
string filename;
switch (device.type()) {
case SCBR:
filename = "X68000 HOST BRIDGE";
break;
case SCDP:
filename = "DaynaPort SCSI/Link";
break;
default:
filename = device.file().name();
break;
}
s << "| " << device.id() << " | " << device.unit() << " | " << PbDeviceType_Name(device.type()) << " | "
<< (filename.empty() ? "NO MEDIA" : filename)
<< (!device.removed() && (device.read_only() || device.protected_()) ? " (WRITEPROTECT)" : "") << endl;
}
s << "+----+----+------+-------------------------------------" << endl;
s << "+----+----+------+-------------------------------------";
return s.str();
}
//---------------------------------------------------------------------------
//
// Map the device ID to the PbDeviceType and vice versa
//
//---------------------------------------------------------------------------
PbDeviceType MapIdToType(const string& id, bool is_sasi)
{
if (id == "SCHD") {
return is_sasi ? SASI_HD : SCSI_HD;
}
else if (id == "SCMO") {
return MO;
}
else if (id == "SCCD") {
return CD;
}
else if (id == "SCBR") {
return BR;
}
else if (id == "SCDP") {
return DAYNAPORT;
}
else if (id == "SCNL") {
return NUVOLINK;
}
else {
return UNDEFINED;
}
}
string MapTypeToId(const PbDeviceType type)
{
switch (type) {
case SASI_HD:
case SCSI_HD:
return "SCHD";
case MO:
return "SCMO";
case CD:
return "SCCD";
case BR:
return "SCBR";
case DAYNAPORT:
return "SCDP";
case NUVOLINK:
return "SCNL";
default:
return "????";
}
}

View File

@ -1,25 +1,17 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Powered by XM6 TypeG Technology.
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020 akuker
// Copyright (C) 2021 Uwe Seimet
//
// Helper methods used by rascsi and rasctl
//
//---------------------------------------------------------------------------
#if !defined(rasutil_h)
#define rasutil_h
#pragma once
#include "google/protobuf/message_lite.h"
#include <string>
#include "rascsi_interface.pb.h"
void SerializeMessage(int, const google::protobuf::MessageLite&);
void DeserializeMessage(int, google::protobuf::MessageLite&);
int ReadNBytes(int, uint8_t *, int);
string ListDevices(const rascsi_interface::PbDevices&);
rascsi_interface::PbDeviceType MapIdToType(const string&, bool);
string MapTypeToId(const rascsi_interface::PbDeviceType);
#endif
std::string ListDevices(const rascsi_interface::PbDevices&);

View File

@ -27,14 +27,14 @@
//---------------------------------------------------------------------------
//
// 定数宣言
// Constant declaration
//
//---------------------------------------------------------------------------
#define BUFSIZE 1024 * 64 // 64KBぐらいかなぁ
//---------------------------------------------------------------------------
//
// 変数宣言
// Variable declaration
//
//---------------------------------------------------------------------------
GPIOBUS bus; // バス
@ -43,35 +43,35 @@ int unitid; // ターゲットユニットID
int bsiz; // ブロックサイズ
int bnum; // ブロック数
Filepath hdffile; // HDFファイル
BOOL restore; // リストアフラグ
bool restore; // リストアフラグ
BYTE buffer[BUFSIZE]; // ワークバッファ
int result; // 結果コード
//---------------------------------------------------------------------------
//
// 関数宣言
// Function declaration
//
//---------------------------------------------------------------------------
void Cleanup();
//---------------------------------------------------------------------------
//
// シグナル処理
// Signal processing
//
//---------------------------------------------------------------------------
void KillHandler(int sig)
{
// 停止指示
// Stop instruction
Cleanup();
exit(0);
}
//---------------------------------------------------------------------------
//
// バナー出力
// Banner output
//
//---------------------------------------------------------------------------
BOOL Banner(int argc, char* argv[])
bool Banner(int argc, char* argv[])
{
printf("RaSCSI hard disk dump utility(SASI HDD) ");
printf("version %s (%s, %s)\n",
@ -87,33 +87,33 @@ BOOL Banner(int argc, char* argv[])
printf(" COUNT is block count.\n");
printf(" FILE is HDF file path.\n");
printf(" -r is restore operation.\n");
return FALSE;
return false;
}
return TRUE;
return true;
}
//---------------------------------------------------------------------------
//
// 初期化
// Initialization
//
//---------------------------------------------------------------------------
BOOL Init()
bool Init()
{
// 割り込みハンドラ設定
if (signal(SIGINT, KillHandler) == SIG_ERR) {
return FALSE;
return false;
}
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
return FALSE;
return false;
}
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
return FALSE;
return false;
}
// GPIO初期化
if (!bus.Init(BUS::INITIATOR)) {
return FALSE;
return false;
}
// ワーク初期化
@ -121,9 +121,9 @@ BOOL Init()
unitid = 0;
bsiz = 256;
bnum = -1;
restore = FALSE;
restore = false;
return TRUE;
return true;
}
//---------------------------------------------------------------------------
@ -139,21 +139,21 @@ void Cleanup()
//---------------------------------------------------------------------------
//
// リセット
// Reset
//
//---------------------------------------------------------------------------
void Reset()
{
// バス信号線をリセット
// Reset bus signal line
bus.Reset();
}
//---------------------------------------------------------------------------
//
// 引数処理
// Argument processing
//
//---------------------------------------------------------------------------
BOOL ParseArgument(int argc, char* argv[])
bool ParseArgument(int argc, char* argv[])
{
int opt;
char *file;
@ -186,7 +186,7 @@ BOOL ParseArgument(int argc, char* argv[])
break;
case 'r':
restore = TRUE;
restore = true;
break;
}
}
@ -195,48 +195,48 @@ BOOL ParseArgument(int argc, char* argv[])
if (targetid < 0 || targetid > 7) {
fprintf(stderr,
"Error : Invalid target id range\n");
return FALSE;
return false;
}
// UNIT IDチェック
if (unitid < 0 || unitid > 1) {
fprintf(stderr,
"Error : Invalid unit id range\n");
return FALSE;
return false;
}
// BSIZチェック
if (bsiz != 256 && bsiz != 512 && bsiz != 1024) {
fprintf(stderr,
"Error : Invalid block size\n");
return FALSE;
return false;
}
// BNUMチェック
if (bnum < 0) {
fprintf(stderr,
"Error : Invalid block count\n");
return FALSE;
return false;
}
// ファイルチェック
if (!file) {
fprintf(stderr,
"Error : Invalid file path\n");
return FALSE;
return false;
}
hdffile.SetPath(file);
return TRUE;
return true;
}
//---------------------------------------------------------------------------
//
// フェーズ待ち
// Waiting for phase
//
//---------------------------------------------------------------------------
BOOL WaitPhase(BUS::phase_t phase)
bool WaitPhase(BUS::phase_t phase)
{
DWORD now;
@ -245,11 +245,11 @@ BOOL WaitPhase(BUS::phase_t phase)
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Aquire();
if (bus.GetREQ() && bus.GetPhase() == phase) {
return TRUE;
return true;
}
}
return FALSE;
return false;
}
//---------------------------------------------------------------------------
@ -265,10 +265,10 @@ void BusFree()
//---------------------------------------------------------------------------
//
// セレクションフェーズ実行
// Selection phase execution
//
//---------------------------------------------------------------------------
BOOL Selection(int id)
bool Selection(int id)
{
BYTE data;
int count;
@ -298,16 +298,16 @@ BOOL Selection(int id)
//---------------------------------------------------------------------------
//
// コマンドフェーズ実行
// Command phase execution
//
//---------------------------------------------------------------------------
BOOL Command(BYTE *buf, int length)
bool Command(BYTE *buf, int length)
{
int count;
// フェーズ待ち
if (!WaitPhase(BUS::command)) {
return FALSE;
return false;
}
// コマンド送信
@ -315,16 +315,16 @@ BOOL Command(BYTE *buf, int length)
// 送信結果が依頼数と同じなら成功
if (count == length) {
return TRUE;
return true;
}
// 送信エラー
return FALSE;
return false;
}
//---------------------------------------------------------------------------
//
// データインフェーズ実行
// Data in phase execution
//
//---------------------------------------------------------------------------
int DataIn(BYTE *buf, int length)
@ -340,7 +340,7 @@ int DataIn(BYTE *buf, int length)
//---------------------------------------------------------------------------
//
// データアウトフェーズ実行
// Data out phase execution
//
//---------------------------------------------------------------------------
int DataOut(BYTE *buf, int length)
@ -652,7 +652,7 @@ int main(int argc, char* argv[])
DWORD dnum;
Fileio fio;
Fileio::OpenMode omode;
off64_t size;
off_t size;
// バナー出力
if (!Banner(argc, argv)) {
@ -732,9 +732,9 @@ int main(int argc, char* argv[])
if (restore) {
size = fio.GetFileSize();
printf("Restore file size : %d bytes", (int)size);
if (size > (off64_t)(bsiz * bnum)) {
if (size > (off_t)(bsiz * bnum)) {
printf("(WARNING : File size is larger than disk size)");
} else if (size < (off64_t)(bsiz * bnum)) {
} else if (size < (off_t)(bsiz * bnum)) {
printf("(ERROR : File size is smaller than disk size)\n");
goto cleanup_exit;
}

View File

@ -42,7 +42,10 @@ public:
enum asc : int {
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
INVALID_COMMAND_OPERATION_CODE = 0x20,
LBA_OUT_OF_RANGE = 0x21,
INVALID_FIELD_IN_CDB = 0x24,
INVALID_LUN = 0x25,
WRITE_PROTECTED = 0x27,
MEDIUM_NOT_PRESENT = 0x3a
};
};
@ -107,9 +110,9 @@ public:
return ((raw_data >> pin_num) & 1);
}
virtual BOOL GetBSY() = 0;
virtual bool GetBSY() = 0;
// BSYシグナル取得
virtual void SetBSY(BOOL ast) = 0;
virtual void SetBSY(bool ast) = 0;
// BSYシグナル設定
virtual BOOL GetSEL() = 0;

View File

@ -20,6 +20,7 @@
#include "spdlog/spdlog.h"
#include <sys/time.h>
#include <climits>
#include <sstream>
//---------------------------------------------------------------------------
//
@ -52,8 +53,7 @@
//
//---------------------------------------------------------------------------
static BYTE prev_value[32] = {0xFF};
static volatile BOOL running; // Running flag
static volatile BOOL active; // Processing flag
static volatile bool running; // Running flag
GPIOBUS *bus; // GPIO Bus
typedef struct data_capture{
DWORD data;
@ -78,7 +78,7 @@ char log_file_name[_MAX_FNAME/2] = "log.vcd";
void KillHandler(int sig)
{
// Stop instruction
running = FALSE;
running = false;
}
//---------------------------------------------------------------------------
@ -143,8 +143,7 @@ BOOL Init()
bus->Reset();
// Other
running = FALSE;
active = FALSE;
running = false;
return TRUE;
}
@ -266,7 +265,9 @@ void create_value_change_dump()
while(i < data_idx)
{
fprintf(fp, "#%llu\n",(QWORD)(data_buffer[i].timestamp*ns_per_loop));
ostringstream s;
s << (QWORD)(data_buffer[i].timestamp*ns_per_loop);
fprintf(fp, "#%s\n",s.str().c_str());
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_BSY, SYMBOL_PIN_BSY);
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_SEL, SYMBOL_PIN_SEL);
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_CD, SYMBOL_PIN_CD);
@ -350,7 +351,9 @@ static DWORD low_bits = 0xFFFFFFFF;
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
#ifdef DEBUG
ostringstream s;
#ifdef DEBUG
DWORD prev_high = high_bits;
DWORD prev_low = low_bits;
#endif
@ -409,13 +412,14 @@ int main(int argc, char* argv[])
sched_setscheduler(0, SCHED_FIFO, &schparam);
// Start execution
running = TRUE;
running = false;
bus->SetACT(FALSE);
(void)gettimeofday(&start_time, NULL);
LOGDEBUG("ALL_SCSI_PINS %08X\n",ALL_SCSI_PINS);
// Main Loop
// Main Loop
while (running) {
// Work initialization
this_sample = (bus->Aquire() & ALL_SCSI_PINS);
@ -441,12 +445,14 @@ int main(int argc, char* argv[])
low_bits &= this_sample;
if ((high_bits != prev_high) || (low_bits != prev_low))
{
LOGDEBUG(" %08lX %08lX\n",high_bits, low_bits);
LOGDEBUG(" %08X %08X\n",high_bits, low_bits);
}
prev_high = high_bits;
prev_low = low_bits;
if((data_idx % 1000) == 0){
LOGDEBUG("Collected %lu samples...", data_idx);
s.str("");
s << "Collected " << data_idx << " samples...";
LOGDEBUG("%s", s.str().c_str());
}
#endif
data_buffer[data_idx].data = this_sample;
@ -471,12 +477,18 @@ int main(int argc, char* argv[])
timersub(&stop_time, &start_time, &time_diff);
elapsed_us = ((time_diff.tv_sec*1000000) + time_diff.tv_usec);
LOGINFO("Elapsed time: %llu microseconds (%lf seconds)",elapsed_us, ((double)elapsed_us)/1000000);
LOGINFO("Collected %lu changes", data_idx);
s.str("");
s << "Elapsed time: " << elapsed_us << " microseconds (" << elapsed_us / 1000000 << " seconds)";
LOGINFO("%s", s.str().c_str());
s.str("");
s << "Collected %lu changes" << data_idx;
LOGINFO("%s", s.str().c_str());
// Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps.
ns_per_loop = (elapsed_us * 1000) / (double)loop_count;
LOGINFO("Read the SCSI bus %llu times with an average of %lu ns for each read", loop_count, (DWORD)ns_per_loop);
s.str("");
s << "Read the SCSI bus " << loop_count << " times with an average of " << ns_per_loop << " ns for each read";
LOGINFO("%s", s.str().c_str());
// Cleanup
Cleanup();

View File

@ -13,13 +13,6 @@
#if !defined(xm6_h)
#define xm6_h
//---------------------------------------------------------------------------
//
// RaSCSI
//
//---------------------------------------------------------------------------
#define RASCSI 1
//---------------------------------------------------------------------------
//
// Various Operation Settings

View File

@ -6,7 +6,7 @@ import time
from ractl_cmds import attach_image
from settings import *
valid_file_suffix = ["*.hda", "*.hdn", "*.hdi", "*.nhd", "*.hdf", "*.hds", "*.iso", "*.cdr", "*.zip"]
valid_file_suffix = ["*.hda", "*.hdn", "*.hdi", "*.nhd", "*.hdf", "*.hds", "*.hdr", "*.iso", "*.cdr", "*.zip"]
valid_file_types = r"|".join([fnmatch.translate(x) for x in valid_file_suffix])

View File

@ -5,7 +5,7 @@ import re
from settings import *
valid_file_suffix = ["*.hda", "*.hdn", "*.hdi", "*.nhd", "*.hdf", "*.hds", "*.iso", "*.cdr", "*.zip"]
valid_file_suffix = ["*.hda", "*.hdn", "*.hdi", "*.nhd", "*.hdf", "*.hds", "*.hdr", "*.iso", "*.cdr", "*.zip"]
valid_file_types = r"|".join([fnmatch.translate(x) for x in valid_file_suffix])
# List of SCSI ID's you'd like to exclude - eg if you are on a Mac, the System is usually 7
EXCLUDE_SCSI_IDS = [7]
@ -70,8 +70,6 @@ def attach_image(scsi_id, image, device_type):
elif device_type == "SCDP":
attach_daynaport(scsi_id)
else:
if device_type == "SCCD":
device_type = "cd"
return subprocess.run(
["rasctl", "-c", "attach", "-t", device_type, "-i", scsi_id, "-f", image],
capture_output=True,
@ -105,7 +103,7 @@ def insert(scsi_id, image):
def attach_daynaport(scsi_id):
return subprocess.run(
["rasctl", "-i", scsi_id, "-c", "attach", "-t", "daynaport"],
["rasctl", "-i", scsi_id, "-c", "attach", "-t", "scdp"],
capture_output=True,
)

View File

@ -75,6 +75,7 @@
</tbody>
</table>
<hr/>
<h2>Image File Management</h2>
<table cellpadding="3" border="black">
<tbody>
@ -220,8 +221,9 @@
<option value="hdn">SCSI Hard Disk image (NEC GENUINE)</option>
<option value="hdi">SCSI Hard Disk image (Anex86 HD image)</option>
<option value="nhd">SCSI Hard Disk image (T98Next HD image)</option>
<option value="hds">SCSI Hard Disk image (Generic - recommended for Atari computers)</option>
<option value="hdr">SCSI Removable Media Disk image (Generic)</option>
<option value="hdf">SASI Hard Disk image (XM6 SASI HD image - typically only used with X68000)</option>
<option value="hds">SCSI Hard Disk image (XM6 SCSI HD image - typically only used with X68000)</option>
</select>
<label for="size">Size(MB):</label>
<input type="number" placeholder="Size(MB)" name="size"/>