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:
Uwe Seimet 2022-09-03 16:53:53 +02:00 committed by GitHub
parent 2411afb2c4
commit ddeede2beb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 3966 additions and 5708 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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/>

View File

@ -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,

View File

@ -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>

View File

@ -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":

View File

@ -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

View File

@ -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)

View File

@ -12,6 +12,6 @@
#include <string>
struct CommandContext {
int fd;
std::string locale;
int fd = -1;
std::string locale = "";
};

View File

@ -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

View 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;
}

View 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 = {};
};

View 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;
}

View 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;
};

View 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

View File

@ -1,171 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// 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.
//
// [ 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
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// 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 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;
};

View File

@ -1,918 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// 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 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;
}