mirror of
https://github.com/LIV2/lide.device.git
synced 2025-12-06 00:32:45 +00:00
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:
parent
89e3b82f6c
commit
eb8364fdbb
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -16,7 +16,7 @@
|
|||||||
"alib.h": "c",
|
"alib.h": "c",
|
||||||
"timer.h": "c",
|
"timer.h": "c",
|
||||||
"stdbool.h": "c",
|
"stdbool.h": "c",
|
||||||
"idetask.h": "c",
|
"iotask.h": "c",
|
||||||
"td64.h": "c",
|
"td64.h": "c",
|
||||||
"string.h": "c",
|
"string.h": "c",
|
||||||
"scsidisk.h": "c",
|
"scsidisk.h": "c",
|
||||||
|
|||||||
2
Makefile
2
Makefile
@ -69,7 +69,7 @@ OBJ = device.o \
|
|||||||
ata.o \
|
ata.o \
|
||||||
atapi.o \
|
atapi.o \
|
||||||
scsi.o \
|
scsi.o \
|
||||||
idetask.o \
|
iotask.o \
|
||||||
lide_alib.o \
|
lide_alib.o \
|
||||||
mounter/mounter.o \
|
mounter/mounter.o \
|
||||||
debug.o
|
debug.o
|
||||||
|
|||||||
66
atapi.c
66
atapi.c
@ -555,7 +555,7 @@ end:
|
|||||||
Trace("Auto sense requested\n");
|
Trace("Auto sense requested\n");
|
||||||
if (ret == IOERR_UNITBUSY) {
|
if (ret == IOERR_UNITBUSY) {
|
||||||
// This was a timeout, fake the autosense data
|
// This was a timeout, fake the autosense data
|
||||||
scsi_sense(cmd,0,0,ret);
|
fake_scsi_sense(cmd,0,0,ret);
|
||||||
} else {
|
} else {
|
||||||
atapi_autosense(cmd,unit);
|
atapi_autosense(cmd,unit);
|
||||||
}
|
}
|
||||||
@ -1366,3 +1366,67 @@ BYTE atapi_autosense(struct SCSICmd *scsi_command, struct IDEUnit *unit) {
|
|||||||
return TDERR_NoMem;
|
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;
|
||||||
|
}
|
||||||
1
atapi.h
1
atapi.h
@ -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_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_translate_play_audio_index(struct SCSICmd *cmd, struct IDEUnit *unit);
|
||||||
BYTE atapi_autosense(struct SCSICmd *scsi_command, 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
|
#endif
|
||||||
46
device.c
46
device.c
@ -19,7 +19,7 @@
|
|||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "atapi.h"
|
#include "atapi.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "idetask.h"
|
#include "iotask.h"
|
||||||
#include "newstyle.h"
|
#include "newstyle.h"
|
||||||
#include "td64.h"
|
#include "td64.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -62,6 +62,7 @@ static const struct Resident romTag = {
|
|||||||
|
|
||||||
const char device_name[] = DEVICE_NAME;
|
const char device_name[] = DEVICE_NAME;
|
||||||
const char device_id_string[] = DEVICE_ID_STRING;
|
const char device_id_string[] = DEVICE_ID_STRING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set_dev_name
|
* set_dev_name
|
||||||
*
|
*
|
||||||
@ -197,6 +198,15 @@ static BOOL FindCDFS() {
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
static bool ioreq_is_valid(struct DeviceBase *dev, struct IORequest *ior) {
|
||||||
struct ExecBase *SysBase = dev->SysBase;
|
struct ExecBase *SysBase = dev->SysBase;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -239,14 +249,14 @@ static void Cleanup(struct DeviceBase *dev) {
|
|||||||
|
|
||||||
if (dev->ExpansionBase) CloseLibrary((struct Library *)dev->ExpansionBase);
|
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->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;
|
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
|
// 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;
|
dev->ExpansionBase = ExpansionBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IDETask *itask;
|
struct IOTask *itask;
|
||||||
struct ConfigDev *cd;
|
struct ConfigDev *cd;
|
||||||
struct Task *self = FindTask(NULL);
|
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;
|
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.
|
// 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.
|
// 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) {
|
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++) {
|
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) {
|
if (itask == NULL) {
|
||||||
Info("Couldn't allocate memory\n");
|
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);
|
SetSignal(0,SIGF_SINGLE);
|
||||||
|
|
||||||
// Start the IDE Task
|
// Start the IO Task
|
||||||
itask->task = L_CreateTask(ATA_TASK_NAME,TASK_PRIORITY,ide_task,TASK_STACK_SIZE,itask);
|
itask->task = L_CreateTask(ATA_TASK_NAME,TASK_PRIORITY,io_task,TASK_STACK_SIZE,itask);
|
||||||
if (itask->task == NULL) {
|
if (itask->task == NULL) {
|
||||||
Info("IDE Task %ld failed\n",itask->taskNum);
|
Info("IO Task %ld failed\n",itask->taskNum);
|
||||||
FreeMem(itask,sizeof(struct IDETask));
|
FreeMem(itask,sizeof(struct IOTask));
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} 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
|
// 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 has been set to false it means the task exited
|
||||||
if (itask->active == false) {
|
if (itask->active == false) {
|
||||||
Info("IDE Task %ld exited.\n",itask->taskNum);
|
Info("IO Task %ld exited.\n",itask->taskNum);
|
||||||
FreeMem(itask,sizeof(struct IDETask));
|
FreeMem(itask,sizeof(struct IOTask));
|
||||||
continue;
|
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 (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;
|
ioreq->io_Error = IOERR_OPENFAIL;
|
||||||
|
|
||||||
if (!(ioreq->io_Flags & IOF_QUICK)) {
|
if (!(ioreq->io_Flags & IOF_QUICK)) {
|
||||||
@ -1003,7 +1013,7 @@ static struct Library * init(BPTR seg_list asm("a0"))
|
|||||||
Info("Add Device.\n");
|
Info("Add Device.\n");
|
||||||
AddDevice((struct Device *)mydev);
|
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;
|
if (!itask->mn_Node.mln_Succ) goto done;
|
||||||
|
|
||||||
|
|||||||
4
device.h
4
device.h
@ -45,7 +45,7 @@ struct Drive {
|
|||||||
struct IDEUnit {
|
struct IDEUnit {
|
||||||
struct MinNode mn_Node;
|
struct MinNode mn_Node;
|
||||||
struct ExecBase *SysBase;
|
struct ExecBase *SysBase;
|
||||||
struct IDETask *itask;
|
struct IOTask *itask;
|
||||||
struct Drive drive;
|
struct Drive drive;
|
||||||
BYTE (*write_taskfile)(struct IDEUnit *, UBYTE, ULONG, UBYTE, UBYTE);
|
BYTE (*write_taskfile)(struct IDEUnit *, UBYTE, ULONG, UBYTE, UBYTE);
|
||||||
enum xfer xferMethod;
|
enum xfer xferMethod;
|
||||||
@ -94,7 +94,7 @@ struct DeviceBase {
|
|||||||
struct MinList ideTasks;
|
struct MinList ideTasks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IDETask {
|
struct IOTask {
|
||||||
struct MinNode mn_Node;
|
struct MinNode mn_Node;
|
||||||
struct Task *task;
|
struct Task *task;
|
||||||
struct Task *parent;
|
struct Task *parent;
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
#include "atapi.h"
|
#include "atapi.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "idetask.h"
|
#include "iotask.h"
|
||||||
#include "newstyle.h"
|
#include "newstyle.h"
|
||||||
#include "scsi.h"
|
#include "scsi.h"
|
||||||
#include "td64.h"
|
#include "td64.h"
|
||||||
@ -23,7 +23,7 @@
|
|||||||
/**
|
/**
|
||||||
* create_timer
|
* 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 SysBase Pointer to the ExecBase
|
||||||
* @param mp Pointer to the MsgPort
|
* @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
|
* handle_scsi_command
|
||||||
*
|
*
|
||||||
@ -267,9 +121,10 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
|
|||||||
|
|
||||||
Trace("SCSI: Command %lx\n",*scsi_command->scsi_Command);
|
Trace("SCSI: Command %lx\n",*scsi_command->scsi_Command);
|
||||||
|
|
||||||
if (unit->flags.atapi == false)
|
if (unit->flags.atapi) {
|
||||||
{
|
error = atapi_handle_scsi_command(unit,scsi_command);
|
||||||
// Non-ATAPI drives - Translate SCSI CMD to ATA
|
} else {
|
||||||
|
// Translate SCSI CMD to ATA
|
||||||
switch (scsi_command->scsi_Command[0]) {
|
switch (scsi_command->scsi_Command[0]) {
|
||||||
case SCSI_CMD_ATA_PASSTHROUGH:
|
case SCSI_CMD_ATA_PASSTHROUGH:
|
||||||
error = scsi_ata_passthrough(unit,scsi_command);
|
error = scsi_ata_passthrough(unit,scsi_command);
|
||||||
@ -281,15 +136,15 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SCSI_CMD_INQUIRY:
|
case SCSI_CMD_INQUIRY:
|
||||||
error = scsi_inquiry_ata(unit,scsi_command);
|
error = scsi_inquiry_emu(unit,scsi_command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCSI_CMD_MODE_SENSE_6:
|
case SCSI_CMD_MODE_SENSE_6:
|
||||||
error = scsi_mode_sense_ata(unit,scsi_command);
|
error = scsi_mode_sense_emu(unit,scsi_command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCSI_CMD_READ_CAPACITY_10:
|
case SCSI_CMD_READ_CAPACITY_10:
|
||||||
error = scsi_read_capacity_ata(unit,scsi_command);
|
error = scsi_read_capacity_emu(unit,scsi_command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCSI_CMD_READ_6:
|
case SCSI_CMD_READ_6:
|
||||||
@ -309,7 +164,7 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
|
|||||||
do_scsi_transfer:
|
do_scsi_transfer:
|
||||||
if (data == NULL || (lba + count) >= unit->logicalSectors) {
|
if (data == NULL || (lba + count) >= unit->logicalSectors) {
|
||||||
error = IOERR_BADADDRESS;
|
error = IOERR_BADADDRESS;
|
||||||
scsi_sense(scsi_command,lba,count,error);
|
fake_scsi_sense(scsi_command,lba,count,error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,71 +179,20 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
|
|||||||
scsi_command->scsi_Actual = scsi_command->scsi_Length;
|
scsi_command->scsi_Actual = scsi_command->scsi_Length;
|
||||||
} else {
|
} else {
|
||||||
if (error == TDERR_NotSpecified) {
|
if (error == TDERR_NotSpecified) {
|
||||||
scsi_sense(scsi_command,lba,
|
fake_scsi_sense(scsi_command,lba,
|
||||||
(unit->last_error[0] << 8 | unit->last_error[4])
|
(unit->last_error[0] << 8 | unit->last_error[4])
|
||||||
,error);
|
,error);
|
||||||
} else {
|
} else {
|
||||||
scsi_sense(scsi_command,lba,count,error);
|
fake_scsi_sense(scsi_command,lba,count,error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = IOERR_NOCMD;
|
error = IOERR_NOCMD;
|
||||||
scsi_sense(scsi_command,0,0,error);
|
fake_scsi_sense(scsi_command,0,0,error);
|
||||||
break;
|
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
|
// 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
|
* @param itask Pointer to an IDETask struct
|
||||||
* @returns number of drives found
|
* @returns number of drives found
|
||||||
*/
|
*/
|
||||||
static BYTE init_units(struct IDETask *itask) {
|
static BYTE init_units(struct IOTask *itask) {
|
||||||
struct ExecBase *SysBase = itask->SysBase;
|
struct ExecBase *SysBase = itask->SysBase;
|
||||||
UBYTE num_units = 0;
|
UBYTE num_units = 0;
|
||||||
struct DeviceBase *dev = itask->dev;
|
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
|
* 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;
|
struct ExecBase *SysBase = itask->SysBase;
|
||||||
if (itask->iomp)
|
if (itask->iomp)
|
||||||
L_DeletePort(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
|
* 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");
|
Info("diskchange check...\n");
|
||||||
struct ExecBase *SysBase = itask->SysBase;
|
struct ExecBase *SysBase = itask->SysBase;
|
||||||
struct IDEUnit *unit;
|
struct IDEUnit *unit;
|
||||||
@ -559,12 +363,12 @@ static void diskchange_check(struct IDETask *itask) {
|
|||||||
/**
|
/**
|
||||||
* process_ioreq
|
* 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 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 ExecBase *SysBase = itask->SysBase;
|
||||||
struct IOExtTD *iotd;
|
struct IOExtTD *iotd;
|
||||||
struct IDEUnit *unit;
|
struct IDEUnit *unit;
|
||||||
@ -719,7 +523,7 @@ transfer:
|
|||||||
|
|
||||||
/* CMD_DIE: Shut down this task and clean up */
|
/* CMD_DIE: Shut down this task and clean up */
|
||||||
case CMD_DIE:
|
case CMD_DIE:
|
||||||
Info("Task: CMD_DIE: Shutting down IDE Task\n");
|
Info("Task: CMD_DIE: Shutting down IO Task\n");
|
||||||
cleanup(itask);
|
cleanup(itask);
|
||||||
ReplyMsg(&ioreq->io_Message);
|
ReplyMsg(&ioreq->io_Message);
|
||||||
RemTask(NULL);
|
RemTask(NULL);
|
||||||
@ -740,22 +544,22 @@ transfer:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ide_task
|
* io_task
|
||||||
*
|
*
|
||||||
* This is a task to complete IO Requests for all units
|
* This is a task to complete IO Requests for all units
|
||||||
* Requests are sent here from begin_io via the dev->IDETaskMP Message port
|
* 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 ExecBase *SysBase = *(struct ExecBase **)4UL;
|
||||||
struct Task *task = FindTask(NULL);
|
struct Task *task = FindTask(NULL);
|
||||||
struct IDETask *itask = (struct IDETask *)task->tc_UserData;
|
struct IOTask *itask = (struct IOTask *)task->tc_UserData;
|
||||||
struct IOStdReq *ioreq;
|
struct IOStdReq *ioreq;
|
||||||
ULONG signalsSet = 0;
|
ULONG signalsSet = 0;
|
||||||
ULONG signalMask = 0;
|
ULONG signalMask = 0;
|
||||||
|
|
||||||
itask->task = task;
|
itask->task = task;
|
||||||
|
|
||||||
Trace("IDE Task: CreatePort()\n");
|
Trace("IO Task: CreatePort()\n");
|
||||||
// Create the MessagePort used to send us requests
|
// Create the MessagePort used to send us requests
|
||||||
if ((itask->iomp = L_CreatePort(NULL,0)) == NULL) {
|
if ((itask->iomp = L_CreatePort(NULL,0)) == NULL) {
|
||||||
cleanup(itask);
|
cleanup(itask);
|
||||||
@ -765,7 +569,7 @@ void __attribute__((noreturn)) ide_task () {
|
|||||||
|
|
||||||
signalMask = (1 << itask->iomp->mp_SigBit);
|
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)) {
|
if (!create_timer(SysBase,&itask->timermp,&itask->tr,UNIT_MICROHZ)) {
|
||||||
cleanup(itask);
|
cleanup(itask);
|
||||||
@ -800,7 +604,7 @@ void __attribute__((noreturn)) ide_task () {
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// Main loop, handle IO Requests as they come in.
|
// Main loop, handle IO Requests as they come in.
|
||||||
Trace("IDE Task: WaitPort()\n");
|
Trace("IO Task: WaitPort()\n");
|
||||||
signalsSet = Wait(signalMask);
|
signalsSet = Wait(signalMask);
|
||||||
|
|
||||||
if (signalsSet & (1 << itask->iomp->mp_SigBit)) {
|
if (signalsSet & (1 << itask->iomp->mp_SigBit)) {
|
||||||
@ -14,4 +14,4 @@
|
|||||||
#define CMD_PAUSE (CMD_PIO + 1)
|
#define CMD_PAUSE (CMD_PIO + 1)
|
||||||
#define CMD_RESUME (CMD_PAUSE + 1)
|
#define CMD_RESUME (CMD_PAUSE + 1)
|
||||||
|
|
||||||
void ide_task();
|
void io_task();
|
||||||
@ -33,7 +33,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "matzetk.h"
|
#include "matzetk.h"
|
||||||
#include "../device.h"
|
#include "../device.h"
|
||||||
#include "../idetask.h"
|
#include "../iotask.h"
|
||||||
|
|
||||||
#define MANUF_ID_BSC 0x082C
|
#define MANUF_ID_BSC 0x082C
|
||||||
#define MANUF_ID_OAHR 5194
|
#define MANUF_ID_OAHR 5194
|
||||||
|
|||||||
152
scsi.c
152
scsi.c
@ -12,13 +12,13 @@
|
|||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "idetask.h"
|
#include "iotask.h"
|
||||||
#include "newstyle.h"
|
#include "newstyle.h"
|
||||||
#include "scsi.h"
|
#include "scsi.h"
|
||||||
#include "td64.h"
|
#include "td64.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scsi_sense
|
* fake_scsi_sense
|
||||||
*
|
*
|
||||||
* Populate sense data based on the error returned by the ATA functions
|
* Populate sense data based on the error returned by the ATA functions
|
||||||
*
|
*
|
||||||
@ -28,7 +28,7 @@
|
|||||||
* @param error Error code returned from ata_transfer
|
* @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;
|
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)))
|
if (!(command->scsi_Flags & SCSIF_AUTOSENSE) || error == 0 || sense == NULL || (command->scsi_SenseLength < sizeof(struct SCSI_FIXED_SENSE)))
|
||||||
@ -122,3 +122,149 @@ void DeleteSCSICmd(struct SCSICmd *cmd) {
|
|||||||
FreeMem(cmd,sizeof(struct SCSICmd));
|
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
6
scsi.h
@ -141,9 +141,11 @@ struct __attribute__((packed)) SCSI_CDB_ATA {
|
|||||||
#define ATA_TLEN_MASK 3
|
#define ATA_TLEN_MASK 3
|
||||||
#define ATA_BYT_BLOK (1<<2)
|
#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);
|
struct SCSICmd * MakeSCSICmd(ULONG cdbSize);
|
||||||
void DeleteSCSICmd(struct SCSICmd *cmd);
|
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
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user