in esp_scsi.c [1689:2026]
static int esp_process_event(struct esp *esp)
{
int write, i;
again:
write = 0;
esp_log_event("process event %d phase %x\n",
esp->event, esp->sreg & ESP_STAT_PMASK);
switch (esp->event) {
case ESP_EVENT_CHECK_PHASE:
switch (esp->sreg & ESP_STAT_PMASK) {
case ESP_DOP:
esp_event(esp, ESP_EVENT_DATA_OUT);
break;
case ESP_DIP:
esp_event(esp, ESP_EVENT_DATA_IN);
break;
case ESP_STATP:
esp_flush_fifo(esp);
scsi_esp_cmd(esp, ESP_CMD_ICCSEQ);
esp_event(esp, ESP_EVENT_STATUS);
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
return 1;
case ESP_MOP:
esp_event(esp, ESP_EVENT_MSGOUT);
break;
case ESP_MIP:
esp_event(esp, ESP_EVENT_MSGIN);
break;
case ESP_CMDP:
esp_event(esp, ESP_EVENT_CMD_START);
break;
default:
shost_printk(KERN_INFO, esp->host,
"Unexpected phase, sreg=%02x\n",
esp->sreg);
esp_schedule_reset(esp);
return 0;
}
goto again;
case ESP_EVENT_DATA_IN:
write = 1;
fallthrough;
case ESP_EVENT_DATA_OUT: {
struct esp_cmd_entry *ent = esp->active_cmd;
struct scsi_cmnd *cmd = ent->cmd;
dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd);
unsigned int dma_len = esp_cur_dma_len(ent, cmd);
if (esp->rev == ESP100)
scsi_esp_cmd(esp, ESP_CMD_NULL);
if (write)
ent->flags |= ESP_CMD_FLAG_WRITE;
else
ent->flags &= ~ESP_CMD_FLAG_WRITE;
if (esp->ops->dma_length_limit)
dma_len = esp->ops->dma_length_limit(esp, dma_addr,
dma_len);
else
dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
esp->data_dma_len = dma_len;
if (!dma_len) {
shost_printk(KERN_ERR, esp->host,
"DMA length is zero!\n");
shost_printk(KERN_ERR, esp->host,
"cur adr[%08llx] len[%08x]\n",
(unsigned long long)esp_cur_dma_addr(ent, cmd),
esp_cur_dma_len(ent, cmd));
esp_schedule_reset(esp);
return 0;
}
esp_log_datastart("start data addr[%08llx] len[%u] write(%d)\n",
(unsigned long long)dma_addr, dma_len, write);
esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
write, ESP_CMD_DMA | ESP_CMD_TI);
esp_event(esp, ESP_EVENT_DATA_DONE);
break;
}
case ESP_EVENT_DATA_DONE: {
struct esp_cmd_entry *ent = esp->active_cmd;
struct scsi_cmnd *cmd = ent->cmd;
int bytes_sent;
if (esp->ops->dma_error(esp)) {
shost_printk(KERN_INFO, esp->host,
"data done, DMA error, resetting\n");
esp_schedule_reset(esp);
return 0;
}
if (ent->flags & ESP_CMD_FLAG_WRITE) {
/* XXX parity errors, etc. XXX */
esp->ops->dma_drain(esp);
}
esp->ops->dma_invalidate(esp);
if (esp->ireg != ESP_INTR_BSERV) {
/* We should always see exactly a bus-service
* interrupt at the end of a successful transfer.
*/
shost_printk(KERN_INFO, esp->host,
"data done, not BSERV, resetting\n");
esp_schedule_reset(esp);
return 0;
}
bytes_sent = esp_data_bytes_sent(esp, ent, cmd);
esp_log_datadone("data done flgs[%x] sent[%d]\n",
ent->flags, bytes_sent);
if (bytes_sent < 0) {
/* XXX force sync mode for this target XXX */
esp_schedule_reset(esp);
return 0;
}
esp_advance_dma(esp, ent, cmd, bytes_sent);
esp_event(esp, ESP_EVENT_CHECK_PHASE);
goto again;
}
case ESP_EVENT_STATUS: {
struct esp_cmd_entry *ent = esp->active_cmd;
if (esp->ireg & ESP_INTR_FDONE) {
ent->status = esp_read8(ESP_FDATA);
ent->message = esp_read8(ESP_FDATA);
scsi_esp_cmd(esp, ESP_CMD_MOK);
} else if (esp->ireg == ESP_INTR_BSERV) {
ent->status = esp_read8(ESP_FDATA);
ent->message = 0xff;
esp_event(esp, ESP_EVENT_MSGIN);
return 0;
}
if (ent->message != COMMAND_COMPLETE) {
shost_printk(KERN_INFO, esp->host,
"Unexpected message %x in status\n",
ent->message);
esp_schedule_reset(esp);
return 0;
}
esp_event(esp, ESP_EVENT_FREE_BUS);
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
break;
}
case ESP_EVENT_FREE_BUS: {
struct esp_cmd_entry *ent = esp->active_cmd;
struct scsi_cmnd *cmd = ent->cmd;
if (ent->message == COMMAND_COMPLETE ||
ent->message == DISCONNECT)
scsi_esp_cmd(esp, ESP_CMD_ESEL);
if (ent->message == COMMAND_COMPLETE) {
esp_log_cmddone("Command done status[%x] message[%x]\n",
ent->status, ent->message);
if (ent->status == SAM_STAT_TASK_SET_FULL)
esp_event_queue_full(esp, ent);
if (ent->status == SAM_STAT_CHECK_CONDITION &&
!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
ent->flags |= ESP_CMD_FLAG_AUTOSENSE;
esp_autosense(esp, ent);
} else {
esp_cmd_is_done(esp, ent, cmd, DID_OK);
}
} else if (ent->message == DISCONNECT) {
esp_log_disconnect("Disconnecting tgt[%d] tag[%x:%x]\n",
cmd->device->id,
ent->tag[0], ent->tag[1]);
esp->active_cmd = NULL;
esp_maybe_execute_command(esp);
} else {
shost_printk(KERN_INFO, esp->host,
"Unexpected message %x in freebus\n",
ent->message);
esp_schedule_reset(esp);
return 0;
}
if (esp->active_cmd)
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
break;
}
case ESP_EVENT_MSGOUT: {
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
if (esp_debug & ESP_DEBUG_MSGOUT) {
int i;
printk("ESP: Sending message [ ");
for (i = 0; i < esp->msg_out_len; i++)
printk("%02x ", esp->msg_out[i]);
printk("]\n");
}
if (esp->rev == FASHME) {
int i;
/* Always use the fifo. */
for (i = 0; i < esp->msg_out_len; i++) {
esp_write8(esp->msg_out[i], ESP_FDATA);
esp_write8(0, ESP_FDATA);
}
scsi_esp_cmd(esp, ESP_CMD_TI);
} else {
if (esp->msg_out_len == 1) {
esp_write8(esp->msg_out[0], ESP_FDATA);
scsi_esp_cmd(esp, ESP_CMD_TI);
} else if (esp->flags & ESP_FLAG_USE_FIFO) {
for (i = 0; i < esp->msg_out_len; i++)
esp_write8(esp->msg_out[i], ESP_FDATA);
scsi_esp_cmd(esp, ESP_CMD_TI);
} else {
/* Use DMA. */
memcpy(esp->command_block,
esp->msg_out,
esp->msg_out_len);
esp->ops->send_dma_cmd(esp,
esp->command_block_dma,
esp->msg_out_len,
esp->msg_out_len,
0,
ESP_CMD_DMA|ESP_CMD_TI);
}
}
esp_event(esp, ESP_EVENT_MSGOUT_DONE);
break;
}
case ESP_EVENT_MSGOUT_DONE:
if (esp->rev == FASHME) {
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
} else {
if (esp->msg_out_len > 1)
esp->ops->dma_invalidate(esp);
/* XXX if the chip went into disconnected mode,
* we can't run the phase state machine anyway.
*/
if (!(esp->ireg & ESP_INTR_DC))
scsi_esp_cmd(esp, ESP_CMD_NULL);
}
esp->msg_out_len = 0;
esp_event(esp, ESP_EVENT_CHECK_PHASE);
goto again;
case ESP_EVENT_MSGIN:
if (esp->ireg & ESP_INTR_BSERV) {
if (esp->rev == FASHME) {
if (!(esp_read8(ESP_STATUS2) &
ESP_STAT2_FEMPTY))
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
} else {
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
if (esp->rev == ESP100)
scsi_esp_cmd(esp, ESP_CMD_NULL);
}
scsi_esp_cmd(esp, ESP_CMD_TI);
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
return 1;
}
if (esp->ireg & ESP_INTR_FDONE) {
u8 val;
if (esp->rev == FASHME)
val = esp->fifo[0];
else
val = esp_read8(ESP_FDATA);
esp->msg_in[esp->msg_in_len++] = val;
esp_log_msgin("Got msgin byte %x\n", val);
if (!esp_msgin_process(esp))
esp->msg_in_len = 0;
if (esp->rev == FASHME)
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
scsi_esp_cmd(esp, ESP_CMD_MOK);
/* Check whether a bus reset is to be done next */
if (esp->event == ESP_EVENT_RESET)
return 0;
if (esp->event != ESP_EVENT_FREE_BUS)
esp_event(esp, ESP_EVENT_CHECK_PHASE);
} else {
shost_printk(KERN_INFO, esp->host,
"MSGIN neither BSERV not FDON, resetting");
esp_schedule_reset(esp);
return 0;
}
break;
case ESP_EVENT_CMD_START:
memcpy(esp->command_block, esp->cmd_bytes_ptr,
esp->cmd_bytes_left);
esp_send_dma_cmd(esp, esp->cmd_bytes_left, 16, ESP_CMD_TI);
esp_event(esp, ESP_EVENT_CMD_DONE);
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
break;
case ESP_EVENT_CMD_DONE:
esp->ops->dma_invalidate(esp);
if (esp->ireg & ESP_INTR_BSERV) {
esp_event(esp, ESP_EVENT_CHECK_PHASE);
goto again;
}
esp_schedule_reset(esp);
return 0;
case ESP_EVENT_RESET:
scsi_esp_cmd(esp, ESP_CMD_RS);
break;
default:
shost_printk(KERN_INFO, esp->host,
"Unexpected event %x, resetting\n", esp->event);
esp_schedule_reset(esp);
return 0;
}
return 1;
}