summaryrefslogtreecommitdiff
path: root/sys/dev/ic/siop_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/siop_common.c')
-rw-r--r--sys/dev/ic/siop_common.c279
1 files changed, 207 insertions, 72 deletions
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);
+}