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
This commit is contained in:
Uwe Seimet 2022-11-09 08:40:26 +01:00 committed by GitHub
parent e8b72c48de
commit 1c0179e7e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 2348 additions and 4280 deletions

View File

@ -56,5 +56,5 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: | 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

View File

@ -115,7 +115,8 @@ SRC_RASDUMP += $(shell find ./rasdump -name '*.cpp')
SRC_RASDUMP += $(shell find ./hal -name '*.cpp') SRC_RASDUMP += $(shell find ./hal -name '*.cpp')
SRC_RASCSI_TEST = $(shell find ./test -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 %.h ./ ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl ./rasdump
vpath %.cpp ./ ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl ./rasdump ./test 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*' 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) 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) $(SRC_SHARED) $(SRC_RASCSI_CORE) $(SRC_RASCTL_CORE): $(OBJ_PROTOBUF)

View File

@ -211,8 +211,8 @@ void ScsiController::Command()
// If not able to receive all, move to the status phase // If not able to receive all, move to the status phase
if (actual_count != command_byte_count) { if (actual_count != command_byte_count) {
LOGERROR("%s Command byte count mismatch: expected %d bytes, received %d byte(s)", __PRETTY_FUNCTION__, LOGERROR("Command byte count mismatch for command $%02X: expected %d bytes, received %d byte(s)",
command_byte_count, actual_count) GetBuffer()[0], command_byte_count, actual_count)
Error(sense_key::ABORTED_COMMAND); Error(sense_key::ABORTED_COMMAND);
return; return;
} }
@ -584,12 +584,12 @@ void ScsiController::Receive()
// Length != 0 if received // Length != 0 if received
if (HasValidLength()) { 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 not able to receive all, move to status phase
if (int len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); if (int len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength());
len != static_cast<int>(GetLength())) { len != static_cast<int>(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); Error(sense_key::ABORTED_COMMAND);
return; return;
} }
@ -692,7 +692,7 @@ void ScsiController::ReceiveBytes()
// If not able to receive all, move to status phase // If not able to receive all, move to status phase
if (uint32_t len = GetBus().ReceiveHandShake(GetBuffer().data() + GetOffset(), GetLength()); len != GetLength()) { 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) __PRETTY_FUNCTION__, GetLength(), len)
Error(sense_key::ABORTED_COMMAND); Error(sense_key::ABORTED_COMMAND);
return; return;

View File

@ -156,7 +156,7 @@ void SCSICD::CreateDataTrack()
auto track = make_unique<CDTrack>(); auto track = make_unique<CDTrack>();
track->Init(1, 0, static_cast<int>(GetBlockCount()) - 1); track->Init(1, 0, static_cast<int>(GetBlockCount()) - 1);
track->SetPath(false, GetFilename()); track->SetPath(false, GetFilename());
tracks.push_back(move(track)); tracks.push_back(std::move(track));
dataindex = 0; dataindex = 0;
} }

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include "config.h"
#include "scsi.h" #include "scsi.h"
#include <cstdint> #include <cstdint>
#include <array> #include <array>
@ -102,6 +103,14 @@ public:
virtual int ReceiveHandShake(uint8_t *buf, int count) = 0; virtual int ReceiveHandShake(uint8_t *buf, int count) = 0;
virtual int SendHandShake(uint8_t *buf, int count, int delay_after_bytes) = 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; virtual bool GetSignal(int pin) const = 0;
// Get SCSI input signal value // Get SCSI input signal value
virtual void SetSignal(int pin, bool ast) = 0; virtual void SetSignal(int pin, bool ast) = 0;

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@
#include "scsi.h" #include "scsi.h"
#include "bus.h" #include "bus.h"
#include <array> #include <array>
#include <vector>
#ifdef __linux__ #ifdef __linux__
#include <linux/gpio.h> #include <linux/gpio.h>
@ -43,13 +42,7 @@
#error Invalid connection type or none specified #error Invalid connection type or none specified
#endif #endif
#ifdef ENABLE_GPIO_TRACE using namespace std; //NOSONAR Not relevant for rascsi
#define GPIO_FUNCTION_TRACE LOGTRACE("%s", __PRETTY_FUNCTION__)
#else
#define GPIO_FUNCTION_TRACE
#endif
using namespace std;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
@ -125,316 +118,397 @@ using namespace std;
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#define ALL_SCSI_PINS \ #define ALL_SCSI_PINS \
((1 << PIN_DT0) | (1 << PIN_DT1) | (1 << PIN_DT2) | (1 << PIN_DT3) | (1 << PIN_DT4) | (1 << PIN_DT5) | \ ((1<<PIN_DT0)|\
(1 << PIN_DT6) | (1 << PIN_DT7) | (1 << PIN_DP) | (1 << PIN_ATN) | (1 << PIN_RST) | (1 << PIN_ACK) | \ (1<<PIN_DT1)|\
(1 << PIN_REQ) | (1 << PIN_MSG) | (1 << PIN_CD) | (1 << PIN_IO) | (1 << PIN_BSY) | (1 << PIN_SEL)) (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))
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Constant declarations (GPIO) // Constant declarations (GPIO)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const static uint32_t SYST_OFFSET = 0x00003000; const static uint32_t SYST_OFFSET = 0x00003000;
const static uint32_t IRPT_OFFSET = 0x0000B200; const static uint32_t IRPT_OFFSET = 0x0000B200;
const static uint32_t ARMT_OFFSET = 0x0000B400; const static uint32_t ARMT_OFFSET = 0x0000B400;
const static uint32_t PADS_OFFSET = 0x00100000; const static uint32_t PADS_OFFSET = 0x00100000;
const static uint32_t GPIO_OFFSET = 0x00200000; const static uint32_t GPIO_OFFSET = 0x00200000;
const static uint32_t QA7_OFFSET = 0x01000000; const static uint32_t QA7_OFFSET = 0x01000000;
const static int GPIO_INPUT = 0; const static int GPIO_INPUT = 0;
const static int GPIO_OUTPUT = 1; const static int GPIO_OUTPUT = 1;
const static int GPIO_PULLNONE = 0; const static int GPIO_PULLNONE = 0;
const static int GPIO_PULLDOWN = 1; const static int GPIO_PULLDOWN = 1;
const static int GPIO_PULLUP = 2; const static int GPIO_PULLUP = 2;
const static int GPIO_FSEL_0 = 0; const static int GPIO_FSEL_0 = 0;
const static int GPIO_FSEL_1 = 1; const static int GPIO_FSEL_1 = 1;
const static int GPIO_FSEL_2 = 2; const static int GPIO_FSEL_2 = 2;
const static int GPIO_FSEL_3 = 3; const static int GPIO_FSEL_3 = 3;
const static int GPIO_SET_0 = 7; const static int GPIO_SET_0 = 7;
const static int GPIO_CLR_0 = 10; const static int GPIO_CLR_0 = 10;
const static int GPIO_LEV_0 = 13; const static int GPIO_LEV_0 = 13;
const static int GPIO_EDS_0 = 16; const static int GPIO_EDS_0 = 16;
const static int GPIO_REN_0 = 19; const static int GPIO_REN_0 = 19;
const static int GPIO_FEN_0 = 22; const static int GPIO_FEN_0 = 22;
const static int GPIO_HEN_0 = 25; const static int GPIO_HEN_0 = 25;
const static int GPIO_LEN_0 = 28; const static int GPIO_LEN_0 = 28;
const static int GPIO_AREN_0 = 31; const static int GPIO_AREN_0 = 31;
const static int GPIO_AFEN_0 = 34; const static int GPIO_AFEN_0 = 34;
const static int GPIO_PUD = 37; const static int GPIO_PUD = 37;
const static int GPIO_CLK_0 = 38; const static int GPIO_CLK_0 = 38;
const static int GPIO_GPPINMUXSD = 52; const static int GPIO_GPPINMUXSD = 52;
const static int GPIO_PUPPDN0 = 57; const static int GPIO_PUPPDN0 = 57;
const static int GPIO_PUPPDN1 = 58; const static int GPIO_PUPPDN1 = 58;
const static int GPIO_PUPPDN3 = 59; const static int GPIO_PUPPDN3 = 59;
const static int GPIO_PUPPDN4 = 60; const static int GPIO_PUPPDN4 = 60;
const static int PAD_0_27 = 11; const static int PAD_0_27 = 11;
const static int SYST_CS = 0; const static int SYST_CS = 0;
const static int SYST_CLO = 1; const static int SYST_CLO = 1;
const static int SYST_CHI = 2; const static int SYST_CHI = 2;
const static int SYST_C0 = 3; const static int SYST_C0 = 3;
const static int SYST_C1 = 4; const static int SYST_C1 = 4;
const static int SYST_C2 = 5; const static int SYST_C2 = 5;
const static int SYST_C3 = 6; const static int SYST_C3 = 6;
const static int ARMT_LOAD = 0; const static int ARMT_LOAD = 0;
const static int ARMT_VALUE = 1; const static int ARMT_VALUE = 1;
const static int ARMT_CTRL = 2; const static int ARMT_CTRL = 2;
const static int ARMT_CLRIRQ = 3; const static int ARMT_CLRIRQ = 3;
const static int ARMT_RAWIRQ = 4; const static int ARMT_RAWIRQ = 4;
const static int ARMT_MSKIRQ = 5; const static int ARMT_MSKIRQ = 5;
const static int ARMT_RELOAD = 6; const static int ARMT_RELOAD = 6;
const static int ARMT_PREDIV = 7; const static int ARMT_PREDIV = 7;
const static int ARMT_FREERUN = 8; const static int ARMT_FREERUN = 8;
const static int IRPT_PND_IRQ_B = 0; const static int IRPT_PND_IRQ_B = 0;
const static int IRPT_PND_IRQ_1 = 1; const static int IRPT_PND_IRQ_1 = 1;
const static int IRPT_PND_IRQ_2 = 2; const static int IRPT_PND_IRQ_2 = 2;
const static int IRPT_FIQ_CNTL = 3; const static int IRPT_FIQ_CNTL = 3;
const static int IRPT_ENB_IRQ_1 = 4; const static int IRPT_ENB_IRQ_1 = 4;
const static int IRPT_ENB_IRQ_2 = 5; const static int IRPT_ENB_IRQ_2 = 5;
const static int IRPT_ENB_IRQ_B = 6; const static int IRPT_ENB_IRQ_B = 6;
const static int IRPT_DIS_IRQ_1 = 7; const static int IRPT_DIS_IRQ_1 = 7;
const static int IRPT_DIS_IRQ_2 = 8; const static int IRPT_DIS_IRQ_2 = 8;
const static int IRPT_DIS_IRQ_B = 9; const static int IRPT_DIS_IRQ_B = 9;
const static int QA7_CORE0_TINTC = 16; const static int QA7_CORE0_TINTC = 16;
const static int GPIO_IRQ = (32 + 20); // GPIO3 const static int GPIO_IRQ = (32 + 20); // GPIO3
#define GPIO_INEDGE ((1 << PIN_BSY) | (1 << PIN_SEL) | (1 << PIN_ATN) | (1 << PIN_ACK) | (1 << PIN_RST)) #define GPIO_INEDGE ((1 << PIN_BSY) | \
(1 << PIN_SEL) | \
(1 << PIN_ATN) | \
(1 << PIN_ACK) | \
(1 << PIN_RST))
#define GPIO_MCI ((1 << PIN_MSG) | (1 << PIN_CD) | (1 << PIN_IO)) #define GPIO_MCI ((1 << PIN_MSG) | \
(1 << PIN_CD) | \
(1 << PIN_IO))
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Constant declarations (GIC) // Constant declarations (GIC)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const static uint32_t ARM_GICD_BASE = 0xFF841000; const static uint32_t ARM_GICD_BASE = 0xFF841000;
const static uint32_t ARM_GICC_BASE = 0xFF842000; const static uint32_t ARM_GICC_BASE = 0xFF842000;
const static uint32_t ARM_GIC_END = 0xFF847FFF; const static uint32_t ARM_GIC_END = 0xFF847FFF;
const static int GICD_CTLR = 0x000; const static int GICD_CTLR = 0x000;
const static int GICD_IGROUPR0 = 0x020; const static int GICD_IGROUPR0 = 0x020;
const static int GICD_ISENABLER0 = 0x040; const static int GICD_ISENABLER0 = 0x040;
const static int GICD_ICENABLER0 = 0x060; const static int GICD_ICENABLER0 = 0x060;
const static int GICD_ISPENDR0 = 0x080; const static int GICD_ISPENDR0 = 0x080;
const static int GICD_ICPENDR0 = 0x0A0; const static int GICD_ICPENDR0 = 0x0A0;
const static int GICD_ISACTIVER0 = 0x0C0; const static int GICD_ISACTIVER0 = 0x0C0;
const static int GICD_ICACTIVER0 = 0x0E0; const static int GICD_ICACTIVER0 = 0x0E0;
const static int GICD_IPRIORITYR0 = 0x100; const static int GICD_IPRIORITYR0 = 0x100;
const static int GICD_ITARGETSR0 = 0x200; const static int GICD_ITARGETSR0 = 0x200;
const static int GICD_ICFGR0 = 0x300; const static int GICD_ICFGR0 = 0x300;
const static int GICD_SGIR = 0x3C0; const static int GICD_SGIR = 0x3C0;
const static int GICC_CTLR = 0x000; const static int GICC_CTLR = 0x000;
const static int GICC_PMR = 0x001; const static int GICC_PMR = 0x001;
const static int GICC_IAR = 0x003; const static int GICC_IAR = 0x003;
const static int GICC_EOIR = 0x004; const static int GICC_EOIR = 0x004;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Constant declarations (GIC IRQ) // Constant declarations (GIC IRQ)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const static int GIC_IRQLOCAL0 = (16 + 14); const static int GIC_IRQLOCAL0 = (16 + 14);
const static int GIC_GPIO_IRQ = (32 + 116); // GPIO3 const static int GIC_GPIO_IRQ = (32 + 116); // GPIO3
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Constant declarations (Control signals) // Constant declarations (Control signals)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#define ACT_OFF !ACT_ON #define ACT_OFF !ACT_ON
#define ENB_OFF !ENB_ON #define ENB_OFF !ENB_ON
#define TAD_OUT !TAD_IN #define TAD_OUT !TAD_IN
#define IND_OUT !IND_IN #define IND_OUT !IND_IN
#define DTD_OUT !DTD_IN #define DTD_OUT !DTD_IN
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Constant declarations (SCSI) // Constant declarations (SCSI)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#define IN GPIO_INPUT #define IN GPIO_INPUT
#define OUT GPIO_OUTPUT #define OUT GPIO_OUTPUT
const static int ON = 1; const static int ON = 1;
const static int OFF = 0; const static int OFF = 0;
//---------------------------------------------------------------------------
//
// Constant declarations (bus control timing)
//
//---------------------------------------------------------------------------
// SCSI Bus timings taken from:
// https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-05.html
const static int SCSI_DELAY_ARBITRATION_DELAY_NS = 2400;
const static int SCSI_DELAY_ASSERTION_PERIOD_NS = 90;
const static int SCSI_DELAY_BUS_CLEAR_DELAY_NS = 800;
const static int SCSI_DELAY_BUS_FREE_DELAY_NS = 800;
const static int SCSI_DELAY_BUS_SET_DELAY_NS = 1800;
const static int SCSI_DELAY_BUS_SETTLE_DELAY_NS = 400;
const static int SCSI_DELAY_CABLE_SKEW_DELAY_NS = 10;
const static int SCSI_DELAY_DATA_RELEASE_DELAY_NS = 400;
const static int SCSI_DELAY_DESKEW_DELAY_NS = 45;
const static int SCSI_DELAY_DISCONNECTION_DELAY_US = 200;
const static int SCSI_DELAY_HOLD_TIME_NS = 45;
const static int SCSI_DELAY_NEGATION_PERIOD_NS = 90;
const static int SCSI_DELAY_POWER_ON_TO_SELECTION_TIME_S = 10; // (recommended)
const static int SCSI_DELAY_RESET_TO_SELECTION_TIME_US = 250*1000; // (recommended)
const static int SCSI_DELAY_RESET_HOLD_TIME_US = 25;
const static int SCSI_DELAY_SELECTION_ABORT_TIME_US = 200;
const static int SCSI_DELAY_SELECTION_TIMEOUT_DELAY_NS = 250*1000; // (recommended)
const static int SCSI_DELAY_FAST_ASSERTION_PERIOD_NS = 30;
const static int SCSI_DELAY_FAST_CABLE_SKEW_DELAY_NS = 5;
const static int SCSI_DELAY_FAST_DESKEW_DELAY_NS = 20;
const static int SCSI_DELAY_FAST_HOLD_TIME_NS = 10;
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;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Class definition // Class definition
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
class GPIOBUS : public BUS class GPIOBUS final : public BUS
{ {
public: public:
static GPIOBUS *create(); // Basic Functions
GPIOBUS()= default;
~GPIOBUS() override = default;
// Destructor
bool Init(mode_e mode = mode_e::TARGET) override;
// Initialization
void Reset() override;
// Reset
void Cleanup() override;
// Cleanup
// Basic Functions //---------------------------------------------------------------------------
GPIOBUS() = default; //
~GPIOBUS() override = default; // Bus signal acquisition
// Destructor //
bool Init(mode_e mode = mode_e::TARGET) override; //---------------------------------------------------------------------------
// Initialization inline uint32_t Acquire() override
void Reset() override; {
// Reset #if defined(__x86_64__) || defined(__X86__)
void Cleanup() override; // Only used for development/debugging purposes. Isn't really applicable
// Cleanup // to any real-world RaSCSI application
return 0;
#else
signals = *level;
uint32_t Acquire() override = 0; #if SIGNAL_CONTROL_MODE < 2
// Invert if negative logic (internal processing is unified to positive logic)
signals = ~signals;
#endif // SIGNAL_CONTROL_MODE
void SetENB(bool ast); return signals;
// Set ENB signal #endif // ifdef __x86_64__ || __X86__
}
bool GetBSY() const override; void SetENB(bool ast);
// Get BSY signal // Set ENB signal
void SetBSY(bool ast) override;
// Set BSY signal
bool GetSEL() const override; bool GetBSY() const override;
// Get SEL signal // Get BSY signal
void SetSEL(bool ast) override; void SetBSY(bool ast) override;
// Set SEL signal // Set BSY signal
bool GetATN() const override; bool GetSEL() const override;
// Get ATN signal // Get SEL signal
void SetATN(bool ast) override; void SetSEL(bool ast) override;
// Set ATN signal // Set SEL signal
bool GetACK() const override; bool GetATN() const override;
// Get ACK signal // Get ATN signal
void SetACK(bool ast) override; void SetATN(bool ast) override;
// Set ACK signal // Set ATN signal
bool GetACT() const; bool GetACK() const override;
// Get ACT signal // Get ACK signal
void SetACT(bool ast); void SetACK(bool ast) override;
// Set ACT signal // Set ACK signal
bool GetRST() const override; bool GetACT() const;
// Get RST signal // Get ACT signal
void SetRST(bool ast) override; void SetACT(bool ast);
// Set RST signal // Set ACT signal
bool GetMSG() const override; bool GetRST() const override;
// Get MSG signal // Get RST signal
void SetMSG(bool ast) override; void SetRST(bool ast) override;
// Set MSG signal // Set RST signal
bool GetCD() const override; bool GetMSG() const override;
// Get CD signal // Get MSG signal
void SetCD(bool ast) override; void SetMSG(bool ast) override;
// Set CD signal // Set MSG signal
bool GetIO() override; bool GetCD() const override;
// Get IO signal // Get CD signal
void SetIO(bool ast) override; void SetCD(bool ast) override;
// Set IO signal // Set CD signal
bool GetREQ() const override; bool GetIO() override;
// Get REQ signal // Get IO signal
void SetREQ(bool ast) override; void SetIO(bool ast) override;
// Set REQ signal // Set IO signal
bool GetDP() const override;
// Get Data parity signal
int CommandHandShake(vector<uint8_t>&) 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); bool GetREQ() const override;
// Get the phase based on raw data // 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<uint8_t>&) 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 #ifdef USE_SEL_EVENT_ENABLE
// SEL signal interrupt // SEL signal interrupt
bool PollSelectEvent(); bool PollSelectEvent() override;
// SEL signal event polling // SEL signal event polling
void ClearSelectEvent(); void ClearSelectEvent() override;
// Clear SEL signal event // 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
#endif #endif
static const array<int, 19> 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<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
uint32_t signals = 0; // All bus signals
#ifdef USE_SEL_EVENT_ENABLE #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 int epfd; // epoll file descriptor
#endif // USE_SEL_EVENT_ENABLE #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<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
uint32_t signals = 0; // All bus signals
#if SIGNAL_CONTROL_MODE == 0 #if SIGNAL_CONTROL_MODE == 0
array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
#else #else
array<uint32_t, 256> tblDatMsk = {}; // Data mask table array<uint32_t, 256> tblDatMsk = {}; // Data mask table
array<uint32_t, 256> tblDatSet = {}; // Table setting table array<uint32_t, 256> tblDatSet = {}; // Table setting table
#endif #endif
static const array<int, 19> SignalTable; // signal table
}; };

View File

@ -16,41 +16,41 @@
// RaSCSI Adapter Aibom version // 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 // 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 // Control signal output logic
#define ACT_ON ON // ACTIVE SIGNAL ON #define ACT_ON ON // ACTIVE SIGNAL ON
#define ENB_ON ON // ENABLE SIGNAL ON #define ENB_ON ON // ENABLE SIGNAL ON
#define IND_IN OFF // INITIATOR SIGNAL INPUT #define IND_IN OFF // INITIATOR SIGNAL INPUT
#define TAD_IN OFF // TARGET SIGNAL INPUT #define TAD_IN OFF // TARGET SIGNAL INPUT
#define DTD_IN OFF // DATA SIGNAL INPUT #define DTD_IN OFF // DATA SIGNAL INPUT
// Control signal pin assignment (-1 means no control) // Control signal pin assignment (-1 means no control)
const static int PIN_ACT = 4; // ACTIVE const static int PIN_ACT = 4; // ACTIVE
const static int PIN_ENB = 17; // ENABLE const static int PIN_ENB = 17; // ENABLE
const static int PIN_IND = 27; // INITIATOR CTRL DIRECTION const static int PIN_IND = 27; // INITIATOR CTRL DIRECTION
const static int PIN_TAD = -1; // TARGET CTRL DIRECTION const static int PIN_TAD = -1; // TARGET CTRL DIRECTION
const static int PIN_DTD = 18; // DATA DIRECTION const static int PIN_DTD = 18; // DATA DIRECTION
// SCSI signal pin assignment // SCSI signal pin assignment
const static int PIN_DT0 = 6; // Data 0 const static int PIN_DT0 = 6; // Data 0
const static int PIN_DT1 = 12; // Data 1 const static int PIN_DT1 = 12; // Data 1
const static int PIN_DT2 = 13; // Data 2 const static int PIN_DT2 = 13; // Data 2
const static int PIN_DT3 = 16; // Data 3 const static int PIN_DT3 = 16; // Data 3
const static int PIN_DT4 = 19; // Data 4 const static int PIN_DT4 = 19; // Data 4
const static int PIN_DT5 = 20; // Data 5 const static int PIN_DT5 = 20; // Data 5
const static int PIN_DT6 = 26; // Data 6 const static int PIN_DT6 = 26; // Data 6
const static int PIN_DT7 = 21; // Data 7 const static int PIN_DT7 = 21; // Data 7
const static int PIN_DP = 5; // Data parity const static int PIN_DP = 5; // Data parity
const static int PIN_ATN = 22; // ATN const static int PIN_ATN = 22; // ATN
const static int PIN_RST = 25; // RST const static int PIN_RST = 25; // RST
const static int PIN_ACK = 10; // ACK const static int PIN_ACK = 10; // ACK
const static int PIN_REQ = 7; // REQ const static int PIN_REQ = 7; // REQ
const static int PIN_MSG = 9; // MSG const static int PIN_MSG = 9; // MSG
const static int PIN_CD = 11; // CD const static int PIN_CD = 11; // CD
const static int PIN_IO = 23; // IO const static int PIN_IO = 23; // IO
const static int PIN_BSY = 24; // BSY const static int PIN_BSY = 24; // BSY
const static int PIN_SEL = 8; // SEL const static int PIN_SEL = 8; // SEL

View File

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

View File

@ -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<uint32_t, 4> 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<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
#else
array<uint32_t, 256> tblDatMsk = {}; // Data mask table
array<uint32_t, 256> tblDatSet = {}; // Table setting table
#endif
};

View File

@ -4,27 +4,24 @@
// for Raspberry Pi // for Raspberry Pi
// //
// Copyright (C) 2022 akuker // Copyright (C) 2022 akuker
// [ GPIO bus factory ]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <memory>
#include "hal/gpiobus_allwinner.h"
#include "hal/gpiobus_factory.h" #include "hal/gpiobus_factory.h"
#include "hal/gpiobus_raspberry.h" #include "hal/gpiobus.h"
#include "hal/sbc_version.h"
#include "log.h"
using namespace std; using namespace std;
unique_ptr<GPIOBUS> GPIOBUS_Factory::Create() unique_ptr<BUS> GPIOBUS_Factory::Create(BUS::mode_e mode)
{ {
if (SBC_Version::IsBananaPi()) { // TODO Make the factory a friend of GPIOBUS and make the GPIOBUS constructor private
LOGTRACE("Creating GPIOBUS_Allwinner") // so that clients cannot use it anymore but have to use the factory.
return make_unique<GPIOBUS_Allwinner>(); // Also make Init() private.
} else { if (auto bus = make_unique<GPIOBUS>(); bus->Init(mode)) {
LOGTRACE("Creating GPIOBUS_Raspberry") bus->Reset();
return make_unique<GPIOBUS_Raspberry>();
} return bus;
}
return nullptr;
} }

View File

@ -3,22 +3,20 @@
// SCSI Target Emulator RaSCSI Reloaded // SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi // for Raspberry Pi
// //
// Powered by XM6 TypeG Technology. // Copyright (C) 2022 akuker
// Copyright (C) 2016-2020 GIMONS
// [ GPIO-SCSI bus ]
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#pragma once #pragma once
#include "bus.h"
#include <memory> #include <memory>
#include "gpiobus.h"
using namespace std; using namespace std;
class GPIOBUS_Factory class GPIOBUS_Factory
{ {
public: public:
static unique_ptr<GPIOBUS> Create();
static unique_ptr<BUS> Create(BUS::mode_e);
}; };

View File

@ -16,41 +16,41 @@
// RaSCSI standard (SCSI logic, standard pin assignment) // 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 // 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) // Control signal pin assignment (-1 means no control)
const static int PIN_ACT = 4; // ACTIVE const static int PIN_ACT = 4; // ACTIVE
const static int PIN_ENB = 5; // ENABLE const static int PIN_ENB = 5; // ENABLE
const static int PIN_IND = 6; // INITIATOR CTRL DIRECTION const static int PIN_IND = 6; // INITIATOR CTRL DIRECTION
const static int PIN_TAD = 7; // TARGET CTRL DIRECTION const static int PIN_TAD = 7; // TARGET CTRL DIRECTION
const static int PIN_DTD = 8; // DATA DIRECTION const static int PIN_DTD = 8; // DATA DIRECTION
// Control signal output logic // Control signal output logic
#define ACT_ON ON // ACTIVE SIGNAL ON #define ACT_ON ON // ACTIVE SIGNAL ON
#define ENB_ON ON // ENABLE SIGNAL ON #define ENB_ON ON // ENABLE SIGNAL ON
#define IND_IN OFF // INITIATOR SIGNAL INPUT #define IND_IN OFF // INITIATOR SIGNAL INPUT
#define TAD_IN OFF // TARGET SIGNAL INPUT #define TAD_IN OFF // TARGET SIGNAL INPUT
#define DTD_IN ON // DATA SIGNAL INPUT #define DTD_IN ON // DATA SIGNAL INPUT
// SCSI signal pin assignment // SCSI signal pin assignment
const static int PIN_DT0 = 10; // Data 0 const static int PIN_DT0 = 10; // Data 0
const static int PIN_DT1 = 11; // Data 1 const static int PIN_DT1 = 11; // Data 1
const static int PIN_DT2 = 12; // Data 2 const static int PIN_DT2 = 12; // Data 2
const static int PIN_DT3 = 13; // Data 3 const static int PIN_DT3 = 13; // Data 3
const static int PIN_DT4 = 14; // Data 4 const static int PIN_DT4 = 14; // Data 4
const static int PIN_DT5 = 15; // Data 5 const static int PIN_DT5 = 15; // Data 5
const static int PIN_DT6 = 16; // Data 6 const static int PIN_DT6 = 16; // Data 6
const static int PIN_DT7 = 17; // Data 7 const static int PIN_DT7 = 17; // Data 7
const static int PIN_DP = 18; // Data parity const static int PIN_DP = 18; // Data parity
const static int PIN_ATN = 19; // ATN const static int PIN_ATN = 19; // ATN
const static int PIN_RST = 20; // RST const static int PIN_RST = 20; // RST
const static int PIN_ACK = 21; // ACK const static int PIN_ACK = 21; // ACK
const static int PIN_REQ = 22; // REQ const static int PIN_REQ = 22; // REQ
const static int PIN_MSG = 23; // MSG const static int PIN_MSG = 23; // MSG
const static int PIN_CD = 24; // CD const static int PIN_CD = 24; // CD
const static int PIN_IO = 25; // IO const static int PIN_IO = 25; // IO
const static int PIN_BSY = 26; // BSY const static int PIN_BSY = 26; // BSY
const static int PIN_SEL = 27; // SEL const static int PIN_SEL = 27; // SEL

View File

@ -16,41 +16,42 @@
// RaSCSI Adapter GAMERnium.com version // 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 // 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 // Control signal output logic
#define ACT_ON ON // ACTIVE SIGNAL ON #define ACT_ON ON // ACTIVE SIGNAL ON
#define ENB_ON ON // ENABLE SIGNAL ON #define ENB_ON ON // ENABLE SIGNAL ON
#define IND_IN OFF // INITIATOR SIGNAL INPUT #define IND_IN OFF // INITIATOR SIGNAL INPUT
#define TAD_IN OFF // TARGET SIGNAL INPUT #define TAD_IN OFF // TARGET SIGNAL INPUT
#define DTD_IN ON // DATA SIGNAL INPUT #define DTD_IN ON // DATA SIGNAL INPUT
// Control signal pin assignment (-1 means no control) // Control signal pin assignment (-1 means no control)
const static int PIN_ACT = 14; // ACTIVE const static int PIN_ACT = 14; // ACTIVE
const static int PIN_ENB = 6; // ENABLE const static int PIN_ENB = 6; // ENABLE
const static int PIN_IND = 7; // INITIATOR CTRL DIRECTION const static int PIN_IND = 7; // INITIATOR CTRL DIRECTION
const static int PIN_TAD = 8; // TARGET CTRL DIRECTION const static int PIN_TAD = 8; // TARGET CTRL DIRECTION
const static int PIN_DTD = 5; // DATA DIRECTION const static int PIN_DTD = 5; // DATA DIRECTION
// SCSI signal pin assignment // SCSI signal pin assignment
const static int PIN_DT0 = 21; // Data 0 const static int PIN_DT0 = 21; // Data 0
const static int PIN_DT1 = 26; // Data 1 const static int PIN_DT1 = 26; // Data 1
const static int PIN_DT2 = 20; // Data 2 const static int PIN_DT2 = 20; // Data 2
const static int PIN_DT3 = 19; // Data 3 const static int PIN_DT3 = 19; // Data 3
const static int PIN_DT4 = 16; // Data 4 const static int PIN_DT4 = 16; // Data 4
const static int PIN_DT5 = 13; // Data 5 const static int PIN_DT5 = 13; // Data 5
const static int PIN_DT6 = 12; // Data 6 const static int PIN_DT6 = 12; // Data 6
const static int PIN_DT7 = 11; // Data 7 const static int PIN_DT7 = 11; // Data 7
const static int PIN_DP = 25; // Data parity const static int PIN_DP = 25; // Data parity
const static int PIN_ATN = 10; // ATN const static int PIN_ATN = 10; // ATN
const static int PIN_RST = 22; // RST const static int PIN_RST = 22; // RST
const static int PIN_ACK = 24; // ACK const static int PIN_ACK = 24; // ACK
const static int PIN_REQ = 15; // REQ const static int PIN_REQ = 15; // REQ
const static int PIN_MSG = 17; // MSG const static int PIN_MSG = 17; // MSG
const static int PIN_CD = 18; // CD const static int PIN_CD = 18; // CD
const static int PIN_IO = 4; // IO const static int PIN_IO = 4; // IO
const static int PIN_BSY = 27; // BSY const static int PIN_BSY = 27; // BSY
const static int PIN_SEL = 23; // SEL const static int PIN_SEL = 23; // SEL

View File

@ -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 <sys/mman.h>
#include "config.h"
#include "hal/gpiobus.h"
#include "hal/gpiobus_raspberry.h"
#include "hal/systimer.h"
#include "log.h"
#include <string.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#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<uint8_t, 4> 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<char, 1024> 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<int, 9> pintbl = {PIN_DT0, PIN_DT1, PIN_DT2, PIN_DT3, PIN_DT4, PIN_DT5, PIN_DT6, PIN_DT7, PIN_DP};
array<bool, 256> 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__
}

View File

@ -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<uint32_t, 4> gpfsel; // GPFSEL0-4 backup values
uint32_t signals = 0; // All bus signals
#if SIGNAL_CONTROL_MODE == 0
array<array<uint32_t, 256>, 3> tblDatMsk; // Data mask table
array<array<uint32_t, 256>, 3> tblDatSet; // Data setting table
#else
array<uint32_t, 256> tblDatMsk = {}; // Data mask table
array<uint32_t, 256> tblDatSet = {}; // Table setting table
#endif
};

View File

@ -16,41 +16,41 @@
// RaSCSI standard (SCSI logic, standard pin assignment) // 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 // 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) // Control signal pin assignment (-1 means no control)
const static int PIN_ACT = 4; // ACTIVE const static int PIN_ACT = 4; // ACTIVE
const static int PIN_ENB = 5; // ENABLE const static int PIN_ENB = 5; // ENABLE
const static int PIN_IND = -1; // INITIATOR CTRL DIRECTION const static int PIN_IND = -1; // INITIATOR CTRL DIRECTION
const static int PIN_TAD = -1; // TARGET CTRL DIRECTION const static int PIN_TAD = -1; // TARGET CTRL DIRECTION
const static int PIN_DTD = -1; // DATA DIRECTION const static int PIN_DTD = -1; // DATA DIRECTION
// Control signal output logic // Control signal output logic
#define ACT_ON ON // ACTIVE SIGNAL ON #define ACT_ON ON // ACTIVE SIGNAL ON
#define ENB_ON ON // ENABLE SIGNAL ON #define ENB_ON ON // ENABLE SIGNAL ON
#define IND_IN OFF // INITIATOR SIGNAL INPUT #define IND_IN OFF // INITIATOR SIGNAL INPUT
#define TAD_IN OFF // TARGET SIGNAL INPUT #define TAD_IN OFF // TARGET SIGNAL INPUT
#define DTD_IN ON // DATA SIGNAL INPUT #define DTD_IN ON // DATA SIGNAL INPUT
// SCSI signal pin assignment // SCSI signal pin assignment
const static int PIN_DT0 = 10; // Data 0 const static int PIN_DT0 = 10; // Data 0
const static int PIN_DT1 = 11; // Data 1 const static int PIN_DT1 = 11; // Data 1
const static int PIN_DT2 = 12; // Data 2 const static int PIN_DT2 = 12; // Data 2
const static int PIN_DT3 = 13; // Data 3 const static int PIN_DT3 = 13; // Data 3
const static int PIN_DT4 = 14; // Data 4 const static int PIN_DT4 = 14; // Data 4
const static int PIN_DT5 = 15; // Data 5 const static int PIN_DT5 = 15; // Data 5
const static int PIN_DT6 = 16; // Data 6 const static int PIN_DT6 = 16; // Data 6
const static int PIN_DT7 = 17; // Data 7 const static int PIN_DT7 = 17; // Data 7
const static int PIN_DP = 18; // Data parity const static int PIN_DP = 18; // Data parity
const static int PIN_ATN = 19; // ATN const static int PIN_ATN = 19; // ATN
const static int PIN_RST = 20; // RST const static int PIN_RST = 20; // RST
const static int PIN_ACK = 21; // ACK const static int PIN_ACK = 21; // ACK
const static int PIN_REQ = 22; // REQ const static int PIN_REQ = 22; // REQ
const static int PIN_MSG = 23; // MSG const static int PIN_MSG = 23; // MSG
const static int PIN_CD = 24; // CD const static int PIN_CD = 24; // CD
const static int PIN_IO = 25; // IO const static int PIN_IO = 25; // IO
const static int PIN_BSY = 26; // BSY const static int PIN_BSY = 26; // BSY
const static int PIN_SEL = 27; // SEL const static int PIN_SEL = 27; // SEL

View File

@ -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 <fstream>
#include <iostream>
#include <sstream>
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<std::string, SBC_Version::sbc_version_type, std::less<>> 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<int>(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<uint8_t, 4> 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

View File

@ -1,70 +0,0 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI Reloaded
// for Raspberry Pi
//
// Copyright (C) 2022 akuker
//
// [ Hardware version detection routines ]
//
//---------------------------------------------------------------------------
#pragma once
#include <map>
#include <string>
//===========================================================================
//
// 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<std::string, sbc_version_type, std::less<>> m_proc_device_tree_mapping;
static const std::string m_device_tree_model_path;
static uint32_t GetDeviceTreeRanges(const char *filename, uint32_t offset);
};

View File

@ -12,56 +12,129 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "hal/systimer.h" #include "hal/systimer.h"
#include "hal/systimer_allwinner.h"
#include "hal/systimer_raspberry.h"
#include <sys/mman.h>
#include "hal/gpiobus.h" #include "hal/gpiobus.h"
#include "hal/sbc_version.h"
#include "config.h" #include "config.h"
#include "log.h" #include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <array>
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<PlatformSpecificTimer> 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<uint32_t, 32> maxclock = { 32, 0, 0x00030004, 8, 0, 4, 0, 0 };
if (!initialized) { // Save the base address
if (SBC_Version::IsRaspberryPi()) { systaddr = syst;
systimer_ptr = make_unique<SysTimer_Raspberry>(); armtaddr = armt;
is_raspberry = true;
} else if (SBC_Version::IsBananaPi()) { // Change the ARM timer to free run mode
systimer_ptr = make_unique<SysTimer_AllWinner>(); armtaddr[ARMT_CTRL] = 0x00000282;
is_allwinnner = true;
} // Get the core frequency
systimer_ptr->Init(); corefreq = 0;
initialized = true; 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() //
{ // Get system timer low byte
return systimer_ptr->GetTimerLow(); //
//---------------------------------------------------------------------------
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) 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) 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);
} }

View File

@ -13,31 +13,11 @@
#pragma once #pragma once
#include <memory>
#include <stdint.h> #include <stdint.h>
#include "config.h" #include "config.h"
#include "scsi.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 // System timer
@ -45,21 +25,23 @@ class PlatformSpecificTimer
//=========================================================================== //===========================================================================
class SysTimer class SysTimer
{ {
public: public:
static void Init(); static void Init(uint32_t *syst, uint32_t *armt);
// Get system timer low byte // Initialization
static uint32_t GetTimerLow(); static uint32_t GetTimerLow();
// Get system timer high byte // Get system timer low byte
static uint32_t GetTimerHigh(); static uint32_t GetTimerHigh();
// Sleep for N nanoseconds // Get system timer high byte
static void SleepNsec(uint32_t nsec); static void SleepNsec(uint32_t nsec);
// Sleep for N microseconds // Sleep for N nanoseconds
static void SleepUsec(uint32_t usec); static void SleepUsec(uint32_t usec);
// Sleep for N microseconds
private: private:
static bool initialized; static volatile uint32_t *systaddr;
static bool is_allwinnner; // System timer address
static bool is_raspberry; static volatile uint32_t *armtaddr;
// ARM timer address
static std::unique_ptr<PlatformSpecificTimer> systimer_ptr; static volatile uint32_t corefreq;
// Core frequency
}; };

View File

@ -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 <sys/mman.h>
#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)
;
}

View File

@ -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 <stdint.h>
#include <string>
//===========================================================================
//
// 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;
};

View File

@ -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 <memory>
#include <sys/ioctl.h>
#include <sys/mman.h>
#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<uint32_t, 32> 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)
;
}

View File

@ -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 <stdint.h>
//===========================================================================
//
// 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;
};

View File

@ -9,13 +9,12 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "log.h" #include "log.h"
#include "hal/gpiobus.h"
#include "hal/gpiobus_factory.h" #include "hal/gpiobus_factory.h"
#include "hal/gpiobus.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include <sys/time.h> #include <sys/time.h>
#include <climits> #include <climits>
#include <csignal> #include <csignal>
#include <sstream>
#include <iostream> #include <iostream>
#include <getopt.h> #include <getopt.h>
#include <sched.h> #include <sched.h>
@ -25,53 +24,20 @@
using namespace std; using namespace std;
static const int _MAX_FNAME = 256; // TODO Should not be global and not be used by sm_vcd_report
//---------------------------------------------------------------------------
//
// Variable declarations
//
//---------------------------------------------------------------------------
static volatile bool running; // Running flag
unique_ptr<GPIOBUS> bus; // GPIO Bus
uint32_t buff_size = 1000000;
data_capture *data_buffer;
uint32_t data_idx = 0;
double ns_per_loop; double ns_per_loop;
bool print_help = false; void ScsiMon::KillHandler(int)
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)
{ {
// Stop instruction
running = false; running = false;
} }
void ScsiMon::parse_arguments(const vector<char *>& args) void ScsiMon::ParseArguments(const vector<char *>& args)
{ {
int opt; int opt;
while ((opt = getopt(args.size(), args.data(), "-Hhb:i:")) != -1) while ((opt = getopt(static_cast<int>(args.size()), args.data(), "-Hhb:i:")) != -1) {
{ switch (opt) {
switch (opt)
{
// The three options below are kind of a compound option with two letters // The three options below are kind of a compound option with two letters
case 'h': case 'h':
case 'H': case 'H':
@ -81,11 +47,11 @@ void ScsiMon::parse_arguments(const vector<char *>& args)
buff_size = atoi(optarg); buff_size = atoi(optarg);
break; break;
case 'i': case 'i':
strncpy(input_file_name, optarg, sizeof(input_file_name)-1); input_file_name = optarg;
import_data = true; import_data = true;
break; break;
case 1: case 1:
strncpy(file_base_name, optarg, sizeof(file_base_name) - 5); file_base_name = optarg;
break; break;
default: default:
cout << "default: " << optarg << endl; cout << "default: " << optarg << endl;
@ -96,22 +62,18 @@ void ScsiMon::parse_arguments(const vector<char *>& args)
/* Process any remaining command line arguments (not options). */ /* Process any remaining command line arguments (not options). */
if (optind < static_cast<int>(args.size())) { if (optind < static_cast<int>(args.size())) {
while (optind < static_cast<int>(args.size())) while (optind < static_cast<int>(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); vcd_file_name = file_base_name;
strcat(vcd_file_name, ".vcd"); vcd_file_name += ".vcd";
strcpy(json_file_name, file_base_name); json_file_name = file_base_name;
strcat(json_file_name, ".json"); json_file_name += ".json";
strcpy(html_file_name, file_base_name); html_file_name = file_base_name;
strcat(html_file_name, ".html"); html_file_name += ".html";
} }
//---------------------------------------------------------------------------
// void ScsiMon::PrintCopyrightText() const
// Copyright text
//
//---------------------------------------------------------------------------
void ScsiMon::print_copyright_text()
{ {
LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ") LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ")
LOGINFO("version %s (%s, %s)", LOGINFO("version %s (%s, %s)",
@ -124,12 +86,7 @@ void ScsiMon::print_copyright_text()
LOGINFO(" ") LOGINFO(" ")
} }
//--------------------------------------------------------------------------- void ScsiMon::PrintHelpText(const vector<char *>& args) const
//
// Help text
//
//---------------------------------------------------------------------------
void ScsiMon::print_help_text(const vector<char *>& args)
{ {
LOGINFO("%s -i [input file json] -b [buffer size] [output file]", args[0]) 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") 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<char *>& args)
LOGINFO(" will be appended to this file name") LOGINFO(" will be appended to this file name")
} }
//--------------------------------------------------------------------------- void ScsiMon::Banner() const
//
// Banner Output
//
//---------------------------------------------------------------------------
void ScsiMon::Banner()
{ {
if (import_data) { if (import_data) {
LOGINFO("Reading input file: %s", input_file_name) LOGINFO("Reading input file: %s", input_file_name.c_str())
} }
else { else {
LOGINFO("Reading live data from the GPIO pins") LOGINFO("Reading live data from the GPIO pins")
@ -156,16 +108,11 @@ void ScsiMon::Banner()
LOGINFO(" Data buffer size: %u", buff_size) LOGINFO(" Data buffer size: %u", buff_size)
LOGINFO(" ") LOGINFO(" ")
LOGINFO("Generating output files:") LOGINFO("Generating output files:")
LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", vcd_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) LOGINFO(" %s - JSON file with raw data", json_file_name.c_str())
LOGINFO(" %s - HTML file with summary of commands", html_file_name) LOGINFO(" %s - HTML file with summary of commands", html_file_name.c_str())
} }
//---------------------------------------------------------------------------
//
// Initialization
//
//---------------------------------------------------------------------------
bool ScsiMon::Init() bool ScsiMon::Init()
{ {
// Interrupt handler settings // Interrupt handler settings
@ -179,43 +126,35 @@ bool ScsiMon::Init()
return false; return false;
} }
// GPIO Initialization bus = GPIOBUS_Factory::Create(BUS::mode_e::TARGET);
bus = GPIOBUS_Factory::Create(); if (bus == nullptr) {
if (!bus->Init())
{
LOGERROR("Unable to intiailize the GPIO bus. Exiting....") LOGERROR("Unable to intiailize the GPIO bus. Exiting....")
return false; return false;
} }
// Bus Reset
bus->Reset();
// Other
running = false; running = false;
return true; return true;
} }
void ScsiMon::Cleanup() void ScsiMon::Cleanup() const
{ {
if (!import_data) { if (!import_data) {
LOGINFO("Stopping data collection....") LOGINFO("Stopping data collection....")
} }
LOGINFO(" ") LOGINFO(" ")
LOGINFO("Generating %s...", vcd_file_name) LOGINFO("Generating %s...", vcd_file_name.c_str())
scsimon_generate_value_change_dump(vcd_file_name, data_buffer, data_idx); scsimon_generate_value_change_dump(vcd_file_name.c_str(), data_buffer, data_idx);
LOGINFO("Generating %s...", json_file_name) LOGINFO("Generating %s...", json_file_name.c_str())
scsimon_generate_json(json_file_name, data_buffer, data_idx); scsimon_generate_json(json_file_name.c_str(), data_buffer, data_idx);
LOGINFO("Generating %s...", html_file_name) LOGINFO("Generating %s...", html_file_name.c_str())
scsimon_generate_html(html_file_name, data_buffer, data_idx); scsimon_generate_html(html_file_name.c_str(), data_buffer, data_idx);
// Cleanup the Bus
bus->Cleanup(); bus->Cleanup();
} }
void ScsiMon::Reset() void ScsiMon::Reset() const
{ {
// Reset the bus
bus->Reset(); bus->Reset();
} }
@ -225,7 +164,7 @@ void ScsiMon::Reset()
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#ifdef __linux__ #ifdef __linux__
void ScsiMon::FixCpu(int cpu) void ScsiMon::FixCpu(int cpu) const
{ {
// Get the number of CPUs // Get the number of CPUs
cpu_set_t cpuset; cpu_set_t cpuset;
@ -248,14 +187,8 @@ static uint32_t high_bits = 0x0;
static uint32_t low_bits = 0xFFFFFFFF; static uint32_t low_bits = 0xFFFFFFFF;
#endif #endif
//---------------------------------------------------------------------------
//
// Main processing
//
//---------------------------------------------------------------------------
int ScsiMon::run(const vector<char *>& args) int ScsiMon::run(const vector<char *>& args)
{ {
#ifdef DEBUG #ifdef DEBUG
spdlog::set_level(spdlog::level::trace); spdlog::set_level(spdlog::level::trace);
#else #else
@ -263,14 +196,13 @@ int ScsiMon::run(const vector<char *>& args)
#endif #endif
spdlog::set_pattern("%^[%l]%$ %v"); spdlog::set_pattern("%^[%l]%$ %v");
print_copyright_text(); PrintCopyrightText();
parse_arguments(args); ParseArguments(args);
#ifdef DEBUG #ifdef DEBUG
uint32_t prev_high = high_bits; uint32_t prev_high = high_bits;
uint32_t prev_low = low_bits; uint32_t prev_low = low_bits;
#endif #endif
ostringstream s;
uint32_t prev_sample = 0xFFFFFFFF; uint32_t prev_sample = 0xFFFFFFFF;
uint32_t this_sample = 0; uint32_t this_sample = 0;
timeval start_time; timeval start_time;
@ -279,23 +211,20 @@ int ScsiMon::run(const vector<char *>& args)
timeval time_diff; timeval time_diff;
uint64_t elapsed_us; uint64_t elapsed_us;
if (print_help) if (print_help) {
{ PrintHelpText(args);
print_help_text(args);
exit(0); exit(0);
} }
// Output the Banner
Banner(); Banner();
data_buffer = (data_capture *)calloc(buff_size, sizeof(data_capture_t)); data_buffer = (data_capture *)calloc(buff_size, sizeof(data_capture_t));
if (import_data) if (import_data) {
{ data_idx = scsimon_read_json(input_file_name.c_str(), data_buffer, buff_size);
data_idx = scsimon_read_json(input_file_name, data_buffer, buff_size);
if (data_idx > 0) 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(); Cleanup();
} }
exit(0); exit(0);
@ -327,48 +256,40 @@ int ScsiMon::run(const vector<char *>& args)
// Start execution // Start execution
running = true; running = true;
bus->SetACT(false); bus->SetACK(false);
(void)gettimeofday(&start_time, nullptr); (void)gettimeofday(&start_time, nullptr);
LOGDEBUG("ALL_SCSI_PINS %08X\n", ALL_SCSI_PINS) LOGDEBUG("ALL_SCSI_PINS %08X\n", ALL_SCSI_PINS)
// Main Loop // Main Loop
while (running) while (running) {
{
// Work initialization // Work initialization
this_sample = (bus->Acquire() & ALL_SCSI_PINS); this_sample = (bus->Acquire() & ALL_SCSI_PINS);
loop_count++; loop_count++;
if (loop_count > LLONG_MAX - 1) if (loop_count > LLONG_MAX - 1) {
{
LOGINFO("Maximum amount of time has elapsed. SCSIMON is terminating.") LOGINFO("Maximum amount of time has elapsed. SCSIMON is terminating.")
running = false; running = false;
} }
if (data_idx >= (buff_size - 2))
{ if (data_idx >= (buff_size - 2)) {
LOGINFO("Internal data buffer is full. SCSIMON is terminating.") LOGINFO("Internal data buffer is full. SCSIMON is terminating.")
running = false; running = false;
} }
if (this_sample != prev_sample) if (this_sample != prev_sample) {
{
#ifdef DEBUG #ifdef DEBUG
// This is intended to be a debug check to see if every pin is set // This is intended to be a debug check to see if every pin is set
// high and low at some point. // high and low at some point.
high_bits |= this_sample; high_bits |= this_sample;
low_bits &= this_sample; low_bits &= this_sample;
if ((high_bits != prev_high) || (low_bits != prev_low)) if ((high_bits != prev_high) || (low_bits != prev_low)) {
{
LOGDEBUG(" %08X %08X\n", high_bits, low_bits) LOGDEBUG(" %08X %08X\n", high_bits, low_bits)
} }
prev_high = high_bits; prev_high = high_bits;
prev_low = low_bits; prev_low = low_bits;
if ((data_idx % 1000) == 0) if ((data_idx % 1000) == 0) {
{ LOGDEBUG("%s", ("Collected " + to_string(data_idx) + " samples...").c_str())
s.str("");
s << "Collected " << data_idx << " samples...";
LOGDEBUG("%s", s.str().c_str())
} }
#endif #endif
data_buffer[data_idx].data = this_sample; data_buffer[data_idx].data = this_sample;
@ -381,8 +302,7 @@ int ScsiMon::run(const vector<char *>& args)
} }
// Collect one last sample, otherwise it looks like the end of the data was cut off // 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].data = this_sample;
data_buffer[data_idx].timestamp = loop_count; data_buffer[data_idx].timestamp = loop_count;
data_idx++; data_idx++;
@ -393,18 +313,13 @@ int ScsiMon::run(const vector<char *>& args)
timersub(&stop_time, &start_time, &time_diff); timersub(&stop_time, &start_time, &time_diff);
elapsed_us = ((time_diff.tv_sec * 1000000) + time_diff.tv_usec); elapsed_us = ((time_diff.tv_sec * 1000000) + time_diff.tv_usec);
s.str(""); LOGINFO("%s", ("Elapsed time: " + to_string(elapsed_us) + " microseconds (" + to_string(elapsed_us / 1000000)
s << "Elapsed time: " << elapsed_us << " microseconds (" << elapsed_us / 1000000 << " seconds)"; + " seconds").c_str())
LOGINFO("%s", s.str().c_str()) LOGINFO("%s", ("Collected " + to_string(data_idx) + " changes").c_str())
s.str("");
s << "Collected " << data_idx << " changes";
LOGINFO("%s", s.str().c_str())
// Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps. ns_per_loop = (double)(elapsed_us * 1000) / (double)loop_count;
ns_per_loop = (elapsed_us * 1000) / (double)loop_count; LOGINFO("%s", ("Read the SCSI bus " + to_string(loop_count) + " times with an average of "
s.str(""); + to_string(ns_per_loop) + " ns for each read").c_str())
s << "Read the SCSI bus " << loop_count << " times with an average of " << ns_per_loop << " ns for each read";
LOGINFO("%s", s.str().c_str())
Cleanup(); Cleanup();

View File

@ -9,10 +9,14 @@
#pragma once #pragma once
#include "hal/bus.h"
#include "monitor/data_sample.h"
#include <vector> #include <vector>
#include <memory>
using namespace std; using namespace std;
// TODO Make static fields/methods non-static
class ScsiMon class ScsiMon
{ {
public: public:
@ -24,12 +28,35 @@ public:
private: private:
void parse_arguments(const vector<char *>&); void ParseArguments(const vector<char *>&);
void print_copyright_text(); void PrintCopyrightText() const;
void print_help_text(const vector<char *>&); void PrintHelpText(const vector<char *>&) const;
void Banner(); void Banner() const;
bool Init(); bool Init();
void Cleanup(); void Cleanup() const;
void Reset(); void Reset() const;
void FixCpu(int); void FixCpu(int) const;
static void KillHandler(int);
static inline volatile bool running;
unique_ptr<BUS> 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;
}; };

View File

@ -43,7 +43,7 @@ uint32_t scsimon_read_json(const char *json_filename, data_capture *data_capture
continue; continue;
strncpy(data, &data_str[strlen(data_label)], 8); strncpy(data, &data_str[strlen(data_label)], 8);
data[8] = '\0'; data[8] = '\0';
data_uint = strtoul(data, &ptr, 16); data_uint = static_cast<uint32_t>(strtoul(data, &ptr, 16));
data_capture_array[sample_count].timestamp = timestamp_uint; data_capture_array[sample_count].timestamp = timestamp_uint;
data_capture_array[sample_count].data = data_uint; data_capture_array[sample_count].data = data_uint;

View File

@ -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) 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); const BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
if (prev_value[pin] != static_cast<int>(new_value)) { if (prev_value[pin] != static_cast<uint8_t>(new_value)) {
prev_value[pin] = static_cast<int>(new_value); prev_value[pin] = static_cast<uint8_t>(new_value);
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl; 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; uint32_t i = 0;
while (i < capture_count) { 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_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_SEL, SYMBOL_PIN_SEL);
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD); vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD);

View File

@ -16,9 +16,8 @@
#include "controllers/scsi_controller.h" #include "controllers/scsi_controller.h"
#include "devices/device_factory.h" #include "devices/device_factory.h"
#include "devices/storage_device.h" #include "devices/storage_device.h"
#include "hal/gpiobus.h"
#include "hal/gpiobus_factory.h" #include "hal/gpiobus_factory.h"
#include "hal/sbc_version.h" #include "hal/gpiobus.h"
#include "hal/systimer.h" #include "hal/systimer.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "protobuf_serializer.h" #include "protobuf_serializer.h"
@ -68,20 +67,11 @@ void Rascsi::Banner(const vector<char *>& args) const
bool Rascsi::InitBus() const bool Rascsi::InitBus() const
{ {
#ifdef USE_SEL_EVENT_ENABLE bus = GPIOBUS_Factory::Create(BUS::mode_e::TARGET);
SBC_Version::Init(); if (bus == nullptr) {
#endif
// GPIOBUS creation
bus = GPIOBUS_Factory::Create();
// GPIO Initialization
if (!bus->Init()) {
return false; return false;
} }
bus->Reset();
auto b = bus; auto b = bus;
controller_manager = make_shared<ControllerManager>(*b); controller_manager = make_shared<ControllerManager>(*b);
auto c = controller_manager; auto c = controller_manager;

View File

@ -19,8 +19,7 @@
using namespace std; using namespace std;
// TODO Only BUS should be known class BUS;
class GPIOBUS;
class ControllerManager; class ControllerManager;
class RascsiExecutor; class RascsiExecutor;
@ -61,7 +60,7 @@ private:
const static inline RascsiResponse rascsi_response; const static inline RascsiResponse rascsi_response;
static inline shared_ptr<GPIOBUS> bus; static inline shared_ptr<BUS> bus;
static inline shared_ptr<ControllerManager> controller_manager; static inline shared_ptr<ControllerManager> controller_manager;

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,27 @@
#pragma once #pragma once
#include "scsi.h"
#include "hal/bus.h" #include "hal/bus.h"
#include <string>
#include <vector> #include <vector>
#include <memory>
#include <stdexcept>
using namespace std; using namespace std;
class rasdump_exception : public runtime_error
{
using runtime_error::runtime_error;
};
class RasDump class RasDump
{ {
static const char COMPONENT_SEPARATOR = ':';
static const int MINIMUM_BUFFER_SIZE = 1024 * 64;
static const int DEFAULT_BUFFER_SIZE = 1024 * 1024;
public: public:
RasDump() = default; RasDump() = default;
@ -25,23 +39,47 @@ public:
private: private:
bool Banner(const vector<char *>&); bool Banner(const vector<char *>&) const;
bool Init(); bool Init() const;
void Reset(); void ParseArguments(const vector<char *>&);
bool ParseArguments(const vector<char *>&); int DumpRestore();
bool WaitPhase(BUS::phase_t); void WaitPhase(BUS::phase_t) const;
void BusFree(); void Selection() const;
bool Selection(int); void Command(scsi_defs::scsi_command, vector<uint8_t>&) const;
bool Command(uint8_t *, int); void DataIn(int);
int DataIn(uint8_t *, int); void DataOut(int);
int DataOut(uint8_t *, int); void Status() const;
int Status(); void MessageIn() const;
int MessageIn(); void MessageOut();
int TestUnitReady(int); void BusFree() const;
int RequestSense(int, uint8_t *); void TestUnitReady() const;
int ModeSense(int, uint8_t *); void RequestSense();
int Inquiry(int, uint8_t *); void Inquiry();
int ReadCapacity(int, uint8_t *); pair<uint64_t, uint32_t> ReadCapacity();
int Read10(int, uint32_t, uint32_t, uint32_t, uint8_t *); void Read10(uint32_t, uint32_t, uint32_t);
int Write10(int, uint32_t, uint32_t, uint32_t, uint8_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> bus;
vector<uint8_t> buffer;
int target_id = -1;
int target_lun = 0;
int initiator_id = 7;
string filename;
bool restore = false;
}; };

View File

@ -1,103 +0,0 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2010-2020 GIMONS
// [ File I/O (Subset for RaSCSI) ]
//
//---------------------------------------------------------------------------
#include "rasdump/rasdump_fileio.h"
#include <fcntl.h>
#include <unistd.h>
#include <cassert>
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;
}
}

View File

@ -1,42 +0,0 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2005 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2013-2020 GIMONS
// [ File I/O (Subset for RaSCSI) ]
//
//---------------------------------------------------------------------------
#pragma once
#include <cstdint>
#include <cstdlib>
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;
};

View File

@ -3,10 +3,12 @@
rasdump \- SCSI disk dumping tool for RaSCSI rasdump \- SCSI disk dumping tool for RaSCSI
.SH SYNOPSIS .SH SYNOPSIS
.B rasdump .B rasdump
\fB\-i\fR \fIID\fR \fB\-t\fR \fIID[:LUN]\fR
[\fB\-b\fR \fIBID\fR] [\fB\-i\fR \fIBID\fR]
\fB\-f\fR \fIFILE\fR \fB\-f\fR \fIFILE\fR
[\fB\-s\fR \fIBUFFER_SIZE\fR]
[\fB\-r\fR] [\fB\-r\fR]
[\fB\-v\fR]
.SH DESCRIPTION .SH DESCRIPTION
.B rasdump .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. 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 .SH OPTIONS
.TP .TP
.BR \-i\fI " "\fIID .BR \-t\fI " "\fIID[:LUN]
SCSI ID of the target device SCSI ID and optional LUN of the target device.
.TP .TP
.BR \-b\fI " "\fIBID .BR \-i\fI " "\fIBID
SCSI ID of the RaSCSI device SCSI ID of the RaSCSI device.
.TP .TP
.BR \-f\fI " "\fIFILE .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 .TP
.BR \-r\fI .BR \-r\fI
Restoration mode Run in restore mode.
.TP
.SH EXAMPLES .BR \-v\fI
Enable verbose logging.
.SH SEE ALSO .SH SEE ALSO
rasctl(1), rascsi(1), scsimon(1), sasidump(1) rasctl(1), rascsi(1), scsimon(1)
Full documentation is available at: <https://www.github.com/akuker/RASCSI/wiki/> Full documentation is available at: <https://www.github.com/akuker/RASCSI/wiki/>

42
doc/rasdump_man_page.txt Normal file
View File

@ -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:
<https://www.github.com/akuker/RASCSI/wiki/>
rasdump(1)