The new code is based on timestamps, rather than delays. This eliminates the need to update every timer in timer_process(), which cost a non-trivial amount of CPU time on low-end machines. This involved changes to every user of the timer code, so this change almost certainly introduces bugs.
2612 lines
123 KiB
C
2612 lines
123 KiB
C
/*AH1542C firmware notes :
|
|
|
|
d1a - command dispatch
|
|
193c - send data
|
|
1954 - get data
|
|
|
|
FW data - 164e
|
|
|
|
BIOS command table - f4b*/
|
|
#include <stdlib.h>
|
|
#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"
|
|
|
|
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;
|
|
|
|
int mbo_irq_enable;
|
|
|
|
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;
|
|
int bios_mbo_inited;
|
|
|
|
cmd_state_t cmd_state;
|
|
ccb_state_t ccb_state;
|
|
scsi_state_t scsi_state;
|
|
|
|
int bios_cmd_state;
|
|
|
|
pc_timer_t 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;
|
|
|
|
int reg3_idx;
|
|
} 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_MAILBOX_OUT_IRQ_ENA 0x05
|
|
#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_INQUIRE_INSTALLED_DEVICES 0x0a
|
|
#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_ADAPTER_MODEL_NR 0x8b
|
|
#define COMMAND_BUSLOGIC_INQUIRY_SYNC_PERIOD 0x8c
|
|
#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)
|
|
{
|
|
picint(1 << scsi->irq);
|
|
scsi->isr |= val | ISR_ANYINTR;
|
|
}
|
|
|
|
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;
|
|
scsi->mbo_irq_enable = 0;
|
|
}
|
|
if (val & CTRL_SRST)
|
|
{
|
|
scsi->isr = 0;
|
|
clear_irq(scsi);
|
|
scsi->status = STATUS_INIT;
|
|
// 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;
|
|
scsi->mbo_irq_enable = 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;
|
|
|
|
case 2:
|
|
if (scsi->type == SCSI_BT545S)
|
|
scsi->isr = val;
|
|
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*/
|
|
if (scsi->type == SCSI_BT545S)
|
|
temp = scsi->isr;
|
|
else
|
|
temp = scsi->isr & ~0x70;
|
|
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
|
|
{
|
|
scsi->reg3_idx++;
|
|
switch (scsi->reg3_idx & 3)
|
|
{
|
|
case 0: temp = 'A'; break;
|
|
case 1: temp = 'D'; break;
|
|
case 2: temp = 'A'; break;
|
|
case 3: temp = 'P'; break;
|
|
}
|
|
}
|
|
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_INQUIRE_INSTALLED_DEVICES:
|
|
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_MAILBOX_OUT_IRQ_ENA:
|
|
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:
|
|
case COMMAND_BUSLOGIC_ADAPTER_MODEL_NR:
|
|
case COMMAND_BUSLOGIC_INQUIRY_SYNC_PERIOD:
|
|
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;
|
|
scsi->current_mbo = 0;
|
|
scsi->current_mbi = 0;
|
|
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_MAILBOX_OUT_IRQ_ENA:
|
|
scsi->mbo_irq_enable = scsi->params[0];
|
|
set_irq(scsi, ISR_HACC);
|
|
scsi->cmd_state = CMD_STATE_IDLE;
|
|
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_INQUIRE_INSTALLED_DEVICES:
|
|
for (c = 0; c < 8; c++)
|
|
scsi->result[c] = scsi->bus.devices[c] ? 1 : 0;
|
|
scsi->cmd_state = CMD_STATE_SEND_RESULT;
|
|
scsi->result_pos = 0;
|
|
scsi->result_len = 8;
|
|
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);
|
|
scsi->bios_mbo_inited = 1;
|
|
pclog("BIOS mailbox init: MBC=%02x MBC=%06x\n", scsi->bios_mbc, scsi->bios_mba);
|
|
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;
|
|
scsi->current_mbo = 0;
|
|
scsi->current_mbi = 0;
|
|
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_ADAPTER_MODEL_NR:
|
|
scsi->result[0] = '5';
|
|
scsi->result[1] = '4';
|
|
scsi->result[2] = '2';
|
|
scsi->result[3] = 'B';
|
|
scsi->result[4] = 'H';
|
|
scsi->cmd_state = CMD_STATE_SEND_RESULT;
|
|
scsi->result_pos = 0;
|
|
scsi->result_len = MIN(scsi->params[0], 5);
|
|
for (; scsi->result_len < scsi->params[0]; scsi->result_len++)
|
|
scsi->result[scsi->result_len] = 0;
|
|
break;
|
|
|
|
case COMMAND_BUSLOGIC_INQUIRY_SYNC_PERIOD:
|
|
for (c = 0; c < 8; c++)
|
|
scsi->result[c] = 0;
|
|
scsi->cmd_state = CMD_STATE_SEND_RESULT;
|
|
scsi->result_pos = 0;
|
|
scsi->result_len = MIN(scsi->params[0], 8);
|
|
for (; scsi->result_len < scsi->params[0]; scsi->result_len++)
|
|
scsi->result[scsi->result_len] = 0;
|
|
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) && 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, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF | ISR_HACC);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (scsi->bios_mbo_inited && 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, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF);
|
|
}
|
|
else if (scsi->mbo_irq_enable)
|
|
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);
|
|
mem_writeb_phys(scsi->ccb.addr + 0xf, scsi->ccb.status);
|
|
|
|
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) | (scsi->ccb.status << 8));
|
|
}
|
|
|
|
if (!scsi->current_mbo_is_bios)
|
|
{
|
|
scsi->current_mbi++;
|
|
if (scsi->current_mbi >= scsi->mbc)
|
|
scsi->current_mbi = 0;
|
|
set_irq(scsi, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF);
|
|
}
|
|
else if (scsi->mbo_irq_enable)
|
|
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);
|
|
mem_writeb_phys(scsi->ccb.addr + 0xf, scsi->ccb.status);
|
|
|
|
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) | (scsi->ccb.status << 8));
|
|
}
|
|
|
|
if (!scsi->current_mbo_is_bios)
|
|
{
|
|
scsi->current_mbi++;
|
|
if (scsi->current_mbi >= scsi->mbc)
|
|
scsi->current_mbi = 0;
|
|
set_irq(scsi, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF);
|
|
}
|
|
else if (scsi->mbo_irq_enable)
|
|
set_irq(scsi, ISR_MBOA);
|
|
}
|
|
// 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))
|
|
{
|
|
pclog("Device failed to request command\n");
|
|
scsi->scsi_state = SCSI_STATE_SELECT_FAILED;
|
|
break;
|
|
}
|
|
|
|
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 %i\n", scsi->cdb.data[scsi->cdb.idx], scsi->cdb.len);
|
|
// 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)
|
|
{
|
|
int bus_out;
|
|
// 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;
|
|
|
|
case BUS_CD:
|
|
bus_out = BUS_SETDATA(0);
|
|
|
|
scsi_bus_update(&scsi->bus, bus_out | BUS_ACK);
|
|
scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK);
|
|
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;
|
|
|
|
timer_advance_u64(&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(&scsi->timer, aha154x_callback, scsi, 1);
|
|
|
|
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(&scsi->timer, aha154x_callback, scsi, 1);
|
|
|
|
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
|
|
};
|