From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:47722) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sb8Kl-0001BR-9T for qemu-devel@nongnu.org; Sun, 03 Jun 2012 06:46:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Sb8Ki-0002fn-IU for qemu-devel@nongnu.org; Sun, 03 Jun 2012 06:46:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:47809) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sb8Ki-0002fR-7x for qemu-devel@nongnu.org; Sun, 03 Jun 2012 06:46:52 -0400 Date: Sun, 3 Jun 2012 13:46:49 +0300 From: "Michael S. Tsirkin" Message-ID: <20120603104648.GD3640@redhat.com> References: <1338719890-9935-1-git-send-email-hpoussin@reactos.org> <1338719890-9935-8-git-send-email-hpoussin@reactos.org> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline In-Reply-To: <1338719890-9935-8-git-send-email-hpoussin@reactos.org> Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH 7/7] esp: add AMD PCscsi emulation (PCI SCSI adapter) List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?iso-8859-1?Q?Herv=E9?= Poussineau Cc: Blue Swirl , Kevin Wolf , qemu-devel@nongnu.org, Paolo Bonzini On Sun, Jun 03, 2012 at 12:38:09PM +0200, Herv=E9 Poussineau wrote: > The PCI version is supported in lots of Operating Systems, > and has been successfully tested on: > - MS DOS 6.22 with MS Windows 3.11 > - MS Windows 98 SE > - MS Windows NT 4.0 >=20 > Signed-off-by: Herv=E9 Poussineau I'm not sure why I'm Cc'd - for the pci_ids changes? These look fine to me. Some minor suggestions below but I only looked at it briefly. I don't have the time to do a proper review ATM, sorry. > --- > default-configs/i386-softmmu.mak | 1 + > hw/esp.c | 340 ++++++++++++++++++++++++++++++= +++++++- > hw/pci_ids.h | 1 + > trace-events | 8 + > 4 files changed, 349 insertions(+), 1 deletion(-) >=20 > diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-so= ftmmu.mak > index 2c78175..fee8cde 100644 > --- a/default-configs/i386-softmmu.mak > +++ b/default-configs/i386-softmmu.mak > @@ -25,3 +25,4 @@ CONFIG_HPET=3Dy > CONFIG_APPLESMC=3Dy > CONFIG_I8259=3Dy > CONFIG_PFLASH_CFI01=3Dy > +CONFIG_ESP=3Dy > diff --git a/hw/esp.c b/hw/esp.c > index e3425bb..f5c00fa 100644 > --- a/hw/esp.c > +++ b/hw/esp.c > @@ -2,6 +2,7 @@ > * QEMU ESP/NCR53C9x emulation > * > * Copyright (c) 2005-2006 Fabrice Bellard > + * Copyright (c) 2012 Herve Poussineau > * > * Permission is hereby granted, free of charge, to any person obtaini= ng a copy > * of this software and associated documentation files (the "Software"= ), to deal > @@ -23,6 +24,7 @@ > */ > =20 > #include "sysbus.h" > +#include "pci.h" > #include "scsi.h" > #include "esp.h" > #include "trace.h" > @@ -57,6 +59,7 @@ struct ESPState { > uint32_t cmdlen; > uint32_t do_cmd; > =20 > + bool dma_autostart; > /* The amount of data left in the current DMA transfer. */ > uint32_t dma_left; > /* The size of the current DMA transfer. Zero if no transfer is i= n > @@ -141,6 +144,7 @@ struct ESPState { > #define CFG1_RESREPT 0x40 > =20 > #define TCHI_FAS100A 0x4 > +#define TCHI_AM53C974 0x12 > =20 > static void esp_raise_irq(ESPState *s) > { > @@ -574,7 +578,9 @@ static void esp_reg_write(ESPState *s, uint32_t sad= dr, uint64_t val) > } > break; > case CMD_TI: > - handle_ti(s); > + if (!s->dma || s->dma_autostart) { > + handle_ti(s); > + } > break; > case CMD_ICCS: > trace_esp_mem_writeb_cmd_iccs(val); > @@ -669,6 +675,7 @@ static const VMStateDescription vmstate_esp =3D { > VMSTATE_UINT32(cmdlen, ESPState), > VMSTATE_UINT32(do_cmd, ESPState), > VMSTATE_UINT32(dma_left, ESPState), > + VMSTATE_BOOL(dma_autostart, ESPState), > VMSTATE_END_OF_LIST() > } > }; > @@ -770,6 +777,7 @@ static int sysbus_esp_init(SysBusDevice *dev) > assert(sysbus->it_shift !=3D -1); > =20 > s->chip_id =3D TCHI_FAS100A; > + s->dma_autostart =3D true; > memory_region_init_io(&sysbus->iomem, &sysbus_esp_mem_ops, sysbus, > "esp", ESP_REGS << sysbus->it_shift); > sysbus_init_mmio(dev, &sysbus->iomem); > @@ -814,9 +822,339 @@ static TypeInfo sysbus_esp_info =3D { > .class_init =3D sysbus_esp_class_init, > }; > =20 > +#define DMA_CMD 0x0 > +#define DMA_STC 0x1 > +#define DMA_SPA 0x2 > +#define DMA_WBC 0x3 > +#define DMA_WAC 0x4 > +#define DMA_STAT 0x5 > +#define DMA_SMDLA 0x6 > +#define DMA_WMAC 0x7 > + > +#define DMA_CMD_MASK 0x03 > +#define DMA_CMD_DIAG 0x04 > +#define DMA_CMD_MDL 0x10 > +#define DMA_CMD_INTE_P 0x20 > +#define DMA_CMD_INTE_D 0x40 > +#define DMA_CMD_DIR 0x80 > + > +#define DMA_STAT_PWDN 0x01 > +#define DMA_STAT_ERROR 0x02 > +#define DMA_STAT_ABORT 0x04 > +#define DMA_STAT_DONE 0x08 > +#define DMA_STAT_SCSIINT 0x10 > +#define DMA_STAT_BCMBLT 0x20 > + > +#define SBAC_STATUS 0x1000 > + > +typedef struct { > + PCIDevice dev; > + MemoryRegion io; > + uint32_t dma_regs[8]; > + uint32_t sbac; > + ESPState esp; > +} PCIESPState; minor: preferable typedef struct PCIESPState PCIESPState; > + > +static void pci_handle_start(PCIESPState *pci, uint32_t val) > +{ > + trace_esp_pci_dma_start(val); > + > + pci->dma_regs[DMA_WBC] =3D pci->dma_regs[DMA_STC]; > + pci->dma_regs[DMA_WAC] =3D pci->dma_regs[DMA_SPA]; > + pci->dma_regs[DMA_WMAC] =3D pci->dma_regs[DMA_SMDLA]; > + > + pci->dma_regs[DMA_STAT] &=3D ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT > + | DMA_STAT_DONE | DMA_STAT_ABORT > + | DMA_STAT_ERROR | DMA_STAT_PWDN); > + > + handle_ti(&pci->esp); > +} > + > +static void pci_handle_blast(PCIESPState *pci, uint32_t val) > +{ > + trace_esp_pci_dma_blast(val); > + hw_error("am53c974: cmd BLAST not implemented"); > +} > + > +static void pci_handle_abort(PCIESPState *pci, uint32_t val) > +{ > + trace_esp_pci_dma_abort(val); > + if (pci->esp.current_req) { > + scsi_req_cancel(pci->esp.current_req); > + } > +} > + It is better to prefix all global scope symbols with esp_ consistently. Reduces the chance of a conflict. > +static void pci_esp_dma_write(PCIESPState *pci, uint32_t saddr, uint32= _t val) > +{ > + trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val); > + switch (saddr) { > + case DMA_CMD: > + pci->dma_regs[saddr] =3D val; > + switch (val & DMA_CMD_MASK) { > + case 0x0: /* IDLE */ > + trace_esp_pci_dma_idle(val); > + break; > + case 0x1: /* BLAST */ > + pci_handle_blast(pci, val); fall-through intentional? > + case 0x2: /* ABORT */ > + pci_handle_abort(pci, val); > + case 0x3: /* START */ > + pci_handle_start(pci, val); > + break; > + default: > + error_report("am53c974: unhandled command (%2.2x)", > + val & DMA_CMD_MASK); > + break; > + } > + break; > + case DMA_STC: > + case DMA_SPA: > + case DMA_SMDLA: > + pci->dma_regs[saddr] =3D val; > + break; > + case DMA_STAT: > + if (!(pci->sbac & SBAC_STATUS)) { > + /* clear some bits on write */ > + uint32_t mask =3D DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_ST= AT_DONE; > + pci->dma_regs[DMA_STAT] &=3D ~(val & mask); > + } > + break; > + default: > + error_report("am53c974: invalid write of 0x%08x at [0x%x]", va= l, saddr); > + return; > + } > +} > + > +static uint32_t pci_esp_dma_read(PCIESPState *pci, uint32_t saddr) > +{ > + uint32_t val; > + > + val =3D pci->dma_regs[saddr]; > + if (saddr =3D=3D DMA_STAT) { > + if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) { > + val |=3D DMA_STAT_SCSIINT; > + } > + if (pci->sbac & SBAC_STATUS) { > + pci->dma_regs[DMA_STAT] &=3D ~(DMA_STAT_ERROR | DMA_STAT_A= BORT | > + DMA_STAT_DONE); > + } > + } > + > + trace_esp_pci_dma_read(saddr, val); > + return val; > +} > + > +static void pci_esp_io_write(void *opaque, target_phys_addr_t addr, > + uint64_t val, unsigned int size) > +{ > + PCIESPState *pci =3D opaque; > + > + if (addr < 0x40) { > + /* SCSI core reg */ > + esp_reg_write(&pci->esp, addr >> 2, val); > + } else if (addr < 0x60) { > + /* PCI DMA CCB */ > + pci_esp_dma_write(pci, (addr - 0x40) >> 2, val); > + } else if (addr =3D=3D 0x70) { > + /* DMA SCSI Bus and control */ > + trace_esp_pci_sbac_write(pci->sbac, val); > + pci->sbac =3D val; > + } else { > + error_report("am53c974: write access outside bounds (reg 0x%x)= ", > + (int)addr); > + } > +} > + > +static uint64_t pci_esp_io_read(void *opaque, target_phys_addr_t addr, > + unsigned int size) > +{ > + PCIESPState *pci =3D opaque; > + > + if (addr < 0x40) { > + /* SCSI core reg */ > + return esp_reg_read(&pci->esp, addr >> 2); > + } else if (addr < 0x60) { > + /* PCI DMA CCB */ > + return pci_esp_dma_read(pci, (addr - 0x40) >> 2); > + } else if (addr =3D=3D 0x70) { > + /* DMA SCSI Bus and control */ > + trace_esp_pci_sbac_read(pci->sbac); > + return pci->sbac; > + } else { > + /* Invalid region */ > + error_report("am53c974: read access outside bounds (reg 0x%x)"= , > + (int)addr); > + return 0; > + } > +} > + > +static void pci_esp_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int = len, > + DMADirection dir) > +{ > + dma_addr_t addr; > + DMADirection expected_dir; > + > + if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) { > + expected_dir =3D DMA_DIRECTION_FROM_DEVICE; > + } else { > + expected_dir =3D DMA_DIRECTION_TO_DEVICE; > + } > + > + if (dir !=3D expected_dir) { > + error_report("am53c974: invalid dma transfer direction"); > + return; > + } > + > + if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) { > + hw_error("am53c974: MDL transfer not implemented"); > + } > + > + addr =3D pci->dma_regs[DMA_SPA]; > + if (pci->dma_regs[DMA_WBC] < len) { > + len =3D pci->dma_regs[DMA_WBC]; > + } > + > + pci_dma_rw(&pci->dev, addr, buf, len, dir); > + > + /* update status registers */ > + pci->dma_regs[DMA_WBC] -=3D len; > + pci->dma_regs[DMA_WAC] +=3D len; > +} > + > +static void pci_esp_dma_memory_read(void *opaque, uint8_t *buf, int le= n) > +{ > + PCIESPState *pci =3D opaque; > + pci_esp_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE); > +} > + > +static void pci_esp_dma_memory_write(void *opaque, uint8_t *buf, int l= en) > +{ > + PCIESPState *pci =3D opaque; > + pci_esp_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE); > +} > + > +static const MemoryRegionOps pci_esp_io_ops =3D { > + .read =3D pci_esp_io_read, > + .write =3D pci_esp_io_write, > + .endianness =3D DEVICE_LITTLE_ENDIAN, > + .impl =3D { > + .min_access_size =3D 4, > + .max_access_size =3D 4, > + }, > +}; > + > +static void pci_esp_hard_reset(DeviceState *dev) > +{ > + PCIESPState *pci =3D DO_UPCAST(PCIESPState, dev.qdev, dev); > + esp_hard_reset(&pci->esp); > + pci->esp.dma_enabled =3D 1; > + pci->dma_regs[DMA_CMD] &=3D ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_C= MD_INTE_P > + | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_M= ASK); > + pci->dma_regs[DMA_WBC] &=3D ~0xffff; > + pci->dma_regs[DMA_WAC] =3D 0xffffffff; > + pci->dma_regs[DMA_STAT] &=3D ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT > + | DMA_STAT_DONE | DMA_STAT_ABORT > + | DMA_STAT_ERROR); > + pci->dma_regs[DMA_WMAC] =3D 0xfffffffd; > +} > + > +static const VMStateDescription vmstate_pci_esp_scsi =3D { > + .name =3D "pciespscsi", > + .version_id =3D 0, > + .minimum_version_id =3D 0, > + .minimum_version_id_old =3D 0, > + .fields =3D (VMStateField[]) { > + VMSTATE_PCI_DEVICE(dev, PCIESPState), > + VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uin= t32_t)), > + VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void pci_esp_command_complete(SCSIRequest *req, uint32_t status= , > + size_t resid) > +{ > + ESPState *s =3D req->hba_private; > + PCIESPState *pci =3D container_of(s, PCIESPState, esp); > + > + esp_command_complete(req, status, resid); > + pci->dma_regs[DMA_WBC] =3D 0; > + pci->dma_regs[DMA_STAT] |=3D DMA_STAT_DONE; > +} > + > +static const struct SCSIBusInfo pci_esp_scsi_info =3D { > + .tcq =3D false, > + .max_target =3D ESP_MAX_DEVS, > + .max_lun =3D 7, > + > + .transfer_data =3D esp_transfer_data, > + .complete =3D pci_esp_command_complete, > + .cancel =3D esp_request_cancelled > +}; > + > +static int pci_esp_scsi_init(PCIDevice *dev) > +{ > + PCIESPState *pci =3D DO_UPCAST(PCIESPState, dev, dev); > + ESPState *s =3D &pci->esp; > + uint8_t *pci_conf; > + > + pci_conf =3D pci->dev.config; > + > + /* Interrupt pin A */ > + pci_conf[PCI_INTERRUPT_PIN] =3D 0x01; > + > + s->dma_memory_read =3D pci_esp_dma_memory_read; > + s->dma_memory_write =3D pci_esp_dma_memory_write; > + s->dma_opaque =3D pci; > + s->chip_id =3D TCHI_AM53C974; > + memory_region_init_io(&pci->io, &pci_esp_io_ops, pci, "esp-io", 0x= 80); > + > + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io= ); > + s->irq =3D pci->dev.irq[0]; > + > + scsi_bus_new(&s->bus, &dev->qdev, &pci_esp_scsi_info); > + if (!dev->qdev.hotplugged) { > + return scsi_bus_legacy_handle_cmdline(&s->bus); > + } > + return 0; > +} > + > +static int pci_esp_scsi_uninit(PCIDevice *d) > +{ > + PCIESPState *pci =3D DO_UPCAST(PCIESPState, dev, d); > + > + memory_region_destroy(&pci->io); > + > + return 0; > +} > + > +static void pci_esp_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc =3D DEVICE_CLASS(klass); > + PCIDeviceClass *k =3D PCI_DEVICE_CLASS(klass); > + > + k->init =3D pci_esp_scsi_init; > + k->exit =3D pci_esp_scsi_uninit; > + k->vendor_id =3D PCI_VENDOR_ID_AMD; > + k->device_id =3D PCI_DEVICE_ID_AMD_SCSI; > + k->revision =3D 0x10; > + k->class_id =3D PCI_CLASS_STORAGE_SCSI; > + dc->desc =3D "AMD Am53c974 PCscsi-PCI SCSI adapter"; > + dc->reset =3D pci_esp_hard_reset; > + dc->vmsd =3D &vmstate_pci_esp_scsi; > +} > + > +static TypeInfo pci_esp_info =3D { > + .name =3D "am53c974", > + .parent =3D TYPE_PCI_DEVICE, > + .instance_size =3D sizeof(PCIESPState), > + .class_init =3D pci_esp_class_init, > +}; > + > static void esp_register_types(void) > { > type_register_static(&sysbus_esp_info); > + type_register_static(&pci_esp_info); > } > =20 > type_init(esp_register_types) > diff --git a/hw/pci_ids.h b/hw/pci_ids.h > index e8235a7..9d6e30b 100644 > --- a/hw/pci_ids.h > +++ b/hw/pci_ids.h > @@ -57,6 +57,7 @@ > =20 > #define PCI_VENDOR_ID_AMD 0x1022 > #define PCI_DEVICE_ID_AMD_LANCE 0x2000 > +#define PCI_DEVICE_ID_AMD_SCSI 0x2020 > =20 > #define PCI_VENDOR_ID_TI 0x104c > =20 > diff --git a/trace-events b/trace-events > index 81780f0..8acb647 100644 > --- a/trace-events > +++ b/trace-events > @@ -639,6 +639,14 @@ esp_mem_writeb_cmd_selatn(uint32_t val) "Select wi= th ATN (%2.2x)" > esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (%2.2= x)" > esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)" > esp_mem_writeb_cmd_dissel(uint32_t val) "Disable selection (%2.2x)" > +esp_pci_dma_read(uint32_t saddr, uint32_t reg) "reg[%d]: 0x%8.8x" > +esp_pci_dma_write(uint32_t saddr, uint32_t reg, uint32_t val) "reg[%d]= : 0x%8.8x -> 0x%8.8x" > +esp_pci_dma_idle(uint32_t val) "IDLE (%.8x)" > +esp_pci_dma_blast(uint32_t val) "BLAST (%.8x)" > +esp_pci_dma_abort(uint32_t val) "ABORT (%.8x)" > +esp_pci_dma_start(uint32_t val) "START (%.8x)" > +esp_pci_sbac_read(uint32_t reg) "sbac: 0x%8.8x" > +esp_pci_sbac_write(uint32_t reg, uint32_t val) "sbac: 0x%8.8x -> 0x%8.= 8x" > =20 > # monitor.c > handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \= "%s\"" > --=20 > 1.7.10