2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// SCSI Target Emulator RaSCSI (*^..^*)
|
|
|
|
// for Raspberry Pi
|
|
|
|
//
|
|
|
|
// Powered by XM6 TypeG Technology.
|
2020-07-04 14:57:44 +00:00
|
|
|
// Copyright (C) 2016-2020 GIMONS
|
2020-07-06 03:56:25 +00:00
|
|
|
// [ RaSCSI main ]
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "os.h"
|
|
|
|
#include "xm6.h"
|
|
|
|
#include "filepath.h"
|
2020-07-04 14:57:44 +00:00
|
|
|
#include "fileio.h"
|
2020-08-28 14:18:02 +00:00
|
|
|
#include "devices/disk.h"
|
|
|
|
#include "devices/sasihd.h"
|
|
|
|
#include "devices/scsihd.h"
|
|
|
|
#include "devices/scsihd_apple.h"
|
|
|
|
#include "devices/scsihd_nec.h"
|
|
|
|
#include "devices/scsicd.h"
|
|
|
|
#include "devices/scsimo.h"
|
|
|
|
#include "devices/scsi_host_bridge.h"
|
2021-02-07 19:00:48 +00:00
|
|
|
#include "devices/scsi_daynaport.h"
|
2020-08-28 14:18:02 +00:00
|
|
|
#include "controllers/scsidev_ctrl.h"
|
|
|
|
#include "controllers/sasidev_ctrl.h"
|
2018-05-03 13:47:57 +00:00
|
|
|
#include "gpiobus.h"
|
2021-01-25 16:07:30 +00:00
|
|
|
#include "rascsi_version.h"
|
2021-02-07 19:00:48 +00:00
|
|
|
#include "rasctl.h"
|
2020-10-19 12:31:06 +00:00
|
|
|
#include "spdlog/spdlog.h"
|
2021-02-07 19:00:48 +00:00
|
|
|
#include "spdlog/sinks/stdout_color_sinks.h"
|
|
|
|
#include <spdlog/async.h>
|
2020-08-28 14:18:02 +00:00
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Constant declarations
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2020-07-06 03:56:25 +00:00
|
|
|
#define CtrlMax 8 // Maximum number of SCSI controllers
|
|
|
|
#define UnitNum 2 // Number of units around controller
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef BAREMETAL
|
|
|
|
#define FPRT(fp, ...) printf( __VA_ARGS__ )
|
|
|
|
#else
|
|
|
|
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Variable declarations
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2020-07-06 03:56:25 +00:00
|
|
|
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
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef BAREMETAL
|
|
|
|
FATFS fatfs; // FatFS
|
|
|
|
#else
|
2020-07-06 03:56:25 +00:00
|
|
|
int monsocket; // Monitor Socket
|
|
|
|
pthread_t monthread; // Monitor Thread
|
2021-02-07 19:00:48 +00:00
|
|
|
pthread_mutex_t ctrl_mutex; // Semaphore for the ctrl array
|
2018-05-03 13:47:57 +00:00
|
|
|
static void *MonThread(void *param);
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifndef BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Signal Processing
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void KillHandler(int sig)
|
|
|
|
{
|
2020-07-06 03:56:25 +00:00
|
|
|
// Stop instruction
|
2020-07-04 14:57:44 +00:00
|
|
|
running = FALSE;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Banner Output
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2020-07-04 14:57:44 +00:00
|
|
|
void Banner(int argc, char* argv[])
|
2018-05-03 13:47:57 +00:00
|
|
|
{
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(stdout,"SCSI Target Emulator RaSCSI(*^..^*) ");
|
2021-01-25 16:07:30 +00:00
|
|
|
FPRT(stdout,"version %s (%s, %s)\n",
|
|
|
|
rascsi_get_version_string(),
|
2020-07-04 14:57:44 +00:00
|
|
|
__DATE__,
|
|
|
|
__TIME__);
|
|
|
|
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
|
|
|
FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n");
|
|
|
|
FPRT(stdout,"Connect type : %s\n", CONNECT_DESC);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-09 18:32:18 +00:00
|
|
|
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
2020-07-09 20:34:29 +00:00
|
|
|
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(stdout,"\n");
|
|
|
|
FPRT(stdout,"Usage: %s [-IDn FILE] ...\n\n", argv[0]);
|
|
|
|
FPRT(stdout," n is SCSI identification number(0-7).\n");
|
|
|
|
FPRT(stdout," FILE is disk image file.\n\n");
|
|
|
|
FPRT(stdout,"Usage: %s [-HDn FILE] ...\n\n", argv[0]);
|
|
|
|
FPRT(stdout," n is X68000 SASI HD number(0-15).\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
FPRT(stdout," FILE is disk image file, \"daynaport\", or \"bridge\".\n\n");
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(stdout," Image type is detected based on file extension.\n");
|
|
|
|
FPRT(stdout," hdf : SASI HD image(XM6 SASI HD image)\n");
|
|
|
|
FPRT(stdout," hds : SCSI HD image(XM6 SCSI HD image)\n");
|
|
|
|
FPRT(stdout," hdn : SCSI HD image(NEC GENUINE)\n");
|
|
|
|
FPRT(stdout," hdi : SCSI HD image(Anex86 HD image)\n");
|
|
|
|
FPRT(stdout," nhd : SCSI HD image(T98Next HD image)\n");
|
|
|
|
FPRT(stdout," hda : SCSI HD image(APPLE GENUINE)\n");
|
|
|
|
FPRT(stdout," mos : SCSI MO image(XM6 SCSI MO image)\n");
|
|
|
|
FPRT(stdout," iso : SCSI CD image(ISO 9660 image)\n");
|
|
|
|
|
|
|
|
#ifndef BAREMETAL
|
|
|
|
exit(0);
|
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Initialization
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL Init()
|
|
|
|
{
|
|
|
|
int i;
|
2020-07-04 14:57:44 +00:00
|
|
|
|
|
|
|
#ifndef BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
struct sockaddr_in server;
|
2021-02-07 19:00:48 +00:00
|
|
|
int yes, result;
|
|
|
|
|
|
|
|
result = pthread_mutex_init(&ctrl_mutex,NULL);
|
|
|
|
if(result != EXIT_SUCCESS){
|
|
|
|
LOGERROR("Unable to create a mutex. Err code: %d",result);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Create socket for monitor
|
2020-07-04 14:57:44 +00:00
|
|
|
monsocket = socket(PF_INET, SOCK_STREAM, 0);
|
2018-05-03 13:47:57 +00:00
|
|
|
memset(&server, 0, sizeof(server));
|
|
|
|
server.sin_family = PF_INET;
|
|
|
|
server.sin_port = htons(6868);
|
2020-07-04 14:57:44 +00:00
|
|
|
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// allow address reuse
|
2020-07-04 14:57:44 +00:00
|
|
|
yes = 1;
|
|
|
|
if (setsockopt(
|
|
|
|
monsocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0){
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Bind
|
2020-07-04 14:57:44 +00:00
|
|
|
if (bind(monsocket, (struct sockaddr *)&server,
|
2018-05-03 13:47:57 +00:00
|
|
|
sizeof(struct sockaddr_in)) < 0) {
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(stderr, "Error : Already running?\n");
|
|
|
|
return FALSE;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Create Monitor Thread
|
2020-07-04 14:57:44 +00:00
|
|
|
pthread_create(&monthread, NULL, MonThread, NULL);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Interrupt handler settings
|
2018-05-03 13:47:57 +00:00
|
|
|
if (signal(SIGINT, KillHandler) == SIG_ERR) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// GPIOBUS creation
|
2020-07-04 14:57:44 +00:00
|
|
|
bus = new GPIOBUS();
|
2020-07-10 01:20:18 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// GPIO Initialization
|
2020-07-07 21:41:12 +00:00
|
|
|
if (!bus->Init()) {
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Bus Reset
|
2020-07-04 14:57:44 +00:00
|
|
|
bus->Reset();
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Controller initialization
|
2018-05-03 13:47:57 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
|
|
|
ctrl[i] = NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Disk Initialization
|
2018-05-03 13:47:57 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
|
|
|
disk[i] = NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Other
|
2020-07-04 14:57:44 +00:00
|
|
|
running = FALSE;
|
|
|
|
active = FALSE;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Cleanup
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void Cleanup()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Delete the disks
|
2020-07-04 14:57:44 +00:00
|
|
|
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
2018-05-03 13:47:57 +00:00
|
|
|
if (disk[i]) {
|
|
|
|
delete disk[i];
|
|
|
|
disk[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Delete the Controllers
|
2018-05-03 13:47:57 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
|
|
|
if (ctrl[i]) {
|
|
|
|
delete ctrl[i];
|
|
|
|
ctrl[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Cleanup the Bus
|
2020-07-04 14:57:44 +00:00
|
|
|
bus->Cleanup();
|
2020-07-10 01:20:18 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Discard the GPIOBUS object
|
2020-07-04 14:57:44 +00:00
|
|
|
delete bus;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifndef BAREMETAL
|
2020-07-06 03:56:25 +00:00
|
|
|
// Close the monitor socket
|
2020-07-04 14:57:44 +00:00
|
|
|
if (monsocket >= 0) {
|
|
|
|
close(monsocket);
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
2021-02-07 19:00:48 +00:00
|
|
|
|
|
|
|
pthread_mutex_destroy(&ctrl_mutex);
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Reset
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void Reset()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Reset all of the controllers
|
2018-05-03 13:47:57 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
|
|
|
if (ctrl[i]) {
|
|
|
|
ctrl[i]->Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Reset the bus
|
2020-07-04 14:57:44 +00:00
|
|
|
bus->Reset();
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// List Devices
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void ListDevice(FILE *fp)
|
|
|
|
{
|
|
|
|
int i;
|
2020-07-04 14:57:44 +00:00
|
|
|
int id;
|
|
|
|
int un;
|
|
|
|
Disk *pUnit;
|
2018-05-03 13:47:57 +00:00
|
|
|
Filepath filepath;
|
|
|
|
BOOL find;
|
|
|
|
char type[5];
|
2021-02-07 19:00:48 +00:00
|
|
|
char dev_status[_MAX_FNAME+26];
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
find = FALSE;
|
|
|
|
type[4] = 0;
|
2020-07-04 14:57:44 +00:00
|
|
|
for (i = 0; i < CtrlMax * UnitNum; i++) {
|
2021-02-07 19:00:48 +00:00
|
|
|
strncpy(dev_status,"",sizeof(dev_status));
|
2020-07-06 03:56:25 +00:00
|
|
|
// Initialize ID and unit number
|
2020-07-04 14:57:44 +00:00
|
|
|
id = i / UnitNum;
|
|
|
|
un = i % UnitNum;
|
|
|
|
pUnit = disk[i];
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// skip if unit does not exist or null disk
|
2020-07-04 14:57:44 +00:00
|
|
|
if (pUnit == NULL || pUnit->IsNULL()) {
|
2018-05-03 13:47:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Output the header
|
|
|
|
if (!find) {
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "\n");
|
|
|
|
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO( "+----+----+------+-------------------------------------");
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO( "| ID | UN | TYPE | DEVICE STATUS\n");
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
2018-05-03 13:47:57 +00:00
|
|
|
find = TRUE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// ID,UNIT,Type,Device Status
|
2020-07-04 14:57:44 +00:00
|
|
|
type[0] = (char)(pUnit->GetID() >> 24);
|
|
|
|
type[1] = (char)(pUnit->GetID() >> 16);
|
|
|
|
type[2] = (char)(pUnit->GetID() >> 8);
|
|
|
|
type[3] = (char)(pUnit->GetID());
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// mount status output
|
2020-07-04 14:57:44 +00:00
|
|
|
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
2021-02-07 19:00:48 +00:00
|
|
|
strncpy(dev_status,"X68000 HOST BRIDGE",sizeof(dev_status));
|
|
|
|
} else if (pUnit->GetID() == MAKEID('S', 'C', 'D', 'P')) {
|
|
|
|
strncpy(dev_status,"DaynaPort SCSI/Link",sizeof(dev_status));
|
2018-05-03 13:47:57 +00:00
|
|
|
} else {
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit->GetPath(filepath);
|
2021-02-07 19:00:48 +00:00
|
|
|
snprintf(dev_status, sizeof(dev_status), "%s",
|
2020-07-04 14:57:44 +00:00
|
|
|
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
|
2018-05-03 13:47:57 +00:00
|
|
|
"NO MEDIA" : filepath.GetPath());
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Write protection status
|
2020-07-04 14:57:44 +00:00
|
|
|
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
|
2021-02-07 19:00:48 +00:00
|
|
|
strcat(dev_status, "(WRITEPROTECT)");
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
2021-02-07 19:00:48 +00:00
|
|
|
FPRT(fp, "| %d | %d | %s | %s\n", id, un, type, dev_status);
|
|
|
|
LOGINFO( "| %d | %d | %s | %s", id, un, type, dev_status);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// If there is no controller, find will be null
|
2018-05-03 13:47:57 +00:00
|
|
|
if (!find) {
|
2020-09-12 22:48:35 +00:00
|
|
|
FPRT(fp, "No images currently attached.\n");
|
2018-05-03 13:47:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-07-10 01:20:18 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "+----+----+------+-------------------------------------\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO( "+----+----+------+-------------------------------------");
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Controller Mapping
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void MapControler(FILE *fp, Disk **map)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
int unitno;
|
|
|
|
int sasi_num;
|
|
|
|
int scsi_num;
|
|
|
|
|
2021-02-07 19:00:48 +00:00
|
|
|
// Take ownership of the ctrl data structure
|
|
|
|
pthread_mutex_lock(&ctrl_mutex);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Replace the changed unit
|
2020-07-04 14:57:44 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
|
|
|
for (j = 0; j < UnitNum; j++) {
|
|
|
|
unitno = i * UnitNum + j;
|
|
|
|
if (disk[unitno] != map[unitno]) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Check if the original unit exists
|
2020-07-04 14:57:44 +00:00
|
|
|
if (disk[unitno]) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Disconnect it from the controller
|
2020-07-04 14:57:44 +00:00
|
|
|
if (ctrl[i]) {
|
|
|
|
ctrl[i]->SetUnit(j, NULL);
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Free the Unit
|
2020-07-04 14:57:44 +00:00
|
|
|
delete disk[unitno];
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Setup a new unit
|
2020-07-04 14:57:44 +00:00
|
|
|
disk[unitno] = map[unitno];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Reconfigure all of the controllers
|
2020-07-04 14:57:44 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Examine the unit configuration
|
2020-07-04 14:57:44 +00:00
|
|
|
sasi_num = 0;
|
|
|
|
scsi_num = 0;
|
|
|
|
for (j = 0; j < UnitNum; j++) {
|
|
|
|
unitno = i * UnitNum + j;
|
2020-07-06 03:56:25 +00:00
|
|
|
// branch by unit type
|
2020-07-04 14:57:44 +00:00
|
|
|
if (disk[unitno]) {
|
|
|
|
if (disk[unitno]->IsSASI()) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Drive is SASI, so increment SASI count
|
2020-07-04 14:57:44 +00:00
|
|
|
sasi_num++;
|
|
|
|
} else {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Drive is SCSI, so increment SCSI count
|
2020-07-04 14:57:44 +00:00
|
|
|
scsi_num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Remove the unit
|
2020-07-04 14:57:44 +00:00
|
|
|
if (ctrl[i]) {
|
|
|
|
ctrl[i]->SetUnit(j, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// If there are no units connected
|
2020-07-04 14:57:44 +00:00
|
|
|
if (sasi_num == 0 && scsi_num == 0) {
|
|
|
|
if (ctrl[i]) {
|
|
|
|
delete ctrl[i];
|
|
|
|
ctrl[i] = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Mixture of SCSI and SASI
|
2020-07-04 14:57:44 +00:00
|
|
|
if (sasi_num > 0 && scsi_num > 0) {
|
|
|
|
FPRT(fp, "Error : SASI and SCSI can't be mixed\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sasi_num > 0) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Only SASI Unit(s)
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Release the controller if it is not SASI
|
2020-07-04 14:57:44 +00:00
|
|
|
if (ctrl[i] && !ctrl[i]->IsSASI()) {
|
|
|
|
delete ctrl[i];
|
|
|
|
ctrl[i] = NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Create a new SASI controller
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!ctrl[i]) {
|
|
|
|
ctrl[i] = new SASIDEV();
|
|
|
|
ctrl[i]->Connect(i, bus);
|
|
|
|
}
|
|
|
|
} else {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Only SCSI Unit(s)
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Release the controller if it is not SCSI
|
2020-07-04 14:57:44 +00:00
|
|
|
if (ctrl[i] && !ctrl[i]->IsSCSI()) {
|
|
|
|
delete ctrl[i];
|
|
|
|
ctrl[i] = NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Create a new SCSI controller
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!ctrl[i]) {
|
|
|
|
ctrl[i] = new SCSIDEV();
|
|
|
|
ctrl[i]->Connect(i, bus);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// connect all units
|
2020-07-04 14:57:44 +00:00
|
|
|
for (j = 0; j < UnitNum; j++) {
|
|
|
|
unitno = i * UnitNum + j;
|
|
|
|
if (disk[unitno]) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Add the unit connection
|
2020-07-04 14:57:44 +00:00
|
|
|
ctrl[i]->SetUnit(j, disk[unitno]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-07 19:00:48 +00:00
|
|
|
pthread_mutex_unlock(&ctrl_mutex);
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Command Processing
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2020-07-04 14:57:44 +00:00
|
|
|
BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file)
|
2018-05-03 13:47:57 +00:00
|
|
|
{
|
2020-07-04 14:57:44 +00:00
|
|
|
Disk *map[CtrlMax * UnitNum];
|
2018-05-03 13:47:57 +00:00
|
|
|
int len;
|
|
|
|
char *ext;
|
|
|
|
Filepath filepath;
|
2020-07-04 14:57:44 +00:00
|
|
|
Disk *pUnit;
|
2021-02-07 19:00:48 +00:00
|
|
|
char type_str[5];
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Copy the Unit List
|
2020-07-04 14:57:44 +00:00
|
|
|
memcpy(map, disk, sizeof(disk));
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Check the Controller Number
|
2020-07-04 14:57:44 +00:00
|
|
|
if (id < 0 || id >= CtrlMax) {
|
|
|
|
FPRT(fp, "Error : Invalid ID\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Check the Unit Number
|
2020-07-04 14:57:44 +00:00
|
|
|
if (un < 0 || un >= UnitNum) {
|
|
|
|
FPRT(fp, "Error : Invalid unit number\n");
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Connect Command
|
2018-05-03 13:47:57 +00:00
|
|
|
if (cmd == 0) { // ATTACH
|
2020-07-06 03:56:25 +00:00
|
|
|
// Distinguish between SASI and SCSI
|
2020-07-04 14:57:44 +00:00
|
|
|
ext = NULL;
|
|
|
|
pUnit = NULL;
|
2021-02-07 19:00:48 +00:00
|
|
|
if (type == rasctl_dev_sasi_hd) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Passed the check
|
2018-05-03 13:47:57 +00:00
|
|
|
if (!file) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Check that command is at least 5 characters long
|
2018-05-03 13:47:57 +00:00
|
|
|
len = strlen(file);
|
|
|
|
if (len < 5) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Check the extension
|
2018-05-03 13:47:57 +00:00
|
|
|
if (file[len - 4] != '.') {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// If the extension is not SASI type, replace with SCSI
|
2018-05-03 13:47:57 +00:00
|
|
|
ext = &file[len - 3];
|
|
|
|
if (xstrcasecmp(ext, "hdf") != 0) {
|
2021-02-07 19:00:48 +00:00
|
|
|
type = rasctl_dev_scsi_hd;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Create a new drive, based upon type
|
2018-05-03 13:47:57 +00:00
|
|
|
switch (type) {
|
2021-02-07 19:00:48 +00:00
|
|
|
case rasctl_dev_sasi_hd: // HDF
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SASIHD();
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-02-07 19:00:48 +00:00
|
|
|
case rasctl_dev_scsi_hd: // HDS/HDN/HDI/NHD/HDA
|
2020-07-04 14:57:44 +00:00
|
|
|
if (ext == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
if (xstrcasecmp(ext, "hdn") == 0 ||
|
|
|
|
xstrcasecmp(ext, "hdi") == 0 || xstrcasecmp(ext, "nhd") == 0) {
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SCSIHD_NEC();
|
2018-05-03 13:47:57 +00:00
|
|
|
} else if (xstrcasecmp(ext, "hda") == 0) {
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SCSIHD_APPLE();
|
2018-05-03 13:47:57 +00:00
|
|
|
} else {
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SCSIHD();
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-02-07 19:00:48 +00:00
|
|
|
case rasctl_dev_mo: // MO
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SCSIMO();
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-02-07 19:00:48 +00:00
|
|
|
case rasctl_dev_cd: // CD
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SCSICD();
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-02-07 19:00:48 +00:00
|
|
|
case rasctl_dev_br: // BRIDGE
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = new SCSIBR();
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-02-07 19:00:48 +00:00
|
|
|
// case rasctl_dev_nuvolink: // Nuvolink
|
|
|
|
// pUnit = new SCSINuvolink();
|
|
|
|
// break;
|
|
|
|
case rasctl_dev_daynaport: // DaynaPort SCSI Link
|
|
|
|
pUnit = new SCSIDaynaPort();
|
|
|
|
LOGTRACE("Done creating SCSIDayanPort");
|
|
|
|
break;
|
2018-05-03 13:47:57 +00:00
|
|
|
default:
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "Error : Invalid device type\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGWARN("rasctl sent a command for an invalid drive type: %d", type);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// drive checks files
|
2021-04-03 19:02:20 +00:00
|
|
|
if (type <= rasctl_dev_scsi_hd || ((type <= rasctl_dev_cd || type == rasctl_dev_daynaport) && xstrcasecmp(file, "-") != 0)) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the Path
|
2018-05-03 13:47:57 +00:00
|
|
|
filepath.SetPath(file);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Open the file path
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!pUnit->Open(filepath)) {
|
|
|
|
FPRT(fp, "Error : File open error [%s]\n", file);
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGWARN("rasctl tried to open an invalid file %s", file);
|
2020-07-04 14:57:44 +00:00
|
|
|
delete pUnit;
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the cache to write-through
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit->SetCacheWB(FALSE);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Replace with the newly created unit
|
2020-07-04 14:57:44 +00:00
|
|
|
map[id * UnitNum + un] = pUnit;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Re-map the controller
|
2020-07-04 14:57:44 +00:00
|
|
|
MapControler(fp, map);
|
2021-02-07 19:00:48 +00:00
|
|
|
type_str[0] = (char)(pUnit->GetID() >> 24);
|
|
|
|
type_str[1] = (char)(pUnit->GetID() >> 16);
|
|
|
|
type_str[2] = (char)(pUnit->GetID() >> 8);
|
|
|
|
type_str[3] = (char)(pUnit->GetID());
|
|
|
|
type_str[4] = '\0';
|
|
|
|
LOGINFO("rasctl added new %s device. ID: %d UN: %d", type_str, id, un);
|
2018-05-03 13:47:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Is this a valid command?
|
2018-05-03 13:47:57 +00:00
|
|
|
if (cmd > 4) {
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "Error : Invalid command\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO("rasctl sent an invalid command: %d",cmd);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Does the controller exist?
|
2018-05-03 13:47:57 +00:00
|
|
|
if (ctrl[id] == NULL) {
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "Error : No such device\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGWARN("rasctl sent a command for invalid controller %d", id);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Does the unit exist?
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit = disk[id * UnitNum + un];
|
|
|
|
if (pUnit == NULL) {
|
|
|
|
FPRT(fp, "Error : No such device\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGWARN("rasctl sent a command for invalid unit ID %d UN %d", id, un);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2021-02-07 19:00:48 +00:00
|
|
|
type_str[0] = (char)(map[id * UnitNum + un]->GetID() >> 24);
|
|
|
|
type_str[1] = (char)(map[id * UnitNum + un]->GetID() >> 16);
|
|
|
|
type_str[2] = (char)(map[id * UnitNum + un]->GetID() >> 8);
|
|
|
|
type_str[3] = (char)(map[id * UnitNum + un]->GetID());
|
|
|
|
type_str[4] = '\0';
|
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Disconnect Command
|
2018-05-03 13:47:57 +00:00
|
|
|
if (cmd == 1) { // DETACH
|
2021-02-07 19:00:48 +00:00
|
|
|
type_str[0] = (char)(map[id * UnitNum + un]->GetID() >> 24);
|
|
|
|
type_str[1] = (char)(map[id * UnitNum + un]->GetID() >> 16);
|
|
|
|
type_str[2] = (char)(map[id * UnitNum + un]->GetID() >> 8);
|
|
|
|
type_str[3] = (char)(map[id * UnitNum + un]->GetID());
|
|
|
|
type_str[4] = '\0';
|
|
|
|
LOGINFO("rasctl command disconnect %s at ID: %d UN: %d", type_str, id, un);
|
2020-07-06 03:56:25 +00:00
|
|
|
// Free the existing unit
|
2020-07-04 14:57:44 +00:00
|
|
|
map[id * UnitNum + un] = NULL;
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Re-map the controller
|
2020-07-04 14:57:44 +00:00
|
|
|
MapControler(fp, map);
|
2018-05-03 13:47:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Valid only for MO or CD
|
2020-07-04 14:57:44 +00:00
|
|
|
if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O') &&
|
|
|
|
pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) {
|
2021-02-07 19:00:48 +00:00
|
|
|
FPRT(fp, "Error : Operation denied (Device type %s isn't removable)\n", type_str);
|
|
|
|
LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, type_str);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case 2: // INSERT
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the file path
|
2018-05-03 13:47:57 +00:00
|
|
|
filepath.SetPath(file);
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", file, type_str, id, un);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Open the file
|
2020-07-10 01:20:18 +00:00
|
|
|
if (!pUnit->Open(filepath)) {
|
2020-07-04 14:57:44 +00:00
|
|
|
FPRT(fp, "Error : File open error [%s]\n", file);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: // EJECT
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO("rasctl commands eject %s ID: %d UN: %d", type_str, id, un);
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit->Eject(TRUE);
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // PROTECT
|
2020-07-04 14:57:44 +00:00
|
|
|
if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) {
|
|
|
|
FPRT(fp, "Error : Operation denied(Deveice isn't MO)\n");
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGWARN("rasctl sent an invalid PROTECT command for %s ID: %d UN: %d", type_str, id, un);
|
2018-05-03 13:47:57 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), type_str, id, un);
|
2020-07-04 14:57:44 +00:00
|
|
|
pUnit->WriteP(!pUnit->IsWriteP());
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-02-07 19:00:48 +00:00
|
|
|
LOGWARN("Received unknown command from rasctl: %d", cmd);
|
2018-05-03 13:47:57 +00:00
|
|
|
ASSERT(FALSE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
bool has_suffix(const char* string, const char* suffix) {
|
|
|
|
int string_len = strlen(string);
|
|
|
|
int suffix_len = strlen(suffix);
|
|
|
|
return (string_len >= suffix_len)
|
|
|
|
&& (xstrcasecmp(string + (string_len - suffix_len), suffix) == 0);
|
|
|
|
}
|
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Argument Parsing
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef BAREMETAL
|
2020-08-09 01:30:17 +00:00
|
|
|
BOOL ParseConfig(int argc, char* argv[])
|
|
|
|
{
|
2020-07-04 14:57:44 +00:00
|
|
|
FRESULT fr;
|
|
|
|
FIL fp;
|
|
|
|
char line[512];
|
2018-05-03 13:47:57 +00:00
|
|
|
int id;
|
2020-07-04 14:57:44 +00:00
|
|
|
int un;
|
2018-05-03 13:47:57 +00:00
|
|
|
int type;
|
|
|
|
char *argID;
|
|
|
|
char *argPath;
|
|
|
|
int len;
|
|
|
|
char *ext;
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Mount the SD card
|
2020-07-04 14:57:44 +00:00
|
|
|
fr = f_mount(&fatfs, "", 1);
|
|
|
|
if (fr != FR_OK) {
|
|
|
|
FPRT(stderr, "Error : SD card mount failed.\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// If there is no setting file, the processing is interrupted
|
2020-07-04 14:57:44 +00:00
|
|
|
fr = f_open(&fp, "rascsi.ini", FA_READ);
|
|
|
|
if (fr != FR_OK) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Start Decoding
|
2020-07-04 14:57:44 +00:00
|
|
|
|
|
|
|
while (TRUE) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Get one Line
|
2020-07-04 14:57:44 +00:00
|
|
|
memset(line, 0x00, sizeof(line));
|
|
|
|
if (f_gets(line, sizeof(line) -1, &fp) == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Delete the CR/LF
|
2020-07-04 14:57:44 +00:00
|
|
|
len = strlen(line);
|
|
|
|
while (len > 0) {
|
|
|
|
if (line[len - 1] != '\r' && line[len - 1] != '\n') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
line[len - 1] = '\0';
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Get the ID and Path
|
2020-07-04 14:57:44 +00:00
|
|
|
argID = &line[0];
|
|
|
|
argPath = &line[4];
|
|
|
|
line[3] = '\0';
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Check if the line is an empty string
|
2020-07-04 14:57:44 +00:00
|
|
|
if (argID[0] == '\0' || argPath[0] == '\0') {
|
|
|
|
continue;
|
|
|
|
}
|
2020-08-09 01:30:17 +00:00
|
|
|
|
|
|
|
if (strlen(argID) == 3 && xstrncasecmp(argID, "id", 2) == 0) {
|
|
|
|
// ID or ID Format
|
|
|
|
|
|
|
|
// Check that the ID number is valid (0-7)
|
|
|
|
if (argID[2] < '0' || argID[2] > '7') {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(IDn n=0-7) [%c]\n", argID[2]);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The ID unit is good
|
|
|
|
id = argID[2] - '0';
|
|
|
|
un = 0;
|
|
|
|
} else if (xstrncasecmp(argID, "hd", 2) == 0) {
|
|
|
|
// HD or HD format
|
|
|
|
|
|
|
|
if (strlen(argID) == 3) {
|
|
|
|
// Check that the HD number is valid (0-9)
|
|
|
|
if (argID[2] < '0' || argID[2] > '9') {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(HDn n=0-15) [%c]\n", argID[2]);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ID was confirmed
|
|
|
|
id = (argID[2] - '0') / UnitNum;
|
|
|
|
un = (argID[2] - '0') % UnitNum;
|
|
|
|
} else if (strlen(argID) == 4) {
|
|
|
|
// Check that the HD number is valid (10-15)
|
|
|
|
if (argID[2] != '1' || argID[3] < '0' || argID[3] > '5') {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(HDn n=0-15) [%c]\n", argID[2]);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The ID unit is good - create the id and unit number
|
|
|
|
id = ((argID[3] - '0') + 10) / UnitNum;
|
|
|
|
un = ((argID[3] - '0') + 10) % UnitNum;
|
|
|
|
argPath++;
|
|
|
|
} else {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(IDn or HDn) [%s]\n", argID);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(IDn or HDn) [%s]\n", argID);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip if there is already an active device
|
|
|
|
if (disk[id * UnitNum + un] &&
|
|
|
|
!disk[id * UnitNum + un]->IsNULL()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize device type
|
|
|
|
type = -1;
|
|
|
|
|
|
|
|
// Check ethernet and host bridge
|
|
|
|
if (xstrcasecmp(argPath, "bridge") == 0) {
|
|
|
|
type = 4;
|
|
|
|
} else {
|
|
|
|
// Check the path length
|
|
|
|
len = strlen(argPath);
|
|
|
|
if (len < 5) {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(File path is short) [%s]\n",
|
|
|
|
argPath);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does the file have an extension?
|
|
|
|
if (argPath[len - 4] != '.') {
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(No extension) [%s]\n", argPath);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Figure out what the type is
|
|
|
|
ext = &argPath[len - 3];
|
|
|
|
if (xstrcasecmp(ext, "hdf") == 0 ||
|
|
|
|
xstrcasecmp(ext, "hds") == 0 ||
|
|
|
|
xstrcasecmp(ext, "hdn") == 0 ||
|
|
|
|
xstrcasecmp(ext, "hdi") == 0 || xstrcasecmp(ext, "nhd") == 0 ||
|
|
|
|
xstrcasecmp(ext, "hda") == 0) {
|
|
|
|
// HD(SASI/SCSI)
|
|
|
|
type = 0;
|
|
|
|
} else if (strcasecmp(ext, "mos") == 0) {
|
|
|
|
// MO
|
|
|
|
type = 2;
|
|
|
|
} else if (strcasecmp(ext, "iso") == 0) {
|
|
|
|
// CD
|
|
|
|
type = 3;
|
|
|
|
} else {
|
|
|
|
// Cannot determine the file type
|
|
|
|
FPRT(stderr,
|
|
|
|
"Error : Invalid argument(file type) [%s]\n", ext);
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute the command
|
|
|
|
if (!ProcessCmd(stderr, id, un, 0, type, argPath)) {
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the configuration file
|
|
|
|
f_close(&fp);
|
|
|
|
|
|
|
|
// Display the device list
|
|
|
|
ListDevice(stdout);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
parse_error:
|
|
|
|
|
|
|
|
// Close the configuration file
|
|
|
|
f_close(&fp);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
#else
|
2020-08-09 06:52:58 +00:00
|
|
|
bool ParseArgument(int argc, char* argv[])
|
2020-08-09 01:30:17 +00:00
|
|
|
{
|
2020-08-09 06:52:58 +00:00
|
|
|
int id = -1;
|
|
|
|
bool is_sasi = false;
|
|
|
|
int max_id = 7;
|
|
|
|
|
|
|
|
int opt;
|
|
|
|
while ((opt = getopt(argc, argv, "-IiHhD:d:")) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'I':
|
|
|
|
case 'i':
|
|
|
|
is_sasi = false;
|
|
|
|
max_id = 7;
|
|
|
|
id = -1;
|
|
|
|
continue;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
case 'H':
|
|
|
|
case 'h':
|
|
|
|
is_sasi = true;
|
|
|
|
max_id = 15;
|
|
|
|
id = -1;
|
|
|
|
continue;
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
case 'D':
|
|
|
|
case 'd': {
|
|
|
|
char* end;
|
|
|
|
id = strtol(optarg, &end, 10);
|
|
|
|
if (*end || (id < 0) || (max_id < id)) {
|
|
|
|
fprintf(stderr, "%s: invalid %s (0-%d)\n",
|
|
|
|
optarg, is_sasi ? "HD" : "ID", max_id);
|
|
|
|
return false;
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
2020-08-09 06:52:58 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
default:
|
|
|
|
return false;
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
case 1:
|
|
|
|
break;
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
if (id < 0) {
|
|
|
|
fprintf(stderr, "%s: ID not specified\n", optarg);
|
|
|
|
return false;
|
|
|
|
} else if (disk[id] && !disk[id]->IsNULL()) {
|
|
|
|
fprintf(stderr, "%d: duplicate ID\n", id);
|
|
|
|
return false;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
char* path = optarg;
|
|
|
|
int type = -1;
|
|
|
|
if (has_suffix(path, ".hdf")
|
|
|
|
|| has_suffix(path, ".hds")
|
|
|
|
|| has_suffix(path, ".hdn")
|
|
|
|
|| has_suffix(path, ".hdi")
|
|
|
|
|| has_suffix(path, ".hda")
|
|
|
|
|| has_suffix(path, ".nhd")) {
|
2021-02-07 22:46:59 +00:00
|
|
|
type = rasctl_dev_sasi_hd;
|
2020-08-09 06:52:58 +00:00
|
|
|
} else if (has_suffix(path, ".mos")) {
|
2021-02-07 22:46:59 +00:00
|
|
|
type = rasctl_dev_mo;
|
2020-08-09 06:52:58 +00:00
|
|
|
} else if (has_suffix(path, ".iso")) {
|
2021-02-07 22:46:59 +00:00
|
|
|
type = rasctl_dev_cd;
|
2020-08-09 06:52:58 +00:00
|
|
|
} else if (xstrcasecmp(path, "bridge") == 0) {
|
2021-02-07 22:46:59 +00:00
|
|
|
type = rasctl_dev_br;
|
|
|
|
} else if (xstrcasecmp(path, "daynaport") == 0) {
|
|
|
|
type = rasctl_dev_daynaport;
|
2018-05-03 13:47:57 +00:00
|
|
|
} else {
|
2020-08-09 06:52:58 +00:00
|
|
|
// Cannot determine the file type
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: unknown file extension\n", path);
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-08-09 06:52:58 +00:00
|
|
|
int un = 0;
|
|
|
|
if (is_sasi) {
|
|
|
|
un = id % UnitNum;
|
|
|
|
id /= UnitNum;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Execute the command
|
2020-08-09 06:52:58 +00:00
|
|
|
if (!ProcessCmd(stderr, id, un, 0, type, path)) {
|
|
|
|
return false;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
2020-08-09 06:52:58 +00:00
|
|
|
id = -1;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Display the device list
|
2018-05-03 13:47:57 +00:00
|
|
|
ListDevice(stdout);
|
2020-08-09 06:52:58 +00:00
|
|
|
return true;
|
2020-07-04 14:57:44 +00:00
|
|
|
}
|
2020-08-09 01:30:17 +00:00
|
|
|
#endif // BAREMETAL
|
2020-07-04 14:57:44 +00:00
|
|
|
|
|
|
|
#ifndef BAREMETAL
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Pin the thread to a specific CPU
|
2020-07-04 14:57:44 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void FixCpu(int cpu)
|
|
|
|
{
|
|
|
|
cpu_set_t cpuset;
|
|
|
|
int cpus;
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Get the number of CPUs
|
2020-07-04 14:57:44 +00:00
|
|
|
CPU_ZERO(&cpuset);
|
|
|
|
sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
|
|
|
|
cpus = CPU_COUNT(&cpuset);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the thread affinity
|
2020-07-04 14:57:44 +00:00
|
|
|
if (cpu < cpus) {
|
|
|
|
CPU_ZERO(&cpuset);
|
|
|
|
CPU_SET(cpu, &cpuset);
|
|
|
|
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Monitor Thread
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void *MonThread(void *param)
|
|
|
|
{
|
2020-07-04 14:57:44 +00:00
|
|
|
struct sched_param schedparam;
|
2018-05-03 13:47:57 +00:00
|
|
|
struct sockaddr_in client;
|
2020-07-10 01:20:18 +00:00
|
|
|
socklen_t len;
|
2018-05-03 13:47:57 +00:00
|
|
|
int fd;
|
|
|
|
FILE *fp;
|
2020-07-04 14:57:44 +00:00
|
|
|
char buf[BUFSIZ];
|
|
|
|
char *p;
|
|
|
|
int i;
|
|
|
|
char *argv[5];
|
2018-05-03 13:47:57 +00:00
|
|
|
int id;
|
2020-07-04 14:57:44 +00:00
|
|
|
int un;
|
2018-05-03 13:47:57 +00:00
|
|
|
int cmd;
|
|
|
|
int type;
|
|
|
|
char *file;
|
2020-07-04 14:57:44 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Scheduler Settings
|
2020-07-04 14:57:44 +00:00
|
|
|
schedparam.sched_priority = 0;
|
|
|
|
sched_setscheduler(0, SCHED_IDLE, &schedparam);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the affinity to a specific processor core
|
2020-07-04 14:57:44 +00:00
|
|
|
FixCpu(2);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Wait for the execution to start
|
2020-07-04 14:57:44 +00:00
|
|
|
while (!running) {
|
|
|
|
usleep(1);
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Setup the monitor socket to receive commands
|
2020-07-04 14:57:44 +00:00
|
|
|
listen(monsocket, 1);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
while (1) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Wait for connection
|
2020-07-10 01:20:18 +00:00
|
|
|
memset(&client, 0, sizeof(client));
|
|
|
|
len = sizeof(client);
|
2020-07-04 14:57:44 +00:00
|
|
|
fd = accept(monsocket, (struct sockaddr*)&client, &len);
|
2018-05-03 13:47:57 +00:00
|
|
|
if (fd < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Fetch the command
|
2018-05-03 13:47:57 +00:00
|
|
|
fp = fdopen(fd, "r+");
|
2020-07-04 14:57:44 +00:00
|
|
|
p = fgets(buf, BUFSIZ, fp);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Failed to get the command
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!p) {
|
|
|
|
goto next;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Remove the newline character
|
2020-07-04 14:57:44 +00:00
|
|
|
p[strlen(p) - 1] = 0;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// List all of the devices
|
2020-07-04 14:57:44 +00:00
|
|
|
if (xstrncasecmp(p, "list", 4) == 0) {
|
2018-05-03 13:47:57 +00:00
|
|
|
ListDevice(fp);
|
2020-07-04 14:57:44 +00:00
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Parameter separation
|
2020-07-04 14:57:44 +00:00
|
|
|
argv[0] = p;
|
|
|
|
for (i = 1; i < 5; i++) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Skip parameter values
|
2020-07-04 14:57:44 +00:00
|
|
|
while (*p && (*p != ' ')) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Replace spaces with null characters
|
2020-07-04 14:57:44 +00:00
|
|
|
while (*p && (*p == ' ')) {
|
|
|
|
*p++ = 0;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// The parameters were lost
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!*p) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Recognized as a parameter
|
2020-07-04 14:57:44 +00:00
|
|
|
argv[i] = p;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Failed to get all parameters
|
2020-07-04 14:57:44 +00:00
|
|
|
if (i < 5) {
|
|
|
|
goto next;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// ID, unit, command, type, file
|
2020-07-04 14:57:44 +00:00
|
|
|
id = atoi(argv[0]);
|
|
|
|
un = atoi(argv[1]);
|
|
|
|
cmd = atoi(argv[2]);
|
|
|
|
type = atoi(argv[3]);
|
|
|
|
file = argv[4];
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Wait until we becom idle
|
2020-07-04 14:57:44 +00:00
|
|
|
while (active) {
|
|
|
|
usleep(500 * 1000);
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Execute the command
|
2020-07-04 14:57:44 +00:00
|
|
|
ProcessCmd(fp, id, un, cmd, type, file);
|
|
|
|
|
|
|
|
next:
|
2020-07-06 03:56:25 +00:00
|
|
|
// Release the connection
|
2018-05-03 13:47:57 +00:00
|
|
|
fclose(fp);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-06 03:56:25 +00:00
|
|
|
// Main processing
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef BAREMETAL
|
|
|
|
extern "C"
|
|
|
|
int startrascsi(void)
|
|
|
|
{
|
|
|
|
int argc = 0;
|
|
|
|
char** argv = NULL;
|
|
|
|
#else
|
2018-05-03 13:47:57 +00:00
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
int i;
|
2020-07-04 14:57:44 +00:00
|
|
|
int ret;
|
|
|
|
int actid;
|
|
|
|
DWORD now;
|
|
|
|
BUS::phase_t phase;
|
|
|
|
BYTE data;
|
2021-05-30 06:50:00 +00:00
|
|
|
// added setvbuf to override stdout buffering, so logs are written immediately and not when the process exits.
|
2021-05-30 06:46:08 +00:00
|
|
|
setvbuf(stdout, NULL, _IONBF, 0);
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifndef BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
struct sched_param schparam;
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-10-19 12:31:06 +00:00
|
|
|
spdlog::set_level(spdlog::level::trace);
|
2021-02-07 19:00:48 +00:00
|
|
|
// Create a thread-safe stdout logger to process the log messages
|
|
|
|
auto logger = spdlog::stdout_color_mt("rascsi stdout logger");
|
|
|
|
|
2020-10-19 12:31:06 +00:00
|
|
|
LOGTRACE("Entering the function %s with %d arguments", __PRETTY_FUNCTION__, argc);
|
2020-07-06 03:56:25 +00:00
|
|
|
// Output the Banner
|
2020-07-04 14:57:44 +00:00
|
|
|
Banner(argc, argv);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Initialize
|
2020-07-04 14:57:44 +00:00
|
|
|
ret = 0;
|
2018-05-03 13:47:57 +00:00
|
|
|
if (!Init()) {
|
2020-07-04 14:57:44 +00:00
|
|
|
ret = EPERM;
|
|
|
|
goto init_exit;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Reset
|
2020-07-04 14:57:44 +00:00
|
|
|
Reset();
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef BAREMETAL
|
2020-07-06 03:56:25 +00:00
|
|
|
// BUSY assert (to hold the host side)
|
2020-07-04 14:57:44 +00:00
|
|
|
bus->SetBSY(TRUE);
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-08-09 01:30:17 +00:00
|
|
|
// Argument parsing
|
|
|
|
if (!ParseConfig(argc, argv)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto err_exit;
|
|
|
|
}
|
|
|
|
#else
|
2020-07-06 03:56:25 +00:00
|
|
|
// Argument parsing
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!ParseArgument(argc, argv)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto err_exit;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
2020-08-09 01:30:17 +00:00
|
|
|
#endif
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef BAREMETAL
|
2020-07-06 03:56:25 +00:00
|
|
|
// Release the busy signal
|
2020-07-04 14:57:44 +00:00
|
|
|
bus->SetBSY(FALSE);
|
|
|
|
#endif
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifndef BAREMETAL
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the affinity to a specific processor core
|
2020-07-04 14:57:44 +00:00
|
|
|
FixCpu(3);
|
|
|
|
|
|
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
2020-07-06 03:56:25 +00:00
|
|
|
// Scheduling policy setting (highest priority)
|
2020-07-04 14:57:44 +00:00
|
|
|
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
|
|
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
|
|
|
#endif // USE_SEL_EVENT_ENABLE
|
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Start execution
|
2020-07-04 14:57:44 +00:00
|
|
|
running = TRUE;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Main Loop
|
2020-07-04 14:57:44 +00:00
|
|
|
while (running) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Work initialization
|
2020-07-04 14:57:44 +00:00
|
|
|
actid = -1;
|
|
|
|
phase = BUS::busfree;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
2020-07-06 03:56:25 +00:00
|
|
|
// SEL signal polling
|
2020-07-04 14:57:44 +00:00
|
|
|
if (bus->PollSelectEvent() < 0) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Stop on interrupt
|
2020-07-04 14:57:44 +00:00
|
|
|
if (errno == EINTR) {
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Get the bus
|
2020-07-04 14:57:44 +00:00
|
|
|
bus->Aquire();
|
|
|
|
#else
|
|
|
|
bus->Aquire();
|
|
|
|
if (!bus->GetSEL()) {
|
|
|
|
#if !defined(BAREMETAL)
|
|
|
|
usleep(0);
|
|
|
|
#endif // !BAREMETAL
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif // USE_SEL_EVENT_ENABLE
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// 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)
|
2020-07-04 14:57:44 +00:00
|
|
|
if (bus->GetBSY()) {
|
|
|
|
now = SysTimer::GetTimerLow();
|
|
|
|
while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) {
|
|
|
|
bus->Aquire();
|
|
|
|
if (!bus->GetBSY()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Stop because it the bus is busy or another device responded
|
2020-07-04 14:57:44 +00:00
|
|
|
if (bus->GetBSY() || !bus->GetSEL()) {
|
2018-05-03 13:47:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-07 19:00:48 +00:00
|
|
|
pthread_mutex_lock(&ctrl_mutex);
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Notify all controllers
|
2020-07-04 14:57:44 +00:00
|
|
|
data = bus->GetDAT();
|
2018-05-03 13:47:57 +00:00
|
|
|
for (i = 0; i < CtrlMax; i++) {
|
2020-07-04 14:57:44 +00:00
|
|
|
if (!ctrl[i] || (data & (1 << i)) == 0) {
|
2018-05-03 13:47:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Find the target that has moved to the selection phase
|
2018-05-03 13:47:57 +00:00
|
|
|
if (ctrl[i]->Process() == BUS::selection) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Get the target ID
|
2018-05-03 13:47:57 +00:00
|
|
|
actid = i;
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Bus Selection phase
|
2018-05-03 13:47:57 +00:00
|
|
|
phase = BUS::selection;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Return to bus monitoring if the selection phase has not started
|
2018-05-03 13:47:57 +00:00
|
|
|
if (phase != BUS::selection) {
|
2021-02-07 19:00:48 +00:00
|
|
|
pthread_mutex_unlock(&ctrl_mutex);
|
2018-05-03 13:47:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Start target device
|
2020-07-04 14:57:44 +00:00
|
|
|
active = TRUE;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
2020-07-06 03:56:25 +00:00
|
|
|
// Scheduling policy setting (highest priority)
|
2018-05-03 13:47:57 +00:00
|
|
|
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
|
|
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// Loop until the bus is free
|
2020-07-04 14:57:44 +00:00
|
|
|
while (running) {
|
2020-07-06 03:56:25 +00:00
|
|
|
// Target drive
|
2018-05-03 13:47:57 +00:00
|
|
|
phase = ctrl[actid]->Process();
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// End when the bus is free
|
2018-05-03 13:47:57 +00:00
|
|
|
if (phase == BUS::busfree) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-02-07 19:00:48 +00:00
|
|
|
pthread_mutex_unlock(&ctrl_mutex);
|
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL)
|
2020-07-06 03:56:25 +00:00
|
|
|
// Set the scheduling priority back to normal
|
2018-05-03 13:47:57 +00:00
|
|
|
schparam.sched_priority = 0;
|
|
|
|
sched_setscheduler(0, SCHED_OTHER, &schparam);
|
2020-07-04 14:57:44 +00:00
|
|
|
#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL
|
|
|
|
|
2020-07-06 03:56:25 +00:00
|
|
|
// End the target travel
|
2020-07-04 14:57:44 +00:00
|
|
|
active = FALSE;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
err_exit:
|
2020-07-06 03:56:25 +00:00
|
|
|
// Cleanup
|
2018-05-03 13:47:57 +00:00
|
|
|
Cleanup();
|
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
init_exit:
|
|
|
|
#if !defined(BAREMETAL)
|
|
|
|
exit(ret);
|
|
|
|
#else
|
|
|
|
return ret;
|
|
|
|
#endif // BAREMETAL
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|