static int stg_expect_signal(struct stg_softc *sc, u_int8_t phase, u_int8_t mask) { struct scsi_low_softc *slp = &sc->sc_sclow; bus_space_tag_t bst = sc->sc_iot; bus_space_handle_t bsh = sc->sc_ioh; int wc; u_int8_t ph; phase &= PHASE_MASK; for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++) { ph = bus_space_read_1(bst, bsh, tmc_bstat); if (ph == (u_int8_t) -1) return -1; if ((ph & PHASE_MASK) != phase) return 0; if ((ph & mask) != 0) return 1; SCSI_LOW_DELAY(STG_DELAY_INTERVAL); } kprintf("%s: stg_expect_signal timeout\n", slp->sl_xname); return -1; }
/**************************************************** * scsi low interface ****************************************************/ static void stghw_attention(struct stg_softc *sc) { sc->sc_busc |= BCTL_ATN; sc->sc_busimg |= BCTL_ATN; bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, sc->sc_busimg); SCSI_LOW_DELAY(10); }
static void stghw_bus_reset(struct stg_softc *sc) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; bus_space_write_1(iot, ioh, tmc_ictl, 0); bus_space_write_1(iot, ioh, tmc_fctl, 0); stghw_bcr_write_1(sc, BCTL_RST); SCSI_LOW_DELAY(100000); stghw_bcr_write_1(sc, BCTL_BUSFREE); }
static int stghw_select_targ_wait(struct stg_softc *sc, int mu) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; mu = mu / STGHW_SELECT_INTERVAL; while (mu -- > 0) { if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) == 0) { SCSI_LOW_DELAY(STGHW_SELECT_INTERVAL); continue; } SCSI_LOW_DELAY(1); if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) != 0) { return 0; } } return ENXIO; }
void bshw_bus_reset(struct ct_softc *ct) { struct scsi_low_softc *slp = &ct->sc_sclow; struct ct_bus_access_handle *chp = &ct->sc_ch; struct bshw_softc *bs = ct->ct_hw; struct bshw *hw = bs->sc_hw; bus_addr_t offs; u_int8_t regv; int i; /* open hardware busmaster mode */ if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0) { printf("%s: change mode using external DMA (%x)\n", slp->sl_xname, (u_int)ct_cr_read_1(chp, 0x37)); } /* clear hardware synch registers */ offs = hw->hw_sregaddr; if (offs != 0) { for (i = 0; i < 8; i ++, offs ++) { ct_cr_write_1(chp, offs, 0); if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0) ct_cr_write_1(chp, offs + 8, 0); } } /* disable interrupt & assert reset */ regv = ct_cr_read_1(chp, wd3s_mbank); regv |= MBR_RST; regv &= ~MBR_IEN; ct_cr_write_1(chp, wd3s_mbank, regv); SCSI_LOW_DELAY(500000); /* reset signal off */ regv &= ~MBR_RST; ct_cr_write_1(chp, wd3s_mbank, regv); /* interrupt enable */ regv |= MBR_IEN; ct_cr_write_1(chp, wd3s_mbank, regv); }
static int stg_negate_signal(struct stg_softc *sc, u_int8_t mask, u_char *s) { struct scsi_low_softc *slp = &sc->sc_sclow; bus_space_tag_t bst = sc->sc_iot; bus_space_handle_t bsh = sc->sc_ioh; int wc; u_int8_t regv; for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++) { regv = bus_space_read_1(bst, bsh, tmc_bstat); if (regv == (u_int8_t) -1) return -1; if ((regv & mask) == 0) return 1; SCSI_LOW_DELAY(STG_DELAY_INTERVAL); } kprintf("%s: %s stg_negate_signal timeout\n", slp->sl_xname, s); return -1; }
/************************************************************** * disconnect & reselect (HW low) **************************************************************/ static int stg_reselected(struct stg_softc *sc) { struct scsi_low_softc *slp = &sc->sc_sclow; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; int tout; u_int sid; u_int8_t regv; if (slp->sl_selid != NULL) { /* XXX: * Selection vs Reselection conflicts. */ bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, BCTL_BUSFREE); } else if (slp->sl_Tnexus != NULL) { kprintf("%s: unexpected termination\n", slp->sl_xname); stg_disconnected(sc, slp->sl_Tnexus); } /* XXX: * We should ack the reselection as soon as possible, * because the target would abort the current reselection seq * due to reselection timeout. */ tout = STG_DELAY_SELECT_POLLING_MAX; while (tout -- > 0) { regv = bus_space_read_1(iot, ioh, tmc_bstat); if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) == (BSTAT_IO | BSTAT_SEL)) { SCSI_LOW_DELAY(1); regv = bus_space_read_1(iot, ioh, tmc_bstat); if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) == (BSTAT_IO | BSTAT_SEL)) goto reselect_start; } SCSI_LOW_DELAY(1); } kprintf("%s: reselction timeout I\n", slp->sl_xname); return EJUSTRETURN; reselect_start: sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid); if ((sid & sc->sc_idbit) == 0) { /* not us */ return EJUSTRETURN; } bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT); bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY); while (tout -- > 0) { regv = bus_space_read_1(iot, ioh, tmc_bstat); if ((regv & (BSTAT_SEL | BSTAT_BSY)) == BSTAT_BSY) goto reselected; SCSI_LOW_DELAY(1); } kprintf("%s: reselction timeout II\n", slp->sl_xname); return EJUSTRETURN; reselected: sid &= ~sc->sc_idbit; sid = ffs(sid) - 1; if (scsi_low_reselected(slp, sid) == NULL) return EJUSTRETURN; #ifdef STG_STATICS stg_statics.reselect ++; #endif /* STG_STATICS */ return EJUSTRETURN; }
static void stg_pio_write(struct stg_softc *sc, struct targ_info *ti, u_int thold) { struct scsi_low_softc *slp = &sc->sc_sclow; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; struct sc_p *sp = &slp->sl_scp; u_int res; int tout; u_int8_t stat; if ((slp->sl_flags & HW_PDMASTART) == 0) { stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW; bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO); bus_space_write_1(iot, ioh, tmc_fctl, stat); slp->sl_flags |= HW_PDMASTART; } tout = sc->sc_tmaxcnt; while (tout -- > 0) { stat = bus_space_read_1(iot, ioh, tmc_bstat); if ((stat & PHASE_MASK) != DATA_OUT_PHASE) break; if (sp->scp_datalen <= 0) { if (sc->sc_dataout_timeout == 0) sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ; break; } if (thold > 0) { crit_enter(); res = bus_space_read_2(iot, ioh, tmc_fdcnt); if (res > thold) { bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); crit_exit(); break; } crit_exit(); } else { res = bus_space_read_2(iot, ioh, tmc_fdcnt); if (res > sc->sc_maxwsize / 2) { SCSI_LOW_DELAY(1); continue; } } if (res == (u_int) -1) break; res = sc->sc_maxwsize - res; if (res > sp->scp_datalen) res = sp->scp_datalen; sp->scp_datalen -= res; if ((res & 0x1) != 0) { bus_space_write_1(iot, ioh, tmc_wfifo, *sp->scp_data); sp->scp_data ++; res --; } bus_space_write_multi_2(iot, ioh, tmc_wfifo, (u_int16_t *) sp->scp_data, res >> 1); sp->scp_data += res; } if (tout <= 0) kprintf("%s: pio write timeout\n", slp->sl_xname); }
static void stg_pio_read(struct stg_softc *sc, struct targ_info *ti, u_int thold) { struct scsi_low_softc *slp = &sc->sc_sclow; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; struct sc_p *sp = &slp->sl_scp; int tout; u_int res; u_int8_t stat; if ((slp->sl_flags & HW_PDMASTART) == 0) { bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_FIFOEN); slp->sl_flags |= HW_PDMASTART; } tout = sc->sc_tmaxcnt; while (tout -- > 0) { if (thold > 0) { crit_enter(); res = bus_space_read_2(iot, ioh, tmc_fdcnt); if (res < thold) { bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); crit_exit(); break; } crit_exit(); } else { stat = bus_space_read_1(iot, ioh, tmc_bstat); res = bus_space_read_2(iot, ioh, tmc_fdcnt); if (res == 0) { if ((stat & PHASE_MASK) != DATA_IN_PHASE) break; if (sp->scp_datalen <= 0) break; SCSI_LOW_DELAY(1); continue; } } /* The assumtion res != 0 is valid here */ if (res > sp->scp_datalen) { if (res == (u_int) -1) break; slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_READ_PADDING) == 0) { kprintf("%s: read padding required\n", slp->sl_xname); break; } sp->scp_datalen = 0; if (res > STG_MAX_DATA_SIZE) res = STG_MAX_DATA_SIZE; while (res -- > 0) { (void) bus_space_read_1(iot, ioh, tmc_rfifo); } continue; } sp->scp_datalen -= res; if (res & 1) { *sp->scp_data = bus_space_read_1(iot, ioh, tmc_rfifo); sp->scp_data ++; res --; } bus_space_read_multi_2(iot, ioh, tmc_rfifo, (u_int16_t *) sp->scp_data, res >> 1); sp->scp_data += res; } if (tout <= 0) kprintf("%s: pio read timeout\n", slp->sl_xname); }
static int stg_timeout(struct stg_softc *sc) { struct scsi_low_softc *slp = &sc->sc_sclow; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; int tout, count; u_int8_t status; if (slp->sl_Tnexus == NULL) return 0; status = bus_space_read_1(iot, ioh, tmc_bstat); if ((status & PHASE_MASK) == 0) { if (sc->sc_ubf_timeout ++ == 0) return 0; kprintf("%s: unexpected bus free detected\n", slp->sl_xname); slp->sl_error |= FATALIO; scsi_low_print(slp, slp->sl_Tnexus); stg_disconnected(sc, slp->sl_Tnexus); return 0; } switch (status & PHASE_MASK) { case DATA_OUT_PHASE: if (sc->sc_dataout_timeout == 0) break; if ((status & BSTAT_REQ) == 0) break; if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0) break; if ((-- sc->sc_dataout_timeout) > 0) break; slp->sl_error |= PDMAERR; if ((slp->sl_flags & HW_WRITE_PADDING) == 0) { kprintf("%s: write padding required\n", slp->sl_xname); break; } bus_space_write_1(iot, ioh, tmc_ictl, 0); tout = STG_DELAY_MAX; while (tout --) { status = bus_space_read_1(iot, ioh, tmc_bstat); if ((status & PHASE_MASK) != DATA_OUT_PHASE) break; if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0) { SCSI_LOW_DELAY(1); continue; } for (count = sc->sc_maxwsize; count > 0; count --) bus_space_write_1(iot, ioh, tmc_wfifo, 0); } status = bus_space_read_1(iot, ioh, tmc_bstat); if ((status & PHASE_MASK) == DATA_OUT_PHASE) sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ; bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); break; default: break; } return 0; }