Implemented SCSI disk WRITE AND VERIFY (10), WRITE AND VERIFY (12), and WRITE SAME (10) commands;

Implemented byte compare mode for the SCSI disk VERIFY (6), VERIFY (10), and VERIFY (12) commands.
This commit is contained in:
OBattler
2017-11-23 21:32:21 +01:00
parent 1cd4018055
commit 7095f329de
2 changed files with 121 additions and 6 deletions

View File

@@ -52,7 +52,9 @@
#define GPCMD_READ_10 0x28
#define GPCMD_WRITE_10 0x2a
#define GPCMD_SEEK_10 0x2b
#define GPCMD_WRITE_AND_VERIFY_10 0x2e
#define GPCMD_VERIFY_10 0x2f
#define GPCMD_WRITE_SAME_10 0x41
#define GPCMD_READ_SUBCHANNEL 0x42
#define GPCMD_READ_TOC_PMA_ATIP 0x43
#define GPCMD_READ_HEADER 0x44
@@ -71,6 +73,7 @@
#define GPCMD_READ_12 0xa8
#define GPCMD_WRITE_12 0xaa
#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */
#define GPCMD_WRITE_AND_VERIFY_12 0xae
#define GPCMD_VERIFY_12 0xaf
#define GPCMD_PLAY_CD_OLD 0xb4
#define GPCMD_READ_CD_OLD 0xb8

View File

@@ -103,10 +103,13 @@ uint8_t scsi_hd_command_flags[0x100] = {
IMPLEMENTED | CHECK_READY, /* 0x28 */
0,
IMPLEMENTED | CHECK_READY, /* 0x2A */
0, 0, 0, 0,
0, 0, 0,
IMPLEMENTED | CHECK_READY, /* 0x2E */
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
IMPLEMENTED | CHECK_READY, /* 0x41 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
IMPLEMENTED, /* 0x55 */
0, 0, 0, 0,
@@ -120,7 +123,8 @@ uint8_t scsi_hd_command_flags[0x100] = {
IMPLEMENTED | CHECK_READY, /* 0xA8 */
0,
IMPLEMENTED | CHECK_READY, /* 0xAA */
0, 0, 0, 0,
0, 0, 0,
IMPLEMENTED | CHECK_READY, /* 0xAE */
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
IMPLEMENTED, /* 0xBD */
@@ -1466,9 +1470,6 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
{
case GPCMD_TEST_UNIT_READY:
case GPCMD_FORMAT_UNIT:
case GPCMD_VERIFY_6:
case GPCMD_VERIFY_10:
case GPCMD_VERIFY_12:
SCSIPhase = SCSI_PHASE_STATUS;
scsi_hd_command_complete(id);
break;
@@ -1567,9 +1568,19 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1);
return;
case GPCMD_VERIFY_6:
case GPCMD_VERIFY_10:
case GPCMD_VERIFY_12:
if (!(cdb[1] & 2)) {
SCSIPhase = SCSI_PHASE_STATUS;
scsi_hd_command_complete(id);
break;
}
case GPCMD_WRITE_6:
case GPCMD_WRITE_10:
case GPCMD_WRITE_AND_VERIFY_10:
case GPCMD_WRITE_12:
case GPCMD_WRITE_AND_VERIFY_12:
if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp)
{
scsi_hd_write_protected(id);
@@ -1578,17 +1589,22 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
switch(cdb[0])
{
case GPCMD_VERIFY_6:
case GPCMD_WRITE_6:
shdc[id].sector_len = cdb[4];
shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos);
break;
case GPCMD_VERIFY_10:
case GPCMD_WRITE_10:
case GPCMD_WRITE_AND_VERIFY_10:
shdc[id].sector_len = (cdb[7] << 8) | cdb[8];
shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos);
break;
case GPCMD_VERIFY_12:
case GPCMD_WRITE_12:
case GPCMD_WRITE_AND_VERIFY_12:
shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
break;
@@ -1634,6 +1650,63 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb)
ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1);
return;
case GPCMD_WRITE_SAME_10:
if ((cdb[1] & 6) == 6)
{
scsi_hd_invalid_field(id);
return;
}
if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp)
{
scsi_hd_write_protected(id);
return;
}
shdc[id].sector_len = (cdb[7] << 8) | cdb[8];
shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos);
if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector))
{
scsi_hd_lba_out_of_range(id);
return;
}
if ((!shdc[id].sector_len) || (*BufLen == 0))
{
SCSIPhase = SCSI_PHASE_STATUS;
ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0);
scsi_hd_log("SCSI HD %i: All done - callback set\n", id);
shdc[id].packet_status = CDROM_PHASE_COMPLETE;
shdc[id].callback = 20 * SCSI_TIME;
break;
}
max_len = 1;
shdc[id].requested_blocks = max_len;
alloc_length = shdc[id].packet_len = max_len << 9;
if ((*BufLen == -1) || (alloc_length < *BufLen))
{
*BufLen = alloc_length;
}
SCSIPhase = SCSI_PHASE_DATA_OUT;
if (shdc[id].requested_blocks > 1)
{
scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1);
}
else
{
scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1);
}
shdc[id].all_blocks_total = shdc[id].block_total;
ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1);
return;
case GPCMD_MODE_SENSE_6:
case GPCMD_MODE_SENSE_10:
SCSIPhase = SCSI_PHASE_DATA_IN;
@@ -2040,6 +2113,11 @@ void scsi_hd_phase_data_out(uint8_t id)
int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength;
uint32_t last_sector = hdd_image_get_last_sector(id);
uint32_t last_to_write = 0;
uint32_t c, h, s;
if (!*BufLen)
{
SCSIPhase = SCSI_PHASE_STATUS;
@@ -2050,9 +2128,15 @@ void scsi_hd_phase_data_out(uint8_t id)
switch (shdc[id].current_cdb[0])
{
case GPCMD_VERIFY_6:
case GPCMD_VERIFY_10:
case GPCMD_VERIFY_12:
break;
case GPCMD_WRITE_6:
case GPCMD_WRITE_10:
case GPCMD_WRITE_AND_VERIFY_10:
case GPCMD_WRITE_12:
case GPCMD_WRITE_AND_VERIFY_12:
if ((shdc[id].requested_blocks > 0) && (*BufLen > 0))
{
if (shdc[id].packet_len > *BufLen)
@@ -2065,6 +2149,34 @@ void scsi_hd_phase_data_out(uint8_t id)
}
}
break;
case GPCMD_WRITE_SAME_10:
if (!shdc[id].current_cdb[7] && !shdc[id].current_cdb[8])
last_to_write = last_sector;
else
last_to_write = shdc[id].sector_pos + shdc[id].sector_len - 1;
for (i = shdc[id].sector_pos; i <= last_to_write; i++) {
if (shdc[id].current_cdb[1] & 2) {
hdbufferb[0] = (i >> 24) & 0xff;
hdbufferb[1] = (i >> 16) & 0xff;
hdbufferb[2] = (i >> 8) & 0xff;
hdbufferb[3] = i & 0xff;
} else if (shdc[id].current_cdb[1] & 4) {
s = (i % hdd[id].spt);
h = ((i - s) / hdd[id].spt) % hdd[id].hpc;
c = ((i - s) / hdd[id].spt) / hdd[id].hpc;
hdbufferb[0] = (c >> 16) & 0xff;
hdbufferb[1] = (c >> 8) & 0xff;
hdbufferb[2] = c & 0xff;
hdbufferb[3] = h & 0xff;
hdbufferb[4] = (s >> 24) & 0xff;
hdbufferb[5] = (s >> 16) & 0xff;
hdbufferb[6] = (s >> 8) & 0xff;
hdbufferb[7] = s & 0xff;
}
hdd_image_write(id, i, 1, hdbufferb);
}
break;
case GPCMD_MODE_SELECT_6:
case GPCMD_MODE_SELECT_10:
in_data_length = *BufLen;