mirror of
https://github.com/akuker/RASCSI.git
synced 2025-02-09 18:30:38 +00:00
SASI code removal, error handling update, bug fixes, code cleanup (#806)
Summary ov most important changes triggered by the SASI code removal: - Removed the SASI controller code - New controller management. There is a new controller base class AbstractController and a class ControllerManager managing the controller lifecycle. The lifecycle management was removed from rasci.cpp and is covered by unit tests. - New device management. The DeviceFactory manages the device lifecycle instead of rascsi.cpp. The new code is covered by unit tests. - The lifecycle managment uses C++ collections with variable size instead of arrays with hard-coded sizes. - The ScsiController method contains most of what was previously contained in scsidev_ctrl.cpp plus the code from sasidev_ctrl.cpp that was relevant for SCSI. - scsi_command_util contains helper methods used for identical SCSI command implementations of more than one device - Devices know their controllers, so that the controller instance does not need to be passed to each SCSI command. This change helps to decouple the devices from the controller. The phase_handler interface is also part of this decoupling. - Use scsi_command_exception for propagating SCSI command execution errors, This resolves issues with the previous error handling, which was based on return values and often on magic numbers. - Removed legacy SCSI error codes, all errors are now encoded by sense_key::, asc:: and status::. - Fixed various warnings reported with -Wextra, -Weffc++ and -Wpedantic. - Use constructor member initialization lists (recommended for ISO C++) - Consistently use new/delete instead of malloc/free (recommended for ISO C++), resulting in better type safety and error handling - Replaced variable sized arrays on the stack (violates ISO C++ and can cause a stack overflow) - Replaced NULL by nullptr (recommended for C++), resulting in better type safety - Use more const member functions in order to avoid side effects - The format device page can now also be changed for hard disk drives (Fujitsu M2624S supports this, for instance), not just for MOs. - Better encapsulation, updated access specifiers in many places - Removed unused methods and method arguments - Fixed a number of TODOs - Added/updated unit tests for a lot of non-legacy classes - Makefile support for creating HTML coverage reports with lcov/genhtml
This commit is contained in:
parent
2411afb2c4
commit
ddeede2beb
13
doc/rascsi.1
13
doc/rascsi.1
@ -20,12 +20,11 @@ rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins
|
||||
.B rascsi
|
||||
Emulates SCSI devices using the Raspberry Pi GPIO pins.
|
||||
.PP
|
||||
In the arguments to RaSCSI, one or more SCSI (-IDn[:u]) or SASI (-HDn[:u]) devices can be specified.
|
||||
In the arguments to RaSCSI, one or more SCSI (-IDn[:u]) devices can be specified.
|
||||
The number (n) after the ID or HD identifier specifies the ID number for that device. The optional number (u) specifies the LUN (logical unit) for that device. The default LUN is 0.
|
||||
For SCSI: The ID is limited from 0-7. However, typically SCSI ID 7 is reserved for the "initiator" (the host computer). The LUN is limited from 0-31. Note that SASI is considered rare and only used on very early Sharp X68000 computers.
|
||||
For SCSI: The ID is limited from 0-7. However, typically SCSI ID 7 is reserved for the "initiator" (the host computer). The LUN is limited from 0-31.
|
||||
.PP
|
||||
RaSCSI will determine the type of device based upon the file extension of the FILE argument.
|
||||
hdf: SASI Hard Disk image (XM6 SASI HD image - typically only used with X68000)
|
||||
hds: SCSI Hard Disk image (generic, non-removable)
|
||||
hdr: SCSI Hard Disk image (generic, removable)
|
||||
hdn: SCSI Hard Disk image (NEC GENUINE)
|
||||
@ -47,7 +46,7 @@ To quit RaSCSI, press Control + C. If it is running in the background, you can k
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-b\fI " " \fIBLOCK_SIZE
|
||||
The optional block size. For SCSI drives 512, 1024, 2048 or 4096 bytes, default size is 512 bytes. For SASI drives 256 or 1024 bytes, default is 256 bytes.
|
||||
The optional block size, either 512, 1024, 2048 or 4096 bytes. Default size is 512 bytes.
|
||||
.TP
|
||||
.BR \-F\fI " " \fIFOLDER
|
||||
The default folder for image files. For files in this folder no absolute path needs to be specified. The initial default folder is '~/images'.
|
||||
@ -85,13 +84,9 @@ Overrides the default locale for client-faces error messages. The client can ove
|
||||
n is the SCSI ID number (0-7). u (0-31) is the optional LUN (logical unit). The default LUN is 0.
|
||||
.IP
|
||||
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, SCLP, SCHS) the filename may have a special meaning or a dummy name can be provided. For SCBR and SCDP it is an optioinal prioritized list of network interfaces, an optional IP address and netmask, e.g. "interfaces=eth0,eth1,wlan0:inet=10.10.20.1/24". For SCLP it is the print command to be used and a reservation timeout in seconds, e.g. "cmd=lp -oraw %f:timeout=60".
|
||||
.TP
|
||||
.BR \-HD\fIn[:u] " " \fIFILE
|
||||
n is the SASI ID number (0-15). The effective SASI ID is calculated as n/2, the effective SASI LUN is calculated is the remainder of n/2. Alternatively the n:u syntax can be used, where ns is the SASI ID (0-7) and u the LUN (0-1).
|
||||
.IP
|
||||
FILE is the name of the image file to use for the SASI device.
|
||||
FILE is the name of the image file to use for the SCSI device.
|
||||
.IP
|
||||
Note: SASI usage is rare, and is typically limited to early Unix workstations and Sharp X68000 systems.
|
||||
|
||||
.SH EXAMPLES
|
||||
Launch RaSCSI with no emulated drives attached:
|
||||
|
@ -14,48 +14,43 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
rascsi Emulates SCSI devices using the Raspberry Pi GPIO pins.
|
||||
|
||||
In the arguments to RaSCSI, one or more SCSI (-IDn[:u]) or SASI
|
||||
(-HDn[:u]) devices can be specified. The number (n) after the ID or HD
|
||||
identifier specifies the ID number for that device. The optional number
|
||||
(u) specifies the LUN (logical unit) for that device. The default LUN
|
||||
is 0. For SCSI: The ID is limited from 0-7. However, typically SCSI ID
|
||||
7 is reserved for the "initiator" (the host computer). The LUN is lim‐
|
||||
ited from 0-31. Note that SASI is considered rare and only used on very
|
||||
early Sharp X68000 computers.
|
||||
In the arguments to RaSCSI, one or more SCSI (-IDn[:u]) devices can be
|
||||
specified. The number (n) after the ID or HD identifier specifies the
|
||||
ID number for that device. The optional number (u) specifies the LUN
|
||||
(logical unit) for that device. The default LUN is 0. For SCSI: The ID
|
||||
is limited from 0-7. However, typically SCSI ID 7 is reserved for the
|
||||
"initiator" (the host computer). The LUN is limited from 0-31.
|
||||
|
||||
RaSCSI will determine the type of device based upon the file extension
|
||||
of the FILE argument.
|
||||
hdf: SASI Hard Disk image (XM6 SASI HD image - typically only used
|
||||
with X68000)
|
||||
hds: SCSI Hard Disk image (generic, non-removable)
|
||||
hdr: SCSI Hard Disk image (generic, removable)
|
||||
hdn: SCSI Hard Disk image (NEC GENUINE)
|
||||
hdi: SCSI Hard Disk image (Anex86 HD image)
|
||||
nhd: SCSI Hard Disk image (T98Next HD image)
|
||||
hda: SCSI Hard Disk image (APPLE GENUINE - typically used with Mac
|
||||
hda: SCSI Hard Disk image (APPLE GENUINE - typically used with Mac
|
||||
SCSI emulation)
|
||||
mos: SCSI Magneto-optical image (XM6 SCSI MO image - typically only
|
||||
used with X68000)
|
||||
iso: SCSI CD-ROM image (ISO 9660 image)
|
||||
|
||||
For example, if you want to specify an Apple-compatible HD image on ID
|
||||
For example, if you want to specify an Apple-compatible HD image on ID
|
||||
0, you can use the following command:
|
||||
sudo rascsi -ID0 /path/to/drive/hdimage.hda
|
||||
|
||||
Once RaSCSI starts, it will open a socket (default port is 6868) to al‐
|
||||
low external management commands. If another process is using the
|
||||
low external management commands. If another process is using the
|
||||
rascsi port, RaSCSI will terminate, since it is likely another instance
|
||||
of RaSCSI. Once RaSCSI has initialized, the rasctl utility can be used
|
||||
to send commands.
|
||||
|
||||
To quit RaSCSI, press Control + C. If it is running in the background,
|
||||
To quit RaSCSI, press Control + C. If it is running in the background,
|
||||
you can kill it using an INT signal.
|
||||
|
||||
OPTIONS
|
||||
-b BLOCK_SIZE
|
||||
The optional block size. For SCSI drives 512, 1024, 2048 or 4096
|
||||
bytes, default size is 512 bytes. For SASI drives 256 or 1024
|
||||
bytes, default is 256 bytes.
|
||||
The optional block size, either 512, 1024, 2048 or 4096 bytes.
|
||||
Default size is 512 bytes.
|
||||
|
||||
-F FOLDER
|
||||
The default folder for image files. For files in this folder no
|
||||
@ -117,16 +112,7 @@ OPTIONS
|
||||
For SCLP it is the print command to be used and a reservation
|
||||
timeout in seconds, e.g. "cmd=lp -oraw %f:timeout=60".
|
||||
|
||||
-HDn[:u] FILE
|
||||
n is the SASI ID number (0-15). The effective SASI ID is calcu‐
|
||||
lated as n/2, the effective SASI LUN is calculated is the re‐
|
||||
mainder of n/2. Alternatively the n:u syntax can be used, where
|
||||
ns is the SASI ID (0-7) and u the LUN (0-1).
|
||||
|
||||
FILE is the name of the image file to use for the SASI device.
|
||||
|
||||
Note: SASI usage is rare, and is typically limited to early Unix
|
||||
workstations and Sharp X68000 systems.
|
||||
FILE is the name of the image file to use for the SCSI device.
|
||||
|
||||
EXAMPLES
|
||||
Launch RaSCSI with no emulated drives attached:
|
||||
|
@ -136,7 +136,7 @@ Command is the operation being requested. Options are:
|
||||
eject, protect and unprotect are idempotent.
|
||||
.TP
|
||||
.BR \-b\fI " " \fIBLOCK_SIZE
|
||||
The optional block size. For SCSI drives 512, 1024, 2048 or 4096 bytes, default size is 512 bytes. For SASI drives 256 or 1024 bytes, default is 256 bytes.
|
||||
The optional block size, either 512, 1024, 2048 or 4096 bytes. The default size is 512 bytes.
|
||||
.TP
|
||||
.BR \-f\fI " " \fIFILE|PARAM
|
||||
Device-specific: Either a path to a disk image file, or a parameter for a non-disk device. See the rascsi(1) man page for permitted file types.
|
||||
|
@ -110,19 +110,18 @@ OPTIONS
|
||||
eject, protect and unprotect are idempotent.
|
||||
|
||||
-b BLOCK_SIZE
|
||||
The optional block size. For SCSI drives 512, 1024, 2048 or 4096
|
||||
bytes, default size is 512 bytes. For SASI drives 256 or 1024
|
||||
bytes, default is 256 bytes.
|
||||
The optional block size, either 512, 1024, 2048 or 4096 bytes.
|
||||
The default size is 512 bytes.
|
||||
|
||||
-f FILE|PARAM
|
||||
Device-specific: Either a path to a disk image file, or a param‐
|
||||
eter for a non-disk device. See the rascsi(1) man page for per‐
|
||||
eter for a non-disk device. See the rascsi(1) man page for per‐
|
||||
mitted file types.
|
||||
|
||||
-t TYPE
|
||||
Specifies the device type. This type overrides the type derived
|
||||
Specifies the device type. This type overrides the type derived
|
||||
from the file extension of the specified image. See the
|
||||
rascsi(1) man page for the available device types. For some
|
||||
rascsi(1) man page for the available device types. For some
|
||||
types there are shortcuts (only the first letter is required):
|
||||
hd: SCSI hard disk drive
|
||||
rm: SCSI removable media drive
|
||||
@ -134,16 +133,16 @@ OPTIONS
|
||||
services: Host services device
|
||||
|
||||
-n VENDOR:PRODUCT:REVISION
|
||||
The vendor, product and revision for the device, to be returned
|
||||
The vendor, product and revision for the device, to be returned
|
||||
with the INQUIRY data. A complete set of name components must be
|
||||
provided. VENDOR may have up to 8, PRODUCT up to 16, REVISION up
|
||||
to 4 characters. Padding with blanks to the maxium length is au‐
|
||||
tomatically applied. Once set the name of a device cannot be
|
||||
tomatically applied. Once set the name of a device cannot be
|
||||
changed.
|
||||
|
||||
-u UNIT
|
||||
Unit number (0-31). This will default to 0. This option is only
|
||||
used when there are multiple SCSI devices on a shared SCSI con‐
|
||||
Unit number (0-31). This will default to 0. This option is only
|
||||
used when there are multiple SCSI devices on a shared SCSI con‐
|
||||
troller. (This is not common)
|
||||
|
||||
EXAMPLES
|
||||
|
@ -1,41 +0,0 @@
|
||||
.TH sasidump 1
|
||||
.SH NAME
|
||||
sasidump \- SASI disk dumping tool for RaSCSI
|
||||
.SH SYNOPSIS
|
||||
.B sasidump
|
||||
\fB\-i\fR \fIID\fR
|
||||
[\fB\-u\fR \fIUT\fR]
|
||||
[\fB\-b\fR \fIBSIZE\fR]
|
||||
\fB\-c\fR \fICOUNT\fR
|
||||
\fB\-f\fR \fIFILE\fR
|
||||
[\fB\-r\fR]
|
||||
.SH DESCRIPTION
|
||||
.B sasidump
|
||||
Samples the data on physical SASI storage media, and stores it to an image file. It can also restore from a dumped file onto physical SASI storage media.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-i\fI " "\fIID
|
||||
SASI ID of the target device
|
||||
.TP
|
||||
.BR \-u\fI " "\fIUD
|
||||
Unit ID of the target device
|
||||
.TP
|
||||
.BR \-b\fI " "\fIBSIZE
|
||||
Block size (default is 512)
|
||||
.TP
|
||||
.BR \-c\fI " "\fICOUNT
|
||||
Block count
|
||||
.TP
|
||||
.BR \-f\fI " "\fIFILE
|
||||
Path to the dump file
|
||||
.TP
|
||||
.BR \-r\fI
|
||||
Restoration mode
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
.SH SEE ALSO
|
||||
rasctl(1), rascsi(1), scsimon(1), rasdump(1)
|
||||
|
||||
Full documentation is available at: <https://www.github.com/akuker/RASCSI/wiki/>
|
@ -54,9 +54,7 @@ class RaCtlCmds:
|
||||
scmo = []
|
||||
sccd = []
|
||||
for dtype in mappings:
|
||||
if mappings[dtype] == proto.PbDeviceType.SAHD:
|
||||
sahd.append(dtype)
|
||||
elif mappings[dtype] == proto.PbDeviceType.SCHD:
|
||||
if mappings[dtype] == proto.PbDeviceType.SCHD:
|
||||
schd.append(dtype)
|
||||
elif mappings[dtype] == proto.PbDeviceType.SCRM:
|
||||
scrm.append(dtype)
|
||||
@ -73,7 +71,6 @@ class RaCtlCmds:
|
||||
"reserved_ids": reserved_ids,
|
||||
"image_dir": image_dir,
|
||||
"scan_depth": scan_depth,
|
||||
"sahd": sahd,
|
||||
"schd": schd,
|
||||
"scrm": scrm,
|
||||
"scmo": scmo,
|
||||
|
@ -543,9 +543,10 @@
|
||||
{{ _("Create Empty Disk Image File") }}
|
||||
</summary>
|
||||
<ul>
|
||||
<li>{{ _("The Generic image type is recommended for most computer platforms.") }}</li>
|
||||
<li>{{ _("APPLE GENUINE (.hda) and NEC GENUINE (.hdn) image types will make RaSCSI behave as a particular drive type that are recognized by Mac and PC98 systems, respectively.") }}</li>
|
||||
<li>{{ _("SASI images should only be used on the original Sharp X68000, or other legacy systems that utilize this pre-SCSI standard.") }}</li>
|
||||
<li>{{ _("The Generic Hard Disk image type is recommended for most computer platforms.") }}</li>
|
||||
<li>{{ _("APPLE GENUINE is appropriate for Apple Macintosh computers.") }}</li>
|
||||
<li>{{ _("NEC GENUINE is appropriate for NEC PC-98 computers.") }}</li>
|
||||
<li>{{ _("The Generic Removable Disk image type can be used with SCSI floppy drives, SyQuest drives, Zip drives etc.") }}</li>
|
||||
</ul>
|
||||
</details>
|
||||
<table style="border: none">
|
||||
@ -566,10 +567,7 @@
|
||||
{{ _("SCSI Hard Disk image (NEC GENUINE) [.hdn]") }}
|
||||
</option>
|
||||
<option value="hdr">
|
||||
{{ _("SCSI Removable Media Disk image (Generic) [.hdr]") }}
|
||||
</option>
|
||||
<option value="hdf">
|
||||
{{ _("SASI Hard Disk image (Legacy) [.hdf]") }}
|
||||
{{ _("SCSI Removable Disk image (Generic) [.hdr]") }}
|
||||
</option>
|
||||
</select>
|
||||
<label for="size">{{ _("Size:") }}</label>
|
||||
|
@ -80,14 +80,12 @@ def get_device_name(device_type):
|
||||
Takes a four letter device acronym (str) device_type.
|
||||
Returns the human-readable name for the device type.
|
||||
"""
|
||||
if device_type == "SAHD":
|
||||
return _("SASI Hard Disk")
|
||||
if device_type == "SCHD":
|
||||
return _("SCSI Hard Disk")
|
||||
return _("Hard Disk")
|
||||
if device_type == "SCRM":
|
||||
return _("Removable Disk")
|
||||
if device_type == "SCMO":
|
||||
return _("Magneto-Optical")
|
||||
return _("Magneto-Optical Disk")
|
||||
if device_type == "SCCD":
|
||||
return _("CD / DVD")
|
||||
if device_type == "SCBR":
|
||||
|
8
src/raspberrypi/.gitignore
vendored
8
src/raspberrypi/.gitignore
vendored
@ -7,14 +7,10 @@
|
||||
*.vcd
|
||||
*.json
|
||||
*.html
|
||||
rascsi
|
||||
scsimon
|
||||
rasctl
|
||||
sasidump
|
||||
rasdump
|
||||
scisparse
|
||||
rascsi.dat
|
||||
obj
|
||||
bin
|
||||
coverage
|
||||
/rascsi_interface.pb.cpp
|
||||
/rascsi_interface.pb.h
|
||||
.project
|
||||
|
@ -1,5 +1,8 @@
|
||||
.DEFAULT_GOAL: all
|
||||
|
||||
# Depending on the GCC version the compilation flags differ
|
||||
GCCVERSION10 := $(shell expr `gcc -dumpversion` \>= 10)
|
||||
|
||||
## Optional build flags:
|
||||
## CROSS_COMPILE : Specify which compiler toolchain to use.
|
||||
## To cross compile set this accordingly, e.g. to:
|
||||
@ -14,14 +17,12 @@ CXX = $(CROSS_COMPILE)g++
|
||||
## this is only used by developers.
|
||||
DEBUG ?= 0
|
||||
ifeq ($(DEBUG), 1)
|
||||
# Debug CFLAGS
|
||||
CFLAGS += -O0 -g -Wall -DDEBUG
|
||||
CXXFLAGS += -O0 -g -Wall -DDEBUG
|
||||
# Debug compiler flags
|
||||
CXXFLAGS += -O0 -g -Wall -Wextra -DDEBUG
|
||||
BUILD_TYPE = Debug
|
||||
else
|
||||
# Release CFLAGS
|
||||
CFLAGS += -O3 -Wall -Werror -DNDEBUG
|
||||
CXXFLAGS += -O3 -Wall -Werror -DNDEBUG
|
||||
# Release compiler flags, ignore unused parameters because they are reported for some assertions
|
||||
CXXFLAGS += -O3 -Wall -Werror -Wextra -Wno-unused-parameter -DNDEBUG
|
||||
BUILD_TYPE = Release
|
||||
endif
|
||||
ifeq ("$(shell uname -s)","Linux")
|
||||
@ -29,23 +30,17 @@ ifeq ("$(shell uname -s)","Linux")
|
||||
CXXFLAGS += -Wno-psabi
|
||||
endif
|
||||
|
||||
CFLAGS += -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP
|
||||
|
||||
CXXFLAGS += -std=c++17 -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP
|
||||
|
||||
## EXTRA_FLAGS : Can be used to pass special purpose flags
|
||||
CFLAGS += $(EXTRA_FLAGS)
|
||||
CXXFLAGS += $(EXTRA_FLAGS)
|
||||
|
||||
# If we're using GCC version 10 or later, we need to add the FMT_HEADER_ONLY definition
|
||||
GCCVERSION10 := $(shell expr `gcc -dumpversion` \>= 10)
|
||||
|
||||
ifeq "$(GCCVERSION10)" "1"
|
||||
CFLAGS += -DFMT_HEADER_ONLY
|
||||
CXXFLAGS += -DFMT_HEADER_ONLY
|
||||
endif
|
||||
|
||||
|
||||
|
||||
## CONNECT_TYPE=FULLSPEC : Specify the type of RaSCSI board type
|
||||
## that you are using. The typical options are
|
||||
## STANDARD or FULLSPEC. The default is FULLSPEC
|
||||
@ -55,14 +50,12 @@ endif
|
||||
CONNECT_TYPE ?= FULLSPEC
|
||||
|
||||
ifdef CONNECT_TYPE
|
||||
CFLAGS += -DCONNECT_TYPE_$(CONNECT_TYPE)
|
||||
CXXFLAGS += -DCONNECT_TYPE_$(CONNECT_TYPE)
|
||||
endif
|
||||
|
||||
RASCSI = rascsi
|
||||
RASCTL = rasctl
|
||||
RASDUMP = rasdump
|
||||
SASIDUMP = sasidump
|
||||
SCSIMON = scsimon
|
||||
RASCSI_TEST = rascsi_test
|
||||
|
||||
@ -73,6 +66,8 @@ RSYSLOG_LOG = /var/log/rascsi.log
|
||||
USR_LOCAL_BIN = /usr/local/bin
|
||||
MAN_PAGE_DIR = /usr/local/man/man1
|
||||
DOC_DIR = ../../doc
|
||||
COVERAGE_DIR = ./coverage
|
||||
COVERAGE_FILE = rascsi.dat
|
||||
OS_FILES = ./os_integration
|
||||
|
||||
OBJDIR := ./obj/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
|
||||
@ -82,8 +77,7 @@ BIN_ALL = \
|
||||
$(BINDIR)/$(RASCSI) \
|
||||
$(BINDIR)/$(RASCTL) \
|
||||
$(BINDIR)/$(SCSIMON) \
|
||||
$(BINDIR)/$(RASDUMP) \
|
||||
$(BINDIR)/$(SASIDUMP)
|
||||
$(BINDIR)/$(RASDUMP)
|
||||
|
||||
SRC_PROTOC = \
|
||||
rascsi_interface.proto
|
||||
@ -91,7 +85,8 @@ SRC_PROTOC = \
|
||||
SRC_PROTOBUF = \
|
||||
rascsi_interface.pb.cpp
|
||||
|
||||
SRC_RASCSI_CORE = scsi.cpp \
|
||||
SRC_RASCSI_CORE = \
|
||||
scsi.cpp \
|
||||
gpiobus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
@ -106,7 +101,6 @@ SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(SRC_PROTOBUF)
|
||||
|
||||
SRC_RASCSI = rascsi.cpp
|
||||
SRC_RASCSI += $(SRC_RASCSI_CORE)
|
||||
|
||||
SRC_SCSIMON = \
|
||||
scsimon.cpp \
|
||||
@ -133,17 +127,8 @@ SRC_RASDUMP = \
|
||||
fileio.cpp \
|
||||
rascsi_version.cpp
|
||||
|
||||
SRC_SASIDUMP = \
|
||||
sasidump.cpp \
|
||||
scsi.cpp \
|
||||
gpiobus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
rascsi_version.cpp
|
||||
|
||||
|
||||
SRC_RASCSI_TEST = $(shell find ./test -name '*.cpp')
|
||||
SRC_RASCSI_TEST += $(SRC_RASCSI_CORE)
|
||||
|
||||
|
||||
vpath %.h ./ ./controllers ./devices ./monitor
|
||||
@ -152,10 +137,10 @@ vpath %.o ./$(OBJDIR)
|
||||
vpath ./$(BINDIR)
|
||||
|
||||
|
||||
OBJ_RASCSI_CORE := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_CORE:%.cpp=%.o)))
|
||||
OBJ_RASCSI := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI:%.cpp=%.o)))
|
||||
OBJ_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
|
||||
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
|
||||
OBJ_SASIDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SASIDUMP:%.cpp=%.o)))
|
||||
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
|
||||
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.cpp=%.o)))
|
||||
|
||||
@ -164,7 +149,7 @@ GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
|
||||
|
||||
# The following will include all of the auto-generated dependency files (*.d)
|
||||
# if they exist. This will trigger a rebuild of a source file if a header changes
|
||||
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON) $(OBJ_RASCSI_TEST))
|
||||
ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON) $(OBJ_RASCSI_TEST))
|
||||
-include $(ALL_DEPS)
|
||||
|
||||
$(OBJDIR) $(BINDIR):
|
||||
@ -183,18 +168,26 @@ $(SRC_PROTOBUF): $(SRC_PROTOC)
|
||||
## all : Rebuild all of the executable files and re-generate
|
||||
## the text versions of the manpages
|
||||
## docs : Re-generate the text versions of the man pages
|
||||
## test : Build and run unit tests
|
||||
## coverage : Build and run unit tests and create coverage HTML files.
|
||||
## Note that you have to run 'make clean' before switching
|
||||
## between coverage and no-coverage builds.
|
||||
.DEFAULT_GOAL := all
|
||||
.PHONY: all ALL docs
|
||||
.PHONY: all ALL docs test coverage
|
||||
all: $(BIN_ALL) docs
|
||||
ALL: all
|
||||
|
||||
test: $(BINDIR)/$(RASCSI_TEST)
|
||||
$(BINDIR)/$(RASCSI_TEST)
|
||||
|
||||
coverage: CXXFLAGS += --coverage
|
||||
coverage: test
|
||||
lcov -q -c -d . --include '*/raspberrypi/*' -o $(COVERAGE_FILE) --exclude '*/test/*' --exclude '*/interfaces/*' --exclude '*/rascsi_interface.pb*'
|
||||
genhtml -q -o $(COVERAGE_DIR) --legend $(COVERAGE_FILE)
|
||||
|
||||
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
|
||||
|
||||
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lpcap -lprotobuf -lstdc++fs
|
||||
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) -lpthread -lpcap -lprotobuf -lstdc++fs
|
||||
|
||||
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lpthread -lprotobuf -lstdc++fs
|
||||
@ -202,22 +195,18 @@ $(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
|
||||
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
|
||||
|
||||
$(BINDIR)/$(SASIDUMP): $(OBJ_SASIDUMP) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SASIDUMP)
|
||||
|
||||
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
|
||||
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_TEST) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_TEST) -lpcap -lprotobuf -lgmock -lgtest -lgtest_main
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
|
||||
|
||||
# Phony rules for building individual utilities
|
||||
.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP) $(SCSIMON)
|
||||
.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SCSIMON)
|
||||
$(RASCSI) : $(BINDIR)/$(RASCSI)
|
||||
$(RASCTL) : $(BINDIR)/$(RASCTL)
|
||||
$(RASDUMP) : $(BINDIR)/$(RASDUMP)
|
||||
$(SASIDUMP): $(BINDIR)/$(SASIDUMP)
|
||||
$(SCSIMON) : $(BINDIR)/$(SCSIMON)
|
||||
|
||||
|
||||
@ -225,7 +214,7 @@ $(SCSIMON) : $(BINDIR)/$(SCSIMON)
|
||||
## compiler files and executable files
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(BINDIR) $(GEN_PROTOBUF)
|
||||
rm -rf $(OBJDIR) $(BINDIR) $(GEN_PROTOBUF) $(COVERAGE_DIR) $(COVERAGE_FILE)
|
||||
|
||||
## install : Copies all of the man pages to the correct location
|
||||
## Copies the binaries to a global install location
|
||||
@ -245,12 +234,10 @@ install: \
|
||||
$(MAN_PAGE_DIR)/rasctl.1 \
|
||||
$(MAN_PAGE_DIR)/scsimon.1 \
|
||||
$(MAN_PAGE_DIR)/rasdump.1 \
|
||||
$(MAN_PAGE_DIR)/sasidump.1 \
|
||||
$(USR_LOCAL_BIN)/$(RASCTL) \
|
||||
$(USR_LOCAL_BIN)/$(RASCSI) \
|
||||
$(USR_LOCAL_BIN)/$(SCSIMON) \
|
||||
$(USR_LOCAL_BIN)/$(RASDUMP) \
|
||||
$(USR_LOCAL_BIN)/$(SASIDUMP) \
|
||||
$(SYSTEMD_CONF) \
|
||||
$(RSYSLOG_CONF) \
|
||||
$(RSYSLOG_LOG)
|
||||
|
@ -12,6 +12,6 @@
|
||||
#include <string>
|
||||
|
||||
struct CommandContext {
|
||||
int fd;
|
||||
std::string locale;
|
||||
int fd = -1;
|
||||
std::string locale = "";
|
||||
};
|
||||
|
@ -18,9 +18,8 @@
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#define USE_SEL_EVENT_ENABLE // Check SEL signal by event
|
||||
#define REMOVE_FIXED_SASIHD_SIZE // remove the size limitation of SASIHD
|
||||
// This avoids an indefinite loop with warnings if there is no RaSCSI hardware
|
||||
// and thus helps with running certain tests on X86 hardware.
|
||||
#if defined(__x86_64__) || defined(__X86__)
|
||||
#if defined(__x86_64) || defined(__X86)
|
||||
#undef USE_SEL_EVENT_ENABLE
|
||||
#endif
|
||||
|
59
src/raspberrypi/controllers/abstract_controller.cpp
Normal file
59
src/raspberrypi/controllers/abstract_controller.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "abstract_controller.h"
|
||||
#include "devices/primary_device.h"
|
||||
|
||||
PrimaryDevice *AbstractController::GetDeviceForLun(int lun) const {
|
||||
const auto& it = ctrl.luns.find(lun);
|
||||
return it == ctrl.luns.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
bool AbstractController::AddDevice(PrimaryDevice *device)
|
||||
{
|
||||
if (HasDeviceForLun(device->GetLun())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl.luns[device->GetLun()] = device;
|
||||
device->SetController(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractController::DeleteDevice(const PrimaryDevice *device)
|
||||
{
|
||||
return ctrl.luns.erase(device->GetLun()) == 1;
|
||||
}
|
||||
|
||||
bool AbstractController::HasDeviceForLun(int lun) const
|
||||
{
|
||||
return ctrl.luns.find(lun) != ctrl.luns.end();
|
||||
}
|
||||
|
||||
int AbstractController::ExtractInitiatorId(int id_data)
|
||||
{
|
||||
int initiator_id = -1;
|
||||
|
||||
int tmp = id_data - (1 << target_id);
|
||||
if (tmp) {
|
||||
initiator_id = 0;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
tmp >>= 1;
|
||||
if (tmp) {
|
||||
initiator_id++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initiator_id;
|
||||
}
|
97
src/raspberrypi/controllers/abstract_controller.h
Normal file
97
src/raspberrypi/controllers/abstract_controller.h
Normal file
@ -0,0 +1,97 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
// Base class for device controllers
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "phase_handler.h"
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PrimaryDevice;
|
||||
|
||||
class AbstractController : virtual public PhaseHandler
|
||||
{
|
||||
public:
|
||||
|
||||
// Maximum number of logical units
|
||||
static const int LUN_MAX = 32;
|
||||
|
||||
enum rascsi_shutdown_mode {
|
||||
NONE,
|
||||
STOP_RASCSI,
|
||||
STOP_PI,
|
||||
RESTART_PI
|
||||
};
|
||||
|
||||
// Internal data definition
|
||||
// TODO Some of these data are probably device specific, and in this case they should be moved.
|
||||
// These data are not internal, otherwise they could all be private
|
||||
typedef struct _ctrl_t {
|
||||
// General
|
||||
BUS::phase_t phase = BUS::busfree; // Transition phase
|
||||
|
||||
// commands
|
||||
DWORD cmd[16]; // Command data
|
||||
DWORD status; // Status data
|
||||
int message; // Message data
|
||||
|
||||
// Transfer
|
||||
// TODO Try to get rid of the static buffer
|
||||
BYTE *buffer; // Transfer data buffer
|
||||
int bufsize; // Transfer data buffer size
|
||||
uint32_t blocks; // Number of transfer blocks
|
||||
uint64_t next; // Next record
|
||||
uint32_t offset; // Transfer offset
|
||||
uint32_t length; // Transfer remaining length
|
||||
|
||||
// Logical units of this device controller mapped to their LUN numbers
|
||||
unordered_map<int, PrimaryDevice *> luns;
|
||||
} ctrl_t;
|
||||
|
||||
AbstractController(BUS *bus, int target_id) : bus(bus), target_id(target_id) {}
|
||||
virtual ~AbstractController() {}
|
||||
|
||||
virtual BUS::phase_t Process(int) = 0;
|
||||
|
||||
virtual void Error(scsi_defs::sense_key, scsi_defs::asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status = scsi_defs::status::CHECK_CONDITION) = 0;
|
||||
virtual void Reset() = 0;
|
||||
virtual int GetInitiatorId() const = 0;
|
||||
virtual void SetByteTransfer(bool) = 0;
|
||||
|
||||
// Get requested LUN based on IDENTIFY message, with LUN from the CDB as fallback
|
||||
virtual int GetEffectiveLun() const = 0;
|
||||
|
||||
virtual int GetMaxLuns() const = 0;
|
||||
|
||||
virtual void ScheduleShutdown(rascsi_shutdown_mode) = 0;
|
||||
|
||||
int GetTargetId() const { return target_id; }
|
||||
|
||||
PrimaryDevice *GetDeviceForLun(int) const;
|
||||
bool AddDevice(PrimaryDevice *);
|
||||
bool DeleteDevice(const PrimaryDevice *);
|
||||
bool HasDeviceForLun(int) const;
|
||||
int ExtractInitiatorId(int id_data);
|
||||
|
||||
// TODO Do not expose internal data
|
||||
ctrl_t* GetCtrl() { return &ctrl; }
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
BUS *bus;
|
||||
|
||||
int target_id;
|
||||
|
||||
ctrl_t ctrl = {};
|
||||
};
|
87
src/raspberrypi/controllers/controller_manager.cpp
Normal file
87
src/raspberrypi/controllers/controller_manager.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "devices/device_factory.h"
|
||||
#include "devices/primary_device.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "scsi_controller.h"
|
||||
#include "controller_manager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
unordered_map<int, AbstractController *> ControllerManager::controllers;
|
||||
|
||||
ControllerManager::~ControllerManager()
|
||||
{
|
||||
DeleteAllControllersAndDevices();
|
||||
}
|
||||
|
||||
ControllerManager& ControllerManager::instance()
|
||||
{
|
||||
static ControllerManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool ControllerManager::CreateScsiController(BUS *bus, PrimaryDevice *device)
|
||||
{
|
||||
AbstractController *controller = FindController(device->GetId());
|
||||
if (controller == nullptr) {
|
||||
controller = new ScsiController(bus, device->GetId());
|
||||
controllers[device->GetId()] = controller;
|
||||
}
|
||||
|
||||
return controller->AddDevice(device);
|
||||
}
|
||||
|
||||
AbstractController *ControllerManager::IdentifyController(int data) const
|
||||
{
|
||||
for (const auto& controller : controllers) {
|
||||
if (data & (1 << controller.second->GetTargetId())) {
|
||||
return controller.second;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AbstractController *ControllerManager::FindController(int target_id) const
|
||||
{
|
||||
const auto& it = controllers.find(target_id);
|
||||
return it == controllers.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
void ControllerManager::DeleteAllControllersAndDevices()
|
||||
{
|
||||
for (const auto& controller : controllers) {
|
||||
delete controller.second;
|
||||
}
|
||||
|
||||
controllers.clear();
|
||||
|
||||
DeviceFactory::instance().DeleteAllDevices();
|
||||
|
||||
FileSupport::UnreserveAll();
|
||||
}
|
||||
|
||||
void ControllerManager::ResetAllControllers()
|
||||
{
|
||||
for (const auto& controller : controllers) {
|
||||
controller.second->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryDevice *ControllerManager::GetDeviceByIdAndLun(int id, int lun) const
|
||||
{
|
||||
const AbstractController *controller = FindController(id);
|
||||
if (controller != nullptr) {
|
||||
return controller->GetDeviceForLun(lun);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
39
src/raspberrypi/controllers/controller_manager.h
Normal file
39
src/raspberrypi/controllers/controller_manager.h
Normal file
@ -0,0 +1,39 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
// Keeps track of and manages the controllers
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
class BUS;
|
||||
class AbstractController;
|
||||
class PrimaryDevice;
|
||||
|
||||
class ControllerManager
|
||||
{
|
||||
ControllerManager() {}
|
||||
~ControllerManager();
|
||||
|
||||
public:
|
||||
// Maximum number of controller devices
|
||||
static const int DEVICE_MAX = 8;
|
||||
|
||||
static ControllerManager& instance();
|
||||
|
||||
bool CreateScsiController(BUS *, PrimaryDevice *);
|
||||
AbstractController *IdentifyController(int) const;
|
||||
AbstractController *FindController(int) const;
|
||||
void DeleteAllControllersAndDevices();
|
||||
void ResetAllControllers();
|
||||
PrimaryDevice *GetDeviceByIdAndLun(int, int) const;
|
||||
|
||||
static std::unordered_map<int, AbstractController *> controllers;
|
||||
};
|
33
src/raspberrypi/controllers/phase_handler.h
Normal file
33
src/raspberrypi/controllers/phase_handler.h
Normal file
@ -0,0 +1,33 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
// An interface with methods for switching bus phases
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scsi.h"
|
||||
|
||||
class PhaseHandler
|
||||
{
|
||||
public:
|
||||
|
||||
PhaseHandler() {}
|
||||
virtual ~PhaseHandler() {}
|
||||
|
||||
virtual void SetPhase(BUS::phase_t) = 0;
|
||||
virtual void BusFree() = 0;
|
||||
virtual void Selection() = 0;
|
||||
virtual void Command() = 0;
|
||||
virtual void Status() = 0;
|
||||
virtual void DataIn() = 0;
|
||||
virtual void DataOut() = 0;
|
||||
virtual void MsgIn() = 0;
|
||||
virtual void MsgOut() = 0;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,171 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(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.
|
||||
//
|
||||
// [ SASI device controller ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
#include "os.h"
|
||||
#include "scsi.h"
|
||||
#include "fileio.h"
|
||||
|
||||
class PrimaryDevice;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// SASI Controller
|
||||
//
|
||||
//===========================================================================
|
||||
class SASIDEV
|
||||
{
|
||||
protected:
|
||||
|
||||
private:
|
||||
enum sasi_command : int {
|
||||
eCmdTestUnitReady = 0x00,
|
||||
eCmdRezero = 0x01,
|
||||
eCmdRequestSense = 0x03,
|
||||
eCmdFormat = 0x04,
|
||||
eCmdReadCapacity = 0x05,
|
||||
eCmdFormatLegacy = 0x06,
|
||||
eCmdReassign = 0x07,
|
||||
eCmdRead6 = 0x08,
|
||||
eCmdWrite6 = 0x0A,
|
||||
eCmdSeek6 = 0x0B,
|
||||
eCmdSetMcastAddr = 0x0D, // DaynaPort specific command
|
||||
eCmdInquiry = 0x12,
|
||||
eCmdModeSelect6 = 0x15,
|
||||
eCmdReserve6 = 0x16,
|
||||
eCmdRelease6 = 0x17,
|
||||
eCmdRead10 = 0x28,
|
||||
eCmdWrite10 = 0x2A,
|
||||
eCmdVerify10 = 0x2E,
|
||||
eCmdVerify = 0x2F,
|
||||
eCmdModeSelect10 = 0x55,
|
||||
eCmdRead16 = 0x88,
|
||||
eCmdWrite16 = 0x8A,
|
||||
eCmdVerify16 = 0x8F,
|
||||
eCmdWriteLong10 = 0x3F,
|
||||
eCmdWriteLong16 = 0x9F,
|
||||
eCmdInvalid = 0xC2,
|
||||
eCmdSasiCmdAssign = 0x0E
|
||||
};
|
||||
|
||||
public:
|
||||
enum {
|
||||
UnitMax = 32 // Maximum number of logical units
|
||||
};
|
||||
|
||||
const int UNKNOWN_SCSI_ID = -1;
|
||||
const int DEFAULT_BUFFER_SIZE = 0x1000;
|
||||
// TODO Remove this duplicate
|
||||
const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
|
||||
|
||||
// For timing adjustments
|
||||
enum {
|
||||
min_exec_time_sasi = 100, // SASI BOOT/FORMAT 30:NG 35:OK
|
||||
min_exec_time_scsi = 50
|
||||
};
|
||||
|
||||
// Internal data definition
|
||||
typedef struct {
|
||||
// General
|
||||
BUS::phase_t phase; // Transition phase
|
||||
int m_scsi_id; // Controller ID (0-7)
|
||||
BUS *bus; // Bus
|
||||
|
||||
// commands
|
||||
DWORD cmd[16]; // Command data
|
||||
DWORD status; // Status data
|
||||
DWORD message; // Message data
|
||||
|
||||
// Run
|
||||
DWORD execstart; // Execution start time
|
||||
|
||||
// Transfer
|
||||
BYTE *buffer; // Transfer data buffer
|
||||
int bufsize; // Transfer data buffer size
|
||||
uint32_t blocks; // Number of transfer block
|
||||
DWORD next; // Next record
|
||||
DWORD offset; // Transfer offset
|
||||
DWORD length; // Transfer remaining length
|
||||
|
||||
// Logical units
|
||||
PrimaryDevice *unit[UnitMax];
|
||||
|
||||
// The current device
|
||||
PrimaryDevice *device;
|
||||
|
||||
// The LUN from the IDENTIFY message
|
||||
int lun;
|
||||
} ctrl_t;
|
||||
|
||||
public:
|
||||
// Basic Functions
|
||||
SASIDEV();
|
||||
virtual ~SASIDEV(); // Destructor
|
||||
virtual void Reset(); // Device Reset
|
||||
|
||||
// External API
|
||||
virtual BUS::phase_t Process(int); // Run
|
||||
|
||||
// Connect
|
||||
void Connect(int id, BUS *sbus); // Controller connection
|
||||
PrimaryDevice* GetUnit(int no); // Get logical unit
|
||||
void SetUnit(int no, PrimaryDevice *dev); // Logical unit setting
|
||||
bool HasUnit(); // Has a valid logical unit
|
||||
|
||||
// Other
|
||||
BUS::phase_t GetPhase() {return ctrl.phase;} // Get the phase
|
||||
|
||||
int GetSCSIID() {return ctrl.m_scsi_id;} // Get the ID
|
||||
ctrl_t* GetCtrl() { return &ctrl; } // Get the internal information address
|
||||
virtual bool IsSASI() const { return true; } // SASI Check
|
||||
virtual bool IsSCSI() const { return false; } // SCSI check
|
||||
|
||||
public:
|
||||
void DataIn(); // Data in phase
|
||||
void Status(); // Status phase
|
||||
void MsgIn(); // Message in phase
|
||||
void DataOut(); // Data out phase
|
||||
|
||||
virtual int GetEffectiveLun() const;
|
||||
|
||||
virtual void Error(scsi_defs::sense_key sense_key = scsi_defs::sense_key::NO_SENSE,
|
||||
scsi_defs::asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status = scsi_defs::status::CHECK_CONDITION); // Common error handling
|
||||
|
||||
protected:
|
||||
// Phase processing
|
||||
virtual void BusFree(); // Bus free phase
|
||||
virtual void Selection(); // Selection phase
|
||||
virtual void Command(); // Command phase
|
||||
virtual void Execute(); // Execution phase
|
||||
|
||||
// Commands
|
||||
void CmdAssign(); // ASSIGN command
|
||||
void CmdSpecify(); // SPECIFY command
|
||||
|
||||
// Data transfer
|
||||
virtual void Send(); // Send data
|
||||
virtual void Receive(); // Receive data
|
||||
|
||||
bool XferIn(BYTE* buf); // Data transfer IN
|
||||
virtual bool XferOut(bool cont); // Data transfer OUT
|
||||
|
||||
// Special operations
|
||||
void FlushUnit(); // Flush the logical unit
|
||||
|
||||
ctrl_t ctrl; // Internal data
|
||||
};
|
1231
src/raspberrypi/controllers/scsi_controller.cpp
Normal file
1231
src/raspberrypi/controllers/scsi_controller.cpp
Normal file
File diff suppressed because it is too large
Load Diff
135
src/raspberrypi/controllers/scsi_controller.h
Normal file
135
src/raspberrypi/controllers/scsi_controller.h
Normal file
@ -0,0 +1,135 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(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 device controller ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "abstract_controller.h"
|
||||
#include "os.h"
|
||||
#include "scsi.h"
|
||||
|
||||
class PrimaryDevice;
|
||||
|
||||
class ScsiController : public AbstractController
|
||||
{
|
||||
// For timing adjustments
|
||||
static const unsigned int MIN_EXEC_TIME = 50;
|
||||
|
||||
// Transfer period factor (limited to 50 x 4 = 200ns)
|
||||
static const int MAX_SYNC_PERIOD = 50;
|
||||
|
||||
// REQ/ACK offset(limited to 16)
|
||||
static const int MAX_SYNC_OFFSET = 16;
|
||||
|
||||
static const int UNKNOWN_INITIATOR_ID = -1;
|
||||
|
||||
const int DEFAULT_BUFFER_SIZE = 0x1000;
|
||||
|
||||
enum rw_command : int {
|
||||
eCmdRead6 = 0x08,
|
||||
eCmdWrite6 = 0x0A,
|
||||
eCmdSetMcastAddr = 0x0D, // DaynaPort specific command
|
||||
eCmdModeSelect6 = 0x15,
|
||||
eCmdRead10 = 0x28,
|
||||
eCmdWrite10 = 0x2A,
|
||||
eCmdVerify10 = 0x2E,
|
||||
eCmdVerify = 0x2F,
|
||||
eCmdModeSelect10 = 0x55,
|
||||
eCmdRead16 = 0x88,
|
||||
eCmdWrite16 = 0x8A,
|
||||
eCmdVerify16 = 0x8F,
|
||||
eCmdWriteLong10 = 0x3F,
|
||||
eCmdWriteLong16 = 0x9F
|
||||
};
|
||||
|
||||
typedef struct _scsi_t {
|
||||
// Synchronous transfer
|
||||
bool syncenable; // Synchronous transfer possible
|
||||
int syncperiod = MAX_SYNC_PERIOD; // Synchronous transfer period
|
||||
int syncoffset; // Synchronous transfer offset
|
||||
int syncack; // Number of synchronous transfer ACKs
|
||||
|
||||
// ATN message
|
||||
bool atnmsg;
|
||||
int msc;
|
||||
BYTE msb[256];
|
||||
} scsi_t;
|
||||
|
||||
public:
|
||||
|
||||
ScsiController(BUS *, int);
|
||||
~ScsiController();
|
||||
|
||||
void Reset() override;
|
||||
|
||||
BUS::phase_t Process(int) override;
|
||||
|
||||
int GetEffectiveLun() const override;
|
||||
|
||||
int GetMaxLuns() const override { return LUN_MAX; };
|
||||
|
||||
void Error(scsi_defs::sense_key sense_key, scsi_defs::asc asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||
scsi_defs::status status = scsi_defs::status::CHECK_CONDITION) override;
|
||||
|
||||
int GetInitiatorId() const override { return initiator_id; }
|
||||
void SetByteTransfer(bool is_byte_transfer) override { this->is_byte_transfer = is_byte_transfer; }
|
||||
|
||||
void Status() override;
|
||||
void DataIn() override;
|
||||
void DataOut() override;
|
||||
|
||||
private:
|
||||
|
||||
// Execution start time
|
||||
DWORD execstart = 0;
|
||||
|
||||
// The initiator ID may be unavailable, e.g. with Atari ACSI and old host adapters
|
||||
int initiator_id = UNKNOWN_INITIATOR_ID;
|
||||
|
||||
// The LUN from the IDENTIFY message
|
||||
int identified_lun = -1;
|
||||
|
||||
bool is_byte_transfer = false;
|
||||
uint32_t bytes_to_transfer = 0;
|
||||
|
||||
// Phases
|
||||
void SetPhase(BUS::phase_t phase) override { ctrl.phase = phase; }
|
||||
void BusFree() override;
|
||||
void Selection() override;
|
||||
void Command() override;
|
||||
void MsgIn() override;
|
||||
void MsgOut() override;
|
||||
|
||||
// Data transfer
|
||||
void Send();
|
||||
bool XferMsg(int);
|
||||
bool XferIn(BYTE* buf);
|
||||
bool XferOut(bool);
|
||||
bool XferOutBlockOriented(bool);
|
||||
void ReceiveBytes();
|
||||
|
||||
void Execute();
|
||||
void FlushUnit();
|
||||
void Receive();
|
||||
|
||||
void ScheduleShutdown(rascsi_shutdown_mode shutdown_mode) override { this->shutdown_mode = shutdown_mode; }
|
||||
|
||||
void Sleep();
|
||||
|
||||
scsi_t scsi = {};
|
||||
|
||||
rascsi_shutdown_mode shutdown_mode = NONE;
|
||||
};
|
||||
|
@ -1,918 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2001-2006 PI.(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 device controller ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#include "log.h"
|
||||
#include "controllers/scsidev_ctrl.h"
|
||||
#include "gpiobus.h"
|
||||
#include "devices/scsi_daynaport.h"
|
||||
#include "devices/scsi_printer.h"
|
||||
|
||||
using namespace scsi_defs;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// SCSI Device
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
SCSIDEV::SCSIDEV() : SASIDEV()
|
||||
{
|
||||
scsi.is_byte_transfer = false;
|
||||
scsi.bytes_to_transfer = 0;
|
||||
shutdown_mode = NONE;
|
||||
|
||||
// Synchronous transfer work initialization
|
||||
scsi.syncenable = FALSE;
|
||||
scsi.syncperiod = 50;
|
||||
scsi.syncoffset = 0;
|
||||
scsi.atnmsg = false;
|
||||
scsi.msc = 0;
|
||||
memset(scsi.msb, 0x00, sizeof(scsi.msb));
|
||||
}
|
||||
|
||||
SCSIDEV::~SCSIDEV()
|
||||
{
|
||||
}
|
||||
|
||||
void SCSIDEV::Reset()
|
||||
{
|
||||
scsi.is_byte_transfer = false;
|
||||
scsi.bytes_to_transfer = 0;
|
||||
|
||||
// Work initialization
|
||||
scsi.atnmsg = false;
|
||||
scsi.msc = 0;
|
||||
memset(scsi.msb, 0x00, sizeof(scsi.msb));
|
||||
|
||||
super::Reset();
|
||||
}
|
||||
|
||||
BUS::phase_t SCSIDEV::Process(int initiator_id)
|
||||
{
|
||||
// Do nothing if not connected
|
||||
if (ctrl.m_scsi_id < 0 || ctrl.bus == NULL) {
|
||||
return ctrl.phase;
|
||||
}
|
||||
|
||||
// Get bus information
|
||||
ctrl.bus->Aquire();
|
||||
|
||||
// Check to see if the reset signal was asserted
|
||||
if (ctrl.bus->GetRST()) {
|
||||
LOGWARN("RESET signal received!");
|
||||
|
||||
// Reset the controller
|
||||
Reset();
|
||||
|
||||
// Reset the bus
|
||||
ctrl.bus->Reset();
|
||||
return ctrl.phase;
|
||||
}
|
||||
|
||||
scsi.initiator_id = initiator_id;
|
||||
|
||||
// Phase processing
|
||||
switch (ctrl.phase) {
|
||||
// Bus free phase
|
||||
case BUS::busfree:
|
||||
BusFree();
|
||||
break;
|
||||
|
||||
// Selection
|
||||
case BUS::selection:
|
||||
Selection();
|
||||
break;
|
||||
|
||||
// Data out (MCI=000)
|
||||
case BUS::dataout:
|
||||
DataOut();
|
||||
break;
|
||||
|
||||
// Data in (MCI=001)
|
||||
case BUS::datain:
|
||||
DataIn();
|
||||
break;
|
||||
|
||||
// Command (MCI=010)
|
||||
case BUS::command:
|
||||
Command();
|
||||
break;
|
||||
|
||||
// Status (MCI=011)
|
||||
case BUS::status:
|
||||
Status();
|
||||
break;
|
||||
|
||||
// Message out (MCI=110)
|
||||
case BUS::msgout:
|
||||
MsgOut();
|
||||
break;
|
||||
|
||||
// Message in (MCI=111)
|
||||
case BUS::msgin:
|
||||
MsgIn();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return ctrl.phase;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Bus free phase
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIDEV::BusFree()
|
||||
{
|
||||
// Phase change
|
||||
if (ctrl.phase != BUS::busfree) {
|
||||
LOGTRACE("%s Bus free phase", __PRETTY_FUNCTION__);
|
||||
|
||||
// Phase setting
|
||||
ctrl.phase = BUS::busfree;
|
||||
|
||||
// Set Signal lines
|
||||
ctrl.bus->SetREQ(FALSE);
|
||||
ctrl.bus->SetMSG(FALSE);
|
||||
ctrl.bus->SetCD(FALSE);
|
||||
ctrl.bus->SetIO(FALSE);
|
||||
ctrl.bus->SetBSY(false);
|
||||
|
||||
// Initialize status and message
|
||||
ctrl.status = 0x00;
|
||||
ctrl.message = 0x00;
|
||||
|
||||
// Initialize ATN message reception status
|
||||
scsi.atnmsg = false;
|
||||
|
||||
ctrl.lun = -1;
|
||||
|
||||
scsi.is_byte_transfer = false;
|
||||
scsi.bytes_to_transfer = 0;
|
||||
|
||||
// When the bus is free RaSCSI or the Pi may be shut down
|
||||
switch(shutdown_mode) {
|
||||
case STOP_RASCSI:
|
||||
LOGINFO("RaSCSI shutdown requested");
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case STOP_PI:
|
||||
LOGINFO("Raspberry Pi shutdown requested");
|
||||
if (system("init 0") == -1) {
|
||||
LOGERROR("Raspberry Pi shutdown failed: %s", strerror(errno));
|
||||
}
|
||||
break;
|
||||
|
||||
case RESTART_PI:
|
||||
LOGINFO("Raspberry Pi restart requested");
|
||||
if (system("init 6") == -1) {
|
||||
LOGERROR("Raspberry Pi restart failed: %s", strerror(errno));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Move to selection phase
|
||||
if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) {
|
||||
Selection();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Selection Phase
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void SCSIDEV::Selection()
|
||||
{
|
||||
// Phase change
|
||||
if (ctrl.phase != BUS::selection) {
|
||||
// invalid if IDs do not match
|
||||
int id = 1 << ctrl.m_scsi_id;
|
||||
if ((ctrl.bus->GetDAT() & id) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||