mirror of
https://github.com/thewesker/RASCSI.git
synced 2025-12-20 12:21:10 -05:00
Start to back out some changes. Just include command processing changes
This commit is contained in:
@@ -54,7 +54,6 @@ SRC_RASCSI = \
|
||||
gpiobus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp\
|
||||
rascsi_mgr.cpp\
|
||||
command_thread.cpp\
|
||||
os.cpp\
|
||||
rasctl_command.cpp
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "os.h"
|
||||
#include "rasctl_command.h"
|
||||
#include "rascsi_mgr.h"
|
||||
#include "sasihd.h"
|
||||
#include "scsihd.h"
|
||||
#include "scsihd_nec.h"
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// [ RaSCSI main ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -27,41 +25,35 @@
|
||||
#include "controllers/sasidev_ctrl.h"
|
||||
#include "gpiobus.h"
|
||||
#include "command_thread.h"
|
||||
#include "rascsi_mgr.h"
|
||||
|
||||
#include "sasidev_ctrl.h"
|
||||
#include "scsidev_ctrl.h"
|
||||
|
||||
#include "sasihd.h"
|
||||
#include "scsihd.h"
|
||||
#include "scsihd_apple.h"
|
||||
#include "scsihd_nec.h"
|
||||
#include "scsicd.h"
|
||||
#include "scsimo.h"
|
||||
#include "scsi_host_bridge.h"
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#define CtrlMax 8 // Maximum number of SCSI controllers
|
||||
#define UnitNum 2 // Number of units around controller
|
||||
#ifdef BAREMETAL
|
||||
#define FPRT(fp, ...) printf( __VA_ARGS__ )
|
||||
#else
|
||||
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
||||
#endif // BAREMETAL
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Variable declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static volatile BOOL running; // Running flag
|
||||
static volatile BOOL active; // Processing flag
|
||||
SASIDEV *ctrl[CtrlMax]; // Controller
|
||||
Disk *disk[CtrlMax * UnitNum]; // Disk
|
||||
GPIOBUS *bus; // GPIO Bus
|
||||
#ifdef BAREMETAL
|
||||
FATFS fatfs; // FatFS
|
||||
#else
|
||||
#endif // BAREMETAL
|
||||
|
||||
#ifndef CONNECT_DESC
|
||||
#define CONNECT_DESC "UNKNOWN"
|
||||
#endif
|
||||
|
||||
#ifndef BAREMETAL
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
@@ -71,7 +63,7 @@ FATFS fatfs; // FatFS
|
||||
void KillHandler(int sig)
|
||||
{
|
||||
// Stop instruction
|
||||
Rascsi_Manager::Stop();
|
||||
running = FALSE;
|
||||
}
|
||||
#endif // BAREMETAL
|
||||
|
||||
@@ -93,7 +85,6 @@ void Banner(int argc, char* argv[])
|
||||
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
||||
FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n");
|
||||
FPRT(stdout,"Connect type : %s\n", CONNECT_DESC);
|
||||
FPRT(stdout,"Build on %s at %s\n", __DATE__, __TIME__);
|
||||
|
||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
||||
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||
@@ -127,17 +118,9 @@ void Banner(int argc, char* argv[])
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Init()
|
||||
{
|
||||
printf("Rascsi_Manager Init\n");
|
||||
if(!Rascsi_Manager::Init()){
|
||||
printf("\tRascsi_Manager FAILED!!\n");
|
||||
return FALSE;
|
||||
}
|
||||
int i;
|
||||
|
||||
printf("Command_Thread Init\n");
|
||||
if(!Command_Thread::Init()){
|
||||
printf("\tCommand_Thread FAILED!!\n");
|
||||
return FALSE;
|
||||
}
|
||||
#ifndef BAREMETAL
|
||||
|
||||
// Interrupt handler settings
|
||||
if (signal(SIGINT, KillHandler) == SIG_ERR) {
|
||||
@@ -149,6 +132,38 @@ BOOL Init()
|
||||
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
|
||||
return FALSE;
|
||||
}
|
||||
#endif // BAREMETAL
|
||||
|
||||
// GPIOBUS creation
|
||||
bus = new GPIOBUS();
|
||||
|
||||
// GPIO Initialization
|
||||
if (!bus->Init()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Bus Reset
|
||||
bus->Reset();
|
||||
|
||||
// Controller initialization
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Disk Initialization
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
disk[i] = NULL;
|
||||
}
|
||||
|
||||
// Other
|
||||
running = FALSE;
|
||||
active = FALSE;
|
||||
|
||||
printf("Command_Thread Init\n");
|
||||
if(!Command_Thread::Init()){
|
||||
printf("\tCommand_Thread FAILED!!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -160,13 +175,243 @@ BOOL Init()
|
||||
//---------------------------------------------------------------------------
|
||||
void Cleanup()
|
||||
{
|
||||
Rascsi_Manager::Close();
|
||||
int i;
|
||||
|
||||
// Delete the disks
|
||||
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
||||
if (disk[i]) {
|
||||
delete disk[i];
|
||||
disk[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the Controllers
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
if (ctrl[i]) {
|
||||
delete ctrl[i];
|
||||
ctrl[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup the Bus
|
||||
bus->Cleanup();
|
||||
|
||||
// Discard the GPIOBUS object
|
||||
delete bus;
|
||||
|
||||
#ifndef BAREMETAL
|
||||
// Close the command socket
|
||||
Command_Thread::Close();
|
||||
#endif // BAREMETAL
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Reset
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Reset all of the controllers
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
if (ctrl[i]) {
|
||||
ctrl[i]->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the bus
|
||||
bus->Reset();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// List Devices
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void ListDevice(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
int id;
|
||||
int un;
|
||||
Disk *pUnit;
|
||||
Filepath filepath;
|
||||
BOOL find;
|
||||
char type[5];
|
||||
|
||||
find = FALSE;
|
||||
type[4] = 0;
|
||||
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
||||
// Initialize ID and unit number
|
||||
id = i / UnitNum;
|
||||
un = i % UnitNum;
|
||||
pUnit = disk[i];
|
||||
|
||||
// skip if unit does not exist or null disk
|
||||
if (pUnit == NULL || pUnit->IsNULL()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Output the header
|
||||
if (!find) {
|
||||
FPRT(fp, "\n");
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n");
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
find = TRUE;
|
||||
}
|
||||
|
||||
// ID,UNIT,Type,Device Status
|
||||
type[0] = (char)(pUnit->GetID() >> 24);
|
||||
type[1] = (char)(pUnit->GetID() >> 16);
|
||||
type[2] = (char)(pUnit->GetID() >> 8);
|
||||
type[3] = (char)(pUnit->GetID());
|
||||
FPRT(fp, "| %d | %d | %s | ", id, un, type);
|
||||
|
||||
// mount status output
|
||||
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||||
FPRT(fp, "%s", "HOST BRIDGE");
|
||||
} else {
|
||||
pUnit->GetPath(filepath);
|
||||
FPRT(fp, "%s",
|
||||
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
|
||||
"NO MEDIA" : filepath.GetPath());
|
||||
}
|
||||
|
||||
// Write protection status
|
||||
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
|
||||
FPRT(fp, "(WRITEPROTECT)");
|
||||
}
|
||||
|
||||
// Goto the next line
|
||||
FPRT(fp, "\n");
|
||||
}
|
||||
|
||||
// If there is no controller, find will be null
|
||||
if (!find) {
|
||||
FPRT(fp, "No device is installed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Controller Mapping
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void MapControler(FILE *fp, Disk **map)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int unitno;
|
||||
int sasi_num;
|
||||
int scsi_num;
|
||||
|
||||
// Replace the changed unit
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
for (j = 0; j < UnitNum; j++) {
|
||||
unitno = i * UnitNum + j;
|
||||
if (disk[unitno] != map[unitno]) {
|
||||
// Check if the original unit exists
|
||||
if (disk[unitno]) {
|
||||
// Disconnect it from the controller
|
||||
if (ctrl[i]) {
|
||||
ctrl[i]->SetUnit(j, NULL);
|
||||
}
|
||||
|
||||
// Free the Unit
|
||||
delete disk[unitno];
|
||||
}
|
||||
|
||||
// Setup a new unit
|
||||
disk[unitno] = map[unitno];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reconfigure all of the controllers
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
// Examine the unit configuration
|
||||
sasi_num = 0;
|
||||
scsi_num = 0;
|
||||
for (j = 0; j < UnitNum; j++) {
|
||||
unitno = i * UnitNum + j;
|
||||
// branch by unit type
|
||||
if (disk[unitno]) {
|
||||
if (disk[unitno]->IsSASI()) {
|
||||
// Drive is SASI, so increment SASI count
|
||||
sasi_num++;
|
||||
} else {
|
||||
// Drive is SCSI, so increment SCSI count
|
||||
scsi_num++;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the unit
|
||||
if (ctrl[i]) {
|
||||
ctrl[i]->SetUnit(j, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no units connected
|
||||
if (sasi_num == 0 && scsi_num == 0) {
|
||||
if (ctrl[i]) {
|
||||
delete ctrl[i];
|
||||
ctrl[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Mixture of SCSI and SASI
|
||||
if (sasi_num > 0 && scsi_num > 0) {
|
||||
FPRT(fp, "Error : SASI and SCSI can't be mixed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sasi_num > 0) {
|
||||
// Only SASI Unit(s)
|
||||
|
||||
// Release the controller if it is not SASI
|
||||
if (ctrl[i] && !ctrl[i]->IsSASI()) {
|
||||
delete ctrl[i];
|
||||
ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Create a new SASI controller
|
||||
if (!ctrl[i]) {
|
||||
ctrl[i] = new SASIDEV();
|
||||
ctrl[i]->Connect(i, bus);
|
||||
}
|
||||
} else {
|
||||
// Only SCSI Unit(s)
|
||||
|
||||
// Release the controller if it is not SCSI
|
||||
if (ctrl[i] && !ctrl[i]->IsSCSI()) {
|
||||
delete ctrl[i];
|
||||
ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Create a new SCSI controller
|
||||
if (!ctrl[i]) {
|
||||
ctrl[i] = new SCSIDEV();
|
||||
ctrl[i]->Connect(i, bus);
|
||||
}
|
||||
}
|
||||
|
||||
// connect all units
|
||||
for (j = 0; j < UnitNum; j++) {
|
||||
unitno = i * UnitNum + j;
|
||||
if (disk[unitno]) {
|
||||
// Add the unit connection
|
||||
ctrl[i]->SetUnit(j, disk[unitno]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Main processing
|
||||
@@ -181,9 +426,13 @@ int startrascsi(void)
|
||||
#else
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int i=0;
|
||||
#endif // BAREMETAL
|
||||
int i;
|
||||
int ret;
|
||||
int actid;
|
||||
DWORD now;
|
||||
BUS::phase_t phase;
|
||||
BYTE data;
|
||||
#ifndef BAREMETAL
|
||||
struct sched_param schparam;
|
||||
#endif // BAREMETAL
|
||||
@@ -198,24 +447,23 @@ int main(int argc, char* argv[])
|
||||
goto init_exit;
|
||||
}
|
||||
|
||||
// Reset
|
||||
Reset();
|
||||
|
||||
#ifdef BAREMETAL
|
||||
// BUSY assert (to hold the host side)
|
||||
Rascsi_Manager::m_bus->SetBSY(TRUE);
|
||||
bus->SetBSY(TRUE);
|
||||
|
||||
// Argument parsing
|
||||
if (!Command_Thread::ParseConfig(argc, argv)) {
|
||||
ret = EINVAL;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
// Release the busy signal
|
||||
Rascsi_Manager::m_bus->SetBSY(FALSE);
|
||||
|
||||
bus->SetBSY(FALSE);
|
||||
#endif
|
||||
|
||||
// For non-baremetal versions, we won't process the startup arguments... yet
|
||||
printf("Here1\n");
|
||||
|
||||
#ifndef BAREMETAL
|
||||
// Set the affinity to a specific processor core
|
||||
FixCpu(3);
|
||||
@@ -227,11 +475,105 @@ int main(int argc, char* argv[])
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
#endif // BAREMETAL
|
||||
|
||||
printf("entering main loop \n");
|
||||
// Start execution
|
||||
running = TRUE;
|
||||
|
||||
// Main Loop
|
||||
while (Rascsi_Manager::IsRunning()) {
|
||||
printf("step %d\n", i++);
|
||||
Rascsi_Manager::Step();
|
||||
while (running) {
|
||||
// Work initialization
|
||||
actid = -1;
|
||||
phase = BUS::busfree;
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal polling
|
||||
if (bus->PollSelectEvent() < 0) {
|
||||
// Stop on interrupt
|
||||
if (errno == EINTR) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the bus
|
||||
bus->Aquire();
|
||||
#else
|
||||
bus->Aquire();
|
||||
if (!bus->GetSEL()) {
|
||||
#if !defined(BAREMETAL)
|
||||
usleep(0);
|
||||
#endif // !BAREMETAL
|
||||
continue;
|
||||
}
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
// Wait until BSY is released as there is a possibility for the
|
||||
// initiator to assert it while setting the ID (for up to 3 seconds)
|
||||
if (bus->GetBSY()) {
|
||||
now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
||||
bus->Aquire();
|
||||
if (!bus->GetBSY()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop because it the bus is busy or another device responded
|
||||
if (bus->GetBSY() || !bus->GetSEL()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Notify all controllers
|
||||
data = bus->GetDAT();
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
if (!ctrl[i] || (data & (1 << i)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the target that has moved to the selection phase
|
||||
if (ctrl[i]->Process() == BUS::selection) {
|
||||
// Get the target ID
|
||||
actid = i;
|
||||
|
||||
// Bus Selection phase
|
||||
phase = BUS::selection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return to bus monitoring if the selection phase has not started
|
||||
if (phase != BUS::selection) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start target device
|
||||
active = TRUE;
|
||||
|
||||
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
||||
// Scheduling policy setting (highest priority)
|
||||
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
||||
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
||||
|
||||
// Loop until the bus is free
|
||||
while (running) {
|
||||
// Target drive
|
||||
phase = ctrl[actid]->Process();
|
||||
|
||||
// End when the bus is free
|
||||
if (phase == BUS::busfree) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
||||
// Set the scheduling priority back to normal
|
||||
schparam.sched_priority = 0;
|
||||
sched_setscheduler(0, SCHED_OTHER, &schparam);
|
||||
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
||||
|
||||
// End the target travel
|
||||
active = FALSE;
|
||||
}
|
||||
printf("Exited main loop\n");
|
||||
|
||||
|
||||
@@ -1,403 +0,0 @@
|
||||
#include "rascsi_mgr.h"
|
||||
#include "log.h"
|
||||
#include "sasidev_ctrl.h"
|
||||
#include "scsidev_ctrl.h"
|
||||
|
||||
SASIDEV *Rascsi_Manager::m_ctrl[CtrlMax]; // Controller
|
||||
Disk *Rascsi_Manager::m_disk[CtrlMax * UnitNum]; // Disk
|
||||
GPIOBUS *Rascsi_Manager::m_bus;
|
||||
|
||||
int Rascsi_Manager::m_actid = -1;
|
||||
BUS::phase_t Rascsi_Manager::m_phase = BUS::busfree;
|
||||
BYTE Rascsi_Manager::m_data = 0;
|
||||
DWORD Rascsi_Manager::m_now = 0;
|
||||
BOOL Rascsi_Manager::m_active = FALSE;
|
||||
BOOL Rascsi_Manager::m_running = FALSE;
|
||||
std::timed_mutex Rascsi_Manager::m_locked;
|
||||
BOOL Rascsi_Manager::m_initialized = FALSE;
|
||||
|
||||
BOOL Rascsi_Manager::AttachDevice(FILE *fp, Disk *disk, int id, int unit_num){
|
||||
BOOL result;
|
||||
m_locked.lock();
|
||||
result = AttachDevicePrivate(fp, disk, id, unit_num);
|
||||
m_locked.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL Rascsi_Manager::DetachDevice(FILE *fp, int id, int unit_num){
|
||||
BOOL result;
|
||||
m_locked.lock();
|
||||
result = DetachDevicePrivate(fp, id, unit_num);
|
||||
m_locked.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL Rascsi_Manager::AttachDevicePrivate(FILE *fp, Disk *disk, int id, int unit_num)
|
||||
{
|
||||
Rascsi_Device_Mode_e cur_mode = GetCurrentDeviceMode();
|
||||
int unitno = (id * UnitNum) + unit_num;
|
||||
|
||||
if((disk->IsSASI() && (cur_mode == rascsi_device_scsi_mode)) ||
|
||||
(!disk->IsSCSI() && (cur_mode == rascsi_device_sasi_mode))){
|
||||
FPRT(fp, "Warning: Can't mix SASI and SCSI devices!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check if something already exists at that SCSI ID / Unit Number
|
||||
if (m_disk[unitno]) {
|
||||
DetachDevicePrivate(fp,id,unit_num);
|
||||
}
|
||||
|
||||
// Add the new unit
|
||||
m_disk[unitno] = disk;
|
||||
|
||||
// If the controllder doesn't already exist, create it.
|
||||
if (m_ctrl[id] == nullptr){
|
||||
// We need to create a new controller
|
||||
if(disk->IsSASI()){
|
||||
m_ctrl[id] = new SASIDEV();
|
||||
}else{
|
||||
m_ctrl[id] = new SCSIDEV();
|
||||
}
|
||||
m_ctrl[id]->Connect(id, m_bus);
|
||||
}
|
||||
|
||||
// Add the disk to the controller
|
||||
m_ctrl[id]->SetUnit(unit_num, disk);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Rascsi_Manager::DetachDevicePrivate(FILE *fp, int id, int unit_num)
|
||||
{
|
||||
int unitno = (id * UnitNum) + unit_num;
|
||||
|
||||
// Disconnect it from the controller
|
||||
if (m_ctrl[id]) {
|
||||
m_ctrl[id]->SetUnit(unit_num, NULL);
|
||||
// Free the Unit
|
||||
delete m_disk[unitno];
|
||||
m_disk[unitno] = nullptr;
|
||||
}else{
|
||||
fprintf(fp, "Warning: A controller was not connected to the drive at id %d un %d\n",id, unit_num);
|
||||
fprintf(fp, "This is some sort of internal error, since you can't have a device without a controller.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If there are no longer any units connected to this controller, delete it
|
||||
if(!m_ctrl[id]->HasUnit()){
|
||||
delete m_ctrl[id];
|
||||
m_ctrl[id] = nullptr;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Disk* Rascsi_Manager::GetDevice(FILE *fp, int id, int unit_num)
|
||||
{
|
||||
int unitno = (id * UnitNum) + unit_num;
|
||||
return m_disk[unitno];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// GetCurrentDeviceMode
|
||||
//
|
||||
// Loop through all of the controllers and check if we have SCSI or SASI
|
||||
// controllers already created. (Note: We can't have a mix of them)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
Rascsi_Device_Mode_e Rascsi_Manager::GetCurrentDeviceMode(){
|
||||
|
||||
Rascsi_Device_Mode_e mode = rascsi_device_unknown_mode;
|
||||
for(int i =0; i < CtrlMax; i++){
|
||||
if(m_ctrl[i] != nullptr){
|
||||
if(m_ctrl[i]->IsSASI()){
|
||||
if(mode == rascsi_device_unknown_mode){
|
||||
mode = rascsi_device_sasi_mode;
|
||||
}else if(mode == rascsi_device_scsi_mode){
|
||||
mode = rascsi_device_invalid_mode;
|
||||
printf("Error: Mix of SCSI and SASI devices. This isn't allowed. Device %d was SASI, but expecting SCSI\n", i);
|
||||
}
|
||||
}else { // This is SCSI
|
||||
if(mode == rascsi_device_unknown_mode){
|
||||
mode = rascsi_device_scsi_mode;
|
||||
}else if(mode == rascsi_device_sasi_mode){
|
||||
mode = rascsi_device_invalid_mode;
|
||||
printf("Error: Mix of SCSI and SASI devices. This isn't allowed. Device %d was SCSI, but expecting SASI\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Reset
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Rascsi_Manager::Reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Reset all of the controllers
|
||||
for (i = 0; i < CtrlMax; i++) {
|
||||
if (m_ctrl[i]) {
|
||||
m_ctrl[i]->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the bus
|
||||
m_bus->Reset();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// List Devices
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Rascsi_Manager::ListDevice(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
int id;
|
||||
int un;
|
||||
Disk *pUnit;
|
||||
Filepath filepath;
|
||||
BOOL find;
|
||||
char type[5];
|
||||
|
||||
find = FALSE;
|
||||
type[4] = 0;
|
||||
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
||||
// Initialize ID and unit number
|
||||
id = i / UnitNum;
|
||||
un = i % UnitNum;
|
||||
pUnit = m_disk[i];
|
||||
|
||||
// skip if unit does not exist or null disk
|
||||
if (pUnit == NULL || pUnit->IsNULL()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Output the header
|
||||
if (!find) {
|
||||
FPRT(fp, "\n");
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n");
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
find = TRUE;
|
||||
}
|
||||
|
||||
// ID,UNIT,Type,Device Status
|
||||
type[0] = (char)(pUnit->GetID() >> 24);
|
||||
type[1] = (char)(pUnit->GetID() >> 16);
|
||||
type[2] = (char)(pUnit->GetID() >> 8);
|
||||
type[3] = (char)(pUnit->GetID());
|
||||
FPRT(fp, "| %d | %d | %s | ", id, un, type);
|
||||
|
||||
// mount status output
|
||||
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||||
FPRT(fp, "%s", "HOST BRIDGE");
|
||||
} else {
|
||||
pUnit->GetPath(filepath);
|
||||
FPRT(fp, "%s",
|
||||
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
|
||||
"NO MEDIA" : filepath.GetPath());
|
||||
}
|
||||
|
||||
// Write protection status
|
||||
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
|
||||
FPRT(fp, "(WRITEPROTECT)");
|
||||
}
|
||||
|
||||
// Goto the next line
|
||||
FPRT(fp, "\n");
|
||||
}
|
||||
|
||||
// If there is no controller, find will be null
|
||||
if (!find) {
|
||||
FPRT(fp, "No device is installed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
||||
}
|
||||
|
||||
void Rascsi_Manager::Close(){
|
||||
// Delete the disks
|
||||
for (int i = 0; i < (CtrlMax * UnitNum); i++) {
|
||||
if (m_disk[i]) {
|
||||
delete m_disk[i];
|
||||
m_disk[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the Controllers
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
if (m_ctrl[i]) {
|
||||
delete m_ctrl[i];
|
||||
m_ctrl[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup the Bus
|
||||
m_bus->Cleanup();
|
||||
|
||||
// Discard the GPIOBUS object
|
||||
delete m_bus;
|
||||
}
|
||||
|
||||
BOOL Rascsi_Manager::Init(){
|
||||
|
||||
if(m_initialized != FALSE){
|
||||
printf("Can not initialize Rascsi_Manager twice!!!\n");
|
||||
return FALSE;
|
||||
}
|
||||
m_initialized = TRUE;
|
||||
|
||||
// GPIOBUS creation
|
||||
m_bus = new GPIOBUS();
|
||||
|
||||
// GPIO Initialization
|
||||
if (!m_bus->Init()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Bus Reset
|
||||
m_bus->Reset();
|
||||
|
||||
// Controller initialization
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
m_ctrl[i] = NULL;
|
||||
}
|
||||
|
||||
// Disk Initialization
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
m_disk[i] = NULL;
|
||||
}
|
||||
|
||||
// Reset
|
||||
Reset();
|
||||
|
||||
m_running = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL Rascsi_Manager::Step()
|
||||
{
|
||||
|
||||
// Work initialization
|
||||
m_actid = -1;
|
||||
m_phase = BUS::busfree;
|
||||
|
||||
#ifdef USE_SEL_EVENT_ENABLE
|
||||
// SEL signal polling
|
||||
if (m_bus->PollSelectEvent() < 0) {
|
||||
// Stop on interrupt
|
||||
if (errno == EINTR) {
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get the bus
|
||||
m_bus->Aquire();
|
||||
#else
|
||||
m_bus->Aquire();
|
||||
if (!m_bus->GetSEL()) {
|
||||
#if !defined(BAREMETAL)
|
||||
usleep(0);
|
||||
#endif // !BAREMETAL
|
||||
return FALSE;
|
||||
}
|
||||
#endif // USE_SEL_EVENT_ENABLE
|
||||
|
||||
// Wait until BSY is released as there is a possibility for the
|
||||
// initiator to assert it while setting the ID (for up to 3 seconds)
|
||||
if (m_bus->GetBSY()) {
|
||||
m_now = SysTimer::GetTimerLow();
|
||||
while ((SysTimer::GetTimerLow() - m_now) < 3 * 1000 * 1000) {
|
||||
m_bus->Aquire();
|
||||
if (!m_bus->GetBSY()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop because it the bus is busy or another device responded
|
||||
if (m_bus->GetBSY() || !m_bus->GetSEL()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_locked.lock();
|
||||
// Notify all controllers
|
||||
m_data = m_bus->GetDAT();
|
||||
for (int i = 0; i < CtrlMax; i++) {
|
||||
if (!m_ctrl[i] || (m_data & (1 << i)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the target that has moved to the selection phase
|
||||
if (m_ctrl[i]->Process() == BUS::selection) {
|
||||
// Get the target ID
|
||||
m_actid = i;
|
||||
|
||||
// Bus Selection phase
|
||||
m_phase = BUS::selection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return to bus monitoring if the selection phase has not started
|
||||
if (m_phase != BUS::selection) {
|
||||
m_locked.unlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Start target device
|
||||
m_active = TRUE;
|
||||
|
||||
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
||||
// Scheduling policy setting (highest priority)
|
||||
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
||||
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
||||
|
||||
// Loop until the bus is free
|
||||
while (m_running) {
|
||||
// Target drive
|
||||
m_phase = m_ctrl[m_actid]->Process();
|
||||
|
||||
// End when the bus is free
|
||||
if (m_phase == BUS::busfree) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
||||
// Set the scheduling priority back to normal
|
||||
schparam.sched_priority = 0;
|
||||
sched_setscheduler(0, SCHED_OTHER, &schparam);
|
||||
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
||||
|
||||
// End the target travel
|
||||
m_active = FALSE;
|
||||
|
||||
m_locked.unlock();
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Rascsi_Manager::Stop(){
|
||||
m_running = FALSE;
|
||||
}
|
||||
BOOL Rascsi_Manager::IsRunning(){
|
||||
return (m_running == TRUE);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2014-2020 GIMONS
|
||||
// Copyright (C) akuker
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License.
|
||||
// See LICENSE file in the project root folder.
|
||||
//
|
||||
// [ RaSCSI Manager ]
|
||||
//
|
||||
// Any meaningful logic should be included in this file so that it can be
|
||||
// tested using unit tests. The main "rascsi.cpp" file should contain very
|
||||
// little functional code.
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "os.h"
|
||||
#include "scsi.h"
|
||||
#include "fileio.h"
|
||||
#include "disk.h"
|
||||
#include "log.h"
|
||||
#include "xm6.h"
|
||||
#include "gpiobus.h"
|
||||
#include "sasidev_ctrl.h"
|
||||
#include <mutex>
|
||||
|
||||
enum Rascsi_Device_Mode_e{
|
||||
rascsi_device_unknown_mode,
|
||||
rascsi_device_sasi_mode,
|
||||
rascsi_device_scsi_mode,
|
||||
rascsi_device_invalid_mode,
|
||||
};
|
||||
|
||||
class Rascsi_Manager{
|
||||
public:
|
||||
static Rascsi_Manager* GetInstance();
|
||||
static void MapControler(FILE *fp, Disk **map);
|
||||
|
||||
static void Stop();
|
||||
static BOOL IsRunning();
|
||||
|
||||
static BOOL AttachDevice(FILE *fp, Disk *disk, int id, int ui);
|
||||
static BOOL DetachDevice(FILE *fp, int id, int ui);
|
||||
static Disk* GetDevice(FILE *fp, int id, int ui);
|
||||
static void ListDevice(FILE *fp);
|
||||
static BOOL Init();
|
||||
static void Close();
|
||||
static void Reset();
|
||||
static BOOL Step();
|
||||
static Rascsi_Device_Mode_e GetCurrentDeviceMode();
|
||||
|
||||
static const int CtrlMax = 8; // Maximum number of SCSI controllers
|
||||
static const int UnitNum=2; // Number of units around controller
|
||||
|
||||
|
||||
// TODO: These need to be made private. All of the functionality that is using
|
||||
// them directly should be updated to be issolated.
|
||||
// The Command_Thread class is WAAAAY too tightly coupled to this class.
|
||||
//
|
||||
static SASIDEV *m_ctrl[CtrlMax]; // Controller
|
||||
static Disk *m_disk[CtrlMax * UnitNum]; // Disk
|
||||
static GPIOBUS *m_bus; // GPIO Bus
|
||||
|
||||
|
||||
private:
|
||||
static int m_actid;
|
||||
static BUS::phase_t m_phase;
|
||||
static BYTE m_data;
|
||||
static DWORD m_now;
|
||||
static BOOL m_active;
|
||||
static BOOL m_running;
|
||||
static BOOL m_initialized;
|
||||
|
||||
static BOOL AttachDevicePrivate(FILE *fp, Disk *disk, int id, int ui);
|
||||
static BOOL DetachDevicePrivate(FILE *fp, int id, int ui);
|
||||
|
||||
// Any PUBLIC functions should lock this before accessing the m_ctrl
|
||||
// m_disk or m_bus data structures. The Public functions could be
|
||||
// called from a different thread.
|
||||
static std::timed_mutex m_locked;
|
||||
};
|
||||
Reference in New Issue
Block a user