version 1.1.1.8, 2018/04/24 17:24:54
|
version 1.1.1.9, 2018/04/24 17:39:47
|
Line 23
|
Line 23
|
*/ |
*/ |
|
|
#include "sysbus.h" |
#include "sysbus.h" |
#include "scsi-disk.h" |
|
#include "scsi.h" |
#include "scsi.h" |
|
#include "esp.h" |
|
|
/* debug ESP card */ |
/* debug ESP card */ |
//#define DEBUG_ESP |
//#define DEBUG_ESP |
Line 63 struct ESPState {
|
Line 63 struct ESPState {
|
uint8_t ti_buf[TI_BUFSZ]; |
uint8_t ti_buf[TI_BUFSZ]; |
uint32_t sense; |
uint32_t sense; |
uint32_t dma; |
uint32_t dma; |
SCSIDevice *scsi_dev[ESP_MAX_DEVS]; |
SCSIBus bus; |
SCSIDevice *current_dev; |
SCSIDevice *current_dev; |
uint8_t cmdbuf[TI_BUFSZ]; |
uint8_t cmdbuf[TI_BUFSZ]; |
uint32_t cmdlen; |
uint32_t cmdlen; |
Line 115 struct ESPState {
|
Line 115 struct ESPState {
|
#define CMD_TI 0x10 |
#define CMD_TI 0x10 |
#define CMD_ICCS 0x11 |
#define CMD_ICCS 0x11 |
#define CMD_MSGACC 0x12 |
#define CMD_MSGACC 0x12 |
|
#define CMD_PAD 0x18 |
#define CMD_SATN 0x1a |
#define CMD_SATN 0x1a |
|
#define CMD_SEL 0x41 |
#define CMD_SELATN 0x42 |
#define CMD_SELATN 0x42 |
#define CMD_SELATNS 0x43 |
#define CMD_SELATNS 0x43 |
#define CMD_ENSEL 0x44 |
#define CMD_ENSEL 0x44 |
Line 185 static uint32_t get_cmd(ESPState *s, uin
|
Line 187 static uint32_t get_cmd(ESPState *s, uin
|
|
|
if (s->current_dev) { |
if (s->current_dev) { |
/* Started a new command before the old one finished. Cancel it. */ |
/* 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; |
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 |
// No such drive |
s->rregs[ESP_RSTAT] = 0; |
s->rregs[ESP_RSTAT] = 0; |
s->rregs[ESP_RINTR] = INTR_DC; |
s->rregs[ESP_RINTR] = INTR_DC; |
Line 197 static uint32_t get_cmd(ESPState *s, uin
|
Line 199 static uint32_t get_cmd(ESPState *s, uin
|
esp_raise_irq(s); |
esp_raise_irq(s); |
return 0; |
return 0; |
} |
} |
s->current_dev = s->scsi_dev[target]; |
s->current_dev = s->bus.devs[target]; |
return dmalen; |
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; |
int32_t datalen; |
int lun; |
int lun; |
|
|
DPRINTF("do_cmd: busid 0x%x\n", buf[0]); |
DPRINTF("do_busid_cmd: busid 0x%x\n", busid); |
lun = buf[0] & 7; |
lun = busid & 7; |
datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun); |
datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun); |
s->ti_size = datalen; |
s->ti_size = datalen; |
if (datalen != 0) { |
if (datalen != 0) { |
s->rregs[ESP_RSTAT] = STAT_TC; |
s->rregs[ESP_RSTAT] = STAT_TC; |
Line 216 static void do_cmd(ESPState *s, uint8_t
|
Line 218 static void do_cmd(ESPState *s, uint8_t
|
s->dma_counter = 0; |
s->dma_counter = 0; |
if (datalen > 0) { |
if (datalen > 0) { |
s->rregs[ESP_RSTAT] |= STAT_DI; |
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 { |
} else { |
s->rregs[ESP_RSTAT] |= STAT_DO; |
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; |
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; |
Line 227 static void do_cmd(ESPState *s, uint8_t
|
Line 229 static void do_cmd(ESPState *s, uint8_t
|
esp_raise_irq(s); |
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) |
static void handle_satn(ESPState *s) |
{ |
{ |
uint8_t buf[32]; |
uint8_t buf[32]; |
Line 237 static void handle_satn(ESPState *s)
|
Line 246 static void handle_satn(ESPState *s)
|
do_cmd(s, buf); |
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) |
static void handle_satn_stop(ESPState *s) |
{ |
{ |
s->cmdlen = get_cmd(s, s->cmdbuf); |
s->cmdlen = get_cmd(s, s->cmdbuf); |
Line 318 static void esp_do_dma(ESPState *s)
|
Line 338 static void esp_do_dma(ESPState *s)
|
if (s->async_len == 0) { |
if (s->async_len == 0) { |
if (to_device) { |
if (to_device) { |
// ti_size is negative |
// ti_size is negative |
s->current_dev->write_data(s->current_dev, 0); |
s->current_dev->info->write_data(s->current_dev, 0); |
} else { |
} 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 |
/* If there is still data to be read from the device then |
complete the DMA operation immediately. Otherwise defer |
complete the DMA operation immediately. Otherwise defer |
until the scsi layer has completed. */ |
until the scsi layer has completed. */ |
Line 334 static void esp_do_dma(ESPState *s)
|
Line 354 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) |
uint32_t arg) |
{ |
{ |
ESPState *s = (ESPState *)opaque; |
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent); |
|
|
if (reason == SCSI_REASON_DONE) { |
if (reason == SCSI_REASON_DONE) { |
DPRINTF("SCSI Command complete\n"); |
DPRINTF("SCSI Command complete\n"); |
Line 355 static void esp_command_complete(void *o
|
Line 375 static void esp_command_complete(void *o
|
} else { |
} else { |
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
s->async_len = arg; |
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) { |
if (s->dma_left) { |
esp_do_dma(s); |
esp_do_dma(s); |
} else if (s->dma_counter != 0 && s->ti_size <= 0) { |
} else if (s->dma_counter != 0 && s->ti_size <= 0) { |
Line 397 static void handle_ti(ESPState *s)
|
Line 417 static void handle_ti(ESPState *s)
|
} |
} |
} |
} |
|
|
static void esp_reset(void *opaque) |
static void esp_reset(DeviceState *d) |
{ |
{ |
ESPState *s = opaque; |
ESPState *s = container_of(d, ESPState, busdev.qdev); |
|
|
memset(s->rregs, 0, ESP_REGS); |
memset(s->rregs, 0, ESP_REGS); |
memset(s->wregs, 0, ESP_REGS); |
memset(s->wregs, 0, ESP_REGS); |
Line 506 static void esp_mem_writeb(void *opaque,
|
Line 526 static void esp_mem_writeb(void *opaque,
|
break; |
break; |
case CMD_RESET: |
case CMD_RESET: |
DPRINTF("Chip reset (%2.2x)\n", val); |
DPRINTF("Chip reset (%2.2x)\n", val); |
esp_reset(s); |
esp_reset(&s->busdev.qdev); |
break; |
break; |
case CMD_BUSRESET: |
case CMD_BUSRESET: |
DPRINTF("Bus reset (%2.2x)\n", val); |
DPRINTF("Bus reset (%2.2x)\n", val); |
Line 526 static void esp_mem_writeb(void *opaque,
|
Line 546 static void esp_mem_writeb(void *opaque,
|
break; |
break; |
case CMD_MSGACC: |
case CMD_MSGACC: |
DPRINTF("Message Accepted (%2.2x)\n", val); |
DPRINTF("Message Accepted (%2.2x)\n", val); |
write_response(s); |
|
s->rregs[ESP_RINTR] = INTR_DC; |
s->rregs[ESP_RINTR] = INTR_DC; |
s->rregs[ESP_RSEQ] = 0; |
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; |
break; |
case CMD_SATN: |
case CMD_SATN: |
DPRINTF("Set ATN (%2.2x)\n", val); |
DPRINTF("Set ATN (%2.2x)\n", val); |
break; |
break; |
|
case CMD_SEL: |
|
DPRINTF("Select without ATN (%2.2x)\n", val); |
|
handle_s_without_atn(s); |
|
break; |
case CMD_SELATN: |
case CMD_SELATN: |
DPRINTF("Set ATN (%2.2x)\n", val); |
DPRINTF("Select with ATN (%2.2x)\n", val); |
handle_satn(s); |
handle_satn(s); |
break; |
break; |
case CMD_SELATNS: |
case CMD_SELATNS: |
DPRINTF("Set ATN & stop (%2.2x)\n", val); |
DPRINTF("Select with ATN & stop (%2.2x)\n", val); |
handle_satn_stop(s); |
handle_satn_stop(s); |
break; |
break; |
case CMD_ENSEL: |
case CMD_ENSEL: |
Line 567 static void esp_mem_writeb(void *opaque,
|
Line 598 static void esp_mem_writeb(void *opaque,
|
s->wregs[saddr] = val; |
s->wregs[saddr] = val; |
} |
} |
|
|
static CPUReadMemoryFunc *esp_mem_read[3] = { |
static CPUReadMemoryFunc * const esp_mem_read[3] = { |
esp_mem_readb, |
esp_mem_readb, |
NULL, |
NULL, |
NULL, |
NULL, |
}; |
}; |
|
|
static CPUWriteMemoryFunc *esp_mem_write[3] = { |
static CPUWriteMemoryFunc * const esp_mem_write[3] = { |
esp_mem_writeb, |
esp_mem_writeb, |
NULL, |
NULL, |
esp_mem_writeb, |
esp_mem_writeb, |
}; |
}; |
|
|
static void esp_save(QEMUFile *f, void *opaque) |
static const VMStateDescription vmstate_esp = { |
{ |
.name ="esp", |
ESPState *s = opaque; |
.version_id = 3, |
|
.minimum_version_id = 3, |
qemu_put_buffer(f, s->rregs, ESP_REGS); |
.minimum_version_id_old = 3, |
qemu_put_buffer(f, s->wregs, ESP_REGS); |
.fields = (VMStateField []) { |
qemu_put_sbe32s(f, &s->ti_size); |
VMSTATE_BUFFER(rregs, ESPState), |
qemu_put_be32s(f, &s->ti_rptr); |
VMSTATE_BUFFER(wregs, ESPState), |
qemu_put_be32s(f, &s->ti_wptr); |
VMSTATE_INT32(ti_size, ESPState), |
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); |
VMSTATE_UINT32(ti_rptr, ESPState), |
qemu_put_be32s(f, &s->sense); |
VMSTATE_UINT32(ti_wptr, ESPState), |
qemu_put_be32s(f, &s->dma); |
VMSTATE_BUFFER(ti_buf, ESPState), |
qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ); |
VMSTATE_UINT32(sense, ESPState), |
qemu_put_be32s(f, &s->cmdlen); |
VMSTATE_UINT32(dma, ESPState), |
qemu_put_be32s(f, &s->do_cmd); |
VMSTATE_BUFFER(cmdbuf, ESPState), |
qemu_put_be32s(f, &s->dma_left); |
VMSTATE_UINT32(cmdlen, ESPState), |
// There should be no transfers in progress, so dma_counter is not saved |
VMSTATE_UINT32(do_cmd, ESPState), |
} |
VMSTATE_UINT32(dma_left, ESPState), |
|
VMSTATE_END_OF_LIST() |
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_sbe32s(f, &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 void esp_scsi_attach(DeviceState *host, BlockDriverState *bd, int id) |
|
{ |
|
ESPState *s = FROM_SYSBUS(ESPState, sysbus_from_qdev(host)); |
|
|
|
if (id < 0) { |
|
for (id = 0; id < ESP_MAX_DEVS; id++) { |
|
if (id == (s->rregs[ESP_CFG1] & 0x7)) |
|
continue; |
|
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); |
|
} |
|
|
|
void esp_init(target_phys_addr_t espaddr, int it_shift, |
void esp_init(target_phys_addr_t espaddr, int it_shift, |
espdma_memory_read_write dma_memory_read, |
espdma_memory_read_write dma_memory_read, |
Line 663 void esp_init(target_phys_addr_t espaddr
|
Line 647 void esp_init(target_phys_addr_t espaddr
|
esp->dma_memory_write = dma_memory_write; |
esp->dma_memory_write = dma_memory_write; |
esp->dma_opaque = dma_opaque; |
esp->dma_opaque = dma_opaque; |
esp->it_shift = it_shift; |
esp->it_shift = it_shift; |
qdev_init(dev); |
qdev_init_nofail(dev); |
s = sysbus_from_qdev(dev); |
s = sysbus_from_qdev(dev); |
sysbus_connect_irq(s, 0, irq); |
sysbus_connect_irq(s, 0, irq); |
sysbus_mmio_map(s, 0, espaddr); |
sysbus_mmio_map(s, 0, espaddr); |
|
*reset = qdev_get_gpio_in(dev, 0); |
} |
} |
|
|
static void esp_init1(SysBusDevice *dev) |
static int esp_init1(SysBusDevice *dev) |
{ |
{ |
ESPState *s = FROM_SYSBUS(ESPState, dev); |
ESPState *s = FROM_SYSBUS(ESPState, dev); |
int esp_io_memory; |
int esp_io_memory; |
Line 680 static void esp_init1(SysBusDevice *dev)
|
Line 665 static void esp_init1(SysBusDevice *dev)
|
esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s); |
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); |
sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory); |
|
|
esp_reset(s); |
|
|
|
register_savevm("esp", -1, 3, esp_save, esp_load, s); |
|
qemu_register_reset(esp_reset, s); |
|
|
|
qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1); |
qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1); |
|
|
scsi_bus_new(&dev->qdev, esp_scsi_attach); |
scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete); |
|
scsi_bus_legacy_handle_cmdline(&s->bus); |
|
return 0; |
} |
} |
|
|
|
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} |
|
} |
|
}; |
|
|
static void esp_register_devices(void) |
static void esp_register_devices(void) |
{ |
{ |
sysbus_register_dev("esp", sizeof(ESPState), esp_init1); |
sysbus_register_withprop(&esp_info); |
} |
} |
|
|
device_init(esp_register_devices) |
device_init(esp_register_devices) |