X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=hw%2Fesp.c;h=2435371d5c5d57e3116691e68b16929dcd6cbb90;hb=22a0e04b9bb5a02e13b3e5cf5ea8abfac5f34120;hp=0a8b3e4d8c5f556961c7196828c27440d3cb5e9c;hpb=2ca83a8dd63bde5f78300dc0c21159873d5aaf54;p=qemu.git diff --git a/hw/esp.c b/hw/esp.c index 0a8b3e4d8..2435371d5 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "scsi-disk.h" +#include "sysbus.h" #include "scsi.h" +#include "esp.h" /* debug ESP card */ //#define DEBUG_ESP @@ -38,18 +38,22 @@ */ #ifdef DEBUG_ESP -#define DPRINTF(fmt, args...) \ -do { printf("ESP: " fmt , ##args); } while (0) +#define DPRINTF(fmt, ...) \ + do { printf("ESP: " fmt , ## __VA_ARGS__); } while (0) #else -#define DPRINTF(fmt, args...) do {} while (0) +#define DPRINTF(fmt, ...) do {} while (0) #endif +#define ESP_ERROR(fmt, ...) \ + do { printf("ESP ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) + #define ESP_REGS 16 -#define TI_BUFSZ 32 +#define TI_BUFSZ 16 typedef struct ESPState ESPState; struct ESPState { + SysBusDevice busdev; uint32_t it_shift; qemu_irq irq; uint8_t rregs[ESP_REGS]; @@ -59,7 +63,7 @@ struct ESPState { uint8_t ti_buf[TI_BUFSZ]; uint32_t sense; uint32_t dma; - SCSIDevice *scsi_dev[ESP_MAX_DEVS]; + SCSIBus bus; SCSIDevice *current_dev; uint8_t cmdbuf[TI_BUFSZ]; uint32_t cmdlen; @@ -111,7 +115,9 @@ struct ESPState { #define CMD_TI 0x10 #define CMD_ICCS 0x11 #define CMD_MSGACC 0x12 +#define CMD_PAD 0x18 #define CMD_SATN 0x1a +#define CMD_SEL 0x41 #define CMD_SELATN 0x42 #define CMD_SELATNS 0x43 #define CMD_ENSEL 0x44 @@ -120,8 +126,8 @@ struct ESPState { #define STAT_DI 0x01 #define STAT_CD 0x02 #define STAT_ST 0x03 -#define STAT_MI 0x06 -#define STAT_MO 0x07 +#define STAT_MO 0x06 +#define STAT_MI 0x07 #define STAT_PIO_MASK 0x06 #define STAT_TC 0x10 @@ -129,6 +135,8 @@ struct ESPState { #define STAT_GE 0x40 #define STAT_INT 0x80 +#define BUSID_DID 0x07 + #define INTR_FC 0x08 #define INTR_BS 0x10 #define INTR_DC 0x20 @@ -139,8 +147,6 @@ struct ESPState { #define CFG1_RESREPT 0x40 -#define CFG2_MASK 0x15 - #define TCHI_FAS100A 0x4 static void esp_raise_irq(ESPState *s) @@ -164,16 +170,16 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) uint32_t dmalen; int target; - dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); - target = s->wregs[ESP_WBUSID] & 7; - DPRINTF("get_cmd: len %d target %d\n", dmalen, target); + target = s->wregs[ESP_WBUSID] & BUSID_DID; if (s->dma) { + dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); s->dma_memory_read(s->dma_opaque, buf, dmalen); } else { + dmalen = s->ti_size; + memcpy(buf, s->ti_buf, dmalen); buf[0] = 0; - memcpy(&buf[1], s->ti_buf, dmalen); - dmalen++; } + DPRINTF("get_cmd: len %d target %d\n", dmalen, target); s->ti_size = 0; s->ti_rptr = 0; @@ -181,11 +187,11 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) if (s->current_dev) { /* Started a new command before the old one finished. Cancel it. */ - s->current_dev->cancel_io(s->current_dev, 0); + s->current_dev->info->cancel_io(s->current_dev, 0); s->async_len = 0; } - if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) { + if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) { // No such drive s->rregs[ESP_RSTAT] = 0; s->rregs[ESP_RINTR] = INTR_DC; @@ -193,18 +199,18 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) esp_raise_irq(s); return 0; } - s->current_dev = s->scsi_dev[target]; + s->current_dev = s->bus.devs[target]; return dmalen; } -static void do_cmd(ESPState *s, uint8_t *buf) +static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) { int32_t datalen; int lun; - DPRINTF("do_cmd: busid 0x%x\n", buf[0]); - lun = buf[0] & 7; - datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun); + DPRINTF("do_busid_cmd: busid 0x%x\n", busid); + lun = busid & 7; + datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun); s->ti_size = datalen; if (datalen != 0) { s->rregs[ESP_RSTAT] = STAT_TC; @@ -212,10 +218,10 @@ static void do_cmd(ESPState *s, uint8_t *buf) s->dma_counter = 0; if (datalen > 0) { s->rregs[ESP_RSTAT] |= STAT_DI; - s->current_dev->read_data(s->current_dev, 0); + s->current_dev->info->read_data(s->current_dev, 0); } else { s->rregs[ESP_RSTAT] |= STAT_DO; - s->current_dev->write_data(s->current_dev, 0); + s->current_dev->info->write_data(s->current_dev, 0); } } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; @@ -223,6 +229,13 @@ static void do_cmd(ESPState *s, uint8_t *buf) esp_raise_irq(s); } +static void do_cmd(ESPState *s, uint8_t *buf) +{ + uint8_t busid = buf[0]; + + do_busid_cmd(s, &buf[1], busid); +} + static void handle_satn(ESPState *s) { uint8_t buf[32]; @@ -233,6 +246,17 @@ static void handle_satn(ESPState *s) do_cmd(s, buf); } +static void handle_s_without_atn(ESPState *s) +{ + uint8_t buf[32]; + int len; + + len = get_cmd(s, buf); + if (len) { + do_busid_cmd(s, buf, 0); + } +} + static void handle_satn_stop(ESPState *s) { s->cmdlen = get_cmd(s, s->cmdbuf); @@ -314,11 +338,11 @@ static void esp_do_dma(ESPState *s) if (s->async_len == 0) { if (to_device) { // ti_size is negative - s->current_dev->write_data(s->current_dev, 0); + s->current_dev->info->write_data(s->current_dev, 0); } else { - s->current_dev->read_data(s->current_dev, 0); + s->current_dev->info->read_data(s->current_dev, 0); /* If there is still data to be read from the device then - complete the DMA operation immeriately. Otherwise defer + complete the DMA operation immediately. Otherwise defer until the scsi layer has completed. */ if (s->dma_left == 0 && s->ti_size > 0) { esp_dma_done(s); @@ -330,10 +354,10 @@ static void esp_do_dma(ESPState *s) } } -static void esp_command_complete(void *opaque, int reason, uint32_t tag, +static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg) { - ESPState *s = (ESPState *)opaque; + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent); if (reason == SCSI_REASON_DONE) { DPRINTF("SCSI Command complete\n"); @@ -351,7 +375,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); s->async_len = arg; - s->async_buf = s->current_dev->get_buf(s->current_dev, 0); + s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0); if (s->dma_left) { esp_do_dma(s); } else if (s->dma_counter != 0 && s->ti_size <= 0) { @@ -393,11 +417,9 @@ static void handle_ti(ESPState *s) } } -static void esp_reset(void *opaque) +static void esp_reset(DeviceState *d) { - ESPState *s = opaque; - - esp_lower_irq(s); + ESPState *s = container_of(d, ESPState, busdev.qdev); memset(s->rregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS); @@ -407,6 +429,8 @@ static void esp_reset(void *opaque) s->ti_wptr = 0; s->dma = 0; s->do_cmd = 0; + + s->rregs[ESP_CFG1] = 7; } static void parent_esp_reset(void *opaque, int irq, int level) @@ -418,17 +442,17 @@ static void parent_esp_reset(void *opaque, int irq, int level) static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) { ESPState *s = opaque; - uint32_t saddr; + uint32_t saddr, old_val; - saddr = (addr >> s->it_shift) & (ESP_REGS - 1); + saddr = addr >> s->it_shift; DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); switch (saddr) { case ESP_FIFO: if (s->ti_size > 0) { s->ti_size--; if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { - /* Data in/out. */ - fprintf(stderr, "esp: PIO data read not implemented\n"); + /* Data out. */ + ESP_ERROR("PIO data read not implemented\n"); s->rregs[ESP_FIFO] = 0; } else { s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; @@ -441,10 +465,15 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) } break; case ESP_RINTR: - // Clear interrupt/error status bits - s->rregs[ESP_RSTAT] &= ~(STAT_GE | STAT_PE); + /* Clear sequence step, interrupt register and all status bits + except TC */ + old_val = s->rregs[ESP_RINTR]; + s->rregs[ESP_RINTR] = 0; + s->rregs[ESP_RSTAT] &= ~STAT_TC; + s->rregs[ESP_RSEQ] = SEQ_CD; esp_lower_irq(s); - break; + + return old_val; default: break; } @@ -456,7 +485,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) ESPState *s = opaque; uint32_t saddr; - saddr = (addr >> s->it_shift) & (ESP_REGS - 1); + saddr = addr >> s->it_shift; DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); switch (saddr) { @@ -467,11 +496,8 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) case ESP_FIFO: if (s->do_cmd) { s->cmdbuf[s->cmdlen++] = val & 0xff; - } else if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { - uint8_t buf; - buf = val & 0xff; - s->ti_size--; - fprintf(stderr, "esp: PIO data write not implemented\n"); + } else if (s->ti_size == TI_BUFSZ - 1) { + ESP_ERROR("fifo overrun\n"); } else { s->ti_size++; s->ti_buf[s->ti_wptr++] = val & 0xff; @@ -500,7 +526,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case CMD_RESET: DPRINTF("Chip reset (%2.2x)\n", val); - esp_reset(s); + esp_reset(&s->busdev.qdev); break; case CMD_BUSRESET: DPRINTF("Bus reset (%2.2x)\n", val); @@ -515,29 +541,43 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) case CMD_ICCS: DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); write_response(s); + s->rregs[ESP_RINTR] = INTR_FC; + s->rregs[ESP_RSTAT] |= STAT_MI; break; case CMD_MSGACC: DPRINTF("Message Accepted (%2.2x)\n", val); - write_response(s); s->rregs[ESP_RINTR] = INTR_DC; s->rregs[ESP_RSEQ] = 0; + s->rregs[ESP_RFLAGS] = 0; + esp_raise_irq(s); + break; + case CMD_PAD: + DPRINTF("Transfer padding (%2.2x)\n", val); + s->rregs[ESP_RSTAT] = STAT_TC; + s->rregs[ESP_RINTR] = INTR_FC; + s->rregs[ESP_RSEQ] = 0; break; case CMD_SATN: DPRINTF("Set ATN (%2.2x)\n", val); break; + case CMD_SEL: + DPRINTF("Select without ATN (%2.2x)\n", val); + handle_s_without_atn(s); + break; case CMD_SELATN: - DPRINTF("Set ATN (%2.2x)\n", val); + DPRINTF("Select with ATN (%2.2x)\n", val); handle_satn(s); break; case CMD_SELATNS: - DPRINTF("Set ATN & stop (%2.2x)\n", val); + DPRINTF("Select with ATN & stop (%2.2x)\n", val); handle_satn_stop(s); break; case CMD_ENSEL: DPRINTF("Enable selection (%2.2x)\n", val); + s->rregs[ESP_RINTR] = 0; break; default: - DPRINTF("Unhandled ESP command (%2.2x)\n", val); + ESP_ERROR("Unhandled ESP command (%2.2x)\n", val); break; } break; @@ -548,124 +588,104 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case ESP_WCCF ... ESP_WTEST: break; - case ESP_CFG2: - s->rregs[saddr] = val & CFG2_MASK; - break; - case ESP_CFG3 ... ESP_RES4: + case ESP_CFG2 ... ESP_RES4: s->rregs[saddr] = val; break; default: - break; + ESP_ERROR("invalid write of 0x%02x at [0x%x]\n", val, saddr); + return; } s->wregs[saddr] = val; } -static CPUReadMemoryFunc *esp_mem_read[3] = { +static CPUReadMemoryFunc * const esp_mem_read[3] = { esp_mem_readb, NULL, NULL, }; -static CPUWriteMemoryFunc *esp_mem_write[3] = { +static CPUWriteMemoryFunc * const esp_mem_write[3] = { esp_mem_writeb, NULL, - NULL, + esp_mem_writeb, }; -static void esp_save(QEMUFile *f, void *opaque) -{ - ESPState *s = opaque; - - qemu_put_buffer(f, s->rregs, ESP_REGS); - qemu_put_buffer(f, s->wregs, ESP_REGS); - qemu_put_be32s(f, (uint32_t *)&s->ti_size); - qemu_put_be32s(f, &s->ti_rptr); - qemu_put_be32s(f, &s->ti_wptr); - qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); - qemu_put_be32s(f, &s->sense); - qemu_put_be32s(f, &s->dma); - qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ); - qemu_put_be32s(f, &s->cmdlen); - qemu_put_be32s(f, &s->do_cmd); - qemu_put_be32s(f, &s->dma_left); - // There should be no transfers in progress, so dma_counter is not saved -} - -static int esp_load(QEMUFile *f, void *opaque, int version_id) -{ - ESPState *s = opaque; - - if (version_id != 3) - return -EINVAL; // Cannot emulate 2 - - qemu_get_buffer(f, s->rregs, ESP_REGS); - qemu_get_buffer(f, s->wregs, ESP_REGS); - qemu_get_be32s(f, (uint32_t *)&s->ti_size); - qemu_get_be32s(f, &s->ti_rptr); - qemu_get_be32s(f, &s->ti_wptr); - qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); - qemu_get_be32s(f, &s->sense); - qemu_get_be32s(f, &s->dma); - qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ); - qemu_get_be32s(f, &s->cmdlen); - qemu_get_be32s(f, &s->do_cmd); - qemu_get_be32s(f, &s->dma_left); - - return 0; -} +static const VMStateDescription vmstate_esp = { + .name ="esp", + .version_id = 3, + .minimum_version_id = 3, + .minimum_version_id_old = 3, + .fields = (VMStateField []) { + VMSTATE_BUFFER(rregs, ESPState), + VMSTATE_BUFFER(wregs, ESPState), + VMSTATE_INT32(ti_size, ESPState), + VMSTATE_UINT32(ti_rptr, ESPState), + VMSTATE_UINT32(ti_wptr, ESPState), + VMSTATE_BUFFER(ti_buf, ESPState), + VMSTATE_UINT32(sense, ESPState), + VMSTATE_UINT32(dma, ESPState), + VMSTATE_BUFFER(cmdbuf, ESPState), + VMSTATE_UINT32(cmdlen, ESPState), + VMSTATE_UINT32(do_cmd, ESPState), + VMSTATE_UINT32(dma_left, ESPState), + VMSTATE_END_OF_LIST() + } +}; -void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) +void esp_init(target_phys_addr_t espaddr, int it_shift, + espdma_memory_read_write dma_memory_read, + espdma_memory_read_write dma_memory_write, + void *dma_opaque, qemu_irq irq, qemu_irq *reset) { - ESPState *s = (ESPState *)opaque; - - if (id < 0) { - for (id = 0; id < ESP_MAX_DEVS; id++) { - if (s->scsi_dev[id] == NULL) - break; - } - } - if (id >= ESP_MAX_DEVS) { - DPRINTF("Bad Device ID %d\n", id); - return; - } - if (s->scsi_dev[id]) { - DPRINTF("Destroying device %d\n", id); - s->scsi_dev[id]->destroy(s->scsi_dev[id]); - } - DPRINTF("Attaching block device %d\n", id); - /* Command queueing is not implemented. */ - s->scsi_dev[id] = scsi_generic_init(bd, 0, esp_command_complete, s); - if (s->scsi_dev[id] == NULL) - s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s); + DeviceState *dev; + SysBusDevice *s; + ESPState *esp; + + dev = qdev_create(NULL, "esp"); + esp = DO_UPCAST(ESPState, busdev.qdev, dev); + esp->dma_memory_read = dma_memory_read; + esp->dma_memory_write = dma_memory_write; + esp->dma_opaque = dma_opaque; + esp->it_shift = it_shift; + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + sysbus_connect_irq(s, 0, irq); + sysbus_mmio_map(s, 0, espaddr); + *reset = qdev_get_gpio_in(dev, 0); } -void *esp_init(target_phys_addr_t espaddr, int it_shift, - espdma_memory_read_write dma_memory_read, - espdma_memory_read_write dma_memory_write, - void *dma_opaque, qemu_irq irq, qemu_irq *reset) +static int esp_init1(SysBusDevice *dev) { - ESPState *s; + ESPState *s = FROM_SYSBUS(ESPState, dev); int esp_io_memory; - s = qemu_mallocz(sizeof(ESPState)); - if (!s) - return NULL; - - s->irq = irq; - s->it_shift = it_shift; - s->dma_memory_read = dma_memory_read; - s->dma_memory_write = dma_memory_write; - s->dma_opaque = dma_opaque; + sysbus_init_irq(dev, &s->irq); + assert(s->it_shift != -1); - esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); - cpu_register_physical_memory(espaddr, ESP_REGS << it_shift, esp_io_memory); + esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s); + sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory); - esp_reset(s); + qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1); - register_savevm("esp", espaddr, 3, esp_save, esp_load, s); - qemu_register_reset(esp_reset, s); + scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete); + scsi_bus_legacy_handle_cmdline(&s->bus); + return 0; +} - *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1); +static SysBusDeviceInfo esp_info = { + .init = esp_init1, + .qdev.name = "esp", + .qdev.size = sizeof(ESPState), + .qdev.vmsd = &vmstate_esp, + .qdev.reset = esp_reset, + .qdev.props = (Property[]) { + {.name = NULL} + } +}; - return s; +static void esp_register_devices(void) +{ + sysbus_register_withprop(&esp_info); } + +device_init(esp_register_devices)