📄 siop_common.c
字号:
int target = siop_cmd->xs->sc_link->target; int sync, offset, scf; int send_msgout = 0; struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; sync = tables->msg_in[3]; offset = tables->msg_in[4]; /* revert to async until told otherwise */ sc->targets[target]->id &= 0x0fff0000; /* Keep SCNTL3.EWS, SCNTL3.CCF and id */ sc->targets[target]->flags &= ~(TARF_ISDT | TARF_ISQAS | TARF_ISIUS); if (siop_target->status == TARST_SYNC_NEG) { /* we initiated sync negotiation */#ifdef DEBUG printf("%s: sdtr for target %d: sync %d offset %d\n", sc->sc_dev.dv_xname, target, sync, offset);#endif scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); if (offset > sc->maxoff || scf == 0) goto reject; sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) sc->targets[target]->id |= SCNTL3_ULTRA << 24; sc->targets[target]->id |= (offset & 0xff) << 8; goto end; /* * We didn't find it in our table, so stay async and send reject * msg. */reject: send_msgout = 1; tables->t_msgout.count= htole32(1); tables->msg_out[0] = MSG_MESSAGE_REJECT; } else { /* target initiated sync neg */#ifdef DEBUG printf("%s: target initiated sdtr for target %d: sync %d offset %d\n", sc->sc_dev.dv_xname, target, sync, offset); printf("sdtr (target): sync %d offset %d\n", sync, offset);#endif if (sync < sc->min_st_sync) sync = sc->min_st_sync; scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); if ((sc->targets[target]->flags & TARF_SYNC) == 0 || offset == 0 || scf == 0) { goto async; } if ((offset > 31) && ((sc->targets[target]->flags & TARF_ISDT) == 0)) offset = 31; if (offset > sc->maxoff) offset = sc->maxoff; sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT); if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) sc->targets[target]->id |= SCNTL3_ULTRA << 24; sc->targets[target]->id |= (offset & 0xff) << 8; siop_sdtr_msg(siop_cmd, 0, sync, offset); send_msgout = 1; goto end;async: siop_sdtr_msg(siop_cmd, 0, 0, 0); send_msgout = 1; }end:#ifdef DEBUG printf("id now 0x%x\n", sc->targets[target]->id);#endif tables->id = htole32(sc->targets[target]->id); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, (sc->targets[target]->id >> 24) & 0xff); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, (sc->targets[target]->id >> 8) & 0xff); if (siop_target->status != TARST_PROBING) { siop_target->status = TARST_OK; siop_print_info(sc, target); } if (send_msgout) { return SIOP_NEG_MSGOUT; } else { return SIOP_NEG_ACK; }}voidsiop_ppr_msg(siop_cmd, offset, ssync, soff) struct siop_cmd *siop_cmd; int offset, ssync, soff;{ struct siop_softc *sc = siop_cmd->siop_sc; u_int8_t protocol; siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_PPR_LEN; siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_PPR; siop_cmd->siop_tables.msg_out[offset + 3] = ssync; siop_cmd->siop_tables.msg_out[offset + 4] = 0; /* RESERVED */ siop_cmd->siop_tables.msg_out[offset + 5] = soff; siop_cmd->siop_tables.msg_out[offset + 6] = MSG_EXT_WDTR_BUS_16_BIT; protocol = 0; if (sc->min_dt_sync != 0) protocol |= MSG_EXT_PPR_PROT_DT; /* XXX - need tests for chip's capability to do QAS & IUS * * if (test for QAS support) * protocol |= MSG_EXT_PPR_PROT_QAS; * if (test for IUS support) * protocol |= MSG_EXT_PPR_PROT_IUS; */ siop_cmd->siop_tables.msg_out[offset + 7] = protocol; siop_cmd->siop_tables.t_msgout.count = htole32(offset + MSG_EXT_PPR_LEN + 2);}voidsiop_sdtr_msg(siop_cmd, offset, ssync, soff) struct siop_cmd *siop_cmd; int offset; int ssync, soff;{ siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_SDTR_LEN; siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_SDTR; siop_cmd->siop_tables.msg_out[offset + 3] = ssync; if ((soff > 31) && ((siop_cmd->siop_target->flags & TARF_ISDT) == 0)) soff = 31; siop_cmd->siop_tables.msg_out[offset + 4] = soff; siop_cmd->siop_tables.t_msgout.count = htole32(offset + MSG_EXT_SDTR_LEN + 2);}voidsiop_wdtr_msg(siop_cmd, offset, wide) struct siop_cmd *siop_cmd; int offset;{ siop_cmd->siop_tables.msg_out[offset + 0] = MSG_EXTENDED; siop_cmd->siop_tables.msg_out[offset + 1] = MSG_EXT_WDTR_LEN; siop_cmd->siop_tables.msg_out[offset + 2] = MSG_EXT_WDTR; siop_cmd->siop_tables.msg_out[offset + 3] = wide; siop_cmd->siop_tables.t_msgout.count = htole32(offset + MSG_EXT_WDTR_LEN + 2);}voidsiop_minphys(bp) struct buf *bp;{ minphys(bp);}voidsiop_sdp(siop_cmd) struct siop_cmd *siop_cmd;{ /* save data pointer. Handle async only for now */ int offset, dbc, sstat; struct siop_softc *sc = siop_cmd->siop_sc; struct scr_table *table; /* table to patch */ if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN)) == 0) return; /* no data pointers to save */ offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); if (offset >= SIOP_NSG) { printf("%s: bad offset in siop_sdp (%d)\n", sc->sc_dev.dv_xname, offset); return; } table = &siop_cmd->siop_xfer->tables.data[offset];#ifdef DEBUG_DR printf("sdp: offset %d count=%d addr=0x%x ", offset, table->count, table->addr);#endif dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff; if (siop_cmd->xs->flags & SCSI_DATA_OUT) { /* need to account for stale data in FIFO */ if (sc->features & SF_CHIP_C10) dbc += bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC); else { int dfifo = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO); if (sc->features & SF_CHIP_FIFO) { dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) & CTEST5_BOMASK) << 8; dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff; } else { dbc += (dfifo - (dbc & 0x7f)) & 0x7f; } } sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0); if (sstat & SSTAT0_OLF) dbc++; if ((sc->features & SF_CHIP_C10) == 0) if (sstat & SSTAT0_ORF) dbc++; if (siop_cmd->siop_target->flags & TARF_ISWIDE) { sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT2); if (sstat & SSTAT2_OLF1) dbc++; if ((sc->features & SF_CHIP_C10) == 0) if (sstat & SSTAT2_ORF1) dbc++; } /* clear the FIFO */ bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | CTEST3_CLF); } table->addr = htole32(letoh32(table->addr) + letoh32(table->count) - dbc); table->count = htole32(dbc);#ifdef DEBUG_DR printf("now count=%d addr=0x%x\n", table->count, table->addr);#endif}voidsiop_clearfifo(sc) struct siop_softc *sc;{ int timeout = 0; int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);#ifdef SIOP_DEBUG_INTR printf("DMA fifo not empty!\n");#endif bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, ctest3 | CTEST3_CLF); while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & CTEST3_CLF) != 0) { delay(1); if (++timeout > 1000) { printf("clear fifo failed\n"); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3, bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) & ~CTEST3_CLF); return; } }}intsiop_modechange(sc) struct siop_softc *sc;{ int retry; int sist0, sist1, stest2, stest4; for (retry = 0; retry < 5; retry++) { /* * Datasheet says to wait 100ms and re-read SIST1, * to check that DIFFSENSE is stable. * We may delay() 5 times for 100ms at interrupt time; * hopefully this will not happen often. */ delay(100000); sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); if (sist1 & SIEN1_SBMC) continue; /* we got an irq again */ stest4 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) & STEST4_MODE_MASK; stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2); switch(stest4) { case STEST4_MODE_DIF: if (sc->features & SF_CHIP_C10) { printf("%s: invalid SCSI mode 0x%x\n", sc->sc_dev.dv_xname, stest4); return 0; } else { printf("%s: switching to differential mode\n", sc->sc_dev.dv_xname); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, stest2 | STEST2_DIF); } break; case STEST4_MODE_SE: printf("%s: switching to single-ended mode\n", sc->sc_dev.dv_xname); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, stest2 & ~STEST2_DIF); break; case STEST4_MODE_LVD: printf("%s: switching to LVD mode\n", sc->sc_dev.dv_xname); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, stest2 & ~STEST2_DIF); break; default: printf("%s: invalid SCSI mode 0x%x\n", sc->sc_dev.dv_xname, stest4); return 0; } bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST0, stest4 >> 2); return 1; } printf("%s: timeout waiting for DIFFSENSE to stabilise\n", sc->sc_dev.dv_xname); return 0;}voidsiop_resetbus(sc) struct siop_softc *sc;{ int scntl1; scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1 | SCNTL1_RST); /* minimum 25 us, more time won't hurt */ delay(100); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);}/* * siop_print_info: print the current negotiated wide/sync xfer values for * a particular target. This function is called whenever * a wide/sync negotiation completes, i.e. whenever * target->status is set to TARST_OK. */voidsiop_print_info(sc, target) struct siop_softc *sc; int target;{ struct siop_target *siop_target; u_int8_t scf, offset; int scf_index, factors, i; siop_target = sc->targets[target]; printf("%s: target %d now using %s%s%s%s%d bit ", sc->sc_dev.dv_xname, target, (siop_target->flags & TARF_TAG) ? "tagged " : "", (siop_target->flags & TARF_ISDT) ? "DT " : "", (siop_target->flags & TARF_ISQAS) ? "QAS " : "", (siop_target->flags & TARF_ISIUS) ? "IUS " : "", (siop_target->flags & TARF_ISWIDE) ? 16 : 8); offset = ((siop_target->id >> 8) & 0xff) >> SXFER_MO_SHIFT; if (offset == 0) printf("async "); else { factors = sizeof(period_factor) / sizeof(period_factor[0]); scf = ((siop_target->id >> 24) & SCNTL3_SCF_MASK) >> SCNTL3_SCF_SHIFT; scf_index = sc->scf_index; for (i = 0; i < factors; i++) if (siop_target->flags & TARF_ISDT) { if (period_factor[i].scf[scf_index].dt_scf == scf) break; } else if (period_factor[i].scf[scf_index].st_scf == scf) break; if (i >= factors) printf("?? "); else printf("%s ", period_factor[i].rate); printf("MHz %d REQ/ACK offset ", offset); } printf("xfers\n");}intsiop_period_factor_to_scf(sc, pf, flags) struct siop_softc *sc; int pf, flags;{ const int scf_index = sc->scf_index; int i; const int factors = sizeof(period_factor) / sizeof(period_factor[0]); for (i = 0; i < factors; i++) if (period_factor[i].factor == pf) { if (flags & TARF_ISDT) return (period_factor[i].scf[scf_index].dt_scf); else return (period_factor[i].scf[scf_index].st_scf); } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -