int csc_intr(void *arg) { struct sfas_softc *dev = arg; csc_regmap_p rp; int quickints; rp = (csc_regmap_p)dev->sc_fas; if (*rp->FAS216.sfas_status & SFAS_STAT_INTERRUPT_PENDING) { quickints = 16; do { dev->sc_status = *rp->FAS216.sfas_status; dev->sc_interrupt = *rp->FAS216.sfas_interrupt; if (dev->sc_interrupt & SFAS_INT_RESELECTED) { dev->sc_resel[0] = *rp->FAS216.sfas_fifo; dev->sc_resel[1] = *rp->FAS216.sfas_fifo; } sfasintr(dev); } while((*rp->FAS216.sfas_status & SFAS_STAT_INTERRUPT_PENDING) && --quickints); } return(0); /* Pass interrupt on down the chain */ }
/* * Actually select the unit, whereby the whole scsi-process is started. */ void sfas_donextcmd(struct sfas_softc *dev, struct sfas_pending *pendp) { int s; /* * Special case for scsi unit reset. I think this is waterproof. We first * select the unit during splbio. We then cycle through the generated * interrupts until the interrupt routine signals that the unit has * acknowledged the reset. After that we have to wait a reset to select * delay before anything else can happend. */ if (pendp->xs->xs_control & XS_CTL_RESET) { struct nexus *nexus; s = splbio(); while(!sfasselect(dev, pendp, 0, 0, 0, 0, SFAS_SELECT_K)) { splx(s); delay(10); s = splbio(); } nexus = dev->sc_cur_nexus; while(nexus->flags & SFAS_NF_UNIT_BUSY) { sfasiwait(dev); sfasintr(dev); } nexus->flags |= SFAS_NF_UNIT_BUSY; splx(s); sfasreset(dev, 0); s = splbio(); nexus->flags &= ~SFAS_NF_UNIT_BUSY; splx(s); } /* * If we are polling, go to splbio and perform the command, else we poke * the scsi-bus via sfasgo to get the interrupt machine going. */ if (pendp->xs->xs_control & XS_CTL_POLL) { s = splbio(); sfasicmd(dev, pendp); TAILQ_INSERT_TAIL(&dev->sc_xs_free, pendp, link); splx(s); } else { sfasgo(dev, pendp); } }
/* * Transfer info to/from device. sfas_ixfer uses polled IO+sfasiwait so the * rules that apply to sfasiwait also applies here. */ void sfas_ixfer(void *v, int polling) { struct sfas_softc *dev = v; sfas_regmap_p rp; u_char *buf; int len, mode, phase; rp = dev->sc_fas; buf = dev->sc_buf; len = dev->sc_len; /* * Decode the scsi phase to determine whether we are reading or writing. * mode == 1 => READ, mode == 0 => WRITE */ phase = dev->sc_status & SFAS_STAT_PHASE_MASK; mode = (phase == SFAS_PHASE_DATA_IN); while(len && ((dev->sc_status & SFAS_STAT_PHASE_MASK) == phase)) if (mode) { *rp->sfas_command = SFAS_CMD_TRANSFER_INFO; sfasiwait(dev); *buf++ = *rp->sfas_fifo; len--; } else { len--; *rp->sfas_fifo = *buf++; *rp->sfas_command = SFAS_CMD_TRANSFER_INFO; sfasiwait(dev); } /* Update buffer pointers to reflect the sent/received data. */ dev->sc_buf = buf; dev->sc_len = len; /* * Since the last sfasiwait will be a phase-change, we can't wait for it * again later, so we have to signal that. * Since this may be called from an interrupt initiated routine then we * must call sfasintr again to avoid losing an interrupt. Phew! */ if(polling) dev->sc_flags |= SFAS_DONT_WAIT; else sfasintr(dev); }
/* * sfasicmd is used to perform IO when we can't use interrupts. sfasicmd * emulates the normal environment by waiting for the chip and calling * sfasintr. */ void sfasicmd(struct sfas_softc *dev, struct sfas_pending *pendp) { struct nexus *nexus; nexus = &dev->sc_nexus[pendp->xs->xs_periph->periph_target]; if (!sfasselect(dev, pendp, (char *)pendp->xs->cmd, pendp->xs->cmdlen, (char *)pendp->xs->data, pendp->xs->datalen, SFAS_SELECT_I)) panic("sfasicmd: Couldn't select unit"); while(nexus->state != SFAS_NS_FINISHED) { sfasiwait(dev); sfasintr(dev); } nexus->flags &= ~SFAS_NF_SYNC_TESTED; }