X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hw%2Fscsi%2Flsi53c895a.c;h=160657f4b9d447c9333f29bd8038e3f6302b5075;hb=a736d719e75db57f05f7be4103a226851d4887e7;hp=513ea47e8aa5ec29eb05967373b9019741e2c29b;hpb=0e4a77370594c91dd126f9872893ed473374cc72;p=mirror_qemu.git diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 513ea47e8a..160657f4b9 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -13,12 +13,13 @@ * as well-behaved operating systems will not try to use them. */ -#include +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "hw/scsi/scsi.h" #include "sysemu/dma.h" +#include "qemu/log.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG @@ -34,6 +35,21 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #endif +static const char *names[] = { + "SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3", "SCID", "SXFER", "SDID", "GPREG", + "SFBR", "SOCL", "SSID", "SBCL", "DSTAT", "SSTAT0", "SSTAT1", "SSTAT2", + "DSA0", "DSA1", "DSA2", "DSA3", "ISTAT", "0x15", "0x16", "0x17", + "CTEST0", "CTEST1", "CTEST2", "CTEST3", "TEMP0", "TEMP1", "TEMP2", "TEMP3", + "DFIFO", "CTEST4", "CTEST5", "CTEST6", "DBC0", "DBC1", "DBC2", "DCMD", + "DNAD0", "DNAD1", "DNAD2", "DNAD3", "DSP0", "DSP1", "DSP2", "DSP3", + "DSPS0", "DSPS1", "DSPS2", "DSPS3", "SCRATCHA0", "SCRATCHA1", "SCRATCHA2", "SCRATCHA3", + "DMODE", "DIEN", "SBR", "DCNTL", "ADDER0", "ADDER1", "ADDER2", "ADDER3", + "SIEN0", "SIEN1", "SIST0", "SIST1", "SLPAR", "0x45", "MACNTL", "GPCNTL", + "STIME0", "STIME1", "RESPID", "0x4b", "STEST0", "STEST1", "STEST2", "STEST3", + "SIDL", "0x51", "0x52", "0x53", "SODL", "0x55", "0x56", "0x57", + "SBDL", "0x59", "0x5a", "0x5b", "SCRATCHB0", "SCRATCHB1", "SCRATCHB2", "SCRATCHB3", +}; + #define LSI_MAX_DEVS 7 #define LSI_SCNTL0_TRG 0x01 @@ -194,6 +210,7 @@ typedef struct { MemoryRegion mmio_io; MemoryRegion ram_io; MemoryRegion io_io; + AddressSpace pci_io_as; int carry; /* ??? Should this be an a visible register somewhere? */ int status; @@ -276,6 +293,7 @@ typedef struct { uint32_t csbc; uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */ uint8_t sbr; + uint32_t adder; /* Script ram is stored as 32-bit words in host byteorder. */ uint32_t script_ram[2048]; @@ -308,7 +326,7 @@ static void lsi_soft_reset(LSIState *s) s->istat0 = 0; s->istat1 = 0; s->dcmd = 0x40; - s->dstat = LSI_DSTAT_DFE; + s->dstat = 0; s->dien = 0; s->sist0 = 0; s->sist1 = 0; @@ -390,6 +408,28 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); static void lsi_execute_script(LSIState *s); static void lsi_reselect(LSIState *s, lsi_request *p); +static inline void lsi_mem_read(LSIState *s, dma_addr_t addr, + void *buf, dma_addr_t len) +{ + if (s->dmode & LSI_DMODE_SIOM) { + address_space_read(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED, + buf, len); + } else { + pci_dma_read(PCI_DEVICE(s), addr, buf, len); + } +} + +static inline void lsi_mem_write(LSIState *s, dma_addr_t addr, + const void *buf, dma_addr_t len) +{ + if (s->dmode & LSI_DMODE_DIOM) { + address_space_write(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED, + buf, len); + } else { + pci_dma_write(PCI_DEVICE(s), addr, buf, len); + } +} + static inline uint32_t read_dword(LSIState *s, uint32_t addr) { uint32_t buf; @@ -533,7 +573,6 @@ static void lsi_bad_selection(LSIState *s, uint32_t id) /* Initiate a SCSI layer data transfer. */ static void lsi_do_dma(LSIState *s, int out) { - PCIDevice *pci_dev; uint32_t count; dma_addr_t addr; SCSIDevice *dev; @@ -545,7 +584,6 @@ static void lsi_do_dma(LSIState *s, int out) return; } - pci_dev = PCI_DEVICE(s); dev = s->current->req->dev; assert(dev); @@ -571,9 +609,9 @@ static void lsi_do_dma(LSIState *s, int out) } /* ??? Set SFBR to first data byte. */ if (out) { - pci_dma_read(pci_dev, addr, s->current->dma_buf, count); + lsi_mem_read(s, addr, s->current->dma_buf, count); } else { - pci_dma_write(pci_dev, addr, s->current->dma_buf, count); + lsi_mem_write(s, addr, s->current->dma_buf, count); } s->current->dma_len -= count; if (s->current->dma_len == 0) { @@ -780,7 +818,7 @@ static void lsi_do_command(LSIState *s) } assert(s->current == NULL); - s->current = g_malloc0(sizeof(lsi_request)); + s->current = g_new0(lsi_request, 1); s->current->tag = s->select_tag; s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf, s->current); @@ -1005,15 +1043,14 @@ bad: #define LSI_BUF_SIZE 4096 static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) { - PCIDevice *d = PCI_DEVICE(s); int n; uint8_t buf[LSI_BUF_SIZE]; DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); while (count) { n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count; - pci_dma_read(d, src, buf, n); - pci_dma_write(d, dest, buf, n); + lsi_mem_read(s, src, buf, n); + lsi_mem_write(s, dest, buf, n); src += n; dest += n; count -= n; @@ -1388,6 +1425,7 @@ again: switch ((insn >> 27) & 7) { case 0: /* Jump */ DPRINTF("Jump to 0x%08x\n", addr); + s->adder = addr; s->dsp = addr; break; case 1: /* Call */ @@ -1478,151 +1516,200 @@ again: static uint8_t lsi_reg_readb(LSIState *s, int offset) { - uint8_t tmp; + uint8_t ret; + #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; + case addr: ret = s->name & 0xff; break; \ + case addr + 1: ret = (s->name >> 8) & 0xff; break; \ + case addr + 2: ret = (s->name >> 16) & 0xff; break; #define CASE_GET_REG32(name, addr) \ - case addr: return s->name & 0xff; \ - case addr + 1: return (s->name >> 8) & 0xff; \ - case addr + 2: return (s->name >> 16) & 0xff; \ - case addr + 3: return (s->name >> 24) & 0xff; + case addr: ret = s->name & 0xff; break; \ + case addr + 1: ret = (s->name >> 8) & 0xff; break; \ + case addr + 2: ret = (s->name >> 16) & 0xff; break; \ + case addr + 3: ret = (s->name >> 24) & 0xff; break; -#ifdef DEBUG_LSI_REG - DPRINTF("Read reg %x\n", offset); -#endif switch (offset) { case 0x00: /* SCNTL0 */ - return s->scntl0; + ret = s->scntl0; + break; case 0x01: /* SCNTL1 */ - return s->scntl1; + ret = s->scntl1; + break; case 0x02: /* SCNTL2 */ - return s->scntl2; + ret = s->scntl2; + break; case 0x03: /* SCNTL3 */ - return s->scntl3; + ret = s->scntl3; + break; case 0x04: /* SCID */ - return s->scid; + ret = s->scid; + break; case 0x05: /* SXFER */ - return s->sxfer; + ret = s->sxfer; + break; case 0x06: /* SDID */ - return s->sdid; + ret = s->sdid; + break; case 0x07: /* GPREG0 */ - return 0x7f; + ret = 0x7f; + break; case 0x08: /* Revision ID */ - return 0x00; + ret = 0x00; + break; + case 0x09: /* SOCL */ + ret = s->socl; + break; case 0xa: /* SSID */ - return s->ssid; + ret = s->ssid; + break; case 0xb: /* SBCL */ /* ??? This is not correct. However it's (hopefully) only used for diagnostics, so should be ok. */ - return 0; + ret = 0; + break; case 0xc: /* DSTAT */ - tmp = s->dstat | LSI_DSTAT_DFE; + ret = s->dstat | LSI_DSTAT_DFE; if ((s->istat0 & LSI_ISTAT0_INTF) == 0) s->dstat = 0; lsi_update_irq(s); - return tmp; + break; case 0x0d: /* SSTAT0 */ - return s->sstat0; + ret = s->sstat0; + break; case 0x0e: /* SSTAT1 */ - return s->sstat1; + ret = s->sstat1; + break; case 0x0f: /* SSTAT2 */ - return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; + ret = s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; + break; CASE_GET_REG32(dsa, 0x10) case 0x14: /* ISTAT0 */ - return s->istat0; + ret = s->istat0; + break; case 0x15: /* ISTAT1 */ - return s->istat1; + ret = s->istat1; + break; case 0x16: /* MBOX0 */ - return s->mbox0; + ret = s->mbox0; + break; case 0x17: /* MBOX1 */ - return s->mbox1; + ret = s->mbox1; + break; case 0x18: /* CTEST0 */ - return 0xff; + ret = 0xff; + break; case 0x19: /* CTEST1 */ - return 0; + ret = 0; + break; case 0x1a: /* CTEST2 */ - tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM; + ret = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM; if (s->istat0 & LSI_ISTAT0_SIGP) { s->istat0 &= ~LSI_ISTAT0_SIGP; - tmp |= LSI_CTEST2_SIGP; + ret |= LSI_CTEST2_SIGP; } - return tmp; + break; case 0x1b: /* CTEST3 */ - return s->ctest3; + ret = s->ctest3; + break; CASE_GET_REG32(temp, 0x1c) case 0x20: /* DFIFO */ - return 0; + ret = 0; + break; case 0x21: /* CTEST4 */ - return s->ctest4; + ret = s->ctest4; + break; case 0x22: /* CTEST5 */ - return s->ctest5; + ret = s->ctest5; + break; case 0x23: /* CTEST6 */ - return 0; + ret = 0; + break; CASE_GET_REG24(dbc, 0x24) case 0x27: /* DCMD */ - return s->dcmd; + ret = s->dcmd; + break; CASE_GET_REG32(dnad, 0x28) CASE_GET_REG32(dsp, 0x2c) CASE_GET_REG32(dsps, 0x30) CASE_GET_REG32(scratch[0], 0x34) case 0x38: /* DMODE */ - return s->dmode; + ret = s->dmode; + break; case 0x39: /* DIEN */ - return s->dien; + ret = s->dien; + break; case 0x3a: /* SBR */ - return s->sbr; + ret = s->sbr; + break; case 0x3b: /* DCNTL */ - return s->dcntl; + ret = s->dcntl; + break; + /* ADDER Output (Debug of relative jump address) */ + CASE_GET_REG32(adder, 0x3c) case 0x40: /* SIEN0 */ - return s->sien0; + ret = s->sien0; + break; case 0x41: /* SIEN1 */ - return s->sien1; + ret = s->sien1; + break; case 0x42: /* SIST0 */ - tmp = s->sist0; + ret = s->sist0; s->sist0 = 0; lsi_update_irq(s); - return tmp; + break; case 0x43: /* SIST1 */ - tmp = s->sist1; + ret = s->sist1; s->sist1 = 0; lsi_update_irq(s); - return tmp; + break; case 0x46: /* MACNTL */ - return 0x0f; + ret = 0x0f; + break; case 0x47: /* GPCNTL0 */ - return 0x0f; + ret = 0x0f; + break; case 0x48: /* STIME0 */ - return s->stime0; + ret = s->stime0; + break; case 0x4a: /* RESPID0 */ - return s->respid0; + ret = s->respid0; + break; case 0x4b: /* RESPID1 */ - return s->respid1; + ret = s->respid1; + break; case 0x4d: /* STEST1 */ - return s->stest1; + ret = s->stest1; + break; case 0x4e: /* STEST2 */ - return s->stest2; + ret = s->stest2; + break; case 0x4f: /* STEST3 */ - return s->stest3; + ret = s->stest3; + break; case 0x50: /* SIDL */ /* This is needed by the linux drivers. We currently only update it during the MSG IN phase. */ - return s->sidl; + ret = s->sidl; + break; case 0x52: /* STEST4 */ - return 0xe0; + ret = 0xe0; + break; case 0x56: /* CCNTL0 */ - return s->ccntl0; + ret = s->ccntl0; + break; case 0x57: /* CCNTL1 */ - return s->ccntl1; + ret = s->ccntl1; + break; case 0x58: /* SBDL */ /* Some drivers peek at the data bus during the MSG IN phase. */ if ((s->sstat1 & PHASE_MASK) == PHASE_MI) return s->msg[0]; - return 0; + ret = 0; + break; case 0x59: /* SBDL high */ - return 0; + ret = 0; + break; CASE_GET_REG32(mmrs, 0xa0) CASE_GET_REG32(mmws, 0xa4) CASE_GET_REG32(sfs, 0xa8) @@ -1637,18 +1724,34 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) CASE_GET_REG32(ia, 0xd4) CASE_GET_REG32(sbc, 0xd8) CASE_GET_REG32(csbc, 0xdc) - } - if (offset >= 0x5c && offset < 0xa0) { + case 0x5c ... 0x9f: + { int n; int shift; n = (offset - 0x58) >> 2; shift = (offset & 3) * 8; - return (s->scratch[n] >> shift) & 0xff; + ret = (s->scratch[n] >> shift) & 0xff; + break; + } + default: + { + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: invalid read from reg %s %x\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", + offset); + ret = 0xff; + break; + } } - BADF("readb 0x%x\n", offset); - exit(1); #undef CASE_GET_REG24 #undef CASE_GET_REG32 + +#ifdef DEBUG_LSI_REG + DPRINTF("Read reg %s %x = %02x\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, ret); +#endif + + return ret; } static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) @@ -1665,7 +1768,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break; #ifdef DEBUG_LSI_REG - DPRINTF("Write reg %x = %02x\n", offset, val); + DPRINTF("Write reg %s %x = %02x\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, val); #endif switch (offset) { case 0x00: /* SCNTL0 */ @@ -1793,9 +1897,6 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) CASE_SET_REG32(dsps, 0x30) CASE_SET_REG32(scratch[0], 0x34) case 0x38: /* DMODE */ - if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) { - BADF("IO mappings not implemented\n"); - } s->dmode = val; break; case 0x39: /* DIEN */ @@ -1880,7 +1981,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) shift = (offset & 3) * 8; s->scratch[n] = deposit32(s->scratch[n], shift, 8, val); } else { - BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val); + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: invalid write to reg %s %x (0x%02x)\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", + offset, val); } } #undef CASE_SET_REG24 @@ -1979,7 +2083,7 @@ static void lsi_scsi_reset(DeviceState *dev) lsi_soft_reset(s); } -static void lsi_pre_save(void *opaque) +static int lsi_pre_save(void *opaque) { LSIState *s = opaque; @@ -1988,6 +2092,8 @@ static void lsi_pre_save(void *opaque) assert(s->current->dma_len == 0); } assert(QTAILQ_EMPTY(&s->queue)); + + return 0; } static const VMStateDescription vmstate_lsi_scsi = { @@ -2082,12 +2188,11 @@ static const struct SCSIBusInfo lsi_scsi_info = { .cancel = lsi_request_cancelled }; -static int lsi_scsi_init(PCIDevice *dev) +static void lsi_scsi_realize(PCIDevice *dev, Error **errp) { LSIState *s = LSI53C895A(dev); DeviceState *d = DEVICE(dev); uint8_t *pci_conf; - Error *err = NULL; pci_conf = dev->config; @@ -2103,20 +2208,21 @@ static int lsi_scsi_init(PCIDevice *dev) memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s, "lsi-io", 256); + address_space_init(&s->pci_io_as, pci_address_space_io(dev), "lsi-pci-io"); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io); pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_io); pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io); QTAILQ_INIT(&s->queue); scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL); - if (!d->hotplugged) { - scsi_bus_legacy_handle_cmdline(&s->bus, &err); - if (err != NULL) { - error_free(err); - return -1; - } - } - return 0; +} + +static void lsi_scsi_unrealize(DeviceState *dev, Error **errp) +{ + LSIState *s = LSI53C895A(dev); + + address_space_destroy(&s->pci_io_as); } static void lsi_class_init(ObjectClass *klass, void *data) @@ -2124,11 +2230,12 @@ static void lsi_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->init = lsi_scsi_init; + k->realize = lsi_scsi_realize; k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; k->device_id = PCI_DEVICE_ID_LSI_53C895A; k->class_id = PCI_CLASS_STORAGE_SCSI; k->subsystem_id = 0x1000; + dc->unrealize = lsi_scsi_unrealize; dc->reset = lsi_scsi_reset; dc->vmsd = &vmstate_lsi_scsi; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); @@ -2139,6 +2246,10 @@ static const TypeInfo lsi_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(LSIState), .class_init = lsi_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, }; static void lsi53c810_class_init(ObjectClass *klass, void *data) @@ -2161,3 +2272,17 @@ static void lsi53c895a_register_types(void) } type_init(lsi53c895a_register_types) + +void lsi53c895a_create(PCIBus *bus) +{ + LSIState *s = LSI53C895A(pci_create_simple(bus, -1, "lsi53c895a")); + + scsi_bus_legacy_handle_cmdline(&s->bus); +} + +void lsi53c810_create(PCIBus *bus, int devfn) +{ + LSIState *s = LSI53C895A(pci_create_simple(bus, devfn, "lsi53c810")); + + scsi_bus_legacy_handle_cmdline(&s->bus); +}