From 7095f329de976aebc69e0cb1326cab1fc954c79f Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 23 Nov 2017 21:32:21 +0100 Subject: [PATCH] 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. --- src/scsi/scsi.h | 3 ++ src/scsi/scsi_disk.c | 124 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 121 insertions(+), 6 deletions(-) diff --git a/src/scsi/scsi.h b/src/scsi/scsi.h index 092dd5650..1b209a316 100644 --- a/src/scsi/scsi.h +++ b/src/scsi/scsi.h @@ -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 diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 44c3ea2c2..62b521a47 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -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;