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\-f\f® \fIFOLDER\fR]
[\fB\-g\f® \fILOG_LEVEL\fR] [\fB\-g\f® \fILOG_LEVEL\fR]
[\fB\-h\fR] [\fB\-h\fR]
[\fB\-n\fR \fIVENDOR:PRODUCT:REVISION\fR]
[\fB\-p\f® \fIPORT\fR] [\fB\-p\f® \fIPORT\fR]
[\fB\-n\fR \fITYPE\fR]
[\fB\-v\fR] [\fB\-v\fR]
[\fB\-IDn\fR \fIFILE\fR] [\fB\-IDn\fR \fIFILE\fR]
[\fB\-HDn\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 .PP
RaSCSI will determine the type of device based upon the file extension of the FILE argument. 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) 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) hdn: SCSI Hard Disk image (NEC GENUINE)
hdi: SCSI Hard Disk image (Anex86 HD image) hdi: SCSI Hard Disk image (Anex86 HD image)
nhd: SCSI Hard Disk image (T98Next 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 .SH OPTIONS
.TP .TP
.BR \-f\fI " " \fIFOLDER .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 .TP
.BR \-g\fI " " \fILOG_LEVEL .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 .TP
.BR \-h\fI " " \fI .BR \-h\fI " " \fI
Show a help page. Show a help page.
.TP .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 .BR \-p\fI " " \fIPORT
The rascsi server port, default is 6868. The rascsi server port, default is 6868.
.TP .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 .BR \-v\fI " " \fI
Display the rascsi version. Display the rascsi version.
.TP .TP
.BR \-ID\fIn " " \fIFILE[:TYPE] .BR \-ID\fIn " " \fIFILE
n is the SCSI ID number (0-7) n is the SCSI ID number (0-7)
.IP .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 .TP
.BR \-HD\fIn " " \fIFILE .BR \-HD\fIn " " \fIFILE
n is the SASI ID number (0-15) n is the SASI ID number (0-15)
.IP .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 .IP
Note: SASI usage is rare, and is typically limited to early Sharp X68000 systems. 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 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 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: 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 /dev/hdb:SCSI_HD rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp DUMMY_FILENAME
To create an empty, 100MB HD image, use the following command: To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800 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 rascsi - Emulates SCSI devices using the Raspberry Pi GPIO pins
SYNOPSIS SYNOPSIS
rascsi [-f[u00AE] FOLDER] [-g[u00AE] LOG_LEVEL] [-h] [-p[u00AE] PORT] rascsi [-f[u00AE] FOLDER] [-g[u00AE] LOG_LEVEL] [-h] [-n VENDOR:PROD
[-v] [-IDn FILE] [-HDn FILE]... UCT:REVISION] [-p[u00AE] PORT] [-n TYPE] [-v] [-IDn FILE] [-HDn
FILE]...
DESCRIPTION DESCRIPTION
rascsi Emulates SCSI devices using the Raspberry Pi GPIO pins. rascsi Emulates SCSI devices using the Raspberry Pi GPIO pins.
In the arguments to RaSCSI, one or more SCSI (-IDn) or SASI (-HDn) de 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 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 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" 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 (the host computer). Note that SASI is considered rare and only used on
very early Sharp X68000 computers. 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. 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) 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) hdn: SCSI Hard Disk image (NEC GENUINE)
hdi: SCSI Hard Disk image (Anex86 HD image) hdi: SCSI Hard Disk image (Anex86 HD image)
nhd: SCSI Hard Disk image (T98Next 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) SCSI emulation)
mos: SCSI Magneto-optical image (XM6 SCSI MO image - typically only mos: SCSI Magneto-optical image (XM6 SCSI MO image - typically only
used with X68000) used with X68000)
iso: SCSI CD-ROM image (ISO 9660 image) 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: 0, you can use the following command:
sudo rascsi -ID0 /path/to/drive/hdimage.hda sudo rascsi -ID0 /path/to/drive/hdimage.hda
Once RaSCSI starts, it will open a socket (default port is 6868) to al 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 rascsi port, RaSCSI will terminate, since it is likely another instance
of RaSCSI. Once RaSCSI has initialized, the rasctl utility can be used of RaSCSI. Once RaSCSI has initialized, the rasctl utility can be used
to send commands. 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. you can kill it using an INT signal.
OPTIONS OPTIONS
-f FOLDER -f FOLDER
The default folder for image files. For files in this folder no The default folder for image files. For files in this folder no
absolute path needs to be specified. The default folder is absolute path needs to be specified. The initial default folder
'/home/pi/images'. is '~/images'.
-g LOG_LEVEL -g LOG_LEVEL
The rascsi log level (trace, debug, info, warn, err, critical, The rascsi log level (trace, debug, info, warn, err, critical,
off). The default log level is 'trace'. off). The default log level is 'info'.
-h Show a help page. -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 -p PORT
The rascsi server port, default is 6868. 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. -v Display the rascsi version.
-IDn FILE[:TYPE] -IDn FILE
n is the SCSI ID number (0-7) n is the SCSI ID number (0-7)
FILE is the name of the image file to attach to that ID. If FILE FILE is the name of the image file to use for the SCSI device.
starts with '/dev/' the extension, which encodes the device For devices that do not support an image file (SCBR, SCDP) a
type, is stripped, so that device files can conveniently be used dummy name must be provided.
as image files. An optional explicit device type (SASI_HD,
SCSI_HD, CD, MO, BR, NUVOLINK, DAYNAPORT) can be provided after
a colon.
-HDn FILE -HDn FILE
n is the SASI ID number (0-15) n is the SASI ID number (0-15)
FILE is the name of the image file to attach to that ID. If FILE FILE is the name of the image file to use for the SASI device.
starts with '/dev/' the extension, which encodes the device
type, is stripped, so that device files can conveniently be used
as image files.
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. Sharp X68000 systems.
EXAMPLES EXAMPLES
@ -92,9 +102,10 @@ EXAMPLES
2 2
rascsi -ID0 /path/to/harddrive.hda -ID2 /path/to/cdimage.iso 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 Launch RaSCSI with a removable SCSI drive image as ID 0 and the raw de
file /dev/hdb (e.g. a USB stick) as an image file: vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter
rascsi -ID0 /dev/hdb.hds 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: To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800 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\-i\fR \fIID\fR
[\fB\-c\fR \fICMD\fR] [\fB\-c\fR \fICMD\fR]
[\fB\-f\fR \fIFILE\fR] [\fB\-f\fR \fIFILE\fR]
[\fB\-n\fR \fINAME\fR]
[\fB\-t\fR \fITYPE\fR] [\fB\-t\fR \fITYPE\fR]
[\fB\-u\fR \fIUNIT\fR] [\fB\-u\fR \fIUNIT\fR]
.SH DESCRIPTION .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: Command is the operation being requested. options are:
attach: attach disk attach: attach disk
detach: detach disk detach: detach disk
insert: insert media (Magneto-Optical and CD only) insert: insert media (removable media devices only)
eject: eject media (Magneto-Optical and CD only) eject: eject media (removable media devices only)
protect: Write protect the media (Magneto-Optical only) protect: write protect the media (not for CD-ROMs, which are always read-only)
unprotect: Remove write protection from the media (Magneto-Optical only) unprotect: remove write protection from the media (not for CD-ROMs, which are always read-only)
.IP .IP
When the command is omitted, rasctl will default to the 'attach' command. eject, protect and unprotect are idempotent.
.TP .TP
.BR \-f\fI " " \fIFILE .BR \-f\fI " " \fIFILE
Path to the disk image file. See the rascsi(1) man page for allowable file types. Path to the disk image file. See the rascsi(1) man page for allowable file types.
.TP .TP
.BR \-t\fI " " \fITYPE .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) hd: Hard disk (SCSI or SASI)
mo: Magneto-Optical disk) mo: Magneto-Optical disk
cd: CD-ROM cd: CD-ROM
bridge: Bridge device (This is only applicable to the Sharp X68000) bridge: Bridge device (This is only applicable to the Sharp X68000)
.TP .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 .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) 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 SYNOPSIS
rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v] -i ID [-c CMD] 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 DESCRIPTION
rasctl Sends commands to the rascsi process to make configuration ad 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: -c CMD Command is the operation being requested. options are:
attach: attach disk attach: attach disk
detach: detach disk detach: detach disk
insert: insert media (Magneto-Optical and CD only) insert: insert media (removable media devices only)
eject: eject media (Magneto-Optical and CD only) eject: eject media (removable media devices only)
protect: Write protect the media (Magneto-Optical only) protect: write protect the media (not for CD-ROMs, which are
unprotect: Remove write protection from the media (Magneto- always read-only)
Optical 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' eject, protect and unprotect are idempotent.
command.
-f FILE -f FILE
Path to the disk image file. See the rascsi(1) man page for al Path to the disk image file. See the rascsi(1) man page for al
lowable file types. lowable file types.
-t TYPE -t TYPE
Specifies the type of disk. If this disagrees with the file ex Specifies the device type. This type overrides the type derived
tension of the specified image, the TYPE argument is ignored. from the file extension of the specified image. See the
Available drive types are: rascsi(1) man page for the available device types. Legacy drive
types are:
hd: Hard disk (SCSI or SASI) hd: Hard disk (SCSI or SASI)
mo: Magneto-Optical disk) mo: Magneto-Optical disk
cd: CD-ROM cd: CD-ROM
bridge: Bridge device (This is only applicable to the Sharp bridge: Bridge device (This is only applicable to the Sharp
X68000) 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 -u UNIT
Unit number (0 or 1). This will default to 0. This option is 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 only used when there are multiple SCSI devices on a shared SCSI

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@
#include "devices/scsi_host_bridge.h" #include "devices/scsi_host_bridge.h"
#include "devices/scsi_daynaport.h" #include "devices/scsi_daynaport.h"
#include "exceptions.h" #include "exceptions.h"
#include <sstream>
//=========================================================================== //===========================================================================
// //
@ -41,46 +42,52 @@ SCSIDEV::SCSIDEV() : SASIDEV()
scsi.msc = 0; scsi.msc = 0;
memset(scsi.msb, 0x00, sizeof(scsi.msb)); memset(scsi.msb, 0x00, sizeof(scsi.msb));
SetupCommand(eCmdTestUnitReady, "CmdTestUnitReady", &SCSIDEV::CmdTestUnitReady); SetUpCommand(eCmdTestUnitReady, "CmdTestUnitReady", &SCSIDEV::CmdTestUnitReady);
SetupCommand(eCmdRezero, "CmdRezero", &SCSIDEV::CmdRezero); SetUpCommand(eCmdRezero, "CmdRezero", &SCSIDEV::CmdRezero);
SetupCommand(eCmdRequestSense, "CmdRequestSense", &SCSIDEV::CmdRequestSense); SetUpCommand(eCmdRequestSense, "CmdRequestSense", &SCSIDEV::CmdRequestSense);
SetupCommand(eCmdFormat, "CmdFormat", &SCSIDEV::CmdFormat); SetUpCommand(eCmdFormat, "CmdFormat", &SCSIDEV::CmdFormat);
SetupCommand(eCmdReassign, "CmdReassign", &SCSIDEV::CmdReassign); SetUpCommand(eCmdReassign, "CmdReassign", &SCSIDEV::CmdReassign);
SetupCommand(eCmdRead6, "CmdRead6", &SCSIDEV::CmdRead6); SetUpCommand(eCmdRead6, "CmdRead6", &SCSIDEV::CmdRead6);
SetupCommand(eCmdWrite6, "CmdWrite6", &SCSIDEV::CmdWrite6); SetUpCommand(eCmdWrite6, "CmdWrite6", &SCSIDEV::CmdWrite6);
SetupCommand(eCmdSeek6, "CmdSeek6", &SCSIDEV::CmdSeek6); SetUpCommand(eCmdSeek6, "CmdSeek6", &SCSIDEV::CmdSeek6);
SetupCommand(eCmdInquiry, "CmdInquiry", &SCSIDEV::CmdInquiry); SetUpCommand(eCmdInquiry, "CmdInquiry", &SCSIDEV::CmdInquiry);
SetupCommand(eCmdModeSelect, "CmdModeSelect", &SCSIDEV::CmdModeSelect); SetUpCommand(eCmdModeSelect, "CmdModeSelect", &SCSIDEV::CmdModeSelect);
SetupCommand(eCmdReserve6, "CmdReserve6", &SCSIDEV::CmdReserve6); SetUpCommand(eCmdReserve6, "CmdReserve6", &SCSIDEV::CmdReserve6);
SetupCommand(eCmdRelease6, "CmdRelease6", &SCSIDEV::CmdRelease6); SetUpCommand(eCmdRelease6, "CmdRelease6", &SCSIDEV::CmdRelease6);
SetupCommand(eCmdModeSense, "CmdModeSense", &SCSIDEV::CmdModeSense); SetUpCommand(eCmdModeSense, "CmdModeSense", &SCSIDEV::CmdModeSense);
SetupCommand(eCmdStartStop, "CmdStartStop", &SCSIDEV::CmdStartStop); SetUpCommand(eCmdStartStop, "CmdStartStop", &SCSIDEV::CmdStartStop);
SetupCommand(eCmdSendDiag, "CmdSendDiag", &SCSIDEV::CmdSendDiag); SetUpCommand(eCmdSendDiag, "CmdSendDiag", &SCSIDEV::CmdSendDiag);
SetupCommand(eCmdRemoval, "CmdRemoval", &SCSIDEV::CmdRemoval); SetUpCommand(eCmdRemoval, "CmdRemoval", &SCSIDEV::CmdRemoval);
SetupCommand(eCmdReadCapacity, "CmdReadCapacity", &SCSIDEV::CmdReadCapacity); SetUpCommand(eCmdReadCapacity10, "CmdReadCapacity10", &SCSIDEV::CmdReadCapacity10);
SetupCommand(eCmdRead10, "CmdRead10", &SCSIDEV::CmdRead10); SetUpCommand(eCmdRead10, "CmdRead10", &SCSIDEV::CmdRead10);
SetupCommand(eCmdWrite10, "CmdWrite10", &SCSIDEV::CmdWrite10); SetUpCommand(eCmdWrite10, "CmdWrite10", &SCSIDEV::CmdWrite10);
SetupCommand(eCmdWriteAndVerify10, "CmdWriteAndVerify10", &SCSIDEV::CmdWrite10); SetUpCommand(eCmdVerify10, "CmdVerify10", &SCSIDEV::CmdWrite10);
SetupCommand(eCmdSeek10, "CmdSeek10", &SCSIDEV::CmdSeek10); SetUpCommand(eCmdSeek10, "CmdSeek10", &SCSIDEV::CmdSeek10);
SetupCommand(eCmdVerify, "CmdVerify", &SCSIDEV::CmdVerify); SetUpCommand(eCmdVerify, "CmdVerify", &SCSIDEV::CmdVerify);
SetupCommand(eCmdSynchronizeCache, "CmdSynchronizeCache", &SCSIDEV::CmdSynchronizeCache); SetUpCommand(eCmdSynchronizeCache, "CmdSynchronizeCache", &SCSIDEV::CmdSynchronizeCache);
SetupCommand(eCmdReadDefectData10, "CmdReadDefectData10", &SCSIDEV::CmdReadDefectData10); SetUpCommand(eCmdReadDefectData10, "CmdReadDefectData10", &SCSIDEV::CmdReadDefectData10);
SetupCommand(eCmdModeSelect10, "CmdModeSelect10", &SCSIDEV::CmdModeSelect10); SetUpCommand(eCmdModeSelect10, "CmdModeSelect10", &SCSIDEV::CmdModeSelect10);
SetupCommand(eCmdReserve10, "CmdReserve10", &SCSIDEV::CmdReserve10); SetUpCommand(eCmdReserve10, "CmdReserve10", &SCSIDEV::CmdReserve10);
SetupCommand(eCmdRelease10, "CmdRelease10", &SCSIDEV::CmdRelease10); SetUpCommand(eCmdRelease10, "CmdRelease10", &SCSIDEV::CmdRelease10);
SetupCommand(eCmdModeSense10, "CmdModeSense10", &SCSIDEV::CmdModeSense10); 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 // MMC specific. TODO Move to separate class
SetupCommand(eCmdReadToc, "CmdReadToc", &SCSIDEV::CmdReadToc); SetUpCommand(eCmdReadToc, "CmdReadToc", &SCSIDEV::CmdReadToc);
SetupCommand(eCmdPlayAudio10, "CmdPlayAudio10", &SCSIDEV::CmdPlayAudio10); SetUpCommand(eCmdPlayAudio10, "CmdPlayAudio10", &SCSIDEV::CmdPlayAudio10);
SetupCommand(eCmdPlayAudioMSF, "CmdPlayAudioMSF", &SCSIDEV::CmdPlayAudioMSF); SetUpCommand(eCmdPlayAudioMSF, "CmdPlayAudioMSF", &SCSIDEV::CmdPlayAudioMSF);
SetupCommand(eCmdPlayAudioTrack, "CmdPlayAudioTrack", &SCSIDEV::CmdPlayAudioTrack); SetUpCommand(eCmdPlayAudioTrack, "CmdPlayAudioTrack", &SCSIDEV::CmdPlayAudioTrack);
SetUpCommand(eCmdGetEventStatusNotification, "CmdGetEventStatusNotification", &SCSIDEV::CmdGetEventStatusNotification);
// DaynaPort specific. TODO Move to separate class // DaynaPort specific. TODO Move to separate class
SetupCommand(eCmdRetrieveStats, "CmdRetrieveStats", &SCSIDEV::CmdRetrieveStats); SetUpCommand(eCmdRetrieveStats, "CmdRetrieveStats", &SCSIDEV::CmdRetrieveStats);
SetupCommand(eCmdSetIfaceMode, "CmdSetIfaceMode", &SCSIDEV::CmdSetIfaceMode); SetUpCommand(eCmdSetIfaceMode, "CmdSetIfaceMode", &SCSIDEV::CmdSetIfaceMode);
SetupCommand(eCmdSetMcastAddr, "CmdSetMcastAddr", &SCSIDEV::CmdSetMcastAddr); SetUpCommand(eCmdSetMcastAddr, "CmdSetMcastAddr", &SCSIDEV::CmdSetMcastAddr);
SetupCommand(eCmdEnableInterface, "CmdEnableInterface", &SCSIDEV::CmdEnableInterface); SetUpCommand(eCmdEnableInterface, "CmdEnableInterface", &SCSIDEV::CmdEnableInterface);
} }
SCSIDEV::~SCSIDEV() 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); scsi_commands[opcode] = new command_t(name, execute);
} }
@ -204,7 +211,6 @@ void SCSIDEV::BusFree()
{ {
// Phase change // Phase change
if (ctrl.phase != BUS::busfree) { if (ctrl.phase != BUS::busfree) {
LOGTRACE( "%s Bus free phase", __PRETTY_FUNCTION__); LOGTRACE( "%s Bus free phase", __PRETTY_FUNCTION__);
// Phase setting // Phase setting
@ -215,7 +221,7 @@ void SCSIDEV::BusFree()
ctrl.bus->SetMSG(FALSE); ctrl.bus->SetMSG(FALSE);
ctrl.bus->SetCD(FALSE); ctrl.bus->SetCD(FALSE);
ctrl.bus->SetIO(FALSE); ctrl.bus->SetIO(FALSE);
ctrl.bus->SetBSY(FALSE); ctrl.bus->SetBSY(false);
// Initialize status and message // Initialize status and message
ctrl.status = 0x00; ctrl.status = 0x00;
@ -258,7 +264,7 @@ void SCSIDEV::Selection()
ctrl.phase = BUS::selection; ctrl.phase = BUS::selection;
// Raise BSY and respond // Raise BSY and respond
ctrl.bus->SetBSY(TRUE); ctrl.bus->SetBSY(true);
return; return;
} }
@ -280,7 +286,7 @@ void SCSIDEV::Selection()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIDEV::Execute() 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 // Phase Setting
ctrl.phase = BUS::execute; 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 the command is valid it must be contained in the command map
if (!scsi_commands.count(static_cast<scsi_command>(ctrl.cmd[0]))) { if (!scsi_commands.count(static_cast<scsi_command>(ctrl.cmd[0]))) {
LOGWARN("%s Received unsupported command: $%02X", __PRETTY_FUNCTION__, (BYTE)ctrl.cmd[0]);
CmdInvalid(); CmdInvalid();
return; return;
} }
command_t* command = scsi_commands[static_cast<scsi_command>(ctrl.cmd[0])]; 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]); LOGDEBUG("++++ CMD ++++ %s ID %d received %s ($%02X)", __PRETTY_FUNCTION__, GetSCSIID(), 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;
}
// Process by command // Process by command
(this->*command->execute)(); (this->*command->execute)();
@ -318,14 +317,13 @@ void SCSIDEV::Execute()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIDEV::MsgOut() void SCSIDEV::MsgOut()
{ {
LOGTRACE("%s ID: %d",__PRETTY_FUNCTION__, this->GetSCSIID()); LOGTRACE("%s ID %d",__PRETTY_FUNCTION__, GetSCSIID());
// Phase change // Phase change
if (ctrl.phase != BUS::msgout) { if (ctrl.phase != BUS::msgout) {
LOGTRACE("Message Out Phase"); LOGTRACE("Message Out Phase");
// process the IDENTIFY message // process the IDENTIFY message
if (ctrl.phase == BUS::selection) { if (ctrl.phase == BUS::selection) {
scsi.atnmsg = TRUE; scsi.atnmsg = TRUE;
scsi.msc = 0; scsi.msc = 0;
@ -378,14 +376,22 @@ void SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
return; 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); 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 if (sense_key || asc) {
ctrl.sense_key = sense_key; // Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.asc = asc; 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; ctrl.message = 0x00;
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__); LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__);
@ -410,24 +416,19 @@ void SCSIDEV::CmdInquiry()
LOGTRACE("%s INQUIRY Command", __PRETTY_FUNCTION__); LOGTRACE("%s INQUIRY Command", __PRETTY_FUNCTION__);
// Find a valid unit // 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. // used for all LUNs, even though each LUN has its individual set of INQUIRY data.
Disk *disk = NULL; PrimaryDevice *device = NULL;
int valid_lun; for (int valid_lun = 0; valid_lun < UnitMax; valid_lun++) {
for (valid_lun = 0; valid_lun < UnitMax; valid_lun++) {
if (ctrl.unit[valid_lun]) { if (ctrl.unit[valid_lun]) {
disk = ctrl.unit[valid_lun]; device = ctrl.unit[valid_lun];
break; break;
} }
} }
// Processed on the disk side (it is originally processed by the controller) // Processed on the disk side (it is originally processed by the controller)
if (disk) { if (device) {
DWORD major = (DWORD)(RASCSI >> 8); ctrl.length = device->Inquiry(ctrl.cmd, ctrl.buffer);
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);
} else { } else {
ctrl.length = 0; ctrl.length = 0;
} }
@ -586,7 +587,7 @@ void SCSIDEV::CmdStartStop()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
BOOL status = ctrl.unit[lun]->StartStop(ctrl.cmd); bool status = ctrl.unit[lun]->StartStop(ctrl.cmd);
if (!status) { if (!status) {
// Failure (Error) // Failure (Error)
Error(); Error();
@ -609,7 +610,7 @@ void SCSIDEV::CmdSendDiag()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
BOOL status = ctrl.unit[lun]->SendDiag(ctrl.cmd); bool status = ctrl.unit[lun]->SendDiag(ctrl.cmd);
if (!status) { if (!status) {
// Failure (Error) // Failure (Error)
Error(); Error();
@ -632,7 +633,7 @@ void SCSIDEV::CmdRemoval()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
BOOL status = ctrl.unit[lun]->Removal(ctrl.cmd); bool status = ctrl.unit[lun]->Removal(ctrl.cmd);
if (!status) { if (!status) {
// Failure (Error) // Failure (Error)
Error(); Error();
@ -648,15 +649,34 @@ void SCSIDEV::CmdRemoval()
// READ CAPACITY // 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(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
int length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer); int length = ctrl.unit[lun]->ReadCapacity10(ctrl.cmd, ctrl.buffer);
ASSERT(length >= 0); 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) { if (length <= 0) {
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT); Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return; return;
@ -696,7 +716,90 @@ void SCSIDEV::CmdRead10()
ctrl.blocks <<= 8; ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[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 // Do not process 0 blocks
if (ctrl.blocks == 0) { if (ctrl.blocks == 0) {
@ -746,7 +849,18 @@ void SCSIDEV::CmdWrite10()
ctrl.blocks <<= 8; ctrl.blocks <<= 8;
ctrl.blocks |= ctrl.cmd[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 // Do not process 0 blocks
if (ctrl.blocks == 0) { if (ctrl.blocks == 0) {
@ -758,10 +872,82 @@ void SCSIDEV::CmdWrite10()
ctrl.length = ctrl.unit[lun]->WriteCheck(record); ctrl.length = ctrl.unit[lun]->WriteCheck(record);
if (ctrl.length <= 0) { if (ctrl.length <= 0) {
// Failure (Error) // 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(); Error();
return; 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 // Set next block
ctrl.next = record + 1; ctrl.next = record + 1;
@ -853,6 +1039,28 @@ void SCSIDEV::CmdVerify()
DataOut(); 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 // SYNCHRONIZE CACHE
@ -923,7 +1131,7 @@ void SCSIDEV::CmdPlayAudio10()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
BOOL status = ctrl.unit[lun]->PlayAudio(ctrl.cmd); bool status = ctrl.unit[lun]->PlayAudio(ctrl.cmd);
if (!status) { if (!status) {
// Failure (Error) // Failure (Error)
Error(); Error();
@ -944,7 +1152,7 @@ void SCSIDEV::CmdPlayAudioMSF()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
BOOL status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd); bool status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd);
if (!status) { if (!status) {
// Failure (Error) // Failure (Error)
Error(); Error();
@ -965,7 +1173,7 @@ void SCSIDEV::CmdPlayAudioTrack()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Command processing on drive // Command processing on drive
BOOL status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd); bool status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd);
if (!status) { if (!status) {
// Failure (Error) // Failure (Error)
Error(); Error();
@ -976,6 +1184,19 @@ void SCSIDEV::CmdPlayAudioTrack()
Status(); 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 // MODE SELECT10
@ -1037,7 +1258,7 @@ void SCSIDEV::CmdGetMessage10()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Error if not a host bridge // 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"); LOGWARN("Received a GetMessage10 command for a non-bridge unit");
Error(); Error();
return; return;
@ -1124,9 +1345,9 @@ void SCSIDEV::CmdRetrieveStats()
DWORD lun = GetLun(); DWORD lun = GetLun();
// Error if not a DaynaPort SCSI Link // Error if not a DaynaPort SCSI Link
if (ctrl.unit[lun]->IsDaynaPort()) { if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("Received a CmdRetrieveStats command for a non-daynaport unit %s", ctrl.unit[lun]->GetID().c_str()); LOGWARN("Received a CmdRetrieveStats command for a non-daynaport unit %s", ctrl.unit[lun]->GetType().c_str());
Error(); Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return; return;
} }
@ -1161,15 +1382,14 @@ void SCSIDEV::CmdSetIfaceMode()
// Error if not a DaynaPort SCSI Link // Error if not a DaynaPort SCSI Link
if (!ctrl.unit[lun]->IsDaynaPort()) { 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()); LOGWARN("%s Received a CmdSetIfaceMode command for a non-daynaport unit %s", __PRETTY_FUNCTION__, ctrl.unit[lun]->GetType().c_str());
Error(); Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return; return;
} }
SCSIDaynaPort *dayna_port = (SCSIDaynaPort*)ctrl.unit[lun]; SCSIDaynaPort *dayna_port = (SCSIDaynaPort*)ctrl.unit[lun];
// Check whether this command is telling us to "Set Interface Mode" // Check whether this command is telling us to "Set Interface Mode" or "Set MAC Address"
// or "Set MAC Address"
ctrl.length = dayna_port->RetrieveStats(ctrl.cmd, ctrl.buffer); ctrl.length = dayna_port->RetrieveStats(ctrl.cmd, ctrl.buffer);
switch(ctrl.cmd[5]){ switch(ctrl.cmd[5]){
@ -1201,7 +1421,7 @@ void SCSIDEV::CmdSetMcastAddr()
if (!ctrl.unit[lun]->IsDaynaPort()) { if (!ctrl.unit[lun]->IsDaynaPort()) {
LOGWARN("Received a SetMcastAddress command for a non-daynaport unit"); 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; return;
} }
@ -1233,8 +1453,8 @@ void SCSIDEV::CmdEnableInterface()
// Error if not a DaynaPort SCSI Link // Error if not a DaynaPort SCSI Link
if (!ctrl.unit[lun]->IsDaynaPort()) { 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()); LOGWARN("%s Received a CmdEnableInterface command for a non-daynaport unit %s", __PRETTY_FUNCTION__, ctrl.unit[lun]->GetType().c_str());
Error(); Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
return; return;
} }
@ -1274,7 +1494,9 @@ void SCSIDEV::Send()
//if Length! = 0, send //if Length! = 0, send
if (ctrl.length != 0) { 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 // The Daynaport needs to have a delay after the size/flags field
// of the read response. In the MacOS driver, it looks like the // of the read response. In the MacOS driver, it looks like the
@ -1310,7 +1532,9 @@ void SCSIDEV::Send()
if (ctrl.blocks != 0) { if (ctrl.blocks != 0) {
// set next buffer (set offset, length) // set next buffer (set offset, length)
result = XferIn(ctrl.buffer); 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 // Continue sending if block !=0
if (ctrl.blocks != 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.length > 0);
ASSERT(ctrl.offset == 0); ASSERT(ctrl.offset == 0);
return; return;
@ -1376,7 +1602,6 @@ void SCSIDEV::Send()
void SCSIDEV::Receive() void SCSIDEV::Receive()
{ {
int len; int len;
int i;
BYTE data; BYTE data;
LOGTRACE("%s",__PRETTY_FUNCTION__); LOGTRACE("%s",__PRETTY_FUNCTION__);
@ -1389,8 +1614,7 @@ void SCSIDEV::Receive()
if (ctrl.length != 0) { if (ctrl.length != 0) {
LOGTRACE("%s length was != 0", __PRETTY_FUNCTION__); LOGTRACE("%s length was != 0", __PRETTY_FUNCTION__);
// Receive // Receive
len = ctrl.bus->ReceiveHandShake( len = ctrl.bus->ReceiveHandShake(&ctrl.buffer[ctrl.offset], ctrl.length);
&ctrl.buffer[ctrl.offset], ctrl.length);
// If not able to receive all, move to status phase // If not able to receive all, move to status phase
if (len != (int)ctrl.length) { if (len != (int)ctrl.length) {
@ -1458,26 +1682,22 @@ void SCSIDEV::Receive()
switch (ctrl.phase) { switch (ctrl.phase) {
// Command phase // Command phase
case BUS::command: case BUS::command:
// Command data transfer len = GPIOBUS::GetCommandByteCount(ctrl.buffer[0]);
len = 6;
if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) { for (int i = 0; i < len; i++) {
// 10 byte CDB
len = 10;
}
for (i = 0; i < len; i++) {
ctrl.cmd[i] = (DWORD)ctrl.buffer[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 // Execution Phase
try { try {
Execute(); Execute();
} }
catch (const lunexception& e) { catch (const lun_exception& e) {
LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun()); 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; break;
// Message out phase // Message out phase
@ -1493,7 +1713,7 @@ void SCSIDEV::Receive()
// Parsing messages sent by ATN // Parsing messages sent by ATN
if (scsi.atnmsg) { if (scsi.atnmsg) {
i = 0; int i = 0;
while (i < scsi.msc) { while (i < scsi.msc) {
// Message type // Message type
data = scsi.msb[i]; data = scsi.msb[i];

View File

@ -67,7 +67,7 @@ public:
BOOL IsSCSI() const {return TRUE;} // SCSI check BOOL IsSCSI() const {return TRUE;} // SCSI check
private: private:
void SetupCommand(scsi_command, const char*, void (SCSIDEV::*)(void)); void SetUpCommand(scsi_command, const char*, void (SCSIDEV::*)(void));
// Phase // Phase
void BusFree(); // Bus free phase void BusFree(); // Bus free phase
@ -88,7 +88,7 @@ private:
void CmdStartStop(); // START STOP UNIT command void CmdStartStop(); // START STOP UNIT command
void CmdSendDiag(); // SEND DIAGNOSTIC command void CmdSendDiag(); // SEND DIAGNOSTIC command
void CmdRemoval(); // PREVENT/ALLOW MEDIUM REMOVAL 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 CmdRead10(); // READ(10) command
void CmdWrite10(); // WRITE(10) command void CmdWrite10(); // WRITE(10) command
void CmdSeek10(); // SEEK(10) command void CmdSeek10(); // SEEK(10) command
@ -99,8 +99,13 @@ private:
void CmdPlayAudio10(); // PLAY AUDIO(10) command void CmdPlayAudio10(); // PLAY AUDIO(10) command
void CmdPlayAudioMSF(); // PLAY AUDIO MSF command void CmdPlayAudioMSF(); // PLAY AUDIO MSF command
void CmdPlayAudioTrack(); // PLAY AUDIO TRACK INDEX command void CmdPlayAudioTrack(); // PLAY AUDIO TRACK INDEX command
void CmdGetEventStatusNotification();
void CmdModeSelect10(); // MODE SELECT(10) command void CmdModeSelect10(); // MODE SELECT(10) command
void CmdModeSense10(); // MODE SENSE(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 CmdGetMessage10(); // GET MESSAGE(10) command
void CmdSendMessage10(); // SEND MESSAGE(10) command void CmdSendMessage10(); // SEND MESSAGE(10) command
void CmdRetrieveStats(); // DaynaPort specific 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 #define IC_BUF_SIZE 1024
@ -46,28 +46,23 @@ static void convert(char const *src, char const *dest,
#endif #endif
{ {
#ifndef __APPLE__ #ifndef __APPLE__
iconv_t cd;
size_t in;
size_t out;
size_t ret;
*outbuf = '\0'; *outbuf = '\0';
in = strlen(inbuf); size_t in = strlen(inbuf);
out = outsize - 1; size_t out = outsize - 1;
cd = iconv_open(dest, src); iconv_t cd = iconv_open(dest, src);
if (cd == (iconv_t)-1) { if (cd == (iconv_t)-1) {
return; return;
} }
ret = iconv(cd, &inbuf, &in, &outbuf, &out); size_t ret = iconv(cd, &inbuf, &in, &outbuf, &out);
if (ret == (size_t)-1) { if (ret == (size_t)-1) {
return; return;
} }
iconv_close(cd); iconv_close(cd);
*outbuf = '\0'; *outbuf = '\0';
#endif //ifndef __macintosh__ #endif //ifndef __APPLE__
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -202,33 +197,33 @@ void Human68k::namests_t::GetCopyFilename(BYTE* szFilename) const
if (ext[j] != ' ') if (ext[j] != ' ')
goto next_ext; goto next_ext;
} }
// 拡張子終端なら転送終了 // If the extension ends, the transfer ends
break; break;
} }
next_ext: next_ext:
*p++ = c; *p++ = c;
} }
// 全ての文字を読み込むと、ここで i >= 3 となる // When all the characters are read, here i >= 3
} }
// 番兵追加 // Add sentinel
*p = '\0'; *p = '\0';
} }
//=========================================================================== //===========================================================================
// //
// ホスト側ドライブ // Host side drive
// //
//=========================================================================== //===========================================================================
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// デフォルトコンストラクタ // Default constructor
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CHostDrv::CHostDrv() CHostDrv::CHostDrv()
{ {
// 初期化 // Initialization
m_bWriteProtect = FALSE; m_bWriteProtect = FALSE;
m_bEnable = FALSE; m_bEnable = FALSE;
m_capCache.sectors = 0; m_capCache.sectors = 0;
@ -240,7 +235,7 @@ CHostDrv::CHostDrv()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// デストラクタ final // Final destructor
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
CHostDrv::~CHostDrv() CHostDrv::~CHostDrv()
@ -252,7 +247,7 @@ CHostDrv::~CHostDrv()
m_nRing--; m_nRing--;
} }
// 実体が存在しないことを確認 (念のため) // Confirm that the entity does not exist (just in case)
ASSERT(m_cRing.Next() == &m_cRing); ASSERT(m_cRing.Next() == &m_cRing);
ASSERT(m_cRing.Prev() == &m_cRing); ASSERT(m_cRing.Prev() == &m_cRing);
ASSERT(m_nRing == 0); ASSERT(m_nRing == 0);
@ -260,7 +255,7 @@ CHostDrv::~CHostDrv()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// 初期化 (デバイス起動とロード) // Initialization (device boot and load)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag) 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_bVolumeCache == FALSE);
ASSERT(m_szVolumeCache[0] == _T('\0')); 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.Next() == &m_cRing);
ASSERT(m_cRing.Prev() == &m_cRing); ASSERT(m_cRing.Prev() == &m_cRing);
ASSERT(m_nRing == 0); ASSERT(m_nRing == 0);
// パラメータを受け取る // Receive parameters
if (nFlag & FSFLAG_WRITE_PROTECT) if (nFlag & FSFLAG_WRITE_PROTECT)
m_bWriteProtect = TRUE; m_bWriteProtect = TRUE;
strcpy(m_szBase, szBase); strcpy(m_szBase, szBase);
// ベースパスの最後のパス区切りマークを削除する // Remove the last path delimiter in the base path
/// @warning Unicode利用時は修正が必要 // @warning needs to be modified when using Unicode
TCHAR* pClear = NULL; TCHAR* pClear = NULL;
TCHAR* p = m_szBase; TCHAR* p = m_szBase;
for (;;) { for (;;) {
@ -306,56 +301,52 @@ void CHostDrv::Init(const TCHAR* szBase, DWORD nFlag)
if (pClear) if (pClear)
*pClear = _T('\0'); *pClear = _T('\0');
// 状態更新 // Status update
m_bEnable = TRUE; m_bEnable = TRUE;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// メディアチェック // Media check
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL CHostDrv::isMediaOffline() BOOL CHostDrv::isMediaOffline()
{ {
// Offline status check
// オフライン状態チェック
return m_bEnable == FALSE; return m_bEnable == FALSE;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// メディアバイトの取得 // Get media bytes
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BYTE CHostDrv::GetMediaByte() const BYTE CHostDrv::GetMediaByte() const
{ {
return Human68k::MEDIA_REMOTE; return Human68k::MEDIA_REMOTE;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// ドライブ状態の取得 // Get drive status
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
DWORD CHostDrv::GetStatus() const DWORD CHostDrv::GetStatus() const
{ {
return 0x40 | (m_bEnable ? (m_bWriteProtect ? 0x08 : 0) | 0x02 : 0); return 0x40 | (m_bEnable ? (m_bWriteProtect ? 0x08 : 0) | 0x02 : 0);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// メディア状態設定 // Media status settings
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostDrv::SetEnable(BOOL bEnable) void CHostDrv::SetEnable(BOOL bEnable)
{ {
m_bEnable = bEnable; m_bEnable = bEnable;
if (bEnable == FALSE) { if (bEnable == FALSE) {
// キャッシュ消去 // Clear cache
m_capCache.sectors = 0; m_capCache.sectors = 0;
m_bVolumeCache = FALSE; m_bVolumeCache = FALSE;
m_szVolumeCache[0] = _T('\0'); m_szVolumeCache[0] = _T('\0');
@ -364,13 +355,12 @@ void CHostDrv::SetEnable(BOOL bEnable)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// メディア交換チェック // Media change check
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL CHostDrv::CheckMedia() BOOL CHostDrv::CheckMedia()
{ {
// Status update
// 状態更新
Update(); Update();
if (m_bEnable == FALSE) if (m_bEnable == FALSE)
CleanCache(); CleanCache();
@ -380,38 +370,36 @@ BOOL CHostDrv::CheckMedia()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// メディア状態更新 // Media status update
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostDrv::Update() void CHostDrv::Update()
{ {
// Considered as media insertion
// メディア挿入とみなす
BOOL bEnable = TRUE; BOOL bEnable = TRUE;
// メディア状態反映 // Media status reflected
SetEnable(bEnable); SetEnable(bEnable);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// イジェクト // Eject
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostDrv::Eject() void CHostDrv::Eject()
{ {
// Media discharge
// メディア排出
CleanCache(); CleanCache();
SetEnable(FALSE); SetEnable(FALSE);
// 状態更新 // Status update
Update(); Update();
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
/// ボリュームラベルの取得 // Get volume label
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostDrv::GetVolume(TCHAR* szLabel) void CHostDrv::GetVolume(TCHAR* szLabel)
@ -419,7 +407,7 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
ASSERT(szLabel); ASSERT(szLabel);
ASSERT(m_bEnable); ASSERT(m_bEnable);
// ボリュームラベルの取得 // Get volume label
strcpy(m_szVolumeCache, "RASDRV "); strcpy(m_szVolumeCache, "RASDRV ");
if (m_szBase[0]) { if (m_szBase[0]) {
strcat(m_szVolumeCache, m_szBase); strcat(m_szVolumeCache, m_szBase);
@ -427,10 +415,10 @@ void CHostDrv::GetVolume(TCHAR* szLabel)
strcat(m_szVolumeCache, "/"); strcat(m_szVolumeCache, "/");
} }
// キャッシュ更新 // Cache update
m_bVolumeCache = TRUE; m_bVolumeCache = TRUE;
// 内容を転送 // Transfer content
strcpy(szLabel, m_szVolumeCache); strcpy(szLabel, m_szVolumeCache);
} }
@ -513,7 +501,6 @@ BOOL CHostDrv::GetCapacityCache(Human68k::capacity_t* pCapacity) const
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CHostDrv::CleanCache() void CHostDrv::CleanCache()
{ {
Lock(); Lock();
for (CHostPath* p = (CHostPath*)m_cRing.Next(); p != &m_cRing;) { for (CHostPath* p = (CHostPath*)m_cRing.Next(); p != &m_cRing;) {
p->Release(); p->Release();
@ -4002,7 +3989,7 @@ int CFileSys::Ioctrl(DWORD nUnit, DWORD nFunction, Human68k::ioctrl_t* pIoctrl)
case 1: case 1:
// Human68k互換のためのダミー // Human68k互換のためのダミー
pIoctrl->param = (unsigned long)-1; pIoctrl->param = -1;
return 0; return 0;
case 2: 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) { static BOOL ip_link(int fd, const char* ifname, BOOL up) {
struct ifreq ifr; struct ifreq ifr;
int err;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); // Need to save room for null terminator 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) { if (err) {
LOGERROR("Error: can't ioctl SIOCGIFFLAGS. Errno: %d %s", errno, strerror(errno)); LOGERROR("Error: can't ioctl SIOCGIFFLAGS. Errno: %d %s", errno, strerror(errno));
return FALSE; return FALSE;
@ -257,7 +256,7 @@ void CTapDriver::OpenDump(const Filepath& path) {
m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath()); m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath());
if (m_pcap_dumper == NULL) { if (m_pcap_dumper == NULL) {
LOGERROR("Error: can't open pcap file: %s", pcap_geterr(m_pcap)); 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()); LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.GetPath());
@ -302,10 +301,10 @@ void CTapDriver::Cleanup()
// Enable // Enable
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL CTapDriver::Enable(){ bool CTapDriver::Enable(){
int fd = socket(PF_INET, SOCK_DGRAM, 0); int fd = socket(PF_INET, SOCK_DGRAM, 0);
LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__); 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); close(fd);
return result; return result;
} }
@ -315,10 +314,10 @@ BOOL CTapDriver::Enable(){
// Disable // Disable
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL CTapDriver::Disable(){ bool CTapDriver::Disable(){
int fd = socket(PF_INET, SOCK_DGRAM, 0); int fd = socket(PF_INET, SOCK_DGRAM, 0);
LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__); 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); close(fd);
return result; return result;
} }
@ -409,7 +408,7 @@ int CTapDriver::Rx(BYTE *buf)
buf[dwReceived + 2] = (BYTE)((crc >> 16) & 0xFF); buf[dwReceived + 2] = (BYTE)((crc >> 16) & 0xFF);
buf[dwReceived + 3] = (BYTE)((crc >> 24) & 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 // Add FCS size to the received message size
dwReceived += 4; dwReceived += 4;

View File

@ -41,8 +41,8 @@ public:
int Rx(BYTE *buf); // Receive int Rx(BYTE *buf); // Receive
int Tx(const BYTE *buf, int len); // Send int Tx(const BYTE *buf, int len); // Send
BOOL PendingPackets(); // Check if there are IP packets available BOOL PendingPackets(); // Check if there are IP packets available
BOOL Enable(); // Enable the ras0 interface bool Enable(); // Enable the ras0 interface
BOOL Disable(); // Disable the ras0 interface bool Disable(); // Disable the ras0 interface
BOOL Flush(); // Purge all of the packets that are waiting to be processed BOOL Flush(); // Purge all of the packets that are waiting to be processed
private: 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 "xm6.h"
#include "log.h" #include "log.h"
#include "scsi.h" #include "scsi.h"
#include "block_device.h"
#include "file_support.h"
#include "filepath.h" #include "filepath.h"
#include <string> #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 // Disk Track
@ -83,14 +45,14 @@ public:
DWORD maplen; // Changed map length DWORD maplen; // Changed map length
BOOL *changemap; // Changed map BOOL *changemap; // Changed map
BOOL raw; // RAW mode flag BOOL raw; // RAW mode flag
off64_t imgoffset; // Offset to actual data off_t imgoffset; // Offset to actual data
} disktrk_t; } disktrk_t;
public: public:
// Basic Functions // Basic Functions
DiskTrack(); // Constructor DiskTrack(); // Constructor
virtual ~DiskTrack(); // Destructor 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 Load(const Filepath& path); // Load
BOOL Save(const Filepath& path); // Save BOOL Save(const Filepath& path); // Save
@ -128,7 +90,7 @@ public:
public: public:
// Basic Functions // 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 virtual ~DiskCache(); // Destructor
void SetRawMode(BOOL raw); // CD-ROM raw mode setting 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_size; // Sector size (8 or 9 or 11)
int sec_blocks; // Blocks per sector int sec_blocks; // Blocks per sector
BOOL cd_raw; // CD-ROM RAW mode 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 // Disk
// //
//=========================================================================== //===========================================================================
class Disk class Disk : public BlockDevice
{ {
public: protected:
// Internal data structure // Internal data structure
typedef struct { 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 int size; // Sector Size
DWORD blocks; // Total number of sectors DWORD blocks; // Total number of sectors
DWORD lun; // LUN
DWORD code; // Status code
DiskCache *dcache; // Disk cache DiskCache *dcache; // Disk cache
off64_t imgoffset; // Offset to actual data off_t imgoffset; // Offset to actual data
} disk_t; } disk_t;
public: public:
// Basic Functions // Basic Functions
Disk(std::string); // Constructor Disk(std::string); // Constructor
virtual ~Disk(); // Destructor 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 // 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 void GetPath(Filepath& path) const; // Get the path
bool Eject(bool); // Eject bool Eject(bool) override; // 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 Flush(); // Flush the cache bool Flush(); // Flush the cache
// Properties
void SetLUN(DWORD lun) { disk.lun = lun; } // LUN set
DWORD GetLUN() { return disk.lun; } // LUN get
// commands // commands
virtual int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor);// INQUIRY command virtual bool TestUnitReady(const DWORD *cdb) override; // TEST UNIT READY command
virtual int RequestSense(const DWORD *cdb, BYTE *buf); // REQUEST SENSE 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 SelectCheck(const DWORD *cdb); // SELECT check
int SelectCheck10(const DWORD *cdb); // SELECT(10) check int SelectCheck10(const DWORD *cdb); // SELECT(10) check
virtual BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length);// MODE SELECT command virtual bool ModeSelect(const DWORD *cdb, const BYTE *buf, int length) override;// MODE SELECT command
virtual int ModeSense(const DWORD *cdb, BYTE *buf); // MODE SENSE command virtual int ModeSense(const DWORD *cdb, BYTE *buf) override; // MODE SENSE command
virtual int ModeSense10(const DWORD *cdb, BYTE *buf); // MODE SENSE(10) 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 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 Rezero(const DWORD *cdb); // REZERO command bool Format(const DWORD *cdb) override; // FORMAT UNIT command
BOOL Format(const DWORD *cdb); // FORMAT UNIT command bool Reassign(const DWORD *cdb); // REASSIGN 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 Read(const DWORD *cdb, BYTE *buf, DWORD block); // READ command
virtual int WriteCheck(DWORD block); // WRITE check virtual int WriteCheck(DWORD block); // WRITE check
virtual BOOL Write(const DWORD *cdb, const BYTE *buf, DWORD block); // WRITE command virtual bool Write(const DWORD *cdb, const BYTE *buf, DWORD block) override; // WRITE command
BOOL Seek(const DWORD *cdb); // SEEK command bool Seek(const DWORD *cdb); // SEEK command
BOOL Assign(const DWORD *cdb); // ASSIGN command bool Assign(const DWORD *cdb); // ASSIGN command
BOOL Specify(const DWORD *cdb); // SPECIFY command bool Specify(const DWORD *cdb); // SPECIFY command
BOOL StartStop(const DWORD *cdb); // START STOP UNIT command bool StartStop(const DWORD *cdb); // START STOP UNIT command
BOOL SendDiag(const DWORD *cdb); // SEND DIAGNOSTIC command bool SendDiag(const DWORD *cdb); // SEND DIAGNOSTIC command
BOOL Removal(const DWORD *cdb); // PREVENT/ALLOW MEDIUM REMOVAL command bool Removal(const DWORD *cdb); // PREVENT/ALLOW MEDIUM REMOVAL command
int ReadCapacity(const DWORD *cdb, BYTE *buf); // READ CAPACITY command int ReadCapacity10(const DWORD *cdb, BYTE *buf) override; // READ CAPACITY(10) command
BOOL Verify(const DWORD *cdb); // VERIFY 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 int ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC command
virtual BOOL PlayAudio(const DWORD *cdb); // PLAY AUDIO command virtual bool PlayAudio(const DWORD *cdb); // PLAY AUDIO command
virtual BOOL PlayAudioMSF(const DWORD *cdb); // PLAY AUDIO MSF command virtual bool PlayAudioMSF(const DWORD *cdb); // PLAY AUDIO MSF command
virtual BOOL PlayAudioTrack(const DWORD *cdb); // PLAY AUDIO TRACK 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
protected: protected:
// Internal processing // Internal processing
virtual int AddError(BOOL change, BYTE *buf); // Add error virtual int AddError(bool change, BYTE *buf); // Add error
virtual int AddFormat(BOOL change, BYTE *buf); // Add format virtual int AddFormat(bool change, BYTE *buf); // Add format
virtual int AddDrive(BOOL change, BYTE *buf); // Add drive virtual int AddDrive(bool change, BYTE *buf); // Add drive
int AddOpt(BOOL change, BYTE *buf); // Add optical int AddOpt(bool change, BYTE *buf); // Add optical
int AddCache(BOOL change, BYTE *buf); // Add cache int AddCache(bool change, BYTE *buf); // Add cache
int AddCDROM(BOOL change, BYTE *buf); // Add CD-ROM int AddCDROM(bool change, BYTE *buf); // Add CD-ROM
int AddCDDA(BOOL change, BYTE *buf); // Add CD_DA int AddCDDA(bool, BYTE *buf); // Add CD_DA
virtual int AddVendor(int page, BOOL change, BYTE *buf); // Add vendor special info virtual int AddVendor(int page, bool change, BYTE *buf); // Add vendor special info
BOOL CheckReady(); // Check if ready BOOL CheckReady(); // Check if ready
// Internal data // Internal data
disk_t disk; // Internal disk data disk_t disk; // Internal disk data
Filepath diskpath; // File path (for GetPath)
BOOL cache_wb; // Cache mode 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") SASIHD::SASIHD() : Disk("SAHD")
{ {
disk.protectable = true; SetProtectable(true);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -42,12 +42,12 @@ SASIHD::SASIHD() : Disk("SAHD")
void SASIHD::Reset() void SASIHD::Reset()
{ {
// Unlock, clear attention // Unlock, clear attention
disk.locked = FALSE; SetLocked(false);
disk.attn = FALSE; SetAttn(false);
// Reset, clear the code // Reset, clear the code
disk.reset = FALSE; SetReset(false);
disk.code = 0x00; SetStatusCode(STATUS_NOERROR);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -55,18 +55,18 @@ void SASIHD::Reset()
// Open // Open
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SASIHD::Open(const Filepath& path, BOOL /*attn*/) void SASIHD::Open(const Filepath& path)
{ {
ASSERT(!disk.ready); ASSERT(!IsReady());
// Open as read-only // Open as read-only
Fileio fio; Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) { 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 // Get file size
off64_t size = fio.GetFileSize(); off_t size = fio.GetFileSize();
fio.Close(); fio.Close();
#if defined(USE_MZ1F23_1024_SUPPORT) #if defined(USE_MZ1F23_1024_SUPPORT)
@ -74,28 +74,28 @@ void SASIHD::Open(const Filepath& path, BOOL /*attn*/)
// 20M(22437888 BS=1024 C=21912) // 20M(22437888 BS=1024 C=21912)
if (size == 0x1566000) { if (size == 0x1566000) {
// Sector size and number of blocks // Sector size and number of blocks
disk.size = 10; SetSectorSize(10);
disk.blocks = (DWORD)(size >> 10); SetBlockCount((DWORD)(size >> 10));
// Call the base class
Disk::Open(path); Disk::Open(path);
FileSupport::SetPath(path);
} }
#endif // USE_MZ1F23_1024_SUPPORT #endif // USE_MZ1F23_1024_SUPPORT
#if defined(REMOVE_FIXED_SASIHD_SIZE) #if defined(REMOVE_FIXED_SASIHD_SIZE)
// Must be in 256-byte units // Must be in 256-byte units
if (size & 0xff) { 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 // 10MB or more
if (size < 0x9f5400) { 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 // Limit to about 512MB
if (size > 512 * 1024 * 1024) { 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 #else
// 10MB, 20MB, 40MBのみ // 10MB, 20MB, 40MBのみ
@ -114,13 +114,13 @@ void SASIHD::Open(const Filepath& path, BOOL /*attn*/)
// Other (Not supported ) // Other (Not supported )
default: default:
throw ioexception("Unsupported file size"); throw io_exception("Unsupported file size");
} }
#endif // REMOVE_FIXED_SASIHD_SIZE #endif // REMOVE_FIXED_SASIHD_SIZE
// Sector size and number of blocks // Sector size 256 bytes and number of blocks
disk.size = 8; SetSectorSize(8);
disk.blocks = (DWORD)(size >> 8); SetBlockCount((DWORD)(size >> 8));
// Call the base class // Call the base class
Disk::Open(path); Disk::Open(path);
@ -147,11 +147,8 @@ int SASIHD::RequestSense(const DWORD *cdb, BYTE *buf)
// SASI fixed to non-extended format // SASI fixed to non-extended format
memset(buf, 0, size); memset(buf, 0, size);
buf[0] = (BYTE)(disk.code >> 16); buf[0] = (BYTE)(GetStatusCode() >> 16);
buf[1] = (BYTE)(disk.lun << 5); buf[1] = (BYTE)(GetLun() << 5);
// Clear the code
disk.code = 0x00;
return size; return size;
} }

View File

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

View File

@ -28,6 +28,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "scsi_daynaport.h" #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") SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
{ {
disk.supports_file = false; SetRemovable(false);
#ifdef __linux__ SetVendor("Dayna");
SetProduct("SCSI/Link");
#ifdef __linux__
// TAP Driver Generation // TAP Driver Generation
m_tap = new CTapDriver(); m_tap = new CTapDriver();
m_bTapEnable = m_tap->Init(); m_bTapEnable = m_tap->Init();
@ -63,8 +67,8 @@ SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
LOGTRACE("%s this->reset()", __PRETTY_FUNCTION__); LOGTRACE("%s this->reset()", __PRETTY_FUNCTION__);
this->Reset(); this->Reset();
disk.ready = true; SetReady(true);
disk.reset = false; SetReset(false);
// Generate MAC Address // Generate MAC Address
LOGTRACE("%s memset(m_mac_addr, 0x00, 6);", __PRETTY_FUNCTION__); LOGTRACE("%s memset(m_mac_addr, 0x00, 6);", __PRETTY_FUNCTION__);
@ -115,14 +119,13 @@ SCSIDaynaPort::~SCSIDaynaPort()
// INQUIRY // 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; // scsi_cdb_6_byte_t command;
// memcpy(&command,cdb,sizeof(command)); // memcpy(&command,cdb,sizeof(command));
ASSERT(cdb); ASSERT(cdb);
ASSERT(buffer); ASSERT(buffer);
ASSERT(cdb[0] == 0x12);
//allocation_length = command->length; //allocation_length = command->length;
DWORD allocation_length = cdb[4] + (((DWORD)cdb[3]) << 8); 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); // 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); LOGTRACE("%s Inquiry, allocation length: %d",__PRETTY_FUNCTION__, (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;
}
if (allocation_length > 4){ if (allocation_length > 4){
if (allocation_length > sizeof(m_daynaport_inquiry_response)) { 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 // Copy the pre-canned response
memcpy(buffer, m_daynaport_inquiry_response, allocation_length); 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); LOGTRACE("response size is %d", (int)allocation_length);
// Success
disk.code = DISK_NOERROR;
return allocation_length; 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 // READ
@ -202,7 +175,9 @@ int SCSIDaynaPort::Read(const DWORD *cdb, BYTE *buf, DWORD block)
ASSERT(buf); 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){ if(command->operation_code != 0x08){
LOGERROR("Received unexpected cdb command: %02X. Expected 0x08", (unsigned int)command->operation_code); 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) 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 // Status check
if (!CheckReady()) { if (!CheckReady()) {
@ -337,7 +314,7 @@ int SCSIDaynaPort::WriteCheck(DWORD block)
} }
if(!m_bTapEnable){ if(!m_bTapEnable){
disk.code = DISK_NOTREADY; SetStatusCode(STATUS_NOTREADY);
return 0; return 0;
} }
@ -345,13 +322,12 @@ int SCSIDaynaPort::WriteCheck(DWORD block)
return 1; return 1;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Write // 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; BYTE data_format;
WORD data_length; WORD data_length;
@ -372,22 +348,21 @@ BOOL SCSIDaynaPort::Write(const DWORD *cdb, const BYTE *buf, DWORD block)
if(data_format == 0x00){ if(data_format == 0x00){
m_tap->Tx(buf, data_length); m_tap->Tx(buf, data_length);
LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length); LOGTRACE("%s Transmitted %u bytes (00 format)", __PRETTY_FUNCTION__, data_length);
return TRUE; return true;
} }
else if (data_format == 0x80){ else if (data_format == 0x80){
// The data length is actuall specified in the first 2 bytes of the payload // The data length is actuall specified in the first 2 bytes of the payload
data_length=(WORD)buf[1] + ((WORD)buf[0] << 8); data_length=(WORD)buf[1] + ((WORD)buf[0] << 8);
m_tap->Tx(&buf[4], data_length); m_tap->Tx(&buf[4], data_length);
LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length); LOGTRACE("%s Transmitted %u bytes (80 format)", __PRETTY_FUNCTION__, data_length);
return TRUE; return true;
} }
else else
{ {
// LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format); // LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)command->format);
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_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 = 18;
response_size = sizeof(m_scsi_link_stats); response_size = sizeof(m_scsi_link_stats);
memcpy(buffer, &m_scsi_link_stats, 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 // Success
disk.code = DISK_NOERROR;
return response_size; return response_size;
// scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb; // scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb;
// scsi_resp_link_stats_t *response = (scsi_resp_link_stats_t*) buffer; // 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 // Enable or Disable the interface
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL SCSIDaynaPort::EnableInterface(const DWORD *cdb) bool SCSIDaynaPort::EnableInterface(const DWORD *cdb)
{ {
int result; bool result;
// scsi_cdb_6_byte_t *command = (scsi_cdb_6_byte_t*)cdb; if (cdb[5] & 0x80) {
// if(command->control & 0x80)
if(cdb[5] & 0x80)
{
result = m_tap->Enable(); result = m_tap->Enable();
if(result){ if (result) {
LOGINFO("The DaynaPort interface has been ENABLED."); LOGINFO("The DaynaPort interface has been ENABLED.");
} }
else{ else{
@ -499,10 +467,9 @@ BOOL SCSIDaynaPort::EnableInterface(const DWORD *cdb)
} }
m_tap->Flush(); m_tap->Flush();
} }
else else {
{
result = m_tap->Disable(); result = m_tap->Disable();
if(result){ if (result) {
LOGINFO("The DaynaPort interface has been DISABLED."); LOGINFO("The DaynaPort interface has been DISABLED.");
} }
else{ 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 // TEST UNIT READY
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/) bool SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/)
{ {
LOGTRACE("%s", __PRETTY_FUNCTION__); LOGTRACE("%s", __PRETTY_FUNCTION__);
// TEST UNIT READY Success // TEST UNIT READY Success
disk.code = DISK_NOERROR; return true;
return TRUE;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,7 @@ public:
// Basic Functions // Basic Functions
CDTrack(SCSICD *scsicd); // Constructor CDTrack(SCSICD *scsicd); // Constructor
virtual ~CDTrack(); // Destructor virtual ~CDTrack(); // Destructor
BOOL Init(int track, DWORD first, DWORD last); // Initialization void Init(int track, DWORD first, DWORD last); // Initialization
// Properties // Properties
void SetPath(BOOL cdda, const Filepath& path); // Set the path void SetPath(BOOL cdda, const Filepath& path); // Set the path
@ -62,47 +62,12 @@ private:
Filepath imgpath; // Image file path 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 // SCSI CD-ROM
// //
//=========================================================================== //===========================================================================
class SCSICD : public Disk class SCSICD : public Disk, public FileSupport
{ {
public: public:
// Number of tracks // Number of tracks
@ -113,19 +78,18 @@ public:
public: public:
// Basic Functions // Basic Functions
SCSICD(); // Constructor SCSICD(); // Constructor
virtual ~SCSICD(); // Destructor ~SCSICD(); // Destructor
void Open(const Filepath& path, BOOL attn = TRUE); // Open void Open(const Filepath& path); // Open
// commands // 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 Read(const DWORD *cdb, BYTE *buf, DWORD block) override; // READ command
int ReadToc(const DWORD *cdb, BYTE *buf); // READ TOC 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 // 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 void GetBuf(DWORD *buffer, int samples, DWORD rate); // Get CD-DA buffer
// LBA-MSF変換 // LBA-MSF変換
@ -148,12 +112,4 @@ private:
int audioindex; // Current audio track int audioindex; // Current audio track
int frame; // Frame number 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 "xm6.h"
#include "fileio.h" #include "fileio.h"
#include "exceptions.h" #include "exceptions.h"
#include <sstream>
//=========================================================================== //===========================================================================
// //
@ -29,9 +30,10 @@
// Constructor // 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() void SCSIHD::Reset()
{ {
// Unlock and release attention // Unlock and release attention
disk.locked = FALSE; SetLocked(false);
disk.attn = FALSE; SetAttn(false);
// No reset, clear code // No reset, clear code
disk.reset = FALSE; SetReset(false);
disk.code = 0x00; SetStatusCode(STATUS_NOERROR);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -55,38 +57,43 @@ void SCSIHD::Reset()
// Open // 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; Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) { 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 // Get file size
off64_t size = fio.GetFileSize(); off_t size = fio.GetFileSize();
fio.Close(); fio.Close();
// Must be 512 bytes // Must be a multiple of 512 bytes
if (size & 0x1ff) { 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
// There is a similar one in wxw/wxw_cfg.cpp
// Bigger files/drives require READ/WRITE(16) to be implemented
if (size > 2LL * 1024 * 1024 * 1024 * 1024) { 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 // sector size 512 bytes and number of blocks
disk.size = 9; SetSectorSize(9);
disk.blocks = (DWORD)(size >> 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); Disk::Open(path);
FileSupport::SetPath(path);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -94,85 +101,52 @@ void SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
// INQUIRY // INQUIRY
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int SCSIHD:: Inquiry( int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf)
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{ {
char vendor[32];
char product[32];
char rev[32];
ASSERT(cdb); ASSERT(cdb);
ASSERT(buf); ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check // EVPD check
if (cdb[1] & 0x01) { if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB; SetStatusCode(STATUS_INVALIDCDB);
return 0; return 0;
} }
// Ready check (Error if no image file) // Ready check (Error if no image file)
if (!disk.ready) { if (!IsReady()) {
disk.code = DISK_NOTREADY; SetStatusCode(STATUS_NOTREADY);
return 0; return 0;
} }
// Basic data // Basic data
// buf[0] ... Direct Access Device // buf[0] ... Direct Access Device
// buf[1] ... Bit 7 set means removable
// buf[2] ... SCSI-2 compliant command system // buf[2] ... SCSI-2 compliant command system
// buf[3] ... SCSI-2 compliant Inquiry response // buf[3] ... SCSI-2 compliant Inquiry response
// buf[4] ... Inquiry additional data // buf[4] ... Inquiry additional data
memset(buf, 0, 8); memset(buf, 0, 8);
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling // 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[0] = 0x7f;
} }
buf[1] = IsRemovable() ? 0x80 : 0x00;
buf[2] = 0x02; buf[2] = 0x02;
buf[3] = 0x02; buf[3] = 0x02;
buf[4] = 122 + 3; // Value close to real HDD buf[4] = 122 + 3; // Value close to real HDD
// Fill with blanks // Padded vendor, product, revision
memset(&buf[8], 0x20, buf[4] - 3); memcpy(&buf[8], GetPaddedName().c_str(), 28);
// 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);
// Size of data that can be returned // Size of data that can be returned
size = (buf[4] + 5); int size = (buf[4] + 5);
// Limit if the other buffer is small // Limit if the other buffer is small
if (size > (int)cdb[4]) { if (size > (int)cdb[4]) {
size = (int)cdb[4]; size = (int)cdb[4];
} }
// Success
disk.code = DISK_NOERROR;
return size; return size;
} }
@ -182,7 +156,7 @@ int SCSIHD:: Inquiry(
// *Not affected by disk.code // *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; BYTE page;
int size; int size;
@ -195,13 +169,13 @@ BOOL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// Mode Parameter header // Mode Parameter header
if (length >= 12) { if (length >= 12) {
// Check the block length bytes // Check the block length bytes
size = 1 << disk.size; size = 1 << GetSectorSize();
if (buf[9] != (BYTE)(size >> 16) || if (buf[9] != (BYTE)(size >> 16) ||
buf[10] != (BYTE)(size >> 8) || buf[10] != (BYTE)(size >> 8) ||
buf[11] != (BYTE)size) { buf[11] != (BYTE)size) {
// currently does not allow changing sector length // currently does not allow changing sector length
disk.code = DISK_INVALIDPRM; SetStatusCode(STATUS_INVALIDPRM);
return FALSE; return false;
} }
buf += 12; buf += 12;
length -= 12; length -= 12;
@ -216,12 +190,12 @@ BOOL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
// format device // format device
case 0x03: case 0x03:
// check the number of bytes in the physical sector // check the number of bytes in the physical sector
size = 1 << disk.size; size = 1 << GetSectorSize();
if (buf[0xc] != (BYTE)(size >> 8) || if (buf[0xc] != (BYTE)(size >> 8) ||
buf[0xd] != (BYTE)size) { buf[0xd] != (BYTE)size) {
// currently does not allow changing sector length // currently does not allow changing sector length
disk.code = DISK_INVALIDPRM; SetStatusCode(STATUS_INVALIDPRM);
return FALSE; return false;
} }
break; 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) // 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 "disk.h"
#include "filepath.h" #include "filepath.h"
#define DEFAULT_PRODUCT "SCSI HD"
//=========================================================================== //===========================================================================
// //
// SCSI Hard Disk // SCSI Hard Disk
// //
//=========================================================================== //===========================================================================
class SCSIHD : public Disk class SCSIHD : public Disk, public FileSupport
{ {
public: public:
// Basic Functions // Basic Functions
SCSIHD(); // Constructor SCSIHD(bool = false); // Constructor
void Reset(); // Reset void Reset(); // Reset
void Open(const Filepath& path, BOOL attn = TRUE); // Open void Open(const Filepath& path); // Open
// commands // commands
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command int Inquiry(const DWORD *cdb, BYTE *buf) override; // INQUIRY command
BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); // MODE SELECT(6) 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() SCSIHD_NEC::SCSIHD_NEC() : SCSIHD()
{ {
SetVendor("NEC");
// Work initialization // Work initialization
cylinders = 0; cylinders = 0;
heads = 0; heads = 0;
@ -68,42 +70,39 @@ static inline DWORD getDwordLE(const BYTE *b)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
{ {
Fileio fio; ASSERT(!IsReady());
off64_t size;
BYTE hdr[512];
LPCTSTR ext;
ASSERT(!disk.ready);
// Open as read-only // Open as read-only
Fileio fio;
if (!fio.Open(path, Fileio::ReadOnly)) { 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 // Get file size
size = fio.GetFileSize(); off_t size = fio.GetFileSize();
// Read header // Read header
if (size >= (off64_t)sizeof(hdr)) { BYTE hdr[512];
if (size >= (off_t)sizeof(hdr)) {
if (!fio.Read(hdr, sizeof(hdr))) { if (!fio.Read(hdr, sizeof(hdr))) {
fio.Close(); fio.Close();
throw ioexception("Can't read hard disk file header"); throw io_exception("Can't read NEC hard disk file header");
} }
} }
fio.Close(); fio.Close();
// Must be in 512 byte units // Must be in 512 byte units
if (size & 0x1ff) { 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) { 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 // Determine parameters by extension
ext = path.GetFileExt(); LPCTSTR ext = path.GetFileExt();
if (strcasecmp(ext, _T(".HDN")) == 0) { if (strcasecmp(ext, _T(".HDN")) == 0) {
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings // Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
imgoffset = 0; imgoffset = 0;
@ -128,34 +127,37 @@ void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]); heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]);
sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]); sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]);
sectorsize = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2 + 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 // Supports 256 or 512 sector sizes
if (sectorsize != 256 && sectorsize != 512) { 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 // Image size consistency check
if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) { if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) {
throw ioexception("Image size consistency check failed"); throw io_exception("Image size consistency check failed");
} }
// Sector size // Sector size
// TODO Do not use disk.size directly
for(disk.size = 16; disk.size > 0; --(disk.size)) { for(disk.size = 16; disk.size > 0; --(disk.size)) {
if ((1 << disk.size) == sectorsize) if ((1 << disk.size) == sectorsize)
break; break;
} }
if (disk.size <= 0 || disk.size > 16) { if (disk.size <= 0 || disk.size > 16) {
throw ioexception("Invalid disk size"); throw io_exception("Invalid disk size");
} }
// Number of blocks // Number of blocks
disk.blocks = (DWORD)(imgsize >> disk.size); SetBlockCount((DWORD)(imgsize >> disk.size));
disk.imgoffset = imgoffset; disk.imgoffset = imgoffset;
// Call the base class LOGINFO("Media capacity for image file '%s': %d blocks", path.GetPath(), GetBlockCount());
Disk::Open(path); Disk::Open(path);
FileSupport::SetPath(path);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -163,28 +165,14 @@ void SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
// INQUIRY // INQUIRY
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int SCSIHD_NEC::Inquiry( int SCSIHD_NEC::Inquiry(const DWORD *cdb, BYTE *buf)
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{ {
int size; int size = SCSIHD::Inquiry(cdb, buf);
// Base class // This drive is a SCSI-1 SCCS drive
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
buf[2] = 0x01; buf[2] = 0x01;
buf[3] = 0x01; buf[3] = 0x01;
// Replace Vendor name
buf[8] = 'N';
buf[9] = 'E';
buf[10] = 'C';
return size; return size;
} }
@ -193,7 +181,7 @@ int SCSIHD_NEC::Inquiry(
// Error page added // Error page added
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int SCSIHD_NEC::AddError(BOOL change, BYTE *buf) int SCSIHD_NEC::AddError(bool change, BYTE *buf)
{ {
ASSERT(buf); ASSERT(buf);
@ -201,11 +189,6 @@ int SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
buf[0] = 0x01; buf[0] = 0x01;
buf[1] = 0x06; 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. // The retry count is 0, and the limit time uses the default value inside the device.
return 8; return 8;
} }
@ -215,7 +198,7 @@ int SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
// Format page added // Format page added
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf) int SCSIHD_NEC::AddFormat(bool change, BYTE *buf)
{ {
ASSERT(buf); ASSERT(buf);
@ -230,7 +213,7 @@ int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
return 24; return 24;
} }
if (disk.ready) { if (IsReady()) {
// Set the number of tracks in one zone (PC-9801-55 seems to see this value) // Set the number of tracks in one zone (PC-9801-55 seems to see this value)
buf[0x2] = (BYTE)(heads >> 8); buf[0x2] = (BYTE)(heads >> 8);
buf[0x3] = (BYTE)heads; buf[0x3] = (BYTE)heads;
@ -246,7 +229,7 @@ int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
} }
// Set removable attributes (remains of the old days) // Set removable attributes (remains of the old days)
if (disk.removable) { if (IsRemovable()) {
buf[20] = 0x20; buf[20] = 0x20;
} }
@ -258,7 +241,7 @@ int SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
// Drive page added // Drive page added
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf) int SCSIHD_NEC::AddDrive(bool change, BYTE *buf)
{ {
ASSERT(buf); ASSERT(buf);
@ -267,11 +250,7 @@ int SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf)
buf[1] = 0x12; buf[1] = 0x12;
// No changeable area // No changeable area
if (change) { if (!change && IsReady()) {
return 20;
}
if (disk.ready) {
// Set the number of cylinders // Set the number of cylinders
buf[0x2] = (BYTE)(cylinders >> 16); buf[0x2] = (BYTE)(cylinders >> 16);
buf[0x3] = (BYTE)(cylinders >> 8); buf[0x3] = (BYTE)(cylinders >> 8);

View File

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

View File

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

View File

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

View File

@ -1,48 +1,56 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// SCSI Target Emulator RaSCSI (*^..^*) // SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi // for Raspberry Pi
// //
// Powered by XM6 TypeG Technology. // Copyright (C) 2021 Uwe Seimet
// Copyright (C) 2016-2020 GIMONS //
// [ Exceptions ] // Various exceptions
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#if !defined(exceptions_h) #pragma once
#define exceptions_h
#include <exception> #include <exception>
#include <string> #include <string>
using namespace std; using namespace std;
class lunexception final : public exception { class illegal_argument_exception final : public exception {
private:
int lun;
public:
lunexception(int _lun) : lun(_lun) { }
~lunexception() { }
int getlun() const {
return lun;
}
};
class ioexception : public exception {
private: private:
string msg; string msg;
public: public:
ioexception(const string& _msg) : msg(_msg) { } illegal_argument_exception(const string& _msg) : msg(_msg) {}
illegal_argument_exception() {};
~ioexception() { }
const string& getmsg() const { const string& getmsg() const {
return msg; 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); handle = open(fname, O_RDWR | omode);
break; break;
// アペンド
case Append:
handle = open(fname, O_CREAT | O_WRONLY | O_APPEND | omode, 0666);
break;
// それ以外 // それ以外
default: default:
ASSERT(FALSE); 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(handle >= 0);
ASSERT(offset >= 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; off_t cur;
off64_t end; off_t end;
ASSERT(handle >= 0); 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); ASSERT(handle >= 0);

View File

@ -39,8 +39,7 @@ public:
enum OpenMode { enum OpenMode {
ReadOnly, // 読み込みのみ ReadOnly, // 読み込みのみ
WriteOnly, // 書き込みのみ WriteOnly, // 書き込みのみ
ReadWrite, // 読み書き両方 ReadWrite // 読み書き両方
Append // アペンド
}; };
public: public:
@ -61,15 +60,15 @@ public:
// オープン // オープン
BOOL OpenDIO(const Filepath& path, OpenMode mode); 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 Read(void *buffer, int size);
// 読み込み // 読み込み
BOOL Write(const 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(); void Close();
// クローズ // クローズ

View File

@ -487,7 +487,7 @@ void GPIOBUS::SetENB(BOOL ast)
// Get BSY signal // Get BSY signal
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL GPIOBUS::GetBSY() bool GPIOBUS::GetBSY()
{ {
return GetSignal(PIN_BSY); return GetSignal(PIN_BSY);
} }
@ -497,7 +497,7 @@ BOOL GPIOBUS::GetBSY()
// Set BSY signal // Set BSY signal
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void GPIOBUS::SetBSY(BOOL ast) void GPIOBUS::SetBSY(bool ast)
{ {
// Set BSY signal // Set BSY signal
SetSignal(PIN_BSY, ast); SetSignal(PIN_BSY, ast);
@ -898,12 +898,7 @@ int GPIOBUS::CommandHandShake(BYTE *buf)
goto irq_enable_exit; goto irq_enable_exit;
} }
// Distinguise whether the command is 6 bytes or 10 bytes count = GetCommandByteCount(*buf);
if (*buf >= 0x20 && *buf <= 0x7D) {
count = 10;
} else {
count = 6;
}
// Increment buffer pointer // Increment buffer pointer
buf++; buf++;
@ -1609,6 +1604,26 @@ BUS::phase_t GPIOBUS::GetPhaseRaw(DWORD raw_data)
return GetPhase(mci); 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); void SetENB(BOOL ast);
// Set ENB signal // Set ENB signal
BOOL GetBSY(); bool GetBSY();
// Get BSY signal // Get BSY signal
void SetBSY(BOOL ast); void SetBSY(bool ast);
// Set BSY signal // Set BSY signal
BOOL GetSEL(); BOOL GetSEL();
@ -575,7 +575,9 @@ public:
static BUS::phase_t GetPhaseRaw(DWORD raw_data); static BUS::phase_t GetPhaseRaw(DWORD raw_data);
// Get the phase based on 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 // SEL signal interrupt
int PollSelectEvent(); int PollSelectEvent();
// SEL signal event polling // SEL signal event polling

View File

@ -23,18 +23,11 @@
spdlog::log(loglevel, logbuf); \ 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 LOGTRACE(...) SPDLOGWRAPPER(spdlog::level::trace, __VA_ARGS__)
#define LOGDEBUG(...) SPDLOGWRAPPER(spdlog::level::debug, __VA_ARGS__) #define LOGDEBUG(...) SPDLOGWRAPPER(spdlog::level::debug, __VA_ARGS__)
#endif
#define LOGINFO(...) SPDLOGWRAPPER(spdlog::level::info, __VA_ARGS__) #define LOGINFO(...) SPDLOGWRAPPER(spdlog::level::info, __VA_ARGS__)
#define LOGWARN(...) SPDLOGWRAPPER(spdlog::level::warn, __VA_ARGS__) #define LOGWARN(...) SPDLOGWRAPPER(spdlog::level::warn, __VA_ARGS__)
#define LOGERROR(...) SPDLOGWRAPPER(spdlog::level::err, __VA_ARGS__) #define LOGERROR(...) SPDLOGWRAPPER(spdlog::level::err, __VA_ARGS__)
#define LOGCRITICAL(...) SPDLOGWRAPPER(spdlog::level::critical, __VA_ARGS__) #define LOGCRITICAL(...) SPDLOGWRAPPER(spdlog::level::critical, __VA_ARGS__)
#endif // log_h #endif

View File

@ -55,6 +55,7 @@
#include <poll.h> #include <poll.h>
#include <dirent.h> #include <dirent.h>
#include <pwd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/epoll.h> #include <sys/epoll.h>
@ -102,9 +103,9 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short WORD; typedef uint16_t WORD;
typedef unsigned long DWORD; typedef uint32_t DWORD;
typedef unsigned long long QWORD; typedef uint64_t QWORD;
typedef int BOOL; typedef int BOOL;
typedef char TCHAR; typedef char TCHAR;
typedef char *LPTSTR; typedef char *LPTSTR;
@ -128,6 +129,4 @@ typedef const char *LPCSTR;
#define _MAX_FNAME 256 #define _MAX_FNAME 256
#define _MAX_EXT 256 #define _MAX_EXT 256
#define off64_t off_t
#endif // os_h #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"; syntax = "proto3";
package rascsi_interface; package rascsi_interface;
// The supported device types // The available device types
enum PbDeviceType { enum PbDeviceType {
UNDEFINED = 0; UNDEFINED = 0;
SASI_HD = 1; // Non-removable SASI drive
SCSI_HD = 2; SAHD = 1;
MO = 3; // Non-removable SCSI drive
CD = 4; SCHD = 2;
BR = 5; // Removable SCSI drive
NUVOLINK = 6; SCRM = 3;
DAYNAPORT = 7; // Magnoto-Optical drive
SCMO = 4;
// CD-ROM drive
SCCD = 5;
// Network bridge
SCBR = 6;
// DaynaPort network adapter
SCDP = 7;
} }
// rascsi remote operations // rascsi remote operations
enum PbOperation { enum PbOperation {
NONE = 0; NONE = 0;
// Returns the full server information // Returns the server information
SERVER_INFO = 1; SERVER_INFO = 1;
// Returns the device list only (required for rasctl/logging semantics compatibility) // Set the default folder for image files, PbCommand.params contains the folder name
LIST = 2 [deprecated = true]; DEFAULT_FOLDER = 2;
// Set server log level, PbCommand.params contains the log level
LOG_LEVEL = 3; LOG_LEVEL = 3;
// Attach new device
ATTACH = 4; ATTACH = 4;
// Detach device. Detach all devices if PbCommand.params == "all". In this case ID and unit are ignored.
DETACH = 5; DETACH = 5;
// Insert media
INSERT = 6; INSERT = 6;
// Eject media
EJECT = 7; EJECT = 7;
// Write-protect media (not possible for read-only media)
PROTECT = 8; PROTECT = 8;
// Make media writable (not possible for read-only media)
UNPROTECT = 9; UNPROTECT = 9;
} }
// Commands rascsi can execute // The image file data
message PbCommand { message PbImageFile {
PbOperation cmd = 1; string name = 1;
int32 id = 2; bool read_only = 2;
int32 un = 3; int64 size = 3;
PbDeviceType type = 4;
string params = 5;
} }
// The result of a command // The device definition, sent from the client to the server
message PbResult { message PbDeviceDefinition {
bool status = 1;
string msg = 2;
}
// The device meta data
message PbDevice {
int32 id = 1; int32 id = 1;
int32 un = 2; int32 unit = 2;
PbDeviceType type = 3; PbDeviceType type = 3;
string file = 4; string file = 4;
bool read_only = 5; // The device name, format is VENDOR:PRODUCT:REVISION
// Note: Read-only media (e.g. CD-ROMs) are not protectable string name = 5;
bool protectable = 6; bool protected = 6;
// Note: Read-only media (e.g. CD-ROMs) are not protected but just read-only }
bool protected = 7;
bool removable = 8; message PbDeviceDefinitions {
bool removed = 9; repeated PbDeviceDefinition devices = 1;
bool lockable = 10; }
bool locked = 11;
bool supports_file = 12; // 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 { message PbDevices {
repeated PbDevice devices = 1; 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 // The rascsi server information
message PbServerInfo { message PbServerInfo {
string rascsi_version = 1; string rascsi_version = 1;
@ -75,7 +127,7 @@ message PbServerInfo {
string current_log_level = 3; string current_log_level = 3;
string default_image_folder = 4; string default_image_folder = 4;
// Files in the default folder // Files in the default folder
repeated string available_image_files = 5; repeated PbImageFile available_image_files = 5;
// The attached devices // The attached devices
PbDevices devices = 6; 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 // Get the RaSCSI version string
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
char* rascsi_get_version_string() const char* rascsi_get_version_string()
{ {
if(rascsi_patch_version < 0) if(rascsi_patch_version < 0)
{ {
@ -42,3 +42,5 @@ char* rascsi_get_version_string()
} }
return rascsi_version_string; return rascsi_version_string;
} }

View File

@ -18,4 +18,4 @@ extern const int rascsi_patch_version; // Patch number
// Fetch the version string // 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 <netdb.h>
#include "google/protobuf/message_lite.h"
#include "os.h" #include "os.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "exceptions.h" #include "exceptions.h"
#include "protobuf_util.h"
#include "rasutil.h" #include "rasutil.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include <sstream> #include <sstream>
@ -35,12 +35,12 @@ int SendCommand(const string& hostname, int port, const PbCommand& command)
try { try {
struct hostent *host = gethostbyname(hostname.c_str()); struct hostent *host = gethostbyname(hostname.c_str());
if (!host) { if (!host) {
throw ioexception("Can't resolve hostname '" + hostname + "'"); throw io_exception("Can't resolve hostname '" + hostname + "'");
} }
fd = socket(AF_INET, SOCK_STREAM, 0); fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) { if (fd < 0) {
throw ioexception("Can't create socket"); throw io_exception("Can't create socket");
} }
struct sockaddr_in server; 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) { if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
ostringstream error; ostringstream error;
error << "Can't connect to rascsi process on host '" << hostname << "', port " << port; error << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
throw ioexception(error.str()); throw io_exception(error.str());
} }
SerializeMessage(fd, command); SerializeMessage(fd, command);
} }
catch(const ioexception& e) { catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl; cerr << "Error: " << e.getmsg() << endl;
if (fd >= 0) { if (fd >= 0) {
close(fd); close(fd);
} }
exit(fd < 0 ? ENOTCONN : -1); exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
} }
return fd; return fd;
@ -84,12 +84,14 @@ bool ReceiveResult(int fd)
close(fd); close(fd);
if (!result.status()) { 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; cerr << "Error: " << e.getmsg() << endl;
return false; return false;
@ -107,25 +109,25 @@ bool ReceiveResult(int fd)
void CommandList(const string& hostname, int port) void CommandList(const string& hostname, int port)
{ {
PbCommand command; PbCommand command;
command.set_cmd(LIST); command.set_cmd(SERVER_INFO);
int fd = SendCommand(hostname.c_str(), port, command); int fd = SendCommand(hostname.c_str(), port, command);
PbDevices devices; PbServerInfo serverInfo;
try { try {
DeserializeMessage(fd, devices); DeserializeMessage(fd, serverInfo);
} }
catch(const ioexception& e) { catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl; cerr << "Error: " << e.getmsg() << endl;
close(fd); 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) 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); 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) void CommandServerInfo(const string& hostname, int port)
{ {
PbCommand command; PbCommand command;
@ -150,12 +163,12 @@ void CommandServerInfo(const string& hostname, int port)
try { try {
DeserializeMessage(fd, serverInfo); DeserializeMessage(fd, serverInfo);
} }
catch(const ioexception& e) { catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl; cerr << "Error: " << e.getmsg() << endl;
close(fd); close(fd);
exit(-1); exit(EXIT_FAILURE);
} }
close(fd); close(fd);
@ -179,19 +192,71 @@ void CommandServerInfo(const string& hostname, int port)
cout << " No image files available in the default folder" << endl; cout << " No image files available in the default folder" << endl;
} }
else { else {
list<string> sorted_image_files; list<string> sorted_files;
for (int i = 0; i < serverInfo.available_image_files_size(); i++) { 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; 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; 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 // Main processing
@ -205,12 +270,14 @@ int main(int argc, char* argv[])
if (argc < 2) { if (argc < 2) {
cerr << "SCSI Target Emulator RaSCSI Controller" << endl; cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << 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 << " where ID := {0|1|2|3|4|5|6|7}" << endl;
cerr << " UNIT := {0|1} default setting is 0." << endl; cerr << " UNIT := {0|1} default setting is 0." << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect}" << endl; cerr << " 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 << " 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 << " HOST := rascsi host to connect to, default is 'localhost'" << endl;
cerr << " PORT := rascsi port to connect to, default is 6868" << 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; 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 << "Usage: " << argv[0] << " -l" << endl;
cerr << " Print device list." << endl; cerr << " Print device list." << endl;
exit(0); exit(EXIT_SUCCESS);
} }
// Parse the arguments // Parse the arguments
int opt; PbCommand command;
int id = -1; PbDeviceDefinitions devices;
int un = 0; command.set_allocated_devices(&devices);
PbOperation cmd = LIST; PbDeviceDefinition *device = devices.add_devices();
PbDeviceType type = UNDEFINED; device->set_id(-1);
const char *hostname = "localhost"; const char *hostname = "localhost";
int port = 6868; int port = 6868;
string params; string log_level;
opterr = 0; string default_folder;
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:u:g:lsv")) != -1) { 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) { switch (opt) {
case 'i': case 'i':
id = optarg[0] - '0'; device->set_id(optarg[0] - '0');
break; break;
case 'u': case 'u':
un = optarg[0] - '0'; device->set_unit(optarg[0] - '0');
break; break;
case 'c': case 'c':
switch (tolower(optarg[0])) { command.set_cmd(ParseOperation(optarg));
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;
}
break; break;
case 't': case 't':
switch (tolower(optarg[0])) { device->set_type(ParseType(optarg));
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;
}
break; break;
case 'f': case 'f':
params = optarg; device->set_file(optarg);
break; break;
case 'l': case 'd':
cmd = LIST; command.set_cmd(DEFAULT_FOLDER);
default_folder = optarg;
break; break;
case 'h': case 'h':
hostname = optarg; hostname = optarg;
break; break;
case 'l':
list = true;
break;
case 'n':
device->set_name(optarg);
break;
case 'p': case 'p':
port = atoi(optarg); port = atoi(optarg);
if (port <= 0 || port > 65535) { if (port <= 0 || port > 65535) {
cerr << "Invalid port " << optarg << ", port must be between 1 and 65535" << endl; cerr << "Invalid port " << optarg << ", port must be between 1 and 65535" << endl;
exit(-1); exit(EXIT_FAILURE);
} }
break; break;
case 'g': case 'g':
cmd = LOG_LEVEL; command.set_cmd(LOG_LEVEL);
params = optarg; log_level = optarg;
break; break;
case 's': case 's':
cmd = SERVER_INFO; command.set_cmd(SERVER_INFO);
break; break;
case 'v': case 'v':
cout << rascsi_get_version_string() << endl; cout << rascsi_get_version_string() << endl;
exit(0); exit(EXIT_SUCCESS);
break; break;
} }
} }
if (cmd == LOG_LEVEL) { if (optopt) {
CommandLogLevel(hostname, port, params); exit(EXIT_FAILURE);
exit(0);
} }
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); CommandServerInfo(hostname, port);
exit(0); exit(EXIT_SUCCESS);
} }
// List display only if (list) {
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
CommandList(hostname, port); CommandList(hostname, port);
exit(0); exit(EXIT_SUCCESS);
}
// 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);
} }
// Send the command
int fd = SendCommand(hostname, port, command); int fd = SendCommand(hostname, port, command);
bool status = ReceiveResult(fd); bool status = ReceiveResult(fd);
close(fd); close(fd);
// All done! // 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 targetid; // Target ID
int boardid; // Board ID (own ID) int boardid; // Board ID (own ID)
Filepath hdsfile; // HDS file Filepath hdsfile; // HDS file
BOOL restore; // Restore flag bool restore; // Restore flag
BYTE buffer[BUFSIZE]; // Work Buffer BYTE buffer[BUFSIZE]; // Work Buffer
int result; // Result Code int result; // Result Code
@ -60,7 +60,7 @@ void KillHandler(int sig)
// Banner Output // Banner Output
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL Banner(int argc, char* argv[]) bool Banner(int argc, char* argv[])
{ {
printf("RaSCSI hard disk dump utility "); printf("RaSCSI hard disk dump utility ");
printf("version %s (%s, %s)\n", 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(" 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(" FILE is HDS file path.\n");
printf(" -r is restore operation.\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 // Initialization
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL Init() bool Init()
{ {
// Interrupt handler setting // Interrupt handler setting
if (signal(SIGINT, KillHandler) == SIG_ERR) { if (signal(SIGINT, KillHandler) == SIG_ERR) {
return FALSE; return false;
} }
if (signal(SIGHUP, KillHandler) == SIG_ERR) { if (signal(SIGHUP, KillHandler) == SIG_ERR) {
return FALSE; return false;
} }
if (signal(SIGTERM, KillHandler) == SIG_ERR) { if (signal(SIGTERM, KillHandler) == SIG_ERR) {
return FALSE; return false;
} }
// GPIO Initialization // GPIO Initialization
if (!bus.Init(BUS::INITIATOR)) { if (!bus.Init(BUS::INITIATOR)) {
return FALSE; return false;
} }
// Work Intitialization // Work Intitialization
targetid = -1; targetid = -1;
boardid = 7; boardid = 7;
restore = FALSE; restore = false;
return TRUE; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -138,7 +138,7 @@ void Reset()
// Argument processing // Argument processing
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL ParseArgument(int argc, char* argv[]) bool ParseArgument(int argc, char* argv[])
{ {
int opt; int opt;
char *file; char *file;
@ -163,7 +163,7 @@ BOOL ParseArgument(int argc, char* argv[])
break; break;
case 'r': case 'r':
restore = TRUE; restore = true;
break; break;
} }
} }
@ -172,33 +172,33 @@ BOOL ParseArgument(int argc, char* argv[])
if (targetid < 0 || targetid > 7) { if (targetid < 0 || targetid > 7) {
fprintf(stderr, fprintf(stderr,
"Error : Invalid target id range\n"); "Error : Invalid target id range\n");
return FALSE; return false;
} }
// BOARD ID check // BOARD ID check
if (boardid < 0 || boardid > 7) { if (boardid < 0 || boardid > 7) {
fprintf(stderr, fprintf(stderr,
"Error : Invalid board id range\n"); "Error : Invalid board id range\n");
return FALSE; return false;
} }
// Target and Board ID duplication check // Target and Board ID duplication check
if (targetid == boardid) { if (targetid == boardid) {
fprintf(stderr, fprintf(stderr,
"Error : Invalid target or board id\n"); "Error : Invalid target or board id\n");
return FALSE; return false;
} }
// File Check // File Check
if (!file) { if (!file) {
fprintf(stderr, fprintf(stderr,
"Error : Invalid file path\n"); "Error : Invalid file path\n");
return FALSE; return false;
} }
hdsfile.SetPath(file); hdsfile.SetPath(file);
return TRUE; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -206,7 +206,7 @@ BOOL ParseArgument(int argc, char* argv[])
// Wait Phase // Wait Phase
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL WaitPhase(BUS::phase_t phase) bool WaitPhase(BUS::phase_t phase)
{ {
DWORD now; DWORD now;
@ -215,11 +215,11 @@ BOOL WaitPhase(BUS::phase_t phase)
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) { while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
bus.Aquire(); bus.Aquire();
if (bus.GetREQ() && bus.GetPhase() == phase) { if (bus.GetREQ() && bus.GetPhase() == phase) {
return TRUE; return true;
} }
} }
return FALSE; return false;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -238,7 +238,7 @@ void BusFree()
// Selection Phase // Selection Phase
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL Selection(int id) bool Selection(int id)
{ {
BYTE data; BYTE data;
int count; int count;
@ -272,13 +272,13 @@ BOOL Selection(int id)
// Command Phase // Command Phase
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
BOOL Command(BYTE *buf, int length) bool Command(BYTE *buf, int length)
{ {
int count; int count;
// Waiting for Phase // Waiting for Phase
if (!WaitPhase(BUS::command)) { if (!WaitPhase(BUS::command)) {
return FALSE; return false;
} }
// Send Command // Send Command
@ -287,11 +287,11 @@ BOOL Command(BYTE *buf, int length)
// Success if the transmission result is the same as the number // Success if the transmission result is the same as the number
// of requests // of requests
if (count == length) { if (count == length) {
return TRUE; return true;
} }
// Return error // Return error
return FALSE; return false;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -808,7 +808,7 @@ int main(int argc, char* argv[])
DWORD dnum; DWORD dnum;
Fileio fio; Fileio fio;
Fileio::OpenMode omode; Fileio::OpenMode omode;
off64_t size; off_t size;
// Banner output // Banner output
if (!Banner(argc, argv)) { if (!Banner(argc, argv)) {
@ -918,9 +918,9 @@ int main(int argc, char* argv[])
if (restore) { if (restore) {
size = fio.GetFileSize(); size = fio.GetFileSize();
printf("Restore file size : %d bytes", (int)size); 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)"); 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"); printf("(ERROR : File size is smaller than disk size)\n");
goto cleanup_exit; goto cleanup_exit;
} }

View File

@ -1,86 +1,19 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// SCSI Target Emulator RaSCSI (*^..^*) // SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi // for Raspberry Pi
// //
// Powered by XM6 TypeG Technology. // Copyright (C) 2021 Uwe Seimet
// Copyright (C) 2016-2020 GIMONS
// Copyright (C) 2020 akuker
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <unistd.h>
#include <sstream> #include <sstream>
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include "exceptions.h"
#include "rasutil.h" #include "rasutil.h"
using namespace std; using namespace std;
using namespace rascsi_interface; 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 // List devices
@ -91,82 +24,38 @@ string ListDevices(const PbDevices& devices)
ostringstream s; ostringstream s;
if (devices.devices_size()) { if (devices.devices_size()) {
s << endl s << "+----+----+------+-------------------------------------" << endl
<< "+----+----+------+-------------------------------------" << endl << "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl; << "+----+----+------+-------------------------------------" << endl;
} }
else { else {
return "No images currently attached.\n"; return "No images currently attached.";
} }
for (int i = 0; i < devices.devices_size() ; i++) { for (int i = 0; i < devices.devices_size() ; i++) {
PbDevice device = devices.devices(i); PbDevice device = devices.devices(i);
s << "| " << device.id() << " | " << device.un() << " | " << MapTypeToId(device.type()) << " | " string filename;
<< (device.file().empty() ? "NO MEDIA" : device.file()) switch (device.type()) {
<< (device.read_only() ? " (WRITEPROTECT)" : "") << endl; 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(); 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 (*^..^*) // SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi // for Raspberry Pi
// //
// Powered by XM6 TypeG Technology. // Copyright (C) 2021 Uwe Seimet
// Copyright (C) 2016-2020 GIMONS //
// Copyright (C) 2020 akuker // Helper methods used by rascsi and rasctl
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#if !defined(rasutil_h) #pragma once
#define rasutil_h
#include "google/protobuf/message_lite.h" #include <string>
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
void SerializeMessage(int, const google::protobuf::MessageLite&); std::string ListDevices(const rascsi_interface::PbDevices&);
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

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <sys/time.h> #include <sys/time.h>
#include <climits> #include <climits>
#include <sstream>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
@ -52,8 +53,7 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static BYTE prev_value[32] = {0xFF}; static BYTE prev_value[32] = {0xFF};
static volatile BOOL running; // Running flag static volatile bool running; // Running flag
static volatile BOOL active; // Processing flag
GPIOBUS *bus; // GPIO Bus GPIOBUS *bus; // GPIO Bus
typedef struct data_capture{ typedef struct data_capture{
DWORD data; DWORD data;
@ -78,7 +78,7 @@ char log_file_name[_MAX_FNAME/2] = "log.vcd";
void KillHandler(int sig) void KillHandler(int sig)
{ {
// Stop instruction // Stop instruction
running = FALSE; running = false;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -143,8 +143,7 @@ BOOL Init()
bus->Reset(); bus->Reset();
// Other // Other
running = FALSE; running = false;
active = FALSE;
return TRUE; return TRUE;
} }
@ -266,7 +265,9 @@ void create_value_change_dump()
while(i < data_idx) 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_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_SEL, SYMBOL_PIN_SEL);
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_CD, SYMBOL_PIN_CD); 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[]) int main(int argc, char* argv[])
{ {
#ifdef DEBUG ostringstream s;
#ifdef DEBUG
DWORD prev_high = high_bits; DWORD prev_high = high_bits;
DWORD prev_low = low_bits; DWORD prev_low = low_bits;
#endif #endif
@ -409,13 +412,14 @@ int main(int argc, char* argv[])
sched_setscheduler(0, SCHED_FIFO, &schparam); sched_setscheduler(0, SCHED_FIFO, &schparam);
// Start execution // Start execution
running = TRUE; running = false;
bus->SetACT(FALSE); bus->SetACT(FALSE);
(void)gettimeofday(&start_time, NULL); (void)gettimeofday(&start_time, NULL);
LOGDEBUG("ALL_SCSI_PINS %08X\n",ALL_SCSI_PINS); LOGDEBUG("ALL_SCSI_PINS %08X\n",ALL_SCSI_PINS);
// Main Loop
// Main Loop
while (running) { while (running) {
// Work initialization // Work initialization
this_sample = (bus->Aquire() & ALL_SCSI_PINS); this_sample = (bus->Aquire() & ALL_SCSI_PINS);
@ -441,12 +445,14 @@ int main(int argc, char* argv[])
low_bits &= this_sample; low_bits &= this_sample;
if ((high_bits != prev_high) || (low_bits != prev_low)) 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_high = high_bits;
prev_low = low_bits; prev_low = low_bits;
if((data_idx % 1000) == 0){ 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 #endif
data_buffer[data_idx].data = this_sample; data_buffer[data_idx].data = this_sample;
@ -471,12 +477,18 @@ int main(int argc, char* argv[])
timersub(&stop_time, &start_time, &time_diff); timersub(&stop_time, &start_time, &time_diff);
elapsed_us = ((time_diff.tv_sec*1000000) + time_diff.tv_usec); elapsed_us = ((time_diff.tv_sec*1000000) + time_diff.tv_usec);
LOGINFO("Elapsed time: %llu microseconds (%lf seconds)",elapsed_us, ((double)elapsed_us)/1000000); s.str("");
LOGINFO("Collected %lu changes", data_idx); 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. // 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; 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
Cleanup(); Cleanup();

View File

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

View File

@ -6,7 +6,7 @@ import time
from ractl_cmds import attach_image from ractl_cmds import attach_image
from settings import * 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]) 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 * 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]) 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 # 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] EXCLUDE_SCSI_IDS = [7]
@ -70,8 +70,6 @@ def attach_image(scsi_id, image, device_type):
elif device_type == "SCDP": elif device_type == "SCDP":
attach_daynaport(scsi_id) attach_daynaport(scsi_id)
else: else:
if device_type == "SCCD":
device_type = "cd"
return subprocess.run( return subprocess.run(
["rasctl", "-c", "attach", "-t", device_type, "-i", scsi_id, "-f", image], ["rasctl", "-c", "attach", "-t", device_type, "-i", scsi_id, "-f", image],
capture_output=True, capture_output=True,
@ -105,7 +103,7 @@ def insert(scsi_id, image):
def attach_daynaport(scsi_id): def attach_daynaport(scsi_id):
return subprocess.run( return subprocess.run(
["rasctl", "-i", scsi_id, "-c", "attach", "-t", "daynaport"], ["rasctl", "-i", scsi_id, "-c", "attach", "-t", "scdp"],
capture_output=True, capture_output=True,
) )

View File

@ -75,6 +75,7 @@
</tbody> </tbody>
</table> </table>
<hr/>
<h2>Image File Management</h2> <h2>Image File Management</h2>
<table cellpadding="3" border="black"> <table cellpadding="3" border="black">
<tbody> <tbody>
@ -220,8 +221,9 @@
<option value="hdn">SCSI Hard Disk image (NEC GENUINE)</option> <option value="hdn">SCSI Hard Disk image (NEC GENUINE)</option>
<option value="hdi">SCSI Hard Disk image (Anex86 HD image)</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="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="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> </select>
<label for="size">Size(MB):</label> <label for="size">Size(MB):</label>
<input type="number" placeholder="Size(MB)" name="size"/> <input type="number" placeholder="Size(MB)" name="size"/>