From 2c2e325f60eaabb0dd5585a79fbac5843699df1b Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 1 Oct 2017 16:26:12 +0100 Subject: [PATCH] Added emulation of Adaptec AHA-1542C and BusLogic BT-545S SCSI adapters. --- nvr/aha1542c.nvr | Bin 0 -> 32 bytes src/Makefile.am | 2 +- src/Makefile.linux32 | 2 +- src/Makefile.linux32-wx-sdl2 | 2 +- src/Makefile.linux64 | 2 +- src/Makefile.linux64-wx-sdl2 | 2 +- src/Makefile.mingw | 2 +- src/Makefile.mingw-network | 2 +- src/Makefile.mingw-wx-sdl2 | 2 +- src/Makefile.mingw-wx-sdl2-network | 2 +- src/Makefile.mingw64 | 2 +- src/Makefile.osx64-wx-sdl2 | 2 +- src/hdd.c | 3 + src/mem.c | 44 +- src/mem.h | 4 + src/scsi_aha1540.c | 2537 ++++++++++++++++++++++++++++ src/scsi_aha1540.h | 2 + 17 files changed, 2600 insertions(+), 12 deletions(-) create mode 100644 nvr/aha1542c.nvr create mode 100644 src/scsi_aha1540.c create mode 100644 src/scsi_aha1540.h diff --git a/nvr/aha1542c.nvr b/nvr/aha1542c.nvr new file mode 100644 index 0000000000000000000000000000000000000000..f62cc4bdef8aada151abd16edab1a7f24689a685 GIT binary patch literal 32 RcmZQC+{S> 14] && !(addr & 1)) + return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return mem_readb_phys(addr) | (mem_readb_phys(addr + 1) << 8); +} +uint32_t mem_readl_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_l[addr >> 14] && !(addr & 3)) + return _mem_read_l[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return mem_readw_phys(addr) | (mem_readw_phys(addr + 2) << 16); +} void mem_writeb_phys(uint32_t addr, uint8_t val) { mem_logical_addr = 0xffffffff; - + if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); } +void mem_writew_phys(uint32_t addr, uint16_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_w[addr >> 14] && !(addr & 1)) + _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + else + { + mem_writeb_phys(addr, val); + mem_writeb_phys(addr+1, val >> 8); + } +} +void mem_writel_phys(uint32_t addr, uint32_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_l[addr >> 14] && !(addr & 3)) + _mem_write_l[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + else + { + mem_writew_phys(addr, val); + mem_writew_phys(addr+2, val >> 16); + } +} uint8_t mem_read_ram(uint32_t addr, void *priv) { diff --git a/src/mem.h b/src/mem.h index fc4c574..618e8dc 100644 --- a/src/mem.h +++ b/src/mem.h @@ -79,7 +79,11 @@ extern int mem_a20_key; void mem_a20_recalc(); uint8_t mem_readb_phys(uint32_t addr); +uint16_t mem_readw_phys(uint32_t addr); +uint32_t mem_readl_phys(uint32_t addr); void mem_writeb_phys(uint32_t addr, uint8_t val); +void mem_writew_phys(uint32_t addr, uint16_t val); +void mem_writel_phys(uint32_t addr, uint32_t val); uint8_t mem_read_ram(uint32_t addr, void *priv); uint16_t mem_read_ramw(uint32_t addr, void *priv); diff --git a/src/scsi_aha1540.c b/src/scsi_aha1540.c new file mode 100644 index 0000000..43720a6 --- /dev/null +++ b/src/scsi_aha1540.c @@ -0,0 +1,2537 @@ +/*AH1542C firmware notes : + + d1a - command dispatch + 193c - send data + 1954 - get data + + FW data - 164e + + BIOS command table - f4b*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "nvr.h" +#include "pic.h" +#include "rom.h" +#include "scsi.h" +#include "scsi_aha1540.h" +#include "timer.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +int primed = 0; +typedef enum +{ + SCSI_AHA1542C, + SCSI_BT545S +} scsi_type_t; + +/*Firmware emulation is implemented via three state machines : + + - Command state - foreground command processing + - CCB state - CCB/mailbox processing - triggered by commands 0x02/0x82 + - SCSI state - SCSI bus handling / data transfer*/ +typedef enum +{ + CMD_STATE_RESET, + CMD_STATE_IDLE, + CMD_STATE_GET_PARAMS, + CMD_STATE_CMD_IN_PROGRESS, + CMD_STATE_SEND_RESULT +} cmd_state_t; + +typedef enum +{ + CCB_STATE_IDLE, + CCB_STATE_SEND_COMMAND, + CCB_STATE_WAIT_COMMAND, + CCB_STATE_SEND_REQUEST_SENSE, + CCB_STATE_WAIT_REQUEST_SENSE +} ccb_state_t; + +typedef enum +{ + SCSI_STATE_IDLE, + SCSI_STATE_SELECT, + SCSI_STATE_SELECT_FAILED, + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_NEXT_PHASE, + SCSI_STATE_END_PHASE, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE +} scsi_state_t; + +typedef enum +{ + MB_FORMAT_4, + MB_FORMAT_8 +} mb_format_t; + +typedef struct aha154x_t +{ + rom_t bios_rom; + mem_mapping_t mapping; + uint32_t bios_addr; + + uint8_t shadow_ram[0x4000]; + uint8_t shadow; + + uint32_t bios_bank; + + uint8_t eeprom[256]; + char fn[256]; + + scsi_type_t type; + + scsi_bus_t bus; + + uint8_t isr; + uint8_t isr_pending; + uint8_t status; + + uint8_t cmd_data; + uint8_t data_in; + + uint8_t command; + int command_len; + int cur_param; + uint8_t params[64]; + + int result_pos, result_len; + uint8_t result[256]; + + uint8_t dma_buffer[64]; + + uint8_t bon, boff; + uint8_t atbs; + + int mbc; + uint32_t mba; + uint32_t mba_i; + int mbo_req; + mb_format_t mb_format; + + int bios_mbc; + uint32_t bios_mba; + int bios_mbo_req; + + cmd_state_t cmd_state; + ccb_state_t ccb_state; + scsi_state_t scsi_state; + + int bios_cmd_state; + + int timer; + + int current_mbo; + int current_mbo_is_bios; + int current_mbi; + + uint8_t mblt, mbu; + + uint8_t int_buffer[512]; + + uint8_t e_d; + uint16_t to; + + uint8_t dipsw; + int irq, dma, host_id; + + struct + { + uint32_t addr; + + uint8_t opcode; + int target_id, transfer_dir, lun; + int scsi_cmd_len; + int req_sense_len; + uint32_t data_len; + uint32_t data_pointer; + uint32_t link_pointer; + uint8_t link_id; + + uint8_t cdb[256]; + + uint8_t status; + + int from_mailbox; + + uint32_t data_seg_list_pointer; + uint32_t data_seg_list_len; + uint32_t data_seg_list_idx; + + int residual; + + int bytes_transferred; + uint32_t total_data_len; + } ccb; + + struct + { + int idx, len; + uint8_t data[256]; + + int data_idx, data_len; + uint32_t data_pointer; + + uint8_t last_status; + + uint32_t data_seg_list_pointer; + uint32_t data_seg_list_len; + uint32_t data_seg_list_idx; + + int scatter_gather; + int bytes_transferred; + } cdb; +} aha154x_t; + +#define STATUS_INVDCMD 0x01 +#define STATUS_DF 0x04 +#define STATUS_CDF 0x08 +#define STATUS_IDLE 0x10 +#define STATUS_INIT 0x20 +#define STATUS_STST 0x80 + +#define CTRL_BRST 0x10 +#define CTRL_IRST 0x20 +#define CTRL_SRST 0x40 +#define CTRL_RESET 0x80 + +#define ISR_MBIF 0x01 +#define ISR_MBOA 0x02 +#define ISR_HACC 0x04 +#define ISR_ANYINTR 0x80 + +#define COMMAND_NOP 0x00 +#define COMMAND_MAILBOX_INITIALIZATION 0x01 +#define COMMAND_START_SCSI_COMMAND 0x02 +#define COMMAND_START_BIOS_COMMAND 0x03 +#define COMMAND_ADAPTER_INQUIRY 0x04 +#define COMMAND_SET_SELECTION_TIMEOUT 0x06 +#define COMMAND_SET_BUS_ON_TIME 0x07 +#define COMMAND_SET_BUS_OFF_TIME 0x08 +#define COMMAND_SET_AT_BUS_SPEED 0x09 +#define COMMAND_RETURN_CONFIG_DATA 0x0b +#define COMMAND_RETURN_SETUP_DATA 0x0d +#define COMMAND_WRITE_CHANNEL_2_BUF 0x1a +#define COMMAND_READ_CHANNEL_2_BUF 0x1b +#define COMMAND_ECHO 0x1f + +#define COMMAND_ADAPTEC_PROGRAM_EEPROM 0x22 +#define COMMAND_ADAPTEC_RETURN_EEPROM_DATA 0x23 +#define COMMAND_ADAPTEC_SET_SHADOW_PARAMS 0x24 +#define COMMAND_ADAPTEC_BIOS_MAILBOX_INIT 0x25 +#define COMMAND_ADAPTEC_SET_BIOS_BANK_1 0x26 +#define COMMAND_ADAPTEC_SET_BIOS_BANK_2 0x27 +#define COMMAND_ADAPTEC_GET_EXT_BIOS_INFO 0x28 +#define COMMAND_ENABLE_MAILBOX_INTERFACE 0x29 +#define COMMAND_ADAPTEC_START_BIOS_SCSI_CMD 0x82 + +#define COMMAND_BUSLOGIC_22 0x22 +#define COMMAND_BUSLOGIC_81 0x81 +#define COMMAND_BUSLOGIC_84 0x84 +#define COMMAND_BUSLOGIC_85 0x85 +#define COMMAND_BUSLOGIC_EXTENDED_SETUP_INFO 0x8d +#define COMMAND_BUSLOGIC_STRICT_RR 0x8f +#define COMMAND_BUSLOGIC_SET_CCB_FORMAT 0x96 + +#define COMMAND_FREE_CCB 0 +#define COMMAND_START_CCB 1 +#define COMMAND_ABORT_CCB 2 + +#define CCB_INITIATOR 0 +#define CCB_INITIATOR_SCATTER_GATHER 2 +#define CCB_INITIATOR_RESIDUAL 3 +#define CCB_INITIATOR_SCATTER_GATHER_RESIDUAL 4 + +#define CCB_SENSE_14 0x00 +#define CCB_SENSE_NONE 0x01 + +#define MBI_CCB_COMPLETE 0x01 +#define MBI_CCB_ABORTED 0x02 +#define MBI_CCB_COMPLETE_WITH_ERROR 0x04 + +#define HOST_STATUS_COMMAND_COMPLETE 0x00 +#define HOST_STATUS_SELECTION_TIME_OUT 0x11 + +#define POLL_TIME_US 10 +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 +/*10us poll period with 50 bytes transferred per poll = 5MB/sec*/ + +static void aha1542c_eeprom_save(aha154x_t *scsi); +static void process_cmd(aha154x_t *scsi); + +static void set_irq(aha154x_t *scsi, uint8_t val) +{ +// pclog("set_irq %02x %02x\n", scsi->isr, val); + if (!scsi->isr) + picint(1 << scsi->irq); + scsi->isr |= val; +} + +static void clear_irq(aha154x_t *scsi) +{ + picintc(1 << scsi->irq); +} + +static void aha154x_out(uint16_t port, uint8_t val, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + if (CS != 0xc800) + { +// pclog("aha154x_out: port=%04x val=%02x %04x:%04x %i\n", port, val, CS, cpu_state.pc, scsi->cmd_state); + } + + switch (port & 3) + { + case 0: /*Control register*/ + if (val & CTRL_RESET) + { + scsi->isr = 0; + clear_irq(scsi); + scsi->status = STATUS_STST; + pclog("hardware reset\n"); + scsi->cmd_state = CMD_STATE_RESET; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + scsi->mb_format = MB_FORMAT_4; + scsi->current_mbi = 0; + } + if (val & CTRL_SRST) + { + scsi->isr = 0; + clear_irq(scsi); + if (scsi->type == SCSI_BT545S) + scsi->status = STATUS_INIT; + else + scsi->status = 0; +// pclog("software reset\n"); + scsi->cmd_state = CMD_STATE_IDLE; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + scsi->mb_format = MB_FORMAT_4; + scsi->current_mbi = 0; + } + if (val & CTRL_IRST) + { + scsi->isr = 0; + clear_irq(scsi); +// update_irq(scsi); + if (scsi->type == SCSI_AHA1542C) + scsi->status &= ~STATUS_INVDCMD; + } + if (val & CTRL_BRST) + { + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; +// output = 3; + } + break; + + case 1: /*Command/data register*/ + if (scsi->status & STATUS_CDF) + break; + if (scsi->type == SCSI_BT545S) + scsi->status &= ~STATUS_INVDCMD; +// fatal("Write command reg while full\n"); + scsi->status |= STATUS_CDF; + scsi->cmd_data = val; + pclog("Write command %02x %04x(%08x):%08x\n", val, CS,cs,cpu_state.pc); + process_cmd(scsi); + break; + } +} + +static uint8_t aha154x_in(uint16_t port, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + uint8_t temp = 0xff; + +// if (primed) +// output = 3; + switch (port & 3) + { + case 0: /*Status register*/ + temp = scsi->status; + if (scsi->cmd_state == CMD_STATE_IDLE && scsi->ccb_state == CCB_STATE_IDLE && scsi->scsi_state == SCSI_STATE_IDLE) + temp |= STATUS_IDLE; + break; + + case 1: /*Data in register*/ +/* if (!(scsi->status & STATUS_DF)) + fatal("Read data in while empty\n");*/ + scsi->status &= ~STATUS_DF; + temp = scsi->data_in; + break; + + case 2: /*Interrupt status register*/ + temp = scsi->isr & ~0x70; + if (scsi->isr) + temp |= ISR_ANYINTR; + break; + + case 3: /*???*/ + if (scsi->type == SCSI_BT545S) + temp = 0x29; /*BT-545S BIOS expects this to return not zero or 0xff for six consecutive reads*/ + else + temp = 0xff; + break; + } + if (CS != 0xc800) + { +// pclog("aha154x_in: port=%04x val=%02x %04x(%08x):%04x %i %i\n", port, temp, CS, cs, cpu_state.pc, ins, scsi->cmd_state); + } + + return temp; +} + +static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed) +{ + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) == state && (bus_state & BUS_BSY)) + { + if (!req_needed || (bus_state & BUS_REQ)) + return 1; + } + } + + return 0; +} + +static void process_cdb(aha154x_t *scsi) +{ + int c; + uint8_t temp; + + scsi->ccb.opcode = mem_readb_phys(scsi->ccb.addr); + switch (scsi->ccb.opcode) + { + case CCB_INITIATOR: + case CCB_INITIATOR_RESIDUAL: + temp = mem_readb_phys(scsi->ccb.addr + 0x01); +// pclog("Read addr+ctrl %02x %06x\n", temp, scsi->ccb.addr+0x01); + scsi->ccb.transfer_dir = (temp >> 3) & 3; + scsi->ccb.scsi_cmd_len = mem_readb_phys(scsi->ccb.addr + 0x02); + scsi->ccb.req_sense_len = mem_readb_phys(scsi->ccb.addr + 0x03); + + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->ccb.lun = temp & 7; + scsi->ccb.target_id = (temp >> 5) & 7; + + scsi->ccb.data_len = mem_readb_phys(scsi->ccb.addr + 0x06) | (mem_readb_phys(scsi->ccb.addr + 0x05) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x04) << 16); + scsi->ccb.data_pointer = mem_readb_phys(scsi->ccb.addr + 0x09) | (mem_readb_phys(scsi->ccb.addr + 0x08) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x07) << 16); + scsi->ccb.link_pointer = mem_readb_phys(scsi->ccb.addr + 0x0c) | (mem_readb_phys(scsi->ccb.addr + 0x0b) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x0a) << 16); + scsi->ccb.link_id = mem_readb_phys(scsi->ccb.addr + 0x0d); + } + else + { + scsi->ccb.data_len = mem_readl_phys(scsi->ccb.addr + 0x04); + scsi->ccb.data_pointer = mem_readl_phys(scsi->ccb.addr + 0x08); + + scsi->ccb.target_id = mem_readb_phys(scsi->ccb.addr + 0x10); + scsi->ccb.lun = mem_readb_phys(scsi->ccb.addr + 0x11) & 0x1f; +// pclog("Target ID = %02x addr=%08x len=%08x\n", scsi->ccb.target_id, scsi->ccb.data_pointer, scsi->ccb.data_len); + } + for (c = 0; c < scsi->ccb.scsi_cmd_len; c++) + scsi->ccb.cdb[c] = mem_readb_phys(scsi->ccb.addr+0x12+c); +// pclog("CCB_INITIATOR: target=%i lun=%i\n", scsi->ccb.target_id, scsi->ccb.lun); +// pclog(" scsi_len=%i data_len=%06x data_pointer=%06x\n", scsi->ccb.scsi_cmd_len, scsi->ccb.data_len, scsi->ccb.data_pointer); + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->ccb.status = 0; + scsi->ccb.from_mailbox = 1; + scsi->ccb.residual = (scsi->ccb.opcode == CCB_INITIATOR_RESIDUAL); + scsi->ccb.total_data_len = scsi->ccb.data_len; + break; + + case CCB_INITIATOR_SCATTER_GATHER: + case CCB_INITIATOR_SCATTER_GATHER_RESIDUAL: +// pclog("Scatter-gather : %08x %08x %08x %08x %08x %i %02x\n", mem_readl_phys(scsi->ccb.addr),mem_readl_phys(scsi->ccb.addr+4),mem_readl_phys(scsi->ccb.addr+8),mem_readl_phys(scsi->ccb.addr+12),mem_readl_phys(scsi->ccb.addr+16), scsi->mb_format == MB_FORMAT_4, scsi->ccb.opcode); + temp = mem_readb_phys(scsi->ccb.addr + 0x01); +// pclog("Read addr+ctrl %02x %06x\n", temp, scsi->ccb.addr+0x01); + scsi->ccb.transfer_dir = (temp >> 3) & 3; + scsi->ccb.scsi_cmd_len = mem_readb_phys(scsi->ccb.addr + 0x02); + scsi->ccb.req_sense_len = mem_readb_phys(scsi->ccb.addr + 0x03); + + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->ccb.lun = temp & 7; + scsi->ccb.target_id = (temp >> 5) & 7; + + scsi->ccb.data_seg_list_len = mem_readb_phys(scsi->ccb.addr + 0x06) | (mem_readb_phys(scsi->ccb.addr + 0x05) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x04) << 16); + scsi->ccb.data_seg_list_pointer = mem_readb_phys(scsi->ccb.addr + 0x09) | (mem_readb_phys(scsi->ccb.addr + 0x08) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x07) << 16); + scsi->ccb.data_seg_list_idx = 0; + if (scsi->ccb.data_seg_list_len < 6) + pclog("Scatter gather table < 6 bytes\n"); + + scsi->ccb.link_pointer = mem_readb_phys(scsi->ccb.addr + 0x0c) | (mem_readb_phys(scsi->ccb.addr + 0x0b) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x0a) << 16); + scsi->ccb.link_id = mem_readb_phys(scsi->ccb.addr + 0x0d); + } + else + { + scsi->ccb.data_seg_list_len = mem_readl_phys(scsi->ccb.addr + 0x04); + scsi->ccb.data_seg_list_pointer = mem_readl_phys(scsi->ccb.addr + 0x08); + scsi->ccb.data_seg_list_idx = 0; + if (scsi->ccb.data_seg_list_len < 8) + pclog("Scatter gather table < 8 bytes\n"); + + scsi->ccb.target_id = mem_readb_phys(scsi->ccb.addr + 0x10); + scsi->ccb.lun = mem_readb_phys(scsi->ccb.addr + 0x11) & 0x1f; +// pclog("Target ID = %02x\n", scsi->ccb.target_id); + } + for (c = 0; c < scsi->ccb.scsi_cmd_len; c++) + scsi->ccb.cdb[c] = mem_readb_phys(scsi->ccb.addr+0x12+c); +// pclog("CCB_INITIATOR_SCATTER_GATHER: target=%i lun=%i\n", scsi->ccb.target_id, scsi->ccb.lun); +// pclog(" scsi_len=%i data_len=%06x data_pointer=%06x\n", scsi->ccb.scsi_cmd_len, scsi->ccb.data_len, scsi->ccb.data_pointer); + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->ccb.status = 0; + scsi->ccb.from_mailbox = 1; + scsi->ccb.residual = (scsi->ccb.opcode == CCB_INITIATOR_SCATTER_GATHER_RESIDUAL); + + if (scsi->ccb.residual) + { + /*Read total data length from scatter list, to use when calculating residual*/ + uint32_t addr = scsi->ccb.data_seg_list_pointer; + + scsi->ccb.total_data_len = 0; + + if (scsi->mb_format == MB_FORMAT_4) + { + for (c = 0; c < scsi->ccb.data_seg_list_len; c += 6) + { + uint32_t len = mem_readb_phys(addr + c + 2) | + (mem_readb_phys(addr + c + 1) << 8) | + (mem_readb_phys(addr + c) << 16); + + scsi->ccb.total_data_len += len; + } + } + else + { + for (c = 0; c < scsi->ccb.data_seg_list_len; c += 6) + { + uint32_t len = mem_readl_phys(addr + c); + + scsi->ccb.total_data_len += len; + } + } + } + break; + + default: + fatal("Unknown CCD opcode %02x\n", scsi->ccb.opcode); + } + pclog("Start CCB at %06x\n", scsi->ccb.addr); +} + +static void process_cmd(aha154x_t *scsi) +{ + uint32_t addr; + int c; + + switch (scsi->cmd_state) + { + case CMD_STATE_RESET: + scsi->status = STATUS_INIT; + scsi->cmd_state = CMD_STATE_IDLE; + pclog("AHA154x reset complete\n"); + break; + + case CMD_STATE_IDLE: + if (scsi->status & STATUS_CDF) + { + int invalid = 0; + + scsi->status &= ~STATUS_CDF; + + scsi->command = scsi->cmd_data; + pclog("New command %02x\n", scsi->command); +// if (scsi->command == 0x22) +// fatal("Here\n"); +// output = 3; + switch (scsi->command) + { + case COMMAND_NOP: + case COMMAND_START_SCSI_COMMAND: + case COMMAND_ADAPTER_INQUIRY: + case COMMAND_RETURN_CONFIG_DATA: + scsi->command_len = 0; + break; + + case COMMAND_ADAPTEC_SET_BIOS_BANK_1: + case COMMAND_ADAPTEC_SET_BIOS_BANK_2: + case COMMAND_ADAPTEC_GET_EXT_BIOS_INFO: + case COMMAND_ADAPTEC_START_BIOS_SCSI_CMD: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 0; + else + invalid = 1; + break; + + case COMMAND_BUSLOGIC_84: + case COMMAND_BUSLOGIC_85: + if (scsi->type == SCSI_BT545S) + scsi->command_len = 0; + else + invalid = 1; + break; + + case COMMAND_ECHO: + case COMMAND_SET_BUS_ON_TIME: + case COMMAND_SET_BUS_OFF_TIME: + case COMMAND_SET_AT_BUS_SPEED: + case COMMAND_RETURN_SETUP_DATA: + scsi->command_len = 1; + break; + + case COMMAND_ADAPTEC_SET_SHADOW_PARAMS: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 1; + else + invalid = 1; + break; + + case 0x22: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 35; /*COMMAND_ADAPTEC_PROGRAM_EEPROM*/ + else + { +// scsi->command_len = 1; /*COMMAND_BUSLOGIC_22*/ + pclog("Get 22\n"); +// scsi->command_len = 0; + invalid = 1; + primed = 1; + } + break; + + case COMMAND_BUSLOGIC_SET_CCB_FORMAT: + case COMMAND_BUSLOGIC_STRICT_RR: + case COMMAND_BUSLOGIC_EXTENDED_SETUP_INFO: + if (scsi->type == SCSI_BT545S) + scsi->command_len = 1; + else + invalid = 1; + break; + + case COMMAND_ENABLE_MAILBOX_INTERFACE: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 2; + else + invalid = 1; + break; + + case COMMAND_WRITE_CHANNEL_2_BUF: + case COMMAND_READ_CHANNEL_2_BUF: + scsi->command_len = 3; + break; + + case COMMAND_SET_SELECTION_TIMEOUT: + scsi->command_len = 4; + break; + + case COMMAND_ADAPTEC_RETURN_EEPROM_DATA: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 3; + else + invalid = 1; + break; + + case COMMAND_MAILBOX_INITIALIZATION: + scsi->command_len = 4; + break; + + case COMMAND_BUSLOGIC_81: + if (scsi->type == SCSI_BT545S) + scsi->command_len = 5; + else + invalid = 1; + break; + + case COMMAND_START_BIOS_COMMAND: + scsi->command_len = 10; + scsi->bios_cmd_state = 0; + break; + + case COMMAND_ADAPTEC_BIOS_MAILBOX_INIT: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 4; + else + invalid = 1; + break; + +/* case 0x40: case 0x42: case 0x44: case 0xff: + invalid = 1; + break;*/ + + default: + if (scsi->type == SCSI_AHA1542C) + { + if ((scsi->command > 0xd && scsi->command < 0x1a) || (scsi->command > 0x2a && scsi->command != 0x82)) + invalid = 1; + else + fatal("Bad AHA154x command %02x\n", scsi->command); + } + else + { + if (scsi->command > 0x22 && (scsi->command < 0xfa || scsi->command > 0xfc) && + !(scsi->command >= 0x81 && scsi->command <= 0x9d) && + scsi->command != 0xda && scsi->command != 0xdc) + invalid = 1; + else + fatal("Bad BT545S command %02x\n", scsi->command); + } + break; + } + + if (invalid) + { + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + } + else if (!scsi->command_len) + scsi->cmd_state = CMD_STATE_CMD_IN_PROGRESS; + else + { + scsi->cmd_state = CMD_STATE_GET_PARAMS; + scsi->cur_param = 0; + } + } + if (scsi->cmd_state != CMD_STATE_CMD_IN_PROGRESS) + { +// pclog("Command not fallthrough\n"); + break; + } +// pclog("Command fallthrough\n"); + /*Fallthrough*/ + + case CMD_STATE_CMD_IN_PROGRESS: + switch (scsi->command) + { + case COMMAND_NOP: +// pclog("NOP complete\n"); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_MAILBOX_INITIALIZATION: + scsi->mbc = scsi->params[0]; + scsi->mba = scsi->params[3] | (scsi->params[2] << 8) | (scsi->params[1] << 16); + scsi->mba_i = scsi->mba + scsi->mbc*4; + scsi->mb_format = MB_FORMAT_4; + pclog("Mailbox init: MBC=%02x MBC=%06x\n", scsi->mbc, scsi->mba); + scsi->status &= ~STATUS_INIT; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_START_SCSI_COMMAND: + pclog("START_SCSI_COMMAND %i %i\n", scsi->ccb_state, scsi->scsi_state); + scsi->mbo_req++; + scsi->cmd_state = CMD_STATE_IDLE; + /*Don't send IRQ until we actually start processing a mailbox*/ + break; + + case COMMAND_START_BIOS_COMMAND: + if (scsi->ccb_state != CCB_STATE_IDLE) + break; + if (!scsi->bios_cmd_state) + pclog("Start BIOS command %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + scsi->params[0], scsi->params[1], scsi->params[2], scsi->params[3], scsi->params[4], + scsi->params[5], scsi->params[6], scsi->params[7], scsi->params[8], scsi->params[9]); + if (scsi->params[0] >= 0x16) + { + /*Only commands below 0x16 are implemented*/ + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + } + else switch (scsi->params[0]) + { + case 0x00: /*Reset Disk System*/ + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x01: /*Get Status of Last Operation*/ + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x02: /*Read Sector(s) Into Memory*/ + switch (scsi->bios_cmd_state) + { + case 0: + { + int sector = scsi->params[5]; + int head = (scsi->params[4] & 0xf) | ((scsi->params[3] & 3) << 4); + int cylinder = (scsi->params[3] >> 2) | ((scsi->params[2] & 0xf) << 6); + + pclog("Cylinder=%i head=%i sector=%i\n", cylinder, head, sector); + addr = sector + (head * 32) + (cylinder * 64 * 32); + } + scsi->ccb.cdb[0] = SCSI_READ_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = addr >> 24; + scsi->ccb.cdb[3] = addr >> 16; + scsi->ccb.cdb[4] = addr >> 8; + scsi->ccb.cdb[5] = addr & 0xff; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = scsi->params[6]; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16);; + scsi->ccb.data_len = 512 * scsi->params[6]; + scsi->ccb.req_sense_len = CCB_SENSE_14; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + pclog("Read sector %08x %06x\n", addr, scsi->ccb.data_pointer); + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->ccb.status) + fatal("Read sector fail %02x\n", scsi->ccb.status); + scsi->data_in = 0x00; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case 0x03: /*Write Disk Sector(s)*/ + switch (scsi->bios_cmd_state) + { + case 0: + { + int sector = scsi->params[5]; + int head = (scsi->params[4] & 0xf) | ((scsi->params[3] & 3) << 4); + int cylinder = (scsi->params[3] >> 2) | ((scsi->params[2] & 0xf) << 6); + + addr = sector + (head * 32) + (cylinder * 64 * 32); + } + scsi->ccb.cdb[0] = SCSI_WRITE_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = addr >> 24; + scsi->ccb.cdb[3] = addr >> 16; + scsi->ccb.cdb[4] = addr >> 8; + scsi->ccb.cdb[5] = addr & 0xff; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = scsi->params[6]; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16);; + scsi->ccb.data_len = 512 * scsi->params[6]; + scsi->ccb.req_sense_len = CCB_SENSE_14; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + pclog("Write sector %08x %06x\n", addr, scsi->ccb.data_pointer); + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->ccb.status) + fatal("Write sector fail %02x\n", scsi->ccb.status); + scsi->data_in = 0x00; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case 0x04: /*Verify Disk Sector(s)*/ + switch (scsi->bios_cmd_state) + { + case 0: + { + int sector = scsi->params[5]; + int head = (scsi->params[4] & 0xf) | ((scsi->params[3] & 3) << 4); + int cylinder = (scsi->params[3] >> 2) | ((scsi->params[2] & 0xf) << 6); + + addr = sector + (head * 32) + (cylinder * 64 * 32); + } + scsi->ccb.cdb[0] = SCSI_VERIFY_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = addr >> 24; + scsi->ccb.cdb[3] = addr >> 16; + scsi->ccb.cdb[4] = addr >> 8; + scsi->ccb.cdb[5] = addr & 0xff; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = scsi->params[6]; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16);; + scsi->ccb.data_len = 512 * scsi->params[6]; + scsi->ccb.req_sense_len = CCB_SENSE_14; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + pclog("Verify sector %08x %06x\n", addr, scsi->ccb.data_pointer); + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->ccb.status) + fatal("Verify sector fail %02x\n", scsi->ccb.status); + scsi->data_in = 0x00; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + /*AHA1542C firmware just fails all of these*/ + case 0x05: case 0x06: case 0x07: + case 0x0a: case 0x0b: + case 0x12: case 0x13: + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x08: /*Get Drive Parameters*/ + switch (scsi->bios_cmd_state) + { + case 0: + scsi->ccb.cdb[0] = SCSI_READ_CAPACITY_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = 0; + scsi->ccb.cdb[3] = 0; + scsi->ccb.cdb[4] = 0; + scsi->ccb.cdb[5] = 0; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = 0; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = -1; + scsi->ccb.data_len = 8; + scsi->ccb.req_sense_len = CCB_SENSE_NONE; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->bios_cmd_state++; + break; + case 1: + addr = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16); + mem_writeb_phys(addr, scsi->int_buffer[0]); + mem_writeb_phys(addr+1, scsi->int_buffer[1]); + mem_writeb_phys(addr+2, scsi->int_buffer[2]); + mem_writeb_phys(addr+3, scsi->int_buffer[3]); + pclog("Got size %06x %02x%02x%02x%02x\n", addr, scsi->int_buffer[3],scsi->int_buffer[2],scsi->int_buffer[1],scsi->int_buffer[0]); + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case 0x09: /*Initialize Drive Parameters*/ + case 0x0c: /*Seek To Cylinder*/ + case 0x0d: /*Reset Hard Disks*/ + case 0x0e: /*Read Sector Buffer*/ + case 0x0f: /*Write Sector Buffer*/ + case 0x10: /*Check If Drive Ready*/ + case 0x11: /*Recalibrate Drive*/ + case 0x14: /*Controller Internal Diagnostic*/ + pclog("Unimplemented AHA1542 BIOS command - 0x%02x\n", scsi->params[0]); + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x15: /*Get Disk Type*/ + switch (scsi->bios_cmd_state) + { + case 0: + scsi->ccb.cdb[0] = SCSI_INQUIRY; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = 0; + scsi->ccb.cdb[3] = 0; + scsi->ccb.cdb[4] = 36; + scsi->ccb.cdb[5] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 6; + scsi->ccb.data_pointer = -1; + scsi->ccb.data_len = 36; + scsi->ccb.req_sense_len = CCB_SENSE_NONE; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->ccb.from_mailbox = 0; + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->int_buffer[0] & 0x1f) + { + /*Not a direct-access device*/ + fatal("Not a direct-access device\n"); + } + scsi->ccb.cdb[0] = SCSI_READ_CAPACITY_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = 0; + scsi->ccb.cdb[3] = 0; + scsi->ccb.cdb[4] = 0; + scsi->ccb.cdb[5] = 0; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = 0; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = -1; + scsi->ccb.data_len = 8; + scsi->ccb.req_sense_len = CCB_SENSE_NONE; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->bios_cmd_state++; + break; + case 2: + addr = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16); + mem_writeb_phys(addr, scsi->int_buffer[0]); + mem_writeb_phys(addr+1, scsi->int_buffer[1]); + mem_writeb_phys(addr+2, scsi->int_buffer[2]); + mem_writeb_phys(addr+3, scsi->int_buffer[3]); + pclog("Got size %06x %02x%02x%02x%02x\n", addr, scsi->int_buffer[3],scsi->int_buffer[2],scsi->int_buffer[1],scsi->int_buffer[0]); + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + default: + fatal("Get Disk Type state %i\n", scsi->bios_cmd_state); + } + //fatal("data_pointer %06x\n", scsi->ccb.data_pointer); + break; + + default: + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case COMMAND_ADAPTER_INQUIRY: + if (scsi->type == SCSI_BT545S) + { + scsi->result[0] = 0x41; + scsi->result[1] = 0x41; /*Standard model*/ + scsi->result[2] = 0x33; /*Firmware revision*/ + scsi->result[3] = 0x33; + } + else + { + scsi->result[0] = 0x44; /*AHA-1542CF*/ + scsi->result[1] = 0x30; + scsi->result[2] = 0x30; /*Firmware revision*/ + scsi->result[3] = 0x31; + } + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 4; + break; + + case COMMAND_SET_SELECTION_TIMEOUT: + scsi->e_d = scsi->params[0]; + scsi->to = (scsi->params[1] << 8) | scsi->params[2]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_BUS_ON_TIME: + scsi->bon = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_BUS_OFF_TIME: + scsi->boff = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_AT_BUS_SPEED: + scsi->atbs = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_RETURN_CONFIG_DATA: + scsi->result[0] = 1 << scsi->dma; + scsi->result[1] = 1 << (scsi->irq-9); + scsi->result[2] = scsi->host_id; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 3; + break; + + case COMMAND_ECHO: + pclog("ECHO\n"); + scsi->result[0] = scsi->params[0]; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 1; + break; + + case COMMAND_RETURN_SETUP_DATA: + pclog("Return setup data %i %02x %06x\n", scsi->params[0], scsi->mbc, scsi->mba); + scsi->result[0] = 0x00; /*SPS*/ + scsi->result[1] = scsi->atbs; /*AT bus speed*/ + scsi->result[2] = scsi->bon; /*BON*/ + scsi->result[3] = scsi->boff; /*BOFF*/ + scsi->result[4] = scsi->mbc; /*DS:E8 - mailbox count*/ + scsi->result[5] = scsi->mba >> 16; /*DS:DA - set by command 0x81?*/ + scsi->result[6] = scsi->mba >> 8; /*DS:DB*/ + scsi->result[7] = scsi->mba & 0xff; /*DS:DC*/ + scsi->result[8] = 0x00; /*STA0*/ + scsi->result[9] = 0x00; /*STA1*/ + scsi->result[10] = 0x00; /*STA2*/ + scsi->result[11] = 0x00; /*STA3*/ + scsi->result[12] = 0x00; /*STA4*/ + scsi->result[13] = 0x00; /*STA5*/ + scsi->result[14] = 0x00; /*STA6*/ + scsi->result[15] = 0x00; /*STA7*/ + scsi->result[16] = 0x00; /*DS (DS:1e5b)*/ + if (scsi->type == SCSI_BT545S) + { + scsi->result[17] = 0x42; /*Firmware version*/ + scsi->result[18] = 0x44; + scsi->result[19] = 0x41; + } + else + { + for (c = 0; c < 20; c++) + scsi->result[c+17] = 0; /*Customer signature*/ + scsi->result[37] = 0; /*Auto-retry*/ + scsi->result[38] = 0; /*Board switches*/ + scsi->result[39] = 0xa3; /*Checksum*/ + scsi->result[40] = 0xc2; + scsi->result[41] = scsi->bios_mba >> 16; + scsi->result[42] = scsi->bios_mba >> 8; + scsi->result[43] = scsi->bios_mba & 0xff; + } + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = MIN(scsi->params[0], 20); + for (; scsi->result_len < scsi->params[0]; scsi->result_len++) + scsi->result[scsi->result_len] = 0; + break; + + case COMMAND_WRITE_CHANNEL_2_BUF: + addr = scsi->params[2] | (scsi->params[1] << 8) | (scsi->params[0] << 16); + pclog("WRITE_CHANNEL_2_BUF %06x\n", addr); + for (c = 0; c < 64; c++) + scsi->dma_buffer[c] = mem_readb_phys(addr + c); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + pclog("Command complete\n"); + break; + + case COMMAND_READ_CHANNEL_2_BUF: + addr = scsi->params[2] | (scsi->params[1] << 8) | (scsi->params[0] << 16); + pclog("READ_CHANNEL_2_BUF %06x\n", addr); + for (c = 0; c < 64; c++) + mem_writeb_phys(addr + c, scsi->dma_buffer[c]); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + pclog("Command complete\n"); + break; + + case 0x22: + if (scsi->type == SCSI_AHA1542C) + { + /*COMMAND_ADAPTEC_PROGRAM_EEPROM*/ + for (c = 0; c < scsi->params[1]; c++) + { + pclog("EEPROM %02x = %02x\n", (scsi->params[2] + c) & 0xff, scsi->params[c+3]); + scsi->eeprom[(scsi->params[2] + c) & 0xff] = scsi->params[c+3]; + } + scsi->host_id = scsi->eeprom[0] & 7; + scsi->dma = (scsi->eeprom[1] >> 4) & 7; + scsi->irq = (scsi->eeprom[1] & 7) + 9; + pclog("Program EEPROM: IRQ=%i DMA=%i host_id=%i\n", scsi->irq, scsi->dma, scsi->host_id); + + aha1542c_eeprom_save(scsi); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + } + else + { + /*COMMAND_BUSLOGIC_22*/ + pclog("BUSLOGIC_22\n"); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + primed = 1; +// scsi->result[0] = 1 << scsi->dma; /*DMA7*/ +// scsi->result[1] = 1 << (scsi->irq-9); /*IRQ10*/ +// scsi->result[2] = scsi->host_id; /*SCSI ID*/ +// scsi->cmd_state = CMD_STATE_SEND_RESULT; +// scsi->result_pos = 0; +// scsi->result_len = 3; + } + break; + + case COMMAND_ADAPTEC_RETURN_EEPROM_DATA: + pclog("Return EEPROM data %02x %02x %02x\n", scsi->params[0], scsi->params[1], scsi->params[2]); + for (c = 0; c < scsi->params[1]; c++) + { + scsi->result[c] = scsi->eeprom[(scsi->params[2] + c) & 0xff]; + pclog(" EEPROM data %02x %02x\n", (scsi->params[2] + c) & 0xff, scsi->result[c]); + } + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = c; + break; + + case COMMAND_ADAPTEC_SET_SHADOW_PARAMS: + pclog("Set shadow params %02x\n", scsi->params[0]); + scsi->shadow = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_BIOS_MAILBOX_INIT: + scsi->bios_mbc = scsi->params[0]; + scsi->bios_mba = scsi->params[3] | (scsi->params[2] << 8) | (scsi->params[1] << 16); + pclog("BIOS mailbox init: MBC=%02x MBC=%06x\n", scsi->bios_mbc, scsi->bios_mba); + scsi->status &= ~STATUS_INIT; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_SET_BIOS_BANK_1: + mem_mapping_set_exec(&scsi->mapping, &scsi->bios_rom.rom[0]); + scsi->bios_bank = 0x0000; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_SET_BIOS_BANK_2: + mem_mapping_set_exec(&scsi->mapping, &scsi->bios_rom.rom[0x4000]); + scsi->bios_bank = 0x4000; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_GET_EXT_BIOS_INFO: + scsi->result[0] = 0; + scsi->result[1] = scsi->mblt; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 2; + break; + + case COMMAND_ENABLE_MAILBOX_INTERFACE: + scsi->mbu = scsi->params[0]; + scsi->mblt = scsi->params[1]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_START_BIOS_SCSI_CMD: + pclog("START_BIOS_SCSI_COMMAND %02x %08x %i\n", scsi->bios_mbc, scsi->bios_mba, scsi->ccb_state); + scsi->bios_mbo_req++; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_BUSLOGIC_81: + scsi->mbc = scsi->params[0]; + scsi->mba = scsi->params[1] | (scsi->params[2] << 8) | (scsi->params[3] << 16) | (scsi->params[4] << 24); + scsi->mba_i = scsi->mba + scsi->mbc*8; + scsi->mb_format = MB_FORMAT_8; + pclog("Mailbox init: MBC=%02x MBC=%08x\n", scsi->mbc, scsi->mba); + scsi->status &= ~STATUS_INIT; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_BUSLOGIC_84: + scsi->result[0] = 0x31; /*Firmware sub-version?*/ + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 1; + break; + + case COMMAND_BUSLOGIC_85: + scsi->result[0] = 0x20; /*???*/ + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 1; + break; + + case COMMAND_BUSLOGIC_EXTENDED_SETUP_INFO: + pclog("Extended setup info %i\n", scsi->params[0]); + scsi->result[0] = 0x41; + scsi->result[1] = scsi->bios_addr >> 12; /*BIOS addr*/ + scsi->result[2] = 0x00; + scsi->result[3] = 0x20; + scsi->result[4] = 0x00; /*DS:E8 >> 3*/ + scsi->result[5] = 0x00; /*DS:DA - set by command 0x81?*/ + scsi->result[6] = 0x00; /*DS:DB*/ + scsi->result[7] = 0x00; /*DS:DC*/ + scsi->result[8] = 0x00; /*DS:DD*/ + scsi->result[9] = 0x33; /*FFFF:9*/ + scsi->result[10] = 0x33; /*FFFF:A*/ + scsi->result[11] = 0x31; /*FFFF:B*/ + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = MIN(scsi->params[0], 12); + for (; scsi->result_len < scsi->params[0]; scsi->result_len++) + scsi->result[scsi->result_len] = 0; + break; + + case COMMAND_BUSLOGIC_STRICT_RR: + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_BUSLOGIC_SET_CCB_FORMAT: + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + default: + fatal("Bad AHA154x command in progress %02x\n", scsi->command); + } + break; + + case CMD_STATE_GET_PARAMS: + if (scsi->status & STATUS_CDF) + { + scsi->status &= ~STATUS_CDF; + + scsi->params[scsi->cur_param++] = scsi->cmd_data; + + if (scsi->cur_param == scsi->command_len) + scsi->cmd_state = CMD_STATE_CMD_IN_PROGRESS; + } + break; + + case CMD_STATE_SEND_RESULT: + if (!(scsi->status & STATUS_DF)) + { + if (scsi->result_pos == scsi->result_len) + { + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + pclog("Command complete\n"); + } + else + { + scsi->status |= STATUS_DF; + scsi->data_in = scsi->result[scsi->result_pos++]; + pclog("Return data %02x %i %i\n", scsi->data_in, scsi->result_pos-1, scsi->result_len); + } + } + break; + + default: + fatal("Unknown state %d\n", scsi->cmd_state); + } +} + +static void process_ccb(aha154x_t *scsi) +{ + int c; + + switch (scsi->ccb_state) + { + case CCB_STATE_IDLE: + if (scsi->status & STATUS_INIT) + break; + if (scsi->mbo_req) + { +// pclog("mbo_req %i\n", scsi->mbc); + for (c = 0; c < scsi->mbc; c++) + { + uint32_t ccb; + uint8_t command; + + if (scsi->mb_format == MB_FORMAT_4) + { + uint32_t mbo = mem_readl_phys(scsi->mba + c*4); + command = mbo & 0xff; + ccb = (mbo >> 24) | ((mbo >> 8) & 0xff00) | ((mbo << 8) & 0xff0000); +// pclog("MBO%02x = %08x\n", c, mbo); + } + else + { + ccb = mem_readl_phys(scsi->mba + c*8); + command = mem_readb_phys(scsi->mba + c*8 + 7); +// pclog("MBO%02x = %08x %02x\n", c, ccb, command); + } + + if (command == COMMAND_START_CCB) + { + pclog("Start CCB %08x %i\n", ccb, c); + + scsi->current_mbo = c; + scsi->current_mbo_is_bios = 0; + scsi->ccb.addr = ccb; + + process_cdb(scsi); + + scsi->mbo_req--; + + set_irq(scsi, ISR_HACC); + break; + } + else if (command == COMMAND_ABORT_CCB) + { +// fatal("Abort command\n"); + scsi->mbo_req--; + + if (scsi->mb_format == MB_FORMAT_4) + { + mem_writeb_phys(scsi->mba + c*8, 0); + + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_ABORTED); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, ccb >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, ccb >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, ccb & 0xff); + } + else + { + mem_writeb_phys(scsi->mba + c*8 + 7, 0); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, ccb); + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_ABORTED); + } + + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, ISR_MBOA | ISR_MBIF | ISR_HACC); + break; + } + } + } + if (scsi->bios_mbo_req) + { + for (c = 0; c < scsi->bios_mbc; c++) + { + uint32_t ccb; + uint8_t command; + + uint32_t mbo = mem_readl_phys(scsi->bios_mba + c*4); + command = mbo & 0xff; + ccb = (mbo >> 24) | ((mbo >> 8) & 0xff00) | ((mbo << 8) & 0xff0000); + + if (command == COMMAND_START_CCB) + { + pclog("Start BIOS CCB %08x %i\n", ccb, c); + + scsi->current_mbo = c; + scsi->current_mbo_is_bios = 1; + scsi->ccb.addr = ccb; + + process_cdb(scsi); + + scsi->bios_mbo_req--; + set_irq(scsi, ISR_HACC); + break; + } + } + } + break; + + case CCB_STATE_SEND_COMMAND: + if (scsi->scsi_state != SCSI_STATE_IDLE) + break; /*Wait until SCSI state machine is ready for new command*/ + for (c = 0; c < scsi->ccb.scsi_cmd_len; c++) + { + scsi->cdb.data[c] = scsi->ccb.cdb[c]; +// pclog(" CDB[%02x]=%02x\n", c, scsi->cdb.data[c]); + } + scsi->cdb.len = scsi->ccb.scsi_cmd_len; + scsi->cdb.idx = 0; + if (scsi->ccb.opcode == CCB_INITIATOR_SCATTER_GATHER || scsi->ccb.opcode == CCB_INITIATOR_SCATTER_GATHER_RESIDUAL) + { + scsi->cdb.data_seg_list_len = scsi->ccb.data_seg_list_len; + scsi->cdb.data_seg_list_pointer = scsi->ccb.data_seg_list_pointer; + scsi->cdb.data_seg_list_idx = 0; + scsi->cdb.scatter_gather = 1; + scsi->cdb.data_len = 0; + scsi->cdb.data_idx = 0; + } + else + { + scsi->cdb.data_pointer = scsi->ccb.data_pointer; + scsi->cdb.data_len = scsi->ccb.data_len; + scsi->cdb.scatter_gather = 0; + } + scsi->cdb.bytes_transferred = 0; + scsi->cdb.data_idx = 0; + scsi->scsi_state = SCSI_STATE_SELECT; + /*SCSI will now select the device and execute the command*/ + scsi->ccb_state = CCB_STATE_WAIT_COMMAND; + break; + + case CCB_STATE_WAIT_COMMAND: + if (scsi->scsi_state == SCSI_STATE_SELECT_FAILED) + { + pclog("Command select has failed\n"); + if (scsi->ccb.from_mailbox) + { + mem_writeb_phys(scsi->ccb.addr + 0xe, HOST_STATUS_SELECTION_TIME_OUT); + + if (scsi->mb_format == MB_FORMAT_4) + { + if (scsi->current_mbo_is_bios) + { + mem_writeb_phys(scsi->bios_mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE_WITH_ERROR); + } + else + { + mem_writeb_phys(scsi->mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE_WITH_ERROR); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, scsi->ccb.addr >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, scsi->ccb.addr >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, scsi->ccb.addr & 0xff); + } + } + else + { + if (scsi->current_mbo_is_bios) + fatal("MBO_IS_BIOS MB_FORMAT_8\n"); + mem_writeb_phys(scsi->mba + scsi->current_mbo*8 + 7, COMMAND_FREE_CCB); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, scsi->ccb.addr); + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE_WITH_ERROR << 24); + } + + if (!scsi->current_mbo_is_bios) + { + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, ISR_MBOA | ISR_MBIF); + } + else + set_irq(scsi, ISR_MBOA); + } +// set_irq(scsi, ISR_HACC); + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + break; + } + if (scsi->scsi_state != SCSI_STATE_IDLE) + break; /*Wait until SCSI state machine has completed command*/ + scsi->ccb.status = scsi->cdb.last_status; + scsi->ccb.bytes_transferred = scsi->cdb.bytes_transferred; + scsi->ccb_state = CCB_STATE_SEND_REQUEST_SENSE; + break; + + case CCB_STATE_SEND_REQUEST_SENSE: + if (scsi->ccb.req_sense_len == CCB_SENSE_NONE) + { +// pclog("No sense data\n"); + if (scsi->ccb.from_mailbox) + { + uint32_t residue = scsi->ccb.total_data_len - scsi->ccb.bytes_transferred; + +// pclog("Residue=%08x %x %x %i MBI=%i\n", residue, scsi->ccb.total_data_len, scsi->ccb.bytes_transferred, scsi->ccb.residual, scsi->current_mbi); + mem_writeb_phys(scsi->ccb.addr + 0xe, HOST_STATUS_COMMAND_COMPLETE); + + if (scsi->mb_format == MB_FORMAT_4) + { + if (scsi->ccb.residual) + { + mem_writeb_phys(scsi->ccb.addr + 0x4, residue >> 16); + mem_writeb_phys(scsi->ccb.addr + 0x5, residue >> 8); + mem_writeb_phys(scsi->ccb.addr + 0x6, residue & 0xff); + } + + if (scsi->current_mbo_is_bios) + { + mem_writeb_phys(scsi->bios_mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE_WITH_ERROR); + } + else + { + mem_writeb_phys(scsi->mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE_WITH_ERROR); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, scsi->ccb.addr >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, scsi->ccb.addr >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, scsi->ccb.addr & 0xff); + } + } + else + { + if (scsi->current_mbo_is_bios) + fatal("MBO_IS_BIOS MB_FORMAT_8\n"); + + if (scsi->ccb.residual) + mem_writel_phys(scsi->ccb.addr + 0x4, residue); + + mem_writeb_phys(scsi->mba + scsi->current_mbo*8 + 7, COMMAND_FREE_CCB); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, scsi->ccb.addr); + if (scsi->ccb.status == STATUS_GOOD) + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE << 24); + else + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE_WITH_ERROR << 24); + } + + if (!scsi->current_mbo_is_bios) + { + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, ISR_MBOA | ISR_MBIF); + } + else + set_irq(scsi, ISR_MBOA); + } + scsi->ccb_state = CCB_STATE_IDLE; + break; + } + /*Build request sense command*/ + scsi->cdb.data[0] = SCSI_REQUEST_SENSE; + scsi->cdb.data[1] = scsi->ccb.lun << 5; + scsi->cdb.data[2] = 0x00; + scsi->cdb.data[3] = 0x00; + if (scsi->ccb.req_sense_len == CCB_SENSE_14) + scsi->cdb.data[4] = 14; + else + scsi->cdb.data[4] = scsi->ccb.req_sense_len; + scsi->cdb.data[5] = 14; + scsi->cdb.len = 6; + scsi->cdb.idx = 0; + if (scsi->ccb.from_mailbox) + scsi->cdb.data_pointer = -1; + else + scsi->cdb.data_pointer = scsi->ccb.addr + 0x12 + scsi->ccb.scsi_cmd_len; + scsi->cdb.data_idx = 0; + scsi->cdb.data_len = scsi->cdb.data[4]; + scsi->cdb.scatter_gather = 0; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->ccb_state = CCB_STATE_WAIT_REQUEST_SENSE; + break; + + case CCB_STATE_WAIT_REQUEST_SENSE: + if (scsi->scsi_state != SCSI_STATE_IDLE) + break; /*Wait until SCSI state machine has completed command*/ + + if (scsi->ccb.from_mailbox) + { + uint32_t residue = scsi->ccb.total_data_len - scsi->ccb.bytes_transferred; +// pclog("residue=%x %x %x\n", residue, scsi->ccb.total_data_len, scsi->ccb.bytes_transferred); + mem_writeb_phys(scsi->ccb.addr + 0xe, HOST_STATUS_COMMAND_COMPLETE); + + if (scsi->mb_format == MB_FORMAT_4) + { + if (scsi->ccb.residual) + { + mem_writeb_phys(scsi->ccb.addr + 0x4, residue >> 16); + mem_writeb_phys(scsi->ccb.addr + 0x5, residue >> 8); + mem_writeb_phys(scsi->ccb.addr + 0x6, residue & 0xff); + } + + if (scsi->current_mbo_is_bios) + { + mem_writeb_phys(scsi->bios_mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE_WITH_ERROR); + } + else + { + mem_writeb_phys(scsi->mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + +// pclog("CCB status %02x\n", scsi->ccb.status); + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE_WITH_ERROR); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, scsi->ccb.addr >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, scsi->ccb.addr >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, scsi->ccb.addr & 0xff); + } + } + else + { + if (scsi->current_mbo_is_bios) + fatal("MBO_IS_BIOS MB_FORMAT_8\n"); + + if (scsi->ccb.residual) + mem_writel_phys(scsi->ccb.addr + 0x4, residue); + + mem_writeb_phys(scsi->mba + scsi->current_mbo*8 + 7, COMMAND_FREE_CCB); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, scsi->ccb.addr); + if (scsi->ccb.status == STATUS_GOOD) + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE << 24); + else + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE_WITH_ERROR << 24); + } + + if (!scsi->current_mbo_is_bios) + { + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, ISR_MBOA | ISR_MBIF); + } + else + set_irq(scsi, ISR_MBOA); + + set_irq(scsi, ISR_MBOA | ISR_MBIF); + } +// pclog("CCB_STATE_WAIT_REQUEST_SENSE over %i\n", scsi->ccb.from_mailbox); + scsi->ccb_state = CCB_STATE_IDLE; + break; + + default: + fatal("Unknown CCB_state %d\n", scsi->ccb_state); + } +} + +static void process_scsi(aha154x_t *scsi) +{ + int c; + int bytes_transferred = 0; + + switch (scsi->scsi_state) + { + case SCSI_STATE_IDLE: + break; + + case SCSI_STATE_SELECT: + scsi->cdb.last_status = 0; +// pclog("Select target ID %i\n", scsi->ccb.target_id); + scsi_bus_update(&scsi->bus, BUS_SEL | BUS_SETDATA(1 << scsi->ccb.target_id)); + if (!(scsi_bus_read(&scsi->bus) & BUS_BSY) || scsi->ccb.target_id > 6) + { + pclog("STATE_SCSI_SELECT failed to select target %i\n", scsi->ccb.target_id); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + break; + } + + scsi_bus_update(&scsi->bus, 0); + if (!(scsi_bus_read(&scsi->bus) & BUS_BSY)) + { + pclog("STATE_SCSI_SELECT failed to select target %i 2\n", scsi->ccb.target_id); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + break; + } + + /*Device should now be selected*/ + if (!wait_for_bus(&scsi->bus, BUS_CD, 1)) + fatal("Device failed to request command\n"); + + scsi->scsi_state = SCSI_STATE_SEND_COMMAND; + break; + + case SCSI_STATE_SELECT_FAILED: + break; + + case SCSI_STATE_SEND_COMMAND: + while (scsi->cdb.idx < scsi->cdb.len && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus_out; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + fatal("SEND_COMMAND - bus phase incorrect\n"); + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + { + pclog("SEND_COMMAND timed out\n"); + break; + } + + bus_out = BUS_SETDATA(scsi->cdb.data[scsi->cdb.idx]); +// pclog(" Command send %02x\n", scsi->cdb.data[scsi->cdb.idx]); +// if (!scsi->cdb.idx && scsi->cdb.data[scsi->cdb.idx] == 0x25 && scsi->current_mbo == 1) +// output = 3; + scsi->cdb.idx++; + bytes_transferred++; + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + } + if (scsi->cdb.idx == scsi->cdb.len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + + case SCSI_STATE_NEXT_PHASE: + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("NEXT_PHASE - dropped BSY waiting\n"); + + if (bus_state & BUS_REQ) + { +// pclog("SCSI next phase - %x\n", bus_state); + switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG)) + { + case 0: +// pclog("Move to write data\n"); + scsi->scsi_state = SCSI_STATE_WRITE_DATA; + break; + + case BUS_IO: +// pclog("Move to read data\n"); + scsi->scsi_state = SCSI_STATE_READ_DATA; + break; + + case (BUS_CD | BUS_IO): +// pclog("Move to read status\n"); + scsi->scsi_state = SCSI_STATE_READ_STATUS; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): +// pclog("Move to read message\n"); + scsi->scsi_state = SCSI_STATE_READ_MESSAGE; + break; + + default: + fatal(" Bad new phase %x\n", bus_state); + } + break; + } + } + break; + + case SCSI_STATE_END_PHASE: + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + { + pclog("END_PHASE - dropped BSY waiting\n"); +// if (scsi->ccb.req_sense_len == CCB_SENSE_NONE) +// fatal("No sense data\n"); + scsi->scsi_state = SCSI_STATE_IDLE; + break; + } + + if (bus_state & BUS_REQ) + fatal("END_PHASE - unexpected REQ\n"); + } + break; + + case SCSI_STATE_READ_DATA: +//pclog("READ_DATA %i,%i %i\n", scsi->cdb.data_idx,scsi->cdb.data_len, scsi->cdb.scatter_gather); + while (scsi->cdb.data_idx < scsi->cdb.data_len && scsi->scsi_state == SCSI_STATE_READ_DATA && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int d; + + for (d = 0; d < 20; d++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + { + pclog("READ_DATA - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = BUS_GETDATA(bus_state); + int bus_out = 0; + + if (scsi->cdb.data_pointer == -1) + scsi->int_buffer[scsi->cdb.data_idx] = data; + else + mem_writeb_phys(scsi->cdb.data_pointer + scsi->cdb.data_idx, data); + scsi->cdb.data_idx++; + scsi->cdb.bytes_transferred++; + +// pclog("Read data %02x %i %06x\n", data, scsi->cdb.data_idx, scsi->cdb.data_pointer + scsi->cdb.data_idx); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + } + } + + bytes_transferred++; + } + if (scsi->cdb.data_idx == scsi->cdb.data_len) + { + if (scsi->cdb.scatter_gather) + { + if (scsi->cdb.data_seg_list_idx >= scsi->cdb.data_seg_list_len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + else + { + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->cdb.data_len = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 2) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 1) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx) << 16); + scsi->cdb.data_pointer = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 5) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 3) << 16); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 6; + } + else + { + scsi->cdb.data_len = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx); + scsi->cdb.data_pointer = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 8; +// output = 3; + } + pclog("Got scatter gather %08x %08x\n", scsi->cdb.data_pointer, scsi->cdb.data_len); + } + } + else + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + } + break; + + case SCSI_STATE_WRITE_DATA: + while (scsi->cdb.data_idx < scsi->cdb.data_len && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int d; + + for (d = 0; d < 20; d++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("WRITE_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != 0) + { + pclog("WRITE_DATA - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data;// = BUS_GETDATA(bus_state); + int bus_out; + + if (scsi->cdb.data_pointer == -1) + data = scsi->int_buffer[scsi->cdb.data_idx]; + else + data = mem_readb_phys(scsi->cdb.data_pointer + scsi->cdb.data_idx); + scsi->cdb.data_idx++; + scsi->cdb.bytes_transferred++; + +// pclog("Write data %02x %i\n", data, scsi->cdb.data_idx); + bus_out = BUS_SETDATA(data); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + } + } + + bytes_transferred++; + } + if (scsi->cdb.data_idx == scsi->cdb.data_len) + { + if (scsi->cdb.scatter_gather) + { + if (scsi->cdb.data_seg_list_idx >= scsi->cdb.data_seg_list_len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + else + { + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->cdb.data_len = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 2) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 1) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx) << 16); + scsi->cdb.data_pointer = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 5) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 3) << 16); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 6; + } + else + { + scsi->cdb.data_len = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx); + scsi->cdb.data_pointer = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 8; + } + pclog("Got scatter gather %08x %08x\n", scsi->cdb.data_pointer, scsi->cdb.data_len); + } + } + else + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + } + break; + + case SCSI_STATE_READ_STATUS: + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_STATUS - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO)) + { + pclog("READ_STATUS - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t status = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read status %02x\n", status); + if (scsi->ccb.from_mailbox) + mem_writeb_phys(scsi->ccb.addr + 0xf, status); + scsi->cdb.last_status = status; + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + } + break; + + case SCSI_STATE_READ_MESSAGE: + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_MESSAGE - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO | BUS_MSG)) + { + pclog("READ_MESSAGE - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t msg = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read message %02x\n", msg); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + + switch (msg) + { + case MSG_COMMAND_COMPLETE: + scsi->scsi_state = SCSI_STATE_END_PHASE; + break; + + default: + fatal("READ_MESSAGE - unknown message %02x\n", msg); + } + break; + } + } + break; + + default: + fatal("Unknown SCSI_state %d\n", scsi->scsi_state); + } +} + +static void aha154x_callback(void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + scsi->timer += TIMER_USEC * POLL_TIME_US; + +// pclog("poll %i\n", scsi->cmd_state); + process_cmd(scsi); + process_ccb(scsi); + process_scsi(scsi); +} + +static uint8_t aha1542c_read(uint32_t addr, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + uint8_t temp = 0xff; + + addr &= 0x3fff; + + + if (addr == 0x3f7e) /*DIP switches*/ + temp = scsi->dipsw; + else if (addr == 0x3f7f) /*Negation of DIP switches, to satisfy BIOS checksum!*/ + temp = (scsi->dipsw ^ 0xff) + 1; + else if (addr >= 0x3f80 && (scsi->shadow & 2)) + temp = scsi->shadow_ram[addr]; + else + temp = scsi->bios_rom.rom[addr | scsi->bios_bank]; + + return temp; +} +static void aha1542c_write(uint32_t addr, uint8_t val, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + addr &= 0x3fff; + + if (addr >= 0x3f80 && (scsi->shadow & 1)) + scsi->shadow_ram[addr] = val; +} + +static void aha1542c_eeprom_load(aha154x_t *scsi, char *fn) +{ + FILE *f; + + strcpy(scsi->fn, fn); + f = nvrfopen(scsi->fn, "rb"); + if (!f) + { + memset(scsi->eeprom, 0, 35); + return; + } + fread(scsi->eeprom, 1, 32, f); + fclose(f); +} + +static void aha1542c_eeprom_save(aha154x_t *scsi) +{ + FILE *f = nvrfopen(scsi->fn, "wb"); + + if (!f) + return; + fwrite(scsi->eeprom, 1, 32, f); + fclose(f); +} + +static uint16_t port_sw_mapping[8] = +{ + 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, -1, -1 +}; + +static void *scsi_aha1542c_init(char *bios_fn) +{ + aha154x_t *scsi = malloc(sizeof(aha154x_t)); + uint32_t addr; + int c; + memset(scsi, 0, sizeof(aha154x_t)); + + rom_init(&scsi->bios_rom, "adaptec_aha1542c_bios_534201-00.bin", 0xd8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + addr = device_get_config_int("bios_addr"); + mem_mapping_add(&scsi->mapping, addr, 0x4000, + aha1542c_read, NULL, NULL, + aha1542c_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + scsi->status = 0; + scsi->cmd_state = CMD_STATE_IDLE; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + + timer_add(aha154x_callback, &scsi->timer, TIMER_ALWAYS_ENABLED, scsi); + + addr = device_get_config_int("addr"); + io_sethandler(addr, 0x0004, + aha154x_in, NULL, NULL, + aha154x_out, NULL, NULL, + scsi); + for (c = 0; c < 8; c++) + { + if (port_sw_mapping[c] == addr) + { + scsi->dipsw = c; + break; + } + } + + scsi_bus_init(&scsi->bus); + + scsi->type = SCSI_AHA1542C; + + aha1542c_eeprom_load(scsi, "aha1542c.nvr"); + + scsi->host_id = scsi->eeprom[0] & 7; + scsi->dma = (scsi->eeprom[1] >> 4) & 7; + scsi->irq = (scsi->eeprom[1] & 7) + 9; + pclog("Init IRQ=%i DMA=%i ID=%i\n", scsi->irq, scsi->dma, scsi->host_id); + + return scsi; +} + +static void *scsi_bt545s_init(char *bios_fn) +{ + aha154x_t *scsi = malloc(sizeof(aha154x_t)); + uint32_t addr; + memset(scsi, 0, sizeof(aha154x_t)); + + addr = device_get_config_int("bios_addr"); + rom_init(&scsi->bios_rom, "BusLogic_BT-545S_U15_27128_5002026-4.50.bin", addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + scsi->bios_addr = addr; + + scsi->status = 0; + scsi->cmd_state = CMD_STATE_IDLE; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + + timer_add(aha154x_callback, &scsi->timer, TIMER_ALWAYS_ENABLED, scsi); + + addr = device_get_config_int("addr"); + io_sethandler(addr, 0x0004, + aha154x_in, NULL, NULL, + aha154x_out, NULL, NULL, + scsi); + + scsi_bus_init(&scsi->bus); + + scsi->type = SCSI_BT545S; + + scsi->host_id = device_get_config_int("host_id"); + scsi->dma = device_get_config_int("dma"); + scsi->irq = device_get_config_int("irq"); + + return scsi; +} + +static void scsi_aha1542c_close(void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + scsi_bus_close(&scsi->bus); + + free(scsi); +} + +static int scsi_aha1542c_available() +{ + return rom_present("adaptec_aha1542c_bios_534201-00.bin"); +} + +static int scsi_bt545s_available() +{ + return rom_present("BusLogic_BT-545S_U15_27128_5002026-4.50.bin"); +} + +static device_config_t aha1542c_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "130", + .value = 0x130 + }, + { + .description = "134", + .value = 0x134 + }, + { + .description = "230", + .value = 0x230 + }, + { + .description = "234", + .value = 0x234 + }, + { + .description = "330", + .value = 0x330 + }, + { + .description = "334", + .value = 0x334 + }, + { + .description = "" + } + }, + .default_int = 0x334 + }, + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "C8000", + .value = 0xc8000 + }, + { + .description = "CC000", + .value = 0xcc000 + }, + { + .description = "D0000", + .value = 0xd0000 + }, + { + .description = "D4000", + .value = 0xd4000 + }, + { + .description = "D8000", + .value = 0xd8000 + }, + { + .description = "DC000", + .value = 0xdc000 + }, + { + .description = "" + } + }, + .default_int = 0xdc000 + }, + { + .type = -1 + } +}; + +static device_config_t bt545s_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "130", + .value = 0x130 + }, + { + .description = "134", + .value = 0x134 + }, + { + .description = "230", + .value = 0x230 + }, + { + .description = "234", + .value = 0x234 + }, + { + .description = "330", + .value = 0x330 + }, + { + .description = "334", + .value = 0x334 + }, + { + .description = "" + } + }, + .default_int = 0x334 + }, + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "C8000", + .value = 0xc8000 + }, + { + .description = "D8000", + .value = 0xd8000 + }, + { + .description = "DC000", + .value = 0xdc000 + }, + { + .description = "" + } + }, + .default_int = 0xdc000 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 9", + .value = 9 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "IRQ 12", + .value = 12 + }, + { + .description = "IRQ 14", + .value = 14 + }, + { + .description = "IRQ 15", + .value = 15 + }, + { + .description = "" + } + }, + .default_int = 10 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 5", + .value = 5 + }, + { + .description = "DMA 6", + .value = 6 + }, + { + .description = "DMA 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .name = "host_id", + .description = "Host ID", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "ID 0", + .value = 0 + }, + { + .description = "ID 1", + .value = 1 + }, + { + .description = "ID 2", + .value = 2 + }, + { + .description = "ID 3", + .value = 3 + }, + { + .description = "ID 4", + .value = 4 + }, + { + .description = "ID 5", + .value = 5 + }, + { + .description = "ID 6", + .value = 6 + }, + { + .description = "ID 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .type = -1 + } +}; + +device_t scsi_aha1542c_device = +{ + "Adaptec AHA-1542C (SCSI)", + DEVICE_AT, + scsi_aha1542c_init, + scsi_aha1542c_close, + scsi_aha1542c_available, + NULL, + NULL, + NULL, + aha1542c_config +}; +device_t scsi_bt545s_device = +{ + "BusLogic BT-545S (SCSI)", + DEVICE_AT, + scsi_bt545s_init, + scsi_aha1542c_close, + scsi_bt545s_available, + NULL, + NULL, + NULL, + bt545s_config +}; diff --git a/src/scsi_aha1540.h b/src/scsi_aha1540.h new file mode 100644 index 0000000..d4db67d --- /dev/null +++ b/src/scsi_aha1540.h @@ -0,0 +1,2 @@ +extern device_t scsi_aha1542c_device; +extern device_t scsi_bt545s_device;