/* ??? Need to check if the {read,write}[wl] routines work properly on
big-endian targets. */
+#include <assert.h> \
+
#include "hw.h"
#include "pci.h"
#include "scsi-disk.h"
+#include "block_int.h"
//#define DEBUG_LSI
//#define DEBUG_LSI_REG
#ifdef DEBUG_LSI
-#define DPRINTF(fmt, args...) \
-do { printf("lsi_scsi: " fmt , ##args); } while (0)
-#define BADF(fmt, args...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args); exit(1);} while (0)
+#define DPRINTF(fmt, ...) \
+do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
#else
-#define DPRINTF(fmt, args...) do {} while(0)
-#define BADF(fmt, args...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args);} while (0)
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
#endif
#define LSI_SCNTL0_TRG 0x01
#define LSI_CCNTL0_PMJCTL 0x40
#define LSI_CCNTL0_ENPMJ 0x80
+#define LSI_CCNTL1_EN64DBMV 0x01
+#define LSI_CCNTL1_EN64TIBMV 0x02
+#define LSI_CCNTL1_64TIMOD 0x04
+#define LSI_CCNTL1_DDAC 0x08
+#define LSI_CCNTL1_ZMOD 0x80
+
+#define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
+
#define PHASE_DO 0
#define PHASE_DI 1
#define PHASE_CMD 2
} lsi_queue;
typedef struct {
- PCIDevice pci_dev;
+ PCIDevice dev;
int mmio_io_addr;
int ram_io_addr;
uint32_t script_ram_base;
uint8_t mbox0;
uint8_t mbox1;
uint8_t dfifo;
+ uint8_t ctest2;
uint8_t ctest3;
uint8_t ctest4;
uint8_t ctest5;
uint32_t sfs;
uint32_t drs;
uint32_t sbms;
- uint32_t dmbs;
+ uint32_t dbms;
uint32_t dnad64;
uint32_t pmjad1;
uint32_t pmjad2;
uint32_t sbc;
uint32_t csbc;
uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
+ uint8_t sbr;
/* Script ram is stored as 32-bit words in host byteorder. */
uint32_t script_ram[2048];
s->mbox0 = 0;
s->mbox1 = 0;
s->dfifo = 0;
+ s->ctest2 = 0;
s->ctest3 = 0;
s->ctest4 = 0;
s->ctest5 = 0;
s->sfs = 0;
s->drs = 0;
s->sbms = 0;
- s->dmbs = 0;
+ s->dbms = 0;
s->dnad64 = 0;
s->pmjad1 = 0;
s->pmjad2 = 0;
s->ia = 0;
s->sbc = 0;
s->csbc = 0;
+ s->sbr = 0;
+}
+
+static int lsi_dma_40bit(LSIState *s)
+{
+ if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
+ return 1;
+ return 0;
+}
+
+static int lsi_dma_ti64bit(LSIState *s)
+{
+ if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
+ return 1;
+ return 0;
+}
+
+static int lsi_dma_64bit(LSIState *s)
+{
+ if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
+ return 1;
+ return 0;
}
static uint8_t lsi_reg_readb(LSIState *s, int offset);
level, s->dstat, s->sist1, s->sist0);
last_level = level;
}
- qemu_set_irq(s->pci_dev.irq[0], level);
+ qemu_set_irq(s->dev.irq[0], level);
}
/* Stop SCRIPTS execution and raise a SCSI interrupt. */
static void lsi_do_dma(LSIState *s, int out)
{
uint32_t count;
- uint32_t addr;
+ target_phys_addr_t addr;
if (!s->current_dma_len) {
/* Wait until data is available. */
count = s->dbc;
if (count > s->current_dma_len)
count = s->current_dma_len;
- DPRINTF("DMA addr=0x%08x len=%d\n", s->dnad, count);
addr = s->dnad;
+ /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
+ if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
+ addr |= ((uint64_t)s->dnad64 << 32);
+ else if (s->dbms)
+ addr |= ((uint64_t)s->dbms << 32);
+ else if (s->sbms)
+ addr |= ((uint64_t)s->sbms << 32);
+
+ DPRINTF("DMA addr=0x" TARGET_FMT_plx " len=%d\n", addr, count);
s->csbc += count;
s->dnad += count;
s->dbc -= count;
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
if (s->queue_len == s->active_commands) {
s->queue_len++;
- s->queue = realloc(s->queue, s->queue_len * sizeof(lsi_queue));
+ s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue));
}
p = &s->queue[s->active_commands++];
p->tag = s->current_tag;
static void lsi_command_complete(void *opaque, int reason, uint32_t tag,
uint32_t arg)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
return (n << 8) >> 8;
}
+#define LSI_BUF_SIZE 4096
static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
{
int n;
- uint8_t buf[TARGET_PAGE_SIZE];
+ uint8_t buf[LSI_BUF_SIZE];
DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
while (count) {
- n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;
+ n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
cpu_physical_memory_read(src, buf, n);
cpu_physical_memory_write(dest, buf, n);
src += n;
static void lsi_execute_script(LSIState *s)
{
uint32_t insn;
- uint32_t addr;
+ uint32_t addr, addr_high;
int opcode;
+ int insn_processed = 0;
s->istat1 |= LSI_ISTAT1_SRUN;
again:
+ insn_processed++;
insn = read_dword(s, s->dsp);
+ if (!insn) {
+ /* If we receive an empty opcode increment the DSP by 4 bytes
+ instead of 8 and execute the next opcode at that location */
+ s->dsp += 4;
+ goto again;
+ }
addr = read_dword(s, s->dsp + 4);
+ addr_high = 0;
DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
s->dsps = addr;
s->dcmd = insn >> 24;
}
s->dbc = insn & 0xffffff;
s->rbc = s->dbc;
+ /* ??? Set ESA. */
+ s->ia = s->dsp - 8;
if (insn & (1 << 29)) {
/* Indirect addressing. */
addr = read_dword(s, addr);
uint32_t buf[2];
int32_t offset;
/* Table indirect addressing. */
+
+ /* 32-bit Table indirect */
offset = sxt24(addr);
cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
- s->dbc = cpu_to_le32(buf[0]);
+ /* byte count is stored in bits 0:23 only */
+ s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
s->rbc = s->dbc;
addr = cpu_to_le32(buf[1]);
+
+ /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
+ * table, bits [31:24] */
+ if (lsi_dma_40bit(s))
+ addr_high = cpu_to_le32(buf[0]) >> 24;
+ else if (lsi_dma_ti64bit(s)) {
+ int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
+ switch (selector) {
+ case 0 ... 0x0f:
+ /* offset index into scratch registers since
+ * TI64 mode can use registers C to R */
+ addr_high = s->scratch[2 + selector];
+ break;
+ case 0x10:
+ addr_high = s->mmrs;
+ break;
+ case 0x11:
+ addr_high = s->mmws;
+ break;
+ case 0x12:
+ addr_high = s->sfs;
+ break;
+ case 0x13:
+ addr_high = s->drs;
+ break;
+ case 0x14:
+ addr_high = s->sbms;
+ break;
+ case 0x15:
+ addr_high = s->dbms;
+ break;
+ default:
+ BADF("Illegal selector specified (0x%x > 0x15)"
+ " for 64-bit DMA block move", selector);
+ break;
+ }
+ }
+ } else if (lsi_dma_64bit(s)) {
+ /* fetch a 3rd dword if 64-bit direct move is enabled and
+ only if we're not doing table indirect or indirect addressing */
+ s->dbms = read_dword(s, s->dsp);
+ s->dsp += 4;
+ s->ia = s->dsp - 12;
}
if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
DPRINTF("Wrong phase got %d expected %d\n",
break;
}
s->dnad = addr;
- /* ??? Set ESA. */
- s->ia = s->dsp - 8;
+ s->dnad64 = addr_high;
switch (s->sstat1 & 0x7) {
case PHASE_DO:
s->waiting = 2;
}
}
}
- /* ??? Need to avoid infinite loops. */
- if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
+ if (insn_processed > 10000 && !s->waiting) {
+ /* Some windows drivers make the device spin waiting for a memory
+ location to change. If we have been executed a lot of code then
+ assume this is the case and force an unexpected device disconnect.
+ This is apparently sufficient to beat the drivers into submission.
+ */
+ if (!(s->sien0 & LSI_SIST0_UDC))
+ fprintf(stderr, "inf. loop with UDC masked\n");
+ lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
+ lsi_disconnect(s);
+ } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
if (s->dcntl & LSI_DCNTL_SSM) {
lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
} else {
static uint8_t lsi_reg_readb(LSIState *s, int offset)
{
uint8_t tmp;
+#define CASE_GET_REG24(name, addr) \
+ case addr: return s->name & 0xff; \
+ case addr + 1: return (s->name >> 8) & 0xff; \
+ case addr + 2: return (s->name >> 16) & 0xff;
+
#define CASE_GET_REG32(name, addr) \
case addr: return s->name & 0xff; \
case addr + 1: return (s->name >> 8) & 0xff; \
return s->sdid;
case 0x07: /* GPREG0 */
return 0x7f;
+ case 0x08: /* Revision ID */
+ return 0x00;
case 0xa: /* SSID */
return s->ssid;
case 0xb: /* SBCL */
CASE_GET_REG32(dsa, 0x10)
case 0x14: /* ISTAT0 */
return s->istat0;
+ case 0x15: /* ISTAT1 */
+ return s->istat1;
case 0x16: /* MBOX0 */
return s->mbox0;
case 0x17: /* MBOX1 */
case 0x19: /* CTEST1 */
return 0;
case 0x1a: /* CTEST2 */
- tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM;
+ tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
if (s->istat0 & LSI_ISTAT0_SIGP) {
s->istat0 &= ~LSI_ISTAT0_SIGP;
tmp |= LSI_CTEST2_SIGP;
return s->ctest4;
case 0x22: /* CTEST5 */
return s->ctest5;
- case 0x24: /* DBC[0:7] */
- return s->dbc & 0xff;
- case 0x25: /* DBC[8:15] */
- return (s->dbc >> 8) & 0xff;
- case 0x26: /* DBC[16->23] */
- return (s->dbc >> 16) & 0xff;
+ case 0x23: /* CTEST6 */
+ return 0;
+ CASE_GET_REG24(dbc, 0x24)
case 0x27: /* DCMD */
return s->dcmd;
+ CASE_GET_REG32(dnad, 0x28)
CASE_GET_REG32(dsp, 0x2c)
CASE_GET_REG32(dsps, 0x30)
CASE_GET_REG32(scratch[0], 0x34)
return s->dmode;
case 0x39: /* DIEN */
return s->dien;
+ case 0x3a: /* SBR */
+ return s->sbr;
case 0x3b: /* DCNTL */
return s->dcntl;
case 0x40: /* SIEN0 */
s->sist1 = 0;
lsi_update_irq(s);
return tmp;
+ case 0x46: /* MACNTL */
+ return 0x0f;
case 0x47: /* GPCNTL0 */
return 0x0f;
case 0x48: /* STIME0 */
CASE_GET_REG32(sfs, 0xa8)
CASE_GET_REG32(drs, 0xac)
CASE_GET_REG32(sbms, 0xb0)
- CASE_GET_REG32(dmbs, 0xb4)
+ CASE_GET_REG32(dbms, 0xb4)
CASE_GET_REG32(dnad64, 0xb8)
CASE_GET_REG32(pmjad1, 0xc0)
CASE_GET_REG32(pmjad2, 0xc4)
}
BADF("readb 0x%x\n", offset);
exit(1);
+#undef CASE_GET_REG24
#undef CASE_GET_REG32
}
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
{
+#define CASE_SET_REG24(name, addr) \
+ case addr : s->name &= 0xffffff00; s->name |= val; break; \
+ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
+ case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
+
#define CASE_SET_REG32(name, addr) \
case addr : s->name &= 0xffffff00; s->name |= val; break; \
case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
SCRIPTS register move instructions are. */
s->sfbr = val;
break;
+ case 0x0a: case 0x0b:
+ /* Openserver writes to these readonly registers on startup */
+ return;
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
/* Linux writes to these readonly registers on startup. */
return;
case 0x17: /* MBOX1 */
s->mbox1 = val;
break;
+ case 0x1a: /* CTEST2 */
+ s->ctest2 = val & LSI_CTEST2_PCICIE;
+ break;
case 0x1b: /* CTEST3 */
s->ctest3 = val & 0x0f;
break;
}
s->ctest5 = val;
break;
+ CASE_SET_REG24(dbc, 0x24)
+ CASE_SET_REG32(dnad, 0x28)
case 0x2c: /* DSP[0:7] */
s->dsp &= 0xffffff00;
s->dsp |= val;
s->dien = val;
lsi_update_irq(s);
break;
+ case 0x3a: /* SBR */
+ s->sbr = val;
+ break;
case 0x3b: /* DCNTL */
s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
CASE_SET_REG32(sfs, 0xa8)
CASE_SET_REG32(drs, 0xac)
CASE_SET_REG32(sbms, 0xb0)
- CASE_SET_REG32(dmbs, 0xb4)
+ CASE_SET_REG32(dbms, 0xb4)
CASE_SET_REG32(dnad64, 0xb8)
CASE_SET_REG32(pmjad1, 0xc0)
CASE_SET_REG32(pmjad2, 0xc4)
BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
}
}
+#undef CASE_SET_REG24
#undef CASE_SET_REG32
}
static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
lsi_reg_writeb(s, addr & 0xff, val);
}
static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
addr &= 0xff;
lsi_reg_writeb(s, addr, val & 0xff);
static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
addr &= 0xff;
lsi_reg_writeb(s, addr, val & 0xff);
static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
return lsi_reg_readb(s, addr & 0xff);
}
static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t val;
addr &= 0xff;
static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t val;
addr &= 0xff;
val = lsi_reg_readb(s, addr);
return val;
}
-static CPUReadMemoryFunc *lsi_mmio_readfn[3] = {
+static CPUReadMemoryFunc * const lsi_mmio_readfn[3] = {
lsi_mmio_readb,
lsi_mmio_readw,
lsi_mmio_readl,
};
-static CPUWriteMemoryFunc *lsi_mmio_writefn[3] = {
+static CPUWriteMemoryFunc * const lsi_mmio_writefn[3] = {
lsi_mmio_writeb,
lsi_mmio_writew,
lsi_mmio_writel,
static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t newval;
int shift;
static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t newval;
addr &= 0x1fff;
static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
addr &= 0x1fff;
s->script_ram[addr >> 2] = val;
static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t val;
addr &= 0x1fff;
static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t val;
addr &= 0x1fff;
static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
addr &= 0x1fff;
return le32_to_cpu(s->script_ram[addr >> 2]);
}
-static CPUReadMemoryFunc *lsi_ram_readfn[3] = {
+static CPUReadMemoryFunc * const lsi_ram_readfn[3] = {
lsi_ram_readb,
lsi_ram_readw,
lsi_ram_readl,
};
-static CPUWriteMemoryFunc *lsi_ram_writefn[3] = {
+static CPUWriteMemoryFunc * const lsi_ram_writefn[3] = {
lsi_ram_writeb,
lsi_ram_writew,
lsi_ram_writel,
static uint32_t lsi_io_readb(void *opaque, uint32_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
return lsi_reg_readb(s, addr & 0xff);
}
static uint32_t lsi_io_readw(void *opaque, uint32_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t val;
addr &= 0xff;
val = lsi_reg_readb(s, addr);
static uint32_t lsi_io_readl(void *opaque, uint32_t addr)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
uint32_t val;
addr &= 0xff;
val = lsi_reg_readb(s, addr);
static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
lsi_reg_writeb(s, addr & 0xff, val);
}
static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
addr &= 0xff;
lsi_reg_writeb(s, addr, val & 0xff);
lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = opaque;
addr &= 0xff;
lsi_reg_writeb(s, addr, val & 0xff);
lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
- LSIState *s = (LSIState *)pci_dev;
+ LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
DPRINTF("Mapping IO at %08x\n", addr);
static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
- LSIState *s = (LSIState *)pci_dev;
+ LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
DPRINTF("Mapping ram at %08x\n", addr);
s->script_ram_base = addr;
static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
- LSIState *s = (LSIState *)pci_dev;
+ LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
DPRINTF("Mapping registers at %08x\n", addr);
cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
}
-void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id)
+void lsi_scsi_attach(DeviceState *host, BlockDriverState *bd, int id)
{
- LSIState *s = (LSIState *)opaque;
+ LSIState *s = DO_UPCAST(LSIState, dev.qdev, host);
if (id < 0) {
for (id = 0; id < LSI_MAX_DEVS; id++) {
s->scsi_dev[id]->destroy(s->scsi_dev[id]);
}
DPRINTF("Attaching block device %d\n", id);
- s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
+ s->scsi_dev[id] = scsi_generic_init(bd, 1, lsi_command_complete, s);
+ if (s->scsi_dev[id] == NULL)
+ s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
+ bd->private = &s->dev;
+}
+
+static void lsi_scsi_save(QEMUFile *f, void *opaque)
+{
+ LSIState *s = opaque;
+
+ assert(s->dma_buf == NULL);
+ assert(s->current_dma_len == 0);
+ assert(s->active_commands == 0);
+
+ pci_device_save(&s->dev, f);
+
+ qemu_put_sbe32s(f, &s->carry);
+ qemu_put_sbe32s(f, &s->sense);
+ qemu_put_sbe32s(f, &s->msg_action);
+ qemu_put_sbe32s(f, &s->msg_len);
+ qemu_put_buffer(f, s->msg, sizeof (s->msg));
+ qemu_put_sbe32s(f, &s->waiting);
+
+ qemu_put_be32s(f, &s->dsa);
+ qemu_put_be32s(f, &s->temp);
+ qemu_put_be32s(f, &s->dnad);
+ qemu_put_be32s(f, &s->dbc);
+ qemu_put_8s(f, &s->istat0);
+ qemu_put_8s(f, &s->istat1);
+ qemu_put_8s(f, &s->dcmd);
+ qemu_put_8s(f, &s->dstat);
+ qemu_put_8s(f, &s->dien);
+ qemu_put_8s(f, &s->sist0);
+ qemu_put_8s(f, &s->sist1);
+ qemu_put_8s(f, &s->sien0);
+ qemu_put_8s(f, &s->sien1);
+ qemu_put_8s(f, &s->mbox0);
+ qemu_put_8s(f, &s->mbox1);
+ qemu_put_8s(f, &s->dfifo);
+ qemu_put_8s(f, &s->ctest2);
+ qemu_put_8s(f, &s->ctest3);
+ qemu_put_8s(f, &s->ctest4);
+ qemu_put_8s(f, &s->ctest5);
+ qemu_put_8s(f, &s->ccntl0);
+ qemu_put_8s(f, &s->ccntl1);
+ qemu_put_be32s(f, &s->dsp);
+ qemu_put_be32s(f, &s->dsps);
+ qemu_put_8s(f, &s->dmode);
+ qemu_put_8s(f, &s->dcntl);
+ qemu_put_8s(f, &s->scntl0);
+ qemu_put_8s(f, &s->scntl1);
+ qemu_put_8s(f, &s->scntl2);
+ qemu_put_8s(f, &s->scntl3);
+ qemu_put_8s(f, &s->sstat0);
+ qemu_put_8s(f, &s->sstat1);
+ qemu_put_8s(f, &s->scid);
+ qemu_put_8s(f, &s->sxfer);
+ qemu_put_8s(f, &s->socl);
+ qemu_put_8s(f, &s->sdid);
+ qemu_put_8s(f, &s->ssid);
+ qemu_put_8s(f, &s->sfbr);
+ qemu_put_8s(f, &s->stest1);
+ qemu_put_8s(f, &s->stest2);
+ qemu_put_8s(f, &s->stest3);
+ qemu_put_8s(f, &s->sidl);
+ qemu_put_8s(f, &s->stime0);
+ qemu_put_8s(f, &s->respid0);
+ qemu_put_8s(f, &s->respid1);
+ qemu_put_be32s(f, &s->mmrs);
+ qemu_put_be32s(f, &s->mmws);
+ qemu_put_be32s(f, &s->sfs);
+ qemu_put_be32s(f, &s->drs);
+ qemu_put_be32s(f, &s->sbms);
+ qemu_put_be32s(f, &s->dbms);
+ qemu_put_be32s(f, &s->dnad64);
+ qemu_put_be32s(f, &s->pmjad1);
+ qemu_put_be32s(f, &s->pmjad2);
+ qemu_put_be32s(f, &s->rbc);
+ qemu_put_be32s(f, &s->ua);
+ qemu_put_be32s(f, &s->ia);
+ qemu_put_be32s(f, &s->sbc);
+ qemu_put_be32s(f, &s->csbc);
+ qemu_put_buffer(f, (uint8_t *)s->scratch, sizeof (s->scratch));
+ qemu_put_8s(f, &s->sbr);
+
+ qemu_put_buffer(f, (uint8_t *)s->script_ram, sizeof (s->script_ram));
}
-void *lsi_scsi_init(PCIBus *bus, int devfn)
+static int lsi_scsi_load(QEMUFile *f, void *opaque, int version_id)
{
- LSIState *s;
+ LSIState *s = opaque;
+ int ret;
- s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA",
- sizeof(*s), devfn, NULL, NULL);
- if (s == NULL) {
- fprintf(stderr, "lsi-scsi: Failed to register PCI device\n");
- return NULL;
+ if (version_id > 0) {
+ return -EINVAL;
}
- s->pci_dev.config[0x00] = 0x00;
- s->pci_dev.config[0x01] = 0x10;
- s->pci_dev.config[0x02] = 0x12;
- s->pci_dev.config[0x03] = 0x00;
- s->pci_dev.config[0x0b] = 0x01;
- s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
+ if ((ret = pci_device_load(&s->dev, f)) < 0)
+ return ret;
+
+ qemu_get_sbe32s(f, &s->carry);
+ qemu_get_sbe32s(f, &s->sense);
+ qemu_get_sbe32s(f, &s->msg_action);
+ qemu_get_sbe32s(f, &s->msg_len);
+ qemu_get_buffer(f, s->msg, sizeof (s->msg));
+ qemu_get_sbe32s(f, &s->waiting);
+
+ qemu_get_be32s(f, &s->dsa);
+ qemu_get_be32s(f, &s->temp);
+ qemu_get_be32s(f, &s->dnad);
+ qemu_get_be32s(f, &s->dbc);
+ qemu_get_8s(f, &s->istat0);
+ qemu_get_8s(f, &s->istat1);
+ qemu_get_8s(f, &s->dcmd);
+ qemu_get_8s(f, &s->dstat);
+ qemu_get_8s(f, &s->dien);
+ qemu_get_8s(f, &s->sist0);
+ qemu_get_8s(f, &s->sist1);
+ qemu_get_8s(f, &s->sien0);
+ qemu_get_8s(f, &s->sien1);
+ qemu_get_8s(f, &s->mbox0);
+ qemu_get_8s(f, &s->mbox1);
+ qemu_get_8s(f, &s->dfifo);
+ qemu_get_8s(f, &s->ctest2);
+ qemu_get_8s(f, &s->ctest3);
+ qemu_get_8s(f, &s->ctest4);
+ qemu_get_8s(f, &s->ctest5);
+ qemu_get_8s(f, &s->ccntl0);
+ qemu_get_8s(f, &s->ccntl1);
+ qemu_get_be32s(f, &s->dsp);
+ qemu_get_be32s(f, &s->dsps);
+ qemu_get_8s(f, &s->dmode);
+ qemu_get_8s(f, &s->dcntl);
+ qemu_get_8s(f, &s->scntl0);
+ qemu_get_8s(f, &s->scntl1);
+ qemu_get_8s(f, &s->scntl2);
+ qemu_get_8s(f, &s->scntl3);
+ qemu_get_8s(f, &s->sstat0);
+ qemu_get_8s(f, &s->sstat1);
+ qemu_get_8s(f, &s->scid);
+ qemu_get_8s(f, &s->sxfer);
+ qemu_get_8s(f, &s->socl);
+ qemu_get_8s(f, &s->sdid);
+ qemu_get_8s(f, &s->ssid);
+ qemu_get_8s(f, &s->sfbr);
+ qemu_get_8s(f, &s->stest1);
+ qemu_get_8s(f, &s->stest2);
+ qemu_get_8s(f, &s->stest3);
+ qemu_get_8s(f, &s->sidl);
+ qemu_get_8s(f, &s->stime0);
+ qemu_get_8s(f, &s->respid0);
+ qemu_get_8s(f, &s->respid1);
+ qemu_get_be32s(f, &s->mmrs);
+ qemu_get_be32s(f, &s->mmws);
+ qemu_get_be32s(f, &s->sfs);
+ qemu_get_be32s(f, &s->drs);
+ qemu_get_be32s(f, &s->sbms);
+ qemu_get_be32s(f, &s->dbms);
+ qemu_get_be32s(f, &s->dnad64);
+ qemu_get_be32s(f, &s->pmjad1);
+ qemu_get_be32s(f, &s->pmjad2);
+ qemu_get_be32s(f, &s->rbc);
+ qemu_get_be32s(f, &s->ua);
+ qemu_get_be32s(f, &s->ia);
+ qemu_get_be32s(f, &s->sbc);
+ qemu_get_be32s(f, &s->csbc);
+ qemu_get_buffer(f, (uint8_t *)s->scratch, sizeof (s->scratch));
+ qemu_get_8s(f, &s->sbr);
+
+ qemu_get_buffer(f, (uint8_t *)s->script_ram, sizeof (s->script_ram));
+
+ return 0;
+}
+
+static int lsi_scsi_uninit(PCIDevice *d)
+{
+ LSIState *s = DO_UPCAST(LSIState, dev, d);
+
+ cpu_unregister_io_memory(s->mmio_io_addr);
+ cpu_unregister_io_memory(s->ram_io_addr);
+
+ qemu_free(s->queue);
+
+ return 0;
+}
- s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn,
+static int lsi_scsi_init(PCIDevice *dev)
+{
+ LSIState *s = DO_UPCAST(LSIState, dev, dev);
+ uint8_t *pci_conf;
+
+ pci_conf = s->dev.config;
+
+ /* PCI Vendor ID (word) */
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_LSI_LOGIC);
+ /* PCI device ID (word) */
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_LSI_53C895A);
+ /* PCI base class code */
+ pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_SCSI);
+ /* PCI subsystem ID */
+ pci_conf[0x2e] = 0x00;
+ pci_conf[0x2f] = 0x10;
+ /* PCI latency timer = 255 */
+ pci_conf[0x0d] = 0xff;
+ /* Interrupt pin 1 */
+ pci_conf[0x3d] = 0x01;
+
+ s->mmio_io_addr = cpu_register_io_memory(lsi_mmio_readfn,
lsi_mmio_writefn, s);
- s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn,
+ s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn,
lsi_ram_writefn, s);
- pci_register_io_region((struct PCIDevice *)s, 0, 256,
+ pci_register_bar((struct PCIDevice *)s, 0, 256,
PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc);
- pci_register_io_region((struct PCIDevice *)s, 1, 0x400,
+ pci_register_bar((struct PCIDevice *)s, 1, 0x400,
PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc);
- pci_register_io_region((struct PCIDevice *)s, 2, 0x2000,
+ pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc);
s->queue = qemu_malloc(sizeof(lsi_queue));
s->queue_len = 1;
s->active_commands = 0;
+ s->dev.unregister = lsi_scsi_uninit;
lsi_soft_reset(s);
- return s;
+ scsi_bus_new(&dev->qdev, lsi_scsi_attach);
+
+ register_savevm("lsiscsi", -1, 0, lsi_scsi_save, lsi_scsi_load, s);
+ return 0;
+}
+
+static PCIDeviceInfo lsi_info = {
+ .qdev.name = "lsi53c895a",
+ .qdev.size = sizeof(LSIState),
+ .init = lsi_scsi_init,
+};
+
+static void lsi53c895a_register_devices(void)
+{
+ pci_qdev_register(&lsi_info);
}
+device_init(lsi53c895a_register_devices);