diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 12f302989..19871fef5 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -68,6 +68,9 @@ endif ifndef CIRRUS CIRRUS := n endif +ifndef NCR_SCSI +NCR_SCSI := n +endif ifndef NV_RIVA NV_RIVA := n endif @@ -87,6 +90,7 @@ endif ifeq ($(DEV_BUILD), y) DEV_BRANCH := y CIRRUS := y + NCR_SCSI := y NV_RIVA := y PAS16 := y endif @@ -201,6 +205,11 @@ CFLAGS += -DUSE_CIRRUS DEVBROBJ += vid_cl_gd.o vid_cl_gd_blit.o vid_cl_ramdac.o endif +ifeq ($(NCR_SCSI), y) +CFLAGS += -DUSE_NCR +DEVBROBJ += scsi_bus.o scsi_ncr5380.o +endif + ifeq ($(NV_RIVA), y) CFLAGS += -DUSE_RIVA DEVBROBJ += vid_nv_riva128.o diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index c1c214b7e..f0213633a 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.9 2017/10/05 + * Version: @(#)cdrom.c 1.0.11 2017/10/07 * * Author: Miran Grca, * Copyright 2016,2017 Miran Grca. @@ -30,8 +30,11 @@ #include "../disk/hdc.h" #include "../disk/hdc_ide.h" #include "../win/win.h" +#include "../win/win_cdrom_ioctl.h" #include "../win/plat_iodev.h" #include "cdrom.h" +#include "cdrom_image.h" +#include "cdrom_null.h" /* Bits of 'status' */ @@ -46,12 +49,6 @@ #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* Media change request */ -#define MODE_SELECT_PHASE_IDLE 0 -#define MODE_SELECT_PHASE_HEADER 1 -#define MODE_SELECT_PHASE_BLOCK_DESC 2 -#define MODE_SELECT_PHASE_PAGE_HEADER 3 -#define MODE_SELECT_PHASE_PAGE 4 - cdrom_t cdrom[CDROM_NUM]; cdrom_drive_t cdrom_drives[CDROM_NUM]; uint8_t atapi_cdrom_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -728,6 +725,7 @@ uint8_t cdrom_mode_sense_pages_saved[CDROM_NUM][0x40][0x40] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 0, 2, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } } }; +#define ENABLE_CDROM_LOG 0 int cdrom_do_log = 0; void cdrom_log(const char *format, ...) @@ -1510,11 +1508,7 @@ static void cdrom_data_command_finish(uint8_t id, int len, int block_len, int al } if (cdrom_request_length_is_zero(id) || (len == 0) || (cdrom_current_mode(id) == 0)) { - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - { - SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength = 0; - } - else + if (cdrom_drives[id].bus_type != CDROM_BUS_SCSI) { cdrom[id].init_length = 0; } @@ -1526,11 +1520,7 @@ static void cdrom_data_command_finish(uint8_t id, int len, int block_len, int al { if (direction == 0) { - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - { - SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength = alloc_len; - } - else + if (cdrom_drives[id].bus_type != CDROM_BUS_SCSI) { cdrom[id].init_length = alloc_len; } @@ -1566,6 +1556,7 @@ static void cdrom_sense_clear(int id, int command) static void cdrom_cmd_error(uint8_t id) { + SCSIPhase = SCSI_PHASE_STATUS; cdrom[id].error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; if (cdrom[id].unit_attention) { @@ -1580,6 +1571,7 @@ static void cdrom_cmd_error(uint8_t id) static void cdrom_unit_attention(uint8_t id) { + SCSIPhase = SCSI_PHASE_STATUS; cdrom[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; if (cdrom[id].unit_attention) { @@ -1925,7 +1917,7 @@ static int cdrom_read_dvd_structure(uint8_t id, int format, const uint8_t *packe case 0x00: /* Physical format information */ total_sectors = (uint64_t) cdrom_drives[id].handler->size(id); - if (layer != 0) + if (layer != 0) { cdrom_invalid_field(id); return 0; @@ -2247,12 +2239,14 @@ void cdrom_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) if ((cdrom_sense_key > 0) && ((cdrom[id].cd_status < CD_STATUS_PLAYING) || (cdrom[id].cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(id)) { + SCSIPhase = SCSI_PHASE_STATUS; buffer[2]=SENSE_ILLEGAL_REQUEST; buffer[12]=ASC_AUDIO_PLAY_OPERATION; buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; } else if ((cdrom_sense_key == 0) && (cdrom[id].cd_status >= CD_STATUS_PLAYING) && (cdrom[id].cd_status != CD_STATUS_STOPPED)) { + SCSIPhase = SCSI_PHASE_STATUS; buffer[2]=SENSE_ILLEGAL_REQUEST; buffer[12]=ASC_AUDIO_PLAY_OPERATION; buffer[13]=(cdrom[id].cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; @@ -2261,13 +2255,14 @@ void cdrom_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) { if (cdrom[id].unit_attention && (cdrom_sense_key == 0)) { + SCSIPhase = SCSI_PHASE_STATUS; buffer[2]=SENSE_UNIT_ATTENTION; buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; buffer[13]=0; } } - /* cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", id, cdbufferb[2], cdbufferb[12], cdbufferb[13]); */ + cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); if (buffer[2] == SENSE_UNIT_ATTENTION) { @@ -2327,7 +2322,7 @@ void cdrom_command(uint8_t id, uint8_t *cdb) char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; -#if 0 +#if 1 int CdbLength; #endif if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) @@ -2360,10 +2355,10 @@ void cdrom_command(uint8_t id, uint8_t *cdb) cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i, Unit attention: %i\n", id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, ins, cdrom[id].unit_attention); cdrom_log("CD-ROM %i: Request length: %04X\n", id, cdrom[id].request_length); -#if 0 +#if 1 for (CdbLength = 1; CdbLength < cdrom[id].cdb_len; CdbLength++) { - cdrom_log("CD-ROM %i: CDB[%d] = 0x%02X\n", id, CdbLength, cdb[CdbLength]); + cdrom_log("CD-ROM %i: CDB[%d] = %d\n", id, CdbLength, cdb[CdbLength]); } #endif } @@ -2380,6 +2375,7 @@ void cdrom_command(uint8_t id, uint8_t *cdb) switch (cdb[0]) { case GPCMD_TEST_UNIT_READY: + SCSIPhase = SCSI_PHASE_STATUS; cdrom_command_complete(id); break; @@ -2390,16 +2386,22 @@ void cdrom_command(uint8_t id, uint8_t *cdb) } cdrom[id].sector_pos = cdrom[id].sector_len = 0; cdrom_seek(id, 0); + SCSIPhase = SCSI_PHASE_STATUS; break; case GPCMD_REQUEST_SENSE: /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE should forget about the not ready, and report unit attention straight away. */ + SCSIPhase = SCSI_PHASE_DATA_IN; if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if (SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength < cdb[4]) + if (SCSI_BufferLength == -1) { - cdb[4] = SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength; + SCSI_BufferLength = cdb[4]; + } + if (SCSI_BufferLength < cdb[4]) + { + cdb[4] = SCSI_BufferLength; } } cdrom_request_sense(id, cdbufferb, cdb[4]); @@ -2408,12 +2410,20 @@ void cdrom_command(uint8_t id, uint8_t *cdb) case GPCMD_SET_SPEED: case GPCMD_SET_SPEED_ALT: + SCSIPhase = SCSI_PHASE_DATA_IN; cdrom_command_complete(id); break; case GPCMD_MECHANISM_STATUS: + SCSIPhase = SCSI_PHASE_DATA_IN; + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + memset(cdbufferb, 0, 8); cdbufferb[5] = 1; @@ -2423,6 +2433,8 @@ void cdrom_command(uint8_t id, uint8_t *cdb) case GPCMD_READ_TOC_PMA_ATIP: cdrom[id].toctimes++; + SCSIPhase = SCSI_PHASE_DATA_IN; + max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; @@ -2436,6 +2448,13 @@ void cdrom_command(uint8_t id, uint8_t *cdb) cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; goto cdrom_readtoc_fallback; } + else + { + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + } alloc_length = cdbufferb[0]; alloc_length <<= 8; alloc_length |= cdbufferb[1]; @@ -2481,6 +2500,11 @@ cdrom_readtoc_fallback: cdbufferb[1] = (len - 2) & 0xff; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, len, 0); /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", id, toc_format, ide->cylinder, cdbufferb[1]); */ return; @@ -2492,6 +2516,8 @@ cdrom_readtoc_fallback: case GPCMD_READ_12: case GPCMD_READ_CD: case GPCMD_READ_CD_MSF: + SCSIPhase = SCSI_PHASE_DATA_IN; + switch(cdb[0]) { case GPCMD_READ_6: @@ -2531,6 +2557,7 @@ cdrom_readtoc_fallback: if (!cdrom[id].sector_len) { + SCSIPhase = SCSI_PHASE_STATUS; /* cdrom_log("CD-ROM %i: All done - callback set\n", id); */ cdrom[id].packet_status = CDROM_PHASE_COMPLETE; cdrom[id].callback = 20 * CDROM_TIME; @@ -2555,6 +2582,12 @@ cdrom_readtoc_fallback: } cdrom[id].packet_len = max_len * alloc_length; + + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = cdrom[id].packet_len; + } + if (cdrom[id].requested_blocks > 1) { cdrom_data_command_finish(id, alloc_length, alloc_length / cdrom[id].requested_blocks, alloc_length, 0); @@ -2575,6 +2608,8 @@ cdrom_readtoc_fallback: return; case GPCMD_READ_HEADER: + SCSIPhase = SCSI_PHASE_DATA_IN; + if (cdrom_drives[id].handler->pass_through) { ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); @@ -2582,6 +2617,13 @@ cdrom_readtoc_fallback: { return; } + else + { + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + } } else { @@ -2605,11 +2647,18 @@ cdrom_readtoc_fallback: len = 8; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, len, 0); return; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: + SCSIPhase = SCSI_PHASE_DATA_IN; + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; @@ -2679,6 +2728,11 @@ cdrom_readtoc_fallback: alloc_length = len; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = alloc_length; + } + cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", id, cdb[2]); cdrom_data_command_finish(id, len, len, alloc_length, 0); @@ -2686,6 +2740,8 @@ cdrom_readtoc_fallback: case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: + SCSIPhase = SCSI_PHASE_DATA_OUT; + if (cdb[0] == GPCMD_MODE_SELECT_6) { len = cdb[4]; @@ -2695,12 +2751,19 @@ cdrom_readtoc_fallback: len = (cdb[7] << 8) | cdb[8]; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + ret = cdrom_mode_select_init(id, cdb[0], len, cdb[1] & 1); cdrom_data_command_finish(id, len, len, len, 1); return; case GPCMD_GET_CONFIGURATION: + SCSIPhase = SCSI_PHASE_DATA_IN; + /* XXX: could result in alignment problems in some architectures */ len = (cdb[7] << 8) | cdb[8]; alloc_length = len; @@ -2750,10 +2813,17 @@ cdrom_readtoc_fallback: cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; cdbufferb[3] = (alloc_length - 4) & 0xff; + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, alloc_length, 0); break; case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + SCSIPhase = SCSI_PHASE_DATA_IN; + gesn_cdb = (void *) cdb; gesn_event_header = (void *) cdbufferb; @@ -2802,10 +2872,17 @@ cdrom_readtoc_fallback: } gesn_event_header->len = used_len - sizeof(*gesn_event_header); + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = used_len; + } + cdrom_data_command_finish(id, used_len, used_len, used_len, 0); break; case GPCMD_READ_DISC_INFORMATION: + SCSIPhase = SCSI_PHASE_DATA_IN; + max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; @@ -2839,10 +2916,18 @@ cdrom_readtoc_fallback: len=34; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, max_len, 0); + SCSIPhase = BUS_IO; break; case GPCMD_READ_TRACK_INFORMATION: + SCSIPhase = SCSI_PHASE_DATA_IN; + max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; @@ -2899,13 +2984,21 @@ cdrom_readtoc_fallback: } } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, max_len, 0); + SCSIPhase = BUS_IO; break; case GPCMD_PLAY_AUDIO_10: case GPCMD_PLAY_AUDIO_12: case GPCMD_PLAY_AUDIO_MSF: case GPCMD_PLAY_AUDIO_TRACK_INDEX: + SCSIPhase = SCSI_PHASE_STATUS; + switch(cdb[0]) { case GPCMD_PLAY_AUDIO_10: @@ -2952,6 +3045,8 @@ cdrom_readtoc_fallback: break; case GPCMD_READ_SUBCHANNEL: + SCSIPhase = SCSI_PHASE_DATA_IN; + max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; @@ -3058,10 +3153,17 @@ cdrom_readtoc_fallback: } } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, max_len, 0); break; case GPCMD_READ_DVD_STRUCTURE: + SCSIPhase = SCSI_PHASE_DATA_IN; + if (cdrom_drives[id].handler->pass_through) { ret = cdrom_pass_through(id, &len, cdrom[id].current_cdb, cdbufferb); @@ -3069,6 +3171,13 @@ cdrom_readtoc_fallback: { return; } + else + { + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + } } else { @@ -3114,6 +3223,11 @@ cdrom_readtoc_fallback: { ret = cdrom_read_dvd_structure(id, format, cdb, cdbufferb); + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = alloc_length; + } + if (ret) { cdrom_data_command_finish(id, len, len, alloc_length, 0); @@ -3137,6 +3251,8 @@ cdrom_readtoc_fallback: break; case GPCMD_START_STOP_UNIT: + SCSIPhase = SCSI_PHASE_STATUS; + switch(cdb[4] & 3) { case 0: /* Stop the disc. */ @@ -3164,6 +3280,8 @@ cdrom_readtoc_fallback: break; case GPCMD_INQUIRY: + SCSIPhase = SCSI_PHASE_DATA_IN; + max_len = cdb[3]; max_len <<= 8; max_len |= cdb[4]; @@ -3242,15 +3360,23 @@ atapi_out: cdbufferb[size_idx] = idx - preamble_len; len=idx; + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, max_len, 0); break; case GPCMD_PREVENT_REMOVAL: + SCSIPhase = SCSI_PHASE_STATUS; cdrom_command_complete(id); break; case GPCMD_PAUSE_RESUME_ALT: case GPCMD_PAUSE_RESUME: + SCSIPhase = SCSI_PHASE_STATUS; + if (cdb[8] & 1) { if (cdrom_drives[id].handler->resume) @@ -3280,6 +3406,8 @@ atapi_out: case GPCMD_SEEK_6: case GPCMD_SEEK_10: + SCSIPhase = SCSI_PHASE_STATUS; + switch(cdb[0]) { case GPCMD_SEEK_6: @@ -3294,15 +3422,24 @@ atapi_out: break; case GPCMD_READ_CDROM_CAPACITY: + SCSIPhase = SCSI_PHASE_DATA_IN; + if (cdrom_read_capacity(id, cdrom[id].current_cdb, cdbufferb, &len) == 0) { return; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + cdrom_data_command_finish(id, len, len, len, 0); break; case GPCMD_STOP_PLAY_SCAN: + SCSIPhase = SCSI_PHASE_STATUS; + if (cdrom_drives[id].handler->stop) { cdrom_drives[id].handler->stop(id); @@ -3495,8 +3632,8 @@ int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) return 0; } - cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSIDevices[scsi_id][scsi_lun].InitLength); - memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, SCSIDevices[scsi_id][scsi_lun].InitLength); + cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSI_BufferLength); + memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, SCSI_BufferLength); return 1; } @@ -3525,7 +3662,7 @@ int cdrom_read_from_dma(uint8_t id) if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - in_data_length = SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].InitLength; + in_data_length = SCSI_BufferLength; cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", id, in_data_length); } else @@ -3618,8 +3755,8 @@ int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) cdbufferb = (uint8_t *) cdrom[id].buffer; - cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSIDevices[scsi_id][scsi_lun].InitLength); - memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, SCSIDevices[scsi_id][scsi_lun].InitLength); + cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSI_BufferLength); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, SCSI_BufferLength); cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); return 1; @@ -3859,3 +3996,41 @@ void cdrom_write(uint8_t channel, uint32_t val, int length) return; } } + +void cdrom_hard_reset(void) +{ + int i = 0; + + for (i=0; i= 'A') && (cdrom_drives[i].host_drive <= 'Z')) + { + ioctl_reset(i); + } + } +} + +void cdrom_general_init(void) +{ + int c = 0; + + cdrom_init_host_drives(); + + for (c=0; c='A') && (cdrom_drives[c].host_drive <= 'Z')) + { + ioctl_open(c, cdrom_drives[c].host_drive); + } else { + cdrom_null_open(c, cdrom_drives[c].host_drive); + } + } +} diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index bd1d99783..7524dbf2c 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -242,5 +242,8 @@ int cdrom_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len #define cdrom_ascq cdrom[id].sense[13] #define cdrom_drive cdrom_drives[id].host_drive +void cdrom_hard_reset(void); +void cdrom_general_init(void); + #endif /*EMU_CDROM_H*/ diff --git a/src/floppy/floppy.c b/src/floppy/floppy.c index 5b1dabdc3..b451067e7 100644 --- a/src/floppy/floppy.c +++ b/src/floppy/floppy.c @@ -409,3 +409,18 @@ void floppy_stop(int drive) if (drives[drive].stop) drives[drive].stop(drive); } + +void floppy_general_init(void) +{ + floppy_init(); + fdi_init(); + img_init(); + d86f_init(); + td0_init(); + imd_init(); + + floppy_load(0, floppyfns[0]); + floppy_load(1, floppyfns[1]); + floppy_load(2, floppyfns[2]); + floppy_load(3, floppyfns[3]); +} diff --git a/src/floppy/floppy.h b/src/floppy/floppy.h index 0e1d93c88..cdc637b4d 100644 --- a/src/floppy/floppy.h +++ b/src/floppy/floppy.h @@ -49,6 +49,7 @@ extern void floppy_load(int drive, wchar_t *fn); extern void floppy_new(int drive, char *fn); extern void floppy_close(int drive); extern void floppy_init(void); +extern void floppy_general_init(void); extern void floppy_reset(void); extern void floppy_poll(int drive); extern void floppy_poll_0(void* priv); diff --git a/src/pc.c b/src/pc.c index e406371d1..4eadd309a 100644 --- a/src/pc.c +++ b/src/pc.c @@ -35,9 +35,6 @@ #include "random.h" #include "device.h" #include "cdrom/cdrom.h" -#include "cdrom/cdrom_image.h" -#include "cdrom/cdrom_ioctl.h" -#include "cdrom/cdrom_null.h" #include "disk/hdd.h" #include "disk/hdc.h" #include "disk/hdc_ide.h" @@ -439,26 +436,7 @@ again2: ide_init_first(); -#if 1 - /* should be in cdrom.c */ - cdrom_init_host_drives(); - - for (c=0; c='A') && (cdrom_drives[c].host_drive <= 'Z')) - { - ioctl_open(c, cdrom_drives[c].host_drive); - } else { - cdrom_null_open(c, cdrom_drives[c].host_drive); - } - } -#endif + cdrom_general_init(); device_init(); @@ -466,22 +444,9 @@ again2: sound_reset(); -#if 1 - /* This should be in floppy.c and fdc.c --FvK */ fdc_init(); - floppy_init(); - fdi_init(); - img_init(); - d86f_init(); - td0_init(); - imd_init(); - - floppy_load(0, floppyfns[0]); - floppy_load(1, floppyfns[1]); - floppy_load(2, floppyfns[2]); - floppy_load(3, floppyfns[3]); -#endif + floppy_general_init(); sound_init(); @@ -489,14 +454,7 @@ again2: ide_reset(); - for (i=0; i= 'A') && (cdrom_drives[i].host_drive <= 'Z')) { - ioctl_reset(i); - } - } + cdrom_hard_reset(); scsi_card_init(); @@ -566,8 +524,6 @@ pc_reset_hard_close(void) void pc_reset_hard_init(void) { - int i; - /* First, we reset the modules that are not part of the * actual machine, but which support some of the modules * that are. @@ -662,15 +618,7 @@ pc_reset_hard_init(void) shadowbios = 0; cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; - for (i=0; i= 'A') && (cdrom_drives[i].host_drive <= 'Z')) - { - ioctl_reset(i); - } - } + cdrom_hard_reset(); } diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index b4b41de44..413313f54 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,7 +8,7 @@ * * Handling of the SCSI controllers. * - * Version: @(#)scsi.c 1.0.7 2017/10/03 + * Version: @(#)scsi.c 1.0.8 2017/10/07 * * Authors: TheCollector1995, * Miran Grca, @@ -30,10 +30,15 @@ #include "scsi.h" #include "scsi_aha154x.h" #include "scsi_buslogic.h" +#ifdef DEV_BRANCH +#ifdef USE_NCR +#include "scsi_ncr5380.h" +#endif +#endif scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; -uint8_t SCSIPhase = SCSI_PHASE_BUS_FREE; +uint8_t SCSIPhase = 0xff; uint8_t SCSIStatus = SCSI_STATUS_OK; uint8_t scsi_cdrom_id = 3; /*common setting*/ char scsi_fn[SCSI_NUM][512]; @@ -42,6 +47,8 @@ uint16_t scsi_hd_location[SCSI_NUM]; int scsi_card_current = 0; int scsi_card_last = 0; +uint32_t SCSI_BufferLength; + typedef struct { char name[64]; @@ -59,6 +66,13 @@ static SCSI_CARD scsi_cards[] = { { "Adaptec AHA-1640", "aha1640", &aha1640_device, aha_device_reset }, { "BusLogic BT-545C", "bt545c", &buslogic_device, BuslogicDeviceReset }, { "BusLogic BT-958D PCI", "bt958d", &buslogic_pci_device, BuslogicDeviceReset }, +#ifdef DEV_BRANCH +#ifdef USE_NCR + { "Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device,NULL }, + { "Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, NULL }, + { "Trantor T130B", "t130b", &scsi_t130b_device, NULL }, +#endif +#endif { "", "", NULL, NULL }, }; diff --git a/src/scsi/scsi.h b/src/scsi/scsi.h index ff8863753..d48ec206c 100644 --- a/src/scsi/scsi.h +++ b/src/scsi/scsi.h @@ -8,7 +8,7 @@ * * SCSI controller handler header. * - * Version: @(#)scsi_h 1.0.6 2017/10/04 + * Version: @(#)scsi_h 1.0.7 2017/10/07 * * Authors: TheCollector1995, * Miran Grca, @@ -211,15 +211,6 @@ extern uint8_t page_current; #define PAGE_CHANGEABLE 1 #define PAGE_CHANGED 2 - -extern uint32_t DataLength; -extern uint32_t DataPointer; - -extern int SectorLBA; -extern int SectorLen; - -extern int MediaPresent; - extern uint8_t SCSIStatus; extern uint8_t SCSIPhase; extern uint8_t scsi_cdrom_id; @@ -242,21 +233,37 @@ extern int prev_status; #define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) -#define SCSI_PHASE_DATAOUT ( 0 ) -#define SCSI_PHASE_DATAIN ( 1 ) -#define SCSI_PHASE_COMMAND ( 2 ) -#define SCSI_PHASE_STATUS ( 3 ) -#define SCSI_PHASE_MESSAGE_OUT ( 6 ) -#define SCSI_PHASE_MESSAGE_IN ( 7 ) -#define SCSI_PHASE_BUS_FREE ( 8 ) -#define SCSI_PHASE_SELECT ( 9 ) +#define MSG_COMMAND_COMPLETE 0x00 +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +extern uint32_t SCSI_BufferLength; typedef struct { uint8_t *CmdBuffer; - uint32_t CmdBufferLength; int LunType; - uint32_t InitLength; } scsi_device_t; @@ -337,4 +344,10 @@ typedef struct { #pragma pack(pop) +#define MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + #endif /*EMU_SCSI_H*/ diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 1a344343f..1759662fa 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -12,11 +12,10 @@ * * NOTE: THIS IS CURRENTLY A MESS, but will be cleaned up as I go. * - * Version: @(#)scsi_aha154x.c 1.0.21 2017/10/07 + * Version: @(#)scsi_aha154x.c 1.0.22 2017/10/08 * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. - * * Copyright 2017 Fred N. van Kempen. */ #include @@ -852,7 +851,7 @@ aha_buf_alloc(Req_t *req, int Is24bit) aha_log("Data to transfer (S/G) %d\n", DataToTransfer); - SCSIDevices[req->TargetID][req->LUN].InitLength = DataToTransfer; + SCSI_BufferLength = DataToTransfer; aha_log("Allocating buffer for Scatter/Gather (%i bytes)\n", DataToTransfer); SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); @@ -891,7 +890,7 @@ aha_buf_alloc(Req_t *req, int Is24bit) req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { Address = DataPointer; - SCSIDevices[req->TargetID][req->LUN].InitLength = DataLength; + SCSI_BufferLength = DataLength; aha_log("Allocating buffer for direct transfer (%i bytes)\n", DataLength); SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); @@ -900,7 +899,7 @@ aha_buf_alloc(Req_t *req, int Is24bit) if (DataLength > 0) { DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, - SCSIDevices[req->TargetID][req->LUN].InitLength); + SCSI_BufferLength); } } } @@ -933,7 +932,7 @@ aha_buf_free(Req_t *req) if ((DataLength != 0) && (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY)) { aha_log("Data length not 0 with TEST UNIT READY: %i (%i)\n", - DataLength, SCSIDevices[req->TargetID][req->LUN].InitLength); + DataLength, SCSI_BufferLength); } if (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) { @@ -988,9 +987,9 @@ aha_buf_free(Req_t *req) if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { /* Should be 0 when scatter/gather? */ - if (DataLength >= SCSIDevices[req->TargetID][req->LUN].InitLength) { + if (DataLength >= SCSI_BufferLength) { Residual = DataLength; - Residual -= SCSIDevices[req->TargetID][req->LUN].InitLength; + Residual -= SCSI_BufferLength; } else { Residual = 0; } @@ -1143,7 +1142,7 @@ aha_req_setup(aha_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) aha_log("Scanning SCSI Target ID %i\n", id); SCSIStatus = SCSI_STATUS_OK; - SCSIDevices[id][lun].InitLength = 0; + SCSI_BufferLength = 0; aha_buf_alloc(req, req->Is24bit); @@ -2043,6 +2042,7 @@ aha_init(device_t *info) case AHA_154xC: strcpy(dev->name, "AHA-154xC"); dev->bios_path = L"roms/scsi/adaptec/aha1542c102.bin"; + dev->nvr_path = L"aha1540c.nvr"; dev->bid = 'D'; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ @@ -2119,8 +2119,6 @@ aha_close(void *priv) if (dev) { - dev->MailboxCount = 0; - if (dev->evt) { thread_destroy_event(dev->evt); dev->evt = NULL; @@ -2249,9 +2247,15 @@ static device_config_t aha_154x_config[] = { device_t aha1540b_device = { "Adaptec AHA-1540B", - 0, AHA_154xB, - aha_init, aha_close, NULL, - NULL, NULL, NULL, NULL, + 0, + AHA_154xB, + aha_init, + aha_close, + NULL, + NULL, + NULL, + NULL, + NULL, aha_154x_config }; @@ -2259,8 +2263,13 @@ device_t aha1542c_device = { "Adaptec AHA-1542C", 0, AHA_154xC, - aha_init, aha_close, NULL, - NULL, NULL, NULL, NULL, + aha_init, + aha_close, + NULL, + NULL, + NULL, + NULL, + NULL, aha_154x_config }; @@ -2268,8 +2277,13 @@ device_t aha1542cf_device = { "Adaptec AHA-1542CF", 0, AHA_154xCF, - aha_init, aha_close, NULL, - NULL, NULL, NULL, NULL, + aha_init, + aha_close, + NULL, + NULL, + NULL, + NULL, + NULL, aha_154x_config }; @@ -2277,7 +2291,11 @@ device_t aha1640_device = { "Adaptec AHA-1640", DEVICE_MCA, AHA_1640, - aha_init, aha_close, NULL, - NULL, NULL, NULL, NULL, + aha_init, + aha_close, + NULL, + NULL, + NULL, + NULL, NULL }; diff --git a/src/scsi/scsi_bios_command.c b/src/scsi/scsi_bios_command.c index 53463cbcb..24cfe95f7 100644 --- a/src/scsi/scsi_bios_command.c +++ b/src/scsi/scsi_bios_command.c @@ -8,7 +8,7 @@ * * The shared AHA and Buslogic SCSI BIOS command handler. * - * Version: @(#)scsi_bios_command.c 1.0.3 2017/10/04 + * Version: @(#)scsi_bios_command.c 1.0.4 2017/10/07 * * Authors: TheCollector1995, * Miran Grca, @@ -200,7 +200,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) /* Get pointer to selected device. */ dev = &SCSIDevices[cmd->id][cmd->lun]; - dev->InitLength = 0; + SCSI_BufferLength = 0; if (! scsi_device_present(cmd->id, cmd->lun)) { cmd_log("BIOS Target ID %i and LUN %i have no device attached\n", @@ -232,7 +232,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) * length for SCSI sense, and no command-specific * indication is given. */ - dev->InitLength = 14; + SCSI_BufferLength = 14; dev->CmdBuffer = (uint8_t *)malloc(14); memset(dev->CmdBuffer, 0x00, 14); @@ -257,9 +257,9 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x02: /* Read Desired Sectors to Memory */ target_check(cmd->id, cmd->lun); - dev->InitLength = sector_len << block_shift; - dev->CmdBuffer = (uint8_t *)malloc(dev->InitLength); - memset(dev->CmdBuffer, 0x00, dev->InitLength); + SCSI_BufferLength = sector_len << block_shift; + dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); + memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); cdb[0] = GPCMD_READ_10; cdb[1] = (cmd->lun & 7) << 5; @@ -276,9 +276,9 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) scsi_device_command(cmd->id, cmd->lun, 12, cdb); if (sector_len > 0) { cmd_log("BIOS DMA: Reading %i bytes at %08X\n", - dev->InitLength, dma_address); + SCSI_BufferLength, dma_address); DMAPageWrite(dma_address, - (char *)dev->CmdBuffer, dev->InitLength); + (char *)dev->CmdBuffer, SCSI_BufferLength); } if (dev->CmdBuffer != NULL) { @@ -291,15 +291,15 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x03: /* Write Desired Sectors from Memory */ target_check(cmd->id, cmd->lun); - dev->InitLength = sector_len << block_shift; - dev->CmdBuffer = (uint8_t *)malloc(dev->InitLength); - memset(dev->CmdBuffer, 0x00, dev->InitLength); + SCSI_BufferLength = sector_len << block_shift; + dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); + memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); if (sector_len > 0) { cmd_log("BIOS DMA: Reading %i bytes at %08X\n", - dev->InitLength, dma_address); + SCSI_BufferLength, dma_address); DMAPageRead(dma_address, - (char *)dev->CmdBuffer, dev->InitLength); + (char *)dev->CmdBuffer, SCSI_BufferLength); } cdb[0] = GPCMD_WRITE_10; @@ -360,15 +360,15 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x08: /* Read Drive Parameters */ target_check(cmd->id, cmd->lun); - dev->InitLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(dev->InitLength); - memset(dev->CmdBuffer, 0x00, dev->InitLength); + SCSI_BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); + memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); ret = scsi_bios_command_08(cmd->id, cmd->lun, dev->CmdBuffer); cmd_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); DMAPageWrite(dma_address, - (char *)dev->CmdBuffer, dev->InitLength); + (char *)dev->CmdBuffer, SCSI_BufferLength); if (dev->CmdBuffer != NULL) { free(dev->CmdBuffer); @@ -385,7 +385,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) target_check(cmd->id, cmd->lun); //FIXME: is this needed? Looks like a copy-paste leftover.. --FvK - dev->InitLength = sector_len << block_shift; + SCSI_BufferLength = sector_len << block_shift; cdb[0] = GPCMD_SEEK_10; cdb[1] = (cmd->lun & 7) << 5; @@ -429,15 +429,15 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x15: /* Read DASD Type */ target_check(cmd->id, cmd->lun); - dev->InitLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(dev->InitLength); - memset(dev->CmdBuffer, 0x00, dev->InitLength); + SCSI_BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); + memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); ret = scsi_bios_command_15(cmd->id, cmd->lun, dev->CmdBuffer); cmd_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); DMAPageWrite(dma_address, - (char *)dev->CmdBuffer, dev->InitLength); + (char *)dev->CmdBuffer, SCSI_BufferLength); if (dev->CmdBuffer != NULL) { free(dev->CmdBuffer); diff --git a/src/scsi/scsi_bus.c b/src/scsi/scsi_bus.c new file mode 100644 index 000000000..05145e7fd --- /dev/null +++ b/src/scsi/scsi_bus.c @@ -0,0 +1,363 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * The generic SCSI bus operations handler. + * + * Version: @(#)scsi_bus.c 1.0.1 2017/10/04 + * + * NOTES: For now ported from PCem with some modifications + * but at least it's a start. + * + * Authors: TheCollector1995, + */ +#include +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "scsi.h" +#include "scsi_device.h" + +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_COMMANDWAIT 2 +#define STATE_DATAIN 3 +#define STATE_DATAOUT 4 +#define STATE_STATUS 5 +#define STATE_MESSAGEIN 6 +#define STATE_PHASESEL 7 + +#define SET_BUS_STATE(bus, state) bus->bus_out = (bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) + +uint32_t SCSI_BufferLength; + +#define ENABLE_SCSI_BUS_LOG 0 +int scsi_bus_do_log = 0; + + +void scsi_bus_log(const char *format, ...) +{ +#ifdef ENABLE_SCSI_BUS_LOG + if (scsi_bus_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + + +/* get the length of a SCSI command based on its command byte type */ +static int get_cmd_len(int cbyte) +{ + int len; + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) len = 6; + if (group == 1 || group == 2) len = 10; + if (group == 5) len = 12; + + //scsi_bus_log("Command group %d, length %d\n", group, len); + + return len; +} + +static int get_dev_id(uint8_t data) +{ + int c; + + for (c = 0; c < SCSI_ID_MAX; c++) + { + if (data & (1 << c)) + { + return c; + } + } + + return -1; +} + +int scsi_bus_update(scsi_bus_t *bus, int bus_assert) +{ + scsi_device_t *dev; + uint8_t lun = 0; + + dev = &SCSIDevices[bus->dev_id][0]; + + if (bus_assert & BUS_ARB) + bus->state = STATE_IDLE; + + dev->CmdBuffer = (uint8_t *)bus->buffer; + + switch (bus->state) + { + case STATE_IDLE: + scsi_bus_log("State Idle\n"); + bus->clear_req = bus->change_state_delay = bus->new_req_delay = 0; + if ((bus_assert & BUS_SEL) && !(bus_assert & BUS_BSY)) + { + uint8_t sel_data = BUS_GETDATA(bus_assert); + + bus->dev_id = get_dev_id(sel_data); + if (scsi_device_present(bus->dev_id, 0)) + { + bus->bus_out |= BUS_BSY; + bus->state = STATE_PHASESEL; + } + //scsi_bus_log("Device id %i\n", bus->dev_id); + break; + } + break; + + case STATE_PHASESEL: + scsi_bus_log("State Phase Sel\n"); + if (!(bus_assert & BUS_SEL)) + { + if (!(bus_assert & BUS_ATN)) + { + if (scsi_device_present(bus->dev_id, 0)) + { + bus->state = STATE_COMMAND; + bus->bus_out = BUS_BSY | BUS_REQ; + bus->command_pos = 0; + SET_BUS_STATE(bus, SCSI_PHASE_COMMAND); + } + else + { + bus->state = STATE_IDLE; + bus->bus_out = 0; + } + } + else + fatal("dropped sel %x\n", bus_assert & BUS_ATN); + } + break; + + case STATE_COMMAND: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + scsi_bus_log("State Command\n"); + bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert); + + bus->clear_req = 3; + bus->new_state = bus->bus_out & SCSI_PHASE_MESSAGE_IN; + bus->bus_out &= ~BUS_REQ; + + if (get_cmd_len(bus->command[0]) == bus->command_pos) + { + lun = (bus->command[1] >> 5) & 7; + bus->data_pos = 0; + + scsi_bus_log("Command 0x%02X\n", bus->command[0]); + + SCSI_BufferLength = -1; + scsi_device_command_phase0(bus->dev_id, lun, get_cmd_len(bus->command[0]), bus->command); + + if (SCSIPhase == SCSI_PHASE_DATA_OUT) + { + /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ + scsi_bus_log("Next state is data out\n"); + + bus->state = STATE_COMMANDWAIT; + bus->clear_req = 0; + } + else + { + /* Other command - execute immediately. */ + scsi_bus_log("Next state is defined by command\n"); + bus->new_state = SCSIPhase; + + bus->change_state_delay = 4; + } + } + } + break; + + case STATE_COMMANDWAIT: + bus->new_state = SCSI_PHASE_DATA_OUT; + bus->change_state_delay = 4; + bus->clear_req = 4; + break; + + case STATE_DATAIN: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + scsi_bus_log("State Data In\n"); + + /* This seems to be read, so we first execute the command, then we return the bytes to the host. */ + + if (bus->data_pos >= SCSI_BufferLength) + { + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_STATUS; + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } + else + { + uint8_t val = dev->CmdBuffer[bus->data_pos++]; + + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; + bus->clear_req = 3; + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_DATA_IN; + } + } + break; + + case STATE_DATAOUT: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + scsi_bus_log("State Data Out\n"); + + /* This is write, so first get the data from the host, then execute the last phase of the command. */ + dev->CmdBuffer[bus->data_pos++] = BUS_GETDATA(bus_assert); + + if (bus->data_pos >= SCSI_BufferLength) + { + /* pclog("%04X bytes written (%02X %02X)\n", bus->data_pos, bus->command[0], bus->command[1]); */ + scsi_bus_log("Actually executing write command\n"); + lun = (bus->command[1] >> 5) & 7; + bus->bus_out &= ~BUS_REQ; + scsi_device_command_phase1(bus->dev_id, lun); + bus->new_state = SCSI_PHASE_STATUS; + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } + else + { + bus->bus_out |= BUS_REQ; + } + } + break; + + case STATE_STATUS: + scsi_bus_log("State Status\n"); + + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + /* pclog("Preparing for message in\n"); */ + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_MESSAGE_IN; + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } + break; + + case STATE_MESSAGEIN: + scsi_bus_log("State Message In\n"); + + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + bus->bus_out &= ~BUS_REQ; + bus->new_state = BUS_IDLE; + bus->change_state_delay = 4; + } + break; + } + bus->bus_in = bus_assert; + + return bus->bus_out | bus->bus_in; +} + +int scsi_bus_read(scsi_bus_t *bus) +{ + scsi_device_t *dev; + + dev = &SCSIDevices[bus->dev_id][0]; + + dev->CmdBuffer = (uint8_t *)bus->buffer; + + if (bus->clear_req) + { + bus->clear_req--; + if (!bus->clear_req) + { + scsi_bus_log("Clear REQ\n"); + + SET_BUS_STATE(bus, bus->new_state); + bus->bus_out |= BUS_REQ; + } + } + + if (bus->change_state_delay) + { + bus->change_state_delay--; + if (!bus->change_state_delay) + { + uint8_t val; + + scsi_bus_log("Change state delay\n"); + + SET_BUS_STATE(bus, bus->new_state); + + switch (bus->bus_out & SCSI_PHASE_MESSAGE_IN) + { + case SCSI_PHASE_DATA_IN: + scsi_bus_log("Phase data in\n"); + bus->state = STATE_DATAIN; + val = dev->CmdBuffer[bus->data_pos++]; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP; + break; + + case SCSI_PHASE_DATA_OUT: + scsi_bus_log("Phase data out\n"); + if (bus->new_state & BUS_IDLE) + { + bus->state = STATE_IDLE; + bus->bus_out &= ~BUS_BSY; + } + else + { + bus->state = STATE_DATAOUT; + } + break; + + case SCSI_PHASE_STATUS: + scsi_bus_log("Phase status\n"); + bus->state = STATE_STATUS; + bus->bus_out |= BUS_REQ; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(SCSIStatus) | BUS_DBP; + /* pclog("SCSI Status (command %02X): %02X (%08X)\n", bus->command[0], SCSIStatus, bus->bus_out); */ + break; + + case SCSI_PHASE_MESSAGE_IN: + scsi_bus_log("Phase message in\n"); + /* pclog("Message in\n"); */ + bus->state = STATE_MESSAGEIN; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + break; + + default: + fatal("change_state_delay bad state %x\n", bus->bus_out); + } + } + } + if (bus->new_req_delay) + { + bus->new_req_delay--; + if (!bus->new_req_delay) + { + bus->bus_out |= BUS_REQ; + } + } + + return bus->bus_out; +} + +int scsi_bus_match(scsi_bus_t *bus, int bus_assert) +{ + return (bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) == (bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)); +} diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 3112b8a3c..2c9724636 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -10,12 +10,11 @@ * 0 - BT-545C ISA; * 1 - BT-958D PCI (but BT-545C ISA on non-PCI machines) * - * Version: @(#)scsi_buslogic.c 1.0.17 2017/10/07 + * Version: @(#)scsi_buslogic.c 1.0.18 2017/10/08 * * Authors: TheCollector1995, * Miran Grca, * Fred N. van Kempen, - * * Copyright 2016,2017 Miran Grca. * Copyright 2017 Fred N. van Kempen. */ @@ -42,7 +41,7 @@ #include "scsi_buslogic.h" -#define BUSLOGIC_RESET_DURATION_US UINT64_C(50) +#define BUSLOGIC_RESET_DURATION_US UINT64_C(5000) /* @@ -1020,7 +1019,7 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) pclog("Data to transfer (S/G) %d\n", DataToTransfer); - SCSIDevices[req->TargetID][req->LUN].InitLength = DataToTransfer; + SCSI_BufferLength = DataToTransfer; SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); @@ -1060,7 +1059,7 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { uint32_t Address = DataPointer; - SCSIDevices[req->TargetID][req->LUN].InitLength = DataLength; + SCSI_BufferLength = DataLength; SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); @@ -1068,7 +1067,7 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) if (DataLength > 0) { DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, - SCSIDevices[req->TargetID][req->LUN].InitLength); + SCSI_BufferLength); } } } @@ -1100,7 +1099,7 @@ BuslogicDataBufferFree(Req_t *req) if ((DataLength != 0) && (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY)) { pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", - DataLength, SCSIDevices[req->TargetID][req->LUN].InitLength); + DataLength, SCSI_BufferLength); } if (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) { @@ -1157,9 +1156,9 @@ BuslogicDataBufferFree(Req_t *req) if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { /* Should be 0 when scatter/gather? */ - if (DataLength >= SCSIDevices[req->TargetID][req->LUN].InitLength) { + if (DataLength >= SCSI_BufferLength) { Residual = DataLength; - Residual -= SCSIDevices[req->TargetID][req->LUN].InitLength; + Residual -= SCSI_BufferLength; } else { Residual = 0; } @@ -1219,7 +1218,7 @@ BuslogicSCSIBIOSDataBufferAllocate(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LU { uint32_t Address = DataPointer; - SCSIDevices[TargetID][LUN].InitLength = DataLength; + SCSI_BufferLength = DataLength; SCSIDevices[TargetID][LUN].CmdBuffer = (uint8_t *) malloc(DataLength); memset(SCSIDevices[TargetID][LUN].CmdBuffer, 0, DataLength); @@ -1227,7 +1226,7 @@ BuslogicSCSIBIOSDataBufferAllocate(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LU if (DataLength > 0) { DMAPageRead(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, - SCSIDevices[TargetID][LUN].InitLength); + SCSI_BufferLength); } } } @@ -1245,7 +1244,7 @@ BuslogicSCSIBIOSDataBufferFree(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) if ((DataLength != 0) && (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY)) { pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", - DataLength, SCSIDevices[TargetID][LUN].InitLength); + DataLength, SCSI_BufferLength); } if (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY) { @@ -1268,9 +1267,9 @@ BuslogicSCSIBIOSDataBufferFree(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) } /* Should be 0 when scatter/gather? */ - if (DataLength >= SCSIDevices[TargetID][LUN].InitLength) { + if (DataLength >= SCSI_BufferLength) { Residual = DataLength; - Residual -= SCSIDevices[TargetID][LUN].InitLength; + Residual -= SCSI_BufferLength; } else { Residual = 0; } @@ -1306,7 +1305,7 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf pclog("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); SCSIStatus = SCSI_STATUS_OK; - SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].InitLength = 0; + SCSI_BufferLength = 0; BuslogicSCSIBIOSDataBufferAllocate(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); @@ -2404,7 +2403,7 @@ BuslogicSCSIRequestSetup(Buslogic_t *bl, uint32_t CCBPointer, Mailbox32_t *Mailb pclog("BuslogicSCSIRequestSetup(): Scanning SCSI Target ID %i\n", Id); SCSIStatus = SCSI_STATUS_OK; - SCSIDevices[Id][Lun].InitLength = 0; + SCSI_BufferLength = 0; BuslogicDataBufferAllocate(req, req->Is24bit); @@ -2880,6 +2879,7 @@ Buslogic_Init(device_t *info) bl = malloc(sizeof(Buslogic_t)); memset(bl, 0x00, sizeof(Buslogic_t)); + bl->chip = info->local; if ((bl->chip == CHIP_BUSLOGIC_PCI) && !PCI) { @@ -3019,13 +3019,11 @@ Buslogic_Init(device_t *info) static void -Buslogic_Close(void *p) +BuslogicClose(void *p) { Buslogic_t *bl = (Buslogic_t *)p; if (bl) { - bl->MailboxCount = 0; - if (bl->evt) { thread_destroy_event(bl->evt); @@ -3130,8 +3128,13 @@ device_t buslogic_device = { "Buslogic BT-545C ISA", 0, CHIP_BUSLOGIC_ISA, - Buslogic_Init, Buslogic_Close, NULL, - NULL, NULL, NULL, NULL, + Buslogic_Init, + BuslogicClose, + NULL, + NULL, + NULL, + NULL, + NULL, BuslogicConfig }; @@ -3139,7 +3142,12 @@ device_t buslogic_pci_device = { "Buslogic BT-958D PCI", 0, CHIP_BUSLOGIC_PCI, - Buslogic_Init, Buslogic_Close, NULL, - NULL, NULL, NULL, NULL, + Buslogic_Init, + BuslogicClose, + NULL, + NULL, + NULL, + NULL, + NULL, BuslogicConfig }; diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 569c31d5b..d6207ee9e 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.5 2017/10/04 + * Version: @(#)scsi_device.c 1.0.6 2017/10/07 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -277,7 +277,7 @@ int scsi_device_block_shift(uint8_t scsi_id, uint8_t scsi_lun) } -void scsi_device_command(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +void scsi_device_command_common(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb, int multi_phase) { uint8_t phase = 0; uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; @@ -321,13 +321,51 @@ void scsi_device_command(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t scsi_device_target_phase_callback(lun_type, id); } else { /* Command first phase complete - call the callback to execute the second phase. */ - scsi_device_target_phase_callback(lun_type, id); - SCSIStatus = scsi_device_target_err_stat_to_scsi(lun_type, id); - /* Command second phase complete - call the callback to complete the command. */ - scsi_device_target_phase_callback(lun_type, id); + if (multi_phase || (SCSIPhase != SCSI_PHASE_DATA_OUT)) + { + scsi_device_target_phase_callback(lun_type, id); + SCSIStatus = scsi_device_target_err_stat_to_scsi(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); + } } } else { /* Error (Check Condition) - call the phase callback to complete the command. */ scsi_device_target_phase_callback(lun_type, id); } } + +void scsi_device_command(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +{ + scsi_device_command_common(scsi_id, scsi_lun, cdb_len, cdb, 1); +} + +void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +{ + scsi_device_command_common(scsi_id, scsi_lun, cdb_len, cdb, 0); +} + +void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + break; + } + + scsi_device_target_phase_callback(lun_type, id); + SCSIStatus = scsi_device_target_err_stat_to_scsi(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); +} diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index c369cc4e3..e9c272251 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.2 2017/08/22 + * Version: @(#)scsi_device.h 1.0.3 2017/10/04 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -16,6 +16,22 @@ #ifndef SCSI_DEVICE_H # define SCSI_DEVICE_H +typedef struct +{ + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; + + int command_pos; + uint8_t command[20]; + int data_pos; + uint8_t buffer[390144]; + + int change_state_delay; + int new_req_delay; +} scsi_bus_t; extern uint8_t *scsi_device_sense(uint8_t id, uint8_t lun); extern void scsi_device_type_data(uint8_t id, uint8_t lun, @@ -32,6 +48,13 @@ extern int scsi_device_cdb_length(uint8_t id, uint8_t lun); extern int scsi_device_block_shift(uint8_t id, uint8_t lun); extern void scsi_device_command(uint8_t id, uint8_t lun, int cdb_len, uint8_t *cdb); +extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, + int cdb_len, uint8_t *cdb); +extern void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun); + +extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert); +extern int scsi_bus_read(scsi_bus_t *bus); +extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert); #endif /*SCSI_DEVICE_H*/ diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 5836ded9e..20beb77de 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.c 1.0.9 2017/10/05 + * Version: @(#)scsi_disk.c 1.0.11 2017/10/07 * * Author: Miran Grca, * Copyright 2017 Miran Grca. @@ -21,6 +21,7 @@ #include "../ibm.h" #include "../timer.h" #include "../device.h" +#include "../nvr.h" #include "../piix.h" #include "../cdrom/cdrom.h" #include "../disk/hdd.h" @@ -124,7 +125,321 @@ uint8_t scsi_hd_command_flags[0x100] = { }; -/* #define ENABLE_SCSI_HD_LOG 0 */ +uint64_t scsi_hd_mode_sense_page_flags[HDD_NUM] = { (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES) }; + +/* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ +const uint8_t scsi_hd_mode_sense_pages_default[HDD_NUM][0x40][0x40] = +{ + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } } +}; + +uint8_t scsi_hd_mode_sense_pages_changeable[HDD_NUM][0x40][0x40] = +{ + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } } +}; + +uint8_t scsi_hd_mode_sense_pages_saved[HDD_NUM][0x40][0x40] = +{ + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } }, + { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } } +}; + +#define ENABLE_SCSI_HD_LOG 0 int scsi_hd_do_log = 0; @@ -143,6 +458,8 @@ void scsi_hd_log(const char *format, ...) } +int scsi_hd_mode_select_terminate(uint8_t id, int force); + /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ int scsi_hd_err_stat_to_scsi(uint8_t id) { @@ -219,6 +536,7 @@ int find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) void scsi_disk_insert(uint8_t id) { shdc[id].unit_attention = (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 1 : 0; + scsi_hd_mode_select_terminate(id, 1); } @@ -307,15 +625,332 @@ int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *l buffer[6] = 2; /* 512 = 0x0200 */ *len = 8; - scsi_hd_log("Read Capacity\n"); - scsi_hd_log("buffer[0]=%x\n", buffer[0]); - scsi_hd_log("buffer[1]=%x\n", buffer[1]); - scsi_hd_log("buffer[2]=%x\n", buffer[2]); - scsi_hd_log("buffer[3]=%x\n", buffer[3]); + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +uint8_t scsi_hd_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) + { + case 0: + case 3: + return scsi_hd_mode_sense_pages_saved[id][page][pos]; + break; + case 1: + return scsi_hd_mode_sense_pages_changeable[id][page][pos]; + break; + case 2: + return scsi_hd_mode_sense_pages_default[id][page][pos]; + break; + } + + return 0; +} + +uint32_t scsi_hd_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint8_t page_control = (type >> 6) & 3; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) + { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = 0; /* Number of blocks (0 = all). */ + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ + buf[pos++] = 8; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) + { + if ((type == GPMODE_ALL_PAGES) || (type == i)) + { + if (scsi_hd_mode_sense_page_flags[id] & (1LL << shdc[id].current_page_code)) + { + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 0); + msplen = scsi_hd_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + scsi_hd_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + { + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + } + + return pos; +} + +void scsi_hd_mode_sense_load(uint8_t id) +{ + FILE *f; + wchar_t temp[512]; + memset(temp, 0, 1024); + _swprintf(temp, L"scsi_hd_%02i_mode_sense.bin", id); + f = _wfopen(nvr_path(temp), L"rb"); + if (!f) + { + return; + } + fread(scsi_hd_mode_sense_pages_saved[id][0x30], 1, 0x18, f); + fclose(f); +} + +void scsi_hd_mode_sense_save(uint8_t id) +{ + FILE *f; + wchar_t temp[512]; + memset(temp, 0, 1024); + _swprintf(temp, L"scsi_hd_%02i_mode_sense.bin", id); + f = _wfopen(nvr_path(temp), L"wb"); + if (!f) + { + return; + } + fwrite(scsi_hd_mode_sense_pages_saved[id][0x30], 1, 0x18, f); + fclose(f); +} + +int scsi_hd_mode_select_init(uint8_t id, uint8_t command, uint16_t pl_length, uint8_t do_save) +{ + switch(command) + { + case GPCMD_MODE_SELECT_6: + shdc[id].current_page_len = 4; + break; + case GPCMD_MODE_SELECT_10: + shdc[id].current_page_len = 8; + break; + default: + scsi_hd_log("SCSI HDD %i: Attempting to initialize MODE SELECT with unrecognized command: %02X\n", id, command); + return -1; + } + if (pl_length == 0) + { + scsi_hd_log("SCSI HDD %i: Attempting to initialize MODE SELECT with zero parameter list length: %02X\n", id, command); + return -2; + } + shdc[id].current_page_pos = 0; + shdc[id].mode_select_phase = MODE_SELECT_PHASE_HEADER; + shdc[id].total_length = pl_length; + shdc[id].written_length = 0; + shdc[id].do_page_save = do_save; + return 1; +} + +int scsi_hd_mode_select_terminate(uint8_t id, int force) +{ + if (((shdc[id].written_length >= shdc[id].total_length) || force) && (shdc[id].mode_select_phase != MODE_SELECT_PHASE_IDLE)) + { + scsi_hd_log("SCSI HDD %i: MODE SELECT terminate: %i\n", id, force); + shdc[id].current_page_pos = shdc[id].current_page_len = shdc[id].block_descriptor_len = 0; + shdc[id].total_length = shdc[id].written_length = 0; + shdc[id].mode_select_phase = MODE_SELECT_PHASE_IDLE; + if (force) + { + scsi_hd_mode_sense_load(id); + } + return 1; + } + else + { + return 0; + } +} + +int scsi_hd_mode_select_header(uint8_t id, uint8_t val) +{ + if (shdc[id].current_page_pos == 0) + { + shdc[id].block_descriptor_len = 0; + } + else if (shdc[id].current_page_pos == (shdc[id].current_page_len - 2)) + { + if (shdc[id].current_page_len == 8) + { + shdc[id].block_descriptor_len |= ((uint16_t) val) << 8; + scsi_hd_log("SCSI HDD %i: Position: %02X, value: %02X, block descriptor length: %02X\n", id, shdc[id].current_page_pos, val, shdc[id].block_descriptor_len); + } + } + else if (shdc[id].current_page_pos == (shdc[id].current_page_len - 1)) + { + shdc[id].block_descriptor_len |= (uint16_t) val; + scsi_hd_log("SCSI HDD %i: Position: %02X, value: %02X, block descriptor length: %02X\n", id, shdc[id].current_page_pos, val, shdc[id].block_descriptor_len); + } + + shdc[id].current_page_pos++; + + if (shdc[id].current_page_pos >= shdc[id].current_page_len) + { + shdc[id].current_page_pos = 0; + if (shdc[id].block_descriptor_len) + { + shdc[id].mode_select_phase = MODE_SELECT_PHASE_BLOCK_DESC; + } + else + { + shdc[id].mode_select_phase = MODE_SELECT_PHASE_PAGE_HEADER; + } + } return 1; } +int scsi_hd_mode_select_block_desc(uint8_t id) +{ + shdc[id].current_page_pos++; + if (shdc[id].current_page_pos >= 8) + { + shdc[id].current_page_pos = 0; + shdc[id].mode_select_phase = MODE_SELECT_PHASE_PAGE_HEADER; + } + return 1; +} + +static void scsi_hd_invalid_field_pl(uint8_t id); + +int scsi_hd_mode_select_page_header(uint8_t id, uint8_t val) +{ + if (shdc[id].current_page_pos == 0) + { + shdc[id].current_page_code = val & 0x3f; + if (!(scsi_hd_mode_sense_page_flags[id] & (1LL << shdc[id].current_page_code))) + { + scsi_hd_log("SCSI HDD %i: Trying to modify an unimplemented page: %02X\n", id, shdc[id].current_page_code); + scsi_hd_mode_select_terminate(id, 1); + scsi_hd_invalid_field_pl(id); + } + shdc[id].current_page_pos++; + } + else if (shdc[id].current_page_pos == 1) + { + shdc[id].current_page_pos = 0; + shdc[id].current_page_len = val; + shdc[id].mode_select_phase = MODE_SELECT_PHASE_PAGE; + } + return 1; +} + +int scsi_hd_mode_select_page(uint8_t id, uint8_t val) +{ + if (scsi_hd_mode_sense_pages_changeable[id][shdc[id].current_page_code][shdc[id].current_page_pos + 2] != 0xFF) + { + if (val != scsi_hd_mode_sense_pages_saved[id][shdc[id].current_page_code][shdc[id].current_page_pos + 2]) + { + /* Trying to change an unchangeable value. */ + scsi_hd_log("SCSI HDD %i: Trying to change an unchangeable value: [%02X][%02X] = %02X (new: %02X)\n", id, shdc[id].current_page_code, shdc[id].current_page_pos + 2, scsi_hd_mode_sense_pages_saved[id][shdc[id].current_page_code][shdc[id].current_page_pos + 2], val); + scsi_hd_mode_select_terminate(id, 1); + scsi_hd_invalid_field_pl(id); + return 0; + } + } + else + { + if (shdc[id].current_page_code == 0xE) + { + if ((shdc[id].current_page_pos == 6) || (shdc[id].current_page_pos == 8)) + { + if (val > 3) + { + /* Trying to set an unsupported audio channel. */ + scsi_hd_log("SCSI HDD %i: Trying to set an unsupported value: [%02X][%02X] = %02X (new: %02X)\n", id, shdc[id].current_page_code, shdc[id].current_page_pos, scsi_hd_mode_sense_pages_saved[id][shdc[id].current_page_code][shdc[id].current_page_pos + 2], val); + return 0; + } + } + } + scsi_hd_mode_sense_pages_saved[id][shdc[id].current_page_code][shdc[id].current_page_pos + 2] = val; + } + shdc[id].current_page_pos++; + if (shdc[id].current_page_pos >= shdc[id].current_page_len) + { + shdc[id].current_page_pos = 0; + shdc[id].mode_select_phase = MODE_SELECT_PHASE_PAGE_HEADER; + } + return 1; +} + +static void scsi_hd_command_complete(uint8_t id); + +int scsi_hd_mode_select_write(uint8_t id, uint8_t val) +{ + int ret = 0; + int ret2 = 0; + + if (id > HDD_NUM) + { + scsi_hd_log("MODE SELECT: attempted write to wrong SCSI HDD drive\n", val); + return -6; + } + + if (shdc[id].total_length == 0) + { + scsi_hd_log("SCSI HDD %i: MODE SELECT: attempted write when not initialized (%02X)\n", id, val); + return -3; + } + + shdc[id].written_length++; + + switch (shdc[id].mode_select_phase) + { + case MODE_SELECT_PHASE_IDLE: + scsi_hd_log("SCSI HDD %i: MODE SELECT idle (%02X)\n", id, val); + ret = 1; + break; + case MODE_SELECT_PHASE_HEADER: + scsi_hd_log("SCSI HDD %i: MODE SELECT header (%02X)\n", id, val); + ret = scsi_hd_mode_select_header(id, val); + break; + case MODE_SELECT_PHASE_BLOCK_DESC: + scsi_hd_log("SCSI HDD %i: MODE SELECT block descriptor (%02X)\n", id, val); + ret = scsi_hd_mode_select_block_desc(id); + break; + case MODE_SELECT_PHASE_PAGE_HEADER: + scsi_hd_log("SCSI HDD %i: MODE SELECT page header (%02X)\n", id, val); + ret = scsi_hd_mode_select_page_header(id, val); + break; + case MODE_SELECT_PHASE_PAGE: + scsi_hd_log("SCSI HDD %i: MODE SELECT page (%02X)\n", id, val); + ret = scsi_hd_mode_select_page(id, val); + if (shdc[id].mode_select_phase == MODE_SELECT_PHASE_PAGE_HEADER) + { + if (shdc[id].do_page_save && (scsi_hd_mode_sense_pages_default[id][shdc[id].current_page_code][0] & 0x80)) + { + scsi_hd_log("SCSI HDD %i: Page %i finished, saving it...\n", id, shdc[id].current_page_code); + scsi_hd_mode_sense_save(id); + } + } + break; + default: + scsi_hd_log("SCSI HDD %i: MODE SELECT unknown phase (%02X)\n", id, val); + ret = -4; + break; + } + + /* On termination, override the return value, but only if it is 1. */ + ret2 = scsi_hd_mode_select_terminate(id, 0); + if (ret2) + { + scsi_hd_command_complete(id); + } + if (ret2 && (ret == 1)) + { + ret = -5; + } + + return ret; +} void scsi_hd_update_request_length(uint8_t id, int len, int block_len) { @@ -392,6 +1027,12 @@ static void scsi_hd_command_read_dma(uint8_t id) } +static void scsi_hd_command_write(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_OUT; + scsi_hd_command_common(id); +} + static void scsi_hd_command_write_dma(uint8_t id) { shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; @@ -412,14 +1053,12 @@ void scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_l } if (len == 0) { - SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength = 0; scsi_hd_command_complete(id); } else { if (direction == 0) { - SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength = alloc_len; scsi_hd_command_read_dma(id); } else @@ -441,6 +1080,7 @@ static void scsi_hd_sense_clear(int id, int command) static void scsi_hd_cmd_error(uint8_t id) { + SCSIPhase = SCSI_PHASE_STATUS; shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; if (shdc[id].unit_attention & 3) { @@ -456,6 +1096,7 @@ static void scsi_hd_cmd_error(uint8_t id) static void scsi_hd_unit_attention(uint8_t id) { + SCSIPhase = SCSI_PHASE_STATUS; shdc[id].error = (SENSE_NOT_READY << 4) | ABRT_ERR; if (shdc[id].unit_attention & 3) { @@ -492,6 +1133,7 @@ static void scsi_hd_invalid_lun(uint8_t id) scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; scsi_hd_asc = ASC_INV_LUN; scsi_hd_ascq = 0; + SCSIPhase = BUS_CD | BUS_IO; scsi_hd_cmd_error(id); } @@ -524,6 +1166,16 @@ static void scsi_hd_invalid_field(uint8_t id) } +static void scsi_hd_invalid_field_pl(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; +} + + static void scsi_hd_data_phase_error(uint8_t id) { scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; @@ -556,7 +1208,6 @@ int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) { scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); - /* pclog("SCSI HD %i: Attempting to execute unknown command %02X (%02X %02X)\n", id, cdb[0], ((cdb[1] >> 3) & 1) ? 0 : 1, cdb[2] & 0x3F); */ scsi_hd_illegal_opcode(id); return 0; } @@ -672,12 +1323,13 @@ void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) if (shdc[id].unit_attention && (scsi_hd_sense_key == 0)) { + SCSIPhase = SCSI_PHASE_STATUS; buffer[2]=SENSE_UNIT_ATTENTION; buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; buffer[13]=0x00; } - /* scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, hdbufferb[2], hdbufferb[12], hdbufferb[13]); */ + scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); if (buffer[2] == SENSE_UNIT_ATTENTION) { @@ -742,6 +1394,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; uint8_t *tempbuffer; uint32_t last_sector = 0; + int block_desc = 0; #if 0 int CdbLength; @@ -781,7 +1434,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) #if 0 for (CdbLength = 1; CdbLength < 12; CdbLength++) { - scsi_hd_log("SCSI HD %i: CDB[%d] = 0x%02X\n", id, CdbLength, cdb[CdbLength]); + scsi_hd_log("SCSI HD %i: CDB[%d] = %d\n", id, CdbLength, cdb[CdbLength]); } #endif } @@ -801,31 +1454,46 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: case GPCMD_VERIFY_12: + SCSIPhase = SCSI_PHASE_STATUS; scsi_hd_command_complete(id); break; case GPCMD_REZERO_UNIT: shdc[id].sector_pos = shdc[id].sector_len = 0; scsi_hd_seek(id, 0); + SCSIPhase = SCSI_PHASE_STATUS; break; case GPCMD_REQUEST_SENSE: /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE should forget about the not ready, and report unit attention straight away. */ - if (SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength < cdb[4]) + if (SCSI_BufferLength == -1) { - cdb[4] = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength; + SCSI_BufferLength = cdb[4]; + } + + if (SCSI_BufferLength < cdb[4]) + { + cdb[4] = SCSI_BufferLength; } scsi_hd_request_sense(id, hdbufferb, cdb[4]); + + SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, 18, 18, cdb[4], 0); break; case GPCMD_MECHANISM_STATUS: len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + memset(hdbufferb, 0, 8); hdbufferb[5] = 1; - + + SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, 8, 8, len, 0); break; @@ -854,9 +1522,10 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) return; } - if ((!shdc[id].sector_len) || (SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength == 0)) + if ((!shdc[id].sector_len) || (SCSI_BufferLength == 0)) { - /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + SCSIPhase = SCSI_PHASE_STATUS; + 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; @@ -867,18 +1536,23 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) alloc_length = shdc[id].packet_len = max_len << 9; - if ((shdc[id].requested_blocks > 0) && (SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength > 0)) + if (SCSI_BufferLength == -1) { - if (alloc_length > SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength) + SCSI_BufferLength = alloc_length; + } + + if ((shdc[id].requested_blocks > 0) && (SCSI_BufferLength > 0)) + { + if (alloc_length > SCSI_BufferLength) { - hdd_image_read(id, shdc[id].sector_pos, SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength >> 9, hdbufferb); + hdd_image_read(id, shdc[id].sector_pos, SCSI_BufferLength >> 9, hdbufferb); } else { hdd_image_read(id, shdc[id].sector_pos, max_len, hdbufferb); } } - + SCSIPhase = SCSI_PHASE_DATA_IN; if (shdc[id].requested_blocks > 1) { scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); @@ -898,6 +1572,105 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) } return; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + SCSIPhase = SCSI_PHASE_DATA_IN; + + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + + if (cdb[0] == GPCMD_MODE_SENSE_6) + { + len = cdb[4]; + } + else + { + len = (cdb[8] | (cdb[7] << 8)); + } + + shdc[id].current_page_code = cdb[2] & 0x3F; + + if (!(scsi_hd_mode_sense_page_flags[id] & (1LL << shdc[id].current_page_code))) + { + scsi_hd_invalid_field(id); + return; + } + + memset(hdbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) + { + len = scsi_hd_mode_sense(id, hdbufferb, 4, cdb[2], block_desc); + if (len > alloc_length) + { + len = alloc_length; + } + hdbufferb[0] = len - 1; + hdbufferb[1] = 0; + if (block_desc) + { + hdbufferb[3] = 8; + } + } + else + { + len = scsi_hd_mode_sense(id, hdbufferb, 8, cdb[2], block_desc); + if (len > alloc_length) + { + len = alloc_length; + } + hdbufferb[0]=(len - 2) >> 8; + hdbufferb[1]=(len - 2) & 255; + hdbufferb[2] = 0; + if (block_desc) + { + hdbufferb[6] = 0; + hdbufferb[7] = 8; + } + } + + if (len > alloc_length) + { + len = alloc_length; + } + else if (len < alloc_length) + { + alloc_length = len; + } + + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = alloc_length; + } + + scsi_hd_log("SCSI HDD %i: Reading mode page: %02X...\n", id, cdb[2]); + + scsi_hd_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + SCSIPhase = SCSI_PHASE_DATA_OUT; + + if (cdb[0] == GPCMD_MODE_SELECT_6) + { + len = cdb[4]; + } + else + { + len = (cdb[7] << 8) | cdb[8]; + } + + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + + scsi_hd_mode_select_init(id, cdb[0], len, cdb[1] & 1); + + scsi_hd_data_command_finish(id, len, len, len, 1); + return; + case GPCMD_WRITE_6: case GPCMD_WRITE_10: case GPCMD_WRITE_12: @@ -912,6 +1685,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) 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_WRITE_10: shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; @@ -930,9 +1704,10 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) return; } - if ((!shdc[id].sector_len) || (SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength == 0)) + if ((!shdc[id].sector_len) || (SCSI_BufferLength == 0)) { - /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + SCSIPhase = SCSI_PHASE_STATUS; + 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; @@ -940,21 +1715,16 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) max_len = shdc[id].sector_len; shdc[id].requested_blocks = max_len; - + alloc_length = shdc[id].packet_len = max_len << 9; - if ((shdc[id].requested_blocks > 0) && (SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength > 0)) + if (SCSI_BufferLength == -1) { - if (alloc_length > SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength) - { - hdd_image_write(id, shdc[id].sector_pos, SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength >> 9, hdbufferb); - } - else - { - hdd_image_write(id, shdc[id].sector_pos, max_len, hdbufferb); - } + SCSI_BufferLength = 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); @@ -964,14 +1734,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); } shdc[id].all_blocks_total = shdc[id].block_total; - if (shdc[id].packet_status != CDROM_PHASE_COMPLETE) - { - StatusBarUpdateIcon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - } - else - { - StatusBarUpdateIcon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - } + StatusBarUpdateIcon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); return; case GPCMD_START_STOP_UNIT: @@ -994,6 +1757,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) break; } + SCSIPhase = SCSI_PHASE_STATUS; scsi_hd_command_complete(id); break; @@ -1002,14 +1766,15 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) max_len <<= 8; max_len |= cdb[4]; - if ((!max_len) || (SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength == 0)) + if ((!max_len) || (SCSI_BufferLength == 0)) { + SCSIPhase = SCSI_PHASE_STATUS; /* 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; - } - + } + tempbuffer = malloc(1024); if (cdb[1] & 1) @@ -1092,25 +1857,32 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) atapi_out: tempbuffer[size_idx] = idx - preamble_len; len=idx; - + if (len > max_len) { len = max_len; } - - if (len > SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength) + + if (SCSI_BufferLength == -1) { - len = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].InitLength; + SCSI_BufferLength = len; } + if (len > SCSI_BufferLength) + { + len = SCSI_BufferLength; + } + memcpy(hdbufferb, tempbuffer, len); free(tempbuffer); + SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, len, len, max_len, 0); break; case GPCMD_PREVENT_REMOVAL: + SCSIPhase = SCSI_PHASE_STATUS; scsi_hd_command_complete(id); break; @@ -1126,6 +1898,8 @@ atapi_out: break; } scsi_hd_seek(id, pos); + + SCSIPhase = SCSI_PHASE_STATUS; scsi_hd_command_complete(id); break; @@ -1135,19 +1909,117 @@ atapi_out: return; } + if (SCSI_BufferLength == -1) + { + SCSI_BufferLength = len; + } + + SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, len, len, len, 0); break; default: - /* pclog("SCSI HD %i: Attempting to execute pseudo-implemented command %02X\n", id, cdb[0]); */ scsi_hd_illegal_opcode(id); break; } - + /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ } +/* 0 = Continue transfer; 1 = Continue transfer, IRQ; -1 = Terminate transfer; -2 = Terminate transfer with error */ +int scsi_hd_mode_select_return(uint8_t id, int ret) +{ + switch(ret) + { + case 0: + /* Invalid field in parameter list. */ + case -6: + /* Attempted to write to a non-existent SCSI HDD drive (should never occur, but you never know). */ + scsi_hd_invalid_field_pl(id); + return -2; + case 1: + /* Successful, more data needed. */ + if (shdc[id].pos >= (shdc[id].packet_len + 2)) + { + shdc[id].pos = 0; + scsi_hd_command_write(id); + return 1; + } + return 0; + case 2: + /* Successful, more data needed, second byte not yet processed. */ + return 0; + case -3: + /* Not initialized. */ + case -4: + /* Unknown phase. */ + scsi_hd_illegal_opcode(id); + return -2; + case -5: + /* Command terminated successfully. */ + /* scsi_hd_command_complete(id); */ + return -1; + default: + return -15; + } +} + +void scsi_hd_phase_data_out(uint8_t id) +{ + int ret = 0; + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + + int in_data_length = 0; + int i; + + switch (shdc[id].current_cdb[0]) + { + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + in_data_length = SCSI_BufferLength; + + for (i = 0; i < in_data_length; i++) + { + ret = scsi_hd_mode_select_write(id, hdbufferb[i]); + ret = scsi_hd_mode_select_return(id, ret); + if (ret == -1) + { + return; + } + else if (ret == -2) + { + scsi_hd_callback(id); + return; + } + } + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_12: + if ((shdc[id].requested_blocks > 0) && (SCSI_BufferLength > 0)) + { + if (shdc[id].packet_len > SCSI_BufferLength) + { + hdd_image_write(id, shdc[id].sector_pos, SCSI_BufferLength >> 9, hdbufferb); + } + else + { + hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); + } + } + scsi_hd_log("HDD image written\n"); + + SCSIPhase = SCSI_PHASE_STATUS; + + StatusBarUpdateIcon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } +} + /* If the result is 1, issue an IRQ, otherwise not. */ void scsi_hd_callback(uint8_t id) { @@ -1173,6 +2045,7 @@ void scsi_hd_callback(uint8_t id) return; case CDROM_PHASE_DATA_OUT_DMA: scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); + scsi_hd_phase_data_out(id); shdc[id].packet_status = CDROM_PHASE_COMPLETE; shdc[id].status = READY_STAT; shdc[id].phase = 3; diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 453b019e3..199bd018c 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -41,6 +41,19 @@ typedef struct { int old_len; int request_pos; uint8_t hd_cdb[16]; + + uint64_t current_page_code; + int current_page_len; + + int current_page_pos; + + int mode_select_phase; + + int total_length; + int written_length; + + int do_page_save; + int block_descriptor_len; } scsi_hard_disk_t; diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c new file mode 100644 index 000000000..66d840687 --- /dev/null +++ b/src/scsi/scsi_ncr5380.c @@ -0,0 +1,852 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for + * the ISA bus. + * + * Version: @(#)scsi_ncr5380.c 1.0.0 2017/10/04 + * + * Authors: Sarah Walker, + * TheCollector1995, + */ +#include +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../mca.h" +#include "../rom.h" +#include "../nvr.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "../device.h" +#include "../win/plat_thread.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr5380.h" + +#define NCR_CURDATA 0 /* current SCSI data (read only) */ +#define NCR_OUTDATA 0 /* output data (write only) */ +#define NCR_INITCOMMAND 1 /* initiator command (read/write) */ +#define NCR_MODE 2 /* mode (read/write) */ +#define NCR_TARGETCMD 3 /* target command (read/write) */ +#define NCR_SELENABLE 4 /* select enable (write only) */ +#define NCR_BUSSTATUS 4 /* bus status (read only) */ +#define NCR_STARTDMA 5 /* start DMA send (write only) */ +#define NCR_BUSANDSTAT 5 /* bus and status (read only) */ +#define NCR_DMATARGET 6 /* DMA target (write only) */ +#define NCR_INPUTDATA 6 /* input data (read only) */ +#define NCR_DMAINIRECV 7 /* DMA initiator receive (write only) */ +#define NCR_RESETPARITY 7 /* reset parity/interrupt (read only) */ + +#define POLL_TIME_US 10 +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 +/*10us poll period with 50 bytes transferred per poll = 5MB/sec*/ + +#pragma pack(push,1) +typedef struct ncr5380_t +{ + uint8_t icr; + uint8_t mode; + uint8_t tcr; + uint8_t ser; + uint8_t isr; + + int target_bsy; + int target_req; + uint8_t target_id; + + uint8_t bus_status; + + int dma_mode; + + scsi_bus_t bus; +} ncr5380_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct lcs6821n_t +{ + rom_t bios_rom; + + mem_mapping_t mapping; + + uint8_t block_count; + int block_count_loaded; + + uint8_t status_ctrl; + + uint8_t buffer[0x80]; + int buffer_pos; + int buffer_host_pos; + + uint8_t int_ram[0x40]; + uint8_t ext_ram[0x600]; + + ncr5380_t ncr; + + int ncr5380_dma_enabled; + + int dma_callback; + int dma_enabled; + + int ncr_busy; +} lcs6821n_t; +#pragma pack(pop) + +#define ICR_DBP 0x01 +#define ICR_ATN 0x02 +#define ICR_SEL 0x04 +#define ICR_BSY 0x08 +#define ICR_ACK 0x10 +#define ICR_ARB_LOST 0x20 +#define ICR_ARB_IN_PROGRESS 0x40 + +#define MODE_ARBITRATE 0x01 +#define MODE_DMA 0x02 +#define MODE_MONITOR_BUSY 0x04 +#define MODE_ENA_EOP_INT 0x08 + +#define STATUS_ACK 0x01 +#define STATUS_BUSY_ERROR 0x04 +#define STATUS_INT 0x10 +#define STATUS_DRQ 0x40 +#define STATUS_END_OF_DMA 0x80 + +#define TCR_IO 0x01 +#define TCR_CD 0x02 +#define TCR_MSG 0x04 +#define TCR_REQ 0x08 +#define TCR_LAST_BYTE_SENT 0x80 + +enum +{ + DMA_IDLE = 0, + DMA_SEND, + DMA_TARGET_RECEIVE, + DMA_INITIATOR_RECEIVE +}; + +#ifdef ENABLE_NCR5380_LOG +int ncr5380_do_log = ENABLE_NCR5380_LOG; +#endif + + +static void +ncr5380_log(const char *fmt, ...) +{ +#if ENABLE_NCR5380_LOG + va_list ap; + + if (ncr5380_do_log) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +static void ncr53c400_dma_changed(void *p, int mode, int enable) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + scsi->ncr5380_dma_enabled = (mode && enable); + + scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); +} + +void ncr5380_reset(ncr5380_t *ncr) +{ + memset(ncr, 0, sizeof(ncr5380_t)); +} + +static uint32_t get_bus_host(ncr5380_t *ncr) +{ + uint32_t bus_host = 0; + + if (ncr->icr & ICR_DBP) + bus_host |= BUS_DBP; + if (ncr->icr & ICR_SEL) + bus_host |= BUS_SEL; + if (ncr->icr & ICR_ATN) + bus_host |= BUS_ATN; + if (ncr->tcr & TCR_IO) + bus_host |= BUS_IO; + if (ncr->tcr & TCR_CD) + bus_host |= BUS_CD; + if (ncr->tcr & TCR_MSG) + bus_host |= BUS_MSG; + if (ncr->tcr & TCR_REQ) + bus_host |= BUS_REQ; + if (ncr->icr & ICR_BSY) + bus_host |= BUS_BSY; + if (ncr->icr & ICR_ACK) + bus_host |= BUS_ACK; + if (ncr->mode & MODE_ARBITRATE) + bus_host |= BUS_ARB; + return bus_host | BUS_SETDATA(SCSI_BufferLength); +} + +static void +ncr5380_write(uint16_t port, uint8_t val, void *priv) +{ + lcs6821n_t *scsi = (lcs6821n_t *)priv; + ncr5380_t *ncr = &scsi->ncr; + int bus_host = 0; + + //ncr5380_log("ncr5380_write: addr=%06x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); + switch (port & 7) + { + case 0: /*Output data register*/ + SCSI_BufferLength = val; + break; + + case 1: /*Initiator Command Register*/ + if ((val & (ICR_BSY | ICR_SEL)) == (ICR_BSY | ICR_SEL) && + (ncr->icr & (ICR_BSY | ICR_SEL)) == ICR_SEL) + { + uint8_t temp = SCSI_BufferLength & 0x7f; + + ncr->target_id = -1; + while (temp) + { + temp >>= 1; + ncr->target_id++; + } + + ncr5380_log("Select - target ID = %i, temp data %x\n", ncr->target_id, temp); + } + + ncr->icr = val; + break; + + case 2: /*Mode register*/ + if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) + { + ncr->icr &= ~ICR_ARB_LOST; + ncr->icr |= ICR_ARB_IN_PROGRESS; + } + + ncr->mode = val; + ncr53c400_dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + if (!(ncr->mode & MODE_DMA)) + { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } + break; + + case 3: /*Target Command Register*/ + ncr->tcr = val; + break; + + case 4: /*Select Enable Register*/ + ncr->ser = val; + break; + + case 5: /*Start DMA Send*/ + ncr->dma_mode = DMA_SEND; + ncr53c400_dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + case 7: /*Start DMA Initiator Receive*/ + ncr->dma_mode = DMA_INITIATOR_RECEIVE; + ncr53c400_dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + default: + // pclog("Bad NCR5380 write %06x %02x\n", port, val); + break; + } + + bus_host = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus_host); +} + +static uint8_t +ncr5380_read(uint16_t port, void *priv) +{ + lcs6821n_t *scsi = (lcs6821n_t *)priv; + ncr5380_t *ncr = &scsi->ncr; + uint32_t bus = 0; + uint8_t temp = 0xff; + + switch (port & 7) + { + case 0: /*Current SCSI Data*/ + if (ncr->icr & ICR_DBP) + { + temp = SCSI_BufferLength; + } + else + { + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); + } + break; + case 1: /*Initiator Command Register*/ + temp = ncr->icr; + break; + case 2: /*Mode Register*/ + temp = ncr->mode; + break; + case 3: /*Target Command Register*/ + temp = ncr->tcr; + break; + + case 4: /*Current SCSI Bus Status*/ + temp = 0; + bus = scsi_bus_read(&ncr->bus); + temp |= (bus & 0xff); + break; + + case 5: /*Bus and Status Register*/ + temp = 0; + + bus = get_bus_host(ncr); + if (scsi_bus_match(&ncr->bus, bus)) + temp |= 8; + bus = scsi_bus_read(&ncr->bus); + + if (bus & BUS_ACK) + temp |= STATUS_ACK; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + temp |= STATUS_DRQ; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + { + int bus_state = 0; + if (bus & BUS_IO) + bus_state |= TCR_IO; + if (bus & BUS_CD) + bus_state |= TCR_CD; + if (bus & BUS_MSG) + bus_state |= TCR_MSG; + if ((ncr->tcr & 7) != bus_state) + ncr->isr |= STATUS_INT; + } + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + temp |= STATUS_BUSY_ERROR; + temp |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); + break; + + case 7: /*Reset Parity/Interrupt*/ + ncr->isr &= ~STATUS_INT; + break; + + default: + ncr5380_log("Bad NCR5380 read %06x\n", port); + break; + } + + //ncr5380_log("ncr5380_read: addr=%06x temp=%02x pc=%04x:%04x\n", port, temp, CS,cpu_state.pc); + return temp; +} + +#define CTRL_DATA_DIR (1 << 6) + +#define STATUS_BUFFER_NOT_READY (1 << 2) +#define STATUS_53C80_ACCESSIBLE (1 << 7) + +static uint8_t +lcs6821n_read(uint32_t addr, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; + + addr &= 0x3fff; + //ncr5380_log("lcs6821n_read %08x\n", addr); + + if (addr < 0x2000) + temp = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x3800) + temp = 0xff; + else if (addr >= 0x3a00) + temp = scsi->ext_ram[addr - 0x3a00]; + else switch (addr & 0x3f80) + { + case 0x3800: + //ncr5380_log("Read intRAM %02x %02x\n", addr & 0x3f, scsi->int_ram[addr & 0x3f]); + temp = scsi->int_ram[addr & 0x3f]; + break; + + case 0x3880: + //ncr5380_log("Read 53c80 %04x\n", addr); + temp = ncr5380_read(addr, scsi); + break; + + case 0x3900: + //ncr5380_log(" Read 3900 %i %02x\n", scsi->buffer_host_pos, scsi->status_ctrl); + if (scsi->buffer_host_pos >= 128 || !(scsi->status_ctrl & CTRL_DATA_DIR)) + temp = 0xff; + else + { + temp = scsi->buffer[scsi->buffer_host_pos++]; + + if (scsi->buffer_host_pos == 128) + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + break; + + case 0x3980: + switch (addr) + { + case 0x3980: /*Status*/ + temp = scsi->status_ctrl;// | 0x80; + if (!scsi->ncr_busy) + temp |= STATUS_53C80_ACCESSIBLE; + break; + case 0x3981: /*Block counter register*/ + temp = scsi->block_count; + break; + case 0x3982: /*Switch register read*/ + temp = 0xff; + break; + case 0x3983: + temp = 0xff; + break; + } + break; +} + + //if (addr >= 0x3880) ncr5380_log("lcs6821n_read: addr=%05x val=%02x\n", addr, temp); + + return temp; +} + +static void +lcs6821n_write(uint32_t addr, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + addr &= 0x3fff; + + //ncr5380_log("lcs6821n_write: addr=%05x val=%02x %04x:%04x %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); + + if (addr >= 0x3a00) + scsi->ext_ram[addr - 0x3a00] = val; + else switch (addr & 0x3f80) + { + case 0x3800: + //ncr5380_log("Write intram %02x %02x\n", addr & 0x3f, val); + scsi->int_ram[addr & 0x3f] = val; + break; + + case 0x3880: + //ncr5380_log("Write 53c80 %04x %02x\n", addr, val); + ncr5380_write(addr, val, scsi); + break; + + case 0x3900: + if (!(scsi->status_ctrl & CTRL_DATA_DIR) && scsi->buffer_host_pos < 128) + { + scsi->buffer[scsi->buffer_host_pos++] = val; + if (scsi->buffer_host_pos == 128) + { + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + scsi->ncr_busy = 1; + } + } + break; + + case 0x3980: + switch (addr) + { + case 0x3980: /*Control*/ + if ((val & CTRL_DATA_DIR) && !(scsi->status_ctrl & CTRL_DATA_DIR)) + { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else if (!(val & CTRL_DATA_DIR) && (scsi->status_ctrl & CTRL_DATA_DIR)) + { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + scsi->status_ctrl = (scsi->status_ctrl & 0x87) | (val & 0x78); + break; + case 0x3981: /*Block counter register*/ + scsi->block_count = val; + scsi->block_count_loaded = 1; + scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); + if (scsi->status_ctrl & CTRL_DATA_DIR) + { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else + { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + break; + } + break; + } +} + +static uint8_t +t130b_read(uint32_t addr, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; + addr &= 0x3fff; + + if (addr < 0x1800) + temp = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x1880) + temp = scsi->ext_ram[addr & 0x7f]; + + return temp; +} +static void +t130b_write(uint32_t addr, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + addr &= 0x3fff; + + if (addr >= 0x1800 && addr < 0x1880) + scsi->ext_ram[addr & 0x7f] = val; +} + +static uint8_t +t130b_in(uint16_t port, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; + + switch (port & 0xf) + { + case 0x0: case 0x1: case 0x2: case 0x3: + temp = lcs6821n_read((port & 7) | 0x3980, scsi); + break; + + case 0x4: case 0x5: + temp = lcs6821n_read(0x3900, scsi); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + temp = ncr5380_read(port, scsi); + break; + } + return temp; +} +static void +t130b_out(uint16_t port, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + switch (port & 0xf) + { + case 0x0: case 0x1: case 0x2: case 0x3: + lcs6821n_write((port & 7) | 0x3980, val, scsi); + break; + + case 0x4: case 0x5: + lcs6821n_write(0x3900, val, scsi); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + ncr5380_write(port, val, scsi); + break; + } +} + +static void ncr53c400_dma_callback(void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + ncr5380_t *ncr = &scsi->ncr; + int c; + int bytes_transferred = 0; + + scsi->dma_callback += POLL_TIME_US; + + switch (scsi->ncr.dma_mode) + { + case DMA_SEND: + if (scsi->status_ctrl & CTRL_DATA_DIR) + { + ncr5380_log("DMA_SEND with DMA direction set wrong\n"); + break; + } + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) + { + break; + } + + if (!scsi->block_count_loaded) + { + break; + } + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus; + uint8_t data; + + for (c = 0; c < 10; c++) + { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) + break; + } + if (c == 10) + { + break; + } + + /*Data ready*/ + data = scsi->buffer[scsi->buffer_pos]; + bus = get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(data); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); + + scsi->buffer_pos++; + bytes_transferred++; + + if (scsi->buffer_pos == 128) + { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; + scsi->ncr_busy = 0; + if (!scsi->block_count) + { + scsi->block_count_loaded = 0; + scsi->dma_enabled = 0; + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + case DMA_INITIATOR_RECEIVE: + if (!(scsi->status_ctrl & CTRL_DATA_DIR)) + { + ncr5380_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + break; + } + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) + break; + + if (!scsi->block_count_loaded) + break; + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus; + uint8_t temp; + + for (c = 0; c < 10; c++) + { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) + break; + } + if (c == 10) + break; + + /*Data ready*/ + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); + bus = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); + + scsi->buffer[scsi->buffer_pos++] = temp; + bytes_transferred++; + + if (scsi->buffer_pos == 128) + { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; + if (!scsi->block_count) + { + scsi->block_count_loaded = 0; + scsi->dma_enabled = 0; + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + default: + // pclog("DMA callback bad mode %i\n", scsi->ncr.dma_mode); + break; + } + + { + int bus = scsi_bus_read(&ncr->bus); + + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + { + ncr->mode &= ~MODE_DMA; + ncr->dma_mode = DMA_IDLE; + ncr53c400_dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + } + } +} + +static void *scsi_53c400_init(wchar_t *bios_fn) +{ + lcs6821n_t *scsi = malloc(sizeof(lcs6821n_t)); + memset(scsi, 0, sizeof(lcs6821n_t)); + + rom_init(&scsi->bios_rom, bios_fn, 0xdc000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + mem_mapping_add(&scsi->mapping, 0xdc000, 0x4000, + lcs6821n_read, NULL, NULL, + lcs6821n_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + ncr5380_reset(&scsi->ncr); + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + timer_add(ncr53c400_dma_callback, &scsi->dma_callback, &scsi->dma_enabled, scsi); + + return scsi; +} + +static void *scsi_lcs6821n_init(device_t *info) +{ + return scsi_53c400_init(L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin"); +} +static void *scsi_rt1000b_init(device_t *info) +{ + return scsi_53c400_init(L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin"); +} + +static void *scsi_t130b_init(device_t *info) +{ + lcs6821n_t *scsi = malloc(sizeof(lcs6821n_t)); + memset(scsi, 0, sizeof(lcs6821n_t)); + + rom_init(&scsi->bios_rom, L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin", 0xdc000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&scsi->mapping, 0xdc000, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + io_sethandler(0x0350, 0x0010, + t130b_in, NULL, NULL, + t130b_out, NULL, NULL, + scsi); + + ncr5380_reset(&scsi->ncr); + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + timer_add(ncr53c400_dma_callback, &scsi->dma_callback, &scsi->dma_enabled, scsi); + + return scsi; +} + + +static void +scsi_53c400_close(void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + free(scsi); +} + +static int scsi_lcs6821n_available() +{ + return rom_present(L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin"); +} + +static int scsi_rt1000b_available() +{ + return rom_present(L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin"); +} + +static int scsi_t130b_available() +{ + return rom_present(L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin"); +} + +device_t scsi_lcs6821n_device = +{ + "Longshine LCS-6821N (SCSI)", + 0, + 0, + scsi_lcs6821n_init, + scsi_53c400_close, + NULL, + scsi_lcs6821n_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t scsi_rt1000b_device = +{ + "Ranco RT1000B (SCSI)", + 0, + 0, + scsi_rt1000b_init, + scsi_53c400_close, + NULL, + scsi_rt1000b_available, + NULL, + NULL, + NULL, + NULL +}; + + +device_t scsi_t130b_device = +{ + "Trantor T130B (SCSI)", + 0, + 0, + scsi_t130b_init, + scsi_53c400_close, + NULL, + scsi_t130b_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/scsi/scsi_ncr5380.h b/src/scsi/scsi_ncr5380.h new file mode 100644 index 000000000..64f962528 --- /dev/null +++ b/src/scsi/scsi_ncr5380.h @@ -0,0 +1,27 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for + * the ISA bus. + * + * Version: @(#)scsi_ncr5380.c 1.0.0 2017/10/04 + * + * Authors: Sarah Walker, + * TheCollector1995, + */ +#ifndef SCSI_NCR5380_H +# define SCSI_NCR5380_H + + +extern device_t scsi_lcs6821n_device; +extern device_t scsi_rt1000b_device; +extern device_t scsi_t130b_device; + + +#endif /*SCSI_NCR5380_H*/ diff --git a/src/win/win.c b/src/win/win.c index 493f1f9dc..04b16674a 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -42,7 +42,6 @@ #include "../nvr.h" #include "../mouse.h" #include "../cdrom/cdrom.h" -#include "../cdrom/cdrom_ioctl.h" #include "../cdrom/cdrom_image.h" #include "../cdrom/cdrom_null.h" #include "../floppy/floppy.h" @@ -60,6 +59,7 @@ #include "plat_ticks.h" #include "plat_ui.h" #include "win.h" +#include "win_cdrom_ioctl.h" #include "win_cgapal.h" #include "win_ddraw.h" #include "win_d3d.h" diff --git a/src/win/win_cdrom.c b/src/win/win_cdrom.c index d38517c39..8d8a1d81f 100644 --- a/src/win/win_cdrom.c +++ b/src/win/win_cdrom.c @@ -29,7 +29,6 @@ #include #include "../config.h" #include "../cdrom/cdrom.h" -#include "../cdrom/cdrom_ioctl.h" #include "../cdrom/cdrom_image.h" #include "../cdrom/cdrom_null.h" #include "../disk/hdd.h" @@ -37,6 +36,7 @@ #include "../scsi/scsi_disk.h" #include "plat_ui.h" #include "win.h" +#include "win_cdrom_ioctl.h" #include "win_language.h" diff --git a/src/cdrom/cdrom_ioctl.c b/src/win/win_cdrom_ioctl.c similarity index 99% rename from src/cdrom/cdrom_ioctl.c rename to src/win/win_cdrom_ioctl.c index 7e2d2f913..04600d5d4 100644 --- a/src/cdrom/cdrom_ioctl.c +++ b/src/win/win_cdrom_ioctl.c @@ -28,8 +28,8 @@ #include "../ibm.h" #include "../device.h" #include "../scsi/scsi.h" -#include "cdrom.h" -#include "cdrom_ioctl.h" +#include "../cdrom/cdrom.h" +#include "win_cdrom_ioctl.h" #define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) diff --git a/src/cdrom/cdrom_ioctl.h b/src/win/win_cdrom_ioctl.h similarity index 100% rename from src/cdrom/cdrom_ioctl.h rename to src/win/win_cdrom_ioctl.h