diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 20420ca71..a2991cce8 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -44,7 +44,8 @@ #define LCS6821N_ROM L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" -#define RT1000B_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define RT1000B_810R_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define RT1000B_820R_ROM L"roms/scsi/ncr5380/RTBIOS82.rom" #define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" @@ -95,8 +96,12 @@ typedef struct { uint8_t icr, mode, tcr, data_wait; uint8_t isr, output_data, target_id, tx_data; + uint8_t msglun; uint8_t command[20]; + uint8_t msgout[4]; + int msgout_pos; + int is_msgout; int dma_mode, cur_bus, bus_in, new_phase; int state, clear_req, wait_data, wait_complete; @@ -116,6 +121,7 @@ typedef struct { int8_t irq; int8_t type; + int8_t bios_ver; uint8_t block_count; uint8_t status_ctrl; uint8_t pad[2]; @@ -143,6 +149,8 @@ typedef struct { #define STATE_STATUS 4 #define STATE_MESSAGEIN 5 #define STATE_SELECT 6 +#define STATE_MESSAGEOUT 7 +#define STATE_MESSAGE_ID 8 #define DMA_IDLE 0 #define DMA_SEND 1 @@ -189,6 +197,18 @@ get_dev_id(uint8_t data) return(-1); } +static int +getmsglen(uint8_t *msgp, int len) +{ + uint8_t msg = msgp[0]; + if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) ||msg >= 0x80) + return 1; + if (msg >= 0x20 && msg <= 0x2f) + return 2; + if (len < 2) + return 3; + return msgp[1]; +} static void ncr_reset(ncr_t *ncr) @@ -326,8 +346,11 @@ ncr_bus_read(ncr5380_t *ncr_dev) } else if (phase == SCSI_PHASE_MESSAGE_IN) { ncr->state = STATE_MESSAGEIN; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; - } else - fatal("Bad new phase: %i\n", phase); + } else if (phase == SCSI_PHASE_MESSAGE_OUT) { + ncr->cur_bus |= BUS_REQ; + ncr->state = STATE_MESSAGEOUT; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->target_id >> 5) | BUS_DBP; + } } } @@ -347,6 +370,7 @@ ncr_bus_update(void *priv, int bus) scsi_device_t *dev = &scsi_devices[ncr->target_id]; double p; uint8_t sel_data; + int msglen; /*Start the SCSI command layer, which will also make the timings*/ if (bus & BUS_ARB) @@ -366,9 +390,13 @@ ncr_bus_update(void *priv, int bus) if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { ncr->cur_bus |= BUS_BSY; ncr->state = STATE_SELECT; + } else { + ncr_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + if (ncr_dev->type == 1 && ncr_dev->bios_ver == 1) + ncr->cur_bus = 0; } - } - } else if (ncr->state == STATE_SELECT) { + } + } else if (ncr->state == STATE_SELECT) { if (!(bus & BUS_SEL)) { if (!(bus & BUS_ATN)) { if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { @@ -383,8 +411,13 @@ ncr_bus_update(void *priv, int bus) ncr->state = STATE_IDLE; ncr->cur_bus = 0; } - } else - fatal("Dropped selection with ATN\n"); + } else { + ncr_log("Set to SCSI Message Out\n"); + ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; + ncr->wait_data = 4; + ncr->msgout_pos = 0; + ncr->is_msgout = 1; + } } } else if (ncr->state == STATE_COMMAND) { if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { @@ -397,6 +430,12 @@ ncr_bus_update(void *priv, int bus) ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); if (ncr->command_pos == cmd_len[(ncr->command[0] >> 5) & 7]) { + if (ncr->msglun >= 0 && ncr->is_msgout) { + ncr->is_msgout = 0; + ncr->command[1] &= ~(0x80 | 0x40 | 0x20); + ncr->command[1] |= ncr->msglun << 5; + } + /*Reset data position to default*/ ncr->data_pos = 0; @@ -486,7 +525,28 @@ ncr_bus_update(void *priv, int bus) ncr->new_phase = BUS_IDLE; ncr->wait_data = 4; } - } + } else if (ncr->state == STATE_MESSAGEOUT) { + ncr_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); + msglen = getmsglen(ncr->msgout, ncr->msgout_pos); + if (ncr->msgout_pos >= msglen) { + if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) + ncr->msglun = ncr->msgout[0] & 7; + ncr->cur_bus &= ~BUS_REQ; + ncr->state = STATE_MESSAGE_ID; + } + } + } else if (ncr->state == STATE_MESSAGE_ID) { + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { + ncr_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + } + } ncr->bus_in = bus; } @@ -510,8 +570,7 @@ ncr_write(uint16_t port, uint8_t val, void *priv) case 1: /* Initiator Command Register */ ncr_log("Write: Initiator command register\n"); if ((val & 0x80) && !(ncr->icr & 0x80)) { - ncr_log("Resetting the 53c400\n"); - picint(1 << ncr_dev->irq); + ncr_log("Resetting the 5380\n"); ncr_reset(&ncr_dev->ncr); } ncr->icr = val; @@ -525,10 +584,13 @@ ncr_write(uint16_t port, uint8_t val, void *priv) } ncr->mode = val; - dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); + + /*Don't stop the timer until it finishes the transfer*/ + if (ncr_dev->block_count_loaded && (ncr->mode & MODE_DMA)) + dma_changed(ncr_dev, ncr->dma_mode, ncr->mode & MODE_DMA); - /*If it's not DMA mode, don't do anything*/ - if (!(ncr->mode & MODE_DMA)) { + /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ + if (!ncr_dev->block_count_loaded && !(ncr->mode & MODE_DMA)) { ncr_log("No DMA mode\n"); ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->isr &= ~STATUS_END_OF_DMA; @@ -788,12 +850,6 @@ memio_write(uint32_t addr, uint8_t val, void *priv) case 0x3980: switch (addr) { case 0x3980: /* Control */ - if (val & 0x80) { - ncr_log("Resetting the 53c400\n"); - picint(1 << ncr_dev->irq); - ncr_reset(&ncr_dev->ncr); - } - if ((val & CTRL_DATA_DIR) && !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { ncr_dev->buffer_host_pos = 128; ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; @@ -809,7 +865,7 @@ memio_write(uint32_t addr, uint8_t val, void *priv) ncr_log("Write block counter register: val=%d\n", val); ncr_dev->block_count = val; ncr_dev->block_count_loaded = 1; - set_dma_enable(ncr_dev, ncr_dev->dma_enabled && ncr_dev->block_count_loaded); + set_dma_enable(ncr_dev, ncr_dev->dma_enabled && ncr_dev->block_count_loaded); if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { ncr_dev->buffer_host_pos = 128; @@ -951,10 +1007,10 @@ ncr_callback(void *priv) if (ncr->cur_bus & BUS_REQ) break; } - + if (c == 10) - break; - + break; + /* Data ready. */ data = ncr_dev->buffer[ncr_dev->buffer_pos]; bus = get_bus_host(ncr) & ~BUS_DATAMASK; @@ -964,8 +1020,10 @@ ncr_callback(void *priv) ncr_bus_update(priv, bus & ~BUS_ACK); bt++; - - if (++ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos++; + ncr_log("Buffer pos for writing = %d\n", ncr_dev->buffer_pos); + + if (ncr_dev->buffer_pos == 128) { ncr_dev->buffer_pos = 0; ncr_dev->buffer_host_pos = 0; ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; @@ -1010,7 +1068,7 @@ ncr_callback(void *priv) if (ncr->cur_bus & BUS_REQ) break; } - + if (c == 10) break; @@ -1066,6 +1124,7 @@ ncr_callback(void *priv) static void * ncr_init(const device_t *info) { + wchar_t *fn = NULL; char temp[128]; ncr5380_t *ncr_dev; @@ -1077,40 +1136,44 @@ ncr_init(const device_t *info) switch(ncr_dev->type) { case 0: /* Longshine LCS6821N */ ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->irq = device_get_config_int("irq"); rom_init(&ncr_dev->bios_rom, LCS6821N_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - mem_mapping_disable(&ncr_dev->bios_rom.mapping); mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, - ncr_dev->bios_rom.rom, 0, ncr_dev); + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); break; case 1: /* Rancho RT1000B */ ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); - rom_init(&ncr_dev->bios_rom, RT1000B_ROM, + ncr_dev->irq = device_get_config_int("irq"); + ncr_dev->bios_ver = device_get_config_int("bios_ver"); + + if (ncr_dev->bios_ver == 1) + fn = RT1000B_820R_ROM; + else + fn = RT1000B_810R_ROM; + + rom_init(&ncr_dev->bios_rom, fn, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_disable(&ncr_dev->bios_rom.mapping); - mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, - ncr_dev->bios_rom.rom, 0, ncr_dev); + ncr_dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr_dev); break; case 2: /* Trantor T130B */ ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); ncr_dev->base = device_get_config_hex16("base"); ncr_dev->irq = device_get_config_int("irq"); - rom_init(&ncr_dev->bios_rom, T130B_ROM, - ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_disable(&ncr_dev->bios_rom.mapping); + if (ncr_dev->rom_addr > 0x00000) { + rom_init(&ncr_dev->bios_rom, T130B_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - if (ncr_dev->rom_addr > 0x00000) { mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, t130b_read, NULL, NULL, t130b_write, NULL, NULL, @@ -1164,10 +1227,9 @@ lcs6821n_available(void) static int rt1000b_available(void) { - return(rom_present(RT1000B_ROM)); + return(rom_present(RT1000B_820R_ROM) && rom_present(RT1000B_810R_ROM)); } - static int t130b_available(void) { @@ -1180,8 +1242,46 @@ static const device_config_t ncr5380_mmio_config[] = { "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, { { - "Disabled", 0 + "C800H", 0xc8000 }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_config_t rancho_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { { "C800H", 0xc8000 }, @@ -1198,6 +1298,35 @@ static const device_config_t ncr5380_mmio_config[] = { "" } }, + + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "" + } + }, + }, + { + "bios_ver", "BIOS Version", CONFIG_SELECTION, "", 1, + { + { + "8.20R", 1 + }, + { + "8.10R", 0 + }, + { + "" + } + }, }, { "", "", -1 @@ -1290,7 +1419,7 @@ const device_t scsi_rt1000b_device = ncr_init, ncr_close, NULL, rt1000b_available, NULL, NULL, - ncr5380_mmio_config + rancho_config }; const device_t scsi_t130b_device = diff --git a/src/scsi/scsi_ncr53c8xx - Cópia.c b/src/scsi/scsi_ncr53c8xx - Cópia.c deleted file mode 100644 index dff69c291..000000000 --- a/src/scsi/scsi_ncr53c8xx - Cópia.c +++ /dev/null @@ -1,2736 +0,0 @@ -/* - * 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 53C810 and 53C875 SCSI Host - * Adapters made by NCR and later Symbios and LSI. These - * controllers were designed for the PCI bus. - * - * To do: Identify the type of serial EEPROM used and its - * interface. - * - * Version: @(#)scsi_ncr53c8xx.c 1.0.17 2018/10/30 - * - * Authors: Paul Brook (QEMU) - * Artyom Tarasenko (QEMU) - * TheCollector1995, - * Miran Grca, - * - * Copyright 2006-2018 Paul Brook. - * Copyright 2009-2018 Artyom Tarasenko. - * Copyright 2017,2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include -#include "../86box.h" -#include "../io.h" -#include "../timer.h" -#include "../dma.h" -#include "../pic.h" -#include "../mem.h" -#include "../rom.h" -#include "../pci.h" -#include "../device.h" -#include "../nvr.h" -#include "../plat.h" -#include "scsi.h" -#include "scsi_device.h" -#include "scsi_ncr53c8xx.h" - -#define NCR53C8XX_ROM L"roms/scsi/ncr53c8xx/NCR307.BIN" - -#define CHIP_810 0x01 -#define CHIP_825 0x03 -#define CHIP_875 0x0f - -#define NCR_SCNTL0_TRG 0x01 -#define NCR_SCNTL0_AAP 0x02 -#define NCR_SCNTL0_EPC 0x08 -#define NCR_SCNTL0_WATN 0x10 -#define NCR_SCNTL0_START 0x20 - -#define NCR_SCNTL1_SST 0x01 -#define NCR_SCNTL1_IARB 0x02 -#define NCR_SCNTL1_AESP 0x04 -#define NCR_SCNTL1_RST 0x08 -#define NCR_SCNTL1_CON 0x10 -#define NCR_SCNTL1_DHP 0x20 -#define NCR_SCNTL1_ADB 0x40 -#define NCR_SCNTL1_EXC 0x80 - -#define NCR_SCNTL2_WSR 0x01 -#define NCR_SCNTL2_VUE0 0x02 -#define NCR_SCNTL2_VUE1 0x04 -#define NCR_SCNTL2_WSS 0x08 -#define NCR_SCNTL2_SLPHBEN 0x10 -#define NCR_SCNTL2_SLPMD 0x20 -#define NCR_SCNTL2_CHM 0x40 -#define NCR_SCNTL2_SDU 0x80 - -#define NCR_ISTAT_DIP 0x01 -#define NCR_ISTAT_SIP 0x02 -#define NCR_ISTAT_INTF 0x04 -#define NCR_ISTAT_CON 0x08 -#define NCR_ISTAT_SEM 0x10 -#define NCR_ISTAT_SIGP 0x20 -#define NCR_ISTAT_SRST 0x40 -#define NCR_ISTAT_ABRT 0x80 - -#define NCR_SSTAT0_SDP0 0x01 -#define NCR_SSTAT0_RST 0x02 -#define NCR_SSTAT0_WOA 0x04 -#define NCR_SSTAT0_LOA 0x08 -#define NCR_SSTAT0_AIP 0x10 -#define NCR_SSTAT0_OLF 0x20 -#define NCR_SSTAT0_ORF 0x40 -#define NCR_SSTAT0_ILF 0x80 - -#define NCR_SIST0_PAR 0x01 -#define NCR_SIST0_RST 0x02 -#define NCR_SIST0_UDC 0x04 -#define NCR_SIST0_SGE 0x08 -#define NCR_SIST0_RSL 0x10 -#define NCR_SIST0_SEL 0x20 -#define NCR_SIST0_CMP 0x40 -#define NCR_SIST0_MA 0x80 - -#define NCR_SIST1_HTH 0x01 -#define NCR_SIST1_GEN 0x02 -#define NCR_SIST1_STO 0x04 -#define NCR_SIST1_SBMC 0x10 - -#define NCR_SOCL_IO 0x01 -#define NCR_SOCL_CD 0x02 -#define NCR_SOCL_MSG 0x04 -#define NCR_SOCL_ATN 0x08 -#define NCR_SOCL_SEL 0x10 -#define NCR_SOCL_BSY 0x20 -#define NCR_SOCL_ACK 0x40 -#define NCR_SOCL_REQ 0x80 - -#define NCR_DSTAT_IID 0x01 -#define NCR_DSTAT_SIR 0x04 -#define NCR_DSTAT_SSI 0x08 -#define NCR_DSTAT_ABRT 0x10 -#define NCR_DSTAT_BF 0x20 -#define NCR_DSTAT_MDPE 0x40 -#define NCR_DSTAT_DFE 0x80 - -#define NCR_DCNTL_COM 0x01 -#define NCR_DCNTL_IRQD 0x02 -#define NCR_DCNTL_STD 0x04 -#define NCR_DCNTL_IRQM 0x08 -#define NCR_DCNTL_SSM 0x10 -#define NCR_DCNTL_PFEN 0x20 -#define NCR_DCNTL_PFF 0x40 -#define NCR_DCNTL_CLSE 0x80 - -#define NCR_DMODE_MAN 0x01 -#define NCR_DMODE_BOF 0x02 -#define NCR_DMODE_ERMP 0x04 -#define NCR_DMODE_ERL 0x08 -#define NCR_DMODE_DIOM 0x10 -#define NCR_DMODE_SIOM 0x20 - -#define NCR_CTEST2_DACK 0x01 -#define NCR_CTEST2_DREQ 0x02 -#define NCR_CTEST2_TEOP 0x04 -#define NCR_CTEST2_PCICIE 0x08 -#define NCR_CTEST2_CM 0x10 -#define NCR_CTEST2_CIO 0x20 -#define NCR_CTEST2_SIGP 0x40 -#define NCR_CTEST2_DDIR 0x80 - -#define NCR_CTEST5_BL2 0x04 -#define NCR_CTEST5_DDIR 0x08 -#define NCR_CTEST5_MASR 0x10 -#define NCR_CTEST5_DFSN 0x20 -#define NCR_CTEST5_BBCK 0x40 -#define NCR_CTEST5_ADCK 0x80 - -/* Enable Response to Reselection */ -#define NCR_SCID_RRE 0x60 - -#define PHASE_DO 0 -#define PHASE_DI 1 -#define PHASE_CMD 2 -#define PHASE_ST 3 -#define PHASE_MO 6 -#define PHASE_MI 7 -#define PHASE_MASK 7 - -/* Maximum length of MSG IN data. */ -#define NCR_MAX_MSGIN_LEN 8 - -/* Flag set if this is a tagged command. */ -#define NCR_TAG_VALID (1 << 16) - -#define NCR_BUF_SIZE 4096 - -typedef struct ncr53c8xx_request { - uint32_t tag; - uint32_t dma_len; - uint8_t *dma_buf; - uint32_t pending; - int out; -} ncr53c8xx_request; - -typedef enum -{ - SCSI_STATE_SEND_COMMAND, - SCSI_STATE_READ_DATA, - SCSI_STATE_WRITE_DATA, - SCSI_STATE_READ_STATUS, - SCSI_STATE_READ_MESSAGE, - SCSI_STATE_WRITE_MESSAGE -} scsi_state_t; - -typedef struct { - wchar_t *nvr_path; - uint8_t pci_slot; - uint8_t chip; - int has_bios; - int BIOSBase; - rom_t bios; - int PCIBase; - int MMIOBase; - mem_mapping_t mmio_mapping; - int RAMBase; - mem_mapping_t ram_mapping; - - int carry; /* ??? Should this be an a visible register somewhere? */ - int status; - /* Action to take at the end of a MSG IN phase. - 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ - int msg_action; - int msg_len; - uint8_t msg[NCR_MAX_MSGIN_LEN]; -#ifdef USE_NVRAM - uint16_t nvram; - uint8_t nvram_t; - uint8_t nvram_op; - uint8_t nvram_param; - uint8_t nvram_start; - uint8_t nvram_index; -#endif - uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ - /* 0 if SCRIPTS are running or stopped. - * 1 if a Wait Reselect instruction has been issued. - * 2 if processing DMA from ncr53c8xx_execute_script. - * 3 if a DMA operation is in progress. */ - int waiting; - - uint8_t current_lun; - - uint8_t istat; - uint8_t dcmd; - uint8_t dstat; - uint8_t dien; - uint8_t sist0; - uint8_t sist1; - uint8_t sien0; - uint8_t sien1; - uint8_t mbox0; - uint8_t mbox1; - uint8_t dfifo; - uint8_t ctest2; - uint8_t ctest3; - uint8_t ctest4; - uint8_t ctest5; - uint8_t dmode; - uint8_t dcntl; - uint8_t scntl0; - uint8_t scntl1; - uint8_t scntl2; - uint8_t scntl3; - uint8_t sstat0; - uint8_t sstat1; - uint8_t scid; - uint8_t sxfer; - uint8_t socl; - uint8_t sdid; - uint8_t ssid; - uint8_t sfbr; - uint8_t stest1; - uint8_t stest2; - uint8_t stest3; - uint8_t sidl0; - uint8_t sidl1; - uint8_t stime0; - uint8_t respid0; - uint8_t respid1; - uint8_t sbr; - uint8_t chip_rev; - uint8_t gpreg; - uint8_t slpar; - uint8_t swide; - uint8_t gpcntl; - uint8_t last_command; - - int command_complete; - ncr53c8xx_request *current; - - int irq; - - uint32_t dsa; - uint32_t temp; - uint32_t dnad; - uint32_t dbc; - uint32_t dsp; - uint32_t dsps; - uint32_t scratcha, scratchb, scratchc, scratchd; - uint32_t scratche, scratchf, scratchg, scratchh; - uint32_t scratchi, scratchj; - int last_level; - void *hba_private; - uint32_t buffer_pos; - int32_t temp_buf_len; - - uint8_t sstop; - - uint8_t regop; - uint32_t adder; - - pc_timer_t timer; -} ncr53c8xx_t; - - -#ifdef ENABLE_NCR53C8XX_LOG -int ncr53c8xx_do_log = ENABLE_NCR53C8XX_LOG; - - -static void -ncr53c8xx_log(const char *fmt, ...) -{ - va_list ap; - - if (ncr53c8xx_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define ncr53c8xx_log(fmt, ...) -#endif - - -static uint8_t ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset); -static void ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val); - - -static __inline__ int32_t -sextract32(uint32_t value, int start, int length) -{ - /* Note that this implementation relies on right shift of signed - * integers being an arithmetic shift. - */ - return ((int32_t)(value << (32 - length - start))) >> (32 - length); -} - - -static __inline__ uint32_t -deposit32(uint32_t value, int start, int length, - uint32_t fieldval) -{ - uint32_t mask; - mask = (~0U >> (32 - length)) << start; - return (value & ~mask) | ((fieldval << start) & mask); -} - - -static __inline__ int -ncr53c8xx_irq_on_rsl(ncr53c8xx_t *dev) -{ - return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); -} - - -static void -ncr53c8xx_soft_reset(ncr53c8xx_t *dev) -{ - int i; - - ncr53c8xx_log("LSI Reset\n"); - timer_stop(&dev->timer); - - dev->carry = 0; - - dev->msg_action = 0; - dev->msg_len = 0; - dev->waiting = 0; - dev->dsa = 0; - dev->dnad = 0; - dev->dbc = 0; - dev->temp = 0; - dev->scratcha = 0; - dev->scratchb = 0; - dev->scratchc = 0; - dev->scratchd = 0; - dev->scratche = 0; - dev->scratchf = 0; - dev->scratchg = 0; - dev->scratchh = 0; - dev->scratchi = 0; - dev->scratchj = 0; - dev->istat = 0; - dev->dcmd = 0x40; - dev->dstat = NCR_DSTAT_DFE; - dev->dien = 0; - dev->sist0 = 0; - dev->sist1 = 0; - dev->sien0 = 0; - dev->sien1 = 0; - dev->mbox0 = 0; - dev->mbox1 = 0; - dev->dfifo = 0; - dev->ctest2 = NCR_CTEST2_DACK; - dev->ctest3 = 0; - dev->ctest4 = 0; - dev->ctest5 = 0; - dev->dsp = 0; - dev->dsps = 0; - dev->dmode = 0; - dev->dcntl = 0; - dev->scntl0 = 0xc0; - dev->scntl1 = 0; - dev->scntl2 = 0; - if (dev->chip >= CHIP_825) - dev->scntl3 = 8; - else - dev->scntl3 = 0; - dev->sstat0 = 0; - dev->sstat1 = 0; - dev->scid = 7; - dev->sxfer = 0; - dev->socl = 0; - dev->sdid = 0; - dev->ssid = 0; - dev->stest1 = 0; - dev->stest2 = 0; - dev->stest3 = 0; - dev->sidl0 = 0; - dev->sidl1 = 0; - dev->stime0 = 0; - dev->stime0 = 1; - dev->respid0 = 0x80; - dev->respid1 = 0x00; - dev->sbr = 0; - dev->last_level = 0; - dev->gpreg = 0; - dev->slpar = 0; - dev->sstop = 1; - dev->gpcntl = 0x0f; -#ifdef USE_NVRAM - dev->nvram_t = dev->nvram_index = 0; -#endif - - if (dev->chip >= CHIP_825) { - /* This *IS* a wide SCSI controller, so reset all SCSI - devices. */ - for (i = 0; i < 16; i++) - scsi_device_reset(&scsi_devices[i]); - } else { - /* This is *NOT* a wide SCSI controller, so do not touch - SCSI devices with ID's >= 8. */ - for (i = 0; i < 8; i++) - scsi_device_reset(&scsi_devices[i]); - } -} - - -static void -ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) -{ - uint32_t i = 0; - - ncr53c8xx_log("ncr53c8xx_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); - - if (dev->dmode & NCR_DMODE_SIOM) { - ncr53c8xx_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); - for (i = 0; i < len; i++) - buf[i] = inb((uint16_t) (addr + i)); - } else { - ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr); - DMAPageRead(addr, buf, len); - } -} - - -static void -ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) -{ - uint32_t i = 0; - - ncr53c8xx_log("ncr53c8xx_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); - - if (dev->dmode & NCR_DMODE_DIOM) { - ncr53c8xx_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); - for (i = 0; i < len; i++) - outb((uint16_t) (addr + i), buf[i]); - } else { - ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr); - DMAPageWrite(addr, buf, len); - } -} - - -static __inline__ uint32_t -read_dword(ncr53c8xx_t *dev, uint32_t addr) -{ - uint32_t buf; - ncr53c8xx_log("Reading the next DWORD from memory (%08X)...\n", addr); - DMAPageRead(addr, (uint8_t *)&buf, 4); - return buf; -} - - -static -void do_irq(ncr53c8xx_t *dev, int level) -{ - if (level) { - pci_set_irq(dev->pci_slot, PCI_INTA); - ncr53c8xx_log("Raising IRQ...\n"); - } else { - pci_clear_irq(dev->pci_slot, PCI_INTA); - ncr53c8xx_log("Lowering IRQ...\n"); - } -} - - -static void -ncr53c8xx_update_irq(ncr53c8xx_t *dev) -{ - int level; - - /* It's unclear whether the DIP/SIP bits should be cleared when the - Interrupt Status Registers are cleared or when istat is read. - We currently do the formwer, which seems to work. */ - level = 0; - if (dev->dstat & 0x7f) { - if ((dev->dstat & dev->dien) & 0x7f) - level = 1; - dev->istat |= NCR_ISTAT_DIP; - } else { - dev->istat &= ~NCR_ISTAT_DIP; - } - - if (dev->sist0 || dev->sist1) { - if ((dev->sist0 & dev->sien0) || (dev->sist1 & dev->sien1)) - level = 1; - dev->istat |= NCR_ISTAT_SIP; - } else { - dev->istat &= ~NCR_ISTAT_SIP; - } - if (dev->istat & NCR_ISTAT_INTF) { - level = 1; - } - - if (level != dev->last_level) { - ncr53c8xx_log("Update IRQ level %d dstat %02x sist %02x%02x\n", - level, dev->dstat, dev->sist1, dev->sist0); - dev->last_level = level; - do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ - } -} - - -/* Stop SCRIPTS execution and raise a SCSI interrupt. */ -static void -ncr53c8xx_script_scsi_interrupt(ncr53c8xx_t *dev, int stat0, int stat1) -{ - uint32_t mask0; - uint32_t mask1; - - ncr53c8xx_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", - stat1, stat0, dev->sist1, dev->sist0); - dev->sist0 |= stat0; - dev->sist1 |= stat1; - /* Stop processor on fatal or unmasked interrupt. As a special hack - we don't stop processing when raising STO. Instead continue - execution and stop at the next insn that accesses the SCSI bus. */ - mask0 = dev->sien0 | ~(NCR_SIST0_CMP | NCR_SIST0_SEL | NCR_SIST0_RSL); - mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); - mask1 &= ~NCR_SIST1_STO; - if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { - ncr53c8xx_log("NCR 810: IRQ-mandated stop\n"); - dev->sstop = 1; - timer_stop(&dev->timer); - } - ncr53c8xx_update_irq(dev); -} - - -/* Stop SCRIPTS execution and raise a DMA interrupt. */ -static void -ncr53c8xx_script_dma_interrupt(ncr53c8xx_t *dev, int stat) -{ - ncr53c8xx_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); - dev->dstat |= stat; - ncr53c8xx_update_irq(dev); - dev->sstop = 1; - timer_stop(&dev->timer); -} - - -static __inline__ void -ncr53c8xx_set_phase(ncr53c8xx_t *dev, int phase) -{ - dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; -} - - -static void -ncr53c8xx_bad_phase(ncr53c8xx_t *dev, int out, int new_phase) -{ - /* Trigger a phase mismatch. */ - ncr53c8xx_log("Phase mismatch interrupt\n"); - ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); - dev->sstop = 1; - timer_stop(&dev->timer); - ncr53c8xx_set_phase(dev, new_phase); -} - - -static void -ncr53c8xx_disconnect(ncr53c8xx_t *dev) -{ - dev->scntl1 &= ~NCR_SCNTL1_CON; - dev->sstat1 &= ~PHASE_MASK; - if (dev->dcmd & 0x01) /* Select with ATN */ - dev->sstat1 |= 0x07; -} - - -static void -ncr53c8xx_bad_selection(ncr53c8xx_t *dev, uint32_t id) -{ - ncr53c8xx_log("Selected absent target %d\n", id); - ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); - ncr53c8xx_disconnect(dev); -} - - -/* Callback to indicate that the SCSI layer has completed a command. */ -static void -ncr53c8xx_command_complete(void *priv, uint32_t status) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; - int out; - - out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); - dev->status = status; - dev->command_complete = 2; - if (dev->waiting && dev->dbc != 0) { - /* Raise phase mismatch for short transfers. */ - ncr53c8xx_bad_phase(dev, out, PHASE_ST); - } else - ncr53c8xx_set_phase(dev, PHASE_ST); - - dev->sstop = 0; -} - - -static void -ncr53c8xx_do_dma(ncr53c8xx_t *dev, int out, uint8_t id) -{ - uint32_t addr, tdbc; - int count; - - scsi_device_t *sd = &scsi_devices[id]; - - if ((!scsi_device_present(sd))) { - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); - return; - } - - if (!dev->current->dma_len) { - /* Wait until data is available. */ - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); - return; - } - - /* Make sure count is never bigger than buffer_length. */ - count = tdbc = dev->dbc; - if (count > dev->temp_buf_len) - count = dev->temp_buf_len; - - addr = dev->dnad; - - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); - dev->dnad += count; - dev->dbc -= count; - - if (out) - ncr53c8xx_read(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); - else { -#ifdef ENABLE_NCR53C8XX_LOG - if (!dev->buffer_pos) - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); -#endif - ncr53c8xx_write(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); - } - - dev->temp_buf_len -= count; - dev->buffer_pos += count; - - if (dev->temp_buf_len <= 0) { - scsi_device_command_phase1(&scsi_devices[id]); -#ifdef ENABLE_NCR53C8XX_LOG - if (out) - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); -#endif - ncr53c8xx_command_complete(dev, sd->status); - } else { - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); - dev->sstop = 0; - } -} - - -/* Queue a byte for a MSG IN phase. */ -static void -ncr53c8xx_add_msg_byte(ncr53c8xx_t *dev, uint8_t data) -{ - if (dev->msg_len >= NCR_MAX_MSGIN_LEN) - ncr53c8xx_log("MSG IN data too long\n"); - else { - ncr53c8xx_log("MSG IN 0x%02x\n", data); - dev->msg[dev->msg_len++] = data; - } -} - - -static void -ncr53c8xx_timer_on(ncr53c8xx_t *dev, scsi_device_t *sd, double p) -{ - if (p <= 0) - timer_on_auto(&dev->timer, ((double) sd->buffer_length) * 0.1); /* Fast SCSI: 10000000 bytes per second */ - else - timer_on_auto(&dev->timer, p); -} - - -static int -ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) -{ - scsi_device_t *sd; - uint8_t buf[12]; - - memset(buf, 0, 12); - DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); - if (dev->dbc > 12) { - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); - dev->dbc = 12; - } - dev->sfbr = buf[0]; - dev->command_complete = 0; - - sd = &scsi_devices[id]; - if (!scsi_device_present(sd)) { - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); - ncr53c8xx_bad_selection(dev, id); - return 0; - } - - dev->current = (ncr53c8xx_request*)malloc(sizeof(ncr53c8xx_request)); - dev->current->tag = id; - - sd->buffer_length = -1; - - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); - dev->last_command = buf[0]; - - /* Make sure bits 5-7 of the CDB have the correct LUN. */ - if ((buf[1] & 0xe0) != (dev->current_lun << 5)) - buf[1] = (buf[1] & 0x1f) | (dev->current_lun << 5); - - scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf); - dev->hba_private = (void *)dev->current; - - dev->waiting = 0; - dev->buffer_pos = 0; - - dev->temp_buf_len = sd->buffer_length; - - if (sd->buffer_length > 0) { - /* This should be set to the underlying device's buffer by command phase 0. */ - dev->current->dma_len = sd->buffer_length; - } - - if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); - ncr53c8xx_set_phase(dev, PHASE_DI); - ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); - return 1; - } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { - ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); - ncr53c8xx_set_phase(dev, PHASE_DO); - ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); - return 1; - } else { - ncr53c8xx_command_complete(dev, sd->status); - return 0; - } -} - - -static void -ncr53c8xx_do_status(ncr53c8xx_t *dev) -{ - uint8_t status; - ncr53c8xx_log("Get status len=%d status=%d\n", dev->dbc, dev->status); - if (dev->dbc != 1) - ncr53c8xx_log("Bad Status move\n"); - dev->dbc = 1; - status = dev->status; - dev->sfbr = status; - ncr53c8xx_write(dev, dev->dnad, &status, 1); - ncr53c8xx_set_phase(dev, PHASE_MI); - dev->msg_action = 1; - ncr53c8xx_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ -} - - -#ifdef USE_WDTR -static void -ncr53c8xx_do_wdtr(ncr53c8xx_t *dev, int exponent) -{ - ncr53c8xx_log("Target-initiated WDTR (%08X)\n", dev); - ncr53c8xx_set_phase(dev, PHASE_MI); - dev->msg_action = 4; - ncr53c8xx_add_msg_byte(dev, 0x01); /* EXTENDED MESSAGE */ - ncr53c8xx_add_msg_byte(dev, 0x02); /* EXTENDED MESSAGE LENGTH */ - ncr53c8xx_add_msg_byte(dev, 0x03); /* WIDE DATA TRANSFER REQUEST */ - ncr53c8xx_add_msg_byte(dev, exponent); /* TRANSFER WIDTH EXPONENT (16-bit) */ -} -#endif - - -static void -ncr53c8xx_do_msgin(ncr53c8xx_t *dev) -{ - uint32_t len; - ncr53c8xx_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); - dev->sfbr = dev->msg[0]; - len = dev->msg_len; - if (len > dev->dbc) - len = dev->dbc; - ncr53c8xx_write(dev, dev->dnad, dev->msg, len); - /* Linux drivers rely on the last byte being in the SIDL. */ - dev->sidl0 = dev->msg[len - 1]; - dev->msg_len -= len; - if (dev->msg_len) - memmove(dev->msg, dev->msg + len, dev->msg_len); - else { - /* ??? Check if ATN (not yet implemented) is asserted and maybe - switch to PHASE_MO. */ - switch (dev->msg_action) { - case 0: - ncr53c8xx_set_phase(dev, PHASE_CMD); - break; - case 1: - ncr53c8xx_disconnect(dev); - break; - case 2: - ncr53c8xx_set_phase(dev, PHASE_DO); - break; - case 3: - ncr53c8xx_set_phase(dev, PHASE_DI); - break; - case 4: - ncr53c8xx_set_phase(dev, PHASE_MO); - break; - default: - abort(); - } - } -} - - -/* Read the next byte during a MSGOUT phase. */ -static uint8_t -ncr53c8xx_get_msgbyte(ncr53c8xx_t *dev) -{ - uint8_t data; - DMAPageRead(dev->dnad, &data, 1); - dev->dnad++; - dev->dbc--; - return data; -} - - -/* Skip the next n bytes during a MSGOUT phase. */ -static void -ncr53c8xx_skip_msgbytes(ncr53c8xx_t *dev, unsigned int n) -{ - dev->dnad += n; - dev->dbc -= n; -} - - -static void -ncr53c8xx_bad_message(ncr53c8xx_t *dev, uint8_t msg) -{ - ncr53c8xx_log("Unimplemented message 0x%02x\n", msg); - ncr53c8xx_set_phase(dev, PHASE_MI); - ncr53c8xx_add_msg_byte(dev, 7); /* MESSAGE REJECT */ - dev->msg_action = 0; -} - - -static void -ncr53c8xx_do_msgout(ncr53c8xx_t *dev, uint8_t id) -{ - uint8_t msg; - int len, arg; -#ifdef ENABLE_NCR53C8XX_LOG - uint32_t current_tag; -#endif - scsi_device_t *sd; - - sd = &scsi_devices[id]; - -#ifdef ENABLE_NCR53C8XX_LOG - current_tag = id; -#endif - - ncr53c8xx_log("MSG out len=%d\n", dev->dbc); - while (dev->dbc) { - msg = ncr53c8xx_get_msgbyte(dev); - dev->sfbr = msg; - - switch (msg) { - case 0x04: - ncr53c8xx_log("MSG: Disconnect\n"); - ncr53c8xx_disconnect(dev); - break; - case 0x08: - ncr53c8xx_log("MSG: No Operation\n"); - ncr53c8xx_set_phase(dev, PHASE_CMD); - break; - case 0x01: - len = ncr53c8xx_get_msgbyte(dev); - msg = ncr53c8xx_get_msgbyte(dev); - arg = ncr53c8xx_get_msgbyte(dev); - (void) len; /* avoid a warning about unused variable*/ - ncr53c8xx_log("Extended message 0x%x (len %d)\n", msg, len); - switch (msg) { - case 1: - ncr53c8xx_log("SDTR (ignored)\n"); - ncr53c8xx_skip_msgbytes(dev, 1); - break; - case 3: - ncr53c8xx_log("WDTR (ignored)\n"); - if (arg > 0x01) { - ncr53c8xx_bad_message(dev, msg); - return; - } -#ifdef USE_WDTR - ncr53c8xx_set_phase(dev, PHASE_CMD); -#endif - break; - case 5: - ncr53c8xx_log("PPR (ignored)\n"); - ncr53c8xx_skip_msgbytes(dev, 4); - break; - default: - ncr53c8xx_bad_message(dev, msg); - return; - } - break; - case 0x20: /* SIMPLE queue */ - id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; - ncr53c8xx_log("SIMPLE queue tag=0x%x\n", id & 0xff); - break; - case 0x21: /* HEAD of queue */ - ncr53c8xx_log("HEAD queue not implemented\n"); - id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; - break; - case 0x22: /* ORDERED queue */ - ncr53c8xx_log("ORDERED queue not implemented\n"); - id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; - break; - case 0x0d: - /* The ABORT TAG message clears the current I/O process only. */ - ncr53c8xx_log("MSG: Abort Tag\n"); - scsi_device_command_stop(sd); - ncr53c8xx_disconnect(dev); - break; - case 0x06: - case 0x0e: - case 0x0c: - /* clear the current I/O process */ - scsi_device_command_stop(sd); - ncr53c8xx_disconnect(dev); - break; - default: - if ((msg & 0x80) == 0) { - ncr53c8xx_bad_message(dev, msg); - return; - } else { - /* 0x80 to 0xff are IDENTIFY messages. */ - ncr53c8xx_log("MSG: Identify\n"); - dev->current_lun = msg & 7; - ncr53c8xx_log("Select LUN %d\n", dev->current_lun); -#ifdef USE_WDTR - ncr53c8xx_do_wdtr(dev, 0x01); -#else - ncr53c8xx_set_phase(dev, PHASE_CMD); -#endif - } - break; - } - } -} - - -static void -ncr53c8xx_memcpy(ncr53c8xx_t *dev, uint32_t dest, uint32_t src, int count) -{ - int n; - uint8_t buf[NCR_BUF_SIZE]; - - ncr53c8xx_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); - while (count) { - n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; - ncr53c8xx_read(dev, src, buf, n); - ncr53c8xx_write(dev, dest, buf, n); - src += n; - dest += n; - count -= n; - } -} - - -static void -ncr53c8xx_process_script(ncr53c8xx_t *dev) -{ - uint32_t insn, addr, id, buf[2], dest; - int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; - int32_t offset; - uint8_t op0, op1, data8, mask, data[7]; -#ifdef ENABLE_NCR53C8XX_LOG - uint8_t *pp; -#endif - - dev->sstop = 0; -again: - insn_processed++; - insn = read_dword(dev, dev->dsp); - if (!insn) { - /* If we receive an empty opcode increment the DSP by 4 bytes - instead of 8 and execute the next opcode at that location */ - dev->dsp += 4; - timer_on_auto(&dev->timer, 10.0); - if (insn_processed < 100) - goto again; - else - return; - } - addr = read_dword(dev, dev->dsp + 4); - ncr53c8xx_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); - dev->dsps = addr; - dev->dcmd = insn >> 24; - dev->dsp += 8; - - switch (insn >> 30) { - case 0: /* Block move. */ - ncr53c8xx_log("00: Block move\n"); - if (dev->sist1 & NCR_SIST1_STO) { - ncr53c8xx_log("Delayed select timeout\n"); - dev->sstop = 1; - break; - } - ncr53c8xx_log("Block Move DBC=%d\n", dev->dbc); - dev->dbc = insn & 0xffffff; - ncr53c8xx_log("Block Move DBC=%d now\n", dev->dbc); - /* ??? Set ESA. */ - if (insn & (1 << 29)) { - /* Indirect addressing. */ - /* Should this respect SIOM? */ - addr = read_dword(dev, addr); - ncr53c8xx_log("Indirect Block Move address: %08X\n", addr); - } else if (insn & (1 << 28)) { - /* Table indirect addressing. */ - - /* 32-bit Table indirect */ - offset = sextract32(addr, 0, 24); - DMAPageRead(dev->dsa + offset, (uint8_t *)buf, 8); - /* byte count is stored in bits 0:23 only */ - dev->dbc = buf[0] & 0xffffff; - addr = buf[1]; - - /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of - * table, bits [31:24] */ - } - if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { - ncr53c8xx_log("Wrong phase got %d expected %d\n", - dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); - ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); - break; - } - dev->dnad = addr; - switch (dev->sstat1 & 0x7) { - case PHASE_DO: - ncr53c8xx_log("Data Out Phase\n"); - dev->waiting = 0; - ncr53c8xx_do_dma(dev, 1, dev->sdid); - break; - case PHASE_DI: - ncr53c8xx_log("Data In Phase\n"); - dev->waiting = 0; - ncr53c8xx_do_dma(dev, 0, dev->sdid); - break; - case PHASE_CMD: - ncr53c8xx_log("Command Phase\n"); - c = ncr53c8xx_do_command(dev, dev->sdid); - - if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) - break; - - dev->dfifo = dev->dbc & 0xff; - dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); - - timer_on_auto(&dev->timer, 40.0); - - if (dev->dcntl & NCR_DCNTL_SSM) - ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); - return; - case PHASE_ST: - ncr53c8xx_log("Status Phase\n"); - ncr53c8xx_do_status(dev); - break; - case PHASE_MO: - ncr53c8xx_log("MSG Out Phase\n"); - ncr53c8xx_do_msgout(dev, dev->sdid); - break; - case PHASE_MI: - ncr53c8xx_log("MSG In Phase\n"); - ncr53c8xx_do_msgin(dev); - break; - default: - ncr53c8xx_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); - } - dev->dfifo = dev->dbc & 0xff; - dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); - break; - - case 1: /* IO or Read/Write instruction. */ - ncr53c8xx_log("01: I/O or Read/Write instruction\n"); - opcode = (insn >> 27) & 7; - if (opcode < 5) { - if (insn & (1 << 25)) - id = read_dword(dev, dev->dsa + sextract32(insn, 0, 24)); - else - id = insn; - id = (id >> 16) & 0xf; - if (insn & (1 << 26)) - addr = dev->dsp + sextract32(addr, 0, 24); - dev->dnad = addr; - switch (opcode) { - case 0: /* Select */ - dev->sdid = id; - if (dev->scntl1 & NCR_SCNTL1_CON) { - ncr53c8xx_log("Already reselected, jumping to alternative address\n"); - dev->dsp = dev->dnad; - break; - } - dev->sstat0 |= NCR_SSTAT0_WOA; - dev->scntl1 &= ~NCR_SCNTL1_IARB; - if (!scsi_device_present(&scsi_devices[id])) { - ncr53c8xx_bad_selection(dev, id); - break; - } - ncr53c8xx_log("Selected target %d%s\n", - id, insn & (1 << 24) ? " ATN" : ""); - dev->scntl1 |= NCR_SCNTL1_CON; - if (insn & (1 << 24)) - dev->socl |= NCR_SOCL_ATN; - ncr53c8xx_set_phase(dev, PHASE_MO); - dev->waiting = 0; - break; - case 1: /* Disconnect */ - ncr53c8xx_log("Wait Disconnect\n"); - dev->scntl1 &= ~NCR_SCNTL1_CON; - break; - case 2: /* Wait Reselect */ - ncr53c8xx_log("Wait Reselect\n"); - if (dev->istat & NCR_ISTAT_SIGP) - dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ - else { - if (!ncr53c8xx_irq_on_rsl(dev)) - dev->waiting = 1; - } - break; - case 3: /* Set */ - ncr53c8xx_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", - insn & (1 << 6) ? " ACK" : "", - insn & (1 << 9) ? " TM" : "", - insn & (1 << 10) ? " CC" : ""); - if (insn & (1 << 3)) { - dev->socl |= NCR_SOCL_ATN; - ncr53c8xx_set_phase(dev, PHASE_MO); - } - if (insn & (1 << 9)) - ncr53c8xx_log("Target mode not implemented\n"); - if (insn & (1 << 10)) - dev->carry = 1; - break; - case 4: /* Clear */ - ncr53c8xx_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", - insn & (1 << 6) ? " ACK" : "", - insn & (1 << 9) ? " TM" : "", - insn & (1 << 10) ? " CC" : ""); - if (insn & (1 << 3)) - dev->socl &= ~NCR_SOCL_ATN; - if (insn & (1 << 10)) - dev->carry = 0; - break; - } - } else { - reg = ((insn >> 16) & 0x7f) | (insn & 0x80); - data8 = (insn >> 8) & 0xff; - opcode = (insn >> 27) & 7; - operator = (insn >> 24) & 7; - op0 = op1 = 0; - switch (opcode) { - case 5: /* From SFBR */ - op0 = dev->sfbr; - op1 = data8; - break; - case 6: /* To SFBR */ - if (operator) - op0 = ncr53c8xx_reg_readb(dev, reg); - op1 = data8; - break; - case 7: /* Read-modify-write */ - if (operator) - op0 = ncr53c8xx_reg_readb(dev, reg); - if (insn & (1 << 23)) - op1 = dev->sfbr; - else - op1 = data8; - break; - } - - switch (operator) { - case 0: /* move */ - op0 = op1; - break; - case 1: /* Shift left */ - op1 = op0 >> 7; - op0 = (op0 << 1) | dev->carry; - dev->carry = op1; - break; - case 2: /* OR */ - op0 |= op1; - break; - case 3: /* XOR */ - op0 ^= op1; - break; - case 4: /* AND */ - op0 &= op1; - break; - case 5: /* SHR */ - op1 = op0 & 1; - op0 = (op0 >> 1) | (dev->carry << 7); - dev->carry = op1; - break; - case 6: /* ADD */ - op0 += op1; - dev->carry = op0 < op1; - break; - case 7: /* ADC */ - op0 += op1 + dev->carry; - if (dev->carry) - dev->carry = op0 <= op1; - else - dev->carry = op0 < op1; - break; - } - - switch (opcode) { - case 5: /* From SFBR */ - case 7: /* Read-modify-write */ - ncr53c8xx_reg_writeb(dev, reg, op0); - break; - case 6: /* To SFBR */ - dev->sfbr = op0; - break; - } - } - break; - - case 2: /* Transfer Control. */ - ncr53c8xx_log("02: Transfer Control\n"); - if ((insn & 0x002e0000) == 0) { - ncr53c8xx_log("NOP\n"); - break; - } - if (dev->sist1 & NCR_SIST1_STO) { - ncr53c8xx_log("Delayed select timeout\n"); - dev->sstop = 1; - break; - } - cond = jmp = (insn & (1 << 19)) != 0; - if (cond == jmp && (insn & (1 << 21))) { - ncr53c8xx_log("Compare carry %d\n", dev->carry == jmp); - cond = dev->carry != 0; - } - if (cond == jmp && (insn & (1 << 17))) { - ncr53c8xx_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), - jmp ? '=' : '!', ((insn >> 24) & 7)); - cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); - } - if (cond == jmp && (insn & (1 << 18))) { - mask = (~insn >> 8) & 0xff; - ncr53c8xx_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, - jmp ? '=' : '!', insn & mask); - cond = (dev->sfbr & mask) == (insn & mask); - } - if (cond == jmp) { - if (insn & (1 << 23)) { - /* Relative address. */ - addr = dev->dsp + sextract32(addr, 0, 24); - } - switch ((insn >> 27) & 7) { - case 0: /* Jump */ - ncr53c8xx_log("Jump to 0x%08x\n", addr); - dev->adder = addr; - dev->dsp = addr; - break; - case 1: /* Call */ - ncr53c8xx_log("Call 0x%08x\n", addr); - dev->temp = dev->dsp; - dev->dsp = addr; - break; - case 2: /* Return */ - ncr53c8xx_log("Return to 0x%08x\n", dev->temp); - dev->dsp = dev->temp; - break; - case 3: /* Interrupt */ - ncr53c8xx_log("Interrupt 0x%08x\n", dev->dsps); - if ((insn & (1 << 20)) != 0) { - dev->istat |= NCR_ISTAT_INTF; - ncr53c8xx_update_irq(dev); - } else - ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SIR); - break; - default: - ncr53c8xx_log("Illegal transfer control\n"); - ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_IID); - break; - } - } else - ncr53c8xx_log("Control condition failed\n"); - break; - - case 3: - ncr53c8xx_log("00: Memory move\n"); - if ((insn & (1 << 29)) == 0) { - /* Memory move. */ - /* ??? The docs imply the destination address is loaded into - the TEMP register. However the Linux drivers rely on - the value being presrved. */ - dest = read_dword(dev, dev->dsp); - dev->dsp += 4; - ncr53c8xx_memcpy(dev, dest, addr, insn & 0xffffff); - } else { -#ifdef ENABLE_NCR53C8XX_LOG - pp = data; -#endif - - if (insn & (1 << 28)) - addr = dev->dsa + sextract32(addr, 0, 24); - n = (insn & 7); - reg = (insn >> 16) & 0xff; - if (insn & (1 << 24)) { - DMAPageRead(addr, data, n); - for (i = 0; i < n; i++) - ncr53c8xx_reg_writeb(dev, reg + i, data[i]); - } else { - ncr53c8xx_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); - for (i = 0; i < n; i++) - data[i] = ncr53c8xx_reg_readb(dev, reg + i); - DMAPageWrite(addr, data, n); - } - } - break; - - default: - ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); - } - - timer_on_auto(&dev->timer, 40.0); - - ncr53c8xx_log("instructions processed %i\n", insn_processed); - if (insn_processed > 10000 && !dev->waiting) { - /* Some windows drivers make the device spin waiting for a memory - location to change. If we have been executed a lot of code then - assume this is the case and force an unexpected device disconnect. - This is apparently sufficient to beat the drivers into submission. - */ - ncr53c8xx_log("Some windows drivers make the device spin...\n"); - if (!(dev->sien0 & NCR_SIST0_UDC)) - ncr53c8xx_log("inf. loop with UDC masked\n"); - ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); - ncr53c8xx_disconnect(dev); - } else if (!dev->sstop && !dev->waiting) { - if (dev->dcntl & NCR_DCNTL_SSM) { - ncr53c8xx_log("NCR 810: SCRIPTS: Single-step mode\n"); - ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); - } else { - ncr53c8xx_log("NCR 810: SCRIPTS: Normal mode\n"); - if (insn_processed < 100) - goto again; - } - } else { - if (dev->sstop) - ncr53c8xx_log("NCR 810: SCRIPTS: Stopped\n"); - if (dev->waiting) - ncr53c8xx_log("NCR 810: SCRIPTS: Waiting\n"); - } - - ncr53c8xx_log("SCRIPTS execution stopped\n"); -} - - -static void -ncr53c8xx_execute_script(ncr53c8xx_t *dev) -{ - dev->sstop = 0; - timer_on_auto(&dev->timer, 40.0); -} - - -static void -ncr53c8xx_callback(void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *) p; - - if (!dev->sstop) { - if (dev->waiting) - timer_on_auto(&dev->timer, 40.0); - else - ncr53c8xx_process_script(dev); - } - - if (dev->sstop) - timer_stop(&dev->timer); - else - timer_on_auto(&dev->timer, 10.0); -} - - -#ifdef USE_NVRAM -static void -ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) -{ - FILE *f; - - if (save) - f = nvr_fopen(dev->nvr_path, L"wb"); - else - f = nvr_fopen(dev->nvr_path, L"rb"); - if (f) - { - if (save) { - fwrite((uint8_t *) &dev->nvram, 1, 1, f); - fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f); - } else { - fread((uint8_t *) &dev->nvram, 1, 1, f); - fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f); - } - fclose(f); - f = NULL; - } -} - - -#define ADDRESS_LENGTH 9 -#define ADDRESS_END (ADDRESS_LENGTH + 2) -#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2) -#define ADDRESS_MASK 0x3f -#define DATA_LENGTH 8 -#define DATA_START (ADDRESS_END + 1) -#define DATA_END (ADDRESS_END + DATA_LENGTH) - - -static void -ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val) -{ - uint8_t temp, old = dev->nvram_t; - dev->nvram_t = val & 0x03; - - if (val & 0x02) { - if (!dev->nvram_index) { - /* First signal clocked in after clock is high, start bit. */ - dev->nvram_start = 1; - ncr53c8xx_log("[W] Serial EEPROM: Start bit\n"); - dev->nvram_op = 0; - } else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) { - if (!dev->nvram_start) - return; - - dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1); - if (dev->nvram_index == 2) { - // ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op); - dev->nvram_param = 0; - } - } else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) { - if (!dev->nvram_start) - return; - - dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3); - if (dev->nvram_index < ADDRESS_END) { - dev->nvram_index++; - return; - } - - switch (dev->nvram_op) { - case 0x00: - temp = dev->nvram_param >> ADDRESS_SHIFT; - switch(temp) { - case 0x00: - ncr53c8xx_log("[W] Serial EEPROM: EWDS\n"); - break; - case 0x01: - ncr53c8xx_log("[W] Serial EEPROM: WRAL\n"); - break; - case 0x02: - ncr53c8xx_log("[W] Serial EEPROM: ERAL\n"); - break; - case 0x03: - ncr53c8xx_log("[W] Serial EEPROM: EWEN\n"); - break; - default: - ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n"); - break; - } - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return; - case 0x01: - ncr53c8xx_log("[W] Serial EEPROM: WRITE\n"); - break; - case 0x02: - ncr53c8xx_log("[W] Serial EEPROM: READ\n"); - break; - case 0x03: - ncr53c8xx_log("[W] Serial EEPROM: ERASE\n"); - break; - default: - ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n"); - break; - } - } else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { - if (!dev->nvram_start) - return; - - if (dev->nvram_index == DATA_END) { - ncr53c8xx_log("[W] Serial EEPROM: Data end\n"); - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return; - } - } - dev->nvram_index++; - } -} - - -static uint8_t -ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev) -{ - uint8_t temp = 0; - - if (dev->gpreg & 0x02) { - if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { - if (!dev->nvram_start) - return temp; - - dev->nvram_index++; - - if (dev->nvram_index == DATA_END) { - ncr53c8xx_log("[R] Serial EEPROM: Data end\n"); - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return temp; - } - } - } - - return temp; -} -#endif - - -static void -ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) -{ - uint8_t tmp = 0; - -#define CASE_SET_REG24(name, addr) \ - case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ - case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ - case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; - -#define CASE_SET_REG32(name, addr) \ - case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ - case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ - case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; \ - case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; - -#ifdef DEBUG_NCR_REG - ncr53c8xx_log("Write reg %02x = %02x\n", offset, val); -#endif - - dev->regop = 1; - - switch (offset) { - case 0x00: /* SCNTL0 */ - dev->scntl0 = val; - if (val & NCR_SCNTL0_START) { - /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) - is enough to make BIOS v4.x happy. */ - ncr53c8xx_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); - dev->sstat0 |= 0x10; - } - break; - case 0x01: /* SCNTL1 */ - dev->scntl1 = val & ~NCR_SCNTL1_SST; - if (val & NCR_SCNTL1_IARB) { - ncr53c8xx_log("Arbitration lost\n"); - dev->sstat0 |= 0x08; - dev->waiting = 0; - } - if (val & NCR_SCNTL1_RST) { - if (!(dev->sstat0 & NCR_SSTAT0_RST)) { - dev->sstat0 |= NCR_SSTAT0_RST; - ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); - } - } else - dev->sstat0 &= ~NCR_SSTAT0_RST; - break; - case 0x02: /* SCNTL2 */ - val &= ~(NCR_SCNTL2_WSR | NCR_SCNTL2_WSS); - dev->scntl2 = val; - break; - case 0x03: /* SCNTL3 */ - dev->scntl3 = val; - break; - case 0x04: /* SCID */ - dev->scid = val; - break; - case 0x05: /* SXFER */ - dev->sxfer = val; - break; - case 0x06: /* SDID */ - if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) - ncr53c8xx_log("Destination ID does not match SSID\n"); - dev->sdid = val & 0xf; - break; - case 0x07: /* GPREG */ - ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); - tmp = dev->gpreg; - dev->gpreg = val & 0xfe; -#ifdef USE_NVRAM - if ((dev->gpcntl & 0xc3) == 0x00) - ncr53c8xx_serial_eeprom_write(dev, val & 0x03); -#endif - break; - case 0x08: /* SFBR */ - /* The CPU is not allowed to write to this register. However the - SCRIPTS register move instructions are. */ - dev->sfbr = val; - break; - case 0x09: /* SOCL */ - ncr53c8xx_log("NCR 810: SOCL write %02X\n", val); - dev->socl = val; - break; - case 0x0a: case 0x0b: - /* Openserver writes to these readonly registers on startup */ - return; - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - /* Linux writes to these readonly registers on startup. */ - return; - CASE_SET_REG32(dsa, 0x10) - case 0x14: /* ISTAT */ - ncr53c8xx_log("ISTAT write: %02X\n", val); - tmp = dev->istat; - dev->istat = (dev->istat & 0x0f) | (val & 0xf0); - if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) - ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_ABRT); - if (val & NCR_ISTAT_INTF) { - dev->istat &= ~NCR_ISTAT_INTF; - ncr53c8xx_update_irq(dev); - } - - if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { - ncr53c8xx_log("Woken by SIGP\n"); - dev->waiting = 0; - dev->dsp = dev->dnad; - /* ncr53c8xx_execute_script(dev); */ - } - if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { - ncr53c8xx_soft_reset(dev); - ncr53c8xx_update_irq(dev); - dev->istat = 0; - } - break; - case 0x16: /* MBOX0 */ - dev->mbox0 = val; - break; - case 0x17: /* MBOX1 */ - dev->mbox1 = val; - break; - case 0x18: /* CTEST0 */ - /* nothing to do */ - break; - case 0x19: /* CTEST1 */ - /* nothing to do */ - break; - case 0x1a: /* CTEST2 */ - dev->ctest2 = val & NCR_CTEST2_PCICIE; - break; - case 0x1b: /* CTEST3 */ - dev->ctest3 = val & 0x0f; - break; - CASE_SET_REG32(temp, 0x1c) - case 0x21: /* CTEST4 */ - if (val & 7) - ncr53c8xx_log("Unimplemented CTEST4-FBL 0x%x\n", val); - dev->ctest4 = val; - break; - case 0x22: /* CTEST5 */ - if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) - ncr53c8xx_log("CTEST5 DMA increment not implemented\n"); - dev->ctest5 = val; - break; - CASE_SET_REG24(dbc, 0x24) - CASE_SET_REG32(dnad, 0x28) - case 0x2c: /* DSP[0:7] */ - dev->dsp &= 0xffffff00; - dev->dsp |= val; - break; - case 0x2d: /* DSP[8:15] */ - dev->dsp &= 0xffff00ff; - dev->dsp |= val << 8; - break; - case 0x2e: /* DSP[16:23] */ - dev->dsp &= 0xff00ffff; - dev->dsp |= val << 16; - break; - case 0x2f: /* DSP[24:31] */ - dev->dsp &= 0x00ffffff; - dev->dsp |= val << 24; - if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) - ncr53c8xx_execute_script(dev); - break; - CASE_SET_REG32(dsps, 0x30) - CASE_SET_REG32(scratcha, 0x34) - case 0x38: /* DMODE */ - dev->dmode = val; - break; - case 0x39: /* DIEN */ - ncr53c8xx_log("DIEN write: %02X\n", val); - dev->dien = val; - ncr53c8xx_update_irq(dev); - break; - case 0x3a: /* SBR */ - dev->sbr = val; - break; - case 0x3b: /* DCNTL */ - dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); - if ((val & NCR_DCNTL_STD) && dev->sstop) - ncr53c8xx_execute_script(dev); - break; - case 0x40: /* SIEN0 */ - dev->sien0 = val; - ncr53c8xx_update_irq(dev); - break; - case 0x41: /* SIEN1 */ - dev->sien1 = val; - ncr53c8xx_update_irq(dev); - break; - case 0x47: /* GPCNTL */ - ncr53c8xx_log("GPCNTL write: %02X\n", val); - dev->gpcntl = val; - break; - case 0x48: /* STIME0 */ - dev->stime0 = val; - break; - case 0x49: /* STIME1 */ - if (val & 0xf) { - ncr53c8xx_log("General purpose timer not implemented\n"); - /* ??? Raising the interrupt immediately seems to be sufficient - to keep the FreeBSD driver happy. */ - ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); - } - break; - case 0x4a: /* RESPID0 */ - dev->respid0 = val; - break; - case 0x4b: /* RESPID1 */ - if (dev->chip >= CHIP_825) - dev->respid1 = val; - break; - case 0x4d: /* STEST1 */ - dev->stest1 = val; - break; - case 0x4e: /* STEST2 */ - if (val & 1) - ncr53c8xx_log("Low level mode not implemented\n"); - dev->stest2 = val; - break; - case 0x4f: /* STEST3 */ - if (val & 0x41) - ncr53c8xx_log("SCSI FIFO test mode not implemented\n"); - dev->stest3 = val; - break; - case 0x54: - case 0x55: - break; - CASE_SET_REG32(scratchb, 0x5c) - CASE_SET_REG32(scratchc, 0x60) - CASE_SET_REG32(scratchd, 0x64) - CASE_SET_REG32(scratche, 0x68) - CASE_SET_REG32(scratchf, 0x6c) - CASE_SET_REG32(scratchg, 0x70) - CASE_SET_REG32(scratchh, 0x74) - CASE_SET_REG32(scratchi, 0x78) - CASE_SET_REG32(scratchj, 0x7c) - default: - ncr53c8xx_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); - } -#undef CASE_SET_REG24 -#undef CASE_SET_REG32 -} - - -static uint8_t -ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) -{ - uint8_t tmp; -#define CASE_GET_REG24(name, addr) \ - case addr: return dev->name & 0xff; \ - case addr + 1: return (dev->name >> 8) & 0xff; \ - case addr + 2: return (dev->name >> 16) & 0xff; - -#define CASE_GET_REG32(name, addr) \ - case addr: return dev->name & 0xff; \ - case addr + 1: return (dev->name >> 8) & 0xff; \ - case addr + 2: return (dev->name >> 16) & 0xff; \ - case addr + 3: return (dev->name >> 24) & 0xff; - -#define CASE_GET_REG32_COND(name, addr) \ - case addr: if (dev->chip >= CHIP_825) \ - return dev->name & 0xff; \ - else \ - return 0x00; \ - case addr + 1: if (dev->chip >= CHIP_825) \ - return (dev->name >> 8) & 0xff; \ - else \ - return 0x00; \ - case addr + 2: if (dev->chip >= CHIP_825) \ - return (dev->name >> 16) & 0xff; \ - else \ - return 0x00; \ - case addr + 3: if (dev->chip >= CHIP_825) \ - return (dev->name >> 24) & 0xff; \ - else \ - return 0x00; - - dev->regop = 1; - - switch (offset) { - case 0x00: /* SCNTL0 */ - ncr53c8xx_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); - return dev->scntl0; - case 0x01: /* SCNTL1 */ - ncr53c8xx_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); - return dev->scntl1; - case 0x02: /* SCNTL2 */ - ncr53c8xx_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); - return dev->scntl2; - case 0x03: /* SCNTL3 */ - ncr53c8xx_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); - return dev->scntl3; - case 0x04: /* SCID */ - ncr53c8xx_log("NCR 810: Read SCID %02X\n", dev->scid); - return dev->scid & ~0x40; - case 0x05: /* SXFER */ - ncr53c8xx_log("NCR 810: Read SXFER %02X\n", dev->sxfer); - return dev->sxfer; - case 0x06: /* SDID */ - ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); - return dev->sdid; - case 0x07: /* GPREG */ -#ifdef USE_NVRAM - tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; - if ((dev->gpcntl & 0xc3) == 0x01) - tmp |= ncr53c8xx_serial_eeprom_read(dev); -#else - tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; -#endif - ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); - return tmp; - case 0x08: /* Revision ID */ - ncr53c8xx_log("NCR 810: Read REVID 00\n"); - return 0x00; - case 0xa: /* SSID */ - ncr53c8xx_log("NCR 810: Read SSID %02X\n", dev->ssid); - return dev->ssid; - case 0xb: /* SBCL */ - /* Bit 7 = REQ (SREQ/ status) - Bit 6 = ACK (SACK/ status) - Bit 5 = BSY (SBSY/ status) - Bit 4 = SEL (SSEL/ status) - Bit 3 = ATN (SATN/ status) - Bit 2 = MSG (SMSG/ status) - Bit 1 = C/D (SC_D/ status) - Bit 0 = I/O (SI_O/ status) */ - tmp = (dev->sstat1 & 7); - ncr53c8xx_log("NCR 810: Read SBCL %02X\n", tmp); - return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ - case 0xc: /* DSTAT */ - tmp = dev->dstat | NCR_DSTAT_DFE; - if ((dev->istat & NCR_ISTAT_INTF) == 0) - dev->dstat = 0; - ncr53c8xx_update_irq(dev); - ncr53c8xx_log("NCR 810: Read DSTAT %02X\n", tmp); - return tmp; - case 0x0d: /* SSTAT0 */ - ncr53c8xx_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); - return dev->sstat0; - case 0x0e: /* SSTAT1 */ - ncr53c8xx_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); - return dev->sstat1; - case 0x0f: /* SSTAT2 */ - ncr53c8xx_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); - return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; - CASE_GET_REG32(dsa, 0x10) - case 0x14: /* ISTAT */ - ncr53c8xx_log("NCR 810: Read ISTAT %02X\n", dev->istat); - tmp = dev->istat; - return tmp; - case 0x16: /* MBOX0 */ - if (dev->chip >= CHIP_825) - return 0x00; - ncr53c8xx_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); - return dev->mbox0; - case 0x17: /* MBOX1 */ - if (dev->chip >= CHIP_825) - return 0x00; - ncr53c8xx_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); - return dev->mbox1; - case 0x18: /* CTEST0 */ - ncr53c8xx_log("NCR 810: Read CTEST0 FF\n"); - return 0xff; - case 0x19: /* CTEST1 */ - ncr53c8xx_log("NCR 810: Read CTEST1 F0\n"); - return 0xf0; /* dma fifo empty */ - case 0x1a: /* CTEST2 */ - tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; - if (dev->istat & NCR_ISTAT_SIGP) { - dev->istat &= ~NCR_ISTAT_SIGP; - tmp |= NCR_CTEST2_SIGP; - } - ncr53c8xx_log("NCR 810: Read CTEST2 %02X\n", tmp); - return tmp; - case 0x1b: /* CTEST3 */ - ncr53c8xx_log("NCR 810: Read CTEST3 %02X\n", - (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4)); - return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4); - CASE_GET_REG32(temp, 0x1c) - case 0x20: /* DFIFO */ - ncr53c8xx_log("NCR 810: Read DFIFO 00\n"); - return 0; - case 0x21: /* CTEST4 */ - ncr53c8xx_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); - return dev->ctest4; - case 0x22: /* CTEST5 */ - ncr53c8xx_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); - return dev->ctest5; - case 0x23: /* CTEST6 */ - ncr53c8xx_log("NCR 810: Read CTEST6 00\n"); - return 0; - CASE_GET_REG24(dbc, 0x24) - case 0x27: /* DCMD */ - ncr53c8xx_log("NCR 810: Read DCMD %02X\n", dev->dcmd); - return dev->dcmd; - CASE_GET_REG32(dnad, 0x28) - CASE_GET_REG32(dsp, 0x2c) - CASE_GET_REG32(dsps, 0x30) - CASE_GET_REG32(scratcha, 0x34) - case 0x38: /* DMODE */ - ncr53c8xx_log("NCR 810: Read DMODE %02X\n", dev->dmode); - return dev->dmode; - case 0x39: /* DIEN */ - ncr53c8xx_log("NCR 810: Read DIEN %02X\n", dev->dien); - return dev->dien; - case 0x3a: /* SBR */ - ncr53c8xx_log("NCR 810: Read SBR %02X\n", dev->sbr); - return dev->sbr; - case 0x3b: /* DCNTL */ - ncr53c8xx_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); - return dev->dcntl; - CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ - case 0x40: /* SIEN0 */ - ncr53c8xx_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); - return dev->sien0; - case 0x41: /* SIEN1 */ - ncr53c8xx_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); - return dev->sien1; - case 0x42: /* SIST0 */ - tmp = dev->sist0; - dev->sist0 = 0x00; - ncr53c8xx_update_irq(dev); - ncr53c8xx_log("NCR 810: Read SIST0 %02X\n", tmp); - return tmp; - case 0x43: /* SIST1 */ - tmp = dev->sist1; - dev->sist1 = 0x00; - ncr53c8xx_update_irq(dev); - ncr53c8xx_log("NCR 810: Read SIST1 %02X\n", tmp); - return tmp; - case 0x44: /* SLPAR */ - if (dev->chip < CHIP_825) - return 0x00; - ncr53c8xx_log("NCR 810: Read SLPAR %02X\n", dev->stime0); - return dev->slpar; - case 0x45: /* SWIDE */ - if (dev->chip < CHIP_825) - return 0x00; - ncr53c8xx_log("NCR 810: Read SWIDE %02X\n", dev->stime0); - return dev->swide; - case 0x46: /* MACNTL */ - ncr53c8xx_log("NCR 810: Read MACNTL 4F\n"); - return 0x4f; - case 0x47: /* GPCNTL */ - ncr53c8xx_log("NCR 810: Read GPCNTL %02X\n", dev->gpcntl); - return dev->gpcntl; - case 0x48: /* STIME0 */ - ncr53c8xx_log("NCR 810: Read STIME0 %02X\n", dev->stime0); - return dev->stime0; - case 0x4a: /* RESPID0 */ - if (dev->chip >= CHIP_825) - ncr53c8xx_log("NCR 810: Read RESPID0 %02X\n", dev->respid0); - else - ncr53c8xx_log("NCR 810: Read RESPID %02X\n", dev->respid0); - return dev->respid0; - case 0x4b: /* RESPID1 */ - if (dev->chip < CHIP_825) - return 0x00; - ncr53c8xx_log("NCR 810: Read RESPID1 %02X\n", dev->respid1); - return dev->respid1; - case 0x4c: /* STEST0 */ - ncr53c8xx_log("NCR 810: Read STEST0 %02X\n", dev->stest1); - return 0x00; - case 0x4d: /* STEST1 */ - ncr53c8xx_log("NCR 810: Read STEST1 %02X\n", dev->stest1); - return dev->stest1; - case 0x4e: /* STEST2 */ - ncr53c8xx_log("NCR 810: Read STEST2 %02X\n", dev->stest2); - return dev->stest2; - case 0x4f: /* STEST3 */ - ncr53c8xx_log("NCR 810: Read STEST3 %02X\n", dev->stest3); - return dev->stest3; - case 0x50: /* SIDL0 */ - /* This is needed by the linux drivers. We currently only update it - during the MSG IN phase. */ - if (dev->chip >= CHIP_825) - ncr53c8xx_log("NCR 810: Read SIDL0 %02X\n", dev->sidl0); - else - ncr53c8xx_log("NCR 810: Read SIDL %02X\n", dev->sidl0); - return dev->sidl0; - case 0x51: /* SIDL1 */ - if (dev->chip < CHIP_825) - return 0x00; - ncr53c8xx_log("NCR 810: Read SIDL1 %02X\n", dev->sidl1); - return dev->sidl1; - case 0x52: /* STEST4 */ - ncr53c8xx_log("NCR 810: Read STEST4 E0\n"); - return 0xe0; - case 0x58: /* SBDL */ - /* Some drivers peek at the data bus during the MSG IN phase. */ - if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { - ncr53c8xx_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); - return dev->msg[0]; - } - ncr53c8xx_log("NCR 810: Read SBDL 00\n"); - return 0; - case 0x59: /* SBDL high */ - ncr53c8xx_log("NCR 810: Read SBDLH 00\n"); - return 0; - CASE_GET_REG32(scratchb, 0x5c) - CASE_GET_REG32_COND(scratchc, 0x60) - CASE_GET_REG32_COND(scratchd, 0x64) - CASE_GET_REG32_COND(scratche, 0x68) - CASE_GET_REG32_COND(scratchf, 0x6c) - CASE_GET_REG32_COND(scratchg, 0x70) - CASE_GET_REG32_COND(scratchh, 0x74) - CASE_GET_REG32_COND(scratchi, 0x78) - CASE_GET_REG32_COND(scratchj, 0x7c) - } - ncr53c8xx_log("readb 0x%x\n", offset); - return 0; - -#undef CASE_GET_REG24 -#undef CASE_GET_REG32 -} - - -static uint8_t -ncr53c8xx_io_readb(uint16_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - return ncr53c8xx_reg_readb(dev, addr & 0xff); -} - - -static uint16_t -ncr53c8xx_io_readw(uint16_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - uint16_t val; - - addr &= 0xff; - val = ncr53c8xx_reg_readb(dev, addr); - val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; - return val; -} - - -static uint32_t -ncr53c8xx_io_readl(uint16_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - uint32_t val; - - addr &= 0xff; - val = ncr53c8xx_reg_readb(dev, addr); - val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; - val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; - val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; - return val; -} - - -static void -ncr53c8xx_io_writeb(uint16_t addr, uint8_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - ncr53c8xx_reg_writeb(dev, addr & 0xff, val); -} - - -static void -ncr53c8xx_io_writew(uint16_t addr, uint16_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - addr &= 0xff; - ncr53c8xx_reg_writeb(dev, addr, val & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); -} - - -static void -ncr53c8xx_io_writel(uint16_t addr, uint32_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - addr &= 0xff; - ncr53c8xx_reg_writeb(dev, addr, val & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); -} - - -static void -ncr53c8xx_mmio_writeb(uint32_t addr, uint8_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - ncr53c8xx_reg_writeb(dev, addr & 0xff, val); -} - - -static void -ncr53c8xx_mmio_writew(uint32_t addr, uint16_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - addr &= 0xff; - ncr53c8xx_reg_writeb(dev, addr, val & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); -} - - -static void -ncr53c8xx_mmio_writel(uint32_t addr, uint32_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - addr &= 0xff; - ncr53c8xx_reg_writeb(dev, addr, val & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); - ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); -} - - -static uint8_t -ncr53c8xx_mmio_readb(uint32_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - return ncr53c8xx_reg_readb(dev, addr & 0xff); -} - - -static uint16_t -ncr53c8xx_mmio_readw(uint32_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - uint16_t val; - - addr &= 0xff; - val = ncr53c8xx_reg_readb(dev, addr); - val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; - return val; -} - - -static uint32_t -ncr53c8xx_mmio_readl(uint32_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - uint32_t val; - - addr &= 0xff; - val = ncr53c8xx_reg_readb(dev, addr); - val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; - val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; - val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; - - return val; -} - - -static void -ncr53c8xx_ram_writeb(uint32_t addr, uint8_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - dev->ram[addr & 0x0fff] = val; -} - - -static void -ncr53c8xx_ram_writew(uint32_t addr, uint16_t val, void *p) -{ - ncr53c8xx_ram_writeb(addr, val & 0xff, p); - ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); -} - - -static void -ncr53c8xx_ram_writel(uint32_t addr, uint32_t val, void *p) -{ - ncr53c8xx_ram_writeb(addr, val & 0xff, p); - ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); - ncr53c8xx_ram_writeb(addr + 2, (val >> 16) & 0xff, p); - ncr53c8xx_ram_writeb(addr + 3, (val >> 24) & 0xff, p); -} - - -static uint8_t -ncr53c8xx_ram_readb(uint32_t addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - return dev->ram[addr & 0x0fff]; -} - - -static uint16_t -ncr53c8xx_ram_readw(uint32_t addr, void *p) -{ - uint16_t val; - - val = ncr53c8xx_ram_readb(addr, p); - val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; - - return val; -} - - -static uint32_t -ncr53c8xx_ram_readl(uint32_t addr, void *p) -{ - uint32_t val; - - val = ncr53c8xx_ram_readb(addr, p); - val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; - val |= ncr53c8xx_ram_readb(addr + 2, p) << 16; - val |= ncr53c8xx_ram_readb(addr + 3, p) << 24; - - return val; -} - - -static void -ncr53c8xx_io_set(ncr53c8xx_t *dev, uint32_t base, uint16_t len) -{ - ncr53c8xx_log("NCR53c8xx: [PCI] Setting I/O handler at %04X\n", base); - io_sethandler(base, len, - ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, - ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); -} - - -static void -ncr53c8xx_io_remove(ncr53c8xx_t *dev, uint32_t base, uint16_t len) -{ - ncr53c8xx_log("NCR53c8xx: Removing I/O handler at %04X\n", base); - io_removehandler(base, len, - ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, - ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); -} - - -static void -ncr53c8xx_mem_init(ncr53c8xx_t *dev, uint32_t addr) -{ - mem_mapping_add(&dev->mmio_mapping, addr, 0x100, - ncr53c8xx_mmio_readb, ncr53c8xx_mmio_readw, ncr53c8xx_mmio_readl, - ncr53c8xx_mmio_writeb, ncr53c8xx_mmio_writew, ncr53c8xx_mmio_writel, - NULL, MEM_MAPPING_EXTERNAL, dev); -} - - -static void -ncr53c8xx_ram_init(ncr53c8xx_t *dev, uint32_t addr) -{ - mem_mapping_add(&dev->ram_mapping, addr, 0x1000, - ncr53c8xx_ram_readb, ncr53c8xx_ram_readw, ncr53c8xx_ram_readl, - ncr53c8xx_ram_writeb, ncr53c8xx_ram_writew, ncr53c8xx_ram_writel, - NULL, MEM_MAPPING_EXTERNAL, dev); -} - - -static void -ncr53c8xx_mem_set_addr(ncr53c8xx_t *dev, uint32_t base) -{ - mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); -} - - -static void -ncr53c8xx_ram_set_addr(ncr53c8xx_t *dev, uint32_t base) -{ - mem_mapping_set_addr(&dev->ram_mapping, base, 0x1000); -} - - -#ifdef USE_BIOS_BAR -static void -ncr53c8xx_bios_set_addr(ncr53c8xx_t *dev, uint32_t base) -{ - mem_mapping_set_addr(&dev->bios.mapping, base, 0x10000); -} -#endif - - -static void -ncr53c8xx_mem_disable(ncr53c8xx_t *dev) -{ - mem_mapping_disable(&dev->mmio_mapping); -} - - -static void -ncr53c8xx_ram_disable(ncr53c8xx_t *dev) -{ - mem_mapping_disable(&dev->ram_mapping); -} - - -#ifdef USE_BIOS_BAR -static void -ncr53c8xx_bios_disable(ncr53c8xx_t *dev) -{ - mem_mapping_disable(&dev->bios.mapping); -} -#endif - - -uint8_t ncr53c8xx_pci_regs[256]; -bar_t ncr53c8xx_pci_bar[4]; - - -static uint8_t -ncr53c8xx_pci_read(int func, int addr, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - - ncr53c8xx_log("NCR53c8xx: Reading register %02X\n", addr & 0xff); - - if ((addr >= 0x80) && (addr <= 0xFF)) - return ncr53c8xx_reg_readb(dev, addr & 0x7F); - - switch (addr) { - case 0x00: - return 0x00; - case 0x01: - return 0x10; - case 0x02: - return dev->chip; - case 0x03: - return 0x00; - case 0x04: - return ncr53c8xx_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ - case 0x05: - return ncr53c8xx_pci_regs[0x05] & 0x01; - case 0x07: - return 2; - case 0x08: - return dev->chip_rev; /*Revision ID*/ - case 0x09: - return 0; /*Programming interface*/ - case 0x0A: - return 0; /*devubclass*/ - case 0x0B: - return 1; /*Class code*/ - case 0x0C: - case 0x0D: - return ncr53c8xx_pci_regs[addr]; - case 0x0E: - return 0; /*Header type */ - case 0x10: - return 1; /*I/O space*/ - case 0x11: - return ncr53c8xx_pci_bar[0].addr_regs[1]; - case 0x12: - return ncr53c8xx_pci_bar[0].addr_regs[2]; - case 0x13: - return ncr53c8xx_pci_bar[0].addr_regs[3]; - case 0x14: - return 0; /*Memory space*/ - case 0x15: - return ncr53c8xx_pci_bar[1].addr_regs[1]; - case 0x16: - return ncr53c8xx_pci_bar[1].addr_regs[2]; - case 0x17: - return ncr53c8xx_pci_bar[1].addr_regs[3]; - case 0x18: - return 0; /*Memory space*/ - case 0x19: - if (dev->chip < CHIP_825) - return 0; - return ncr53c8xx_pci_bar[2].addr_regs[1]; - case 0x1A: - if (dev->chip < CHIP_825) - return 0; - return ncr53c8xx_pci_bar[2].addr_regs[2]; - case 0x1B: - if (dev->chip < CHIP_825) - return 0; - return ncr53c8xx_pci_bar[2].addr_regs[3]; - case 0x2C: - return 0x00; - case 0x2D: - if (dev->chip >= CHIP_825) - return 0; - return 0x10; - case 0x2E: - if (dev->chip >= CHIP_825) - return 0; - return 0x01; - case 0x2F: - return 0x00; -#ifdef USE_BIOS_BAR - case 0x30: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; - return ncr53c8xx_pci_bar[3].addr_regs[0]; - case 0x31: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; - return ncr53c8xx_pci_bar[3].addr_regs[1]; - case 0x32: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; - return ncr53c8xx_pci_bar[3].addr_regs[2]; - case 0x33: - if ((dev->chip < CHIP_825) || !dev->has_bios) - return 0; - return ncr53c8xx_pci_bar[3].addr_regs[3]; -#endif - case 0x3C: - return dev->irq; - case 0x3D: - return PCI_INTA; - case 0x3E: - return 0x11; - case 0x3F: - return 0x40; - } - - return(0); -} - - -static void -ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - uint8_t valxor; - - ncr53c8xx_log("NCR53c8xx: Write value %02X to register %02X\n", val, addr & 0xff); - - if ((addr >= 0x80) && (addr <= 0xFF)) { - ncr53c8xx_reg_writeb(dev, addr & 0x7F, val); - return; - } - - switch (addr) - { - case 0x04: - valxor = (val & 0x57) ^ ncr53c8xx_pci_regs[addr]; - if (valxor & PCI_COMMAND_IO) { - ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); - if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) - ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); - } - if (valxor & PCI_COMMAND_MEM) { - ncr53c8xx_mem_disable(dev); - if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) - ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); - if (dev->chip >= CHIP_825) { - ncr53c8xx_ram_disable(dev); - if ((dev->RAMBase != 0) && (val & PCI_COMMAND_MEM)) - ncr53c8xx_ram_set_addr(dev, dev->RAMBase); - } - } - ncr53c8xx_pci_regs[addr] = val & 0x57; - break; - - case 0x05: - ncr53c8xx_pci_regs[addr] = val & 0x01; - break; - - case 0x0C: - case 0x0D: - ncr53c8xx_pci_regs[addr] = val; - break; - - case 0x10: case 0x11: case 0x12: case 0x13: - /* I/O Base set. */ - /* First, remove the old I/O. */ - ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); - /* Then let's set the PCI regs. */ - ncr53c8xx_pci_bar[0].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - ncr53c8xx_pci_bar[0].addr &= 0xff00; - dev->PCIBase = ncr53c8xx_pci_bar[0].addr; - /* Log the new base. */ - ncr53c8xx_log("NCR53c8xx: New I/O base is %04X\n" , dev->PCIBase); - /* We're done, so get out of the here. */ - if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_IO) { - if (dev->PCIBase != 0) { - ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); - } - } - return; - - case 0x15: case 0x16: case 0x17: - /* MMIO Base set. */ - /* First, remove the old I/O. */ - ncr53c8xx_mem_disable(dev); - /* Then let's set the PCI regs. */ - ncr53c8xx_pci_bar[1].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - ncr53c8xx_pci_bar[1].addr &= 0xffffc000; - dev->MMIOBase = ncr53c8xx_pci_bar[1].addr & 0xffffc000; - /* Log the new base. */ - ncr53c8xx_log("NCR53c8xx: New MMIO base is %08X\n" , dev->MMIOBase); - /* We're done, so get out of the here. */ - if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { - if (dev->MMIOBase != 0) - ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); - } - return; - - case 0x19: case 0x1A: case 0x1B: - if (dev->chip < CHIP_825) - return; - /* RAM Base set. */ - /* First, remove the old I/O. */ - ncr53c8xx_ram_disable(dev); - /* Then let's set the PCI regs. */ - ncr53c8xx_pci_bar[2].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - ncr53c8xx_pci_bar[2].addr &= 0xffffc000; - dev->RAMBase = ncr53c8xx_pci_bar[2].addr & 0xffffc000; - /* Log the new base. */ - ncr53c8xx_log("NCR53c8xx: New RAM base is %08X\n" , dev->RAMBase); - /* We're done, so get out of the here. */ - if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { - if (dev->RAMBase != 0) - ncr53c8xx_ram_set_addr(dev, dev->RAMBase); - } - return; - -#ifdef USE_BIOS_BAR - case 0x30: case 0x31: case 0x32: case 0x33: - return; - if ((dev->chip < CHIP_825) || !dev->has_bios) - return; - /* BIOS Base set. */ - /* First, remove the old I/O. */ - ncr53c8xx_bios_disable(dev); - /* Then let's set the PCI regs. */ - ncr53c8xx_pci_bar[3].addr_regs[addr & 3] = val; - /* Then let's calculate the new I/O base. */ - ncr53c8xx_pci_bar[3].addr &= 0xffff0001; - dev->BIOSBase = ncr53c8xx_pci_bar[3].addr & 0xffff0000; - /* Log the new base. */ - ncr53c8xx_log("NCR53c8xx: New BIOS base is %08X\n" , dev->BIOSBase); - /* We're done, so get out of the here. */ - if (ncr53c8xx_pci_bar[3].addr & 0x00000001) - ncr53c8xx_bios_set_addr(dev, dev->BIOSBase); - return; -#endif - - case 0x3C: - ncr53c8xx_pci_regs[addr] = val; - dev->irq = val; - return; - } -} - - -static void * -ncr53c8xx_init(const device_t *info) -{ - ncr53c8xx_t *dev; - - dev = malloc(sizeof(ncr53c8xx_t)); - memset(dev, 0x00, sizeof(ncr53c8xx_t)); - - dev->chip_rev = 0; - dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); - - ncr53c8xx_pci_bar[0].addr_regs[0] = 1; - ncr53c8xx_pci_bar[1].addr_regs[0] = 0; - dev->chip = info->local; - ncr53c8xx_pci_regs[0x04] = 3; - - ncr53c8xx_mem_init(dev, 0x0fffff00); - ncr53c8xx_mem_disable(dev); - - dev->has_bios = device_get_config_int("bios"); - if (dev->has_bios) - rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - if (dev->chip >= CHIP_825) { - - if (dev->chip == CHIP_875) { - dev->chip_rev = 0x04; - dev->nvr_path = L"ncr53c875.nvr"; - } else { - dev->chip_rev = 0x26; - dev->nvr_path = L"ncr53c825a.nvr"; - } - ncr53c8xx_pci_bar[2].addr_regs[0] = 0; - ncr53c8xx_pci_bar[3].addr = 0xffff0000; - /* Need to make it align on a 16k boundary as that's this emulator's - memory mapping granularity. */ - ncr53c8xx_ram_init(dev, 0x0fffc000); - ncr53c8xx_ram_disable(dev); - -#ifdef USE_BIOS_BAR - if (dev->has_bios) - ncr53c8xx_bios_disable(dev); -#endif - } else { - if (dev->has_bios) - rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - dev->nvr_path = L"ncr53c810.nvr"; - } - -#ifdef USE_NVRAM - /* Load the serial EEPROM. */ - ncr53c8xx_eeprom(dev, 0); -#endif - - ncr53c8xx_soft_reset(dev); - - timer_add(&dev->timer, ncr53c8xx_callback, dev, 0); - - return(dev); -} - - -static void -ncr53c8xx_close(void *priv) -{ - ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; - - if (dev) { - free(dev); - dev = NULL; - } -} - - -static const device_config_t ncr53c8xx_pci_config[] = { - { - "bios", "Enable BIOS", CONFIG_BINARY, "", 0 - }, - { - "", "", -1 - } -}; - - -const device_t ncr53c810_pci_device = -{ - "NCR 53c810 (SCSI)", - DEVICE_PCI, - 0x01, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - ncr53c8xx_pci_config -}; - -const device_t ncr53c825a_pci_device = -{ - "NCR 53c825A (SCSI)", - DEVICE_PCI, - CHIP_825, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - ncr53c8xx_pci_config -}; - -const device_t ncr53c875_pci_device = -{ - "NCR 53c875 (SCSI)", - DEVICE_PCI, - CHIP_875, - ncr53c8xx_init, ncr53c8xx_close, NULL, - NULL, NULL, NULL, - ncr53c8xx_pci_config -};