mirror of
https://github.com/LIV2/lide.device.git
synced 2025-12-06 00:32:45 +00:00
Add diskchange task
This commit is contained in:
parent
2fc75de0f5
commit
a2e42d3b59
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -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
1
ata.c
@ -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
100
atapi.c
@ -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;
|
||||
}
|
||||
1
atapi.h
1
atapi.h
@ -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
|
||||
1
device.h
1
device.h
@ -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;
|
||||
|
||||
14
driver.c
14
driver.c
@ -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;
|
||||
|
||||
|
||||
94
idetask.c
94
idetask.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user