📄 esp.c
字号:
sc->sc_dmaaddr += i; sc->sc_resid -= i; if ((sc->sc_espintr & ESPINTR_SVC) == 0) { esperror(sc, "no bus service req"); return (ACT_RESET); } break; case S_STAT: /* * The last thing we did was tell it `initiator complete' * and so we expect to have gotten both the status byte * and the final message byte. It is possible that we * got something else.... * * Apparently, BUS SERVICE is set if we got just status, * while FUNCTION COMPLETE is set if we got both. */ if ((reg & (ESPINTR_SVC|ESPINTR_CMP)) != ESPINTR_CMP) { esperror(sc, "bad status interrupt state"); return (ACT_RESET); } reg = ESP_NFIFO(sc->sc_espfflags); if (reg < 2) { printf( "%s: command done but fifo count = %d; must be >= 2\n", sc->sc_dev.dv_xname, reg); return (ACT_RESET); } /* * Read the status and the first msg byte. * It should be CMD_COMPLETE. Eventually we * may handle IDENTIFY, DISCONNECT, etc., as well. */ sc->sc_stat[0] = esp->esp_fifo; sc->sc_msg[0] = reg = esp->esp_fifo; esp->esp_cmd = ESPCMD_MSG_ACCEPT; if (reg == MSG_CMD_COMPLETE) { sc->sc_state = S_FI; return (ACT_CONT); } if (SCSIMSGLEN(reg) != 1) { printf("%s: target %d is naughty\n", sc->sc_dev.dv_xname, sc->sc_targ); return (ACT_RESET); } printf("%s: warning: target %d returned msg 0x%x\n", sc->sc_dev.dv_xname, sc->sc_targ, reg); sc->sc_state = S_FI; return (ACT_CONT); case S_MI: if ((reg & ESPINTR_SVC) == 0) { esperror(sc, "missing phase after msg in"); return (ACT_RESET); } reg = ESP_NFIFO(sc->sc_espfflags); for (i = 0; i < reg; i++) sc->sc_msg[i] = esp->esp_fifo; break; case S_FI: esperror(sc, "target did not disconnect"); return (ACT_RESET); } /* * Things are still moving along. The phase tells us * what the device wants next. Do it. */ switch (sc->sc_espstat & ESPSTAT_PHASE) { case ESPPHASE_DATA_OUT:if (!sc->sc_sentcmd) esperror(sc, "DIAG: data out without command"); if (sc->sc_dmactl & DMA_READ) { esperror(sc, "wrong phase (want to read)"); return (ACT_RESET); } newstate = S_DO; goto do_data_xfer; case ESPPHASE_DATA_IN:if (!sc->sc_sentcmd) esperror(sc, "DIAG: data in without command"); if (!(sc->sc_dmactl & DMA_READ)) { esperror(sc, "wrong phase (want to write)"); return (ACT_RESET); } newstate = S_DI;do_data_xfer: if (sc->sc_resid == 0) { esperror(sc, "data count error"); return (ACT_RESET); } /* * Compute DMA count based on chip limits. * Set DMA address and load transfer count into * ESP via DMA NOP, then set DMA control, and * then we can start the DMA. */ sc->sc_state = newstate; i = min(sc->sc_resid, ESPMAX); i = min(i, DMAMAX(sc->sc_dmaaddr)); sc->sc_dmasize = i; dma->dma_addr = sc->sc_dmaaddr; esp->esp_tch = i >> 8; esp->esp_tcl = i; esp->esp_cmd = ESPCMD_DMA | ESPCMD_NOP; dma->dma_csr = sc->sc_dmactl; sc->sc_dmaactive = 1; esp->esp_cmd = ESPCMD_DMA | ESPCMD_XFER_INFO; return (ACT_IO); case ESPPHASE_CMD: /* * Silly thing wants the command again. * Load it into the FIFO and go to SVC state. */printf("%s: redoing command\n", sc->sc_dev.dv_xname); cdb = sc->sc_curcdb; reg = SCSICMDLEN(cdb->cdb_bytes[0]); for (i = 0; i < reg; i++) esp->esp_fifo = cdb->cdb_bytes[i]; sc->sc_state = S_SVC; esp->esp_cmd = ESPCMD_XFER_INFO; return (ACT_CONT); case ESPPHASE_STATUS: sc->sc_state = S_STAT; esp->esp_cmd = ESPCMD_INIT_COMP; return (ACT_CONT); case ESPPHASE_MSG_IN:printf("%s: accepting (& ignoring) msg from target %d\n", sc->sc_dev.dv_xname, sc->sc_targ); sc->sc_state = S_MI; esp->esp_cmd = ESPCMD_MSG_ACCEPT; return (ACT_CONT); default: esperror(sc, "bad phase"); return (ACT_RESET); } /* NOTREACHED */}/* * Clear out target state by doing a special TEST UNIT READY. * Note that this calls espicmd (possibly recursively). */voidespclear(sc, targ) register struct esp_softc *sc; register int targ;{ /* turn off needclear immediately since this calls espicmd() again */ sc->sc_needclear &= ~(1 << targ); sc->sc_clearing = 1; (void) scsi_test_unit_ready(&sc->sc_hba, targ, 0); sc->sc_clearing = 0;}/* * THIS SHOULD BE ADJUSTABLE */ /* name howlong purpose */#define SELECT_WAIT 300000 /* wait for select to complete */#define CMD_WAIT 100000 /* wait for next phase, generic */#define DATA_WAIT 100000 /* time to xfer data in/out *//* * Send an `immediate' command, i.e., poll until the whole thing is done. * Return the status byte from the device, or -1 if we timed out. We use * DMA to transfer the data as the fifo only moves one byte at a time. */intespicmd(hba, targ, cdb, buf, len, rw) struct hba_softc *hba; int targ; struct scsi_cdb *cdb; caddr_t buf; int len, rw;{ register struct esp_softc *sc = (struct esp_softc *)hba; register volatile struct espreg *esp = sc->sc_esp; register volatile struct dmareg *dma = sc->sc_dma; register int r, wait; /* * Clear the target if necessary. */ if (sc->sc_needclear & (1 << targ) && !sc->sc_probing) espclear(sc, targ); /* * Set up DMA transfer control (leaving interrupts disabled). */ sc->sc_dmactl = rw & B_READ ? DMA_ENA | DMA_READ : DMA_ENA; sc->sc_dmaaddr = (u_long)buf; sc->sc_resid = len; /* * Disable hardware interrupts and start select sequence, * then loop, calling espact() after each ``interrupt''. */ DMAWAIT(dma); /* ??? */ dma->dma_csr = 0; espselect(sc, targ, cdb); wait = SELECT_WAIT; for (;;) { r = dma->dma_csr; if (!DMA_INTR(r)) { if (--wait < 0) { esperror(sc, "timeout"); goto reset; } DELAY(1); continue; } sc->sc_espstat = esp->esp_stat; sc->sc_espstep = esp->esp_step & ESPSTEP_MASK; sc->sc_espintr = esp->esp_intr; sc->sc_espfflags = esp->esp_fflags; sc->sc_dmacsr = r; switch (r = espact(sc)) { case ACT_CONT: case ACT_QUICKINTR: wait = CMD_WAIT; break; case ACT_IO: wait = DATA_WAIT; break; case ACT_RESET: sc->sc_state = S_IDLE; goto reset; case ACT_DONE: sc->sc_state = S_IDLE; return (sc->sc_stat[0]); case ACT_ERROR: sc->sc_state = S_IDLE; return (-1); default: panic("espicmd action"); } }reset: espreset(sc, RESET_ESPCHIP); /* ??? */ return (-1);}/* * Dump (write memory, possibly physmem). * SPARC higher-level dump code always provides virtual addresses, * so we need not do any I/O mapping here. */intespdump(hba, targ, cdb, buf, len) register struct hba_softc *hba; int targ; struct scsi_cdb *cdb; caddr_t buf; register int len;{ return (espicmd(hba, targ, cdb, buf, len, B_WRITE));}/* * Allocate resources (SCSI bus and DVMA space) for the given transfer. * Must be called at splbio(). * * THIS SHOULD RETURN SUCCESS/FAIL INDICATION */voidespstart(self, sq, bp, dgo, dev) struct device *self; register struct sq *sq; struct buf *bp; scdgo_fn dgo; struct device *dev;{ register struct esp_softc *sc = (struct esp_softc *)self; if (sc->sc_hba.hba_busy == 0) { /* * Bus not busy, nothing to do here, just tell * this target or unit that it has the SCSI bus. */ sc->sc_hba.hba_busy = 1; (*dgo)(dev, &sc->sc_cdbspace); } else { /* * Bus is busy; just enqueue. */ sq->sq_dgo = dgo; sq->sq_dev = dev; sq->sq_forw = NULL; if (sc->sc_hba.hba_head == NULL) sc->sc_hba.hba_head = sq; else sc->sc_hba.hba_tail->sq_forw = sq; sc->sc_hba.hba_tail = sq; }}/* * Start buffered I/O. * Return 0 on success, 1 on failure. */intespgo(self, targ, intr, dev, bp, pad) struct device *self; int targ; scintr_fn intr; struct device *dev; register struct buf *bp; int pad;{ register struct esp_softc *sc = (struct esp_softc *)self; if (sc->sc_needclear & (1 << targ)) espclear(sc, targ); /* Set up dma control for espact(). */ sc->sc_dmactl = bp->b_flags & B_READ ? DMA_ENA | DMA_READ | DMA_IE : DMA_ENA | DMA_IE; sc->sc_dmaaddr = (u_long)bp->b_un.b_addr; sc->sc_resid = bp->b_bcount; /* * Enable interrupts and start selection. * The rest is done in espintr() and espact(). */ sc->sc_hba.hba_intr = intr; /* remember dev done function */ sc->sc_hba.hba_intrdev = dev; /* and its first arg */ sc->sc_dma->dma_csr = DMA_IE; espselect(sc, targ, &sc->sc_cdbspace); return (0);}/* * Handle interrupt. Return 1 if taken. */intespintr(sc0) void *sc0;{ register struct esp_softc *sc = (struct esp_softc *)sc0; register volatile struct espreg *esp = sc->sc_esp; register volatile struct dmareg *dma = sc->sc_dma; register int r, wait; register struct sq *sq; r = dma->dma_csr; if (!DMA_INTR(r)) return (0); /* not ours */ sc->sc_intrcnt.ev_count++;again: sc->sc_espstat = esp->esp_stat; sc->sc_espstep = esp->esp_step & ESPSTEP_MASK; sc->sc_espintr = esp->esp_intr; sc->sc_espfflags = esp->esp_fflags; sc->sc_dmacsr = r; if (sc->sc_state == S_IDLE) { printf("%s: stray interrupt\n", sc->sc_dev.dv_xname); dma->dma_csr &= ~DMA_IE; /* ??? */ return (1); } switch (r = espact(sc)) { case ACT_CONT: /* just return */ case ACT_IO: break; case ACT_RESET: /* please reset esp */reset: espreset(sc, RESET_ESPCHIP); /* ??? */ /* FALLTHROUGH */ case ACT_DONE: /* this one is done, successfully */ case ACT_ERROR: /* this one is done due to `severe' error */ sc->sc_state = S_IDLE; if (!sc->sc_hba.hba_busy) panic("espintr sq"); /* * This transaction is done. * Call the driver's intr routine, * then start the next guy if any. */ (*sc->sc_hba.hba_intr)(sc->sc_hba.hba_intrdev, r == ACT_DONE ? sc->sc_stat[0] : -1, sc->sc_resid); if ((sq = sc->sc_hba.hba_head) != NULL) { sc->sc_hba.hba_head = sq->sq_forw; (*sq->sq_dgo)(sq->sq_dev, &sc->sc_cdbspace); } else sc->sc_hba.hba_busy = 0; break; case ACT_QUICKINTR: /* wait a short while for another interrupt */printf("%s: quickintr: ", sc->sc_dev.dv_xname); wait = 100; do { r = dma->dma_csr; if (DMA_INTR(r)) {printf("got one, wait=%d\n", wait); goto again; } } while (--wait > 0);printf("did not get one\n"); break; default: panic("espintr action"); } return (1);}/* * Target or unit decided to let go of the bus early. */voidesprel(self) struct device *self;{ register struct esp_softc *sc = (struct esp_softc *)self; register struct sq *sq; /* if there is someone else waiting, give them a crack at it */ if ((sq = sc->sc_hba.hba_head) != NULL) (*sq->sq_dgo)(sq->sq_dev, &sc->sc_cdbspace); else sc->sc_hba.hba_busy = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -