2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2022-12-05 17:58:23 +00:00
|
|
|
// SCSI Target Emulator PiSCSI
|
2018-05-03 13:47:57 +00:00
|
|
|
// for Raspberry Pi
|
|
|
|
//
|
|
|
|
// Powered by XM6 TypeG Technology.
|
2020-07-04 14:57:44 +00:00
|
|
|
// Copyright (C) 2016-2020 GIMONS
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-09-10 21:40:24 +00:00
|
|
|
#include "hal/gpiobus.h"
|
2022-12-03 04:20:27 +00:00
|
|
|
#include "hal/sbc_version.h"
|
2022-10-25 00:21:40 +00:00
|
|
|
#include "hal/systimer.h"
|
2023-10-15 06:38:15 +00:00
|
|
|
#include <spdlog/spdlog.h>
|
2022-12-03 04:20:27 +00:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/time.h>
|
2022-10-04 15:23:42 +00:00
|
|
|
#ifdef __linux__
|
2022-09-25 21:49:24 +00:00
|
|
|
#include <sys/epoll.h>
|
|
|
|
#endif
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-11-09 07:40:26 +00:00
|
|
|
using namespace std;
|
2022-09-25 21:49:24 +00:00
|
|
|
|
SASI code removal, error handling update, bug fixes, code cleanup (#806)
Summary ov most important changes triggered by the SASI code removal:
- Removed the SASI controller code
- New controller management. There is a new controller base class AbstractController and a class ControllerManager managing the controller lifecycle. The lifecycle management was removed from rasci.cpp and is covered by unit tests.
- New device management. The DeviceFactory manages the device lifecycle instead of rascsi.cpp. The new code is covered by unit tests.
- The lifecycle managment uses C++ collections with variable size instead of arrays with hard-coded sizes.
- The ScsiController method contains most of what was previously contained in scsidev_ctrl.cpp plus the code from sasidev_ctrl.cpp that was relevant for SCSI.
- scsi_command_util contains helper methods used for identical SCSI command implementations of more than one device
- Devices know their controllers, so that the controller instance does not need to be passed to each SCSI command. This change helps to decouple the devices from the controller. The phase_handler interface is also part of this decoupling.
- Use scsi_command_exception for propagating SCSI command execution errors, This resolves issues with the previous error handling, which was based on return values and often on magic numbers.
- Removed legacy SCSI error codes, all errors are now encoded by sense_key::, asc:: and status::.
- Fixed various warnings reported with -Wextra, -Weffc++ and -Wpedantic.
- Use constructor member initialization lists (recommended for ISO C++)
- Consistently use new/delete instead of malloc/free (recommended for ISO C++), resulting in better type safety and error handling
- Replaced variable sized arrays on the stack (violates ISO C++ and can cause a stack overflow)
- Replaced NULL by nullptr (recommended for C++), resulting in better type safety
- Use more const member functions in order to avoid side effects
- The format device page can now also be changed for hard disk drives (Fujitsu M2624S supports this, for instance), not just for MOs.
- Better encapsulation, updated access specifiers in many places
- Removed unused methods and method arguments
- Fixed a number of TODOs
- Added/updated unit tests for a lot of non-legacy classes
- Makefile support for creating HTML coverage reports with lcov/genhtml
2022-09-03 14:53:53 +00:00
|
|
|
bool GPIOBUS::Init(mode_e mode)
|
2018-05-03 13:47:57 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
GPIO_FUNCTION_TRACE
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Save operation mode
|
|
|
|
actmode = mode;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
return true;
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Receive command handshake
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2022-12-03 04:20:27 +00:00
|
|
|
int GPIOBUS::CommandHandShake(vector<uint8_t> &buf)
|
2020-07-04 14:57:44 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
// Only works in TARGET mode
|
|
|
|
if (actmode != mode_e::TARGET) {
|
|
|
|
return 0;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
DisableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Assert REQ signal
|
|
|
|
SetREQ(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK signal
|
|
|
|
bool ret = WaitACK(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait until the signal line stabilizes
|
|
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Get data
|
|
|
|
buf[0] = GetDAT();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Disable REQ signal
|
|
|
|
SetREQ(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Timeout waiting for ACK assertion
|
|
|
|
if (!ret) {
|
|
|
|
EnableIRQ();
|
|
|
|
return 0;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK to clear
|
|
|
|
ret = WaitACK(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Timeout waiting for ACK to clear
|
|
|
|
if (!ret) {
|
|
|
|
EnableIRQ();
|
|
|
|
return 0;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// The ICD AdSCSI ST, AdSCSI Plus ST and AdSCSI Micro ST host adapters allow SCSI devices to be connected
|
|
|
|
// to the ACSI bus of Atari ST/TT computers and some clones. ICD-aware drivers prepend a $1F byte in front
|
|
|
|
// of the CDB (effectively resulting in a custom SCSI command) in order to get access to the full SCSI
|
|
|
|
// command set. Native ACSI is limited to the low SCSI command classes with command bytes < $20.
|
|
|
|
// Most other host adapters (e.g. LINK96/97 and the one by Inventronik) and also several devices (e.g.
|
|
|
|
// UltraSatan or GigaFile) that can directly be connected to the Atari's ACSI port also support ICD
|
|
|
|
// semantics. I fact, these semantics have become a standard in the Atari world.
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-05 17:58:23 +00:00
|
|
|
// PiSCSI becomes ICD compatible by ignoring the prepended $1F byte before processing the CDB.
|
2022-12-03 04:20:27 +00:00
|
|
|
if (buf[0] == 0x1F) {
|
|
|
|
SetREQ(ON);
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
ret = WaitACK(ON);
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Get the actual SCSI command
|
|
|
|
buf[0] = GetDAT();
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
SetREQ(OFF);
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
if (!ret) {
|
|
|
|
EnableIRQ();
|
|
|
|
return 0;
|
|
|
|
}
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
WaitACK(OFF);
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
if (!ret) {
|
|
|
|
EnableIRQ();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2022-02-05 01:45:10 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
const int command_byte_count = GetCommandByteCount(buf[0]);
|
|
|
|
if (command_byte_count == 0) {
|
|
|
|
EnableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2022-11-06 18:44:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
int offset = 0;
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
int bytes_received;
|
|
|
|
for (bytes_received = 1; bytes_received < command_byte_count; bytes_received++) {
|
|
|
|
++offset;
|
2022-11-06 18:44:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Assert REQ signal
|
|
|
|
SetREQ(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK signal
|
|
|
|
ret = WaitACK(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait until the signal line stabilizes
|
|
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Get data
|
|
|
|
buf[offset] = GetDAT();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Clear the REQ signal
|
|
|
|
SetREQ(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for ACK assertion
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK to clear
|
|
|
|
ret = WaitACK(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for ACK to clear
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
EnableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
return bytes_received;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Data reception handshake
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2022-11-02 06:36:25 +00:00
|
|
|
int GPIOBUS::ReceiveHandShake(uint8_t *buf, int count)
|
2018-05-03 13:47:57 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
int i;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Disable IRQs
|
|
|
|
DisableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
if (actmode == mode_e::TARGET) {
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
// Assert the REQ signal
|
|
|
|
SetREQ(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK
|
|
|
|
bool ret = WaitACK(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait until the signal line stabilizes
|
|
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Get data
|
|
|
|
*buf = GetDAT();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Clear the REQ signal
|
|
|
|
SetREQ(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for ACK signal
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK to clear
|
|
|
|
ret = WaitACK(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for ACK to clear
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Advance the buffer pointer to receive the next byte
|
|
|
|
buf++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Get phase
|
|
|
|
Acquire();
|
|
|
|
phase_t phase = GetPhase();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
// Wait for the REQ signal to be asserted
|
|
|
|
bool ret = WaitREQ(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for REQ signal
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Phase error
|
|
|
|
Acquire();
|
|
|
|
if (GetPhase() != phase) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait until the signal line stabilizes
|
|
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Get data
|
|
|
|
*buf = GetDAT();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Assert the ACK signal
|
|
|
|
SetACK(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for REQ to clear
|
|
|
|
ret = WaitREQ(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Clear the ACK signal
|
|
|
|
SetACK(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for REQ to clear
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Phase error
|
|
|
|
Acquire();
|
|
|
|
if (GetPhase() != phase) {
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Advance the buffer pointer to receive the next byte
|
|
|
|
buf++;
|
|
|
|
}
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Re-enable IRQ
|
|
|
|
EnableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Return the number of bytes received
|
|
|
|
return i;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Data transmission handshake
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2022-11-02 06:36:25 +00:00
|
|
|
int GPIOBUS::SendHandShake(uint8_t *buf, int count, int delay_after_bytes)
|
2018-05-03 13:47:57 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
int i;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Disable IRQs
|
|
|
|
DisableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
if (actmode == mode_e::TARGET) {
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
if (i == delay_after_bytes) {
|
2023-10-15 06:38:15 +00:00
|
|
|
spdlog::trace("DELAYING for " + to_string(SCSI_DELAY_SEND_DATA_DAYNAPORT_US) + " after " +
|
|
|
|
to_string(delay_after_bytes) + " bytes");
|
2022-12-03 04:20:27 +00:00
|
|
|
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
|
|
|
|
}
|
2021-04-05 19:17:05 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Set the DATA signals
|
|
|
|
SetDAT(*buf);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK to clear
|
|
|
|
bool ret = WaitACK(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for ACK to clear
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Already waiting for ACK to clear
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Assert the REQ signal
|
|
|
|
SetREQ(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK
|
|
|
|
ret = WaitACK(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Clear REQ signal
|
|
|
|
SetREQ(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for ACK to clear
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Advance the data buffer pointer to receive the next byte
|
|
|
|
buf++;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for ACK to clear
|
|
|
|
WaitACK(OFF);
|
|
|
|
} else {
|
|
|
|
// Get Phase
|
|
|
|
Acquire();
|
|
|
|
phase_t phase = GetPhase();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
if (i == delay_after_bytes) {
|
2023-10-15 06:38:15 +00:00
|
|
|
spdlog::trace("DELAYING for " + to_string(SCSI_DELAY_SEND_DATA_DAYNAPORT_US) + " after " +
|
|
|
|
to_string(delay_after_bytes) + " bytes");
|
2022-12-03 04:20:27 +00:00
|
|
|
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
|
|
|
|
}
|
2021-04-05 19:17:05 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Set the DATA signals
|
|
|
|
SetDAT(*buf);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for REQ to be asserted
|
|
|
|
bool ret = WaitREQ(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for REQ to be asserted
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Phase error
|
|
|
|
Acquire();
|
|
|
|
if (GetPhase() != phase) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Already waiting for REQ assertion
|
2020-10-19 12:31:06 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Assert the ACK signal
|
|
|
|
SetACK(ON);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Wait for REQ to clear
|
|
|
|
ret = WaitREQ(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Clear the ACK signal
|
|
|
|
SetACK(OFF);
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for timeout waiting for REQ to clear
|
|
|
|
if (!ret) {
|
|
|
|
break;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Phase error
|
|
|
|
Acquire();
|
|
|
|
if (GetPhase() != phase) {
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Advance the data buffer pointer to receive the next byte
|
|
|
|
buf++;
|
|
|
|
}
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Re-enable IRQ
|
|
|
|
EnableIRQ();
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Return number of transmissions
|
|
|
|
return i;
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// SEL signal event polling
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
SASI code removal, error handling update, bug fixes, code cleanup (#806)
Summary ov most important changes triggered by the SASI code removal:
- Removed the SASI controller code
- New controller management. There is a new controller base class AbstractController and a class ControllerManager managing the controller lifecycle. The lifecycle management was removed from rasci.cpp and is covered by unit tests.
- New device management. The DeviceFactory manages the device lifecycle instead of rascsi.cpp. The new code is covered by unit tests.
- The lifecycle managment uses C++ collections with variable size instead of arrays with hard-coded sizes.
- The ScsiController method contains most of what was previously contained in scsidev_ctrl.cpp plus the code from sasidev_ctrl.cpp that was relevant for SCSI.
- scsi_command_util contains helper methods used for identical SCSI command implementations of more than one device
- Devices know their controllers, so that the controller instance does not need to be passed to each SCSI command. This change helps to decouple the devices from the controller. The phase_handler interface is also part of this decoupling.
- Use scsi_command_exception for propagating SCSI command execution errors, This resolves issues with the previous error handling, which was based on return values and often on magic numbers.
- Removed legacy SCSI error codes, all errors are now encoded by sense_key::, asc:: and status::.
- Fixed various warnings reported with -Wextra, -Weffc++ and -Wpedantic.
- Use constructor member initialization lists (recommended for ISO C++)
- Consistently use new/delete instead of malloc/free (recommended for ISO C++), resulting in better type safety and error handling
- Replaced variable sized arrays on the stack (violates ISO C++ and can cause a stack overflow)
- Replaced NULL by nullptr (recommended for C++), resulting in better type safety
- Use more const member functions in order to avoid side effects
- The format device page can now also be changed for hard disk drives (Fujitsu M2624S supports this, for instance), not just for MOs.
- Better encapsulation, updated access specifiers in many places
- Removed unused methods and method arguments
- Fixed a number of TODOs
- Added/updated unit tests for a lot of non-legacy classes
- Makefile support for creating HTML coverage reports with lcov/genhtml
2022-09-03 14:53:53 +00:00
|
|
|
bool GPIOBUS::PollSelectEvent()
|
2020-07-04 14:57:44 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
#ifndef USE_SEL_EVENT_ENABLE
|
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
GPIO_FUNCTION_TRACE
|
2023-10-15 06:38:15 +00:00
|
|
|
spdlog::trace(__PRETTY_FUNCTION__);
|
2023-10-22 15:29:26 +00:00
|
|
|
errno = 0;
|
2022-12-03 04:20:27 +00:00
|
|
|
|
|
|
|
if (epoll_event epev; epoll_wait(epfd, &epev, 1, -1) <= 0) {
|
2023-10-15 06:38:15 +00:00
|
|
|
spdlog::warn("epoll_wait failed");
|
2022-12-03 04:20:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
if (gpioevent_data gpev; read(selevreq.fd, &gpev, sizeof(gpev)) < 0) {
|
2023-10-15 06:38:15 +00:00
|
|
|
spdlog::warn("read failed");
|
2022-10-01 15:56:06 +00:00
|
|
|
return false;
|
2022-12-03 04:20:27 +00:00
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
return true;
|
|
|
|
#endif
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Cancel SEL signal event
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2021-07-26 18:33:36 +00:00
|
|
|
void GPIOBUS::ClearSelectEvent()
|
2020-07-04 14:57:44 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
GPIO_FUNCTION_TRACE
|
2022-11-09 07:40:26 +00:00
|
|
|
}
|
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Wait for signal change
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2022-12-03 04:20:27 +00:00
|
|
|
bool GPIOBUS::WaitSignal(int pin, bool ast)
|
2022-11-09 07:40:26 +00:00
|
|
|
{
|
2022-12-03 04:20:27 +00:00
|
|
|
// Get current time
|
2023-10-22 15:29:26 +00:00
|
|
|
const uint32_t now = SysTimer::GetTimerLow();
|
2022-11-09 07:40:26 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Calculate timeout (3000ms)
|
2023-10-22 15:29:26 +00:00
|
|
|
const uint32_t timeout = 3000 * 1000;
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
do {
|
|
|
|
// Immediately upon receiving a reset
|
|
|
|
Acquire();
|
|
|
|
if (GetRST()) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-11-09 07:40:26 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// Check for the signal edge
|
|
|
|
if (GetSignal(pin) == ast) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} while ((SysTimer::GetTimerLow() - now) < timeout);
|
2022-11-09 07:40:26 +00:00
|
|
|
|
2022-12-03 04:20:27 +00:00
|
|
|
// We timed out waiting for the signal
|
|
|
|
return false;
|
2023-10-15 06:38:15 +00:00
|
|
|
}
|