📄 mesh.c
字号:
static int mesh_phasemm_seqerr; mesh_phasemm_seqerr++; phase_mismatch(ms); return; } printk(KERN_ERR "mesh: sequence error (err=%x exc=%x)\n", err, exc); } else { printk(KERN_ERR "mesh: unknown error %x (exc=%x)\n", err, exc); } mesh_dump_regs(ms); dumplog(ms, ms->conn_tgt); if (ms->phase > selecting && (mr->bus_status1 & BS1_BSY)) { /* try to do what the target wants */ do_abort(ms); phase_mismatch(ms); return; } ms->stat = DID_ERROR; mesh_done(ms, 1);}static void handle_exception(struct mesh_state *ms){ int exc; volatile struct mesh_regs *mr = ms->mesh; exc = in_8(&mr->exception); out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE); if (exc & EXC_RESELECTED) { static int mesh_resel_exc; mesh_resel_exc++; reselected(ms); } else if (exc == EXC_ARBLOST) { printk(KERN_DEBUG "mesh: lost arbitration\n"); ms->stat = DID_BUS_BUSY; mesh_done(ms, 1); } else if (exc == EXC_SELTO) { /* selection timed out */ ms->stat = DID_BAD_TARGET; mesh_done(ms, 1); } else if (exc == EXC_PHASEMM) { /* target wants to do something different: find out what it wants and do it. */ phase_mismatch(ms); } else { printk(KERN_ERR "mesh: can't cope with exception %x\n", exc); mesh_dump_regs(ms); dumplog(ms, ms->conn_tgt); do_abort(ms); phase_mismatch(ms); }}static voidmesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs){ struct mesh_state *ms = (struct mesh_state *) dev_id; volatile struct mesh_regs *mr = ms->mesh; int intr;#if 0 if (ALLOW_DEBUG(ms->conn_tgt)) printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x " "phase=%d msgphase=%d\n", mr->bus_status0, mr->interrupt, mr->exception, mr->error, ms->phase, ms->msgphase);#endif while ((intr = in_8(&mr->interrupt)) != 0) { dlog(ms, "interrupt intr/err/exc/seq=%.8x", MKWORD(intr, mr->error, mr->exception, mr->sequence)); if (intr & INT_ERROR) { handle_error(ms); } else if (intr & INT_EXCEPTION) { handle_exception(ms); } else if (intr & INT_CMDDONE) { out_8(&mr->interrupt, INT_CMDDONE); cmd_complete(ms); } }}static voidhandle_msgin(struct mesh_state *ms){ int i, code; Scsi_Cmnd *cmd = ms->current_req; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; if (ms->n_msgin == 0) return; code = ms->msgin[0]; if (ALLOW_DEBUG(ms->conn_tgt)) { printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin); for (i = 0; i < ms->n_msgin; ++i) printk(" %x", ms->msgin[i]); printk("\n"); } dlog(ms, "msgin msg=%.8x", MKWORD(ms->n_msgin, code, ms->msgin[1], ms->msgin[2])); ms->expect_reply = 0; ms->n_msgout = 0; if (ms->n_msgin < msgin_length(ms)) goto reject; if (cmd) cmd->SCp.Message = code; switch (code) { case COMMAND_COMPLETE: break; case EXTENDED_MESSAGE: switch (ms->msgin[2]) { case EXTENDED_MODIFY_DATA_POINTER: ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6] + (ms->msgin[4] << 16) + (ms->msgin[5] << 8); break; case EXTENDED_SDTR: if (tp->sdtr_state != sdtr_sent) { /* reply with an SDTR */ add_sdtr_msg(ms); /* limit period to at least his value, offset to no more than his */ if (ms->msgout[3] < ms->msgin[3]) ms->msgout[3] = ms->msgin[3]; if (ms->msgout[4] > ms->msgin[4]) ms->msgout[4] = ms->msgin[4]; set_sdtr(ms, ms->msgout[3], ms->msgout[4]); ms->msgphase = msg_out; } else { set_sdtr(ms, ms->msgin[3], ms->msgin[4]); } break; default: goto reject; } break; case SAVE_POINTERS: tp->saved_ptr = ms->data_ptr; break; case RESTORE_POINTERS: ms->data_ptr = tp->saved_ptr; break; case DISCONNECT: ms->phase = disconnecting; break; case ABORT: break; case MESSAGE_REJECT: if (tp->sdtr_state == sdtr_sent) set_sdtr(ms, 0, 0); break; case NOP: break; default: if (IDENTIFY_BASE <= code && code <= IDENTIFY_BASE + 7) { if (cmd == NULL) { do_abort(ms); ms->msgphase = msg_out; } else if (code != cmd->lun + IDENTIFY_BASE) { printk(KERN_WARNING "mesh: lun mismatch " "(%d != %d) on reselection from " "target %d\n", i, cmd->lun, ms->conn_tgt); } break; } goto reject; } return; reject: printk(KERN_WARNING "mesh: rejecting message from target %d:", ms->conn_tgt); for (i = 0; i < ms->n_msgin; ++i) printk(" %x", ms->msgin[i]); printk("\n"); ms->msgout[0] = MESSAGE_REJECT; ms->n_msgout = 1; ms->msgphase = msg_out;}static voidmesh_done(struct mesh_state *ms, int start_next){ Scsi_Cmnd *cmd; struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; cmd = ms->current_req; ms->current_req = 0; tp->current_req = 0; if (cmd) { cmd->result = (ms->stat << 16) + cmd->SCp.Status; if (ms->stat == DID_OK) cmd->result += (cmd->SCp.Message << 8); if (DEBUG_TARGET(cmd)) { printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n", cmd->result, ms->data_ptr, cmd->request_bufflen); if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3) && cmd->request_buffer != 0) { unsigned char *b = cmd->request_buffer; printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); } } cmd->SCp.this_residual -= ms->data_ptr; mesh_completed(ms, cmd); } if (start_next) { out_8(&ms->mesh->sequence, SEQ_ENBRESEL); udelay(1); ms->phase = idle; mesh_start(ms); }}static voidmesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd){#ifdef MESH_NEW_STYLE_EH (*cmd->scsi_done)(cmd);#else if (ms->completed_q == NULL) ms->completed_q = cmd; else ms->completed_qtail->host_scribble = (void *) cmd; ms->completed_qtail = cmd; cmd->host_scribble = NULL; queue_task(&ms->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH);#endif /* MESH_NEW_STYLE_EH */}/* * Set up DMA commands for transferring data. */static voidset_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd){ int i, dma_cmd, total, off, dtot; struct scatterlist *scl; struct dbdma_cmd *dcmds; dma_cmd = ms->tgts[ms->conn_tgt].data_goes_out? OUTPUT_MORE: INPUT_MORE; dcmds = ms->dma_cmds; dtot = 0; if (cmd) { cmd->SCp.this_residual = cmd->request_bufflen; if (cmd->use_sg > 0) { total = 0; scl = (struct scatterlist *) cmd->buffer; off = ms->data_ptr; for (i = 0; i < cmd->use_sg; ++i, ++scl) { total += scl->length; if (off >= scl->length) { off -= scl->length; continue; } if (scl->length > 0xffff) panic("mesh: scatterlist element >= 64k"); st_le16(&dcmds->req_count, scl->length - off); st_le16(&dcmds->command, dma_cmd); st_le32(&dcmds->phy_addr, virt_to_phys(scl->address) + off); dcmds->xfer_status = 0; ++dcmds; dtot += scl->length - off; off = 0; } } else if (ms->data_ptr < cmd->request_bufflen) { dtot = cmd->request_bufflen - ms->data_ptr; if (dtot > 0xffff) panic("mesh: transfer size >= 64k"); st_le16(&dcmds->req_count, dtot); st_le32(&dcmds->phy_addr, virt_to_phys(cmd->request_buffer) + ms->data_ptr); dcmds->xfer_status = 0; ++dcmds; } } if (dtot == 0) { /* Either the target has overrun our buffer, or the caller didn't provide a buffer. */ static char mesh_extra_buf[64]; dtot = sizeof(mesh_extra_buf); st_le16(&dcmds->req_count, dtot); st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf)); dcmds->xfer_status = 0; ++dcmds; } dma_cmd += OUTPUT_LAST - OUTPUT_MORE; st_le16(&dcmds[-1].command, dma_cmd); memset(dcmds, 0, sizeof(*dcmds)); st_le16(&dcmds->command, DBDMA_STOP); ms->dma_count = dtot;}static voidhalt_dma(struct mesh_state *ms){ volatile struct dbdma_regs *md = ms->dma; volatile struct mesh_regs *mr = ms->mesh; Scsi_Cmnd *cmd = ms->current_req; int t, nb; if (!ms->tgts[ms->conn_tgt].data_goes_out) { /* wait a little while until the fifo drains */ t = 50; while (t > 0 && mr->fifo_count != 0 && (in_le32(&md->status) & ACTIVE) != 0) { --t; udelay(1); } } out_le32(&md->control, RUN << 16); /* turn off RUN bit */ nb = (mr->count_hi << 8) + mr->count_lo; dlog(ms, "halt_dma fc/count=%.6x", MKWORD(0, mr->fifo_count, 0, nb)); if (ms->tgts[ms->conn_tgt].data_goes_out) nb += mr->fifo_count; /* nb is the number of bytes not yet transferred to/from the target. */ ms->data_ptr -= nb; dlog(ms, "data_ptr %x", ms->data_ptr); if (ms->data_ptr < 0) { printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n", ms->data_ptr, nb, ms); ms->data_ptr = 0;#ifdef MESH_DBG dumplog(ms, ms->conn_tgt); dumpslog(ms);#endif /* MESH_DBG */ } else if (cmd && cmd->request_bufflen != 0 && ms->data_ptr > cmd->request_bufflen) { printk(KERN_DEBUG "mesh: target %d overrun, " "data_ptr=%x total=%x goes_out=%d\n", ms->conn_tgt, ms->data_ptr, cmd->request_bufflen, ms->tgts[ms->conn_tgt].data_goes_out); } ms->dma_started = 0;}/* * Work out whether we expect data to go out from the host adaptor or into it. * (If this information is available from somewhere else in the scsi * code, somebody please let me know :-) */static intdata_goes_out(Scsi_Cmnd *cmd){ switch (cmd->cmnd[0]) { case CHANGE_DEFINITION: case COMPARE: case COPY: case COPY_VERIFY: case FORMAT_UNIT: case LOG_SELECT: case MEDIUM_SCAN: case MODE_SELECT: case MODE_SELECT_10: case REASSIGN_BLOCKS: case RESERVE: case SEARCH_EQUAL: case SEARCH_EQUAL_12: case SEARCH_HIGH: case SEARCH_HIGH_12: case SEARCH_LOW: case SEARCH_LOW_12: case SEND_DIAGNOSTIC: case SEND_VOLUME_TAG: case SET_WINDOW: case UPDATE_BLOCK: case WRITE_BUFFER: case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_LONG: case WRITE_LONG_2: /* alternate code for WRITE_LONG */ case WRITE_SAME: case WRITE_VERIFY: case WRITE_VERIFY_12: return 1; default: return 0; }}#ifdef MESH_DBGstatic inline u32 readtb(void){ u32 tb;#ifdef DBG_USE_TB /* Beware: if you enable this, it will crash on 601s. */ asm ("mftb %0" : "=r" (tb) : );#else tb = 0;#endif return tb;}static void dlog(struct mesh_state *ms, char *fmt, int a){ struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; struct dbglog *tlp, *slp; tlp = &tp->log[tp->log_ix]; slp = &ms->log[ms->log_ix]; tlp->fmt = fmt; tlp->tb = readtb(); tlp->phase = (ms->msgphase << 4) + ms->phase; tlp->bs0 = ms->mesh->bus_status0; tlp->bs1 = ms->mesh->bus_status1; tlp->tgt = ms->conn_tgt; tlp->d = a; *slp = *tlp; if (++tp->log_ix >= N_DBG_LOG) tp->log_ix = 0; if (tp->n_log < N_DBG_LOG) ++tp->n_log; if (++ms->log_ix >= N_DBG_SLOG) ms->log_ix = 0; if (ms->n_log < N_DBG_SLOG) ++ms->n_log;}static void dumplog(struct mesh_state *ms, int t){ struct mesh_target *tp = &ms->tgts[t]; struct dbglog *lp; int i; if (tp->n_log == 0) return; i = tp->log_ix - tp->n_log; if (i < 0) i += N_DBG_LOG; tp->n_log = 0; do { lp = &tp->log[i]; printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ", t, lp->bs1, lp->bs0, lp->phase);#ifdef DBG_USE_TB printk("tb=%10u ", lp->tb);#endif printk(lp->fmt, lp->d); printk("\n"); if (++i >= N_DBG_LOG) i = 0; } while (i != tp->log_ix);}static void dumpslog(struct mesh_state *ms){ struct dbglog *lp; int i; if (ms->n_log == 0) return; i = ms->log_ix - ms->n_log; if (i < 0) i += N_DBG_SLOG; ms->n_log = 0; do { lp = &ms->log[i]; printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ", lp->bs1, lp->bs0, lp->phase, lp->tgt);#ifdef DBG_USE_TB printk("tb=%10u ", lp->tb);#endif printk(lp->fmt, lp->d); printk("\n"); if (++i >= N_DBG_SLOG) i = 0; } while (i != ms->log_ix);}#endif /* MESH_DBG */static Scsi_Host_Template driver_template = SCSI_MESH;#include "scsi_module.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -