static void ct_phase_error(struct ct_softc *ct, u_int8_t scsi_status) { struct scsi_low_softc *slp = &ct->sc_sclow; struct targ_info *ti = slp->sl_Tnexus; struct ct_err *pep; u_int msg = 0; if ((scsi_status & BSR_CM) == BSR_CMDERR && (scsi_status & BSR_PHVALID) == 0) { pep = &ct_cmderr[scsi_status & BSR_PM]; slp->sl_error |= pep->pe_err; if ((pep->pe_err & PARITYERR) != 0) { if (ti->ti_phase == PH_MSGIN) msg = SCSI_LOW_MSG_PARITY; else msg = SCSI_LOW_MSG_ERROR; } else msg = pep->pe_errmsg; if (msg != 0) scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1); if (pep->pe_msg != NULL) { device_printf(slp->sl_dev, "phase error: %s", pep->pe_msg); scsi_low_print(slp, slp->sl_Tnexus); } if (pep->pe_done != 0) scsi_low_disconnected(slp, ti); } else { slp->sl_error |= FATALIO; scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error"); } }
int stgintr(void *arg) { struct stg_softc *sc = arg; 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 targ_info *ti; struct buf *bp; u_int derror, flags; int len; u_int8_t status, astatus, regv; /******************************************* * interrupt check *******************************************/ if (slp->sl_flags & HW_INACTIVE) return 0; astatus = bus_space_read_1(iot, ioh, tmc_astat); status = bus_space_read_1(iot, ioh, tmc_bstat); if ((astatus & ASTAT_STATMASK) == 0 || astatus == (u_int8_t) -1) return 0; bus_space_write_1(iot, ioh, tmc_ictl, 0); if (astatus & ASTAT_SCSIRST) { bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); bus_space_write_1(iot, ioh, tmc_ictl, 0); scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, "bus reset (power off?)"); return 1; } /******************************************* * debug section *******************************************/ #ifdef STG_DEBUG if (stg_debug) { scsi_low_print(slp, NULL); kprintf("%s: st %x ist %x\n\n", slp->sl_xname, status, astatus); #ifdef DDB if (stg_debug > 1) SCSI_LOW_DEBUGGER("stg"); #endif /* DDB */ } #endif /* STG_DEBUG */ /******************************************* * reselection & nexus *******************************************/ if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED) { if (stg_reselected(sc) == EJUSTRETURN) goto out; } if ((ti = slp->sl_Tnexus) == NULL) return 0; derror = 0; if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART && (sc->sc_fcRinit & FCTL_PARENB) != 0) { slp->sl_error |= PARITYERR; derror = SCSI_LOW_DATA_PE; if ((status & PHASE_MASK) == MESSAGE_IN_PHASE) scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); else scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); } /******************************************* * aribitration & selection *******************************************/ switch (ti->ti_phase) { case PH_ARBSTART: if ((astatus & ASTAT_ARBIT) == 0) { #ifdef STG_STATICS stg_statics.arbit_fail_0 ++; #endif /* STG_STATICS */ goto arb_fail; } status = bus_space_read_1(iot, ioh, tmc_bstat); if ((status & BSTAT_IO) != 0) { /* XXX: * Selection vs Reselection conflicts. */ #ifdef STG_STATICS stg_statics.arbit_fail_1 ++; #endif /* STG_STATICS */ arb_fail: bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, BCTL_BUSFREE); scsi_low_arbit_fail(slp, slp->sl_Qnexus); goto out; } /* * selection assert start. */ SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); scsi_low_arbit_win(slp); crit_enter(); bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit | (1 << ti->ti_id)); stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL); bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); if ((stg_io_control & STG_WAIT_FOR_SELECT) != 0) { /* selection abort delay 200 + 100 micro sec */ if (stghw_select_targ_wait(sc, 300) == 0) { SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); stg_selection_done_and_expect_msgout(sc); } } crit_exit(); goto out; case PH_SELSTART: if ((status & BSTAT_BSY) == 0) { /* selection timeout delay 250 ms */ if (stghw_select_targ_wait(sc, 250 * 1000) != 0) { stg_disconnected(sc, ti); goto out; } } SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); stg_selection_done_and_expect_msgout(sc); goto out; case PH_SELECTED: if ((status & BSTAT_REQ) == 0) goto out; stg_target_nexus_establish(sc); break; case PH_RESEL: if ((status & BSTAT_REQ) == 0) goto out; /* clear a busy line */ bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); stghw_bcr_write_1(sc, sc->sc_busc); stg_target_nexus_establish(sc); if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) { kprintf("%s: unexpected phase after reselect\n", slp->sl_xname); slp->sl_error |= FATALIO; scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); goto out; } break; } /******************************************* * data phase *******************************************/ if ((slp->sl_flags & HW_PDMASTART) && STG_IS_PHASE_DATA(status) == 0) { if (slp->sl_scp.scp_direction == SCSI_LOW_READ) stg_pio_read(sc, ti, 0); stg_pdma_end(sc, ti); } /******************************************* * scsi seq *******************************************/ switch (status & PHASE_MASK) { case COMMAND_PHASE: if (stg_expect_signal(sc, COMMAND_PHASE, BSTAT_REQ) <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_CMD); if (scsi_low_cmd(slp, ti) != 0) { scsi_low_attention(slp); } if (stg_xfer(sc, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen, COMMAND_PHASE, 0) != 0) { kprintf("%s: CMDOUT short\n", slp->sl_xname); } break; case DATA_OUT_PHASE: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) { scsi_low_attention(slp); } if ((sc->sc_icinit & ICTL_FIFO) != 0) stg_pio_write(sc, ti, sc->sc_wthold); else stg_pio_write(sc, ti, 0); break; case DATA_IN_PHASE: SCSI_LOW_SETUP_PHASE(ti, PH_DATA); if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) { scsi_low_attention(slp); } if ((sc->sc_icinit & ICTL_FIFO) != 0) stg_pio_read(sc, ti, sc->sc_rthold); else stg_pio_read(sc, ti, 0); break; case STATUS_PHASE: regv = stg_expect_signal(sc, STATUS_PHASE, BSTAT_REQ); if (regv <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_STAT); regv = bus_space_read_1(iot, ioh, tmc_sdna); if (scsi_low_statusin(slp, ti, regv | derror) != 0) { scsi_low_attention(slp); } if (regv != bus_space_read_1(iot, ioh, tmc_rdata)) { kprintf("%s: STATIN: data mismatch\n", slp->sl_xname); } stg_negate_signal(sc, BSTAT_ACK, "statin<ACK>"); break; case MESSAGE_OUT_PHASE: if (stg_expect_signal(sc, MESSAGE_OUT_PHASE, BSTAT_REQ) <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); flags = (ti->ti_ophase != ti->ti_phase) ? SCSI_LOW_MSGOUT_INIT : 0; len = scsi_low_msgout(slp, ti, flags); if (len > 1 && slp->sl_atten == 0) { scsi_low_attention(slp); } if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE, slp->sl_clear_atten) != 0) { kprintf("%s: MSGOUT short\n", slp->sl_xname); } else { if (slp->sl_msgphase >= MSGPH_ABORT) { stg_disconnected(sc, ti); } } break; case MESSAGE_IN_PHASE: /* confirm phase and req signal */ if (stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ) <= 0) break; SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); /* read data with NOACK */ regv = bus_space_read_1(iot, ioh, tmc_sdna); if (scsi_low_msgin(slp, ti, derror | regv) == 0) { if (scsi_low_is_msgout_continue(ti, 0) != 0) { scsi_low_attention(slp); } } /* read data with ACK */ if (regv != bus_space_read_1(iot, ioh, tmc_rdata)) { kprintf("%s: MSGIN: data mismatch\n", slp->sl_xname); } /* wait for the ack negated */ stg_negate_signal(sc, BSTAT_ACK, "msgin<ACK>"); if (slp->sl_msgphase != 0 && slp->sl_msgphase < MSGPH_ABORT) { stg_disconnected(sc, ti); } break; case BUSFREE_PHASE: kprintf("%s: unexpected disconnect\n", slp->sl_xname); stg_disconnected(sc, ti); break; default: slp->sl_error |= FATALIO; kprintf("%s: unknown phase bus %x intr %x\n", slp->sl_xname, status, astatus); break; } out: bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); return 1; }