From 1c0179e7e3d0b389b043287181c451047c2858eb Mon Sep 17 00:00:00 2001 From: Uwe Seimet <48174652+uweseimet@users.noreply.github.com> Date: Wed, 9 Nov 2022 08:40:26 +0100 Subject: [PATCH] rasdump and monitor updates, made rasdump work, improved bus abstraction (#973) * Moved rasdump and monitor to sub-folders, cleaned up code * Fixes rasdump issues and added additional features like device type check, LUN support and configurable buffer size --- .github/workflows/run_tests.yml | 2 +- cpp/Makefile | 5 +- cpp/controllers/scsi_controller.cpp | 10 +- cpp/devices/scsicd.cpp | 2 +- cpp/hal/bus.h | 9 + cpp/hal/gpiobus.cpp | 1710 +++++++++++++++++---------- cpp/hal/gpiobus.h | 580 +++++---- cpp/hal/gpiobus_aibom.h | 60 +- cpp/hal/gpiobus_allwinner.cpp | 120 -- cpp/hal/gpiobus_allwinner.h | 128 -- cpp/hal/gpiobus_factory.cpp | 27 +- cpp/hal/gpiobus_factory.h | 10 +- cpp/hal/gpiobus_fullspec.h | 60 +- cpp/hal/gpiobus_gamernium.h | 61 +- cpp/hal/gpiobus_raspberry.cpp | 856 -------------- cpp/hal/gpiobus_raspberry.h | 124 -- cpp/hal/gpiobus_standard.h | 60 +- cpp/hal/sbc_version.cpp | 215 ---- cpp/hal/sbc_version.h | 70 -- cpp/hal/systimer.cpp | 145 ++- cpp/hal/systimer.h | 54 +- cpp/hal/systimer_allwinner.cpp | 155 --- cpp/hal/systimer_allwinner.h | 106 -- cpp/hal/systimer_raspberry.cpp | 148 --- cpp/hal/systimer_raspberry.h | 49 - cpp/monitor/sm_core.cpp | 199 +--- cpp/monitor/sm_core.h | 41 +- cpp/monitor/sm_json_report.cpp | 2 +- cpp/monitor/sm_vcd_report.cpp | 6 +- cpp/rascsi/rascsi_core.cpp | 16 +- cpp/rascsi/rascsi_core.h | 5 +- cpp/rasdump/rasdump_core.cpp | 1302 +++++++------------- cpp/rasdump/rasdump_core.h | 76 +- cpp/rasdump/rasdump_fileio.cpp | 103 -- cpp/rasdump/rasdump_fileio.h | 42 - doc/rasdump.1 | 28 +- doc/rasdump_man_page.txt | 42 + 37 files changed, 2348 insertions(+), 4280 deletions(-) delete mode 100644 cpp/hal/gpiobus_allwinner.cpp delete mode 100644 cpp/hal/gpiobus_allwinner.h delete mode 100644 cpp/hal/gpiobus_raspberry.cpp delete mode 100644 cpp/hal/gpiobus_raspberry.h delete mode 100644 cpp/hal/sbc_version.cpp delete mode 100644 cpp/hal/sbc_version.h delete mode 100644 cpp/hal/systimer_allwinner.cpp delete mode 100644 cpp/hal/systimer_allwinner.h delete mode 100644 cpp/hal/systimer_raspberry.cpp delete mode 100644 cpp/hal/systimer_raspberry.h delete mode 100644 cpp/rasdump/rasdump_fileio.cpp delete mode 100644 cpp/rasdump/rasdump_fileio.h create mode 100644 doc/rasdump_man_page.txt diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index d690aa22..e4b6d28c 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -56,5 +56,5 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | - cd $SOURCES | sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" --define sonar.projectKey=akuker_RASCSI --define sonar.organization=rascsi --define sonar.cfamily.gcov.reportsPath=. --define sonar.cfamily.cache.enabled=false --define sonar.coverage.exclusions="**/test/**" --define sonar.cpd.exclusions="**test/**" --define sonar.python.version=3 + cd $SOURCES | sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" --define sonar.projectKey=akuker_RASCSI --define sonar.organization=rascsi --define sonar.cfamily.gcov.reportsPath=. --define sonar.coverage.exclusions="**/test/**" --define sonar.cpd.exclusions="**test/**" --define sonar.python.version=3 diff --git a/cpp/Makefile b/cpp/Makefile index cff18de7..483a71c4 100644 --- a/cpp/Makefile +++ b/cpp/Makefile @@ -115,7 +115,8 @@ SRC_RASDUMP += $(shell find ./rasdump -name '*.cpp') SRC_RASDUMP += $(shell find ./hal -name '*.cpp') SRC_RASCSI_TEST = $(shell find ./test -name '*.cpp') - +SRC_RASCSI_TEST += $(shell find ./rasdump -name '*.cpp') +SRC_RASCSI_TEST += $(shell find ./monitor -name '*.cpp') vpath %.h ./ ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl ./rasdump vpath %.cpp ./ ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl ./rasdump ./test @@ -177,7 +178,7 @@ lcov: test lcov -q -c -d . --include '*/cpp/*' -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 +docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt $(DOC_DIR)/rasdump_man_page.txt $(SRC_SHARED) $(SRC_RASCSI_CORE) $(SRC_RASCTL_CORE): $(OBJ_PROTOBUF) diff --git a/cpp/controllers/scsi_controller.cpp b/cpp/controllers/scsi_controller.cpp index 34188a55..698f9fb8 100644 --- a/cpp/controllers/scsi_controller.cpp +++ b/cpp/controllers/scsi_controller.cpp @@ -211,8 +211,8 @@ void ScsiController::Command() // If not able to receive all, move to the status phase if (actual_count != command_byte_count) { - LOGERROR("%s Command byte count mismatch: expected %d bytes, received %d byte(s)", __PRETTY_FUNCTION__, - command_byte_count, actual_count) + LOGERROR("Command byte count mismatch for command $%02X: expected %d bytes, received %d byte(s)", + GetBuffer()[0], command_byte_count, actual_count) Error(sense_key::ABORTED_COMMAND); return; } @@ -584,12 +584,12 @@ void ScsiController::Receive() // Length != 0 if received if (HasValidLength()) { - LOGTRACE("%s Length is %d bytes", __PRETTY_FUNCTION__, GetLength()) + LOGTRACE("%s Length is %d byte(s)", __PRETTY_FUNCTION__, GetLength()) // If not able to receive all, move to status phase if (int len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); len != static_cast(GetLength())) { - LOGERROR("%s Not able to receive %d bytes of data, only received %d",__PRETTY_FUNCTION__, GetLength(), len) + LOGERROR("%s Not able to receive %d byte(s) of data, only received %d",__PRETTY_FUNCTION__, GetLength(), len) Error(sense_key::ABORTED_COMMAND); return; } @@ -692,7 +692,7 @@ void ScsiController::ReceiveBytes() // If not able to receive all, move to status phase if (uint32_t len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); len != GetLength()) { - LOGERROR("%s Not able to receive %d bytes of data, only received %d", + LOGERROR("%s Not able to receive %d byte(s) of data, only received %d", __PRETTY_FUNCTION__, GetLength(), len) Error(sense_key::ABORTED_COMMAND); return; diff --git a/cpp/devices/scsicd.cpp b/cpp/devices/scsicd.cpp index cabe321d..10b64301 100644 --- a/cpp/devices/scsicd.cpp +++ b/cpp/devices/scsicd.cpp @@ -156,7 +156,7 @@ void SCSICD::CreateDataTrack() auto track = make_unique(); track->Init(1, 0, static_cast(GetBlockCount()) - 1); track->SetPath(false, GetFilename()); - tracks.push_back(move(track)); + tracks.push_back(std::move(track)); dataindex = 0; } diff --git a/cpp/hal/bus.h b/cpp/hal/bus.h index 7400fcfa..3a2adfc5 100644 --- a/cpp/hal/bus.h +++ b/cpp/hal/bus.h @@ -9,6 +9,7 @@ #pragma once +#include "config.h" #include "scsi.h" #include #include @@ -102,6 +103,14 @@ public: virtual int ReceiveHandShake(uint8_t *buf, int count) = 0; virtual int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) = 0; +#ifdef USE_SEL_EVENT_ENABLE + // SEL signal event polling + virtual bool PollSelectEvent() = 0; + + // Clear SEL signal event + virtual void ClearSelectEvent() = 0; +#endif + virtual bool GetSignal(int pin) const = 0; // Get SCSI input signal value virtual void SetSignal(int pin, bool ast) = 0; diff --git a/cpp/hal/gpiobus.cpp b/cpp/hal/gpiobus.cpp index 62781a4f..f8b41c0d 100644 --- a/cpp/hal/gpiobus.cpp +++ b/cpp/hal/gpiobus.cpp @@ -10,420 +10,668 @@ // //--------------------------------------------------------------------------- +#include +#include +#include #include "hal/gpiobus.h" -#include "config.h" -#include "hal/sbc_version.h" #include "hal/systimer.h" +#include "config.h" #include "log.h" #include -#include -#include -#include #ifdef __linux__ #include #endif -#if defined CONNECT_TYPE_STANDARD -#include "hal/gpiobus_standard.h" -#elif defined CONNECT_TYPE_FULLSPEC -#include "hal/gpiobus_fullspec.h" -#elif defined CONNECT_TYPE_AIBOM -#include "hal/gpiobus_aibom.h" -#elif defined CONNECT_TYPE_GAMERNIUM -#include "hal/gpiobus_gamernium.h" -#else -#error Invalid connection type or none specified -#endif - -//--------------------------------------------------------------------------- -// -// Constant declarations (bus control timing) -// -//--------------------------------------------------------------------------- -// SCSI Bus timings taken from: -// https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-05.html -[[maybe_unused]] const static int SCSI_DELAY_ARBITRATION_DELAY_NS = 2400; -[[maybe_unused]] const static int SCSI_DELAY_ASSERTION_PERIOD_NS = 90; -[[maybe_unused]] const static int SCSI_DELAY_BUS_CLEAR_DELAY_NS = 800; -[[maybe_unused]] const static int SCSI_DELAY_BUS_FREE_DELAY_NS = 800; -[[maybe_unused]] const static int SCSI_DELAY_BUS_SET_DELAY_NS = 1800; -[[maybe_unused]] const static int SCSI_DELAY_BUS_SETTLE_DELAY_NS = 400; -[[maybe_unused]] const static int SCSI_DELAY_CABLE_SKEW_DELAY_NS = 10; -[[maybe_unused]] const static int SCSI_DELAY_DATA_RELEASE_DELAY_NS = 400; -[[maybe_unused]] const static int SCSI_DELAY_DESKEW_DELAY_NS = 45; -[[maybe_unused]] const static int SCSI_DELAY_DISCONNECTION_DELAY_US = 200; -[[maybe_unused]] const static int SCSI_DELAY_HOLD_TIME_NS = 45; -[[maybe_unused]] const static int SCSI_DELAY_NEGATION_PERIOD_NS = 90; -[[maybe_unused]] const static int SCSI_DELAY_POWER_ON_TO_SELECTION_TIME_S = 10; // (recommended) -[[maybe_unused]] const static int SCSI_DELAY_RESET_TO_SELECTION_TIME_US = 250 * 1000; // (recommended) -[[maybe_unused]] const static int SCSI_DELAY_RESET_HOLD_TIME_US = 25; -[[maybe_unused]] const static int SCSI_DELAY_SELECTION_ABORT_TIME_US = 200; -[[maybe_unused]] const static int SCSI_DELAY_SELECTION_TIMEOUT_DELAY_NS = 250 * 1000; // (recommended) -[[maybe_unused]] const static int SCSI_DELAY_FAST_ASSERTION_PERIOD_NS = 30; -[[maybe_unused]] const static int SCSI_DELAY_FAST_CABLE_SKEW_DELAY_NS = 5; -[[maybe_unused]] const static int SCSI_DELAY_FAST_DESKEW_DELAY_NS = 20; -[[maybe_unused]] const static int SCSI_DELAY_FAST_HOLD_TIME_NS = 10; -[[maybe_unused]] const static int SCSI_DELAY_FAST_NEGATION_PERIOD_NS = 30; - -// The DaynaPort SCSI Link do a short delay in the middle of transfering -// a packet. This is the number of uS that will be delayed between the -// header and the actual data. -const static int SCSI_DELAY_SEND_DATA_DAYNAPORT_US = 100; - using namespace std; -// Nothing SBC hardware specific should be done in this function +#ifdef __linux__ +//--------------------------------------------------------------------------- +// +// imported from bcm_host.c +// +//--------------------------------------------------------------------------- +static uint32_t get_dt_ranges(const char *filename, uint32_t offset) +{ + uint32_t address = ~0; + if (FILE *fp = fopen(filename, "rb"); fp) { + fseek(fp, offset, SEEK_SET); + if (array buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) { + address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0; + } + fclose(fp); + } + return address; +} + +uint32_t bcm_host_get_peripheral_address() +{ + uint32_t address = get_dt_ranges("/proc/device-tree/soc/ranges", 4); + if (address == 0) { + address = get_dt_ranges("/proc/device-tree/soc/ranges", 8); + } + address = (address == (uint32_t)~0) ? 0x20000000 : address; + return address; +} +#endif + +#ifdef __NetBSD__ +// Assume the Raspberry Pi series and estimate the address from CPU +uint32_t bcm_host_get_peripheral_address() +{ + array buf; + size_t len = buf.size(); + uint32_t address; + + if (sysctlbyname("hw.model", buf.data(), &len, NULL, 0) || + strstr(buf, "ARM1176JZ-S") != buf.data()) { + // Failed to get CPU model || Not BCM2835 + // use the address of BCM283[67] + address = 0x3f000000; + } else { + // Use BCM2835 address + address = 0x20000000; + } + printf("Peripheral address : 0x%lx\n", address); + return address; +} +#endif + bool GPIOBUS::Init(mode_e mode) { - GPIO_FUNCTION_TRACE - // Save operation mode - actmode = mode; - return true; + // Save operation mode + actmode = mode; + +#if defined(__x86_64__) || defined(__X86__) + return true; +#else + int i; +#ifdef USE_SEL_EVENT_ENABLE + epoll_event ev = {}; +#endif + + // Get the base address + baseaddr = (uint32_t)bcm_host_get_peripheral_address(); + + // Open /dev/mem + int fd = open("/dev/mem", O_RDWR | O_SYNC); + if (fd == -1) { + LOGERROR("Error: Unable to open /dev/mem. Are you running as root?") + return false; + } + + // Map peripheral region memory + void *map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr); + if (map == MAP_FAILED) { + LOGERROR("Error: Unable to map memory") + close(fd); + return false; + } + + // Determine the type of raspberry pi from the base address + if (baseaddr == 0xfe000000) { + rpitype = 4; + } else if (baseaddr == 0x3f000000) { + rpitype = 2; + } else { + rpitype = 1; + } + + // GPIO + gpio = (uint32_t *)map; + gpio += GPIO_OFFSET / sizeof(uint32_t); + level = &gpio[GPIO_LEV_0]; + + // PADS + pads = (uint32_t *)map; + pads += PADS_OFFSET / sizeof(uint32_t); + + // System timer + SysTimer::Init( + (uint32_t *)map + SYST_OFFSET / sizeof(uint32_t), + (uint32_t *)map + ARMT_OFFSET / sizeof(uint32_t)); + + // Interrupt controller + irpctl = (uint32_t *)map; + irpctl += IRPT_OFFSET / sizeof(uint32_t); + + // Quad-A7 control + qa7regs = (uint32_t *)map; + qa7regs += QA7_OFFSET / sizeof(uint32_t); + + // Map GIC memory + if (rpitype == 4) { + map = mmap(NULL, 8192, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, ARM_GICD_BASE); + if (map == MAP_FAILED) { + close(fd); + return false; + } + gicd = (uint32_t *)map; + gicc = (uint32_t *)map; + gicc += (ARM_GICC_BASE - ARM_GICD_BASE) / sizeof(uint32_t); + } else { + gicd = NULL; + gicc = NULL; + } + close(fd); + + // Set Drive Strength to 16mA + DrvConfig(7); + + // Set pull up/pull down +#if SIGNAL_CONTROL_MODE == 0 + int pullmode = GPIO_PULLNONE; +#elif SIGNAL_CONTROL_MODE == 1 + int pullmode = GPIO_PULLUP; +#else + int pullmode = GPIO_PULLDOWN; +#endif + + // Initialize all signals + for (i = 0; SignalTable[i] >= 0; i++) { + int j = SignalTable[i]; + PinSetSignal(j, OFF); + PinConfig(j, GPIO_INPUT); + PullConfig(j, pullmode); + } + + // Set control signals + PinSetSignal(PIN_ACT, OFF); + PinSetSignal(PIN_TAD, OFF); + PinSetSignal(PIN_IND, OFF); + PinSetSignal(PIN_DTD, OFF); + PinConfig(PIN_ACT, GPIO_OUTPUT); + PinConfig(PIN_TAD, GPIO_OUTPUT); + PinConfig(PIN_IND, GPIO_OUTPUT); + PinConfig(PIN_DTD, GPIO_OUTPUT); + + // Set the ENABLE signal + // This is used to show that the application is running + PinSetSignal(PIN_ENB, ENB_OFF); + PinConfig(PIN_ENB, GPIO_OUTPUT); + + // GPFSEL backup + gpfsel[0] = gpio[GPIO_FSEL_0]; + gpfsel[1] = gpio[GPIO_FSEL_1]; + gpfsel[2] = gpio[GPIO_FSEL_2]; + gpfsel[3] = gpio[GPIO_FSEL_3]; + + // Initialize SEL signal interrupt +#ifdef USE_SEL_EVENT_ENABLE + // GPIO chip open + fd = open("/dev/gpiochip0", 0); + if (fd == -1) { + LOGERROR("Unable to open /dev/gpiochip0. Is RaSCSI already running?") + return false; + } + + // Event request setting + strcpy(selevreq.consumer_label, "RaSCSI"); + selevreq.lineoffset = PIN_SEL; + selevreq.handleflags = GPIOHANDLE_REQUEST_INPUT; +#if SIGNAL_CONTROL_MODE < 2 + selevreq.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE; +#else + selevreq.eventflags = GPIOEVENT_REQUEST_RISING_EDGE; +#endif // SIGNAL_CONTROL_MODE + + //Get event request + if (ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &selevreq) == -1) { + LOGERROR("Unable to register event request. Is RaSCSI already running?") + close(fd); + return false; + } + + // Close GPIO chip file handle + close(fd); + + // epoll initialization + epfd = epoll_create(1); + ev.events = EPOLLIN | EPOLLPRI; + ev.data.fd = selevreq.fd; + epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev); +#else + // Edge detection setting +#if SIGNAL_CONTROL_MODE == 2 + gpio[GPIO_AREN_0] = 1 << PIN_SEL; +#else + gpio[GPIO_AFEN_0] = 1 << PIN_SEL; +#endif // SIGNAL_CONTROL_MODE + + // Clear event + gpio[GPIO_EDS_0] = 1 << PIN_SEL; + + // Register interrupt handler + setIrqFuncAddress(IrqHandler); + + // GPIO interrupt setting + if (rpitype == 4) { + // GIC Invalid + gicd[GICD_CTLR] = 0; + + // Route all interupts to core 0 + for (i = 0; i < 8; i++) { + gicd[GICD_ICENABLER0 + i] = 0xffffffff; + gicd[GICD_ICPENDR0 + i] = 0xffffffff; + gicd[GICD_ICACTIVER0 + i] = 0xffffffff; + } + for (i = 0; i < 64; i++) { + gicd[GICD_IPRIORITYR0 + i] = 0xa0a0a0a0; + gicd[GICD_ITARGETSR0 + i] = 0x01010101; + } + + // Set all interrupts as level triggers + for (i = 0; i < 16; i++) { + gicd[GICD_ICFGR0 + i] = 0; + } + + // GIC Invalid + gicd[GICD_CTLR] = 1; + + // Enable CPU interface for core 0 + gicc[GICC_PMR] = 0xf0; + gicc[GICC_CTLR] = 1; + + // Enable interrupts + gicd[GICD_ISENABLER0 + (GIC_GPIO_IRQ / 32)] = + 1 << (GIC_GPIO_IRQ % 32); + } else { + // Enable interrupts + irpctl[IRPT_ENB_IRQ_2] = (1 << (GPIO_IRQ % 32)); + } +#endif // USE_SEL_EVENT_ENABLE + + // Create work table + MakeTable(); + + // Finally, enable ENABLE + // Show the user that this app is running + SetControl(PIN_ENB, ENB_ON); + + return true; +#endif // ifdef __x86_64__ || __X86__ + } void GPIOBUS::Cleanup() { #if defined(__x86_64__) || defined(__X86__) - return; + return; #else - // Release SEL signal interrupt + // Release SEL signal interrupt #ifdef USE_SEL_EVENT_ENABLE - close(selevreq.fd); -#endif // USE_SEL_EVENT_ENABLE + close(selevreq.fd); +#endif // USE_SEL_EVENT_ENABLE - // Set control signals - PinSetSignal(PIN_ENB, OFF); - PinSetSignal(PIN_ACT, OFF); - PinSetSignal(PIN_TAD, OFF); - PinSetSignal(PIN_IND, OFF); - PinSetSignal(PIN_DTD, OFF); - PinConfig(PIN_ACT, GPIO_INPUT); - PinConfig(PIN_TAD, GPIO_INPUT); - PinConfig(PIN_IND, GPIO_INPUT); - PinConfig(PIN_DTD, GPIO_INPUT); + // Set control signals + PinSetSignal(PIN_ENB, OFF); + PinSetSignal(PIN_ACT, OFF); + PinSetSignal(PIN_TAD, OFF); + PinSetSignal(PIN_IND, OFF); + PinSetSignal(PIN_DTD, OFF); + PinConfig(PIN_ACT, GPIO_INPUT); + PinConfig(PIN_TAD, GPIO_INPUT); + PinConfig(PIN_IND, GPIO_INPUT); + PinConfig(PIN_DTD, GPIO_INPUT); - // Initialize all signals - for (int i = 0; SignalTable[i] >= 0; i++) { - int pin = SignalTable[i]; - PinSetSignal(pin, OFF); - PinConfig(pin, GPIO_INPUT); - PullConfig(pin, GPIO_PULLNONE); - } + // Initialize all signals + for (int i = 0; SignalTable[i] >= 0; i++) { + int pin = SignalTable[i]; + PinSetSignal(pin, OFF); + PinConfig(pin, GPIO_INPUT); + PullConfig(pin, GPIO_PULLNONE); + } - // Set drive strength back to 8mA - DrvConfig(3); + // Set drive strength back to 8mA + DrvConfig(3); #endif // ifdef __x86_64__ || __X86__ } void GPIOBUS::Reset() { - GPIO_FUNCTION_TRACE #if defined(__x86_64__) || defined(__X86__) - return; + return; #else - int i; - int j; + int i; + int j; - // Turn off active signal - SetControl(PIN_ACT, ACT_OFF); + // Turn off active signal + SetControl(PIN_ACT, ACT_OFF); - // Set all signals to off - for (i = 0;; i++) { - j = SignalTable[i]; - if (j < 0) { - break; - } + // Set all signals to off + for (i = 0;; i++) { + j = SignalTable[i]; + if (j < 0) { + break; + } - SetSignal(j, OFF); - } + SetSignal(j, OFF); + } - if (actmode == mode_e::TARGET) { - // Target mode + if (actmode == mode_e::TARGET) { + // Target mode - // Set target signal to input - SetControl(PIN_TAD, TAD_IN); - SetMode(PIN_BSY, IN); - SetMode(PIN_MSG, IN); - SetMode(PIN_CD, IN); - SetMode(PIN_REQ, IN); - SetMode(PIN_IO, IN); + // Set target signal to input + SetControl(PIN_TAD, TAD_IN); + SetMode(PIN_BSY, IN); + SetMode(PIN_MSG, IN); + SetMode(PIN_CD, IN); + SetMode(PIN_REQ, IN); + SetMode(PIN_IO, IN); - // Set the initiator signal to input - SetControl(PIN_IND, IND_IN); - SetMode(PIN_SEL, IN); - SetMode(PIN_ATN, IN); - SetMode(PIN_ACK, IN); - SetMode(PIN_RST, IN); + // Set the initiator signal to input + SetControl(PIN_IND, IND_IN); + SetMode(PIN_SEL, IN); + SetMode(PIN_ATN, IN); + SetMode(PIN_ACK, IN); + SetMode(PIN_RST, IN); - // Set data bus signals to input - SetControl(PIN_DTD, DTD_IN); - SetMode(PIN_DT0, IN); - SetMode(PIN_DT1, IN); - SetMode(PIN_DT2, IN); - SetMode(PIN_DT3, IN); - SetMode(PIN_DT4, IN); - SetMode(PIN_DT5, IN); - SetMode(PIN_DT6, IN); - SetMode(PIN_DT7, IN); - SetMode(PIN_DP, IN); - } else { - // Initiator mode + // Set data bus signals to input + SetControl(PIN_DTD, DTD_IN); + SetMode(PIN_DT0, IN); + SetMode(PIN_DT1, IN); + SetMode(PIN_DT2, IN); + SetMode(PIN_DT3, IN); + SetMode(PIN_DT4, IN); + SetMode(PIN_DT5, IN); + SetMode(PIN_DT6, IN); + SetMode(PIN_DT7, IN); + SetMode(PIN_DP, IN); + } else { + // Initiator mode - // Set target signal to input - SetControl(PIN_TAD, TAD_IN); - SetMode(PIN_BSY, IN); - SetMode(PIN_MSG, IN); - SetMode(PIN_CD, IN); - SetMode(PIN_REQ, IN); - SetMode(PIN_IO, IN); + // Set target signal to input + SetControl(PIN_TAD, TAD_IN); + SetMode(PIN_BSY, IN); + SetMode(PIN_MSG, IN); + SetMode(PIN_CD, IN); + SetMode(PIN_REQ, IN); + SetMode(PIN_IO, IN); - // Set the initiator signal to output - SetControl(PIN_IND, IND_OUT); - SetMode(PIN_SEL, OUT); - SetMode(PIN_ATN, OUT); - SetMode(PIN_ACK, OUT); - SetMode(PIN_RST, OUT); + // Set the initiator signal to output + SetControl(PIN_IND, IND_OUT); + SetMode(PIN_SEL, OUT); + SetMode(PIN_ATN, OUT); + SetMode(PIN_ACK, OUT); + SetMode(PIN_RST, OUT); - // Set the data bus signals to output - SetControl(PIN_DTD, DTD_OUT); - SetMode(PIN_DT0, OUT); - SetMode(PIN_DT1, OUT); - SetMode(PIN_DT2, OUT); - SetMode(PIN_DT3, OUT); - SetMode(PIN_DT4, OUT); - SetMode(PIN_DT5, OUT); - SetMode(PIN_DT6, OUT); - SetMode(PIN_DT7, OUT); - SetMode(PIN_DP, OUT); - } + // Set the data bus signals to output + SetControl(PIN_DTD, DTD_OUT); + SetMode(PIN_DT0, OUT); + SetMode(PIN_DT1, OUT); + SetMode(PIN_DT2, OUT); + SetMode(PIN_DT3, OUT); + SetMode(PIN_DT4, OUT); + SetMode(PIN_DT5, OUT); + SetMode(PIN_DT6, OUT); + SetMode(PIN_DT7, OUT); + SetMode(PIN_DP, OUT); + } - // Initialize all signals - signals = 0; + // Initialize all signals + signals = 0; #endif // ifdef __x86_64__ || __X86__ } void GPIOBUS::SetENB(bool ast) { - GPIO_FUNCTION_TRACE - PinSetSignal(PIN_ENB, ast ? ENB_ON : ENB_OFF); + PinSetSignal(PIN_ENB, ast ? ENB_ON : ENB_OFF); } bool GPIOBUS::GetBSY() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_BSY); + return GetSignal(PIN_BSY); } void GPIOBUS::SetBSY(bool ast) { - GPIO_FUNCTION_TRACE - // Set BSY signal - SetSignal(PIN_BSY, ast); + // Set BSY signal + SetSignal(PIN_BSY, ast); - if (actmode == mode_e::TARGET) { - if (ast) { - // Turn on ACTIVE signal - SetControl(PIN_ACT, ACT_ON); + if (actmode == mode_e::TARGET) { + if (ast) { + // Turn on ACTIVE signal + SetControl(PIN_ACT, ACT_ON); - // Set Target signal to output - SetControl(PIN_TAD, TAD_OUT); + // Set Target signal to output + SetControl(PIN_TAD, TAD_OUT); - SetMode(PIN_BSY, OUT); - SetMode(PIN_MSG, OUT); - SetMode(PIN_CD, OUT); - SetMode(PIN_REQ, OUT); - SetMode(PIN_IO, OUT); - } else { - // Turn off the ACTIVE signal - SetControl(PIN_ACT, ACT_OFF); + SetMode(PIN_BSY, OUT); + SetMode(PIN_MSG, OUT); + SetMode(PIN_CD, OUT); + SetMode(PIN_REQ, OUT); + SetMode(PIN_IO, OUT); + } else { + // Turn off the ACTIVE signal + SetControl(PIN_ACT, ACT_OFF); - // Set the target signal to input - SetControl(PIN_TAD, TAD_IN); + // Set the target signal to input + SetControl(PIN_TAD, TAD_IN); - SetMode(PIN_BSY, IN); - SetMode(PIN_MSG, IN); - SetMode(PIN_CD, IN); - SetMode(PIN_REQ, IN); - SetMode(PIN_IO, IN); - } - } + SetMode(PIN_BSY, IN); + SetMode(PIN_MSG, IN); + SetMode(PIN_CD, IN); + SetMode(PIN_REQ, IN); + SetMode(PIN_IO, IN); + } + } } bool GPIOBUS::GetSEL() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_SEL); + return GetSignal(PIN_SEL); } void GPIOBUS::SetSEL(bool ast) { - GPIO_FUNCTION_TRACE - if (actmode == mode_e::INITIATOR && ast) { - // Turn on ACTIVE signal - SetControl(PIN_ACT, ACT_ON); - } + if (actmode == mode_e::INITIATOR && ast) { + // Turn on ACTIVE signal + SetControl(PIN_ACT, ACT_ON); + } - // Set SEL signal - SetSignal(PIN_SEL, ast); + // Set SEL signal + SetSignal(PIN_SEL, ast); } bool GPIOBUS::GetATN() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_ATN); + return GetSignal(PIN_ATN); } void GPIOBUS::SetATN(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_ATN, ast); + SetSignal(PIN_ATN, ast); } bool GPIOBUS::GetACK() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_ACK); + return GetSignal(PIN_ACK); } void GPIOBUS::SetACK(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_ACK, ast); + SetSignal(PIN_ACK, ast); } bool GPIOBUS::GetACT() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_ACT); + return GetSignal(PIN_ACT); } void GPIOBUS::SetACT(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_ACT, ast); + SetSignal(PIN_ACT, ast); } bool GPIOBUS::GetRST() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_RST); + return GetSignal(PIN_RST); } void GPIOBUS::SetRST(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_RST, ast); + SetSignal(PIN_RST, ast); } bool GPIOBUS::GetMSG() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_MSG); + return GetSignal(PIN_MSG); } void GPIOBUS::SetMSG(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_MSG, ast); + SetSignal(PIN_MSG, ast); } bool GPIOBUS::GetCD() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_CD); + return GetSignal(PIN_CD); } void GPIOBUS::SetCD(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_CD, ast); + SetSignal(PIN_CD, ast); } bool GPIOBUS::GetIO() { - GPIO_FUNCTION_TRACE - bool ast = GetSignal(PIN_IO); + bool ast = GetSignal(PIN_IO); - if (actmode == mode_e::INITIATOR) { - // Change the data input/output direction by IO signal - if (ast) { - SetControl(PIN_DTD, DTD_IN); - SetMode(PIN_DT0, IN); - SetMode(PIN_DT1, IN); - SetMode(PIN_DT2, IN); - SetMode(PIN_DT3, IN); - SetMode(PIN_DT4, IN); - SetMode(PIN_DT5, IN); - SetMode(PIN_DT6, IN); - SetMode(PIN_DT7, IN); - SetMode(PIN_DP, IN); - } else { - SetControl(PIN_DTD, DTD_OUT); - SetMode(PIN_DT0, OUT); - SetMode(PIN_DT1, OUT); - SetMode(PIN_DT2, OUT); - SetMode(PIN_DT3, OUT); - SetMode(PIN_DT4, OUT); - SetMode(PIN_DT5, OUT); - SetMode(PIN_DT6, OUT); - SetMode(PIN_DT7, OUT); - SetMode(PIN_DP, OUT); - } - } + if (actmode == mode_e::INITIATOR) { + // Change the data input/output direction by IO signal + if (ast) { + SetControl(PIN_DTD, DTD_IN); + SetMode(PIN_DT0, IN); + SetMode(PIN_DT1, IN); + SetMode(PIN_DT2, IN); + SetMode(PIN_DT3, IN); + SetMode(PIN_DT4, IN); + SetMode(PIN_DT5, IN); + SetMode(PIN_DT6, IN); + SetMode(PIN_DT7, IN); + SetMode(PIN_DP, IN); + } else { + SetControl(PIN_DTD, DTD_OUT); + SetMode(PIN_DT0, OUT); + SetMode(PIN_DT1, OUT); + SetMode(PIN_DT2, OUT); + SetMode(PIN_DT3, OUT); + SetMode(PIN_DT4, OUT); + SetMode(PIN_DT5, OUT); + SetMode(PIN_DT6, OUT); + SetMode(PIN_DT7, OUT); + SetMode(PIN_DP, OUT); + } + } - return ast; + return ast; } void GPIOBUS::SetIO(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_IO, ast); + SetSignal(PIN_IO, ast); - if (actmode == mode_e::TARGET) { - // Change the data input/output direction by IO signal - if (ast) { - SetControl(PIN_DTD, DTD_OUT); - SetDAT(0); - SetMode(PIN_DT0, OUT); - SetMode(PIN_DT1, OUT); - SetMode(PIN_DT2, OUT); - SetMode(PIN_DT3, OUT); - SetMode(PIN_DT4, OUT); - SetMode(PIN_DT5, OUT); - SetMode(PIN_DT6, OUT); - SetMode(PIN_DT7, OUT); - SetMode(PIN_DP, OUT); - } else { - SetControl(PIN_DTD, DTD_IN); - SetMode(PIN_DT0, IN); - SetMode(PIN_DT1, IN); - SetMode(PIN_DT2, IN); - SetMode(PIN_DT3, IN); - SetMode(PIN_DT4, IN); - SetMode(PIN_DT5, IN); - SetMode(PIN_DT6, IN); - SetMode(PIN_DT7, IN); - SetMode(PIN_DP, IN); - } - } + if (actmode == mode_e::TARGET) { + // Change the data input/output direction by IO signal + if (ast) { + SetControl(PIN_DTD, DTD_OUT); + SetDAT(0); + SetMode(PIN_DT0, OUT); + SetMode(PIN_DT1, OUT); + SetMode(PIN_DT2, OUT); + SetMode(PIN_DT3, OUT); + SetMode(PIN_DT4, OUT); + SetMode(PIN_DT5, OUT); + SetMode(PIN_DT6, OUT); + SetMode(PIN_DT7, OUT); + SetMode(PIN_DP, OUT); + } else { + SetControl(PIN_DTD, DTD_IN); + SetMode(PIN_DT0, IN); + SetMode(PIN_DT1, IN); + SetMode(PIN_DT2, IN); + SetMode(PIN_DT3, IN); + SetMode(PIN_DT4, IN); + SetMode(PIN_DT5, IN); + SetMode(PIN_DT6, IN); + SetMode(PIN_DT7, IN); + SetMode(PIN_DP, IN); + } + } } bool GPIOBUS::GetREQ() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_REQ); + return GetSignal(PIN_REQ); } void GPIOBUS::SetREQ(bool ast) { - GPIO_FUNCTION_TRACE - SetSignal(PIN_REQ, ast); + SetSignal(PIN_REQ, ast); +} + +//--------------------------------------------------------------------------- +// +// Get data signals +// +//--------------------------------------------------------------------------- +uint8_t GPIOBUS::GetDAT() +{ + uint32_t data = Acquire(); + data = + ((data >> (PIN_DT0 - 0)) & (1 << 0)) | + ((data >> (PIN_DT1 - 1)) & (1 << 1)) | + ((data >> (PIN_DT2 - 2)) & (1 << 2)) | + ((data >> (PIN_DT3 - 3)) & (1 << 3)) | + ((data >> (PIN_DT4 - 4)) & (1 << 4)) | + ((data >> (PIN_DT5 - 5)) & (1 << 5)) | + ((data >> (PIN_DT6 - 6)) & (1 << 6)) | + ((data >> (PIN_DT7 - 7)) & (1 << 7)); + + return (uint8_t)data; +} + +//--------------------------------------------------------------------------- +// +// Set data signals +// +//--------------------------------------------------------------------------- +void GPIOBUS::SetDAT(uint8_t dat) +{ + // Write to port +#if SIGNAL_CONTROL_MODE == 0 + uint32_t fsel = gpfsel[0]; + fsel &= tblDatMsk[0][dat]; + fsel |= tblDatSet[0][dat]; + if (fsel != gpfsel[0]) { + gpfsel[0] = fsel; + gpio[GPIO_FSEL_0] = fsel; + } + + fsel = gpfsel[1]; + fsel &= tblDatMsk[1][dat]; + fsel |= tblDatSet[1][dat]; + if (fsel != gpfsel[1]) { + gpfsel[1] = fsel; + gpio[GPIO_FSEL_1] = fsel; + } + + fsel = gpfsel[2]; + fsel &= tblDatMsk[2][dat]; + fsel |= tblDatSet[2][dat]; + if (fsel != gpfsel[2]) { + gpfsel[2] = fsel; + gpio[GPIO_FSEL_2] = fsel; + } +#else + gpio[GPIO_CLR_0] = tblDatMsk[dat]; + gpio[GPIO_SET_0] = tblDatSet[dat]; +#endif // SIGNAL_CONTROL_MODE } bool GPIOBUS::GetDP() const { - GPIO_FUNCTION_TRACE - return GetSignal(PIN_DP); + return GetSignal(PIN_DP); } //--------------------------------------------------------------------------- @@ -433,123 +681,122 @@ bool GPIOBUS::GetDP() const //--------------------------------------------------------------------------- int GPIOBUS::CommandHandShake(vector& buf) { - GPIO_FUNCTION_TRACE - // Only works in TARGET mode - if (actmode != mode_e::TARGET) { - return 0; - } + // Only works in TARGET mode + if (actmode != mode_e::TARGET) { + return 0; + } - DisableIRQ(); + DisableIRQ(); - // Assert REQ signal - SetSignal(PIN_REQ, ON); + // Assert REQ signal + SetSignal(PIN_REQ, ON); - // Wait for ACK signal - bool ret = WaitSignal(PIN_ACK, ON); + // Wait for ACK signal + bool ret = WaitSignal(PIN_ACK, ON); - // Wait until the signal line stabilizes - SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); + // Wait until the signal line stabilizes + SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); - // Get data - buf[0] = GetDAT(); + // Get data + buf[0] = GetDAT(); - // Disable REQ signal - SetSignal(PIN_REQ, OFF); + // Disable REQ signal + SetSignal(PIN_REQ, OFF); - // Timeout waiting for ACK assertion - if (!ret) { - EnableIRQ(); - return 0; - } + // Timeout waiting for ACK assertion + if (!ret) { + EnableIRQ(); + return 0; + } - // Wait for ACK to clear - ret = WaitSignal(PIN_ACK, OFF); + // Wait for ACK to clear + ret = WaitSignal(PIN_ACK, OFF); - // Timeout waiting for ACK to clear - if (!ret) { - EnableIRQ(); - return 0; - } + // Timeout waiting for ACK to clear + if (!ret) { + EnableIRQ(); + return 0; + } - // The ICD AdSCSI ST, AdSCSI Plus ST and AdSCSI Micro ST host adapters allow SCSI devices to be connected - // to the ACSI bus of Atari ST/TT computers and some clones. ICD-aware drivers prepend a $1F byte in front - // of the CDB (effectively resulting in a custom SCSI command) in order to get access to the full SCSI - // command set. Native ACSI is limited to the low SCSI command classes with command bytes < $20. - // Most other host adapters (e.g. LINK96/97 and the one by Inventronik) and also several devices (e.g. - // UltraSatan or GigaFile) that can directly be connected to the Atari's ACSI port also support ICD - // semantics. I fact, these semantics have become a standard in the Atari world. + // The ICD AdSCSI ST, AdSCSI Plus ST and AdSCSI Micro ST host adapters allow SCSI devices to be connected + // to the ACSI bus of Atari ST/TT computers and some clones. ICD-aware drivers prepend a $1F byte in front + // of the CDB (effectively resulting in a custom SCSI command) in order to get access to the full SCSI + // command set. Native ACSI is limited to the low SCSI command classes with command bytes < $20. + // Most other host adapters (e.g. LINK96/97 and the one by Inventronik) and also several devices (e.g. + // UltraSatan or GigaFile) that can directly be connected to the Atari's ACSI port also support ICD + // semantics. I fact, these semantics have become a standard in the Atari world. - // RaSCSI becomes ICD compatible by ignoring the prepended $1F byte before processing the CDB. - if (buf[0] == 0x1F) { - SetSignal(PIN_REQ, ON); + // RaSCSI becomes ICD compatible by ignoring the prepended $1F byte before processing the CDB. + if (buf[0] == 0x1F) { + SetSignal(PIN_REQ, ON); - ret = WaitSignal(PIN_ACK, ON); + ret = WaitSignal(PIN_ACK, ON); - SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); + SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); - // Get the actual SCSI command - buf[0] = GetDAT(); + // Get the actual SCSI command + buf[0] = GetDAT(); - SetSignal(PIN_REQ, OFF); + SetSignal(PIN_REQ, OFF); - if (!ret) { - EnableIRQ(); - return 0; - } + if (!ret) { + EnableIRQ(); + return 0; + } - WaitSignal(PIN_ACK, OFF); + WaitSignal(PIN_ACK, OFF); - if (!ret) { - EnableIRQ(); - return 0; - } - } + if (!ret) { + EnableIRQ(); + return 0; + } + } - const int command_byte_count = GetCommandByteCount(buf[0]); - if (command_byte_count == 0) { - EnableIRQ(); + const int command_byte_count = GetCommandByteCount(buf[0]); + if (command_byte_count == 0) { + EnableIRQ(); - return 0; - } + return 0; + } - int offset = 0; + int offset = 0; - int bytes_received; - for (bytes_received = 1; bytes_received < command_byte_count; bytes_received++) { - ++offset; + int bytes_received; + for (bytes_received = 1; bytes_received < command_byte_count; bytes_received++) { + ++offset; - // Assert REQ signal - SetSignal(PIN_REQ, ON); + // Assert REQ signal + SetSignal(PIN_REQ, ON); - // Wait for ACK signal - ret = WaitSignal(PIN_ACK, ON); + // Wait for ACK signal + ret = WaitSignal(PIN_ACK, ON); - // Wait until the signal line stabilizes - SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); + // Wait until the signal line stabilizes + SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); - // Get data - buf[offset] = GetDAT(); + // Get data + buf[offset] = GetDAT(); - // Clear the REQ signal - SetSignal(PIN_REQ, OFF); + // Clear the REQ signal + SetSignal(PIN_REQ, OFF); - // Check for timeout waiting for ACK assertion - if (!ret) { - break; - } + // Check for timeout waiting for ACK assertion + if (!ret) { + break; + } - // Wait for ACK to clear - ret = WaitSignal(PIN_ACK, OFF); + // Wait for ACK to clear + ret = WaitSignal(PIN_ACK, OFF); - // Check for timeout waiting for ACK to clear - if (!ret) { - break; - } - } + // Check for timeout waiting for ACK to clear + if (!ret) { + break; + } + } - EnableIRQ(); + EnableIRQ(); - return bytes_received; + return bytes_received; } //--------------------------------------------------------------------------- @@ -559,99 +806,97 @@ int GPIOBUS::CommandHandShake(vector& buf) //--------------------------------------------------------------------------- int GPIOBUS::ReceiveHandShake(uint8_t *buf, int count) { - GPIO_FUNCTION_TRACE + int i; - int i; + // Disable IRQs + DisableIRQ(); - // Disable IRQs - DisableIRQ(); + if (actmode == mode_e::TARGET) { + for (i = 0; i < count; i++) { + // Assert the REQ signal + SetSignal(PIN_REQ, ON); - if (actmode == mode_e::TARGET) { - for (i = 0; i < count; i++) { - // Assert the REQ signal - SetSignal(PIN_REQ, ON); + // Wait for ACK + bool ret = WaitSignal(PIN_ACK, ON); - // Wait for ACK - bool ret = WaitSignal(PIN_ACK, ON); + // Wait until the signal line stabilizes + SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); - // Wait until the signal line stabilizes - SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); + // Get data + *buf = GetDAT(); - // Get data - *buf = GetDAT(); + // Clear the REQ signal + SetSignal(PIN_REQ, OFF); - // Clear the REQ signal - SetSignal(PIN_REQ, OFF); + // Check for timeout waiting for ACK signal + if (!ret) { + break; + } - // Check for timeout waiting for ACK signal - if (!ret) { - break; - } + // Wait for ACK to clear + ret = WaitSignal(PIN_ACK, OFF); - // Wait for ACK to clear - ret = WaitSignal(PIN_ACK, OFF); + // Check for timeout waiting for ACK to clear + if (!ret) { + break; + } - // Check for timeout waiting for ACK to clear - if (!ret) { - break; - } + // Advance the buffer pointer to receive the next byte + buf++; + } + } else { + // Get phase + uint32_t phase = Acquire() & GPIO_MCI; - // Advance the buffer pointer to receive the next byte - buf++; - } - } else { - // Get phase - uint32_t phase = Acquire() & GPIO_MCI; + for (i = 0; i < count; i++) { + // Wait for the REQ signal to be asserted + bool ret = WaitSignal(PIN_REQ, ON); - for (i = 0; i < count; i++) { - // Wait for the REQ signal to be asserted - bool ret = WaitSignal(PIN_REQ, ON); + // Check for timeout waiting for REQ signal + if (!ret) { + break; + } - // Check for timeout waiting for REQ signal - if (!ret) { - break; - } + // Phase error + if ((signals & GPIO_MCI) != phase) { + break; + } - // Phase error - if ((signals & GPIO_MCI) != phase) { - break; - } + // Wait until the signal line stabilizes + SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); - // Wait until the signal line stabilizes - SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS); + // Get data + *buf = GetDAT(); - // Get data - *buf = GetDAT(); + // Assert the ACK signal + SetSignal(PIN_ACK, ON); - // Assert the ACK signal - SetSignal(PIN_ACK, ON); + // Wait for REQ to clear + ret = WaitSignal(PIN_REQ, OFF); - // Wait for REQ to clear - ret = WaitSignal(PIN_REQ, OFF); + // Clear the ACK signal + SetSignal(PIN_ACK, OFF); - // Clear the ACK signal - SetSignal(PIN_ACK, OFF); + // Check for timeout waiting for REQ to clear + if (!ret) { + break; + } - // Check for timeout waiting for REQ to clear - if (!ret) { - break; - } + // Phase error + if ((signals & GPIO_MCI) != phase) { + break; + } - // Phase error - if ((signals & GPIO_MCI) != phase) { - break; - } + // Advance the buffer pointer to receive the next byte + buf++; + } + } - // Advance the buffer pointer to receive the next byte - buf++; - } - } + // Re-enable IRQ + EnableIRQ(); - // Re-enable IRQ - EnableIRQ(); - - // Return the number of bytes received - return i; + // Return the number of bytes received + return i; } //--------------------------------------------------------------------------- @@ -661,112 +906,108 @@ int GPIOBUS::ReceiveHandShake(uint8_t *buf, int count) //--------------------------------------------------------------------------- int GPIOBUS::SendHandShake(uint8_t *buf, int count, int delay_after_bytes) { - GPIO_FUNCTION_TRACE + int i; - int i; + // Disable IRQs + DisableIRQ(); - // Disable IRQs - DisableIRQ(); + if (actmode == mode_e::TARGET) { + for (i = 0; i < count; i++) { + if(i==delay_after_bytes){ + LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes) + SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US); + } - if (actmode == mode_e::TARGET) { - for (i = 0; i < count; i++) { - if (i == delay_after_bytes) { - LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, - (int)delay_after_bytes) - SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US); - } + // Set the DATA signals + SetDAT(*buf); - // Set the DATA signals - SetDAT(*buf); + // Wait for ACK to clear + bool ret = WaitSignal(PIN_ACK, OFF); - // Wait for ACK to clear - bool ret = WaitSignal(PIN_ACK, OFF); + // Check for timeout waiting for ACK to clear + if (!ret) { + break; + } - // Check for timeout waiting for ACK to clear - if (!ret) { - break; - } + // Already waiting for ACK to clear - // Already waiting for ACK to clear + // Assert the REQ signal + SetSignal(PIN_REQ, ON); - // Assert the REQ signal - SetSignal(PIN_REQ, ON); + // Wait for ACK + ret = WaitSignal(PIN_ACK, ON); - // Wait for ACK - ret = WaitSignal(PIN_ACK, ON); + // Clear REQ signal + SetSignal(PIN_REQ, OFF); - // Clear REQ signal - SetSignal(PIN_REQ, OFF); + // Check for timeout waiting for ACK to clear + if (!ret) { + break; + } - // Check for timeout waiting for ACK to clear - if (!ret) { - break; - } + // Advance the data buffer pointer to receive the next byte + buf++; + } - // Advance the data buffer pointer to receive the next byte - buf++; - } + // Wait for ACK to clear + WaitSignal(PIN_ACK, OFF); + } else { + // Get Phase + uint32_t phase = Acquire() & GPIO_MCI; - // Wait for ACK to clear - WaitSignal(PIN_ACK, OFF); - } else { - // Get Phase - uint32_t phase = Acquire() & GPIO_MCI; + for (i = 0; i < count; i++) { + if(i==delay_after_bytes){ + LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, (int)delay_after_bytes) + SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US); + } - for (i = 0; i < count; i++) { - if (i == delay_after_bytes) { - LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US, - (int)delay_after_bytes) - SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US); - } + // Set the DATA signals + SetDAT(*buf); - // Set the DATA signals - SetDAT(*buf); + // Wait for REQ to be asserted + bool ret = WaitSignal(PIN_REQ, ON); - // Wait for REQ to be asserted - bool ret = WaitSignal(PIN_REQ, ON); + // Check for timeout waiting for REQ to be asserted + if (!ret) { + break; + } - // Check for timeout waiting for REQ to be asserted - if (!ret) { - break; - } + // Phase error + if ((signals & GPIO_MCI) != phase) { + break; + } - // Phase error - if ((signals & GPIO_MCI) != phase) { - break; - } + // Already waiting for REQ assertion - // Already waiting for REQ assertion + // Assert the ACK signal + SetSignal(PIN_ACK, ON); - // Assert the ACK signal - SetSignal(PIN_ACK, ON); + // Wait for REQ to clear + ret = WaitSignal(PIN_REQ, OFF); - // Wait for REQ to clear - ret = WaitSignal(PIN_REQ, OFF); + // Clear the ACK signal + SetSignal(PIN_ACK, OFF); - // Clear the ACK signal - SetSignal(PIN_ACK, OFF); + // Check for timeout waiting for REQ to clear + if (!ret) { + break; + } - // Check for timeout waiting for REQ to clear - if (!ret) { - break; - } + // Phase error + if ((signals & GPIO_MCI) != phase) { + break; + } - // Phase error - if ((signals & GPIO_MCI) != phase) { - break; - } + // Advance the data buffer pointer to receive the next byte + buf++; + } + } - // Advance the data buffer pointer to receive the next byte - buf++; - } - } + // Re-enable IRQ + EnableIRQ(); - // Re-enable IRQ - EnableIRQ(); - - // Return number of transmissions - return i; + // Return number of transmissions + return i; } #ifdef USE_SEL_EVENT_ENABLE @@ -777,22 +1018,19 @@ int GPIOBUS::SendHandShake(uint8_t *buf, int count, int delay_after_bytes) //--------------------------------------------------------------------------- bool GPIOBUS::PollSelectEvent() { - GPIO_FUNCTION_TRACE - errno = 0; + errno = 0; - if (epoll_event epev; epoll_wait(epfd, &epev, 1, -1) <= 0) { - LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__) - LOGWARN("[%08X] %s", errno, strerror(errno)) + if (epoll_event epev; epoll_wait(epfd, &epev, 1, -1) <= 0) { + LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__) + return false; + } + + if (gpioevent_data gpev; read(selevreq.fd, &gpev, sizeof(gpev)) < 0) { + LOGWARN("%s read failed", __PRETTY_FUNCTION__) return false; - } + } - if (gpioevent_data gpev; read(selevreq.fd, &gpev, sizeof(gpev)) < 0) { - LOGWARN("%s read failed", __PRETTY_FUNCTION__) - LOGWARN("[%08X] %s", errno, strerror(errno)) - return false; - } - - return true; + return true; } //--------------------------------------------------------------------------- @@ -802,18 +1040,21 @@ bool GPIOBUS::PollSelectEvent() //--------------------------------------------------------------------------- void GPIOBUS::ClearSelectEvent() { - GPIO_FUNCTION_TRACE } -#endif // USE_SEL_EVENT_ENABLE +#endif // USE_SEL_EVENT_ENABLE //--------------------------------------------------------------------------- // // Signal table // //--------------------------------------------------------------------------- -const array GPIOBUS::SignalTable = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6, - PIN_DT7, PIN_DP, PIN_SEL, PIN_ATN, PIN_RST, PIN_ACK, PIN_BSY, - PIN_MSG, PIN_CD, PIN_IO, PIN_REQ, -1}; +const array GPIOBUS::SignalTable = { + PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, + PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP, + PIN_SEL,PIN_ATN, PIN_RST, PIN_ACK, + PIN_BSY, PIN_MSG, PIN_CD, PIN_IO, PIN_REQ, + -1 +}; //--------------------------------------------------------------------------- // @@ -822,92 +1063,170 @@ const array GPIOBUS::SignalTable = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, //--------------------------------------------------------------------------- void GPIOBUS::MakeTable(void) { - GPIO_FUNCTION_TRACE + const array pintbl = { + PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, + PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP + }; - const array pintbl = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP}; + array tblParity; - array tblParity; - - // Create parity table - for (uint32_t i = 0; i < 0x100; i++) { - uint32_t bits = i; - uint32_t parity = 0; - for (int j = 0; j < 8; j++) { - parity ^= bits & 1; - bits >>= 1; - } - parity = ~parity; - tblParity[i] = parity & 1; - } + // Create parity table + for (uint32_t i = 0; i < 0x100; i++) { + uint32_t bits = i; + uint32_t parity = 0; + for (int j = 0; j < 8; j++) { + parity ^= bits & 1; + bits >>= 1; + } + parity = ~parity; + tblParity[i] = parity & 1; + } #if SIGNAL_CONTROL_MODE == 0 - // Mask and setting data generation - for (auto &tbl : tblDatMsk) { - tbl.fill(-1); - } - for (auto &tbl : tblDatSet) { - tbl.fill(0); - } + // Mask and setting data generation + for (auto& tbl : tblDatMsk) { + tbl.fill(-1); + } + for (auto& tbl : tblDatSet) { + tbl.fill(0); + } - for (uint32_t i = 0; i < 0x100; i++) { - // Bit string for inspection - uint32_t bits = i; + for (uint32_t i = 0; i < 0x100; i++) { + // Bit string for inspection + uint32_t bits = i; - // Get parity - if (tblParity[i]) { - bits |= (1 << 8); - } + // Get parity + if (tblParity[i]) { + bits |= (1 << 8); + } - // Bit check - for (int j = 0; j < 9; j++) { - // Index and shift amount calculation - int index = pintbl[j] / 10; - int shift = (pintbl[j] % 10) * 3; + // Bit check + for (int j = 0; j < 9; j++) { + // Index and shift amount calculation + int index = pintbl[j] / 10; + int shift = (pintbl[j] % 10) * 3; - // Mask data - tblDatMsk[index][i] &= ~(0x7 << shift); + // Mask data + tblDatMsk[index][i] &= ~(0x7 << shift); - // Setting data - if (bits & 1) { - tblDatSet[index][i] |= (1 << shift); - } + // Setting data + if (bits & 1) { + tblDatSet[index][i] |= (1 << shift); + } - bits >>= 1; - } - } + bits >>= 1; + } + } #else - for (uint32_t i = 0; i < 0x100; i++) { - // Bit string for inspection - uint32_t bits = i; + for (uint32_t i = 0; i < 0x100; i++) { + // Bit string for inspection + uint32_t bits = i; - // Get parity - if (tblParity[i]) { - bits |= (1 << 8); - } + // Get parity + if (tblParity[i]) { + bits |= (1 << 8); + } #if SIGNAL_CONTROL_MODE == 1 - // Negative logic is inverted - bits = ~bits; + // Negative logic is inverted + bits = ~bits; #endif - // Create GPIO register information - uint32_t gpclr = 0; - uint32_t gpset = 0; - for (int j = 0; j < 9; j++) { - if (bits & 1) { - gpset |= (1 << pintbl[j]); - } else { - gpclr |= (1 << pintbl[j]); - } - bits >>= 1; - } + // Create GPIO register information + uint32_t gpclr = 0; + uint32_t gpset = 0; + for (int j = 0; j < 9; j++) { + if (bits & 1) { + gpset |= (1 << pintbl[j]); + } else { + gpclr |= (1 << pintbl[j]); + } + bits >>= 1; + } - tblDatMsk[i] = gpclr; - tblDatSet[i] = gpset; - } + tblDatMsk[i] = gpclr; + tblDatSet[i] = gpset; + } #endif } +//--------------------------------------------------------------------------- +// +// Control signal setting +// +//--------------------------------------------------------------------------- +void GPIOBUS::SetControl(int pin, bool ast) +{ + PinSetSignal(pin, ast); +} + +//--------------------------------------------------------------------------- +// +// Input/output mode setting +// +//--------------------------------------------------------------------------- +void GPIOBUS::SetMode(int pin, int mode) +{ +#if SIGNAL_CONTROL_MODE == 0 + if (mode == OUT) { + return; + } +#endif // SIGNAL_CONTROL_MODE + + int index = pin / 10; + int shift = (pin % 10) * 3; + uint32_t data = gpfsel[index]; + data &= ~(0x7 << shift); + if (mode == OUT) { + data |= (1 << shift); + } + gpio[index] = data; + gpfsel[index] = data; +} + +//--------------------------------------------------------------------------- +// +// Get input signal value +// +//--------------------------------------------------------------------------- +bool GPIOBUS::GetSignal(int pin) const +{ + return (signals >> pin) & 1; +} + +//--------------------------------------------------------------------------- +// +// Set output signal value +// +//--------------------------------------------------------------------------- +void GPIOBUS::SetSignal(int pin, bool ast) +{ +#if SIGNAL_CONTROL_MODE == 0 + int index = pin / 10; + int shift = (pin % 10) * 3; + uint32_t data = gpfsel[index]; + if (ast) { + data |= (1 << shift); + } else { + data &= ~(0x7 << shift); + } + gpio[index] = data; + gpfsel[index] = data; +#elif SIGNAL_CONTROL_MODE == 1 + if (ast) { + gpio[GPIO_CLR_0] = 0x1 << pin; + } else { + gpio[GPIO_SET_0] = 0x1 << pin; + } +#elif SIGNAL_CONTROL_MODE == 2 + if (ast) { + gpio[GPIO_SET_0] = 0x1 << pin; + } else { + gpio[GPIO_CLR_0] = 0x1 << pin; + } +#endif // SIGNAL_CONTROL_MODE +} + //--------------------------------------------------------------------------- // // Wait for signal change @@ -915,32 +1234,160 @@ void GPIOBUS::MakeTable(void) //--------------------------------------------------------------------------- bool GPIOBUS::WaitSignal(int pin, int ast) { - GPIO_FUNCTION_TRACE + // Get current time + uint32_t now = SysTimer::GetTimerLow(); - // Get current time - uint32_t now = SysTimer::GetTimerLow(); + // Calculate timeout (3000ms) + uint32_t timeout = 3000 * 1000; - // Calculate timeout (3000ms) - uint32_t timeout = 3000 * 1000; + // end immediately if the signal has changed + do { + // Immediately upon receiving a reset + Acquire(); + if (GetRST()) { + return false; + } - // end immediately if the signal has changed - do { - // Immediately upon receiving a reset - Acquire(); - if (GetRST()) { - return false; - } - - // Check for the signal edge + // Check for the signal edge if (((signals >> pin) ^ ~ast) & 1) { - return true; - } - } while ((SysTimer::GetTimerLow() - now) < timeout); + return true; + } + } while ((SysTimer::GetTimerLow() - now) < timeout); - // We timed out waiting for the signal - return false; + // We timed out waiting for the signal + return false; } +void GPIOBUS::DisableIRQ() +{ +#ifdef __linux__ + if (rpitype == 4) { + // RPI4 is disabled by GICC + giccpmr = gicc[GICC_PMR]; + gicc[GICC_PMR] = 0; + } else if (rpitype == 2) { + // RPI2,3 disable core timer IRQ + tintcore = sched_getcpu() + QA7_CORE0_TINTC; + tintctl = qa7regs[tintcore]; + qa7regs[tintcore] = 0; + } else { + // Stop system timer interrupt with interrupt controller + irptenb = irpctl[IRPT_ENB_IRQ_1]; + irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf; + } +#else + (void)0; +#endif +} + +void GPIOBUS::EnableIRQ() +{ + if (rpitype == 4) { + // RPI4 enables interrupts via the GICC + gicc[GICC_PMR] = giccpmr; + } else if (rpitype == 2) { + // RPI2,3 re-enable core timer IRQ + qa7regs[tintcore] = tintctl; + } else { + // Restart the system timer interrupt with the interrupt controller + irpctl[IRPT_ENB_IRQ_1] = irptenb & 0xf; + } +} + +//--------------------------------------------------------------------------- +// +// Pin direction setting (input/output) +// +//--------------------------------------------------------------------------- +void GPIOBUS::PinConfig(int pin, int mode) +{ + // Check for invalid pin + if (pin < 0) { + return; + } + + int index = pin / 10; + uint32_t mask = ~(0x7 << ((pin % 10) * 3)); + gpio[index] = (gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3)); +} + +//--------------------------------------------------------------------------- +// +// Pin pull-up/pull-down setting +// +//--------------------------------------------------------------------------- +void GPIOBUS::PullConfig(int pin, int mode) +{ + uint32_t pull; + + // Check for invalid pin + if (pin < 0) { + return; + } + + if (rpitype == 4) { + switch (mode) { + case GPIO_PULLNONE: + pull = 0; + break; + case GPIO_PULLUP: + pull = 1; + break; + case GPIO_PULLDOWN: + pull = 2; + break; + default: + return; + } + + pin &= 0x1f; + int shift = (pin & 0xf) << 1; + uint32_t bits = gpio[GPIO_PUPPDN0 + (pin >> 4)]; + bits &= ~(3 << shift); + bits |= (pull << shift); + gpio[GPIO_PUPPDN0 + (pin >> 4)] = bits; + } else { + pin &= 0x1f; + gpio[GPIO_PUD] = mode & 0x3; + SysTimer::SleepUsec(2); + gpio[GPIO_CLK_0] = 0x1 << pin; + SysTimer::SleepUsec(2); + gpio[GPIO_PUD] = 0; + gpio[GPIO_CLK_0] = 0; + } +} + +//--------------------------------------------------------------------------- +// +// Set output pin +// +//--------------------------------------------------------------------------- +void GPIOBUS::PinSetSignal(int pin, bool ast) +{ + // Check for invalid pin + if (pin < 0) { + return; + } + + if (ast) { + gpio[GPIO_SET_0] = 0x1 << pin; + } else { + gpio[GPIO_CLR_0] = 0x1 << pin; + } +} + +//--------------------------------------------------------------------------- +// +// Set the signal drive strength +// +//--------------------------------------------------------------------------- +void GPIOBUS::DrvConfig(uint32_t drive) +{ + uint32_t data = pads[PAD_0_27]; + pads[PAD_0_27] = (0xFFFFFFF8 & data) | drive | 0x5a000000; +} + + //--------------------------------------------------------------------------- // // Generic Phase Acquisition (Doesn't read GPIO) @@ -948,24 +1395,23 @@ bool GPIOBUS::WaitSignal(int pin, int ast) //--------------------------------------------------------------------------- BUS::phase_t GPIOBUS::GetPhaseRaw(uint32_t raw_data) { - GPIO_FUNCTION_TRACE - // Selection Phase - if (GetPinRaw(raw_data, PIN_SEL)) { - if (GetPinRaw(raw_data, PIN_IO)) { - return BUS::phase_t::reselection; - } else { - return BUS::phase_t::selection; - } - } + // Selection Phase + if (GetPinRaw(raw_data, PIN_SEL)) { + if(GetPinRaw(raw_data, PIN_IO)) { + return BUS::phase_t::reselection; + } else{ + return BUS::phase_t::selection; + } + } - // Bus busy phase - if (!GetPinRaw(raw_data, PIN_BSY)) { - return BUS::phase_t::busfree; - } + // Bus busy phase + if (!GetPinRaw(raw_data, PIN_BSY)) { + return BUS::phase_t::busfree; + } - // Get target phase from bus signal line - int mci = GetPinRaw(raw_data, PIN_MSG) ? 0x04 : 0x00; - mci |= GetPinRaw(raw_data, PIN_CD) ? 0x02 : 0x00; - mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00; - return GetPhase(mci); + // Get target phase from bus signal line + int mci = GetPinRaw(raw_data, PIN_MSG) ? 0x04 : 0x00; + mci |= GetPinRaw(raw_data, PIN_CD) ? 0x02 : 0x00; + mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00; + return GetPhase(mci); } diff --git a/cpp/hal/gpiobus.h b/cpp/hal/gpiobus.h index dc2d3019..56597979 100644 --- a/cpp/hal/gpiobus.h +++ b/cpp/hal/gpiobus.h @@ -15,7 +15,6 @@ #include "scsi.h" #include "bus.h" #include -#include #ifdef __linux__ #include @@ -43,13 +42,7 @@ #error Invalid connection type or none specified #endif -#ifdef ENABLE_GPIO_TRACE -#define GPIO_FUNCTION_TRACE LOGTRACE("%s", __PRETTY_FUNCTION__) -#else -#define GPIO_FUNCTION_TRACE -#endif - -using namespace std; +using namespace std; //NOSONAR Not relevant for rascsi //--------------------------------------------------------------------------- // @@ -125,316 +118,397 @@ using namespace std; // //--------------------------------------------------------------------------- -#define ALL_SCSI_PINS \ - ((1 << PIN_DT0) | (1 << PIN_DT1) | (1 << PIN_DT2) | (1 << PIN_DT3) | (1 << PIN_DT4) | (1 << PIN_DT5) | \ - (1 << PIN_DT6) | (1 << PIN_DT7) | (1 << PIN_DP) | (1 << PIN_ATN) | (1 << PIN_RST) | (1 << PIN_ACK) | \ - (1 << PIN_REQ) | (1 << PIN_MSG) | (1 << PIN_CD) | (1 << PIN_IO) | (1 << PIN_BSY) | (1 << PIN_SEL)) +#define ALL_SCSI_PINS \ + ((1<&) override; - // Command receive handshake - int ReceiveHandShake(uint8_t *buf, int count) override; - // Data receive handshake - int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) override; - // Data transmission handshake + bool GetIO() override; + // Get IO signal + void SetIO(bool ast) override; + // Set IO signal - static BUS::phase_t GetPhaseRaw(uint32_t raw_data); - // Get the phase based on raw data + bool GetREQ() const override; + // Get REQ signal + void SetREQ(bool ast) override; + // Set REQ signal + + uint8_t GetDAT() override; + // Get DAT signal + void SetDAT(uint8_t dat) override; + // Set DAT signal + bool GetDP() const override; + // Get Data parity signal + int CommandHandShake(vector&) override; + // Command receive handshake + int ReceiveHandShake(uint8_t *buf, int count) override; + // Data receive handshake + int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) override; + // Data transmission handshake + + static BUS::phase_t GetPhaseRaw(uint32_t raw_data); + // Get the phase based on raw data #ifdef USE_SEL_EVENT_ENABLE - // SEL signal interrupt - bool PollSelectEvent(); - // SEL signal event polling - void ClearSelectEvent(); - // Clear SEL signal event -#endif // USE_SEL_EVENT_ENABLE - - protected: - // SCSI I/O signal control - virtual void MakeTable() = 0; - // Create work data - virtual void SetControl(int pin, bool ast) = 0; - // Set Control Signal - virtual void SetMode(int pin, int mode) = 0; - // Set SCSI I/O mode - bool GetSignal(int pin) const override = 0; - // Set Control Signal - void SetSignal(int pin, bool ast) override = 0; - // Set SCSI I/O mode - virtual bool WaitSignal(int pin, int ast) = 0; - // Wait for a signal to change - // Interrupt control - virtual void DisableIRQ() = 0; - // IRQ Disabled - virtual void EnableIRQ() = 0; - // IRQ Enabled - - // GPIO pin functionality settings - virtual void PinConfig(int pin, int mode) = 0; - // GPIO pin direction setting - virtual void PullConfig(int pin, int mode) = 0; - // GPIO pin pull up/down resistor setting - virtual void PinSetSignal(int pin, bool ast) = 0; - // Set GPIO output signal - virtual void DrvConfig(uint32_t drive) = 0; - // Set GPIO drive strength - - mode_e actmode = mode_e::TARGET; // Operation mode - -#if !defined(__x86_64__) && !defined(__X86__) - uint32_t baseaddr = 0; // Base address + // SEL signal interrupt + bool PollSelectEvent() override; + // SEL signal event polling + void ClearSelectEvent() override; + // Clear SEL signal event #endif - static const array SignalTable; // signal table +private: + // SCSI I/O signal control + void MakeTable(); + // Create work data + void SetControl(int pin, bool ast); + // Set Control Signal + void SetMode(int pin, int mode); + // Set SCSI I/O mode + bool GetSignal(int pin) const override; + // Get SCSI input signal value + void SetSignal(int pin, bool ast) override; + // Set SCSI output signal value + bool WaitSignal(int pin, int ast); + // Wait for a signal to change + // Interrupt control + void DisableIRQ(); + // IRQ Disabled + void EnableIRQ(); + // IRQ Enabled + + // GPIO pin functionality settings + void PinConfig(int pin, int mode); + // GPIO pin direction setting + void PullConfig(int pin, int mode); + // GPIO pin pull up/down resistor setting + void PinSetSignal(int pin, bool ast); + // Set GPIO output signal + void DrvConfig(uint32_t drive); + // Set GPIO drive strength + + + mode_e actmode = mode_e::TARGET; // Operation mode + +#if !defined(__x86_64__) && !defined(__X86__) + uint32_t baseaddr = 0; // Base address +#endif + + int rpitype = 0; // Type of Raspberry Pi + + volatile uint32_t *gpio = nullptr; // GPIO register + + volatile uint32_t *pads = nullptr; // PADS register + +#if !defined(__x86_64__) && !defined(__X86__) + volatile uint32_t *level = nullptr; // GPIO input level +#endif + + volatile uint32_t *irpctl = nullptr; // Interrupt control register + + volatile uint32_t irptenb; // Interrupt enabled state + + volatile uint32_t *qa7regs = nullptr; // QA7 register + + volatile int tintcore; // Interupt control target CPU. + + volatile uint32_t tintctl; // Interupt control + + volatile uint32_t giccpmr; // GICC priority setting + +#if !defined(__x86_64__) && !defined(__X86__) + volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register +#endif + + volatile uint32_t *gicc = nullptr; // GIC CPU interface register + + array gpfsel; // GPFSEL0-4 backup values + + uint32_t signals = 0; // All bus signals #ifdef USE_SEL_EVENT_ENABLE - struct gpioevent_request selevreq = {}; // SEL signal event request + struct gpioevent_request selevreq = {}; // SEL signal event request - int epfd; // epoll file descriptor -#endif // USE_SEL_EVENT_ENABLE - - private: - int rpitype = 0; // Type of Raspberry Pi - - volatile uint32_t *gpio = nullptr; // GPIO register - - volatile uint32_t *pads = nullptr; // PADS register - -#if !defined(__x86_64__) && !defined(__X86__) - volatile uint32_t *level = nullptr; // GPIO input level -#endif - - volatile uint32_t *irpctl = nullptr; // Interrupt control register - - volatile uint32_t irptenb; // Interrupt enabled state - - volatile uint32_t *qa7regs = nullptr; // QA7 register - - volatile int tintcore; // Interupt control target CPU. - - volatile uint32_t tintctl; // Interupt control - - volatile uint32_t giccpmr; // GICC priority setting - -#if !defined(__x86_64__) && !defined(__X86__) - volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register -#endif - - volatile uint32_t *gicc = nullptr; // GIC CPU interface register - - array gpfsel; // GPFSEL0-4 backup values - - uint32_t signals = 0; // All bus signals + int epfd; // epoll file descriptor +#endif // USE_SEL_EVENT_ENABLE #if SIGNAL_CONTROL_MODE == 0 - array, 3> tblDatMsk; // Data mask table + array, 3> tblDatMsk; // Data mask table - array, 3> tblDatSet; // Data setting table + array, 3> tblDatSet; // Data setting table #else - array tblDatMsk = {}; // Data mask table + array tblDatMsk = {}; // Data mask table - array tblDatSet = {}; // Table setting table + array tblDatSet = {}; // Table setting table #endif + + static const array SignalTable; // signal table }; + diff --git a/cpp/hal/gpiobus_aibom.h b/cpp/hal/gpiobus_aibom.h index 6fbb0425..01f1f9e6 100644 --- a/cpp/hal/gpiobus_aibom.h +++ b/cpp/hal/gpiobus_aibom.h @@ -16,41 +16,41 @@ // RaSCSI Adapter Aibom version // -const std::string CONNECT_DESC = "AIBOM PRODUCTS version"; // Startup message +const std::string CONNECT_DESC = "AIBOM PRODUCTS version"; // Startup message // Select signal control mode -const static int SIGNAL_CONTROL_MODE = 2; // SCSI positive logic specification +const static int SIGNAL_CONTROL_MODE = 2; // SCSI positive logic specification // Control signal output logic -#define ACT_ON ON // ACTIVE SIGNAL ON -#define ENB_ON ON // ENABLE SIGNAL ON -#define IND_IN OFF // INITIATOR SIGNAL INPUT -#define TAD_IN OFF // TARGET SIGNAL INPUT -#define DTD_IN OFF // DATA SIGNAL INPUT +#define ACT_ON ON // ACTIVE SIGNAL ON +#define ENB_ON ON // ENABLE SIGNAL ON +#define IND_IN OFF // INITIATOR SIGNAL INPUT +#define TAD_IN OFF // TARGET SIGNAL INPUT +#define DTD_IN OFF // DATA SIGNAL INPUT // Control signal pin assignment (-1 means no control) -const static int PIN_ACT = 4; // ACTIVE -const static int PIN_ENB = 17; // ENABLE -const static int PIN_IND = 27; // INITIATOR CTRL DIRECTION -const static int PIN_TAD = -1; // TARGET CTRL DIRECTION -const static int PIN_DTD = 18; // DATA DIRECTION +const static int PIN_ACT = 4; // ACTIVE +const static int PIN_ENB = 17; // ENABLE +const static int PIN_IND = 27; // INITIATOR CTRL DIRECTION +const static int PIN_TAD = -1; // TARGET CTRL DIRECTION +const static int PIN_DTD = 18; // DATA DIRECTION // SCSI signal pin assignment -const static int PIN_DT0 = 6; // Data 0 -const static int PIN_DT1 = 12; // Data 1 -const static int PIN_DT2 = 13; // Data 2 -const static int PIN_DT3 = 16; // Data 3 -const static int PIN_DT4 = 19; // Data 4 -const static int PIN_DT5 = 20; // Data 5 -const static int PIN_DT6 = 26; // Data 6 -const static int PIN_DT7 = 21; // Data 7 -const static int PIN_DP = 5; // Data parity -const static int PIN_ATN = 22; // ATN -const static int PIN_RST = 25; // RST -const static int PIN_ACK = 10; // ACK -const static int PIN_REQ = 7; // REQ -const static int PIN_MSG = 9; // MSG -const static int PIN_CD = 11; // CD -const static int PIN_IO = 23; // IO -const static int PIN_BSY = 24; // BSY -const static int PIN_SEL = 8; // SEL +const static int PIN_DT0 = 6; // Data 0 +const static int PIN_DT1 = 12; // Data 1 +const static int PIN_DT2 = 13; // Data 2 +const static int PIN_DT3 = 16; // Data 3 +const static int PIN_DT4 = 19; // Data 4 +const static int PIN_DT5 = 20; // Data 5 +const static int PIN_DT6 = 26; // Data 6 +const static int PIN_DT7 = 21; // Data 7 +const static int PIN_DP = 5; // Data parity +const static int PIN_ATN = 22; // ATN +const static int PIN_RST = 25; // RST +const static int PIN_ACK = 10; // ACK +const static int PIN_REQ = 7; // REQ +const static int PIN_MSG = 9; // MSG +const static int PIN_CD = 11; // CD +const static int PIN_IO = 23; // IO +const static int PIN_BSY = 24; // BSY +const static int PIN_SEL = 8; // SEL diff --git a/cpp/hal/gpiobus_allwinner.cpp b/cpp/hal/gpiobus_allwinner.cpp deleted file mode 100644 index 8d45047d..00000000 --- a/cpp/hal/gpiobus_allwinner.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// -// [ GPIO-SCSI bus ] -// -//--------------------------------------------------------------------------- - -#include "hal/gpiobus_allwinner.h" -#include "hal/gpiobus.h" -#include "log.h" - -extern int wiringPiMode; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -bool GPIOBUS_Allwinner::Init(mode_e mode) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) - return false; -} - -void GPIOBUS_Allwinner::Cleanup() -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::Reset(){LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__)} - -uint8_t GPIOBUS_Allwinner::GetDAT() -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) - return 0; -} - -void GPIOBUS_Allwinner::SetDAT(uint8_t dat) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::MakeTable(void) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::SetControl(int pin, bool ast) -{ - GPIOBUS_Allwinner::SetSignal(pin, ast); -} - -void GPIOBUS_Allwinner::SetMode(int pin, int mode) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -bool GPIOBUS_Allwinner::GetSignal(int pin) const -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) - return false; - // return (digitalRead(pin) != 0); -} - -void GPIOBUS_Allwinner::SetSignal(int pin, bool ast) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -bool GPIOBUS_Allwinner::WaitSignal(int pin, int ast) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) - return false; -} - -void GPIOBUS_Allwinner::DisableIRQ() -{ - LOGERROR("%s not implemented!!", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::EnableIRQ() -{ - LOGERROR("%s not implemented!!", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::PinConfig(int pin, int mode) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::PullConfig(int pin, int mode) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::PinSetSignal(int pin, bool ast) -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) -} - -void GPIOBUS_Allwinner::DrvConfig(uint32_t drive) -{ - (void)drive; - LOGERROR("%s not implemented!!", __PRETTY_FUNCTION__) -} - -uint32_t GPIOBUS_Allwinner::Acquire() -{ - LOGWARN("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__) - // Only used for development/debugging purposes. Isn't really applicable - // to any real-world RaSCSI application - return 0; -} - -#pragma GCC diagnostic pop \ No newline at end of file diff --git a/cpp/hal/gpiobus_allwinner.h b/cpp/hal/gpiobus_allwinner.h deleted file mode 100644 index 959cd9a4..00000000 --- a/cpp/hal/gpiobus_allwinner.h +++ /dev/null @@ -1,128 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// [ GPIO-SCSI bus ] -// -//--------------------------------------------------------------------------- - -#pragma once - -#include "config.h" -#include "hal/gpiobus.h" -#include "log.h" -#include "scsi.h" - -//--------------------------------------------------------------------------- -// -// Class definition -// -//--------------------------------------------------------------------------- -class GPIOBUS_Allwinner : public GPIOBUS -{ - public: - // Basic Functions - GPIOBUS_Allwinner() = default; - ~GPIOBUS_Allwinner() override = default; - // Destructor - bool Init(mode_e mode = mode_e::TARGET) override; - // Initialization - void Reset() override; - // Reset - void Cleanup() override; - // Cleanup - - //--------------------------------------------------------------------------- - // - // Bus signal acquisition - // - //--------------------------------------------------------------------------- - uint32_t Acquire() override; - - uint8_t GetDAT() override; - // Get DAT signal - void SetDAT(uint8_t dat) override; - // Set DAT signal - protected: - // SCSI I/O signal control - void MakeTable() override; - // Create work data - void SetControl(int pin, bool ast) override; - // Set Control Signal - void SetMode(int pin, int mode) override; - // Set SCSI I/O mode - bool GetSignal(int pin) const override; - // Get SCSI input signal value - void SetSignal(int pin, bool ast) override; - // Set SCSI output signal value - bool WaitSignal(int pin, int ast) override; - // Wait for a signal to change - // Interrupt control - void DisableIRQ() override; - // IRQ Disabled - void EnableIRQ() override; - // IRQ Enabled - - // GPIO pin functionality settings - void PinConfig(int pin, int mode) override; - // GPIO pin direction setting - void PullConfig(int pin, int mode) override; - // GPIO pin pull up/down resistor setting - void PinSetSignal(int pin, bool ast) override; - // Set GPIO output signal - void DrvConfig(uint32_t drive) override; - // Set GPIO drive strength - -#if !defined(__x86_64__) && !defined(__X86__) - uint32_t baseaddr = 0; // Base address -#endif - - volatile uint32_t *gpio = nullptr; // GPIO register - - volatile uint32_t *pads = nullptr; // PADS register - -#if !defined(__x86_64__) && !defined(__X86__) - volatile uint32_t *level = nullptr; // GPIO input level -#endif - - volatile uint32_t *irpctl = nullptr; // Interrupt control register - - volatile uint32_t irptenb; // Interrupt enabled state - - volatile uint32_t *qa7regs = nullptr; // QA7 register - - volatile int tintcore; // Interupt control target CPU. - - volatile uint32_t tintctl; // Interupt control - - volatile uint32_t giccpmr; // GICC priority setting - -#if !defined(__x86_64__) && !defined(__X86__) - volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register -#endif - - volatile uint32_t *gicc = nullptr; // GIC CPU interface register - - array gpfsel; // GPFSEL0-4 backup values - - uint32_t signals = 0; // All bus signals - -#ifdef USE_SEL_EVENT_ENABLE - struct gpioevent_request selevreq = {}; // SEL signal event request - - int epfd; // epoll file descriptor -#endif // USE_SEL_EVENT_ENABLE - -#if SIGNAL_CONTROL_MODE == 0 - array, 3> tblDatMsk; // Data mask table - - array, 3> tblDatSet; // Data setting table -#else - array tblDatMsk = {}; // Data mask table - - array tblDatSet = {}; // Table setting table -#endif -}; diff --git a/cpp/hal/gpiobus_factory.cpp b/cpp/hal/gpiobus_factory.cpp index 6e0ae96d..a6305c30 100644 --- a/cpp/hal/gpiobus_factory.cpp +++ b/cpp/hal/gpiobus_factory.cpp @@ -4,27 +4,24 @@ // for Raspberry Pi // // Copyright (C) 2022 akuker -// [ GPIO bus factory ] // //--------------------------------------------------------------------------- -#include - -#include "hal/gpiobus_allwinner.h" #include "hal/gpiobus_factory.h" -#include "hal/gpiobus_raspberry.h" -#include "hal/sbc_version.h" -#include "log.h" +#include "hal/gpiobus.h" using namespace std; -unique_ptr GPIOBUS_Factory::Create() +unique_ptr GPIOBUS_Factory::Create(BUS::mode_e mode) { - if (SBC_Version::IsBananaPi()) { - LOGTRACE("Creating GPIOBUS_Allwinner") - return make_unique(); - } else { - LOGTRACE("Creating GPIOBUS_Raspberry") - return make_unique(); - } + // TODO Make the factory a friend of GPIOBUS and make the GPIOBUS constructor private + // so that clients cannot use it anymore but have to use the factory. + // Also make Init() private. + if (auto bus = make_unique(); bus->Init(mode)) { + bus->Reset(); + + return bus; + } + + return nullptr; } diff --git a/cpp/hal/gpiobus_factory.h b/cpp/hal/gpiobus_factory.h index cc0bac8a..a62f47a6 100644 --- a/cpp/hal/gpiobus_factory.h +++ b/cpp/hal/gpiobus_factory.h @@ -3,22 +3,20 @@ // SCSI Target Emulator RaSCSI Reloaded // for Raspberry Pi // -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// [ GPIO-SCSI bus ] +// Copyright (C) 2022 akuker // //--------------------------------------------------------------------------- #pragma once +#include "bus.h" #include -#include "gpiobus.h" - using namespace std; class GPIOBUS_Factory { public: - static unique_ptr Create(); + + static unique_ptr Create(BUS::mode_e); }; diff --git a/cpp/hal/gpiobus_fullspec.h b/cpp/hal/gpiobus_fullspec.h index 9f47eb07..ee62c6d5 100644 --- a/cpp/hal/gpiobus_fullspec.h +++ b/cpp/hal/gpiobus_fullspec.h @@ -16,41 +16,41 @@ // RaSCSI standard (SCSI logic, standard pin assignment) // -const std::string CONNECT_DESC = "FULLSPEC"; // Startup message +const std::string CONNECT_DESC = "FULLSPEC"; // Startup message // Select signal control mode -const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification +const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification // Control signal pin assignment (-1 means no control) -const static int PIN_ACT = 4; // ACTIVE -const static int PIN_ENB = 5; // ENABLE -const static int PIN_IND = 6; // INITIATOR CTRL DIRECTION -const static int PIN_TAD = 7; // TARGET CTRL DIRECTION -const static int PIN_DTD = 8; // DATA DIRECTION +const static int PIN_ACT = 4; // ACTIVE +const static int PIN_ENB = 5; // ENABLE +const static int PIN_IND = 6; // INITIATOR CTRL DIRECTION +const static int PIN_TAD = 7; // TARGET CTRL DIRECTION +const static int PIN_DTD = 8; // DATA DIRECTION // Control signal output logic -#define ACT_ON ON // ACTIVE SIGNAL ON -#define ENB_ON ON // ENABLE SIGNAL ON -#define IND_IN OFF // INITIATOR SIGNAL INPUT -#define TAD_IN OFF // TARGET SIGNAL INPUT -#define DTD_IN ON // DATA SIGNAL INPUT +#define ACT_ON ON // ACTIVE SIGNAL ON +#define ENB_ON ON // ENABLE SIGNAL ON +#define IND_IN OFF // INITIATOR SIGNAL INPUT +#define TAD_IN OFF // TARGET SIGNAL INPUT +#define DTD_IN ON // DATA SIGNAL INPUT // SCSI signal pin assignment -const static int PIN_DT0 = 10; // Data 0 -const static int PIN_DT1 = 11; // Data 1 -const static int PIN_DT2 = 12; // Data 2 -const static int PIN_DT3 = 13; // Data 3 -const static int PIN_DT4 = 14; // Data 4 -const static int PIN_DT5 = 15; // Data 5 -const static int PIN_DT6 = 16; // Data 6 -const static int PIN_DT7 = 17; // Data 7 -const static int PIN_DP = 18; // Data parity -const static int PIN_ATN = 19; // ATN -const static int PIN_RST = 20; // RST -const static int PIN_ACK = 21; // ACK -const static int PIN_REQ = 22; // REQ -const static int PIN_MSG = 23; // MSG -const static int PIN_CD = 24; // CD -const static int PIN_IO = 25; // IO -const static int PIN_BSY = 26; // BSY -const static int PIN_SEL = 27; // SEL +const static int PIN_DT0 = 10; // Data 0 +const static int PIN_DT1 = 11; // Data 1 +const static int PIN_DT2 = 12; // Data 2 +const static int PIN_DT3 = 13; // Data 3 +const static int PIN_DT4 = 14; // Data 4 +const static int PIN_DT5 = 15; // Data 5 +const static int PIN_DT6 = 16; // Data 6 +const static int PIN_DT7 = 17; // Data 7 +const static int PIN_DP = 18; // Data parity +const static int PIN_ATN = 19; // ATN +const static int PIN_RST = 20; // RST +const static int PIN_ACK = 21; // ACK +const static int PIN_REQ = 22; // REQ +const static int PIN_MSG = 23; // MSG +const static int PIN_CD = 24; // CD +const static int PIN_IO = 25; // IO +const static int PIN_BSY = 26; // BSY +const static int PIN_SEL = 27; // SEL diff --git a/cpp/hal/gpiobus_gamernium.h b/cpp/hal/gpiobus_gamernium.h index ca4e0d76..bf295284 100644 --- a/cpp/hal/gpiobus_gamernium.h +++ b/cpp/hal/gpiobus_gamernium.h @@ -16,41 +16,42 @@ // RaSCSI Adapter GAMERnium.com version // -const std::string CONNECT_DESC = "GAMERnium.com version"; // Startup message +const std::string CONNECT_DESC = "GAMERnium.com version"; // Startup message // Select signal control mode -const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification +const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification // Control signal output logic -#define ACT_ON ON // ACTIVE SIGNAL ON -#define ENB_ON ON // ENABLE SIGNAL ON -#define IND_IN OFF // INITIATOR SIGNAL INPUT -#define TAD_IN OFF // TARGET SIGNAL INPUT -#define DTD_IN ON // DATA SIGNAL INPUT +#define ACT_ON ON // ACTIVE SIGNAL ON +#define ENB_ON ON // ENABLE SIGNAL ON +#define IND_IN OFF // INITIATOR SIGNAL INPUT +#define TAD_IN OFF // TARGET SIGNAL INPUT +#define DTD_IN ON // DATA SIGNAL INPUT // Control signal pin assignment (-1 means no control) -const static int PIN_ACT = 14; // ACTIVE -const static int PIN_ENB = 6; // ENABLE -const static int PIN_IND = 7; // INITIATOR CTRL DIRECTION -const static int PIN_TAD = 8; // TARGET CTRL DIRECTION -const static int PIN_DTD = 5; // DATA DIRECTION +const static int PIN_ACT = 14; // ACTIVE +const static int PIN_ENB = 6; // ENABLE +const static int PIN_IND = 7; // INITIATOR CTRL DIRECTION +const static int PIN_TAD = 8; // TARGET CTRL DIRECTION +const static int PIN_DTD = 5; // DATA DIRECTION // SCSI signal pin assignment -const static int PIN_DT0 = 21; // Data 0 -const static int PIN_DT1 = 26; // Data 1 -const static int PIN_DT2 = 20; // Data 2 -const static int PIN_DT3 = 19; // Data 3 -const static int PIN_DT4 = 16; // Data 4 -const static int PIN_DT5 = 13; // Data 5 -const static int PIN_DT6 = 12; // Data 6 -const static int PIN_DT7 = 11; // Data 7 -const static int PIN_DP = 25; // Data parity -const static int PIN_ATN = 10; // ATN -const static int PIN_RST = 22; // RST -const static int PIN_ACK = 24; // ACK -const static int PIN_REQ = 15; // REQ -const static int PIN_MSG = 17; // MSG -const static int PIN_CD = 18; // CD -const static int PIN_IO = 4; // IO -const static int PIN_BSY = 27; // BSY -const static int PIN_SEL = 23; // SEL +const static int PIN_DT0 = 21; // Data 0 +const static int PIN_DT1 = 26; // Data 1 +const static int PIN_DT2 = 20; // Data 2 +const static int PIN_DT3 = 19; // Data 3 +const static int PIN_DT4 = 16; // Data 4 +const static int PIN_DT5 = 13; // Data 5 +const static int PIN_DT6 = 12; // Data 6 +const static int PIN_DT7 = 11; // Data 7 +const static int PIN_DP = 25; // Data parity +const static int PIN_ATN = 10; // ATN +const static int PIN_RST = 22; // RST +const static int PIN_ACK = 24; // ACK +const static int PIN_REQ = 15; // REQ +const static int PIN_MSG = 17; // MSG +const static int PIN_CD = 18; // CD +const static int PIN_IO = 4; // IO +const static int PIN_BSY = 27; // BSY +const static int PIN_SEL = 23; // SEL + diff --git a/cpp/hal/gpiobus_raspberry.cpp b/cpp/hal/gpiobus_raspberry.cpp deleted file mode 100644 index 66d3807b..00000000 --- a/cpp/hal/gpiobus_raspberry.cpp +++ /dev/null @@ -1,856 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// -// [ GPIO-SCSI bus ] -// -//--------------------------------------------------------------------------- - -#include - -#include "config.h" -#include "hal/gpiobus.h" -#include "hal/gpiobus_raspberry.h" -#include "hal/systimer.h" -#include "log.h" -#include -#include -#include -#include -#include - -#ifdef __linux__ -//--------------------------------------------------------------------------- -// -// imported from bcm_host.c -// -//--------------------------------------------------------------------------- -static uint32_t get_dt_ranges(const char *filename, uint32_t offset) -{ - GPIO_FUNCTION_TRACE - uint32_t address = ~0; - if (FILE *fp = fopen(filename, "rb"); fp) { - fseek(fp, offset, SEEK_SET); - if (array buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) { - address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0; - } - fclose(fp); - } - return address; -} - -uint32_t bcm_host_get_peripheral_address() -{ - GPIO_FUNCTION_TRACE - uint32_t address = get_dt_ranges("/proc/device-tree/soc/ranges", 4); - if (address == 0) { - address = get_dt_ranges("/proc/device-tree/soc/ranges", 8); - } - address = (address == (uint32_t)~0) ? 0x20000000 : address; - return address; -} -#endif // __linux__ - -#ifdef __NetBSD__ -// Assume the Raspberry Pi series and estimate the address from CPU -uint32_t bcm_host_get_peripheral_address() -{ - GPIO_FUNCTION_TRACE - array buf; - size_t len = buf.size(); - uint32_t address; - - if (sysctlbyname("hw.model", buf.data(), &len, NULL, 0) || strstr(buf, "ARM1176JZ-S") != buf.data()) { - // Failed to get CPU model || Not BCM2835 - // use the address of BCM283[67] - address = 0x3f000000; - } else { - // Use BCM2835 address - address = 0x20000000; - } - LOGDEBUG("Peripheral address : 0x%lx\n", address); - return address; -} -#endif // __NetBSD__ - -bool GPIOBUS_Raspberry::Init(mode_e mode) -{ - GPIO_FUNCTION_TRACE - GPIOBUS::Init(mode); - -#if defined(__x86_64__) || defined(__X86__) - - // When we're running on x86, there is no hardware to talk to, so just return. - return true; -#else -#ifdef USE_SEL_EVENT_ENABLE - epoll_event ev = {}; -#endif - - // Get the base address - baseaddr = (uint32_t)bcm_host_get_peripheral_address(); - LOGTRACE("%s Base addr: %08X", __PRETTY_FUNCTION__, baseaddr); - - // Open /dev/mem - int fd = open("/dev/mem", O_RDWR | O_SYNC); - if (fd == -1) { - LOGERROR("Error: Unable to open /dev/mem. Are you running as root?") - return false; - } - - LOGTRACE("%s Mapping Memory....", __PRETTY_FUNCTION__); - - // Map peripheral region memory - void *map = mmap(NULL, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, baseaddr); - if (map == MAP_FAILED) { - LOGERROR("Error: Unable to map memory") - close(fd); - return false; - } - LOGTRACE("%s Done!", __PRETTY_FUNCTION__); - - // Determine the type of raspberry pi from the base address - if (baseaddr == 0xfe000000) { - rpitype = 4; - LOGINFO("%s I'm a pi 4", __PRETTY_FUNCTION__); - } else if (baseaddr == 0x3f000000) { - rpitype = 2; - } else { - rpitype = 1; - } - - // GPIO - gpio = (uint32_t *)map; - gpio += GPIO_OFFSET / sizeof(uint32_t); - level = &gpio[GPIO_LEV_0]; - - // PADS - pads = (uint32_t *)map; - pads += PADS_OFFSET / sizeof(uint32_t); - - // // System timer - // SysTimer::Init( - // (uint32_t *)map + SYST_OFFSET / sizeof(uint32_t), - // (uint32_t *)map + ARMT_OFFSET / sizeof(uint32_t)); - SysTimer::Init(); - - // Interrupt controller - irpctl = (uint32_t *)map; - irpctl += IRPT_OFFSET / sizeof(uint32_t); - - // Quad-A7 control - qa7regs = (uint32_t *)map; - qa7regs += QA7_OFFSET / sizeof(uint32_t); - - LOGTRACE("%s Mapping GIC Memory....", __PRETTY_FUNCTION__); - // Map GIC memory - if (rpitype == 4) { - map = mmap(NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ARM_GICD_BASE); - if (map == MAP_FAILED) { - close(fd); - return false; - } - gicd = (uint32_t *)map; - gicc = (uint32_t *)map; - gicc += (ARM_GICC_BASE - ARM_GICD_BASE) / sizeof(uint32_t); - } else { - gicd = NULL; - gicc = NULL; - } - close(fd); - - LOGTRACE("%s Set Drive Strength", __PRETTY_FUNCTION__); - // Set Drive Strength to 16mA - DrvConfig(7); - - // Set pull up/pull down - LOGTRACE("%s Set pull up/down....", __PRETTY_FUNCTION__); - -#if SIGNAL_CONTROL_MODE == 0 - LOGTRACE("%s GPIO_PULLNONE", __PRETTY_FUNCTION__); - int pullmode = GPIO_PULLNONE; -#elif SIGNAL_CONTROL_MODE == 1 - LOGTRACE("%s GPIO_PULLUP", __PRETTY_FUNCTION__); - int pullmode = GPIO_PULLUP; -#else - LOGTRACE("%s GPIO_PULLDOWN", __PRETTY_FUNCTION__); - int pullmode = GPIO_PULLDOWN; -#endif - - // Initialize all signals - LOGTRACE("%s Initialize all signals....", __PRETTY_FUNCTION__); - - for (int i = 0; SignalTable[i] >= 0; i++) { - int j = SignalTable[i]; - PinSetSignal(j, OFF); - PinConfig(j, GPIO_INPUT); - PullConfig(j, pullmode); - } - - // Set control signals - LOGTRACE("%s Set control signals....", __PRETTY_FUNCTION__); - PinSetSignal(PIN_ACT, OFF); - PinSetSignal(PIN_TAD, OFF); - PinSetSignal(PIN_IND, OFF); - PinSetSignal(PIN_DTD, OFF); - PinConfig(PIN_ACT, GPIO_OUTPUT); - PinConfig(PIN_TAD, GPIO_OUTPUT); - PinConfig(PIN_IND, GPIO_OUTPUT); - PinConfig(PIN_DTD, GPIO_OUTPUT); - - // Set the ENABLE signal - // This is used to show that the application is running - PinSetSignal(PIN_ENB, ENB_OFF); - PinConfig(PIN_ENB, GPIO_OUTPUT); - - // GPFSEL backup - LOGTRACE("%s GPFSEL backup....", __PRETTY_FUNCTION__); - - gpfsel[0] = gpio[GPIO_FSEL_0]; - gpfsel[1] = gpio[GPIO_FSEL_1]; - gpfsel[2] = gpio[GPIO_FSEL_2]; - gpfsel[3] = gpio[GPIO_FSEL_3]; - - // Initialize SEL signal interrupt -#ifdef USE_SEL_EVENT_ENABLE - // GPIO chip open - LOGTRACE("%s GPIO chip open", __PRETTY_FUNCTION__); - int gpio_fd = open("/dev/gpiochip0", 0); - if (gpio_fd == -1) { - LOGERROR("Unable to open /dev/gpiochip0. Is RaSCSI already running?") - return false; - } - - // Event request setting - LOGTRACE("%s Event request setting (pin sel: %d)", __PRETTY_FUNCTION__, PIN_SEL); - strcpy(selevreq.consumer_label, "RaSCSI"); - selevreq.lineoffset = PIN_SEL; - selevreq.handleflags = GPIOHANDLE_REQUEST_INPUT; -#if SIGNAL_CONTROL_MODE < 2 - selevreq.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE; - LOGTRACE("%s eventflags = GPIOEVENT_REQUEST_FALLING_EDGE", __PRETTY_FUNCTION__); -#else - selevreq.eventflags = GPIOEVENT_REQUEST_RISING_EDGE; - LOGTRACE("%s eventflags = GPIOEVENT_REQUEST_RISING_EDGE", __PRETTY_FUNCTION__); -#endif // SIGNAL_CONTROL_MODE - - // Get event request - if (ioctl(gpio_fd, GPIO_GET_LINEEVENT_IOCTL, &selevreq) == -1) { - LOGERROR("selevreq.fd = %d %08X", selevreq.fd, (unsigned int)selevreq.fd); - LOGERROR("Unable to register event request. Is RaSCSI already running?") - LOGERROR("[%08X] %s", errno, strerror(errno)); - close(gpio_fd); - return false; - } - - // Close GPIO chip file handle - LOGTRACE("%s Close GPIO chip file handle", __PRETTY_FUNCTION__); - close(gpio_fd); - - // epoll initialization - LOGTRACE("%s epoll initialization", __PRETTY_FUNCTION__); - epfd = epoll_create(1); - if (epfd == -1) { - LOGERROR("Unable to create the epoll event"); - return false; - } - memset(&ev, 0, sizeof(ev)); - ev.events = EPOLLIN | EPOLLPRI; - ev.data.fd = selevreq.fd; - epoll_ctl(epfd, EPOLL_CTL_ADD, selevreq.fd, &ev); -#else - // Edge detection setting -#if SIGNAL_CONTROL_MODE == 2 - gpio[GPIO_AREN_0] = 1 << PIN_SEL; -#else - gpio[GPIO_AFEN_0] = 1 << PIN_SEL; -#endif // SIGNAL_CONTROL_MODE - - // Clear event - gpio[GPIO_EDS_0] = 1 << PIN_SEL; - - // Register interrupt handler - setIrqFuncAddress(IrqHandler); - - // GPIO interrupt setting - if (rpitype == 4) { - // GIC Invalid - gicd[GICD_CTLR] = 0; - - // Route all interupts to core 0 - for (i = 0; i < 8; i++) { - gicd[GICD_ICENABLER0 + i] = 0xffffffff; - gicd[GICD_ICPENDR0 + i] = 0xffffffff; - gicd[GICD_ICACTIVER0 + i] = 0xffffffff; - } - for (i = 0; i < 64; i++) { - gicd[GICD_IPRIORITYR0 + i] = 0xa0a0a0a0; - gicd[GICD_ITARGETSR0 + i] = 0x01010101; - } - - // Set all interrupts as level triggers - for (i = 0; i < 16; i++) { - gicd[GICD_ICFGR0 + i] = 0; - } - - // GIC Invalid - gicd[GICD_CTLR] = 1; - - // Enable CPU interface for core 0 - gicc[GICC_PMR] = 0xf0; - gicc[GICC_CTLR] = 1; - - // Enable interrupts - gicd[GICD_ISENABLER0 + (GIC_GPIO_IRQ / 32)] = 1 << (GIC_GPIO_IRQ % 32); - } else { - // Enable interrupts - irpctl[IRPT_ENB_IRQ_2] = (1 << (GPIO_IRQ % 32)); - } -#endif // USE_SEL_EVENT_ENABLE - - // Create work table - - MakeTable(); - - // Finally, enable ENABLE - LOGTRACE("%s Finally, enable ENABLE....", __PRETTY_FUNCTION__); - // Show the user that this app is running - SetControl(PIN_ENB, ENB_ON); - - return true; -#endif // ifdef __x86_64__ || __X86__ -} - -void GPIOBUS_Raspberry::Cleanup() -{ - GPIO_FUNCTION_TRACE -#if defined(__x86_64__) || defined(__X86__) - return; -#else - // Release SEL signal interrupt -#ifdef USE_SEL_EVENT_ENABLE - close(selevreq.fd); -#endif // USE_SEL_EVENT_ENABLE - - // Set control signals - PinSetSignal(PIN_ENB, OFF); - PinSetSignal(PIN_ACT, OFF); - PinSetSignal(PIN_TAD, OFF); - PinSetSignal(PIN_IND, OFF); - PinSetSignal(PIN_DTD, OFF); - PinConfig(PIN_ACT, GPIO_INPUT); - PinConfig(PIN_TAD, GPIO_INPUT); - PinConfig(PIN_IND, GPIO_INPUT); - PinConfig(PIN_DTD, GPIO_INPUT); - - // Initialize all signals - for (int i = 0; SignalTable[i] >= 0; i++) { - int pin = SignalTable[i]; - PinSetSignal(pin, OFF); - PinConfig(pin, GPIO_INPUT); - PullConfig(pin, GPIO_PULLNONE); - } - - // Set drive strength back to 8mA - DrvConfig(3); -#endif // ifdef __x86_64__ || __X86__ -} - -void GPIOBUS_Raspberry::Reset() -{ - GPIO_FUNCTION_TRACE -#if defined(__x86_64__) || defined(__X86__) - return; -#else - int i; - int j; - - // Turn off active signal - SetControl(PIN_ACT, ACT_OFF); - - // Set all signals to off - for (i = 0;; i++) { - j = SignalTable[i]; - if (j < 0) { - break; - } - - SetSignal(j, OFF); - } - - if (actmode == mode_e::TARGET) { - // Target mode - - // Set target signal to input - SetControl(PIN_TAD, TAD_IN); - SetMode(PIN_BSY, IN); - SetMode(PIN_MSG, IN); - SetMode(PIN_CD, IN); - SetMode(PIN_REQ, IN); - SetMode(PIN_IO, IN); - - // Set the initiator signal to input - SetControl(PIN_IND, IND_IN); - SetMode(PIN_SEL, IN); - SetMode(PIN_ATN, IN); - SetMode(PIN_ACK, IN); - SetMode(PIN_RST, IN); - - // Set data bus signals to input - SetControl(PIN_DTD, DTD_IN); - SetMode(PIN_DT0, IN); - SetMode(PIN_DT1, IN); - SetMode(PIN_DT2, IN); - SetMode(PIN_DT3, IN); - SetMode(PIN_DT4, IN); - SetMode(PIN_DT5, IN); - SetMode(PIN_DT6, IN); - SetMode(PIN_DT7, IN); - SetMode(PIN_DP, IN); - } else { - // Initiator mode - - // Set target signal to input - SetControl(PIN_TAD, TAD_IN); - SetMode(PIN_BSY, IN); - SetMode(PIN_MSG, IN); - SetMode(PIN_CD, IN); - SetMode(PIN_REQ, IN); - SetMode(PIN_IO, IN); - - // Set the initiator signal to output - SetControl(PIN_IND, IND_OUT); - SetMode(PIN_SEL, OUT); - SetMode(PIN_ATN, OUT); - SetMode(PIN_ACK, OUT); - SetMode(PIN_RST, OUT); - - // Set the data bus signals to output - SetControl(PIN_DTD, DTD_OUT); - SetMode(PIN_DT0, OUT); - SetMode(PIN_DT1, OUT); - SetMode(PIN_DT2, OUT); - SetMode(PIN_DT3, OUT); - SetMode(PIN_DT4, OUT); - SetMode(PIN_DT5, OUT); - SetMode(PIN_DT6, OUT); - SetMode(PIN_DT7, OUT); - SetMode(PIN_DP, OUT); - } - - // Initialize all signals - signals = 0; -#endif // ifdef __x86_64__ || __X86__ -} - -//--------------------------------------------------------------------------- -// -// Get data signals -// -//--------------------------------------------------------------------------- -uint8_t GPIOBUS_Raspberry::GetDAT() -{ - GPIO_FUNCTION_TRACE - uint32_t data = Acquire(); - data = ((data >> (PIN_DT0 - 0)) & (1 << 0)) | ((data >> (PIN_DT1 - 1)) & (1 << 1)) | - ((data >> (PIN_DT2 - 2)) & (1 << 2)) | ((data >> (PIN_DT3 - 3)) & (1 << 3)) | - ((data >> (PIN_DT4 - 4)) & (1 << 4)) | ((data >> (PIN_DT5 - 5)) & (1 << 5)) | - ((data >> (PIN_DT6 - 6)) & (1 << 6)) | ((data >> (PIN_DT7 - 7)) & (1 << 7)); - return (uint8_t)data; -} - -//--------------------------------------------------------------------------- -// -// Set data signals -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::SetDAT(uint8_t dat) -{ - GPIO_FUNCTION_TRACE - // Write to port -#if SIGNAL_CONTROL_MODE == 0 - uint32_t fsel = gpfsel[0]; - fsel &= tblDatMsk[0][dat]; - fsel |= tblDatSet[0][dat]; - if (fsel != gpfsel[0]) { - gpfsel[0] = fsel; - gpio[GPIO_FSEL_0] = fsel; - } - - fsel = gpfsel[1]; - fsel &= tblDatMsk[1][dat]; - fsel |= tblDatSet[1][dat]; - if (fsel != gpfsel[1]) { - gpfsel[1] = fsel; - gpio[GPIO_FSEL_1] = fsel; - } - - fsel = gpfsel[2]; - fsel &= tblDatMsk[2][dat]; - fsel |= tblDatSet[2][dat]; - if (fsel != gpfsel[2]) { - gpfsel[2] = fsel; - gpio[GPIO_FSEL_2] = fsel; - } -#else - gpio[GPIO_CLR_0] = tblDatMsk[dat]; - gpio[GPIO_SET_0] = tblDatSet[dat]; -#endif // SIGNAL_CONTROL_MODE -} - -//--------------------------------------------------------------------------- -// -// Create work table -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::MakeTable(void) -{ - GPIO_FUNCTION_TRACE - - const array pintbl = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP}; - - array tblParity; - - // Create parity table - for (uint32_t i = 0; i < 0x100; i++) { - uint32_t bits = i; - uint32_t parity = 0; - for (int j = 0; j < 8; j++) { - parity ^= bits & 1; - bits >>= 1; - } - parity = ~parity; - tblParity[i] = parity & 1; - } - -#if SIGNAL_CONTROL_MODE == 0 - // Mask and setting data generation - for (auto &tbl : tblDatMsk) { - tbl.fill(-1); - } - for (auto &tbl : tblDatSet) { - tbl.fill(0); - } - - for (uint32_t i = 0; i < 0x100; i++) { - // Bit string for inspection - uint32_t bits = i; - - // Get parity - if (tblParity[i]) { - bits |= (1 << 8); - } - - // Bit check - for (int j = 0; j < 9; j++) { - // Index and shift amount calculation - int index = pintbl[j] / 10; - int shift = (pintbl[j] % 10) * 3; - - // Mask data - tblDatMsk[index][i] &= ~(0x7 << shift); - - // Setting data - if (bits & 1) { - tblDatSet[index][i] |= (1 << shift); - } - - bits >>= 1; - } - } -#else - for (uint32_t i = 0; i < 0x100; i++) { - // Bit string for inspection - uint32_t bits = i; - - // Get parity - if (tblParity[i]) { - bits |= (1 << 8); - } - -#if SIGNAL_CONTROL_MODE == 1 - // Negative logic is inverted - bits = ~bits; -#endif - - // Create GPIO register information - uint32_t gpclr = 0; - uint32_t gpset = 0; - for (int j = 0; j < 9; j++) { - if (bits & 1) { - gpset |= (1 << pintbl[j]); - } else { - gpclr |= (1 << pintbl[j]); - } - bits >>= 1; - } - - tblDatMsk[i] = gpclr; - tblDatSet[i] = gpset; - } -#endif -} - -//--------------------------------------------------------------------------- -// -// Control signal setting -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::SetControl(int pin, bool ast) -{ - PinSetSignal(pin, ast); -} - -//--------------------------------------------------------------------------- -// -// Input/output mode setting -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::SetMode(int pin, int mode) -{ -#if SIGNAL_CONTROL_MODE == 0 - if (mode == OUT) { - return; - } -#endif // SIGNAL_CONTROL_MODE - - int index = pin / 10; - int shift = (pin % 10) * 3; - uint32_t data = gpfsel[index]; - data &= ~(0x7 << shift); - if (mode == OUT) { - data |= (1 << shift); - } - gpio[index] = data; - gpfsel[index] = data; -} - -//--------------------------------------------------------------------------- -// -// Get input signal value -// -//--------------------------------------------------------------------------- -bool GPIOBUS_Raspberry::GetSignal(int pin) const -{ - return (signals >> pin) & 1; -} - -//--------------------------------------------------------------------------- -// -// Set output signal value -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::SetSignal(int pin, bool ast) -{ -#if SIGNAL_CONTROL_MODE == 0 - int index = pin / 10; - int shift = (pin % 10) * 3; - uint32_t data = gpfsel[index]; - if (ast) { - data |= (1 << shift); - } else { - data &= ~(0x7 << shift); - } - gpio[index] = data; - gpfsel[index] = data; -#elif SIGNAL_CONTROL_MODE == 1 - if (ast) { - gpio[GPIO_CLR_0] = 0x1 << pin; - } else { - gpio[GPIO_SET_0] = 0x1 << pin; - } -#elif SIGNAL_CONTROL_MODE == 2 - if (ast) { - gpio[GPIO_SET_0] = 0x1 << pin; - } else { - gpio[GPIO_CLR_0] = 0x1 << pin; - } -#endif // SIGNAL_CONTROL_MODE -} - -//--------------------------------------------------------------------------- -// -// Wait for signal change -// -// TODO: maybe this should be moved to SCSI_Bus? -//--------------------------------------------------------------------------- -bool GPIOBUS_Raspberry::WaitSignal(int pin, int ast) -{ - // Get current time - uint32_t now = SysTimer::GetTimerLow(); - - // Calculate timeout (3000ms) - uint32_t timeout = 3000 * 1000; - - // end immediately if the signal has changed - do { - // Immediately upon receiving a reset - Acquire(); - if (GetRST()) { - return false; - } - - // Check for the signal edge - if (((signals >> pin) ^ ~ast) & 1) { - return true; - } - } while ((SysTimer::GetTimerLow() - now) < timeout); - - // We timed out waiting for the signal - return false; -} - -void GPIOBUS_Raspberry::DisableIRQ() -{ - GPIO_FUNCTION_TRACE -#ifdef __linux - if (rpitype == 4) { - // RPI4 is disabled by GICC - giccpmr = gicc[GICC_PMR]; - gicc[GICC_PMR] = 0; - } else if (rpitype == 2) { - // RPI2,3 disable core timer IRQ - tintcore = sched_getcpu() + QA7_CORE0_TINTC; - tintctl = qa7regs[tintcore]; - qa7regs[tintcore] = 0; - } else { - // Stop system timer interrupt with interrupt controller - irptenb = irpctl[IRPT_ENB_IRQ_1]; - irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf; - } -#else - (void) - 0; -#endif -} - -void GPIOBUS_Raspberry::EnableIRQ() -{ - GPIO_FUNCTION_TRACE - if (rpitype == 4) { - // RPI4 enables interrupts via the GICC - gicc[GICC_PMR] = giccpmr; - } else if (rpitype == 2) { - // RPI2,3 re-enable core timer IRQ - qa7regs[tintcore] = tintctl; - } else { - // Restart the system timer interrupt with the interrupt controller - irpctl[IRPT_ENB_IRQ_1] = irptenb & 0xf; - } -} - -//--------------------------------------------------------------------------- -// -// Pin direction setting (input/output) -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::PinConfig(int pin, int mode) -{ - // Check for invalid pin - if (pin < 0) { - return; - } - - int index = pin / 10; - uint32_t mask = ~(0x7 << ((pin % 10) * 3)); - gpio[index] = (gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3)); -} - -//--------------------------------------------------------------------------- -// -// Pin pull-up/pull-down setting -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::PullConfig(int pin, int mode) -{ - uint32_t pull; - - // Check for invalid pin - if (pin < 0) { - return; - } - - if (rpitype == 4) { - LOGTRACE("%s I'm a Pi 4", __PRETTY_FUNCTION__) - switch (mode) { - case GPIO_PULLNONE: - pull = 0; - break; - case GPIO_PULLUP: - pull = 1; - break; - case GPIO_PULLDOWN: - pull = 2; - break; - default: - return; - } - - pin &= 0x1f; - int shift = (pin & 0xf) << 1; - uint32_t bits = gpio[GPIO_PUPPDN0 + (pin >> 4)]; - bits &= ~(3 << shift); - bits |= (pull << shift); - gpio[GPIO_PUPPDN0 + (pin >> 4)] = bits; - } else { - pin &= 0x1f; - gpio[GPIO_PUD] = mode & 0x3; - SysTimer::SleepUsec(2); - gpio[GPIO_CLK_0] = 0x1 << pin; - SysTimer::SleepUsec(2); - gpio[GPIO_PUD] = 0; - gpio[GPIO_CLK_0] = 0; - } -} - -//--------------------------------------------------------------------------- -// -// Set output pin -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::PinSetSignal(int pin, bool ast) -{ - // Check for invalid pin - if (pin < 0) { - return; - } - - if (ast) { - gpio[GPIO_SET_0] = 0x1 << pin; - } else { - gpio[GPIO_CLR_0] = 0x1 << pin; - } -} - -//--------------------------------------------------------------------------- -// -// Set the signal drive strength -// -//--------------------------------------------------------------------------- -void GPIOBUS_Raspberry::DrvConfig(uint32_t drive) -{ - uint32_t data = pads[PAD_0_27]; - pads[PAD_0_27] = (0xFFFFFFF8 & data) | drive | 0x5a000000; -} - -uint32_t GPIOBUS_Raspberry::Acquire() -{ - GPIO_FUNCTION_TRACE; -#if defined(__x86_64__) || defined(__X86__) - // Only used for development/debugging purposes. Isn't really applicable - // to any real-world RaSCSI application - return 0; -#else - signals = *level; - -#if SIGNAL_CONTROL_MODE < 2 - // Invert if negative logic (internal processing is unified to positive logic) - signals = ~signals; -#endif // SIGNAL_CONTROL_MODE - return signals; -#endif // ifdef __x86_64__ || __X86__ -} diff --git a/cpp/hal/gpiobus_raspberry.h b/cpp/hal/gpiobus_raspberry.h deleted file mode 100644 index 691477c5..00000000 --- a/cpp/hal/gpiobus_raspberry.h +++ /dev/null @@ -1,124 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// [ GPIO-SCSI bus ] -// -//--------------------------------------------------------------------------- - -#pragma once - -#include "config.h" -#include "hal/gpiobus.h" -#include "log.h" -#include "scsi.h" - -//--------------------------------------------------------------------------- -// -// Class definition -// -//--------------------------------------------------------------------------- -class GPIOBUS_Raspberry final : public GPIOBUS -{ - public: - // Basic Functions - GPIOBUS_Raspberry() = default; - ~GPIOBUS_Raspberry() override = default; - // Destructor - bool Init(mode_e mode = mode_e::TARGET) override; - // Initialization - void Reset() override; - // Reset - void Cleanup() override; - // Cleanup - - //--------------------------------------------------------------------------- - // - // Bus signal acquisition - // - //--------------------------------------------------------------------------- - uint32_t Acquire() override; - - uint8_t GetDAT() override; - // Get DAT signal - void SetDAT(uint8_t dat) override; - // Set DAT signal - private: - // SCSI I/O signal control - void MakeTable() override; - // Create work data - void SetControl(int pin, bool ast) override; - // Set Control Signal - void SetMode(int pin, int mode) override; - // Set SCSI I/O mode - bool GetSignal(int pin) const override; - // Get SCSI input signal value - void SetSignal(int pin, bool ast) override; - // Set SCSI output signal value - bool WaitSignal(int pin, int ast) override; - // Wait for a signal to change - // Interrupt control - void DisableIRQ() override; - // IRQ Disabled - void EnableIRQ() override; - // IRQ Enabled - - // GPIO pin functionality settings - void PinConfig(int pin, int mode) override; - // GPIO pin direction setting - void PullConfig(int pin, int mode) override; - // GPIO pin pull up/down resistor setting - void PinSetSignal(int pin, bool ast) override; - // Set GPIO output signal - void DrvConfig(uint32_t drive) override; - // Set GPIO drive strength - -#if !defined(__x86_64__) && !defined(__X86__) - uint32_t baseaddr = 0; // Base address -#endif - - int rpitype = 0; // Type of Raspberry Pi - - volatile uint32_t *gpio = nullptr; // GPIO register - - volatile uint32_t *pads = nullptr; // PADS register - -#if !defined(__x86_64__) && !defined(__X86__) - volatile uint32_t *level = nullptr; // GPIO input level -#endif - - volatile uint32_t *irpctl = nullptr; // Interrupt control register - - volatile uint32_t irptenb; // Interrupt enabled state - - volatile uint32_t *qa7regs = nullptr; // QA7 register - - volatile int tintcore; // Interupt control target CPU. - - volatile uint32_t tintctl; // Interupt control - - volatile uint32_t giccpmr; // GICC priority setting - -#if !defined(__x86_64__) && !defined(__X86__) - volatile uint32_t *gicd = nullptr; // GIC Interrupt distributor register -#endif - - volatile uint32_t *gicc = nullptr; // GIC CPU interface register - - array gpfsel; // GPFSEL0-4 backup values - - uint32_t signals = 0; // All bus signals - -#if SIGNAL_CONTROL_MODE == 0 - array, 3> tblDatMsk; // Data mask table - - array, 3> tblDatSet; // Data setting table -#else - array tblDatMsk = {}; // Data mask table - - array tblDatSet = {}; // Table setting table -#endif -}; diff --git a/cpp/hal/gpiobus_standard.h b/cpp/hal/gpiobus_standard.h index f6b3cacd..502d1e99 100644 --- a/cpp/hal/gpiobus_standard.h +++ b/cpp/hal/gpiobus_standard.h @@ -16,41 +16,41 @@ // RaSCSI standard (SCSI logic, standard pin assignment) // -const std::string CONNECT_DESC = "STANDARD"; // Startup message +const std::string CONNECT_DESC = "STANDARD"; // Startup message // Select signal control mode -const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification +const static int SIGNAL_CONTROL_MODE = 0; // SCSI logical specification // Control signal pin assignment (-1 means no control) -const static int PIN_ACT = 4; // ACTIVE -const static int PIN_ENB = 5; // ENABLE -const static int PIN_IND = -1; // INITIATOR CTRL DIRECTION -const static int PIN_TAD = -1; // TARGET CTRL DIRECTION -const static int PIN_DTD = -1; // DATA DIRECTION +const static int PIN_ACT = 4; // ACTIVE +const static int PIN_ENB = 5; // ENABLE +const static int PIN_IND = -1; // INITIATOR CTRL DIRECTION +const static int PIN_TAD = -1; // TARGET CTRL DIRECTION +const static int PIN_DTD = -1; // DATA DIRECTION // Control signal output logic -#define ACT_ON ON // ACTIVE SIGNAL ON -#define ENB_ON ON // ENABLE SIGNAL ON -#define IND_IN OFF // INITIATOR SIGNAL INPUT -#define TAD_IN OFF // TARGET SIGNAL INPUT -#define DTD_IN ON // DATA SIGNAL INPUT +#define ACT_ON ON // ACTIVE SIGNAL ON +#define ENB_ON ON // ENABLE SIGNAL ON +#define IND_IN OFF // INITIATOR SIGNAL INPUT +#define TAD_IN OFF // TARGET SIGNAL INPUT +#define DTD_IN ON // DATA SIGNAL INPUT // SCSI signal pin assignment -const static int PIN_DT0 = 10; // Data 0 -const static int PIN_DT1 = 11; // Data 1 -const static int PIN_DT2 = 12; // Data 2 -const static int PIN_DT3 = 13; // Data 3 -const static int PIN_DT4 = 14; // Data 4 -const static int PIN_DT5 = 15; // Data 5 -const static int PIN_DT6 = 16; // Data 6 -const static int PIN_DT7 = 17; // Data 7 -const static int PIN_DP = 18; // Data parity -const static int PIN_ATN = 19; // ATN -const static int PIN_RST = 20; // RST -const static int PIN_ACK = 21; // ACK -const static int PIN_REQ = 22; // REQ -const static int PIN_MSG = 23; // MSG -const static int PIN_CD = 24; // CD -const static int PIN_IO = 25; // IO -const static int PIN_BSY = 26; // BSY -const static int PIN_SEL = 27; // SEL +const static int PIN_DT0 = 10; // Data 0 +const static int PIN_DT1 = 11; // Data 1 +const static int PIN_DT2 = 12; // Data 2 +const static int PIN_DT3 = 13; // Data 3 +const static int PIN_DT4 = 14; // Data 4 +const static int PIN_DT5 = 15; // Data 5 +const static int PIN_DT6 = 16; // Data 6 +const static int PIN_DT7 = 17; // Data 7 +const static int PIN_DP = 18; // Data parity +const static int PIN_ATN = 19; // ATN +const static int PIN_RST = 20; // RST +const static int PIN_ACK = 21; // ACK +const static int PIN_REQ = 22; // REQ +const static int PIN_MSG = 23; // MSG +const static int PIN_CD = 24; // CD +const static int PIN_IO = 25; // IO +const static int PIN_BSY = 26; // BSY +const static int PIN_SEL = 27; // SEL diff --git a/cpp/hal/sbc_version.cpp b/cpp/hal/sbc_version.cpp deleted file mode 100644 index 2821ac05..00000000 --- a/cpp/hal/sbc_version.cpp +++ /dev/null @@ -1,215 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Copyright (C) 2022 akuker -// -// [ Hardware version detection routines ] -// -//--------------------------------------------------------------------------- - -#include "sbc_version.h" -#include "log.h" -#include -#include -#include - -SBC_Version::sbc_version_type SBC_Version::m_sbc_version = sbc_version_type::sbc_unknown; - -const std::string SBC_Version::m_str_raspberry_pi_1 = "Raspberry Pi 1"; -const std::string SBC_Version::m_str_raspberry_pi_2_3 = "Raspberry Pi 2/3"; -const std::string SBC_Version::m_str_raspberry_pi_4 = "Raspberry Pi 4"; -const std::string SBC_Version::m_str_bananapi_m2_berry = "Banana Pi M2 Berry/Ultra"; -const std::string SBC_Version::m_str_bananapi_m2_zero = "Banana Pi M2 Zero"; -const std::string SBC_Version::m_str_bananapi_m2_plus = "Banana Pi BPI-M2-Plus H3"; -const std::string SBC_Version::m_str_bananapi_m3 = "Banana Pi M3"; -const std::string SBC_Version::m_str_bananapi_m4 = "Banana Pi M4"; -const std::string SBC_Version::m_str_unknown_sbc = "Unknown SBC"; - -// The strings in this table should align with the 'model' embedded -// in the device tree. This can be aquired by running: -// cat /proc/device-tree/model -// Only the first part of the string is checked. Anything following -// will be ignored. For example: -// "Raspberry Pi 4 Model B" will match with both of the following: -// - Raspberry Pi 4 Model B Rev 1.4 -// - Raspberry Pi 4 Model B Rev 1.3 -const std::map> SBC_Version::m_proc_device_tree_mapping = { - {"Raspberry Pi 1 Model ", sbc_version_type::sbc_raspberry_pi_1}, - {"Raspberry Pi 2 Model ", sbc_version_type::sbc_raspberry_pi_2_3}, - {"Raspberry Pi 3 Model ", sbc_version_type::sbc_raspberry_pi_2_3}, - {"Raspberry Pi 4 Model ", sbc_version_type::sbc_raspberry_pi_4}, - {"Raspberry Pi 400 ", sbc_version_type::sbc_raspberry_pi_4}, - {"Raspberry Pi Zero W", sbc_version_type::sbc_raspberry_pi_1}, - {"Raspberry Pi Zero", sbc_version_type::sbc_raspberry_pi_1}, - {"Banana Pi BPI-M2-Zero ", sbc_version_type::sbc_bananapi_m2_zero}, - {"Banana Pi BPI-M2-Ultra ", sbc_version_type::sbc_bananapi_m2_berry}, - {"Banana Pi BPI-M2-Plus H3", sbc_version_type::sbc_bananapi_m2_plus}, - {"Banana Pi M2 Berry ", sbc_version_type::sbc_bananapi_m2_berry}, - // sbc_bananapi_m3, TBD.... - // sbc_bananapi_m4, -}; - -const std::string SBC_Version::m_device_tree_model_path = "/proc/device-tree/model"; - -//--------------------------------------------------------------------------- -// -// Convert the SBC Version to a printable string -// -//--------------------------------------------------------------------------- -const std::string *SBC_Version::GetString() -{ - switch (m_sbc_version) { - case sbc_version_type::sbc_raspberry_pi_1: - return &m_str_raspberry_pi_1; - case sbc_version_type::sbc_raspberry_pi_2_3: - return &m_str_raspberry_pi_2_3; - case sbc_version_type::sbc_raspberry_pi_4: - return &m_str_raspberry_pi_4; - case sbc_version_type::sbc_bananapi_m2_berry: - return &m_str_bananapi_m2_berry; - case sbc_version_type::sbc_bananapi_m2_zero: - return &m_str_bananapi_m2_zero; - case sbc_version_type::sbc_bananapi_m2_plus: - return &m_str_bananapi_m2_plus; - case sbc_version_type::sbc_bananapi_m3: - return &m_str_bananapi_m3; - case sbc_version_type::sbc_bananapi_m4: - return &m_str_bananapi_m4; - default: - LOGERROR("Unknown type of sbc detected: %d", static_cast(m_sbc_version)) - return &m_str_unknown_sbc; - } -} - -SBC_Version::sbc_version_type SBC_Version::GetSbcVersion() -{ - return m_sbc_version; -} - -//--------------------------------------------------------------------------- -// -// Determine which version of single board computer (Pi) is being used -// based upon the device tree model string. -// -//--------------------------------------------------------------------------- -void SBC_Version::Init() -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - std::string device_tree_model; - - const std::ifstream input_stream(SBC_Version::m_device_tree_model_path); - - if (input_stream.fail()) { - LOGERROR("Failed to open %s. Are you running as root?", SBC_Version::m_device_tree_model_path.c_str()) - throw std::invalid_argument("Failed to open /proc/device-tree/model"); - } - - std::stringstream str_buffer; - str_buffer << input_stream.rdbuf(); - device_tree_model = str_buffer.str(); - - for (const auto &[key, value] : m_proc_device_tree_mapping) { - if (device_tree_model.rfind(key, 0) == 0) { - m_sbc_version = value; - LOGINFO("Detected device %s", GetString()->c_str()) - return; - } - } - LOGERROR("%s Unable to determine single board computer type. Defaulting to Raspberry Pi 4", __PRETTY_FUNCTION__) - m_sbc_version = sbc_version_type::sbc_raspberry_pi_4; -} - -bool SBC_Version::IsRaspberryPi() -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - switch (m_sbc_version) { - case sbc_version_type::sbc_raspberry_pi_1: - case sbc_version_type::sbc_raspberry_pi_2_3: - case sbc_version_type::sbc_raspberry_pi_4: - return true; - case sbc_version_type::sbc_bananapi_m2_berry: - case sbc_version_type::sbc_bananapi_m2_zero: - case sbc_version_type::sbc_bananapi_m2_plus: - case sbc_version_type::sbc_bananapi_m3: - case sbc_version_type::sbc_bananapi_m4: - return false; - default: - return false; - } -} - -bool SBC_Version::IsBananaPi() -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - switch (m_sbc_version) { - case sbc_version_type::sbc_raspberry_pi_1: - case sbc_version_type::sbc_raspberry_pi_2_3: - case sbc_version_type::sbc_raspberry_pi_4: - return false; - case sbc_version_type::sbc_bananapi_m2_berry: - case sbc_version_type::sbc_bananapi_m2_zero: - case sbc_version_type::sbc_bananapi_m2_plus: - case sbc_version_type::sbc_bananapi_m3: - case sbc_version_type::sbc_bananapi_m4: - return true; - default: - return false; - } -} - -// The following functions are only used on the Raspberry Pi -// (imported from bcm_host.c) -uint32_t SBC_Version::GetDeviceTreeRanges(const char *filename, uint32_t offset) -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - uint32_t address = ~0; - if (FILE *fp = fopen(filename, "rb"); fp) { - fseek(fp, offset, SEEK_SET); - if (std::array buf; fread(buf.data(), 1, buf.size(), fp) == buf.size()) { - address = (int)buf[0] << 24 | (int)buf[1] << 16 | (int)buf[2] << 8 | (int)buf[3] << 0; - } - fclose(fp); - } - return address; -} - -#if defined __linux__ -uint32_t SBC_Version::GetPeripheralAddress(void) -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - uint32_t address = GetDeviceTreeRanges("/proc/device-tree/soc/ranges", 4); - if (address == 0) { - address = GetDeviceTreeRanges("/proc/device-tree/soc/ranges", 8); - } - address = (address == (uint32_t)~0) ? 0x20000000 : address; - - LOGDEBUG("Peripheral address : 0x%8x\n", address) - - return address; -} -#elif defined __NetBSD__ -uint32_t SBC_Version::GetPeripheralAddress(void) -{ - char buf[1024]; - size_t len = sizeof(buf); - uint32_t address; - - if (sysctlbyname("hw.model", buf, &len, NULL, 0) || strstr(buf, "ARM1176JZ-S") != buf) { - // Failed to get CPU model || Not BCM2835 - // use the address of BCM283[67] - address = 0x3f000000; - } else { - // Use BCM2835 address - address = 0x20000000; - } - LOGDEBUG("Peripheral address : 0x%lx\n", address); - return address; -} -#else -uint32_t SBC_Version::GetPeripheralAddress(void) -{ - return 0; -} -#endif diff --git a/cpp/hal/sbc_version.h b/cpp/hal/sbc_version.h deleted file mode 100644 index 520f0c85..00000000 --- a/cpp/hal/sbc_version.h +++ /dev/null @@ -1,70 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Copyright (C) 2022 akuker -// -// [ Hardware version detection routines ] -// -//--------------------------------------------------------------------------- - -#pragma once - -#include -#include - -//=========================================================================== -// -// Single Board Computer Versions -// -//=========================================================================== -class SBC_Version -{ - public: - // Type of Single Board Computer - enum class sbc_version_type : uint8_t { - sbc_unknown = 0, - sbc_raspberry_pi_1, - sbc_raspberry_pi_2_3, - sbc_raspberry_pi_4, - sbc_bananapi_m2_berry, - sbc_bananapi_m2_zero, - sbc_bananapi_m2_plus, - sbc_bananapi_m3, - sbc_bananapi_m4, - }; - - SBC_Version() = delete; - ~SBC_Version() = delete; - - static void Init(); - - static sbc_version_type GetSbcVersion(); - - static bool IsRaspberryPi(); - static bool IsBananaPi(); - - static const std::string *GetString(); - - static uint32_t GetPeripheralAddress(); - - private: - static sbc_version_type m_sbc_version; - - static const std::string m_str_raspberry_pi_1; - static const std::string m_str_raspberry_pi_2_3; - static const std::string m_str_raspberry_pi_4; - static const std::string m_str_bananapi_m2_berry; - static const std::string m_str_bananapi_m2_zero; - static const std::string m_str_bananapi_m2_plus; - static const std::string m_str_bananapi_m3; - static const std::string m_str_bananapi_m4; - static const std::string m_str_unknown_sbc; - - static const std::map> m_proc_device_tree_mapping; - - static const std::string m_device_tree_model_path; - - static uint32_t GetDeviceTreeRanges(const char *filename, uint32_t offset); -}; diff --git a/cpp/hal/systimer.cpp b/cpp/hal/systimer.cpp index 4a313698..1dd727fa 100644 --- a/cpp/hal/systimer.cpp +++ b/cpp/hal/systimer.cpp @@ -12,56 +12,129 @@ //--------------------------------------------------------------------------- #include "hal/systimer.h" -#include "hal/systimer_allwinner.h" -#include "hal/systimer_raspberry.h" -#include - #include "hal/gpiobus.h" -#include "hal/sbc_version.h" - #include "config.h" -#include "log.h" +#include +#include +#include +#include +#include -bool SysTimer::initialized = false; -bool SysTimer::is_allwinnner = false; -bool SysTimer::is_raspberry = false; +//--------------------------------------------------------------------------- +// +// System timer address +// +//--------------------------------------------------------------------------- +volatile uint32_t* SysTimer::systaddr; -std::unique_ptr SysTimer::systimer_ptr; +//--------------------------------------------------------------------------- +// +// ARM timer address +// +//--------------------------------------------------------------------------- +volatile uint32_t* SysTimer::armtaddr; -void SysTimer::Init() +//--------------------------------------------------------------------------- +// +// Core frequency +// +//--------------------------------------------------------------------------- +volatile uint32_t SysTimer::corefreq; + +//--------------------------------------------------------------------------- +// +// Initialize the system timer +// +//--------------------------------------------------------------------------- +void SysTimer::Init(uint32_t *syst, uint32_t *armt) { - LOGTRACE("%s", __PRETTY_FUNCTION__) + // RPI Mailbox property interface + // Get max clock rate + // Tag: 0x00030004 + // + // Request: Length: 4 + // Value: u32: clock id + // Response: Length: 8 + // Value: u32: clock id, u32: rate (in Hz) + // + // Clock id + // 0x000000004: CORE + array maxclock = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 }; - if (!initialized) { - if (SBC_Version::IsRaspberryPi()) { - systimer_ptr = make_unique(); - is_raspberry = true; - } else if (SBC_Version::IsBananaPi()) { - systimer_ptr = make_unique(); - is_allwinnner = true; - } - systimer_ptr->Init(); - initialized = true; - } + // Save the base address + systaddr = syst; + armtaddr = armt; + + // Change the ARM timer to free run mode + armtaddr[ARMT_CTRL] = 0x00000282; + + // Get the core frequency + corefreq = 0; + int fd = open("/dev/vcio", O_RDONLY); + if (fd >= 0) { + ioctl(fd, _IOWR(100, 0, char *), maxclock); + corefreq = maxclock[6] / 1000000; + } + close(fd); } -// Get system timer low byte -uint32_t SysTimer::GetTimerLow() -{ - return systimer_ptr->GetTimerLow(); +//--------------------------------------------------------------------------- +// +// Get system timer low byte +// +//--------------------------------------------------------------------------- +uint32_t SysTimer::GetTimerLow() { + return systaddr[SYST_CLO]; } -// Get system timer high byte -uint32_t SysTimer::GetTimerHigh() -{ - return systimer_ptr->GetTimerHigh(); + +//--------------------------------------------------------------------------- +// +// Get system timer high byte +// +//--------------------------------------------------------------------------- +uint32_t SysTimer::GetTimerHigh() { + return systaddr[SYST_CHI]; } -// Sleep for N nanoseconds + +//--------------------------------------------------------------------------- +// +// Sleep in nanoseconds +// +//--------------------------------------------------------------------------- void SysTimer::SleepNsec(uint32_t nsec) { - systimer_ptr->SleepNsec(nsec); + // If time is 0, don't do anything + if (nsec == 0) { + return; + } + + // Calculate the timer difference + uint32_t diff = corefreq * nsec / 1000; + + // Return if the difference in time is too small + if (diff == 0) { + return; + } + + // Start + uint32_t start = armtaddr[ARMT_FREERUN]; + + // Loop until timer has elapsed + while ((armtaddr[ARMT_FREERUN] - start) < diff); } -// Sleep for N microseconds + +//--------------------------------------------------------------------------- +// +// Sleep in microseconds +// +//--------------------------------------------------------------------------- void SysTimer::SleepUsec(uint32_t usec) { - systimer_ptr->SleepUsec(usec); + // If time is 0, don't do anything + if (usec == 0) { + return; + } + + uint32_t now = GetTimerLow(); + while ((GetTimerLow() - now) < usec); } diff --git a/cpp/hal/systimer.h b/cpp/hal/systimer.h index 746afa62..8f4b31d9 100644 --- a/cpp/hal/systimer.h +++ b/cpp/hal/systimer.h @@ -13,31 +13,11 @@ #pragma once -#include #include #include "config.h" #include "scsi.h" -class PlatformSpecificTimer -{ - public: - // Default constructor - PlatformSpecificTimer() = default; - // Default destructor - virtual ~PlatformSpecificTimer() = default; - // Initialization - virtual void Init() = 0; - // Get system timer low byte - virtual uint32_t GetTimerLow() = 0; - // Get system timer high byte - virtual uint32_t GetTimerHigh() = 0; - // Sleep for N nanoseconds - virtual void SleepNsec(uint32_t nsec) = 0; - // Sleep for N microseconds - virtual void SleepUsec(uint32_t usec) = 0; -}; - //=========================================================================== // // System timer @@ -45,21 +25,23 @@ class PlatformSpecificTimer //=========================================================================== class SysTimer { - public: - static void Init(); - // Get system timer low byte - static uint32_t GetTimerLow(); - // Get system timer high byte - static uint32_t GetTimerHigh(); - // Sleep for N nanoseconds - static void SleepNsec(uint32_t nsec); - // Sleep for N microseconds - static void SleepUsec(uint32_t usec); +public: + static void Init(uint32_t *syst, uint32_t *armt); + // Initialization + static uint32_t GetTimerLow(); + // Get system timer low byte + static uint32_t GetTimerHigh(); + // Get system timer high byte + static void SleepNsec(uint32_t nsec); + // Sleep for N nanoseconds + static void SleepUsec(uint32_t usec); + // Sleep for N microseconds - private: - static bool initialized; - static bool is_allwinnner; - static bool is_raspberry; - - static std::unique_ptr systimer_ptr; +private: + static volatile uint32_t *systaddr; + // System timer address + static volatile uint32_t *armtaddr; + // ARM timer address + static volatile uint32_t corefreq; + // Core frequency }; diff --git a/cpp/hal/systimer_allwinner.cpp b/cpp/hal/systimer_allwinner.cpp deleted file mode 100644 index 920bf88f..00000000 --- a/cpp/hal/systimer_allwinner.cpp +++ /dev/null @@ -1,155 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Copyright (C) 2022 akuker -// -// [ High resolution timer for the Allwinner series of SoC's] -// -//--------------------------------------------------------------------------- - -#include "hal/systimer_allwinner.h" -#include - -#include "hal/gpiobus.h" - -#include "config.h" -#include "log.h" - -const std::string SysTimer_AllWinner::dev_mem_filename = "/dev/mem"; - -//--------------------------------------------------------------------------- -// -// Initialize the system timer -// -//--------------------------------------------------------------------------- -void SysTimer_AllWinner::Init() -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - - int fd; - - if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) { - LOGERROR("I can't open /dev/mem. Are you running as root?") - exit(-1); - } - - hsitimer_regs = (struct sun8i_hsitimer_registers *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, - hs_timer_base_address); - - if (hsitimer_regs == MAP_FAILED) { - LOGERROR("Unable to map high speed timer registers. Are you running as root?") - } - - sysbus_regs = (struct sun8i_sysbus_registers *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, - system_bus_base_address); - - if (sysbus_regs == MAP_FAILED) { - LOGERROR("Unable to map system bus registers. Are you running as root?") - } - - enable_hs_timer(); -} - -void SysTimer_AllWinner::enable_hs_timer() -{ - // By default, the HSTimer clock gating is masked. When it is necessary to use - // the HSTimer, its clock gating should be opened in BUS Clock Gating Register 0 - // and then de-assert the software reset in BUS Software Reset Register 0 on the - // CCU module. If it is not needed to use the HSTimer, both the gating bit and - // the software reset bit should be set 0. - - LOGTRACE("%s [Before Enable] CLK GATE: %08X SOFT RST: %08X", __PRETTY_FUNCTION__, sysbus_regs->bus_clk_gating_reg0, - sysbus_regs->bus_soft_rst_reg0) - - sysbus_regs->bus_clk_gating_reg0 = sysbus_regs->bus_clk_gating_reg0 | (1 << BUS_CLK_GATING_REG0_HSTMR); - sysbus_regs->bus_soft_rst_reg0 = sysbus_regs->bus_soft_rst_reg0 | (1 << BUS_SOFT_RST_REG0_HSTMR); - LOGTRACE("%s [After Enable] CLK GATE: %08X SOFT RST: %08X", __PRETTY_FUNCTION__, sysbus_regs->bus_clk_gating_reg0, - sysbus_regs->bus_soft_rst_reg0) - - // Set interval value to the maximum value. (its a 52 bit register) - hsitimer_regs->hs_tmr_intv_hi_reg = (1 << 20) - 1; //(0xFFFFF) - hsitimer_regs->hs_tmr_intv_lo_reg = UINT32_MAX; - - // Select prescale value of 1, continuouse mode - hsitimer_regs->hs_tmr_ctrl_reg = HS_TMR_CLK_PRE_SCALE_1; - - // Set reload bit - hsitimer_regs->hs_tmr_ctrl_reg |= HS_TMR_RELOAD; - - // Enable HSTimer - hsitimer_regs->hs_tmr_ctrl_reg |= HS_TMR_EN; -} - -// TODO: According to the data sheet, we should turn off the HS timer when we're done with it. But, its just going to -// eat up a little extra power if we leave it running. -void SysTimer_AllWinner::disable_hs_timer() -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - - LOGINFO("[Before Disable] CLK GATE: %08X SOFT RST: %08X", sysbus_regs->bus_clk_gating_reg0, - sysbus_regs->bus_soft_rst_reg0) - - sysbus_regs->bus_clk_gating_reg0 = sysbus_regs->bus_clk_gating_reg0 & ~(1 << BUS_CLK_GATING_REG0_HSTMR); - sysbus_regs->bus_soft_rst_reg0 = sysbus_regs->bus_soft_rst_reg0 & ~(1 << BUS_SOFT_RST_REG0_HSTMR); - - LOGINFO("[After Disable] CLK GATE: %08X SOFT RST: %08X", sysbus_regs->bus_clk_gating_reg0, - sysbus_regs->bus_soft_rst_reg0) -} - -uint32_t SysTimer_AllWinner::GetTimerLow() -{ - // RaSCSI expects the timer to count UP, but the Allwinner HS timer counts - // down. So, we subtract the current timer value from UINT32_MAX - return UINT32_MAX - (hsitimer_regs->hs_tmr_curnt_lo_reg / 200); -} - -uint32_t SysTimer_AllWinner::GetTimerHigh() -{ - return (uint32_t)0; -} - -//--------------------------------------------------------------------------- -// -// Sleep in nanoseconds -// -//--------------------------------------------------------------------------- -void SysTimer_AllWinner::SleepNsec(uint32_t nsec) -{ - // If time is less than one HS timer clock tick, don't do anything - if (nsec < 20) { - return; - } - - // The HS timer receives a 200MHz clock input, which equates to - // one clock tick every 5 ns. - auto clockticks = (uint32_t)std::ceil(nsec / 5); - - uint32_t enter_time = hsitimer_regs->hs_tmr_curnt_lo_reg; - - LOGTRACE("%s entertime: %08X ns: %d clockticks: %d", __PRETTY_FUNCTION__, enter_time, nsec, clockticks) - while ((enter_time - hsitimer_regs->hs_tmr_curnt_lo_reg) < clockticks) - ; - - return; -} - -//--------------------------------------------------------------------------- -// -// Sleep in microseconds -// -//--------------------------------------------------------------------------- -void SysTimer_AllWinner::SleepUsec(uint32_t usec) -{ - LOGTRACE("%s", __PRETTY_FUNCTION__) - - // If time is 0, don't do anything - if (usec == 0) { - return; - } - - uint32_t enter_time = GetTimerLow(); - while ((GetTimerLow() - enter_time) < usec) - ; -} diff --git a/cpp/hal/systimer_allwinner.h b/cpp/hal/systimer_allwinner.h deleted file mode 100644 index 72036e47..00000000 --- a/cpp/hal/systimer_allwinner.h +++ /dev/null @@ -1,106 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Copyright (C) 2022 akuker -// -// [ High resolution timer ] -// -//--------------------------------------------------------------------------- -#pragma once - -#include "systimer.h" -#include -#include - -//=========================================================================== -// -// System timer -// -//=========================================================================== -class SysTimer_AllWinner : public PlatformSpecificTimer -{ - public: - // Default constructor - SysTimer_AllWinner() = default; - // Default destructor - ~SysTimer_AllWinner() override = default; - // Initialization - void Init() override; - // Get system timer low byte - uint32_t GetTimerLow() override; - // Get system timer high byte - uint32_t GetTimerHigh() override; - // Sleep for N nanoseconds - void SleepNsec(uint32_t nsec) override; - // Sleep for N microseconds - void SleepUsec(uint32_t usec) override; - - private: - void enable_hs_timer(); - void disable_hs_timer(); - - static const std::string dev_mem_filename; - - /* Reference: Allwinner H3 Datasheet, section 4.9.3 */ - static const uint32_t hs_timer_base_address = 0x01C60000; - /* Note: Currently the high speed timer is NOT in the armbian - * device tree. If it is ever added, this should be pulled - * from there */ - - struct sun8i_hsitimer_registers { - /* 0x00 HS Timer IRQ Enabled Register */ - uint32_t hs_tmr_irq_en_reg; - /* 0x04 HS Timer Status Register */ - uint32_t hs_tmr_irq_stat_reg; - /* 0x08 Unused */ - uint32_t unused_08; - /* 0x0C Unused */ - uint32_t unused_0C; - /* 0x10 HS Timer Control Register */ - uint32_t hs_tmr_ctrl_reg; - /* 0x14 HS Timer Interval Value Low Reg */ - uint32_t hs_tmr_intv_lo_reg; - /* 0x18 HS Timer Interval Value High Register */ - uint32_t hs_tmr_intv_hi_reg; - /* 0x1C HS Timer Current Value Low Register */ - uint32_t hs_tmr_curnt_lo_reg; - /* 0x20 HS Timer Current Value High Register */ - uint32_t hs_tmr_curnt_hi_reg; - }; - - /* Constants for the HS Timer IRQ enable Register (section 4.9.4.1) */ - static const uint32_t HS_TMR_INTERUPT_ENB = (1 << 0); - - /* Constants for the HS Timer Control Register (section 4.9.4.3) */ - static const uint32_t HS_TMR_EN = (1 << 0); - static const uint32_t HS_TMR_RELOAD = (1 << 1); - static const uint32_t HS_TMR_CLK_PRE_SCALE_1 = (0 << 4); - static const uint32_t HS_TMR_CLK_PRE_SCALE_2 = (1 << 4); - static const uint32_t HS_TMR_CLK_PRE_SCALE_4 = (2 << 4); - static const uint32_t HS_TMR_CLK_PRE_SCALE_8 = (3 << 4); - static const uint32_t HS_TMR_CLK_PRE_SCALE_16 = (4 << 4); // NOSONAR This matches the datasheet - static const uint32_t HS_TMR_MODE_SINGLE = (1 << 7); - static const uint32_t HS_TMR_TEST_MODE = (1 << 31); - - struct sun8i_hsitimer_registers *hsitimer_regs; - - /* Reference: Allwinner H3 Datasheet, section 4.3.4 */ - static const uint32_t system_bus_base_address = 0x01C20000; - - struct sun8i_sysbus_registers { - uint32_t pad_00_5C[(0x60 / sizeof(uint32_t))]; //NOSONAR c-style array used for padding - /* 0x0060 Bus Clock Gating Register 0 */ - uint32_t bus_clk_gating_reg0; - uint32_t pad_64_2C0[((0x2C0 - 0x64) / sizeof(uint32_t))]; //NOSONAR c-style array used for padding - /* 0x2C0 Bus Software Reset Register 0 */ - uint32_t bus_soft_rst_reg0; - }; - - /* Bit associated with the HS Timer */ - static const uint32_t BUS_CLK_GATING_REG0_HSTMR = 19; - static const uint32_t BUS_SOFT_RST_REG0_HSTMR = 19; - - struct sun8i_sysbus_registers *sysbus_regs; -}; diff --git a/cpp/hal/systimer_raspberry.cpp b/cpp/hal/systimer_raspberry.cpp deleted file mode 100644 index efac1d3c..00000000 --- a/cpp/hal/systimer_raspberry.cpp +++ /dev/null @@ -1,148 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// Copyright (C) 2022 akuker -// -// [ High resolution timer ] -// -//--------------------------------------------------------------------------- - -#include "hal/systimer_raspberry.h" -#include -#include -#include - -#include "hal/gpiobus.h" -#include "hal/sbc_version.h" - -#include "config.h" -#include "log.h" - -// System timer address -volatile uint32_t *SysTimer_Raspberry::systaddr = nullptr; -// ARM timer address -volatile uint32_t *SysTimer_Raspberry::armtaddr = nullptr; -volatile uint32_t SysTimer_Raspberry::corefreq = 0; - -//--------------------------------------------------------------------------- -// -// Initialize the system timer -// -//--------------------------------------------------------------------------- -void SysTimer_Raspberry::Init() -{ - // Get the base address - auto baseaddr = SBC_Version::GetPeripheralAddress(); - - // Open /dev/mem - int mem_fd = open("/dev/mem", O_RDWR | O_SYNC); - if (mem_fd == -1) { - LOGERROR("Error: Unable to open /dev/mem. Are you running as root?") - return; - } - - // Map peripheral region memory - void *map = mmap(nullptr, 0x1000100, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, baseaddr); - if (map == MAP_FAILED) { - LOGERROR("Error: Unable to map memory") - close(mem_fd); - return; - } - close(mem_fd); - - // RPI Mailbox property interface - // Get max clock rate - // Tag: 0x00030004 - // - // Request: Length: 4 - // Value: u32: clock id - // Response: Length: 8 - // Value: u32: clock id, u32: rate (in Hz) - // - // Clock id - // 0x000000004: CORE - std::array maxclock = {32, 0, 0x00030004, 8, 0, 4, 0, 0}; - - // Save the base address - systaddr = (uint32_t *)map + SYST_OFFSET / sizeof(uint32_t); - armtaddr = (uint32_t *)map + ARMT_OFFSET / sizeof(uint32_t); - - // Change the ARM timer to free run mode - armtaddr[ARMT_CTRL] = 0x00000282; - - // Get the core frequency - if (int vcio_fd = open("/dev/vcio", O_RDONLY); vcio_fd >= 0) { - ioctl(vcio_fd, _IOWR(100, 0, char *), maxclock.data()); - corefreq = maxclock[6] / 1000000; - close(vcio_fd); - } -} - -//--------------------------------------------------------------------------- -// -// Get system timer low byte -// -//--------------------------------------------------------------------------- -uint32_t SysTimer_Raspberry::GetTimerLow() -{ - return systaddr[SYST_CLO]; -} - -//--------------------------------------------------------------------------- -// -// Get system timer high byte -// -//--------------------------------------------------------------------------- -uint32_t SysTimer_Raspberry::GetTimerHigh() -{ - return systaddr[SYST_CHI]; -} - -//--------------------------------------------------------------------------- -// -// Sleep in nanoseconds -// -//--------------------------------------------------------------------------- -void SysTimer_Raspberry::SleepNsec(uint32_t nsec) -{ - // If time is 0, don't do anything - if (nsec == 0) { - return; - } - - // Calculate the timer difference - uint32_t diff = corefreq * nsec / 1000; - - // Return if the difference in time is too small - if (diff == 0) { - return; - } - - // Start - uint32_t start = armtaddr[ARMT_FREERUN]; - - // Loop until timer has elapsed - while ((armtaddr[ARMT_FREERUN] - start) < diff) - ; -} - -//--------------------------------------------------------------------------- -// -// Sleep in microseconds -// -//--------------------------------------------------------------------------- -void SysTimer_Raspberry::SleepUsec(uint32_t usec) -{ - // If time is 0, don't do anything - if (usec == 0) { - return; - } - - uint32_t now = GetTimerLow(); - while ((GetTimerLow() - now) < usec) - ; -} diff --git a/cpp/hal/systimer_raspberry.h b/cpp/hal/systimer_raspberry.h deleted file mode 100644 index f126bd11..00000000 --- a/cpp/hal/systimer_raspberry.h +++ /dev/null @@ -1,49 +0,0 @@ -//--------------------------------------------------------------------------- -// -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi -// -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// Copyright (C) 2022 akuker -// -// [ High resolution timer ] -// -//--------------------------------------------------------------------------- - -#pragma once - -#include "systimer.h" -#include - -//=========================================================================== -// -// System timer -// -//=========================================================================== -class SysTimer_Raspberry : public PlatformSpecificTimer -{ - public: - // Default constructor - SysTimer_Raspberry() = default; - // Default destructor - ~SysTimer_Raspberry() override = default; - // Initialization - void Init() override; - // Get system timer low byte - uint32_t GetTimerLow() override; - // Get system timer high byte - uint32_t GetTimerHigh() override; - // Sleep for N nanoseconds - void SleepNsec(uint32_t nsec) override; - // Sleep for N microseconds - void SleepUsec(uint32_t usec) override; - - private: - // System timer address - static volatile uint32_t *systaddr; - // ARM timer address - static volatile uint32_t *armtaddr; - // Core frequency - static volatile uint32_t corefreq; -}; diff --git a/cpp/monitor/sm_core.cpp b/cpp/monitor/sm_core.cpp index f755f797..5e6a9e82 100644 --- a/cpp/monitor/sm_core.cpp +++ b/cpp/monitor/sm_core.cpp @@ -9,13 +9,12 @@ //--------------------------------------------------------------------------- #include "log.h" -#include "hal/gpiobus.h" #include "hal/gpiobus_factory.h" +#include "hal/gpiobus.h" #include "rascsi_version.h" #include #include #include -#include #include #include #include @@ -25,53 +24,20 @@ using namespace std; -static const int _MAX_FNAME = 256; - -//--------------------------------------------------------------------------- -// -// Variable declarations -// -//--------------------------------------------------------------------------- -static volatile bool running; // Running flag -unique_ptr bus; // GPIO Bus - -uint32_t buff_size = 1000000; -data_capture *data_buffer; -uint32_t data_idx = 0; - +// TODO Should not be global and not be used by sm_vcd_report double ns_per_loop; -bool print_help = false; -bool import_data = false; - -// We don't really need to support 256 character file names - this causes -// all kinds of compiler warnings when the log filename can be up to 256 -// characters. _MAX_FNAME/2 is just an arbitrary value. -char file_base_name[_MAX_FNAME / 2] = "log"; -char vcd_file_name[_MAX_FNAME]; -char json_file_name[_MAX_FNAME]; -char html_file_name[_MAX_FNAME]; -char input_file_name[_MAX_FNAME]; - -//--------------------------------------------------------------------------- -// -// Signal Processing -// -//--------------------------------------------------------------------------- -void KillHandler(int) +void ScsiMon::KillHandler(int) { - // Stop instruction running = false; } -void ScsiMon::parse_arguments(const vector& args) +void ScsiMon::ParseArguments(const vector& args) { int opt; - while ((opt = getopt(args.size(), args.data(), "-Hhb:i:")) != -1) - { - switch (opt) - { + while ((opt = getopt(static_cast(args.size()), args.data(), "-Hhb:i:")) != -1) { + switch (opt) { // The three options below are kind of a compound option with two letters case 'h': case 'H': @@ -81,11 +47,11 @@ void ScsiMon::parse_arguments(const vector& args) buff_size = atoi(optarg); break; case 'i': - strncpy(input_file_name, optarg, sizeof(input_file_name)-1); + input_file_name = optarg; import_data = true; break; case 1: - strncpy(file_base_name, optarg, sizeof(file_base_name) - 5); + file_base_name = optarg; break; default: cout << "default: " << optarg << endl; @@ -96,22 +62,18 @@ void ScsiMon::parse_arguments(const vector& args) /* Process any remaining command line arguments (not options). */ if (optind < static_cast(args.size())) { while (optind < static_cast(args.size())) - strncpy(file_base_name, args[optind++], sizeof(file_base_name)-1); + file_base_name = args[optind++]; } - strcpy(vcd_file_name, file_base_name); - strcat(vcd_file_name, ".vcd"); - strcpy(json_file_name, file_base_name); - strcat(json_file_name, ".json"); - strcpy(html_file_name, file_base_name); - strcat(html_file_name, ".html"); + vcd_file_name = file_base_name; + vcd_file_name += ".vcd"; + json_file_name = file_base_name; + json_file_name += ".json"; + html_file_name = file_base_name; + html_file_name += ".html"; } -//--------------------------------------------------------------------------- -// -// Copyright text -// -//--------------------------------------------------------------------------- -void ScsiMon::print_copyright_text() + +void ScsiMon::PrintCopyrightText() const { LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ") LOGINFO("version %s (%s, %s)", @@ -124,12 +86,7 @@ void ScsiMon::print_copyright_text() LOGINFO(" ") } -//--------------------------------------------------------------------------- -// -// Help text -// -//--------------------------------------------------------------------------- -void ScsiMon::print_help_text(const vector& args) +void ScsiMon::PrintHelpText(const vector& args) const { LOGINFO("%s -i [input file json] -b [buffer size] [output file]", args[0]) LOGINFO(" -i [input file json] - scsimon will parse the json file instead of capturing new data") @@ -139,15 +96,10 @@ void ScsiMon::print_help_text(const vector& args) LOGINFO(" will be appended to this file name") } -//--------------------------------------------------------------------------- -// -// Banner Output -// -//--------------------------------------------------------------------------- -void ScsiMon::Banner() +void ScsiMon::Banner() const { if (import_data) { - LOGINFO("Reading input file: %s", input_file_name) + LOGINFO("Reading input file: %s", input_file_name.c_str()) } else { LOGINFO("Reading live data from the GPIO pins") @@ -156,16 +108,11 @@ void ScsiMon::Banner() LOGINFO(" Data buffer size: %u", buff_size) LOGINFO(" ") LOGINFO("Generating output files:") - LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", vcd_file_name) - LOGINFO(" %s - JSON file with raw data", json_file_name) - LOGINFO(" %s - HTML file with summary of commands", html_file_name) + LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", vcd_file_name.c_str()) + LOGINFO(" %s - JSON file with raw data", json_file_name.c_str()) + LOGINFO(" %s - HTML file with summary of commands", html_file_name.c_str()) } -//--------------------------------------------------------------------------- -// -// Initialization -// -//--------------------------------------------------------------------------- bool ScsiMon::Init() { // Interrupt handler settings @@ -179,43 +126,35 @@ bool ScsiMon::Init() return false; } - // GPIO Initialization - bus = GPIOBUS_Factory::Create(); - if (!bus->Init()) - { + bus = GPIOBUS_Factory::Create(BUS::mode_e::TARGET); + if (bus == nullptr) { LOGERROR("Unable to intiailize the GPIO bus. Exiting....") return false; } - // Bus Reset - bus->Reset(); - - // Other running = false; return true; } -void ScsiMon::Cleanup() +void ScsiMon::Cleanup() const { if (!import_data) { LOGINFO("Stopping data collection....") } LOGINFO(" ") - LOGINFO("Generating %s...", vcd_file_name) - scsimon_generate_value_change_dump(vcd_file_name, data_buffer, data_idx); - LOGINFO("Generating %s...", json_file_name) - scsimon_generate_json(json_file_name, data_buffer, data_idx); - LOGINFO("Generating %s...", html_file_name) - scsimon_generate_html(html_file_name, data_buffer, data_idx); + LOGINFO("Generating %s...", vcd_file_name.c_str()) + scsimon_generate_value_change_dump(vcd_file_name.c_str(), data_buffer, data_idx); + LOGINFO("Generating %s...", json_file_name.c_str()) + scsimon_generate_json(json_file_name.c_str(), data_buffer, data_idx); + LOGINFO("Generating %s...", html_file_name.c_str()) + scsimon_generate_html(html_file_name.c_str(), data_buffer, data_idx); - // Cleanup the Bus bus->Cleanup(); } -void ScsiMon::Reset() +void ScsiMon::Reset() const { - // Reset the bus bus->Reset(); } @@ -225,7 +164,7 @@ void ScsiMon::Reset() // //--------------------------------------------------------------------------- #ifdef __linux__ -void ScsiMon::FixCpu(int cpu) +void ScsiMon::FixCpu(int cpu) const { // Get the number of CPUs cpu_set_t cpuset; @@ -248,14 +187,8 @@ static uint32_t high_bits = 0x0; static uint32_t low_bits = 0xFFFFFFFF; #endif -//--------------------------------------------------------------------------- -// -// Main processing -// -//--------------------------------------------------------------------------- int ScsiMon::run(const vector& args) { - #ifdef DEBUG spdlog::set_level(spdlog::level::trace); #else @@ -263,14 +196,13 @@ int ScsiMon::run(const vector& args) #endif spdlog::set_pattern("%^[%l]%$ %v"); - print_copyright_text(); - parse_arguments(args); + PrintCopyrightText(); + ParseArguments(args); #ifdef DEBUG uint32_t prev_high = high_bits; uint32_t prev_low = low_bits; #endif - ostringstream s; uint32_t prev_sample = 0xFFFFFFFF; uint32_t this_sample = 0; timeval start_time; @@ -279,23 +211,20 @@ int ScsiMon::run(const vector& args) timeval time_diff; uint64_t elapsed_us; - if (print_help) - { - print_help_text(args); + if (print_help) { + PrintHelpText(args); exit(0); } - // Output the Banner Banner(); data_buffer = (data_capture *)calloc(buff_size, sizeof(data_capture_t)); - if (import_data) - { - data_idx = scsimon_read_json(input_file_name, data_buffer, buff_size); + if (import_data) { + data_idx = scsimon_read_json(input_file_name.c_str(), data_buffer, buff_size); if (data_idx > 0) { - LOGDEBUG("Read %d samples from %s", data_idx, input_file_name) + LOGDEBUG("Read %d samples from %s", data_idx, input_file_name.c_str()) Cleanup(); } exit(0); @@ -327,48 +256,40 @@ int ScsiMon::run(const vector& args) // Start execution running = true; - bus->SetACT(false); + bus->SetACK(false); (void)gettimeofday(&start_time, nullptr); LOGDEBUG("ALL_SCSI_PINS %08X\n", ALL_SCSI_PINS) // Main Loop - while (running) - { + while (running) { // Work initialization this_sample = (bus->Acquire() & ALL_SCSI_PINS); loop_count++; - if (loop_count > LLONG_MAX - 1) - { + if (loop_count > LLONG_MAX - 1) { LOGINFO("Maximum amount of time has elapsed. SCSIMON is terminating.") running = false; } - if (data_idx >= (buff_size - 2)) - { + + if (data_idx >= (buff_size - 2)) { LOGINFO("Internal data buffer is full. SCSIMON is terminating.") running = false; } - if (this_sample != prev_sample) - { - + if (this_sample != prev_sample) { #ifdef DEBUG // This is intended to be a debug check to see if every pin is set // high and low at some point. high_bits |= this_sample; low_bits &= this_sample; - if ((high_bits != prev_high) || (low_bits != prev_low)) - { + if ((high_bits != prev_high) || (low_bits != prev_low)) { LOGDEBUG(" %08X %08X\n", high_bits, low_bits) } prev_high = high_bits; prev_low = low_bits; - if ((data_idx % 1000) == 0) - { - s.str(""); - s << "Collected " << data_idx << " samples..."; - LOGDEBUG("%s", s.str().c_str()) + if ((data_idx % 1000) == 0) { + LOGDEBUG("%s", ("Collected " + to_string(data_idx) + " samples...").c_str()) } #endif data_buffer[data_idx].data = this_sample; @@ -381,8 +302,7 @@ int ScsiMon::run(const vector& args) } // Collect one last sample, otherwise it looks like the end of the data was cut off - if (data_idx < buff_size) - { + if (data_idx < buff_size) { data_buffer[data_idx].data = this_sample; data_buffer[data_idx].timestamp = loop_count; data_idx++; @@ -393,18 +313,13 @@ int ScsiMon::run(const vector& args) timersub(&stop_time, &start_time, &time_diff); elapsed_us = ((time_diff.tv_sec * 1000000) + time_diff.tv_usec); - s.str(""); - s << "Elapsed time: " << elapsed_us << " microseconds (" << elapsed_us / 1000000 << " seconds)"; - LOGINFO("%s", s.str().c_str()) - s.str(""); - s << "Collected " << data_idx << " changes"; - LOGINFO("%s", s.str().c_str()) + LOGINFO("%s", ("Elapsed time: " + to_string(elapsed_us) + " microseconds (" + to_string(elapsed_us / 1000000) + + " seconds").c_str()) + LOGINFO("%s", ("Collected " + to_string(data_idx) + " changes").c_str()) - // Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps. - ns_per_loop = (elapsed_us * 1000) / (double)loop_count; - s.str(""); - s << "Read the SCSI bus " << loop_count << " times with an average of " << ns_per_loop << " ns for each read"; - LOGINFO("%s", s.str().c_str()) + ns_per_loop = (double)(elapsed_us * 1000) / (double)loop_count; + LOGINFO("%s", ("Read the SCSI bus " + to_string(loop_count) + " times with an average of " + + to_string(ns_per_loop) + " ns for each read").c_str()) Cleanup(); diff --git a/cpp/monitor/sm_core.h b/cpp/monitor/sm_core.h index a39354b6..4bf0c6a3 100644 --- a/cpp/monitor/sm_core.h +++ b/cpp/monitor/sm_core.h @@ -9,10 +9,14 @@ #pragma once +#include "hal/bus.h" +#include "monitor/data_sample.h" #include +#include using namespace std; +// TODO Make static fields/methods non-static class ScsiMon { public: @@ -24,12 +28,35 @@ public: private: - void parse_arguments(const vector&); - void print_copyright_text(); - void print_help_text(const vector&); - void Banner(); + void ParseArguments(const vector&); + void PrintCopyrightText() const; + void PrintHelpText(const vector&) const; + void Banner() const; bool Init(); - void Cleanup(); - void Reset(); - void FixCpu(int); + void Cleanup() const; + void Reset() const; + void FixCpu(int) const; + + static void KillHandler(int); + + static inline volatile bool running; + + unique_ptr bus; + + uint32_t buff_size = 1000000; + + data_capture *data_buffer = nullptr; + + uint32_t data_idx = 0; + + bool print_help = false; + + bool import_data = false; + + string file_base_name = "log"; + string vcd_file_name; + string json_file_name; + string html_file_name; + string input_file_name; + }; diff --git a/cpp/monitor/sm_json_report.cpp b/cpp/monitor/sm_json_report.cpp index 2389edd9..0d7f9283 100644 --- a/cpp/monitor/sm_json_report.cpp +++ b/cpp/monitor/sm_json_report.cpp @@ -43,7 +43,7 @@ uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture continue; strncpy(data, &data_str[strlen(data_label)], 8); data[8] = '\0'; - data_uint = strtoul(data, &ptr, 16); + data_uint = static_cast(strtoul(data, &ptr, 16)); data_capture_array[sample_count].timestamp = timestamp_uint; data_capture_array[sample_count].data = data_uint; diff --git a/cpp/monitor/sm_vcd_report.cpp b/cpp/monitor/sm_vcd_report.cpp index 3fe287ba..68d85da7 100644 --- a/cpp/monitor/sm_vcd_report.cpp +++ b/cpp/monitor/sm_vcd_report.cpp @@ -75,8 +75,8 @@ static uint8_t get_data_field(uint32_t data) static void vcd_output_if_changed_phase(ofstream& fp, uint32_t data, int pin, char symbol) { const BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data); - if (prev_value[pin] != static_cast(new_value)) { - prev_value[pin] = static_cast(new_value); + if (prev_value[pin] != static_cast(new_value)) { + prev_value[pin] = static_cast(new_value); fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl; } } @@ -164,7 +164,7 @@ void scsimon_generate_value_change_dump(const char *filename, const data_capture uint32_t i = 0; while (i < capture_count) { - vcd_ofstream << "#" << (uint64_t)(data_capture_array[i].timestamp * ns_per_loop) << endl; + vcd_ofstream << "#" << (uint64_t)((double)data_capture_array[i].timestamp * ns_per_loop) << endl; vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_BSY, SYMBOL_PIN_BSY); vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL); vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD); diff --git a/cpp/rascsi/rascsi_core.cpp b/cpp/rascsi/rascsi_core.cpp index eceb3e5b..47465c03 100644 --- a/cpp/rascsi/rascsi_core.cpp +++ b/cpp/rascsi/rascsi_core.cpp @@ -16,9 +16,8 @@ #include "controllers/scsi_controller.h" #include "devices/device_factory.h" #include "devices/storage_device.h" -#include "hal/gpiobus.h" #include "hal/gpiobus_factory.h" -#include "hal/sbc_version.h" +#include "hal/gpiobus.h" #include "hal/systimer.h" #include "rascsi_version.h" #include "protobuf_serializer.h" @@ -68,20 +67,11 @@ void Rascsi::Banner(const vector& args) const bool Rascsi::InitBus() const { -#ifdef USE_SEL_EVENT_ENABLE - SBC_Version::Init(); -#endif - - // GPIOBUS creation - bus = GPIOBUS_Factory::Create(); - - // GPIO Initialization - if (!bus->Init()) { + bus = GPIOBUS_Factory::Create(BUS::mode_e::TARGET); + if (bus == nullptr) { return false; } - bus->Reset(); - auto b = bus; controller_manager = make_shared(*b); auto c = controller_manager; diff --git a/cpp/rascsi/rascsi_core.h b/cpp/rascsi/rascsi_core.h index ef13b912..6690ea0b 100644 --- a/cpp/rascsi/rascsi_core.h +++ b/cpp/rascsi/rascsi_core.h @@ -19,8 +19,7 @@ using namespace std; -// TODO Only BUS should be known -class GPIOBUS; +class BUS; class ControllerManager; class RascsiExecutor; @@ -61,7 +60,7 @@ private: const static inline RascsiResponse rascsi_response; - static inline shared_ptr bus; + static inline shared_ptr bus; static inline shared_ptr controller_manager; diff --git a/cpp/rasdump/rasdump_core.cpp b/cpp/rasdump/rasdump_core.cpp index 150e7396..904c25b9 100644 --- a/cpp/rasdump/rasdump_core.cpp +++ b/cpp/rasdump/rasdump_core.cpp @@ -1,172 +1,121 @@ //--------------------------------------------------------------------------- // -// SCSI Target Emulator RaSCSI Reloaded -// for Raspberry Pi +// SCSI Target Emulator RaSCSI Reloaded +// for Raspberry Pi // -// Powered by XM6 TypeG Technology. -// Copyright (C) 2016-2020 GIMONS -// [ HDD dump utility (initiator mode) ] +// Powered by XM6 TypeG Technology. +// Copyright (C) 2016-2020 GIMONS +// Copyright (C) 2022 Uwe Seimet // //--------------------------------------------------------------------------- -#include -#include -#include -#include "rasdump/rasdump_fileio.h" -#include "rasdump/rasdump_core.h" -#include "hal/gpiobus.h" +// TODO Evaluate CHECK CONDITION + +#include "log.h" #include "hal/gpiobus_factory.h" +#include "hal/gpiobus.h" #include "hal/systimer.h" #include "rascsi_version.h" +#include "rasdump/rasdump_core.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include +#include +#include #include #include -#include +#include using namespace std; +using namespace spdlog; +using namespace scsi_defs; -//--------------------------------------------------------------------------- -// -// Constant Declaration -// -//--------------------------------------------------------------------------- -static const int BUFSIZE = 1024 * 64; // Buffer size of about 64KB - -//--------------------------------------------------------------------------- -// -// Variable Declaration -// -//--------------------------------------------------------------------------- -unique_ptr bus; // GPIO Bus -int targetid; // Target ID -int boardid; // Board ID (own ID) -string hdsfile; // HDS file -bool restore; // Restore flag -array buffer; // Work Buffer -int result; // Result Code - -//--------------------------------------------------------------------------- -// -// Cleanup() Function declaration -// -//--------------------------------------------------------------------------- -void Cleanup(); - -//--------------------------------------------------------------------------- -// -// Signal processing -// -//--------------------------------------------------------------------------- -void KillHandler(int) +void RasDump::CleanUp() { - // Stop running - Cleanup(); - exit(0); + if (bus != nullptr) { + bus->Cleanup(); + } } -//--------------------------------------------------------------------------- -// -// Banner Output -// -//--------------------------------------------------------------------------- -bool RasDump::Banner(const vector& args) +void RasDump::KillHandler(int) { - printf("RaSCSI hard disk dump utility "); - printf("version %s (%s, %s)\n", - rascsi_get_version_string().c_str(), - __DATE__, - __TIME__); + CleanUp(); + + exit(EXIT_SUCCESS); +} + +bool RasDump::Banner(const vector& args) const +{ + cout << "RaSCSI hard disk dump utility version " << rascsi_get_version_string() + << " (" << __DATE__ << ", " << __TIME__ << ")\n" << flush; + + if (args.size() < 2 || string(args[1]) == "-h") { + cout << "Usage: " << args[0] << " -t ID[:LUN] [-i BID] -f FILE [-v] [-r] [-s BUFFER_SIZE]\n" + << " ID is the target device ID (0-7).\n" + << " LUN is the optional target device LUN (0-7). Default is 0.\n" + << " BID is the RaSCSI board ID (0-7). Default is 7.\n" + << " FILE is the dump file path.\n" + << " BUFFER_SIZE is the transfer buffer size, at least " + << to_string(MINIMUM_BUFFER_SIZE / 1024) << " KiB. Default is 1 MiB.\n" + << " -v Enable verbose logging.\n" + << " -r Restore instead of dump.\n" << flush; - if (args.size() < 2 || strcmp(args[1], "-h") == 0) { - printf("Usage: %s -i ID [-b BID] -f FILE [-r]\n", args[0]); - printf(" ID is target device SCSI ID {0|1|2|3|4|5|6|7}.\n"); - printf(" BID is rascsi board SCSI ID {0|1|2|3|4|5|6|7}. Default is 7.\n"); - printf(" FILE is HDS file path.\n"); - printf(" -r is restore operation.\n"); return false; } return true; } -//--------------------------------------------------------------------------- -// -// Initialization -// -//--------------------------------------------------------------------------- -bool RasDump::Init() +bool RasDump::Init() const { // Interrupt handler setting - if (signal(SIGINT, KillHandler) == SIG_ERR) { - return false; - } - if (signal(SIGHUP, KillHandler) == SIG_ERR) { - return false; - } - if (signal(SIGTERM, KillHandler) == SIG_ERR) { + if (signal(SIGINT, KillHandler) == SIG_ERR || signal(SIGHUP, KillHandler) == SIG_ERR || + signal(SIGTERM, KillHandler) == SIG_ERR) { return false; } - bus = GPIOBUS_Factory::Create(); + bus = GPIOBUS_Factory::Create(BUS::mode_e::INITIATOR); - // GPIO Initialization - if (!bus->Init(BUS::mode_e::INITIATOR)) { - return false; - } - - // Work Intitialization - targetid = -1; - boardid = 7; - restore = false; - - return true; + return bus != nullptr; } -//--------------------------------------------------------------------------- -// -// Cleanup -// -//--------------------------------------------------------------------------- -void Cleanup() -{ - // Cleanup the bus - bus->Cleanup(); -} - -//--------------------------------------------------------------------------- -// -// Reset -// -//--------------------------------------------------------------------------- -void RasDump::Reset() -{ - // Reset the bus signal line - bus->Reset(); -} - -//--------------------------------------------------------------------------- -// -// Argument processing -// -//--------------------------------------------------------------------------- -bool RasDump::ParseArguments(const vector& args) +void RasDump::ParseArguments(const vector& args) { int opt; - const char *file = nullptr; - // Argument Parsing + int buffer_size = DEFAULT_BUFFER_SIZE; + opterr = 0; - while ((opt = getopt(args.size(), args.data(), "i:b:f:r")) != -1) { + while ((opt = getopt(static_cast(args.size()), args.data(), "i:f:s:t:u:rv")) != -1) { switch (opt) { case 'i': - targetid = optarg[0] - '0'; - break; - - case 'b': - boardid = optarg[0] - '0'; + if (!GetAsInt(optarg, initiator_id) || initiator_id > 7) { + throw rasdump_exception("Invalid RaSCSI board ID " + to_string(initiator_id) + " (0-7)"); + } break; case 'f': - file = optarg; + filename = optarg; + break; + + case 's': + if (!GetAsInt(optarg, buffer_size) || buffer_size < MINIMUM_BUFFER_SIZE) { + throw rasdump_exception("Buffer size must be at least " + to_string(MINIMUM_BUFFER_SIZE / 1024) + "KiB"); + } + + break; + + case 't': + ProcessId(optarg, target_id, target_lun); + break; + + case 'u': + if (!GetAsInt(optarg, target_lun) || target_lun > 7) { + throw rasdump_exception("Invalid target LUN " + to_string(target_lun) + " (0-7)"); + } + break; + + case 'v': + set_level(level::debug); break; case 'r': @@ -178,86 +127,259 @@ bool RasDump::ParseArguments(const vector& args) } } - // TARGET ID check - if (targetid < 0 || targetid > 7) { - fprintf(stderr, - "Error : Invalid target id range\n"); - return false; + if (target_id == initiator_id) { + throw rasdump_exception("Target ID and RaSCSI board ID must not be identical"); } - // BOARD ID check - if (boardid < 0 || boardid > 7) { - fprintf(stderr, - "Error : Invalid board id range\n"); - return false; + if (filename.empty()) { + throw rasdump_exception("Missing filename"); } - // Target and Board ID duplication check - if (targetid == boardid) { - fprintf(stderr, - "Error : Invalid target or board id\n"); - return false; - } - - // File Check - if (!file) { - fprintf(stderr, - "Error : Invalid file path\n"); - return false; - } - - hdsfile = file; - - return true; + buffer = vector(buffer_size); } -//--------------------------------------------------------------------------- -// -// Wait Phase -// -//--------------------------------------------------------------------------- -bool RasDump::WaitPhase(BUS::phase_t phase) +void RasDump::WaitPhase(BUS::phase_t phase) const { + LOGDEBUG("Waiting for %s phase", BUS::GetPhaseStrRaw(phase)) + // Timeout (3000ms) const uint32_t now = SysTimer::GetTimerLow(); while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) { bus->Acquire(); if (bus->GetREQ() && bus->GetPhase() == phase) { - return true; + return; } } - return false; + throw rasdump_exception("Expected " + string(BUS::GetPhaseStrRaw(phase)) + " phase, actual phase is " + + string(BUS::GetPhaseStrRaw(bus->GetPhase()))); } -//--------------------------------------------------------------------------- -// -// Bus Free Phase -// -//--------------------------------------------------------------------------- -void RasDump::BusFree() +void RasDump::Selection() const +{ + // Set initiator and target ID + auto data = static_cast(1 << initiator_id); + data |= (1 << target_id); + bus->SetDAT(data); + + bus->SetSEL(true); + //bus->SetATN(true); + + WaitForBusy(); + + bus->SetSEL(false); + + // TODO Send IDENTIFY message for LUN selection + //buffer[0] = 0x80 | target_lun; + //MessageOut(); + + //bus->SetATN(false); +} + +void RasDump::Command(scsi_command cmd, vector& cdb) const +{ + LOGDEBUG("Executing %s", command_mapping.find(cmd)->second.second) + + Selection(); + + WaitPhase(BUS::phase_t::command); + + // Send command. Success if the transmission result is the same as the number of requests + cdb[0] = static_cast(cmd); + cdb[1] |= target_lun << 5; + if (static_cast(cdb.size()) != bus->SendHandShake(cdb.data(), static_cast(cdb.size()), BUS::SEND_NO_DELAY)) { + BusFree(); + + throw rasdump_exception(command_mapping.find(cmd)->second.second + string(" failed")); + } +} + +void RasDump::DataIn(int length) +{ + WaitPhase(BUS::phase_t::datain); + + if (!bus->ReceiveHandShake(buffer.data(), length)) { + throw rasdump_exception("DATA IN failed"); + } +} + +void RasDump::DataOut(int length) +{ + WaitPhase(BUS::phase_t::dataout); + + if (!bus->SendHandShake(buffer.data(), length, BUS::SEND_NO_DELAY)) { + throw rasdump_exception("DATA OUT failed"); + } +} + +void RasDump::Status() const +{ + WaitPhase(BUS::phase_t::status); + + if (array buf; bus->ReceiveHandShake(buf.data(), 1) != 1) { + throw rasdump_exception("STATUS failed"); + } +} + +void RasDump::MessageIn() const +{ + WaitPhase(BUS::phase_t::msgin); + + if (array buf; bus->ReceiveHandShake(buf.data(), 1) != 1) { + throw rasdump_exception("MESSAGE IN failed"); + } +} + +void RasDump::MessageOut() +{ + WaitPhase(BUS::phase_t::msgout); + + if (!bus->SendHandShake(buffer.data(), 1, BUS::SEND_NO_DELAY)) { + throw rasdump_exception("MESSAGE OUT failed"); + } +} + +void RasDump::BusFree() const { - // Bus Reset bus->Reset(); } -//--------------------------------------------------------------------------- -// -// Selection Phase -// -//--------------------------------------------------------------------------- -bool RasDump::Selection(int id) +void RasDump::TestUnitReady() const { - // ID setting and SEL assert - uint8_t data = 1 << boardid; - data |= (1 << id); - bus->SetDAT(data); - bus->SetSEL(true); + vector cdb(6); + Command(scsi_command::eCmdTestUnitReady, cdb); - // wait for busy + Status(); + + MessageIn(); + + BusFree(); +} + +void RasDump::RequestSense() +{ + vector cdb(6); + cdb[4] = 0xff; + Command(scsi_command::eCmdRequestSense, cdb); + + DataIn(256); + + Status(); + + MessageIn(); + + BusFree(); +} + +void RasDump::Inquiry() +{ + vector cdb(6); + cdb[4] = 0xff; + Command(scsi_command::eCmdInquiry, cdb); + + DataIn(256); + + Status(); + + MessageIn(); + + BusFree(); +} + +pair RasDump::ReadCapacity() +{ + vector cdb(10); + Command(scsi_command::eCmdReadCapacity10, cdb); + + DataIn(8); + + Status(); + + MessageIn(); + + BusFree(); + + uint64_t capacity = (static_cast(buffer[0]) << 24) | (static_cast(buffer[1]) << 16) | + (static_cast(buffer[2]) << 8) | static_cast(buffer[3]); + + int sector_size_offset = 4; + + if (static_cast(capacity) == -1) { + cdb.resize(16); + // READ CAPACITY(16), not READ LONG(16) + cdb[1] = 0x10; + Command(scsi_command::eCmdReadCapacity16_ReadLong16, cdb); + + DataIn(14); + + Status(); + + MessageIn(); + + BusFree(); + + capacity = (static_cast(buffer[0]) << 56) | (static_cast(buffer[1]) << 48) | + (static_cast(buffer[2]) << 40) | (static_cast(buffer[3]) << 32) | + (static_cast(buffer[4]) << 24) | (static_cast(buffer[5]) << 16) | + (static_cast(buffer[6]) << 8) | static_cast(buffer[7]); + + sector_size_offset = 8; + } + + const uint32_t sector_size = (static_cast(buffer[sector_size_offset]) << 24) | + (static_cast(buffer[sector_size_offset + 1]) << 16) | + (static_cast(buffer[sector_size_offset +2]) << 8) | + static_cast(buffer[sector_size_offset + 3]); + + return make_pair(capacity, sector_size); +} + +void RasDump::Read10(uint32_t bstart, uint32_t blength, uint32_t length) +{ + vector cdb(10); + cdb[2] = (uint8_t)(bstart >> 24); + cdb[3] = (uint8_t)(bstart >> 16); + cdb[4] = (uint8_t)(bstart >> 8); + cdb[5] = (uint8_t)bstart; + cdb[7] = (uint8_t)(blength >> 8); + cdb[8] = (uint8_t)blength; + Command(scsi_command::eCmdRead10, cdb); + + DataIn(length); + + Status(); + + MessageIn(); + + BusFree(); +} + +void RasDump::Write10(uint32_t bstart, uint32_t blength, uint32_t length) +{ + vector cdb(10); + cdb[2] = (uint8_t)(bstart >> 24); + cdb[3] = (uint8_t)(bstart >> 16); + cdb[4] = (uint8_t)(bstart >> 8); + cdb[5] = (uint8_t)bstart; + cdb[7] = (uint8_t)(blength >> 8); + cdb[8] = (uint8_t)blength; + Command(scsi_command::eCmdWrite10, cdb); + + DataOut(length); + + Status(); + + MessageIn(); + + BusFree(); +} + +void RasDump::WaitForBusy() const +{ + // Wait for busy for up to 2 s int count = 10000; do { - // Wait 20 microseconds + // Wait 20 ms const timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000}; nanosleep(&ts, nullptr); bus->Acquire(); @@ -266,733 +388,197 @@ bool RasDump::Selection(int id) } } while (count--); - // SEL negate - bus->SetSEL(false); - // Success if the target is busy - return bus->GetBSY(); + if(!bus->GetBSY()) { + throw rasdump_exception("SELECTION failed"); + } } -//--------------------------------------------------------------------------- -// -// Command Phase -// -//--------------------------------------------------------------------------- -bool RasDump::Command(uint8_t *buf, int length) -{ - // Waiting for Phase - if (!WaitPhase(BUS::phase_t::command)) { - return false; - } - - // Send Command - const int count = bus->SendHandShake(buf, length, BUS::SEND_NO_DELAY); - - // Success if the transmission result is the same as the number - // of requests - if (count == length) { - return true; - } - - // Return error - return false; -} - -//--------------------------------------------------------------------------- -// -// Data in phase -// -//--------------------------------------------------------------------------- -int RasDump::DataIn(uint8_t *buf, int length) -{ - // Wait for phase - if (!WaitPhase(BUS::phase_t::datain)) { - return -1; - } - - // Data reception - return bus->ReceiveHandShake(buf, length); -} - -//--------------------------------------------------------------------------- -// -// Data out phase -// -//--------------------------------------------------------------------------- -int RasDump::DataOut(uint8_t *buf, int length) -{ - // Wait for phase - if (!WaitPhase(BUS::phase_t::dataout)) { - return -1; - } - - // Data transmission - return bus->SendHandShake(buf, length, BUS::SEND_NO_DELAY); -} - -//--------------------------------------------------------------------------- -// -// Status Phase -// -//--------------------------------------------------------------------------- -int RasDump::Status() -{ - uint8_t buf[256]; - - // Wait for phase - if (!WaitPhase(BUS::phase_t::status)) { - return -2; - } - - // Data reception - if (bus->ReceiveHandShake(buf, 1) == 1) { - return (int)buf[0]; - } - - // Return error - return -1; -} - -//--------------------------------------------------------------------------- -// -// Message in phase -// -//--------------------------------------------------------------------------- -int RasDump::MessageIn() -{ - uint8_t buf[256]; - - // Wait for phase - if (!WaitPhase(BUS::phase_t::msgin)) { - return -2; - } - - // Data reception - if (bus->ReceiveHandShake(buf, 1) == 1) { - return (int)buf[0]; - } - - // Return error - return -1; -} - -//--------------------------------------------------------------------------- -// -// TEST UNIT READY -// -//--------------------------------------------------------------------------- -int RasDump::TestUnitReady(int id) -{ - array cmd = {}; - - // Result code initialization - result = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x00; - if (!Command(cmd.data(), 6)) { - result = -2; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus free - BusFree(); - - return result; -} - -//--------------------------------------------------------------------------- -// -// REQUEST SENSE -// -//--------------------------------------------------------------------------- -int RasDump::RequestSense(int id, uint8_t *buf) -{ - array cmd = {}; - - // Result code initialization - result = 0; - int count = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x03; - cmd[4] = 0xff; - if (!Command(cmd.data(), 6)) { - result = -2; - goto exit; - } - - // DATAIN - memset(buf, 0x00, 256); - count = DataIn(buf, 256); - if (count <= 0) { - result = -3; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus Free - BusFree(); - - // Returns the number of transfers if successful - if (result == 0) { - return count; - } - - return result; -} - -//--------------------------------------------------------------------------- -// -// MODE SENSE -// -//--------------------------------------------------------------------------- -int RasDump::ModeSense(int id, uint8_t *buf) -{ - array cmd = {}; - - // Result code initialization - result = 0; - int count = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x1a; - cmd[2] = 0x3f; - cmd[4] = 0xff; - if (!Command(cmd.data(), 6)) { - result = -2; - goto exit; - } - - // DATAIN - memset(buf, 0x00, 256); - count = DataIn(buf, 256); - if (count <= 0) { - result = -3; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus free - BusFree(); - - // Returns the number of transfers if successful - if (result == 0) { - return count; - } - - return result; -} - -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- -int RasDump::Inquiry(int id, uint8_t *buf) -{ - array cmd = {}; - - // Result code initialization - result = 0; - int count = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x12; - cmd[4] = 0xff; - if (!Command(cmd.data(), 6)) { - result = -2; - goto exit; - } - - // DATAIN - memset(buf, 0x00, 256); - count = DataIn(buf, 256); - if (count <= 0) { - result = -3; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus free - BusFree(); - - // Returns the number of transfers if successful - if (result == 0) { - return count; - } - - return result; -} - -//--------------------------------------------------------------------------- -// -// READ CAPACITY -// -//--------------------------------------------------------------------------- -int RasDump::ReadCapacity(int id, uint8_t *buf) -{ - array cmd = {}; - - // Result code initialization - result = 0; - int count = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x25; - if (!Command(cmd.data(), 10)) { - result = -2; - goto exit; - } - - // DATAIN - memset(buf, 0x00, 8); - count = DataIn(buf, 8); - if (count <= 0) { - result = -3; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus free - BusFree(); - - // Returns the number of transfers if successful - if (result == 0) { - return count; - } - - return result; -} - -//--------------------------------------------------------------------------- -// -// READ10 -// -//--------------------------------------------------------------------------- -int RasDump::Read10(int id, uint32_t bstart, uint32_t blength, uint32_t length, uint8_t *buf) -{ - array cmd = {}; - - // Result code initialization - result = 0; - int count = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x28; - cmd[2] = (uint8_t)(bstart >> 24); - cmd[3] = (uint8_t)(bstart >> 16); - cmd[4] = (uint8_t)(bstart >> 8); - cmd[5] = (uint8_t)bstart; - cmd[7] = (uint8_t)(blength >> 8); - cmd[8] = (uint8_t)blength; - if (!Command(cmd.data(), 10)) { - result = -2; - goto exit; - } - - // DATAIN - count = DataIn(buf, length); - if (count <= 0) { - result = -3; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus free - BusFree(); - - // Returns the number of transfers if successful - if (result == 0) { - return count; - } - - return result; -} - -//--------------------------------------------------------------------------- -// -// WRITE10 -// -//--------------------------------------------------------------------------- -int RasDump::Write10(int id, uint32_t bstart, uint32_t blength, uint32_t length, uint8_t *buf) -{ - array cmd = {}; - - // Result code initialization - result = 0; - int count = 0; - - // SELECTION - if (!Selection(id)) { - result = -1; - goto exit; - } - - // COMMAND - cmd[0] = 0x2a; - cmd[2] = (uint8_t)(bstart >> 24); - cmd[3] = (uint8_t)(bstart >> 16); - cmd[4] = (uint8_t)(bstart >> 8); - cmd[5] = (uint8_t)bstart; - cmd[7] = (uint8_t)(blength >> 8); - cmd[8] = (uint8_t)blength; - if (!Command(cmd.data(), 10)) { - result = -2; - goto exit; - } - - // DATAOUT - count = DataOut(buf, length); - if (count <= 0) { - result = -3; - goto exit; - } - - // STATUS - if (Status() < 0) { - result = -4; - goto exit; - } - - // MESSAGE IN - if (MessageIn() < 0) { - result = -5; - goto exit; - } - -exit: - // Bus free - BusFree(); - - // Returns the number of transfers if successful - if (result == 0) { - return count; - } - - return result; -} - -//--------------------------------------------------------------------------- -// -// Main process -// -//--------------------------------------------------------------------------- int RasDump::run(const vector& args) { - int i; - char str[32]; - uint32_t bsiz; - uint32_t bnum; - uint32_t duni; - uint32_t dsiz; - uint32_t dnum; - Fileio fio; - Fileio::OpenMode omode; - off_t size; - - // Banner output if (!Banner(args)) { - exit(0); + return EXIT_SUCCESS; } - // Initialization if (!Init()) { - fprintf(stderr, "Error : Initializing. Are you root?\n"); + cerr << "Error: Initializing. Are you root?" << endl; // Probably not root - exit(EPERM); + return EPERM; } - // Prase Argument - if (!ParseArguments(args)) { - // Cleanup - Cleanup(); - - // Exit with invalid argument error - exit(EINVAL); - } + try { + ParseArguments(args); #ifndef USE_SEL_EVENT_ENABLE - cerr << "Error: No RaSCSI hardware support" << endl; - exit(EXIT_FAILURE); + cerr << "Error: No RaSCSI hardware support" << endl; + return EXIT_FAILURE; #endif - // Reset the SCSI bus - Reset(); - - // File Open - if (restore) { - omode = Fileio::OpenMode::ReadOnly; - } else { - omode = Fileio::OpenMode::WriteOnly; + return DumpRestore(); } - if (!fio.Open(hdsfile.c_str(), omode)) { - fprintf(stderr, "Error : Can't open hds file\n"); + catch(const rasdump_exception& e) { + cerr << "Error: " << e.what() << endl; - // Cleanup - Cleanup(); - exit(EPERM); + CleanUp(); + + return EXIT_FAILURE; } - // Bus free - BusFree(); + CleanUp(); - // Assert reset signal + return EXIT_SUCCESS; +} + +int RasDump::DumpRestore() +{ + fstream fs; + fs.open(filename, (restore ? ios::in : ios::out) | ios::binary); + + if (fs.fail()) { + throw rasdump_exception("Can't open image file '" + filename + "'"); + } + + // Assert RST for 1 ms bus->SetRST(true); - // Wait 1 ms const timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000}; nanosleep(&ts, nullptr); bus->SetRST(false); - // Start dump - printf("TARGET ID : %d\n", targetid); - printf("BOARD ID : %d\n", boardid); + cout << "Target device ID: " << target_id << ", LUN: " << target_lun << "\n"; + cout << "RaSCSI board ID: " << initiator_id << "\n" << flush; - // TEST UNIT READY - int count = TestUnitReady(targetid); - if (count < 0) { - fprintf(stderr, "TEST UNIT READY ERROR %d\n", count); - goto cleanup_exit; - } - - // REQUEST SENSE(for CHECK CONDITION) - count = RequestSense(targetid, buffer.data()); - if (count < 0) { - fprintf(stderr, "REQUEST SENSE ERROR %d\n", count); - goto cleanup_exit; - } - - // INQUIRY - count = Inquiry(targetid, buffer.data()); - if (count < 0) { - fprintf(stderr, "INQUIRY ERROR %d\n", count); - goto cleanup_exit; - } + Inquiry(); // Display INQUIRY information - memset(str, 0x00, sizeof(str)); - memcpy(str, &buffer[8], 8); - printf("Vendor : %s\n", str); - memset(str, 0x00, sizeof(str)); - memcpy(str, &buffer[16], 16); - printf("Product : %s\n", str); - memset(str, 0x00, sizeof(str)); - memcpy(str, &buffer[32], 4); - printf("Revison : %s\n", str); + array str = {}; + memcpy(str.data(), &buffer[8], 8); + cout << "Vendor: " << str.data() << "\n"; + str.fill(0); + memcpy(str.data(), &buffer[16], 16); + cout << "Product: " << str.data() << "\n"; + str.fill(0); + memcpy(str.data(), &buffer[32], 4); + cout << "Revision: " << str.data() << "\n" << flush; - // Get drive capacity - count = ReadCapacity(targetid, buffer.data()); - if (count < 0) { - fprintf(stderr, "READ CAPACITY ERROR %d\n", count); - goto cleanup_exit; + if (auto type = static_cast(buffer[0]); + type != device_type::DIRECT_ACCESS && type != device_type::CD_ROM && type != device_type::OPTICAL_MEMORY) { + throw rasdump_exception("Invalid device type, supported types are DIRECT ACCESS, CD-ROM and OPTICAL MEMORY"); } - // Display block size and number of blocks - bsiz = - (buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | buffer[7]; - bnum = - (buffer[0] << 24) | (buffer[1] << 16) | - (buffer[2] << 8) | buffer[3]; - bnum++; - printf("Number of blocks : %d Blocks\n", (int)bnum); - printf("Block length : %d Bytes\n", (int)bsiz); - printf("Unit Capacity : %d MBytes %d Bytes\n", - (int)(bsiz * bnum / 1024 / 1024), - (int)(bsiz * bnum)); + TestUnitReady(); + + RequestSense(); + + const auto [capacity, sector_size] = ReadCapacity(); + + cout << "Number of sectors: " << capacity << "\n" + << "Sector size: " << sector_size << " bytes\n" + << "Capacity: " << sector_size * capacity / 1024 / 1024 << " MiB (" + << sector_size * capacity << " bytes)\n\n" << flush; - // Get the restore file size if (restore) { - size = fio.GetFileSize(); - printf("Restore file size : %d bytes", (int)size); - if (size > (off_t)(bsiz * bnum)) { - printf("(WARNING : File size is larger than disk size)"); - } else if (size < (off_t)(bsiz * bnum)) { - printf("(ERROR : File size is smaller than disk size)\n"); - goto cleanup_exit; + cout << "Starting restore\n" << flush; + + // filesystem::file_size cannot be used here because gcc < 10.3.0 cannot handle more than 2 GiB + off_t size; + if (struct stat st; !stat(filename.c_str(), &st)) { + size = st.st_size; } - printf("\n"); + else { + throw rasdump_exception("Can't determine file size"); + } + + cout << "Restore file size: " << size << " bytes\n"; + if (size > (off_t)(sector_size * capacity)) { + cout << "WARNING: File size is larger than disk size\n" << flush; + } else if (size < (off_t)(sector_size * capacity)) { + throw rasdump_exception("File size is smaller than disk size"); + } + } + else { + cout << "Starting dump\n" << flush; } // Dump by buffer size - duni = BUFSIZE; - duni /= bsiz; - dsiz = BUFSIZE; - dnum = bnum * bsiz; - dnum /= BUFSIZE; - - if (restore) { - printf("Restore progress : "); - } else { - printf("Dump progress : "); - } - - for (i = 0; i < (int)dnum; i++) { - if (i > 0) { - printf("\033[21D"); - printf("\033[0K"); - } - printf("%3d%%(%7d/%7d)", - (int)((i + 1) * 100 / dnum), - (int)(i * duni), - (int)bnum); - fflush(stdout); + auto dsiz = static_cast(buffer.size()); + const int duni = dsiz / sector_size; + int dnum = static_cast((capacity * sector_size) / dsiz); + int i; + for (i = 0; i < dnum; i++) { if (restore) { - if (fio.Read(buffer.data(), dsiz) && Write10(targetid, i * duni, duni, dsiz, buffer.data()) >= 0) { - continue; - } - } else { - if (Read10(targetid, i * duni, duni, dsiz, buffer.data()) >= 0 && fio.Write(buffer.data(), dsiz)) { - continue; - } + fs.read((char *)buffer.data(), dsiz); + Write10(i * duni, duni, dsiz); + } + else { + Read10(i * duni, duni, dsiz); + fs.write((const char *)buffer.data(), dsiz); } - printf("\n"); - printf("Error occured and aborted... %d\n", result); - goto cleanup_exit; - } + if (fs.fail()) { + throw rasdump_exception("File I/O failed"); + } - if (dnum > 0) { - printf("\033[21D"); - printf("\033[0K"); + cout << ((i + 1) * 100 / dnum) << "%" << " (" << ( i + 1) * duni << "/" << capacity << ")\n" << flush; } // Rounding on capacity - dnum = bnum % duni; - dsiz = dnum * bsiz; + dnum = capacity % duni; + dsiz = dnum * sector_size; if (dnum > 0) { if (restore) { - if (fio.Read(buffer.data(), dsiz)) { - Write10(targetid, i * duni, dnum, dsiz, buffer.data()); - } - } else { - if (Read10(targetid, i * duni, dnum, dsiz, buffer.data()) >= 0) { - fio.Write(buffer.data(), dsiz); + fs.read((char *)buffer.data(), dsiz); + if (!fs.fail()) { + Write10(i * duni, dnum, dsiz); } } + else { + Read10(i * duni, dnum, dsiz); + fs.write((const char *)buffer.data(), dsiz); + } + + if (fs.fail()) { + throw rasdump_exception("File I/O failed"); + } + + cout << "100% (" << capacity << "/" << capacity << ")\n" << flush; } - // Completion Message - printf("%3d%%(%7d/%7d)\n", 100, (int)bnum, (int)bnum); - -cleanup_exit: - // File close - fio.Close(); - - // Cleanup - Cleanup(); - - // end - exit(0); + return EXIT_SUCCESS; +} + +void RasDump::ProcessId(const string& id_spec, int& id, int& lun) +{ + if (const size_t separator_pos = id_spec.find(COMPONENT_SEPARATOR); separator_pos == string::npos) { + if (!GetAsInt(id_spec, id) || id >= 8) { + throw rasdump_exception("Invalid device ID (0-7)"); + } + + lun = 0; + } + else if (!GetAsInt(id_spec.substr(0, separator_pos), id) || id < 0 || id > 7 || + !GetAsInt(id_spec.substr(separator_pos + 1), lun) || lun >= 32) { + throw rasdump_exception("Invalid unit (0-7)"); + } +} + +bool RasDump::GetAsInt(const string& value, int& result) +{ + if (value.find_first_not_of("0123456789") != string::npos) { + return false; + } + + try { + auto v = stoul(value); + result = (int)v; + } + catch(const invalid_argument&) { + return false; + } + catch(const out_of_range&) { + return false; + } + + return true; } diff --git a/cpp/rasdump/rasdump_core.h b/cpp/rasdump/rasdump_core.h index 21bf806e..4a66ccec 100644 --- a/cpp/rasdump/rasdump_core.h +++ b/cpp/rasdump/rasdump_core.h @@ -9,13 +9,27 @@ #pragma once +#include "scsi.h" #include "hal/bus.h" +#include #include +#include +#include using namespace std; +class rasdump_exception : public runtime_error +{ + using runtime_error::runtime_error; +}; + class RasDump { + static const char COMPONENT_SEPARATOR = ':'; + + static const int MINIMUM_BUFFER_SIZE = 1024 * 64; + static const int DEFAULT_BUFFER_SIZE = 1024 * 1024; + public: RasDump() = default; @@ -25,23 +39,47 @@ public: private: - bool Banner(const vector&); - bool Init(); - void Reset(); - bool ParseArguments(const vector&); - bool WaitPhase(BUS::phase_t); - void BusFree(); - bool Selection(int); - bool Command(uint8_t *, int); - int DataIn(uint8_t *, int); - int DataOut(uint8_t *, int); - int Status(); - int MessageIn(); - int TestUnitReady(int); - int RequestSense(int, uint8_t *); - int ModeSense(int, uint8_t *); - int Inquiry(int, uint8_t *); - int ReadCapacity(int, uint8_t *); - int Read10(int, uint32_t, uint32_t, uint32_t, uint8_t *); - int Write10(int, uint32_t, uint32_t, uint32_t, uint8_t *); + bool Banner(const vector&) const; + bool Init() const; + void ParseArguments(const vector&); + int DumpRestore(); + void WaitPhase(BUS::phase_t) const; + void Selection() const; + void Command(scsi_defs::scsi_command, vector&) const; + void DataIn(int); + void DataOut(int); + void Status() const; + void MessageIn() const; + void MessageOut(); + void BusFree() const; + void TestUnitReady() const; + void RequestSense(); + void Inquiry(); + pair ReadCapacity(); + void Read10(uint32_t, uint32_t, uint32_t); + void Write10(uint32_t, uint32_t, uint32_t); + void WaitForBusy() const; + + // TODO Use ras_util after removing its dependencies on protobuf interface. + // Not required in case rasdump is integrated into rascsi. + static void ProcessId(const string&, int&, int&); + static bool GetAsInt(const string&, int&); + + static void CleanUp(); + static void KillHandler(int); + + // A static instance is needed because of the signal handler + static inline unique_ptr bus; + + vector buffer; + + int target_id = -1; + + int target_lun = 0; + + int initiator_id = 7; + + string filename; + + bool restore = false; }; diff --git a/cpp/rasdump/rasdump_fileio.cpp b/cpp/rasdump/rasdump_fileio.cpp deleted file mode 100644 index 4002dc8a..00000000 --- a/cpp/rasdump/rasdump_fileio.cpp +++ /dev/null @@ -1,103 +0,0 @@ -//--------------------------------------------------------------------------- -// -// X68000 EMULATOR "XM6" -// -// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) -// Copyright (C) 2010-2020 GIMONS -// [ File I/O (Subset for RaSCSI) ] -// -//--------------------------------------------------------------------------- - -#include "rasdump/rasdump_fileio.h" -#include -#include -#include - -Fileio::~Fileio() -{ - // Safety measure for Release - Close(); -} - -bool Fileio::Open(const char *fname, OpenMode mode, bool directIO) -{ - assert(fname); - assert(handle < 0); - - // Always fail a read from a null array - if (fname[0] == '\0') { - handle = -1; - return false; - } - - // Default mode - const mode_t omode = directIO ? O_DIRECT : 0; - - switch (mode) { - case OpenMode::ReadOnly: - handle = open(fname, O_RDONLY | omode); - break; - - case OpenMode::WriteOnly: - handle = open(fname, O_CREAT | O_WRONLY | O_TRUNC | omode, 0666); - break; - - case OpenMode::ReadWrite: - handle = open(fname, O_RDWR | omode); - break; - - default: - assert(false); - break; - } - - // Evaluate results - return handle != -1; -} - -bool Fileio::Open(const char *fname, OpenMode mode) -{ - return Open(fname, mode, false); -} - -bool Fileio::Read(uint8_t *buffer, int size) const -{ - assert(buffer); - assert(size > 0); - assert(handle >= 0); - - return read(handle, buffer, size) == size; -} - -bool Fileio::Write(const uint8_t *buffer, int size) const -{ - assert(buffer); - assert(size > 0); - assert(handle >= 0); - - return write(handle, buffer, size) == size; -} - -off_t Fileio::GetFileSize() const -{ - assert(handle >= 0); - - // Get file position in 64bit - const off_t cur = lseek(handle, 0, SEEK_CUR); - - // Get file size in64bitで - const off_t end = lseek(handle, 0, SEEK_END); - - // Return to start position - lseek(handle, cur, SEEK_SET); - - return end; -} - -void Fileio::Close() -{ - if (handle != -1) { - close(handle); - handle = -1; - } -} diff --git a/cpp/rasdump/rasdump_fileio.h b/cpp/rasdump/rasdump_fileio.h deleted file mode 100644 index e775dc6e..00000000 --- a/cpp/rasdump/rasdump_fileio.h +++ /dev/null @@ -1,42 +0,0 @@ -//--------------------------------------------------------------------------- -// -// X68000 EMULATOR "XM6" -// -// Copyright (C) 2001-2005 PI.(ytanaka@ipc-tokai.or.jp) -// Copyright (C) 2013-2020 GIMONS -// [ File I/O (Subset for RaSCSI) ] -// -//--------------------------------------------------------------------------- - -#pragma once - -#include -#include - -class Fileio -{ -public: - - enum class OpenMode { - ReadOnly, - WriteOnly, - ReadWrite - }; - - Fileio() = default; - virtual ~Fileio(); - Fileio(Fileio&) = default; - Fileio& operator=(const Fileio&) = default; - - bool Open(const char *fname, OpenMode mode); - bool Read(uint8_t *buffer, int size) const; - bool Write(const uint8_t *buffer, int size) const; - off_t GetFileSize() const; - void Close(); - -private: - - bool Open(const char *fname, OpenMode mode, bool directIO); - - int handle = -1; -}; diff --git a/doc/rasdump.1 b/doc/rasdump.1 index c1ea69b4..64f9313e 100644 --- a/doc/rasdump.1 +++ b/doc/rasdump.1 @@ -3,10 +3,12 @@ rasdump \- SCSI disk dumping tool for RaSCSI .SH SYNOPSIS .B rasdump -\fB\-i\fR \fIID\fR -[\fB\-b\fR \fIBID\fR] +\fB\-t\fR \fIID[:LUN]\fR +[\fB\-i\fR \fIBID\fR] \fB\-f\fR \fIFILE\fR +[\fB\-s\fR \fIBUFFER_SIZE\fR] [\fB\-r\fR] +[\fB\-v\fR] .SH DESCRIPTION .B rasdump samples the data on physical SCSI storage media, including hard drives and MO drives, and stores it to an image file. It can also restore from a dumped file onto physical SCSI storage media. Can be connected directly, through a STANDARD RaSCSI board, or a FULLSPEC RaSCSI board. @@ -15,21 +17,25 @@ Set its own ID with the BID option. Defaults to 7 if ommitted. .SH OPTIONS .TP -.BR \-i\fI " "\fIID -SCSI ID of the target device +.BR \-t\fI " "\fIID[:LUN] +SCSI ID and optional LUN of the target device. .TP -.BR \-b\fI " "\fIBID -SCSI ID of the RaSCSI device +.BR \-i\fI " "\fIBID +SCSI ID of the RaSCSI device. .TP .BR \-f\fI " "\fIFILE -Path to the dump file +Path to the dump file. +.TP +.BR \-s\fI " "\fIBUFFER_SIZE +The transfer buffer size, at least 64 KiB. Default is 64 KiB. .TP .BR \-r\fI -Restoration mode - -.SH EXAMPLES +Run in restore mode. +.TP +.BR \-v\fI +Enable verbose logging. .SH SEE ALSO -rasctl(1), rascsi(1), scsimon(1), sasidump(1) +rasctl(1), rascsi(1), scsimon(1) Full documentation is available at: diff --git a/doc/rasdump_man_page.txt b/doc/rasdump_man_page.txt new file mode 100644 index 00000000..876a4dce --- /dev/null +++ b/doc/rasdump_man_page.txt @@ -0,0 +1,42 @@ +!! ------ THIS FILE IS AUTO_GENERATED! DO NOT MANUALLY UPDATE!!! +!! ------ The native file is rasdump.1. Re-run 'make docs' after updating\n\n +rasdump(1) General Commands Manual rasdump(1) + +NAME + rasdump - SCSI disk dumping tool for RaSCSI + +SYNOPSIS + rasdump -t ID[:LUN] [-i BID] -f FILE [-s BUFFER_SIZE] [-r] [-v] + +DESCRIPTION + rasdump samples the data on physical SCSI storage media, including hard + drives and MO drives, and stores it to an image file. It can also re‐ + store from a dumped file onto physical SCSI storage media. Can be con‐ + nected directly, through a STANDARD RaSCSI board, or a FULLSPEC RaSCSI + board. + + Set its own ID with the BID option. Defaults to 7 if ommitted. + +OPTIONS + -t ID[:LUN] + SCSI ID and optional LUN of the target device. + + -i BID SCSI ID of the RaSCSI device. + + -f FILE + Path to the dump file. + + -s BUFFER_SIZE + The transfer buffer size, at least 64 KiB. Default is 64 KiB. + + -r Run in restore mode. + + -v Enable verbose logging. + +SEE ALSO + rasctl(1), rascsi(1), scsimon(1) + + Full documentation is available at: + + + rasdump(1)