Added more code for SCSI removable hard disk emulation, only the UI parts (and testing) are left now.
This commit is contained in:
186
src/scsi_disk.c
186
src/scsi_disk.c
@@ -73,7 +73,9 @@ uint8_t scsi_hd_command_flags[0x100] =
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
IMPLEMENTED | ALLOW_UA, /* 0x12 */
|
||||
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
IMPLEMENTED | CHECK_READY, /* 0x1B */
|
||||
0, 0,
|
||||
IMPLEMENTED | CHECK_READY, /* 0x1E */
|
||||
0, 0, 0, 0, 0, 0,
|
||||
IMPLEMENTED | CHECK_READY, /* 0x25 */
|
||||
@@ -475,6 +477,10 @@ static void scsi_hd_sense_clear(int id, int command)
|
||||
static void scsi_hd_cmd_error(uint8_t id)
|
||||
{
|
||||
shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR;
|
||||
if (shdc[id].unit_attention)
|
||||
{
|
||||
shdc[id].error |= MCR_ERR;
|
||||
}
|
||||
shdc[id].status = READY_STAT | ERR_STAT;
|
||||
shdc[id].phase = 3;
|
||||
shdc[id].packet_status = 0x80;
|
||||
@@ -482,6 +488,28 @@ static void scsi_hd_cmd_error(uint8_t id)
|
||||
scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq);
|
||||
}
|
||||
|
||||
static void scsi_hd_unit_attention(uint8_t id)
|
||||
{
|
||||
shdc[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR;
|
||||
if (cdrom[id].unit_attention)
|
||||
{
|
||||
shdc[id].error |= MCR_ERR;
|
||||
}
|
||||
shdc[id].status = READY_STAT | ERR_STAT;
|
||||
shdc[id].phase = 3;
|
||||
shdc[id].packet_status = 0x80;
|
||||
shdc[id].callback = 50 * CDROM_TIME;
|
||||
scsi_hd_log("SCSI HD %i: UNIT ATTENTION\n", id);
|
||||
}
|
||||
|
||||
static void scsi_hd_not_ready(uint8_t id)
|
||||
{
|
||||
scsi_hd_sense_key = SENSE_NOT_READY;
|
||||
scsi_hd_asc = ASC_MEDIUM_NOT_PRESENT;
|
||||
scsi_hd_ascq = 0;
|
||||
scsi_hd_cmd_error(id);
|
||||
}
|
||||
|
||||
static void scsi_hd_invalid_lun(uint8_t id)
|
||||
{
|
||||
scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST;
|
||||
@@ -625,6 +653,11 @@ int scsi_hd_read_blocks(uint8_t id, uint32_t *len, int first_batch)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void scsi_disk_insert(uint8_t id)
|
||||
{
|
||||
shdc[id].unit_attention = (hdc[id].bus == 5) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*SCSI Sense Initialization*/
|
||||
void scsi_hd_sense_code_ok(uint8_t id)
|
||||
{
|
||||
@@ -635,6 +668,8 @@ void scsi_hd_sense_code_ok(uint8_t id)
|
||||
|
||||
int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb)
|
||||
{
|
||||
int ready = 1;
|
||||
|
||||
if (((shdc[id].request_length >> 5) & 7) != hdc[id].scsi_lun)
|
||||
{
|
||||
scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((shdc[id].request_length >> 5) & 7));
|
||||
@@ -649,6 +684,55 @@ int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hdc[id].bus == 5)
|
||||
{
|
||||
/* Removable disk, set ready state. */
|
||||
if (wcslen(hdd_fn[id]) > 0)
|
||||
{
|
||||
ready = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ready = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */
|
||||
shdc[id].unit_attention = 0;
|
||||
}
|
||||
|
||||
if (!ready && shdc[id].unit_attention)
|
||||
{
|
||||
/* If the drive is not ready, there is no reason to keep the
|
||||
UNIT ATTENTION condition present, as we only use it to mark
|
||||
disc changes. */
|
||||
shdc[id].unit_attention = 0;
|
||||
}
|
||||
|
||||
/* If the UNIT ATTENTION condition is set and the command does not allow
|
||||
execution under it, error out and report the condition. */
|
||||
if (shdc[id].unit_attention == 1)
|
||||
{
|
||||
/* Only increment the unit attention phase if the command can not pass through it. */
|
||||
if (!(scsi_hd_command_flags[cdb[0]] & ALLOW_UA))
|
||||
{
|
||||
/* scsi_hd_log("SCSI HD %i: Unit attention now 2\n", id); */
|
||||
shdc[id].unit_attention = 2;
|
||||
scsi_hd_log("SCSI HD %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]);
|
||||
scsi_hd_unit_attention(id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (shdc[id].unit_attention == 2)
|
||||
{
|
||||
if (cdb[0] != GPCMD_REQUEST_SENSE)
|
||||
{
|
||||
/* scsi_hd_log("SCSI HD %i: Unit attention now 0\n", id); */
|
||||
shdc[id].unit_attention = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unless the command is REQUEST SENSE, clear the sense. This will *NOT*
|
||||
the UNIT ATTENTION condition if it's set. */
|
||||
if (cdb[0] != GPCMD_REQUEST_SENSE)
|
||||
@@ -656,6 +740,14 @@ int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb)
|
||||
scsi_hd_sense_clear(id, cdb[0]);
|
||||
}
|
||||
|
||||
/* Next it's time for NOT READY. */
|
||||
if ((scsi_hd_command_flags[cdb[0]] & CHECK_READY) && !ready)
|
||||
{
|
||||
scsi_hd_log("SCSI HD %i: Not ready (%02X)\n", id, cdb[0]);
|
||||
scsi_hd_not_ready(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scsi_hd_log("SCSI HD %i: Continuing with command\n", id);
|
||||
|
||||
return 1;
|
||||
@@ -692,14 +784,56 @@ void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length)
|
||||
|
||||
buffer[0] = 0x70;
|
||||
|
||||
if (shdc[id].unit_attention && (scsi_hd_sense_key == 0))
|
||||
{
|
||||
buffer[2]=SENSE_UNIT_ATTENTION;
|
||||
buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED;
|
||||
buffer[13]=0;
|
||||
}
|
||||
|
||||
/* scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, hdbufferb[2], hdbufferb[12], hdbufferb[13]); */
|
||||
|
||||
if (buffer[2] == SENSE_UNIT_ATTENTION)
|
||||
{
|
||||
/* If the last remaining sense is unit attention, clear
|
||||
that condition. */
|
||||
shdc[id].unit_attention = 0;
|
||||
}
|
||||
|
||||
/* Clear the sense stuff as per the spec. */
|
||||
scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE);
|
||||
}
|
||||
|
||||
void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length)
|
||||
{
|
||||
int ready = 1;
|
||||
|
||||
if (hdc[id].bus == 5)
|
||||
{
|
||||
/* Removable disk, set ready state. */
|
||||
if (wcslen(hdd_fn[id]) > 0)
|
||||
{
|
||||
ready = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ready = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */
|
||||
shdc[id].unit_attention = 0;
|
||||
}
|
||||
|
||||
if (!ready && shdc[id].unit_attention)
|
||||
{
|
||||
/* If the drive is not ready, there is no reason to keep the
|
||||
UNIT ATTENTION condition present, as we only use it to mark
|
||||
disc changes. */
|
||||
shdc[id].unit_attention = 0;
|
||||
}
|
||||
|
||||
/* Do *NOT* advance the unit attention phase. */
|
||||
|
||||
scsi_hd_request_sense(id, buffer, alloc_length);
|
||||
@@ -772,6 +906,16 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
|
||||
scsi_hd_command_complete(id);
|
||||
break;
|
||||
|
||||
case GPCMD_PREVENT_REMOVAL:
|
||||
if (hdc[id].bus != 5)
|
||||
{
|
||||
scsi_hd_illegal_opcode(id);
|
||||
break;
|
||||
}
|
||||
|
||||
scsi_hd_command_complete(id);
|
||||
break;
|
||||
|
||||
case GPCMD_REZERO_UNIT:
|
||||
shdc[id].sector_pos = shdc[id].sector_len = 0;
|
||||
scsi_hd_seek(id, 0);
|
||||
@@ -921,6 +1065,37 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
|
||||
}
|
||||
return;
|
||||
|
||||
case GPCMD_START_STOP_UNIT:
|
||||
if (hdc[id].bus != 5)
|
||||
{
|
||||
scsi_hd_illegal_opcode(id);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(cdbufferb[4] & 3)
|
||||
{
|
||||
case 0: /* Stop the disc. */
|
||||
case 1: /* Start the disc and read the TOC. */
|
||||
break;
|
||||
case 2: /* Eject the disc if possible. */
|
||||
#ifndef __unix
|
||||
#if 0
|
||||
win_removable_disk_eject(id);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
case 3: /* Load the disc (close tray). */
|
||||
#ifndef __unix
|
||||
#if 0
|
||||
win_removable_disk_reload(id);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
scsi_hd_command_complete(id);
|
||||
break;
|
||||
|
||||
case GPCMD_INQUIRY:
|
||||
max_len = cdb[3];
|
||||
max_len <<= 8;
|
||||
@@ -985,7 +1160,14 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
|
||||
|
||||
memset(hdbufferb, 0, 8);
|
||||
hdbufferb[0] = 0; /*SCSI HD*/
|
||||
hdbufferb[1] = 0; /*Fixed*/
|
||||
if (hdc[id].bus == 5)
|
||||
{
|
||||
hdbufferb[1] = 0x80; /*Removable*/
|
||||
}
|
||||
else
|
||||
{
|
||||
hdbufferb[1] = 0; /*Fixed*/
|
||||
}
|
||||
hdbufferb[2] = 0x02; /*SCSI-2 compliant*/
|
||||
hdbufferb[3] = 0x02;
|
||||
hdbufferb[4] = 31;
|
||||
|
||||
Reference in New Issue
Block a user