Re-organize and tidy up

No functional changes

* Move + Rename scsi command emulation out of idetask to scsi.c
* Move ATAPI SCSI command handling out of idetask to atapi.c
* Rename idetask to iotask
This commit is contained in:
Matt Harlum 2025-08-03 09:37:29 +00:00
parent 89e3b82f6c
commit eb8364fdbb
11 changed files with 281 additions and 254 deletions

View File

@ -16,7 +16,7 @@
"alib.h": "c",
"timer.h": "c",
"stdbool.h": "c",
"idetask.h": "c",
"iotask.h": "c",
"td64.h": "c",
"string.h": "c",
"scsidisk.h": "c",

View File

@ -69,7 +69,7 @@ OBJ = device.o \
ata.o \
atapi.o \
scsi.o \
idetask.o \
iotask.o \
lide_alib.o \
mounter/mounter.o \
debug.o

66
atapi.c
View File

@ -555,7 +555,7 @@ end:
Trace("Auto sense requested\n");
if (ret == IOERR_UNITBUSY) {
// This was a timeout, fake the autosense data
scsi_sense(cmd,0,0,ret);
fake_scsi_sense(cmd,0,0,ret);
} else {
atapi_autosense(cmd,unit);
}
@ -1365,4 +1365,68 @@ BYTE atapi_autosense(struct SCSICmd *scsi_command, struct IDEUnit *unit) {
} else {
return TDERR_NoMem;
}
}
/**
* atapi_handle_scsi_command
*
* Handles SCSI commands for ATAPI devices by translating unsupported commands
* and applying compatibility fixes for specific device types.
*
* @param unit Pointer to an IDEUnit struct representing the ATAPI device
* @param scsi_command Pointer to a SCSICmd struct containing the command to execute
* @return BYTE Error code (0 for success, non-zero for error)
*/
BYTE atapi_handle_scsi_command(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
BYTE error = 0;
switch (scsi_command->scsi_Command[0]) {
case SCSI_CMD_INQUIRY:
// Fudge the SCSI version number for CD/DVDs
// Some software expects version 2 but ATAPI returns version 0
error = atapi_packet(scsi_command,unit);
if (error == 0 && unit->deviceType == DG_CDROM) {
if ((scsi_command->scsi_Command[1] & 1) == 0) {
((struct SCSI_Inquiry *)scsi_command->scsi_Data)->version = 2;
}
}
break;
case SCSI_CMD_READ_6:
case SCSI_CMD_WRITE_6:
// ATAPI devices don't support READ/WRITE(6) so translate it
error = atapi_scsi_read_write_6(scsi_command,unit);
break;
case SCSI_CMD_MODE_SENSE_6:
error = atapi_scsi_mode_sense_6(scsi_command,unit);
break;
case SCSI_CMD_MODE_SELECT_6:
error = atapi_scsi_mode_select_6(scsi_command,unit);
break;
case SCSI_CMD_PLAY_TRACK_INDEX:
error = atapi_translate_play_audio_index(scsi_command,unit);
break;
case SCSI_CMD_READ_CAPACITY_10:
// CDROMs don't support parameters for READ_CAPACITY_10 so clear them all
for (int i=1; i < scsi_command->scsi_CmdLength; i++) {
scsi_command->scsi_Command[i] = 0;
}
default:
if (!((ULONG)scsi_command->scsi_Data & 0x01)) { // Buffer is word-aligned?
error = atapi_packet(scsi_command,unit);
} else {
error = atapi_packet_unaligned(scsi_command,unit);
}
break;
}
return error;
}

View File

@ -62,4 +62,5 @@ BYTE atapi_play_track_index(struct IDEUnit *unit, UBYTE start, UBYTE end);
BYTE atapi_play_audio_msf(struct IDEUnit *unit, struct SCSI_TRACK_MSF *start, struct SCSI_TRACK_MSF *end);
BYTE atapi_translate_play_audio_index(struct SCSICmd *cmd, struct IDEUnit *unit);
BYTE atapi_autosense(struct SCSICmd *scsi_command, struct IDEUnit *unit);
BYTE atapi_handle_scsi_command(struct IDEUnit *unit, struct SCSICmd *scsi_command);
#endif

View File

@ -19,7 +19,7 @@
#include "ata.h"
#include "atapi.h"
#include "device.h"
#include "idetask.h"
#include "iotask.h"
#include "newstyle.h"
#include "td64.h"
#include "debug.h"
@ -62,6 +62,7 @@ static const struct Resident romTag = {
const char device_name[] = DEVICE_NAME;
const char device_id_string[] = DEVICE_ID_STRING;
/**
* set_dev_name
*
@ -197,6 +198,15 @@ static BOOL FindCDFS() {
}
#endif
/**
* ioreq_is_valid
*
* Check if the supplied IOReq points to a valid unit
*
* @param dev Pointer to DeviceBase
* @param ior The ioreq to test
* @returns bool
*/
static bool ioreq_is_valid(struct DeviceBase *dev, struct IORequest *ior) {
struct ExecBase *SysBase = dev->SysBase;
bool found = false;
@ -239,14 +249,14 @@ static void Cleanup(struct DeviceBase *dev) {
if (dev->ExpansionBase) CloseLibrary((struct Library *)dev->ExpansionBase);
struct IDETask *itask;
struct IOTask *itask;
for (itask = (struct IDETask *)dev->ideTasks.mlh_Head;
for (itask = (struct IOTask *)dev->ideTasks.mlh_Head;
itask->mn_Node.mln_Succ != NULL;
itask = (struct IDETask *)itask->mn_Node.mln_Succ)
itask = (struct IOTask *)itask->mn_Node.mln_Succ)
{
itask->cd->cd_Flags |= CDF_CONFIGME;
FreeMem(itask,sizeof(struct IDETask));
FreeMem(itask,sizeof(struct IOTask));
}
// if devName doesn't point to the const device_name then we need to free up that memory
@ -360,7 +370,7 @@ struct Library * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list a
dev->ExpansionBase = ExpansionBase;
}
struct IDETask *itask;
struct IOTask *itask;
struct ConfigDev *cd;
struct Task *self = FindTask(NULL);
@ -375,7 +385,7 @@ struct Library * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list a
cd = cb.cb_ConfigDev;
// Add an IDE Task for each board
// Add an IO Task for each channel of each board
// When loaded from Autoconfig ROM this will still only attach to one board.
// If the driver is loaded by BindDrivers though then this should attach to multiple boards.
for (cd = cb.cb_ConfigDev; cd != NULL; cd = cd->cd_NextCD) {
@ -408,9 +418,9 @@ struct Library * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list a
for (int c=0; c < channels; c++) {
Info("Starting IDE Task %ld\n",dev->numTasks);
Info("Starting IO Task %ld\n",dev->numTasks);
itask = AllocMem(sizeof(struct IDETask), MEMF_ANY|MEMF_CLEAR);
itask = AllocMem(sizeof(struct IOTask), MEMF_ANY|MEMF_CLEAR);
if (itask == NULL) {
Info("Couldn't allocate memory\n");
@ -428,14 +438,14 @@ struct Library * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list a
SetSignal(0,SIGF_SINGLE);
// Start the IDE Task
itask->task = L_CreateTask(ATA_TASK_NAME,TASK_PRIORITY,ide_task,TASK_STACK_SIZE,itask);
// Start the IO Task
itask->task = L_CreateTask(ATA_TASK_NAME,TASK_PRIORITY,io_task,TASK_STACK_SIZE,itask);
if (itask->task == NULL) {
Info("IDE Task %ld failed\n",itask->taskNum);
FreeMem(itask,sizeof(struct IDETask));
Info("IO Task %ld failed\n",itask->taskNum);
FreeMem(itask,sizeof(struct IOTask));
continue;
} else {
Trace("IDE Task %ld created!, waiting for init\n",itask->taskNum);
Trace("IO Task %ld created!, waiting for init\n",itask->taskNum);
}
// Wait for task to init
@ -443,8 +453,8 @@ struct Library * init_device(struct ExecBase *SysBase asm("a6"), BPTR seg_list a
// If itask->active has been set to false it means the task exited
if (itask->active == false) {
Info("IDE Task %ld exited.\n",itask->taskNum);
FreeMem(itask,sizeof(struct IDETask));
Info("IO Task %ld exited.\n",itask->taskNum);
FreeMem(itask,sizeof(struct IOTask));
continue;
}
@ -704,7 +714,7 @@ static void begin_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq as
if (unit->itask == NULL || unit->itask->active == false) {
// If the IDE task is dead then we can only throw an error and reply now.
// If the IO task is dead then we can only throw an error and reply now.
ioreq->io_Error = IOERR_OPENFAIL;
if (!(ioreq->io_Flags & IOF_QUICK)) {
@ -1003,7 +1013,7 @@ static struct Library * init(BPTR seg_list asm("a0"))
Info("Add Device.\n");
AddDevice((struct Device *)mydev);
struct IDETask *itask = (struct IDETask *)mydev->ideTasks.mlh_Head;
struct IOTask *itask = (struct IOTask *)mydev->ideTasks.mlh_Head;
if (!itask->mn_Node.mln_Succ) goto done;

View File

@ -45,7 +45,7 @@ struct Drive {
struct IDEUnit {
struct MinNode mn_Node;
struct ExecBase *SysBase;
struct IDETask *itask;
struct IOTask *itask;
struct Drive drive;
BYTE (*write_taskfile)(struct IDEUnit *, UBYTE, ULONG, UBYTE, UBYTE);
enum xfer xferMethod;
@ -94,7 +94,7 @@ struct DeviceBase {
struct MinList ideTasks;
};
struct IDETask {
struct IOTask {
struct MinNode mn_Node;
struct Task *task;
struct Task *parent;

View File

@ -13,7 +13,7 @@
#include "atapi.h"
#include "debug.h"
#include "device.h"
#include "idetask.h"
#include "iotask.h"
#include "newstyle.h"
#include "scsi.h"
#include "td64.h"
@ -23,7 +23,7 @@
/**
* create_timer
*
* Create and initialize the timer for the IDE task
* Create and initialize the timer for the IO task
*
* @param SysBase Pointer to the ExecBase
* @param mp Pointer to the MsgPort
@ -98,152 +98,6 @@ static void delete_timer(struct ExecBase *SysBase, struct MsgPort *mp, struct ti
}
}
/**
* scsi_inquiry_ata
*
* Handle SCSI-Direct INQUIRY commands for ATA devices
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
static BYTE scsi_inquiry_ata(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
struct ExecBase *SysBase = unit->SysBase;
struct SCSI_Inquiry *data = (struct SCSI_Inquiry *)scsi_command->scsi_Data;
BYTE error;
data->peripheral_type = unit->deviceType;
data->removable_media = 0;
data->version = 2;
data->response_format = 2;
data->additional_length = (sizeof(struct SCSI_Inquiry) - 4);
UWORD *identity = AllocMem(512,MEMF_CLEAR|MEMF_ANY);
if (!identity) {
error = TDERR_NoMem;
scsi_sense(scsi_command,0,0,error);
return error;
}
if (!(ata_identify(unit,identity))) {
error = HFERR_SelTimeout;
scsi_sense(scsi_command,0,0,error);
FreeMem(identity,512);
return error;
}
CopyMem(&identity[ata_identify_model],&data->vendor,24);
CopyMem(&identity[ata_identify_fw_rev],&data->revision,4);
CopyMem(&identity[ata_identify_serial],&data->serial,8);
FreeMem(identity,512);
scsi_command->scsi_Actual = scsi_command->scsi_Length;
return 0;
}
/**
* scsi_read_capacity_ata
*
* Handle SCSI-Direct READ CAPACITY commands for ATA devices
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
static BYTE scsi_read_capacity_ata(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
struct SCSI_CAPACITY_10 *data = (struct SCSI_CAPACITY_10 *)scsi_command->scsi_Data;
BYTE error;
if (data == NULL) {
error = IOERR_BADADDRESS;
scsi_sense(scsi_command,0,0,error);
return error;
}
struct SCSI_READ_CAPACITY_10 *cdb = (struct SCSI_READ_CAPACITY_10 *)scsi_command->scsi_Command;
data->block_size = unit->blockSize;
if (cdb->flags & 0x01) {
// Partial Medium Indicator - Return end of cylinder
// Implement this so HDToolbox stops moaning about track size
ULONG spc = unit->sectorsPerTrack * unit->heads;
data->lba = (((cdb->lba / spc) + 1) * spc) - 1;
} else {
data->lba = (unit->logicalSectors) - 1;
}
scsi_command->scsi_Actual = 8;
return 0;
}
/**
* scsi_mode_sense_ata
*
* Handle SCSI-Direct MODE SENSE (6) commands for ATA devices
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
static BYTE scsi_mode_sense_ata(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
BYTE error;
UBYTE *data = (APTR)scsi_command->scsi_Data;
UBYTE *command = (APTR)scsi_command->scsi_Command;
if (data == NULL) {
return IOERR_BADADDRESS;
}
UBYTE page = command[2] & 0x3F;
UBYTE subpage = command[3];
if (subpage != 0 || (page != 0x3F && page != 0x03 && page != 0x04)) {
error = HFERR_BadStatus;
scsi_sense(scsi_command,0,0,error);
return error;
}
UBYTE *data_length = data; // Mode data length
data[1] = unit->deviceType; // Mode parameter: Media type
data[2] = 0; // DPOFUA
data[3] = 0; // Block descriptor length
*data_length = 3;
UBYTE idx = 4;
if (page == 0x3F || page == 0x03) {
data[idx++] = 0x03; // Page Code: Format Parameters
data[idx++] = 0x16; // Page length
for (int i=0; i <8; i++) {
data[idx++] = 0;
}
data[idx++] = (unit->sectorsPerTrack >> 8);
data[idx++] = unit->sectorsPerTrack;
data[idx++] = (unit->blockSize >> 8);
data[idx++] = unit->blockSize;
for (int i=0; i<10; i++) {
data[idx++] = 0;
}
}
if (page == 0x3F || page == 0x04) {
data[idx++] = 0x04; // Page code: Rigid Drive Geometry Parameters
data[idx++] = 0x16; // Page length
data[idx++] = (unit->cylinders >> 16);
data[idx++] = (unit->cylinders >> 8);
data[idx++] = unit->cylinders;
data[idx++] = unit->heads;
for (int i=0; i<18; i++) {
data[idx++] = 0;
}
}
*data_length = idx - 1;
scsi_command->scsi_Actual = idx;
return 0;
}
/**
* handle_scsi_command
*
@ -267,9 +121,10 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
Trace("SCSI: Command %lx\n",*scsi_command->scsi_Command);
if (unit->flags.atapi == false)
{
// Non-ATAPI drives - Translate SCSI CMD to ATA
if (unit->flags.atapi) {
error = atapi_handle_scsi_command(unit,scsi_command);
} else {
// Translate SCSI CMD to ATA
switch (scsi_command->scsi_Command[0]) {
case SCSI_CMD_ATA_PASSTHROUGH:
error = scsi_ata_passthrough(unit,scsi_command);
@ -281,15 +136,15 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
break;
case SCSI_CMD_INQUIRY:
error = scsi_inquiry_ata(unit,scsi_command);
error = scsi_inquiry_emu(unit,scsi_command);
break;
case SCSI_CMD_MODE_SENSE_6:
error = scsi_mode_sense_ata(unit,scsi_command);
error = scsi_mode_sense_emu(unit,scsi_command);
break;
case SCSI_CMD_READ_CAPACITY_10:
error = scsi_read_capacity_ata(unit,scsi_command);
error = scsi_read_capacity_emu(unit,scsi_command);
break;
case SCSI_CMD_READ_6:
@ -309,7 +164,7 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
do_scsi_transfer:
if (data == NULL || (lba + count) >= unit->logicalSectors) {
error = IOERR_BADADDRESS;
scsi_sense(scsi_command,lba,count,error);
fake_scsi_sense(scsi_command,lba,count,error);
break;
}
@ -324,71 +179,20 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
scsi_command->scsi_Actual = scsi_command->scsi_Length;
} else {
if (error == TDERR_NotSpecified) {
scsi_sense(scsi_command,lba,
fake_scsi_sense(scsi_command,lba,
(unit->last_error[0] << 8 | unit->last_error[4])
,error);
} else {
scsi_sense(scsi_command,lba,count,error);
fake_scsi_sense(scsi_command,lba,count,error);
}
}
break;
default:
error = IOERR_NOCMD;
scsi_sense(scsi_command,0,0,error);
fake_scsi_sense(scsi_command,0,0,error);
break;
}
} else {
// SCSI command handling for ATAPI Drives
switch (scsi_command->scsi_Command[0]) {
case SCSI_CMD_INQUIRY:
// Fudge the SCSI version number for CD/DVDs
// Some software expects version 2 but ATAPI returns version 0
error = atapi_packet(scsi_command,unit);
if (error == 0 && unit->deviceType == DG_CDROM) {
if ((scsi_command->scsi_Command[1] & 1) == 0) {
((struct SCSI_Inquiry *)scsi_command->scsi_Data)->version = 2;
}
}
break;
case SCSI_CMD_READ_6:
case SCSI_CMD_WRITE_6:
// ATAPI devices don't support READ/WRITE(6) so translate it
error = atapi_scsi_read_write_6(scsi_command,unit);
break;
case SCSI_CMD_MODE_SENSE_6:
error = atapi_scsi_mode_sense_6(scsi_command,unit);
break;
case SCSI_CMD_MODE_SELECT_6:
error = atapi_scsi_mode_select_6(scsi_command,unit);
break;
case SCSI_CMD_PLAY_TRACK_INDEX:
error = atapi_translate_play_audio_index(scsi_command,unit);
break;
case SCSI_CMD_READ_CAPACITY_10:
// CDROMs don't support parameters for READ_CAPACITY_10 so clear them all
for (int i=1; i < scsi_command->scsi_CmdLength; i++) {
scsi_command->scsi_Command[i] = 0;
}
default:
if (!((ULONG)scsi_command->scsi_Data & 0x01)) { // Buffer is word-aligned?
error = atapi_packet(scsi_command,unit);
} else {
error = atapi_packet_unaligned(scsi_command,unit);
}
break;
}
}
// SCSI Command complete, handle any errors
@ -415,7 +219,7 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
* @param itask Pointer to an IDETask struct
* @returns number of drives found
*/
static BYTE init_units(struct IDETask *itask) {
static BYTE init_units(struct IOTask *itask) {
struct ExecBase *SysBase = itask->SysBase;
UBYTE num_units = 0;
struct DeviceBase *dev = itask->dev;
@ -476,7 +280,7 @@ static BYTE init_units(struct IDETask *itask) {
*
* Clean up after the task, freeing resources etc back to the system
*/
static void cleanup(struct IDETask *itask) {
static void cleanup(struct IOTask *itask) {
struct ExecBase *SysBase = itask->SysBase;
if (itask->iomp)
L_DeletePort(itask->iomp);
@ -507,9 +311,9 @@ static void cleanup(struct IDETask *itask) {
*
* Check for disk changes and send interrupts if necessary
*
* @param itask Pointer to the IDE task
* @param itask Pointer to the IO task
*/
static void diskchange_check(struct IDETask *itask) {
static void diskchange_check(struct IOTask *itask) {
Info("diskchange check...\n");
struct ExecBase *SysBase = itask->SysBase;
struct IDEUnit *unit;
@ -559,12 +363,12 @@ static void diskchange_check(struct IDETask *itask) {
/**
* process_ioreq
*
* Process an IO request for the IDE task
* Process an IO request for the IO task
*
* @param ioreq Pointer to the IO request
* @param itask Pointer to the IDE task
* @param itask Pointer to the IO task
*/
static void process_ioreq(struct IDETask *itask, struct IOStdReq *ioreq) {
static void process_ioreq(struct IOTask *itask, struct IOStdReq *ioreq) {
struct ExecBase *SysBase = itask->SysBase;
struct IOExtTD *iotd;
struct IDEUnit *unit;
@ -719,7 +523,7 @@ transfer:
/* CMD_DIE: Shut down this task and clean up */
case CMD_DIE:
Info("Task: CMD_DIE: Shutting down IDE Task\n");
Info("Task: CMD_DIE: Shutting down IO Task\n");
cleanup(itask);
ReplyMsg(&ioreq->io_Message);
RemTask(NULL);
@ -740,22 +544,22 @@ transfer:
}
/**
* ide_task
* io_task
*
* This is a task to complete IO Requests for all units
* Requests are sent here from begin_io via the dev->IDETaskMP Message port
*/
void __attribute__((noreturn)) ide_task () {
void __attribute__((noreturn)) io_task () {
struct ExecBase *SysBase = *(struct ExecBase **)4UL;
struct Task *task = FindTask(NULL);
struct IDETask *itask = (struct IDETask *)task->tc_UserData;
struct IOTask *itask = (struct IOTask *)task->tc_UserData;
struct IOStdReq *ioreq;
ULONG signalsSet = 0;
ULONG signalMask = 0;
itask->task = task;
Trace("IDE Task: CreatePort()\n");
Trace("IO Task: CreatePort()\n");
// Create the MessagePort used to send us requests
if ((itask->iomp = L_CreatePort(NULL,0)) == NULL) {
cleanup(itask);
@ -765,7 +569,7 @@ void __attribute__((noreturn)) ide_task () {
signalMask = (1 << itask->iomp->mp_SigBit);
Trace("IDE Task: CreatePort() ok\n");
Trace("IO Task: CreatePort() ok\n");
if (!create_timer(SysBase,&itask->timermp,&itask->tr,UNIT_MICROHZ)) {
cleanup(itask);
@ -800,7 +604,7 @@ void __attribute__((noreturn)) ide_task () {
while (1) {
// Main loop, handle IO Requests as they come in.
Trace("IDE Task: WaitPort()\n");
Trace("IO Task: WaitPort()\n");
signalsSet = Wait(signalMask);
if (signalsSet & (1 << itask->iomp->mp_SigBit)) {

View File

@ -14,4 +14,4 @@
#define CMD_PAUSE (CMD_PIO + 1)
#define CMD_RESUME (CMD_PAUSE + 1)
void ide_task();
void io_task();

View File

@ -33,7 +33,7 @@
#include "config.h"
#include "matzetk.h"
#include "../device.h"
#include "../idetask.h"
#include "../iotask.h"
#define MANUF_ID_BSC 0x082C
#define MANUF_ID_OAHR 5194

154
scsi.c
View File

@ -12,13 +12,13 @@
#include "ata.h"
#include "debug.h"
#include "device.h"
#include "idetask.h"
#include "iotask.h"
#include "newstyle.h"
#include "scsi.h"
#include "td64.h"
/**
* scsi_sense
* fake_scsi_sense
*
* Populate sense data based on the error returned by the ATA functions
*
@ -28,7 +28,7 @@
* @param error Error code returned from ata_transfer
*
*/
void scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE error)
void fake_scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE error)
{
struct SCSI_FIXED_SENSE *sense = (struct SCSI_FIXED_SENSE *)command->scsi_SenseData;
if (!(command->scsi_Flags & SCSIF_AUTOSENSE) || error == 0 || sense == NULL || (command->scsi_SenseLength < sizeof(struct SCSI_FIXED_SENSE)))
@ -121,4 +121,150 @@ void DeleteSCSICmd(struct SCSICmd *cmd) {
if (cdb) FreeMem(cdb,(ULONG)cmd->scsi_CmdLength);
FreeMem(cmd,sizeof(struct SCSICmd));
}
}
}
/**
* scsi_inquiry_emu
*
* Emulate SCSI-Direct INQUIRY command
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
struct ExecBase *SysBase = unit->SysBase;
struct SCSI_Inquiry *data = (struct SCSI_Inquiry *)scsi_command->scsi_Data;
BYTE error;
data->peripheral_type = unit->deviceType;
data->removable_media = 0;
data->version = 2;
data->response_format = 2;
data->additional_length = (sizeof(struct SCSI_Inquiry) - 4);
UWORD *identity = AllocMem(512,MEMF_CLEAR|MEMF_ANY);
if (!identity) {
error = TDERR_NoMem;
fake_scsi_sense(scsi_command,0,0,error);
return error;
}
if (!(ata_identify(unit,identity))) {
error = HFERR_SelTimeout;
fake_scsi_sense(scsi_command,0,0,error);
FreeMem(identity,512);
return error;
}
CopyMem(&identity[ata_identify_model],&data->vendor,24);
CopyMem(&identity[ata_identify_fw_rev],&data->revision,4);
CopyMem(&identity[ata_identify_serial],&data->serial,8);
FreeMem(identity,512);
scsi_command->scsi_Actual = scsi_command->scsi_Length;
return 0;
}
/**
* scsi_read_capacity_emu
*
* Emulate SCSI-Direct READ CAPACITY command
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
BYTE scsi_read_capacity_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
struct SCSI_CAPACITY_10 *data = (struct SCSI_CAPACITY_10 *)scsi_command->scsi_Data;
BYTE error;
if (data == NULL) {
error = IOERR_BADADDRESS;
fake_scsi_sense(scsi_command,0,0,error);
return error;
}
struct SCSI_READ_CAPACITY_10 *cdb = (struct SCSI_READ_CAPACITY_10 *)scsi_command->scsi_Command;
data->block_size = unit->blockSize;
if (cdb->flags & 0x01) {
// Partial Medium Indicator - Return end of cylinder
// Implement this so HDToolbox stops moaning about track size
ULONG spc = unit->sectorsPerTrack * unit->heads;
data->lba = (((cdb->lba / spc) + 1) * spc) - 1;
} else {
data->lba = (unit->logicalSectors) - 1;
}
scsi_command->scsi_Actual = 8;
return 0;
}
/**
* scsi_mode_sense_emu
*
* Emulate SCSI-Direct MODE SENSE (6) commands
*
* @param unit Pointer to an IDEUnit struct
* @param scsi_command Pointer to a SCSICmd struct
*/
BYTE scsi_mode_sense_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) {
BYTE error;
UBYTE *data = (APTR)scsi_command->scsi_Data;
UBYTE *command = (APTR)scsi_command->scsi_Command;
if (data == NULL) {
return IOERR_BADADDRESS;
}
UBYTE page = command[2] & 0x3F;
UBYTE subpage = command[3];
if (subpage != 0 || (page != 0x3F && page != 0x03 && page != 0x04)) {
error = HFERR_BadStatus;
fake_scsi_sense(scsi_command,0,0,error);
return error;
}
UBYTE *data_length = data; // Mode data length
data[1] = unit->deviceType; // Mode parameter: Media type
data[2] = 0; // DPOFUA
data[3] = 0; // Block descriptor length
*data_length = 3;
UBYTE idx = 4;
if (page == 0x3F || page == 0x03) {
data[idx++] = 0x03; // Page Code: Format Parameters
data[idx++] = 0x16; // Page length
for (int i=0; i <8; i++) {
data[idx++] = 0;
}
data[idx++] = (unit->sectorsPerTrack >> 8);
data[idx++] = unit->sectorsPerTrack;
data[idx++] = (unit->blockSize >> 8);
data[idx++] = unit->blockSize;
for (int i=0; i<10; i++) {
data[idx++] = 0;
}
}
if (page == 0x3F || page == 0x04) {
data[idx++] = 0x04; // Page code: Rigid Drive Geometry Parameters
data[idx++] = 0x16; // Page length
data[idx++] = (unit->cylinders >> 16);
data[idx++] = (unit->cylinders >> 8);
data[idx++] = unit->cylinders;
data[idx++] = unit->heads;
for (int i=0; i<18; i++) {
data[idx++] = 0;
}
}
*data_length = idx - 1;
scsi_command->scsi_Actual = idx;
return 0;
}

6
scsi.h
View File

@ -141,9 +141,11 @@ struct __attribute__((packed)) SCSI_CDB_ATA {
#define ATA_TLEN_MASK 3
#define ATA_BYT_BLOK (1<<2)
void scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE error);
void fake_scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE error);
struct SCSICmd * MakeSCSICmd(ULONG cdbSize);
void DeleteSCSICmd(struct SCSICmd *cmd);
BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
BYTE scsi_read_capacity_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
BYTE scsi_mode_sense_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);
#endif