version 1.1.1.11, 2018/04/24 18:39:39
|
version 1.1.1.12, 2018/04/24 19:01:38
|
Line 61 struct ESPState {
|
Line 61 struct ESPState {
|
int32_t ti_size; |
int32_t ti_size; |
uint32_t ti_rptr, ti_wptr; |
uint32_t ti_rptr, ti_wptr; |
uint8_t ti_buf[TI_BUFSZ]; |
uint8_t ti_buf[TI_BUFSZ]; |
uint32_t sense; |
uint32_t status; |
uint32_t dma; |
uint32_t dma; |
SCSIBus bus; |
SCSIBus bus; |
SCSIDevice *current_dev; |
SCSIDevice *current_dev; |
|
SCSIRequest *current_req; |
uint8_t cmdbuf[TI_BUFSZ]; |
uint8_t cmdbuf[TI_BUFSZ]; |
uint32_t cmdlen; |
uint32_t cmdlen; |
uint32_t do_cmd; |
uint32_t do_cmd; |
Line 187 static void esp_dma_enable(void *opaque,
|
Line 188 static void esp_dma_enable(void *opaque,
|
} |
} |
} |
} |
|
|
|
static void esp_request_cancelled(SCSIRequest *req) |
|
{ |
|
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); |
|
|
|
if (req == s->current_req) { |
|
scsi_req_unref(s->current_req); |
|
s->current_req = NULL; |
|
s->current_dev = NULL; |
|
} |
|
} |
|
|
static uint32_t get_cmd(ESPState *s, uint8_t *buf) |
static uint32_t get_cmd(ESPState *s, uint8_t *buf) |
{ |
{ |
uint32_t dmalen; |
uint32_t dmalen; |
Line 199 static uint32_t get_cmd(ESPState *s, uin
|
Line 211 static uint32_t get_cmd(ESPState *s, uin
|
} else { |
} else { |
dmalen = s->ti_size; |
dmalen = s->ti_size; |
memcpy(buf, s->ti_buf, dmalen); |
memcpy(buf, s->ti_buf, dmalen); |
buf[0] = 0; |
buf[0] = buf[2] >> 5; |
} |
} |
DPRINTF("get_cmd: len %d target %d\n", dmalen, target); |
DPRINTF("get_cmd: len %d target %d\n", dmalen, target); |
|
|
Line 207 static uint32_t get_cmd(ESPState *s, uin
|
Line 219 static uint32_t get_cmd(ESPState *s, uin
|
s->ti_rptr = 0; |
s->ti_rptr = 0; |
s->ti_wptr = 0; |
s->ti_wptr = 0; |
|
|
if (s->current_dev) { |
if (s->current_req) { |
/* 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->info->cancel_io(s->current_dev, 0); |
scsi_req_cancel(s->current_req); |
s->async_len = 0; |
s->async_len = 0; |
} |
} |
|
|
Line 232 static void do_busid_cmd(ESPState *s, ui
|
Line 244 static void do_busid_cmd(ESPState *s, ui
|
|
|
DPRINTF("do_busid_cmd: busid 0x%x\n", busid); |
DPRINTF("do_busid_cmd: busid 0x%x\n", busid); |
lun = busid & 7; |
lun = busid & 7; |
datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun); |
s->current_req = scsi_req_new(s->current_dev, 0, lun, NULL); |
|
datalen = scsi_req_enqueue(s->current_req, buf); |
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 240 static void do_busid_cmd(ESPState *s, ui
|
Line 253 static void do_busid_cmd(ESPState *s, ui
|
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->info->read_data(s->current_dev, 0); |
|
} else { |
} else { |
s->rregs[ESP_RSTAT] |= STAT_DO; |
s->rregs[ESP_RSTAT] |= STAT_DO; |
s->current_dev->info->write_data(s->current_dev, 0); |
|
} |
} |
|
scsi_req_continue(s->current_req); |
} |
} |
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; |
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; |
s->rregs[ESP_RSEQ] = SEQ_CD; |
s->rregs[ESP_RSEQ] = SEQ_CD; |
Line 306 static void handle_satn_stop(ESPState *s
|
Line 318 static void handle_satn_stop(ESPState *s
|
|
|
static void write_response(ESPState *s) |
static void write_response(ESPState *s) |
{ |
{ |
DPRINTF("Transfer status (sense=%d)\n", s->sense); |
DPRINTF("Transfer status (status=%d)\n", s->status); |
s->ti_buf[0] = s->sense; |
s->ti_buf[0] = s->status; |
s->ti_buf[1] = 0; |
s->ti_buf[1] = 0; |
if (s->dma) { |
if (s->dma) { |
s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); |
s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); |
Line 370 static void esp_do_dma(ESPState *s)
|
Line 382 static void esp_do_dma(ESPState *s)
|
else |
else |
s->ti_size -= len; |
s->ti_size -= len; |
if (s->async_len == 0) { |
if (s->async_len == 0) { |
if (to_device) { |
scsi_req_continue(s->current_req); |
// ti_size is negative |
/* If there is still data to be read from the device then |
s->current_dev->info->write_data(s->current_dev, 0); |
complete the DMA operation immediately. Otherwise defer |
} else { |
until the scsi layer has completed. */ |
s->current_dev->info->read_data(s->current_dev, 0); |
if (to_device || s->dma_left != 0 || s->ti_size == 0) { |
/* If there is still data to be read from the device then |
return; |
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); |
|
} |
|
} |
} |
} else { |
|
/* Partially filled a scsi buffer. Complete immediately. */ |
|
esp_dma_done(s); |
|
} |
} |
|
|
|
/* Partially filled a scsi buffer. Complete immediately. */ |
|
esp_dma_done(s); |
} |
} |
|
|
static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, |
static void esp_command_complete(SCSIRequest *req, uint32_t status) |
uint32_t arg) |
|
{ |
{ |
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent); |
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); |
|
|
if (reason == SCSI_REASON_DONE) { |
DPRINTF("SCSI Command complete\n"); |
DPRINTF("SCSI Command complete\n"); |
if (s->ti_size != 0) { |
if (s->ti_size != 0) |
DPRINTF("SCSI command completed unexpectedly\n"); |
DPRINTF("SCSI command completed unexpectedly\n"); |
} |
s->ti_size = 0; |
s->ti_size = 0; |
s->dma_left = 0; |
s->dma_left = 0; |
s->async_len = 0; |
s->async_len = 0; |
if (arg) |
if (status) { |
DPRINTF("Command failed\n"); |
DPRINTF("Command failed\n"); |
s->sense = arg; |
} |
s->rregs[ESP_RSTAT] = STAT_ST; |
s->status = status; |
esp_dma_done(s); |
s->rregs[ESP_RSTAT] = STAT_ST; |
|
esp_dma_done(s); |
|
if (s->current_req) { |
|
scsi_req_unref(s->current_req); |
|
s->current_req = NULL; |
s->current_dev = NULL; |
s->current_dev = NULL; |
} else { |
} |
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
} |
s->async_len = arg; |
|
s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0); |
static void esp_transfer_data(SCSIRequest *req, uint32_t len) |
if (s->dma_left) { |
{ |
esp_do_dma(s); |
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); |
} else if (s->dma_counter != 0 && s->ti_size <= 0) { |
|
/* If this was the last part of a DMA transfer then the |
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); |
completion interrupt is deferred to here. */ |
s->async_len = len; |
esp_dma_done(s); |
s->async_buf = scsi_req_get_buf(req); |
} |
if (s->dma_left) { |
|
esp_do_dma(s); |
|
} else if (s->dma_counter != 0 && s->ti_size <= 0) { |
|
/* If this was the last part of a DMA transfer then the |
|
completion interrupt is deferred to here. */ |
|
esp_dma_done(s); |
} |
} |
} |
} |
|
|
Line 678 static const VMStateDescription vmstate_
|
Line 693 static const VMStateDescription vmstate_
|
VMSTATE_UINT32(ti_rptr, ESPState), |
VMSTATE_UINT32(ti_rptr, ESPState), |
VMSTATE_UINT32(ti_wptr, ESPState), |
VMSTATE_UINT32(ti_wptr, ESPState), |
VMSTATE_BUFFER(ti_buf, ESPState), |
VMSTATE_BUFFER(ti_buf, ESPState), |
VMSTATE_UINT32(sense, ESPState), |
VMSTATE_UINT32(status, ESPState), |
VMSTATE_UINT32(dma, ESPState), |
VMSTATE_UINT32(dma, ESPState), |
VMSTATE_BUFFER(cmdbuf, ESPState), |
VMSTATE_BUFFER(cmdbuf, ESPState), |
VMSTATE_UINT32(cmdlen, ESPState), |
VMSTATE_UINT32(cmdlen, ESPState), |
Line 714 void esp_init(target_phys_addr_t espaddr
|
Line 729 void esp_init(target_phys_addr_t espaddr
|
*dma_enable = qdev_get_gpio_in(dev, 1); |
*dma_enable = qdev_get_gpio_in(dev, 1); |
} |
} |
|
|
|
static const struct SCSIBusOps esp_scsi_ops = { |
|
.transfer_data = esp_transfer_data, |
|
.complete = esp_command_complete, |
|
.cancel = esp_request_cancelled |
|
}; |
|
|
static int esp_init1(SysBusDevice *dev) |
static int esp_init1(SysBusDevice *dev) |
{ |
{ |
ESPState *s = FROM_SYSBUS(ESPState, dev); |
ESPState *s = FROM_SYSBUS(ESPState, dev); |
Line 728 static int esp_init1(SysBusDevice *dev)
|
Line 749 static int esp_init1(SysBusDevice *dev)
|
|
|
qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2); |
qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2); |
|
|
scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete); |
scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops); |
return scsi_bus_legacy_handle_cmdline(&s->bus); |
return scsi_bus_legacy_handle_cmdline(&s->bus); |
} |
} |
|
|