diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2001-04-15 06:01:33 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2001-04-15 06:01:33 +0000 |
commit | eec6fc2cdaf9318e5cd310cf0863d77276d49d0a (patch) | |
tree | f192bd690df7dc4a9f8b6c89bb4af785d227119d /sys/dev/ic | |
parent | c8c56fd9ceeee1295adc3c3951381e53cdc4cce9 (diff) |
Support U160 on 53c1010 chips.
Add support for PPR negotiations and DT transfers,
and the preservation and restoration of the
SCNTL4 register which controls Ultra3 transfers.
Redo sync lookup, since the same period factor
can mean two things depending on whether you are
using DT or ST. Keep a minimum allowed ST period
factor, and a minimum allowd DT period factor for
each adapter.
Currently NO support for QAS or IUS or AIP.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/siop.c | 161 | ||||
-rw-r--r-- | sys/dev/ic/siop_common.c | 279 | ||||
-rw-r--r-- | sys/dev/ic/siopreg.h | 69 | ||||
-rw-r--r-- | sys/dev/ic/siopvar.h | 8 | ||||
-rw-r--r-- | sys/dev/ic/siopvar_common.h | 65 |
5 files changed, 393 insertions, 189 deletions
diff --git a/sys/dev/ic/siop.c b/sys/dev/ic/siop.c index c855a7c456f..d74355488dc 100644 --- a/sys/dev/ic/siop.c +++ b/sys/dev/ic/siop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: siop.c,v 1.5 2001/03/06 16:29:32 krw Exp $ */ +/* $OpenBSD: siop.c,v 1.6 2001/04/15 06:01:28 krw Exp $ */ /* $NetBSD: siop.c,v 1.39 2001/02/11 18:04:49 bouyer Exp $ */ /* @@ -229,19 +229,24 @@ siop_attach(sc) for (i = 0; i < 16; i++) sc->targets[i] = NULL; - /* find min/max sync period for this chip */ - sc->maxsync = 0; - sc->minsync = 255; - for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) { - if (sc->clock_period != scf_period[i].clock) - continue; - if (sc->maxsync < scf_period[i].period) - sc->maxsync = scf_period[i].period; - if (sc->minsync > scf_period[i].period) - sc->minsync = scf_period[i].period; - } - if (sc->maxsync == 255 || sc->minsync == 0) - panic("siop: can't find my sync parameters\n"); + /* find min_dt_sync and min_st_sync for this chip */ + sc->min_dt_sync = 0; + for (i = 0; i < sizeof(period_factor) / sizeof(period_factor[0]); i++) + if (period_factor[i].scf[sc->scf_index].dt_scf != 0) { + sc->min_dt_sync = period_factor[i].factor; + break; + } + + sc->min_st_sync = 0; + for (i = 0; i < sizeof(period_factor) / sizeof(period_factor[0]); i++) + if (period_factor[i].scf[sc->scf_index].st_scf != 0) { + sc->min_st_sync = period_factor[i].factor; + break; + } + + if (sc->min_st_sync == 0) + panic("%s: can't find minimum allowed sync period factor\n", sc->sc_dev.dv_xname); + /* Do a bus reset, so that devices fall back to narrow/async */ siop_resetbus(sc); /* @@ -742,7 +747,7 @@ scintr: } siop_target->status = TARST_SYNC_NEG; siop_sdtr_msg(siop_cmd, 0, - sc->minsync, sc->maxoff); + sc->min_st_sync, sc->maxoff); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); @@ -809,6 +814,7 @@ scintr: CALL_SCRIPT(Ent_get_extmsgdata); return 1; case A_int_extmsgdata: + { #ifdef SIOP_DEBUG_INTR { int i; @@ -821,55 +827,56 @@ scintr: printf("\n"); } #endif - if (siop_cmd->siop_tables.msg_in[2] == MSG_EXT_WDTR) { - switch (siop_wdtr_neg(siop_cmd)) { - case SIOP_NEG_MSGOUT: - siop_update_scntl3(sc, - siop_cmd->siop_target); - siop_table_sync(siop_cmd, - BUS_DMASYNC_PREREAD | - BUS_DMASYNC_PREWRITE); - CALL_SCRIPT(Ent_send_msgout); - return(1); - case SIOP_NEG_ACK: - siop_update_scntl3(sc, - siop_cmd->siop_target); - CALL_SCRIPT(Ent_msgin_ack); - return(1); - default: - panic("invalid retval from " - "siop_wdtr_neg()"); - } - return(1); + int neg_action = SIOP_NEG_NOP; + const char *neg_name = ""; + + switch (siop_cmd->siop_tables.msg_in[2]) { + case MSG_EXT_WDTR: + neg_action = siop_wdtr_neg(siop_cmd); + neg_name = "wdtr"; + break; + case MSG_EXT_SDTR: + neg_action = siop_sdtr_neg(siop_cmd); + neg_name = "sdtr"; + break; + case MSG_EXT_PPR: + neg_action = siop_ppr_neg(siop_cmd); + neg_name = "ppr"; + break; + default: + neg_action = SIOP_NEG_MSGREJ; + break; } - if (siop_cmd->siop_tables.msg_in[2] == MSG_EXT_SDTR) { - switch (siop_sdtr_neg(siop_cmd)) { - case SIOP_NEG_MSGOUT: - siop_update_scntl3(sc, - siop_cmd->siop_target); - siop_table_sync(siop_cmd, - BUS_DMASYNC_PREREAD | - BUS_DMASYNC_PREWRITE); - CALL_SCRIPT(Ent_send_msgout); - return(1); - case SIOP_NEG_ACK: - siop_update_scntl3(sc, - siop_cmd->siop_target); - CALL_SCRIPT(Ent_msgin_ack); - return(1); - default: - panic("invalid retval from " - "siop_wdtr_neg()"); - } - return(1); + + switch (neg_action) { + case SIOP_NEG_NOP: + break; + case SIOP_NEG_MSGOUT: + siop_update_scntl3(sc, siop_cmd->siop_target); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_send_msgout); + break; + case SIOP_NEG_ACK: + siop_update_scntl3(sc, siop_cmd->siop_target); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_msgin_ack); + break; + case SIOP_NEG_MSGREJ: + siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT; + siop_cmd->siop_tables.t_msgout.count = htole32(1); + siop_table_sync(siop_cmd, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + CALL_SCRIPT(Ent_send_msgout); + break; + default: + panic("invalid return value from siop_%s_neg(): 0x%x", neg_name, neg_action); } - /* send a message reject */ - siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT; - siop_cmd->siop_tables.t_msgout.count = htole32(1); - siop_table_sync(siop_cmd, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - CALL_SCRIPT(Ent_send_msgout); - return 1; + + return (1); + } + case A_int_disc: INCSTAT(siop_stat_intr_sdp); offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, @@ -1180,7 +1187,7 @@ siop_handle_reset(sc) } } sc->targets[target]->status = TARST_ASYNC; - sc->targets[target]->flags &= ~TARF_ISWIDE; + sc->targets[target]->flags &= ~(TARF_ISWIDE | TARF_ISDT | TARF_ISQAS | TARF_ISIUS); } /* Next commands from the urgent list */ for (siop_cmd = TAILQ_FIRST(&sc->urgent_list); siop_cmd != NULL; @@ -1363,11 +1370,19 @@ siop_scsicmd(xs) sc->targets[target]->flags |= TARF_TAG; xs->sc_link->openings += SIOP_NTAG - SIOP_OPENINGS; } + if ((inqdata->flags & SID_WBus16) && (sc->features & SF_BUS_WIDE)) sc->targets[target]->flags |= TARF_WIDE; if (inqdata->flags & SID_Sync) sc->targets[target]->flags |= TARF_SYNC; - if (sc->targets[target]->flags & (TARF_WIDE | TARF_SYNC)) { + + if ((sc->features & SF_CHIP_C10) + && (sc->targets[target]->flags & TARF_WIDE) + && (inqdata->flags2 & (SID_CLOCKING | SID_QAS | SID_IUS))) + sc->targets[target]->flags |= TARF_PPR; + + if (sc->targets[target]->flags + & (TARF_WIDE | TARF_SYNC | TARF_PPR)) { sc->targets[target]->status = TARST_ASYNC; siop_add_dev(sc, target, lun); } @@ -1728,13 +1743,13 @@ siop_morecbd(sc) newcbd->cmds[i].siop_tables.t_msgout.count= htole32(1); newcbd->cmds[i].siop_tables.t_msgout.addr = htole32(dsa); newcbd->cmds[i].siop_tables.t_msgin.count= htole32(1); - newcbd->cmds[i].siop_tables.t_msgin.addr = htole32(dsa + 8); + newcbd->cmds[i].siop_tables.t_msgin.addr = htole32(dsa + 16); newcbd->cmds[i].siop_tables.t_extmsgin.count= htole32(2); - newcbd->cmds[i].siop_tables.t_extmsgin.addr = htole32(dsa + 9); + newcbd->cmds[i].siop_tables.t_extmsgin.addr = htole32(dsa + 17); newcbd->cmds[i].siop_tables.t_extmsgdata.addr = - htole32(dsa + 11); + htole32(dsa + 19); newcbd->cmds[i].siop_tables.t_status.count= htole32(1); - newcbd->cmds[i].siop_tables.t_status.addr = htole32(dsa + 16); + newcbd->cmds[i].siop_tables.t_status.addr = htole32(dsa + 32); /* The select/reselect script */ scr = &newcbd->cmds[i].siop_xfer->resel[0]; @@ -1894,6 +1909,16 @@ siop_update_scntl3(sc, siop_target) siop_script_write(sc, siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2, 0x78050000 | (siop_target->id & 0x0000ff00)); + /* If DT, change null op ('MOVE 0xff TO SFBR') to 'MOVE n TO SCNTL4' */ + if (siop_target->flags & TARF_ISDT) + siop_script_write(sc, + siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 4, + 0x78bc0000 | ((siop_target->id << 8) & 0x0000ff00)); + else + siop_script_write(sc, + siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 4, + 0x7808ff00); + siop_script_sync(sc, BUS_DMASYNC_PREWRITE); } diff --git a/sys/dev/ic/siop_common.c b/sys/dev/ic/siop_common.c index 47e1fd813c9..186f967e47b 100644 --- a/sys/dev/ic/siop_common.c +++ b/sys/dev/ic/siop_common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: siop_common.c,v 1.5 2001/03/10 05:04:06 krw Exp $ */ +/* $OpenBSD: siop_common.c,v 1.6 2001/04/15 06:01:29 krw Exp $ */ /* $NetBSD: siop_common.c,v 1.12 2001/02/11 18:04:50 bouyer Exp $ */ /* @@ -71,6 +71,8 @@ siop_common_reset(sc) SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div); + if (sc->features & SF_CHIP_C10) + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0, @@ -129,6 +131,7 @@ siop_setuptables(siop_cmd) struct scsi_xfer *xs = siop_cmd->xs; int target = xs->sc_link->target; int lun = xs->sc_link->lun; + int targ_flags = sc->targets[target]->flags; siop_cmd->siop_tables.id = htole32(sc->targets[target]->id); memset(siop_cmd->siop_tables.msg_out, 0, 8); @@ -138,18 +141,24 @@ siop_setuptables(siop_cmd) siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 0); siop_cmd->siop_tables.t_msgout.count= htole32(1); if (sc->targets[target]->status == TARST_ASYNC) { - if (sc->targets[target]->flags & TARF_WIDE) { + if (targ_flags & TARF_PPR) { + sc->targets[target]->status = TARST_PPR_NEG; + if (sc->min_dt_sync != 0) + siop_ppr_msg(siop_cmd, 1, sc->min_dt_sync, sc->maxoff); + else + siop_ppr_msg(siop_cmd, 1, sc->min_st_sync, sc->maxoff); + } else if (targ_flags & TARF_WIDE) { sc->targets[target]->status = TARST_WIDE_NEG; siop_wdtr_msg(siop_cmd, 1, MSG_EXT_WDTR_BUS_16_BIT); - } else if (sc->targets[target]->flags & TARF_SYNC) { + } else if (targ_flags & TARF_SYNC) { sc->targets[target]->status = TARST_SYNC_NEG; - siop_sdtr_msg(siop_cmd, 1, sc->minsync, sc->maxoff); + siop_sdtr_msg(siop_cmd, 1, sc->min_st_sync, sc->maxoff); } else { sc->targets[target]->status = TARST_OK; siop_print_info(sc, target); } } else if (sc->targets[target]->status == TARST_OK && - (sc->targets[target]->flags & TARF_TAG) && + (targ_flags & TARF_TAG) && siop_cmd->status != CMDST_SENSE) { siop_cmd->flags |= CMDFL_TAG; } @@ -173,6 +182,81 @@ siop_setuptables(siop_cmd) } int +siop_ppr_neg(siop_cmd) + struct siop_cmd *siop_cmd; +{ + struct siop_softc *sc = siop_cmd->siop_sc; + struct siop_target *siop_target = siop_cmd->siop_target; + int target = siop_cmd->xs->sc_link->target; + struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; + int offset, sync, protocol, scf; + + sync = tables->msg_in[3]; + offset = tables->msg_in[5]; + protocol = tables->msg_in[7]; + +#ifdef DEBUG + printf("%s: siop_ppr_neg: sync = %x, offset = %x, protocol = %x\n", + sc->sc_dev.dv_xname, sync, offset, protocol); +#endif + /* + * Process protocol bits first, because finding the correct scf + * via siop_period_factor_to_scf() requires the TARF_ISDT flag + * to be correctly set. + */ + if (protocol & MSG_EXT_PPR_PROT_IUS) + siop_target->flags |= TARF_ISIUS; + + if (protocol & MSG_EXT_PPR_PROT_DT) { + siop_target->flags |= TARF_ISDT; + sc->targets[target]->id |= SCNTL4_ULTRA3; + } + + if (protocol & MSG_EXT_PPR_PROT_QAS) + siop_target->flags |= TARF_ISQAS; + + scf = siop_period_factor_to_scf(sc, sync, siop_target->flags); + + if ((offset > sc->maxoff) || + (scf == 0) || + ((siop_target->flags & TARF_ISDT) && (offset == 1))) { + tables->t_msgout.count= htole32(1); + tables->msg_out[0] = MSG_MESSAGE_REJECT; + return (SIOP_NEG_MSGOUT); + } + + siop_target->id |= scf << (24 + SCNTL3_SCF_SHIFT); + + if (((sc->features & SF_CHIP_C10) == 0) && (sync < 25)) + siop_target->id |= SCNTL3_ULTRA << 24; + + siop_target->id |= (offset & 0xff) << 8; + + if (tables->msg_in[6] == MSG_EXT_WDTR_BUS_16_BIT) { + siop_target->flags |= TARF_ISWIDE; + sc->targets[target]->id |= (SCNTL3_EWS << 24); + } + +#ifdef DEBUG + printf("%s: siop_ppr_neg: id now 0x%x, flags is now 0x%x\n", + sc->sc_dev.dv_xname, siop_target->id, siop_target->flags); +#endif + tables->id = htole32(siop_target->id); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, + (siop_target->id >> 24) & 0xff); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, + (siop_target->id >> 8) & 0xff); + /* Only cards with SCNTL4 can cause PPR negotiations, so ... */ + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, + (siop_target->id & 0xff)); + + siop_target->status = TARST_OK; + siop_print_info(sc, target); + + return (SIOP_NEG_ACK); +} + +int siop_wdtr_neg(siop_cmd) struct siop_cmd *siop_cmd; { @@ -181,17 +265,17 @@ siop_wdtr_neg(siop_cmd) int target = siop_cmd->xs->sc_link->target; struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; - /* revert to async until told otherwise */ - sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); - sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); - sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); + /* revert to narrow async until told otherwise */ + sc->targets[target]->id &= 0x07ff0000; /* Keep SCNTL3.CCF and id */ + sc->targets[target]->flags &= ~(TARF_ISWIDE | TARF_ISDT | TARF_ISQAS | TARF_ISIUS); 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); + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0); + if (sc->features & SF_CHIP_C10) + bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0); if (siop_target->status == TARST_WIDE_NEG) { /* we initiated wide negotiation */ @@ -229,7 +313,7 @@ siop_wdtr_neg(siop_cmd) /* we now need to do sync */ if (siop_target->flags & TARF_SYNC) { siop_target->status = TARST_SYNC_NEG; - siop_sdtr_msg(siop_cmd, 0, sc->minsync, sc->maxoff); + siop_sdtr_msg(siop_cmd, 0, sc->min_st_sync, sc->maxoff); return SIOP_NEG_MSGOUT; } else { siop_target->status = TARST_OK; @@ -269,7 +353,7 @@ siop_sdtr_neg(siop_cmd) struct siop_softc *sc = siop_cmd->siop_sc; struct siop_target *siop_target = siop_cmd->siop_target; int target = siop_cmd->xs->sc_link->target; - int sync, offset, i; + int sync, offset, scf; int send_msgout = 0; struct siop_xfer_common *tables = &siop_cmd->siop_xfer->tables; @@ -277,35 +361,23 @@ siop_sdtr_neg(siop_cmd) offset = tables->msg_in[4]; /* revert to async until told otherwise */ - sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24); - sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24); - sc->targets[target]->id &= ~(SXFER_MO_MASK << 8); + 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("sdtr: sync %d offset %d\n", sync, offset); + printf("%s: sdtr for target %d: sync %d offset %d\n", + sc->sc_dev.dv_xname, target, sync, offset); #endif - if (offset > sc->maxoff || sync < sc->minsync || - sync > sc->maxsync) + scf = siop_period_factor_to_scf(sc, sync, sc->targets[target]->flags); + if (offset > sc->maxoff || scf == 0) goto reject; - for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); - i++) { - if (sc->clock_period != scf_period[i].clock) - continue; - if (scf_period[i].period == sync) { - /* ok, found it. we now are sync. */ - sc->targets[target]->id |= scf_period[i].scf - << (24 + SCNTL3_SCF_SHIFT); - if ((sync < 25) - && ((sc->features & SF_CHIP_C10) == 0)) - sc->targets[target]->id |= - SCNTL3_ULTRA << 24; - sc->targets[target]->id |= - (offset & SXFER_MO_MASK) << 8; - goto end; - } - } + 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. @@ -316,37 +388,30 @@ reject: 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 - || sync > sc->maxsync) { + || scf == 0) { goto async; } + if ((offset > 31) && ((sc->targets[target]->flags & TARF_ISDT) == 0)) + offset = 31; if (offset > sc->maxoff) offset = sc->maxoff; - if (sync < sc->minsync) - sync = sc->minsync; - /* look for sync period */ - for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); - i++) { - if (sc->clock_period != scf_period[i].clock) - continue; - if (scf_period[i].period == sync) { - /* ok, found it. we now are sync. */ - sc->targets[target]->id |= scf_period[i].scf - << (24 + SCNTL3_SCF_SHIFT); - if ((sync < 25) - && ((sc->features & SF_CHIP_C10) == 0)) - sc->targets[target]->id |= - SCNTL3_ULTRA << 24; - sc->targets[target]->id |= - (offset & SXFER_MO_MASK) << 8; - siop_sdtr_msg(siop_cmd, 0, sync, offset); - send_msgout = 1; - goto end; - } - } + + 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; @@ -374,6 +439,40 @@ end: } void +siop_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); +} + +void siop_sdtr_msg(siop_cmd, offset, ssync, soff) struct siop_cmd *siop_cmd; int offset; @@ -383,6 +482,10 @@ siop_sdtr_msg(siop_cmd, offset, ssync, soff) 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); @@ -585,30 +688,62 @@ siop_print_info(sc, target) { struct siop_target *siop_target = sc->targets[target]; u_int8_t scf, offset; - int clock, i; + int scf_index, i; + + const int factors = sizeof(period_factor) / sizeof(period_factor[0]); + + offset = ((siop_target->id >> 8) & 0xff) >> SXFER_MO_SHIFT; - offset = ((siop_target->id >> 8) & SXFER_MO_MASK) >> SXFER_MO_SHIFT; scf = ((siop_target->id >> 24) & SCNTL3_SCF_MASK) >> SCNTL3_SCF_SHIFT; - clock = sc->clock_period; + scf_index = sc->scf_index; - printf("%s: target %d now using%s%d bit ", + 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_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); if (offset == 0) printf("async "); - else { - for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) - if ((scf_period[i].clock == clock) - && (scf_period[i].scf == scf)) { - printf("%s ", scf_period[i].rate); - break; + else { + for (i = 0; i < factors; i++) + if (siop_target->flags & TARF_ISDT) { + if (period_factor[i].scf[scf_index].dt_scf == scf) + break; } - if (i == sizeof(scf_period) / sizeof(scf_period[0])) - printf("? "); + 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"); } + +int +siop_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); +} diff --git a/sys/dev/ic/siopreg.h b/sys/dev/ic/siopreg.h index dc02816b7c4..c7bfde8e2a8 100644 --- a/sys/dev/ic/siopreg.h +++ b/sys/dev/ic/siopreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: siopreg.h,v 1.2 2001/03/10 05:04:06 krw Exp $ */ +/* $OpenBSD: siopreg.h,v 1.3 2001/04/15 06:01:29 krw Exp $ */ /* $NetBSD: siopreg.h,v 1.7 2000/10/06 16:35:13 bouyer Exp $ */ /* @@ -74,28 +74,49 @@ #define SCNTL3_CCF_SHIFT 0 #define SCNTL3_CCF_MASK 0x07 -/* periods for various SCF values, assume transfer period of 4 */ -struct scf_period { - int clock; /* clock period (ns * 10) */ - int period; /* scsi period, as set in the SDTR message */ - int scf; /* scf value to use */ - char *rate; /* the resulting rate */ +#define SIOP_CLOCKS_SUPPORTED 3 /* 3 supported clocks: 25, 12.5, 6.25 ns */ + +struct period_factor { + int factor; /* transfer period factor from sdtr/ppr */ + char *rate; /* string describing transfer rate */ + struct { + int st_scf; + int dt_scf; + } scf[SIOP_CLOCKS_SUPPORTED]; + /* scf value to use in SCNTL3[6:4] + * 0 == SCLK/3 + * 1 == SCLK/1 + * 2 == SCLK/1.5 + * 3 == SCLK/2 + * 4 == SCLK/3 + * 5 == SCLK/4 + * 6 == SCLK/6 + * 7 == SCLK/8 + * + * One entry for each different clock + * supported, showing appropriate scf + * for the period_factor requested. A + * value of 0 indicates the rate is + * not supported. + * + * scf[0] == scf for a 25ns cycle + * scf[1] == scf for a 12.5 ns cycle + * scf[2] == scf for a 6.25 ns cycle + * + * min sync = first non zero in column + * max sync = last non zero in column + */ }; -static const struct scf_period scf_period[] __attribute__((__unused__)) = { - {250, 25, 1, "10.0"}, - {250, 37, 2, "6.67"}, - {250, 50, 3, "5.0"}, - {250, 75, 4, "3.33"}, - {125, 12, 1, "20.0"}, - {125, 18, 2, "13.33"}, - {125, 25, 3, "10.0"}, - {125, 37, 4, "6.67"}, - {125, 50, 5, "5.0"}, - { 62, 10, 1, "40.0"}, - { 62, 12, 3, "20.0"}, - { 62, 18, 4, "13.3"}, - { 62, 25, 5, "10.0"}, +static const struct period_factor period_factor[] __attribute__((__unused__)) = { + {0x09, "80", {{0,0},{0,0},{0,1}}}, + {0x0a, "40", {{0,0},{0,0},{1,3}}}, + {0x0c, "20", {{0,0},{1,0},{3,5}}}, + {0x12, "13.3", {{0,0},{2,0},{4,6}}}, + {0x19, "10", {{1,0},{3,0},{5,7}}}, + {0x25, "6.67", {{2,0},{4,0},{6,0}}}, + {0x32, "5", {{3,0},{5,0},{7,0}}}, + {0x4b, "3.33", {{4,0},{6,0},{0,0}}}, }; #define SIOP_SCID 0x04 /* SCSI chip ID R/W */ @@ -108,7 +129,7 @@ static const struct scf_period scf_period[] __attribute__((__unused__)) = { #define SXFER_TP_SHIFT 5 #define SXFER_TP_MASK 0xe0 #define SXFER_MO_SHIFT 0 -#define SXFER_MO_MASK 0x1f +#define SXFER_MO_MASK 0x1f #define SIOP_SDID 0x06 /* SCSI destiation ID, R/W */ #define SDID_ENCID_SHIFT 0 @@ -376,4 +397,8 @@ static const struct scf_period scf_period[] __attribute__((__unused__)) = { #define SIOP_SCRATCHJ 0x7c /* Scratch register J, R/W, 875-only */ +#define SIOP_SCNTL4 0xbc +#define SCNTL4_ULTRA3 0x80 +#define SCNTL4_AIP 0x40 + #define SIOP_DFBC 0xf0 /* DMA FIFO byte count, RO, C10-only */ diff --git a/sys/dev/ic/siopvar.h b/sys/dev/ic/siopvar.h index b5ca1393cb1..e61fd9730b6 100644 --- a/sys/dev/ic/siopvar.h +++ b/sys/dev/ic/siopvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: siopvar.h,v 1.3 2001/03/10 05:04:06 krw Exp $ */ +/* $OpenBSD: siopvar.h,v 1.4 2001/04/15 06:01:29 krw Exp $ */ /* $NetBSD: siopvar.h,v 1.13 2000/10/23 23:18:11 bouyer Exp $ */ /* @@ -46,9 +46,9 @@ struct siop_softc { int maxburst; int maxoff; int clock_div; /* async. clock divider (scntl3) */ - int clock_period; /* clock period (ns * 10) */ - int minsync; /* min and max sync period, */ - int maxsync; /* as sent in SDTR message */ + int min_dt_sync; /* minimum acceptable double transition sync */ + int min_st_sync; /* minimum acceptable single transition sync */ + int scf_index; /* clock id == index into period_factor[].scf */ bus_space_tag_t sc_rt; /* bus_space registers tag */ bus_space_handle_t sc_rh; /* bus_space registers handle */ bus_addr_t sc_raddr; /* register adresses */ diff --git a/sys/dev/ic/siopvar_common.h b/sys/dev/ic/siopvar_common.h index 565618cd043..f02c2d4127c 100644 --- a/sys/dev/ic/siopvar_common.h +++ b/sys/dev/ic/siopvar_common.h @@ -1,4 +1,4 @@ -/* $OpenBSD: siopvar_common.h,v 1.3 2001/03/06 16:29:32 krw Exp $ */ +/* $OpenBSD: siopvar_common.h,v 1.4 2001/04/15 06:01:29 krw Exp $ */ /* $NetBSD: siopvar_common.h,v 1.10 2001/01/26 21:58:56 bouyer Exp $ */ /* @@ -57,22 +57,22 @@ typedef struct scr_table { * transfer. */ struct siop_xfer_common { - u_int8_t msg_out[8]; /* 0 */ - u_int8_t msg_in[8]; /* 8 */ - u_int32_t status; /* 16 */ - u_int32_t pad1; /* 20 */ - u_int32_t id; /* 24 */ - u_int32_t pad2; /* 28 */ - scr_table_t t_msgin; /* 32 */ - scr_table_t t_extmsgin; /* 40 */ - scr_table_t t_extmsgdata; /* 48 */ - scr_table_t t_msgout; /* 56 */ - scr_table_t cmd; /* 64 */ - scr_table_t t_status; /* 72 */ - scr_table_t data[SIOP_NSG]; /* 80 */ + u_int8_t msg_out[16]; /* 0 */ + u_int8_t msg_in[16]; /* 16 */ + u_int32_t status; /* 32 */ + u_int32_t pad1; /* 36 */ + u_int32_t id; /* 40 */ + u_int32_t pad2; /* 44 */ + scr_table_t t_msgin; /* 48 */ + scr_table_t t_extmsgin; /* 56 */ + scr_table_t t_extmsgdata; /* 64 */ + scr_table_t t_msgout; /* 72 */ + scr_table_t cmd; /* 80 */ + scr_table_t t_status; /* 88 */ + scr_table_t data[SIOP_NSG]; /* 96 */ } __attribute__((__packed__)); -/* status can hold the SCSI_* status values, and 2 additionnal values: */ +/* status can hold the SCSI_* status values, and 2 additional values: */ #define SCSI_SIOP_NOCHECK 0xfe /* don't check the scsi status */ #define SCSI_SIOP_NOSTATUS 0xff /* device didn't report status */ @@ -146,7 +146,12 @@ struct siop_lun { struct siop_target { int status; /* target status, see below */ int flags; /* target flags, see below */ - u_int32_t id; /* for SELECT FROM */ + u_int32_t id; /* for SELECT FROM + * 31-24 == SCNTL3 + * 23-16 == SCSI id + * 15- 8 == SXFER + * 7- 0 == SCNTL4 + */ struct siop_lun *siop_lun[8]; /* per-lun state */ u_int reseloff; /* XXX */ struct siop_lunsw *lunsw; /* XXX */ @@ -157,13 +162,19 @@ struct siop_target { #define TARST_ASYNC 1 /* target needs sync/wide negotiation */ #define TARST_WIDE_NEG 2 /* target is doing wide negotiation */ #define TARST_SYNC_NEG 3 /* target is doing sync negotiation */ -#define TARST_OK 4 /* sync/wide agreement is valid */ +#define TARST_PPR_NEG 4 /* target is doing PPR (Parallel Protocol Request) */ +#define TARST_OK 5 /* sync/wide agreement is valid */ /* target flags */ -#define TARF_SYNC 0x01 /* target can do sync */ -#define TARF_WIDE 0x02 /* target can do wide */ -#define TARF_TAG 0x04 /* target can do tags */ -#define TARF_ISWIDE 0x08 /* target is wide */ +#define TARF_SYNC 0x01 /* target can do sync xfers */ +#define TARF_WIDE 0x02 /* target can do wide xfers */ +#define TARF_TAG 0x04 /* target can do taggged queuing */ +#define TARF_PPR 0x08 /* target can do PPR negotiation */ + +#define TARF_ISWIDE 0x10 /* target is using wide xfers */ +#define TARF_ISIUS 0x20 /* target is using IUS */ +#define TARF_ISDT 0x40 /* target is using DT */ +#define TARF_ISQAS 0x80 /* target is using QAS */ struct siop_lunsw { TAILQ_ENTRY (siop_lunsw) next; @@ -177,7 +188,7 @@ siop_table_sync(siop_cmd, ops) struct siop_cmd *siop_cmd; int ops; { - struct siop_softc *sc = siop_cmd->siop_sc; + struct siop_softc *sc = siop_cmd->siop_sc; bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, ops); } @@ -187,18 +198,26 @@ int siop_modechange __P((struct siop_softc *)); int siop_wdtr_neg __P((struct siop_cmd *)); int siop_sdtr_neg __P((struct siop_cmd *)); +int siop_ppr_neg __P((struct siop_cmd *)); void siop_sdtr_msg __P((struct siop_cmd *, int, int, int)); void siop_wdtr_msg __P((struct siop_cmd *, int, int)); -/* actions to take at return of siop_wdtr_neg() and siop_sdtr_neg() */ +void siop_ppr_msg __P((struct siop_cmd *, int, int, int)); + +/* actions to take at return of siop_<xxx>_neg() */ #define SIOP_NEG_NOP 0x0 #define SIOP_NEG_MSGOUT 0x1 #define SIOP_NEG_ACK 0x2 +#define SIOP_NEG_MSGREJ 0x3 void siop_print_info __P((struct siop_softc *, int)); void siop_minphys __P((struct buf *)); void siop_sdp __P((struct siop_cmd *)); void siop_clearfifo __P((struct siop_softc *)); void siop_resetbus __P((struct siop_softc *)); + +int siop_period_factor_to_scf __P((struct siop_softc *, int, int)); +int siop_scf_to_period_factor __P((struct siop_softc *, int, int)); + /* XXXX should be callbacks */ void siop_add_dev __P((struct siop_softc *, int, int)); void siop_del_dev __P((struct siop_softc *, int, int)); |