Add diskchange task

This commit is contained in:
Matt Harlum 2023-04-30 21:54:29 +00:00
parent 2fc75de0f5
commit a2e42d3b59
8 changed files with 157 additions and 58 deletions

View File

@ -20,7 +20,8 @@
"td64.h": "c",
"string.h": "c",
"scsidisk.h": "c",
"ndkcompat.h": "c"
"ndkcompat.h": "c",
"device.h": "c"
},
"C_Cpp.errorSquiggles": "enabled"
}

1
ata.c
View File

@ -248,6 +248,7 @@ bool ata_init_unit(struct IDEUnit *unit) {
unit->device_type = (buf[0] >> 8) & 0x1F;
unit->atapi = true;
if ((atapi_test_unit_ready(unit)) == 0) {
atapi_update_presence(unit,true);
atapi_get_capacity(unit);
}
} else {

100
atapi.c
View File

@ -29,12 +29,14 @@
* @param tries Tries, sets the timeout
*/
static bool atapi_wait_drq(struct IDEUnit *unit, ULONG tries) {
Trace("atapi_wait_drq enter\n");
struct timerequest *tr = unit->TimeReq;
for (int i=0; i < tries; i++) {
if ((*unit->drive->status_command & ata_flag_drq) != 0) return true;
wait_us(tr,ATAPI_BSY_WAIT_LOOP_US);
wait_us(tr,ATAPI_DRQ_WAIT_LOOP_US);
}
Trace("atapi_wait_drq timeout\n");
return false;
}
@ -46,12 +48,14 @@ static bool atapi_wait_drq(struct IDEUnit *unit, ULONG tries) {
* @param tries Tries, sets the timeout
*/
static bool atapi_wait_not_bsy(struct IDEUnit *unit, ULONG tries) {
Trace("atapi_wait_not_bsy enter\n");
struct timerequest *tr = unit->TimeReq;
for (int i=0; i < tries; i++) {
if ((*(volatile BYTE *)unit->drive->status_command & ata_flag_busy) == 0) return true;
wait_us(tr,ATAPI_BSY_WAIT_LOOP_US);
}
Trace("atapi_wait_not_bsy timeout\n");
return false;
}
@ -95,7 +99,7 @@ void atapi_dev_reset(struct IDEUnit *unit) {
bool atapi_check_signature(struct IDEUnit *unit) {
atapi_dev_reset(unit);
wait_us(unit->TimeReq,10000);
for (int i=0; i<20; i++) {
if ((*unit->drive->lbaHigh == 0xEB) && (*unit->drive->lbaMid == 0x14)) return true;
}
@ -131,8 +135,8 @@ bool atapi_identify(struct IDEUnit *unit, UWORD *buffer) {
if (!atapi_wait_drq(unit,ATAPI_DRQ_WAIT_COUNT)) {
if (*unit->drive->status_command & (ata_flag_error | ata_flag_df)) {
Warn("ATAPI: IDENTIFY Status: Error\n");
Warn("ATAPI: last_error: %08lx\n",&unit->last_error[0]);
Info("ATAPI: IDENTIFY Status: Error\n");
Info("ATAPI: last_error: %08lx\n",&unit->last_error[0]);
// Save the error details
unit->last_error[0] = *unit->drive->error_features;
unit->last_error[1] = *unit->drive->lbaHigh;
@ -208,17 +212,18 @@ BYTE atapi_translate(APTR io_Data,ULONG lba, ULONG count, ULONG *io_Actual, stru
}
if (senseKey == 0x06) {
if (asc == 0x28) {
ret = TDERR_DiskChanged; // Medium changed
if (atapi_update_presence(unit,true)) ret = TDERR_DiskChanged; // Medium changed
break;
} else {
// Otherwise it was a reset complete message
continue;
}
} else if (senseKey == 0x02) { // Unit becoming ready
if (asc == 0x04) {
} else if (senseKey == 0x02) { // Unit not ready
if (asc == 0x04) { // Unit becoming ready
wait(unit->TimeReq,1); // Wait
continue; // and try again
} else { // Medium Error / Not ready
continue; // and try again
} else { // Medium Error / Not ready
atapi_update_presence(unit,false);
ret = IOERR_UNITBUSY;
break; // done
}
@ -332,11 +337,11 @@ BYTE atapi_packet(struct SCSICmd *cmd, struct IDEUnit *unit) {
Info("Error: %02lx\n",*status);
Info("Interrupt reason: %02lx\n",*unit->drive->sectorCount);
cmd->scsi_Status = 2;
if (cmd->scsi_Flags & (SCSIF_AUTOSENSE | SCSIF_OLDAUTOSENSE) && cmd->scsi_SenseData != NULL && cmd->scsi_SenseLength >= 18) {
UBYTE *sense = cmd->scsi_SenseData;
cmd->scsi_SenseActual = 18;
atapi_request_sense(unit,&sense[0],&sense[2],&sense[12],&sense[13]);
}
// if (cmd->scsi_Flags & (SCSIF_AUTOSENSE | SCSIF_OLDAUTOSENSE) && cmd->scsi_SenseData != NULL && cmd->scsi_SenseLength >= 18) {
// UBYTE *sense = cmd->scsi_SenseData;
// cmd->scsi_SenseActual = 18;
// atapi_request_sense(unit,&sense[0],&sense[2],&sense[12],&sense[13]);
// }
return HFERR_BadStatus;
}
@ -429,59 +434,44 @@ BYTE atapi_test_unit_ready(struct IDEUnit *unit) {
Trace("ATAPI: TUR Return: %ld SenseKey %lx\n",ret,senseKey);
if (ret == 0) {
if (unit->mediumPresent == false) {
Trace("ATAPI TUR: setting medium as present\n");
unit->mediumPresent = true;
unit->change_count++;
ret = atapi_get_capacity(unit);
}
goto done;
} else {
if (ret != 0) {
if ((ret = atapi_request_sense(unit,&senseError,&senseKey,&asc,&asq)) == 0) {
Trace("SenseKey: %lx ASC: %lx ASQ: %lx\n",senseKey,asc,asq);
switch (senseKey) {
case 0: // If there's no Sense Key it must have been a timeout or bad phase
// Reset the device before trying again
ret = TDERR_NotSpecified;
atapi_dev_reset(unit);
break;
case 2: // Not ready
if (asc == 4 && tries > 0) { // Becoming ready
if (asc == 4) { // Becoming ready
// The medium is becoming ready, wait a few seconds before checking again
wait(unit->TimeReq,3);
ret = TDERR_DiskChanged;
if (tries > 0) wait(unit->TimeReq,3);
} else { // Anything else - No medium/bad medium etc
if (unit->mediumPresent == true) {
Trace("ATAPI TUR: Setting medium as not present\n");
unit->change_count++;
unit->mediumPresent = false;
unit->logicalSectors = 0;
unit->blockShift = 0;
unit->blockSize = 0;
ret = TDERR_DiskChanged;
goto done;
}
Trace("ATAPI TUR: Setting medium as not present\n");
ret = TDERR_DiskChanged;
goto done;
}
break;
case 6: // Unit attention
if (asc == 0x28) { // Medium became ready
if (unit->mediumPresent == false) {
Trace("ATAPI TUR: Not-ready to ready - setting medium as present\n");
unit->mediumPresent = true;
unit->change_count++;
ret = atapi_get_capacity(unit);
goto done;
}
ret = 0;
}
break;
case 3: // Medium error
ret = TDERR_DiskChanged;
break;
default:
ret = TDERR_NotSpecified;
goto done;
}
}
}
}
done:
if (atapi_update_presence(unit,(ret == 0))) Info("Media state changed\n");
DeleteSCSICmd(cmd);
return ret;
@ -739,4 +729,30 @@ BYTE atapi_check_wp(struct IDEUnit *unit) {
return ret;
}
/**
* atapi_update_presence
*
* If the medium has changed state update the unit info, geometry etc
* @param unit Pointer to an IDEUnit struct
* @param present Medium present
* @returns bool true if changed
*/
bool atapi_update_presence(struct IDEUnit *unit, bool present) {
bool ret = false;
if (present && unit->mediumPresent == false) {
unit->change_count++;
unit->mediumPresent = true;
atapi_get_capacity(unit);
ret = true;
} else if (!present && unit->mediumPresent == true) {
unit->change_count++;
unit->mediumPresent = false;
unit->logicalSectors = 0;
unit->blockShift = 0;
unit->blockSize = 0;
ret = true;
}
return ret;
}

View File

@ -43,4 +43,5 @@ BYTE atapi_mode_sense(struct IDEUnit *unit, BYTE page_code, UWORD *buffer, UWORD
BYTE atapi_scsi_mode_sense_6(struct SCSICmd *cmd, struct IDEUnit *unit);
BYTE atapi_start_stop_unit(struct IDEUnit *unit, bool start, bool loej);
BYTE atapi_check_wp(struct IDEUnit *unit);
bool atapi_update_presence(struct IDEUnit *unit, bool present);
#endif

View File

@ -58,6 +58,7 @@ struct DeviceBase {
struct Library *ExpansionBase;
struct Library *TimerBase;
struct Task *Task;
struct Task *ChangeTask;
struct MsgPort *TaskMP;
volatile bool TaskActive;
struct MsgPort *TimerMP;

View File

@ -196,7 +196,7 @@ struct Library __attribute__((used, saveds)) * init_device(struct ExecBase *SysB
Info("Channels: %ld\n",channels);
for (BYTE i=0; i < (2 * channels); i++) {
for (BYTE i=0; i < 2/*(2 * channels)*/; i++) {
dev->units[i].SysBase = SysBase;
dev->units[i].TimeReq = dev->TimeReq;
dev->units[i].cd = cd;
@ -250,6 +250,10 @@ struct Library __attribute__((used, saveds)) * init_device(struct ExecBase *SysB
return NULL;
}
}
dev->ChangeTask = CreateTask(dev->lib.lib_Node.ln_Name,TASK_PRIORITY,(APTR)diskchange_task,TASK_STACK_SIZE);
dev->ChangeTask->tc_UserData = dev;
Info("Startup finished.\n");
return (struct Library *)dev;
} else {
@ -415,6 +419,8 @@ static UWORD supported_commands[] =
*/
static void __attribute__((used, saveds)) begin_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq asm("a1"))
{
struct IDEUnit *unit = (struct IDEUnit *)ioreq->io_Unit;
Trace((CONST_STRPTR) "running begin_io()\n");
ioreq->io_Error = TDERR_NotSpecified;
@ -425,20 +431,20 @@ static void __attribute__((used, saveds)) begin_io(struct DeviceBase *dev asm("a
if (ioreq == NULL || ioreq->io_Unit == 0) return;
Trace("Command %lx\n",ioreq->io_Command);
switch (ioreq->io_Command) {
case TD_MOTOR:
case CMD_CLEAR:
case CMD_UPDATE:
case TD_MOTOR:
ioreq->io_Actual = 0;
ioreq->io_Error = 0;
break;
case TD_CHANGENUM:
ioreq->io_Actual = ((struct IDEUnit *)ioreq->io_Unit)->change_count;
ioreq->io_Actual = unit->change_count;
ioreq->io_Error = 0;
break;
case TD_GETDRIVETYPE:
ioreq->io_Actual = ((struct IDEUnit *)ioreq->io_Unit)->device_type;
ioreq->io_Actual = unit->device_type;
ioreq->io_Error = 0;
break;

View File

@ -17,6 +17,7 @@
#include "newstyle.h"
#include "scsi.h"
#include "td64.h"
#include "wait.h"
/**
* handle_scsi_command
@ -206,7 +207,21 @@ static void handle_scsi_command(struct IOStdReq *ioreq) {
}
default:
error = atapi_packet(scsi_command,unit);
if ((error = atapi_packet(scsi_command,unit)) != 0) {
if (scsi_command->scsi_Flags & (SCSIF_AUTOSENSE)) {
Trace("Auto sense requested\n");
struct SCSICmd *cmd = MakeSCSICmd();
cmd->scsi_Command[0] = SCSI_CMD_REQUEST_SENSE;
cmd->scsi_Command[4] = 18;
cmd->scsi_Data = (UWORD *)scsi_command->scsi_SenseData;
cmd->scsi_Length = scsi_command->scsi_SenseLength;
cmd->scsi_Flags = SCSIF_READ;
cmd->scsi_CmdLength = 1;
atapi_packet(cmd,unit);
scsi_command->scsi_SenseActual = cmd->scsi_Actual;
DeleteSCSICmd(cmd);
}
}
break;
}
}
@ -227,6 +242,64 @@ static void handle_scsi_command(struct IOStdReq *ioreq) {
}
}
void __attribute__((noreturn)) diskchange_task () {
struct ExecBase *SysBase = *(struct ExecBase **)4UL;
struct Task volatile *task = FindTask(NULL);
struct MsgPort *TimerMP, *iomp = NULL;
struct timerequest *TimerReq = NULL;
struct IOStdReq *ioreq = NULL;
struct IDEUnit *unit = NULL;
bool previous;
bool present;
while (task->tc_UserData == NULL); // Wait for Task Data to be populated
struct DeviceBase *dev = (struct DeviceBase *)task->tc_UserData;
if ((TimerMP = CreatePort(NULL,0)) == NULL || (TimerReq = (struct timerequest *)CreateExtIO(TimerMP, sizeof(struct timerequest))) == NULL) goto die;
if ((iomp = CreatePort(NULL,0)) == NULL || (ioreq = CreateStdIO(iomp)) == NULL) goto die;
if (OpenDevice("timer.device",UNIT_MICROHZ,(struct IORequest *)TimerReq,0) != 0) goto die;
ioreq->io_Command = TD_CHANGESTATE;
ioreq->io_Data = NULL;
ioreq->io_Length = 1;
ioreq->io_Actual = 0;
while (1) {
ioreq->io_Data = NULL;
ioreq->io_Length = 0;
for (int i=-0; i < MAX_UNITS; i++) {
unit = &dev->units[i];
Info("Testing unit %ld\n",i);
if (unit->present && unit->atapi) {
Info("Current state: %ld\n",unit->mediumPresent);
previous = unit->mediumPresent;
ioreq->io_Unit = (struct Unit *)unit;
PutMsg(dev->TaskMP,(struct Message *)ioreq);
WaitPort(iomp);
GetMsg(iomp);
present = (ioreq->io_Actual == 0);
Info("previous / new state:%ld %ld\n",previous,present);
}
}
Info("Wait...\n");
wait(TimerReq,3);
}
die:
Info("Change task dying...\n");
if (ioreq) DeleteStdIO(ioreq);
if (iomp) DeletePort(iomp);
if (TimerReq) DeleteExtIO((struct IORequest *)TimerReq);
if (TimerMP) DeletePort(TimerMP);
RemTask(NULL);
Wait(0);
while (1);
}
/**
* ide_task
*
@ -244,10 +317,10 @@ void __attribute__((noreturn)) ide_task () {
ULONG count;
enum xfer_dir direction = WRITE;
Info("Task: waiting for init\n");
Info("IDE Task: waiting for init\n");
while (task->tc_UserData == NULL); // Wait for Task Data to be populated
struct DeviceBase *dev = (struct DeviceBase *)task->tc_UserData;
Trace("Task: CreatePort()\n");
Trace("IDE Task: CreatePort()\n");
// Create the MessagePort used to send us requests
if ((mp = CreatePort(NULL,0)) == NULL) {
dev->Task = NULL; // Failed to create MP, let the device know
@ -264,7 +337,7 @@ void __attribute__((noreturn)) ide_task () {
while (1) {
// Main loop, handle IO Requests as they come in.
Trace("Task: WaitPort()\n");
Trace("IDE Task: WaitPort()\n");
Wait(1 << mp->mp_SigBit); // Wait for an IORequest to show up
while ((ioreq = (struct IOStdReq *)GetMsg(mp))) {
@ -285,11 +358,8 @@ void __attribute__((noreturn)) ide_task () {
ioreq->io_Error = 0;
ioreq->io_Actual = 0;
if (unit->atapi) {
if ((ioreq->io_Error = atapi_test_unit_ready(unit) == TDERR_DiskChanged)) {
ioreq->io_Actual = 1;
ioreq->io_Error = 0;
break;
}
ioreq->io_Actual = (atapi_test_unit_ready(unit) != 0);
break;
}
ioreq->io_Actual = (((struct IDEUnit *)ioreq->io_Unit)->mediumPresent) ? 0 : 1;
break;
@ -319,7 +389,8 @@ void __attribute__((noreturn)) ide_task () {
case NSCMD_TD_WRITE64:
case NSCMD_TD_FORMAT64:
if (unit->atapi == true && unit->mediumPresent == false) {
ioreq->io_Error = IOERR_BADADDRESS;
Trace("Access attempt without media\n");
ioreq->io_Error = TDERR_DiskChanged;
break;
}
@ -328,7 +399,8 @@ void __attribute__((noreturn)) ide_task () {
count = (ioreq->io_Length >> blockShift);
if ((lba + count) > (unit->logicalSectors)) {
ioreq->io_Error = IOERR_BADADDRESS;
Trace("Read past end of device\n");
ioreq->io_Error = TDERR_SeekError;
break;
}

View File

@ -9,3 +9,4 @@
#define CMD_DIE 0x1000
void ide_task();
void diskchange_task();