summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorbouyer <bouyer@NetBSD.org>2002-04-25 19:34:02 +0000
committerbouyer <bouyer@NetBSD.org>2002-04-25 19:34:02 +0000
commitf66f6c27a67c4500b80a50d607b02da81e8b274a (patch)
tree3060e12442552f7606fb76249905f431b0767efb /sys/dev
parentf53d9a4fa78d36d069cb3d2077be9a7debe9bfcd (diff)
- We can't share the per-lun DSA entry for untagged and tag table DSA;
there may be tagged commands still running when we queue a request sense command. Solve this by using 2 DSA entry per LUN - Now that we have the command DSA before select, we can load T/L/Q in SCRATCHC. This makes the selection timeout handler simpler. - Avoid a race condition when setting the free flag in the cmd ring (see comment in the script) - don't forget to update the ID in the head of LUN table after a sync/wide negotiation. This fixes the command timeout at the first data command after negotiation (the bus reset handler did update the ID properly, so subsequent commands were OK). - for DMA interrupts, clear fifo if it's not empty. Leaving the fifo dirty would prevent subsequent interrupts from coming in. - Various improvements in debug messages - misc cleanups.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/esiop.c278
-rw-r--r--sys/dev/ic/esiopvar.h3
-rw-r--r--sys/dev/microcode/siop/esiop.ss28
3 files changed, 165 insertions, 144 deletions
diff --git a/sys/dev/ic/esiop.c b/sys/dev/ic/esiop.c
index 7fce56b340f..1175e44e693 100644
--- a/sys/dev/ic/esiop.c
+++ b/sys/dev/ic/esiop.c
@@ -1,4 +1,4 @@
-/* $NetBSD: esiop.c,v 1.8 2002/04/24 09:43:14 bouyer Exp $ */
+/* $NetBSD: esiop.c,v 1.9 2002/04/25 19:34:02 bouyer Exp $ */
/*
* Copyright (c) 2002 Manuel Bouyer.
@@ -33,7 +33,7 @@
/* SYM53c7/8xx PCI-SCSI I/O Processors driver */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: esiop.c,v 1.8 2002/04/24 09:43:14 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: esiop.c,v 1.9 2002/04/25 19:34:02 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -94,10 +94,10 @@ void esiop_dump_script __P((struct esiop_softc *));
void esiop_morecbd __P((struct esiop_softc *));
void esiop_moretagtbl __P((struct esiop_softc *));
void siop_add_reselsw __P((struct esiop_softc *, int));
-struct esiop_cmd * esiop_cmd_find __P((struct esiop_softc *, int, u_int32_t));
void esiop_target_register __P((struct esiop_softc *, u_int32_t));
-static int nintr = 0;
+void esiop_update_scntl3 __P((struct esiop_softc *,
+ struct siop_common_target *));
#ifdef SIOP_STATS
static int esiop_stat_intr = 0;
@@ -369,32 +369,37 @@ esiop_intr(v)
u_int32_t tflags;
u_int32_t addr;
int freetarget = 0;
- int restart = 0;
int slot;
int retval = 0;
again:
istat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT);
if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0) {
- if (istat & ISTAT_SEM) {
- bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
- SIOP_ISTAT, (istat & ~ISTAT_SEM));
- esiop_checkdone(sc);
- }
return retval;
}
retval = 1;
- nintr++;
- if (nintr > 100) {
- panic("esiop: intr loop");
- }
INCSTAT(esiop_stat_intr);
if (istat & ISTAT_INTF) {
bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
SIOP_ISTAT, ISTAT_INTF);
esiop_checkdone(sc);
+ if (sc->sc_flags & SCF_CHAN_NOSLOT) {
+ /*
+ * at last one command terminated,
+ * so we should have free slots now
+ */
+ sc->sc_flags &= ~SCF_CHAN_NOSLOT;
+ scsipi_channel_thaw(&sc->sc_c.sc_chan, 1);
+ }
goto again;
}
+
+ if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
+ (ISTAT_DIP | ISTAT_ABRT)) {
+ bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
+ SIOP_ISTAT, 0);
+ }
+
/* get CMD from T/L/Q */
tflags = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
SIOP_SCRATCHC);
@@ -480,13 +485,15 @@ none:
printf(" parity");
if (dstat & DSTAT_DFE)
printf(" dma fifo empty");
+ else
+ siop_clearfifo(&sc->sc_c);
printf(", DSP=0x%x DSA=0x%x: ",
(int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
SIOP_DSP) - sc->sc_c.sc_scriptaddr),
bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA));
if (esiop_cmd)
- printf("last msg_in=0x%x status=0x%x\n",
- esiop_cmd->cmd_tables->msg_in[0],
+ printf("T/L/Q=%d/%d/%d last msg_in=0x%x status=0x%x\n",
+ target, lun, tag, esiop_cmd->cmd_tables->msg_in[0],
le32toh(esiop_cmd->cmd_tables->status));
else
printf(" current T/L/Q invalid\n");
@@ -595,21 +602,17 @@ none:
goto reset;
}
if ((sist & (SIST1_STO << 8)) && need_reset == 0) {
- /* selection time out, assume there's no device here */
/*
- * SCRATCHC has not been loaded yet, we have to find
- * params by ourselve. scratchE0 should point to
- * the slot.
+ * selection time out, assume there's no device here
+ * We also have to update the ring pointer ourselve
*/
slot = bus_space_read_1(sc->sc_c.sc_rt,
sc->sc_c.sc_rh, SIOP_SCRATCHE);
esiop_script_sync(sc,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- target = bus_space_read_1(sc->sc_c.sc_rt,
- sc->sc_c.sc_rh, SIOP_SDID);
- esiop_cmd = esiop_cmd_find(sc, target,
- esiop_script_read(sc,
- sc->sc_shedoffset + slot * CMD_SLOTSIZE) & ~0x3);
+#ifdef SIOP_DEBUG_SCHED
+ printf("sel timeout target %d, slot %d\n", target, slot);
+#endif
/*
* mark this slot as free, and advance to next slot
*/
@@ -633,12 +636,6 @@ none:
esiop_script_sync(sc,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
if (esiop_cmd) {
- xs = esiop_cmd->cmd_c.xs;
- esiop_target = (struct esiop_target *)
- esiop_cmd->cmd_c.siop_target;
- lun = xs->xs_periph->periph_lun;
- tag = esiop_cmd->cmd_c.tag;
- esiop_lun = esiop_target->esiop_lun[lun];
esiop_cmd->cmd_c.status = CMDST_DONE;
xs->error = XS_SELTIMEOUT;
freetarget = 1;
@@ -899,53 +896,65 @@ scintr:
if (esiop_cmd->cmd_tables->msg_in[2] == MSG_EXT_PPR) {
switch (siop_ppr_neg(&esiop_cmd->cmd_c)) {
case SIOP_NEG_MSGOUT:
+ esiop_update_scntl3(sc,
+ esiop_cmd->cmd_c.siop_target);
esiop_table_sync(esiop_cmd,
BUS_DMASYNC_PREREAD |
BUS_DMASYNC_PREWRITE);
CALL_SCRIPT(Ent_send_msgout);
- return(1);
+ return 1;
case SIOP_NEG_ACK:
+ esiop_update_scntl3(sc,
+ esiop_cmd->cmd_c.siop_target);
CALL_SCRIPT(Ent_msgin_ack);
- return(1);
+ return 1;
default:
panic("invalid retval from "
"siop_wdtr_neg()");
}
- return(1);
+ return 1;
}
if (esiop_cmd->cmd_tables->msg_in[2] == MSG_EXT_WDTR) {
switch (siop_wdtr_neg(&esiop_cmd->cmd_c)) {
case SIOP_NEG_MSGOUT:
+ esiop_update_scntl3(sc,
+ esiop_cmd->cmd_c.siop_target);
esiop_table_sync(esiop_cmd,
BUS_DMASYNC_PREREAD |
BUS_DMASYNC_PREWRITE);
CALL_SCRIPT(Ent_send_msgout);
- return(1);
+ return 1;
case SIOP_NEG_ACK:
+ esiop_update_scntl3(sc,
+ esiop_cmd->cmd_c.siop_target);
CALL_SCRIPT(Ent_msgin_ack);
- return(1);
+ return 1;
default:
panic("invalid retval from "
"siop_wdtr_neg()");
}
- return(1);
+ return 1;
}
if (esiop_cmd->cmd_tables->msg_in[2] == MSG_EXT_SDTR) {
switch (siop_sdtr_neg(&esiop_cmd->cmd_c)) {
case SIOP_NEG_MSGOUT:
+ esiop_update_scntl3(sc,
+ esiop_cmd->cmd_c.siop_target);
esiop_table_sync(esiop_cmd,
BUS_DMASYNC_PREREAD |
BUS_DMASYNC_PREWRITE);
CALL_SCRIPT(Ent_send_msgout);
- return(1);
+ return 1;
case SIOP_NEG_ACK:
+ esiop_update_scntl3(sc,
+ esiop_cmd->cmd_c.siop_target);
CALL_SCRIPT(Ent_msgin_ack);
- return(1);
+ return 1;
default:
panic("invalid retval from "
"siop_wdtr_neg()");
}
- return(1);
+ return 1;
}
/* send a message reject */
esiop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
@@ -983,7 +992,7 @@ scintr:
case A_int_resfail:
printf("reselect failed\n");
CALL_SCRIPT(Ent_script_sched);
- return 1;
+ return 1;
case A_int_done:
if (xs == NULL) {
printf("%s: done without command\n",
@@ -1024,10 +1033,6 @@ end:
#ifdef SIOP_DEBUG_INTR
printf("esiop_intr end: status %d\n", xs->status);
#endif
- if (xs->status == SCSI_OK)
- CALL_SCRIPT(Ent_script_sched);
- else
- restart = 1;
if (tag >= 0)
esiop_lun->tactive[tag] = NULL;
else
@@ -1035,15 +1040,14 @@ end:
esiop_scsicmd_end(esiop_cmd);
if (freetarget && esiop_target->target_c.status == TARST_PROBING)
esiop_del_dev(sc, target, lun);
- if (restart)
- CALL_SCRIPT(Ent_script_sched);
+ CALL_SCRIPT(Ent_script_sched);
if (sc->sc_flags & SCF_CHAN_NOSLOT) {
/* a command terminated, so we have free slots now */
sc->sc_flags &= ~SCF_CHAN_NOSLOT;
scsipi_channel_thaw(&sc->sc_c.sc_chan, 1);
}
- return retval;
+ return 1;
}
void
@@ -1181,22 +1185,22 @@ esiop_unqueue(sc, target, lun)
for (slot = 0; slot < A_ncmd_slots; slot++) {
slotdsa = esiop_script_read(sc,
sc->sc_shedoffset + slot * CMD_SLOTSIZE);
- if (slotdsa & A_f_cmd_free)
- continue;
- if ((slotdsa & ~A_f_cmd_free) == esiop_cmd->cmd_c.dsa)
+ /* if the slot has any flag, it won't match the DSA */
+ if (slotdsa == esiop_cmd->cmd_c.dsa) { /* found it */
+ /* Mark this slot as ignore */
+ esiop_script_write(sc,
+ sc->sc_shedoffset + slot * CMD_SLOTSIZE,
+ esiop_cmd->cmd_c.dsa | A_f_cmd_ignore);
+ /* ask to requeue */
+ esiop_cmd->cmd_c.xs->error = XS_REQUEUE;
+ esiop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
+ esiop_lun->tactive[tag] = NULL;
+ esiop_scsicmd_end(esiop_cmd);
break;
+ }
}
- if (slot > ESIOP_NTAG)
- continue; /* didn't find it */
- /* Mark this slot as ignore */
- esiop_script_write(sc, sc->sc_shedoffset + slot * CMD_SLOTSIZE,
- esiop_cmd->cmd_c.dsa | A_f_cmd_ignore);
- /* ask to requeue */
- esiop_cmd->cmd_c.xs->error = XS_REQUEUE;
- esiop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
- esiop_lun->tactive[tag] = NULL;
- esiop_scsicmd_end(esiop_cmd);
}
+ esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
/*
@@ -1236,9 +1240,9 @@ esiop_handle_qtag_reject(esiop_cmd)
esiop_cmd->cmd_c.flags &= ~CMDFL_TAG;
esiop_cmd->cmd_c.tag = -1;
/* update DSA table */
- esiop_script_write(sc, esiop_target->lun_table_offset + lun + 2,
+ esiop_script_write(sc, esiop_target->lun_table_offset +
+ lun * 2 + A_target_luntbl / sizeof(u_int32_t),
esiop_cmd->cmd_c.dsa);
- esiop_lun->lun_flags &= ~LUNF_TAGTABLE;
esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
return 0;
}
@@ -1263,6 +1267,7 @@ esiop_handle_reset(sc)
printf("%s: scsi bus reset\n", sc->sc_c.sc_dev.dv_xname);
/* stop, reset and restart the chip */
esiop_reset(sc);
+
if (sc->sc_flags & SCF_CHAN_NOSLOT) {
/* chip has been reset, all slots are free now */
sc->sc_flags &= ~SCF_CHAN_NOSLOT;
@@ -1341,7 +1346,8 @@ esiop_scsipi_request(chan, req, arg)
s = splbio();
#ifdef SIOP_DEBUG_SCHED
- printf("starting cmd for %d:%d\n", target, lun);
+ printf("starting cmd for %d:%d tag %d(%d)\n", target, lun,
+ xs->xs_tag_type, xs->xs_tag_id);
#endif
esiop_cmd = TAILQ_FIRST(&sc->free_list);
if (esiop_cmd == NULL) {
@@ -1486,8 +1492,17 @@ esiop_scsipi_request(chan, req, arg)
if (sc->sc_c.targets[xm->xm_target] == NULL)
return;
s = splbio();
- if (xm->xm_mode & PERIPH_CAP_TQING)
+ if ((xm->xm_mode & PERIPH_CAP_TQING) &&
+ (sc->sc_c.targets[xm->xm_target]->flags & TARF_TAG) == 0) {
sc->sc_c.targets[xm->xm_target]->flags |= TARF_TAG;
+ /* allocate tag tables for this device */
+ for (lun = 0;
+ lun < sc->sc_c.sc_chan.chan_nluns; lun++) {
+ if (sc->sc_c.sc_chan.chan_periphs[
+ xm->xm_target][lun])
+ esiop_add_dev(sc, xm->xm_target, lun);
+ }
+ }
if ((xm->xm_mode & PERIPH_CAP_WIDE16) &&
(sc->sc_c.features & SF_BUS_WIDE))
sc->sc_c.targets[xm->xm_target]->flags |= TARF_WIDE;
@@ -1501,11 +1516,6 @@ esiop_scsipi_request(chan, req, arg)
sc->sc_c.targets[xm->xm_target]->status == TARST_PROBING)
sc->sc_c.targets[xm->xm_target]->status = TARST_ASYNC;
- for (lun = 0; lun < sc->sc_c.sc_chan.chan_nluns; lun++) {
- if (sc->sc_c.sc_chan.chan_periphs[xm->xm_target][lun])
- /* allocate a lun sw entry for this device */
- esiop_add_dev(sc, xm->xm_target, lun);
- }
splx(s);
}
}
@@ -1521,8 +1531,6 @@ esiop_start(sc, esiop_cmd)
int timeout;
int target, lun, slot;
- nintr = 0;
-
/*
* first make sure to read valid data
*/
@@ -1578,15 +1586,10 @@ esiop_start(sc, esiop_cmd)
esiop_cmd->cmd_c.status = CMDST_ACTIVE;
else
panic("esiop_start: bad status");
+ /* DSA table for reselect */
if (esiop_cmd->cmd_c.flags & CMDFL_TAG) {
esiop_lun->tactive[esiop_cmd->cmd_c.tag] = esiop_cmd;
/* DSA table for reselect */
- if ((esiop_lun->lun_flags & LUNF_TAGTABLE) == 0) {
- esiop_script_write(sc,
- esiop_target->lun_table_offset + lun + 2,
- esiop_lun->lun_tagtbl->tbl_dsa);
- esiop_lun->lun_flags |= LUNF_TAGTABLE;
- }
esiop_lun->lun_tagtbl->tbl[esiop_cmd->cmd_c.tag] =
htole32(esiop_cmd->cmd_c.dsa);
bus_dmamap_sync(sc->sc_c.sc_dmat,
@@ -1595,15 +1598,16 @@ esiop_start(sc, esiop_cmd)
sizeof(u_int32_t) * ESIOP_NTAG, BUS_DMASYNC_PREWRITE);
} else {
esiop_lun->active = esiop_cmd;
- /* DSA table for reselect */
- esiop_script_write(sc, esiop_target->lun_table_offset + lun + 2,
+ esiop_script_write(sc,
+ esiop_target->lun_table_offset +
+ lun * 2 + A_target_luntbl / sizeof(u_int32_t),
esiop_cmd->cmd_c.dsa);
- esiop_lun->lun_flags &= ~LUNF_TAGTABLE;
-
}
/* scheduler slot: DSA */
esiop_script_write(sc, sc->sc_shedoffset + slot * CMD_SLOTSIZE,
esiop_cmd->cmd_c.dsa);
+ /* make sure SCRIPT processor will read valid data */
+ esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/* handle timeout */
if ((esiop_cmd->cmd_c.xs->xs_control & XS_CTL_POLL) == 0) {
/* start exire timer */
@@ -1613,8 +1617,6 @@ esiop_start(sc, esiop_cmd)
callout_reset( &esiop_cmd->cmd_c.xs->xs_callout,
timeout, esiop_timeout, esiop_cmd);
}
- /* make sure SCRIPT processor will read valid data */
- esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/* Signal script it has some work to do */
bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
SIOP_ISTAT, ISTAT_SIGP);
@@ -1633,11 +1635,34 @@ esiop_timeout(v)
struct esiop_softc *sc =
(struct esiop_softc *)esiop_cmd->cmd_c.siop_sc;
int s;
+#ifdef SIOP_DEBUG
+ int slot, slotdsa;
+#endif
+ s = splbio();
+ esiop_table_sync(esiop_cmd,
+ BUS_DMASYNC_POSTREAD |
+ BUS_DMASYNC_POSTWRITE);
scsipi_printaddr(esiop_cmd->cmd_c.xs->xs_periph);
- printf("command timeout\n");
+#ifdef SIOP_DEBUG
+ printf("command timeout (status %d)\n", le32toh(esiop_cmd->cmd_tables->status));
- s = splbio();
+ esiop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ for (slot = 0; slot < A_ncmd_slots; slot++) {
+ slotdsa = esiop_script_read(sc,
+ sc->sc_shedoffset + slot * CMD_SLOTSIZE);
+ if ((slotdsa & 0x01) == 0)
+ printf("slot %d not free (0x%x)\n", slot, slotdsa);
+ }
+ printf("istat 0x%x ", bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT));
+ printf("DSP 0x%lx DSA 0x%x\n",
+ (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr),
+ bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA));
+ bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_CTEST2);
+ printf("istat 0x%x\n", bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT));
+#else
+ printf("command timeout\n");
+#endif
/* reset the scsi bus */
siop_resetbus(&sc->sc_c);
@@ -1892,6 +1917,16 @@ bad3:
}
void
+esiop_update_scntl3(sc, _siop_target)
+ struct esiop_softc *sc;
+ struct siop_common_target *_siop_target;
+{
+ struct esiop_target *esiop_target = (struct esiop_target *)_siop_target;
+ esiop_script_write(sc, esiop_target->lun_table_offset,
+ esiop_target->target_c.id);
+}
+
+void
esiop_add_dev(sc, target, lun)
struct esiop_softc *sc;
int target;
@@ -1901,21 +1936,23 @@ esiop_add_dev(sc, target, lun)
(struct esiop_target *)sc->sc_c.targets[target];
struct esiop_lun *esiop_lun = esiop_target->esiop_lun[lun];
- if (esiop_target->target_c.flags & TARF_TAG) {
- /* we need a tag DSA table */
+ /* we need a tag DSA table */
+ esiop_lun->lun_tagtbl= TAILQ_FIRST(&sc->free_tagtbl);
+ if (esiop_lun->lun_tagtbl == NULL) {
+ esiop_moretagtbl(sc);
esiop_lun->lun_tagtbl= TAILQ_FIRST(&sc->free_tagtbl);
if (esiop_lun->lun_tagtbl == NULL) {
- esiop_moretagtbl(sc);
- esiop_lun->lun_tagtbl= TAILQ_FIRST(&sc->free_tagtbl);
- if (esiop_lun->lun_tagtbl == NULL) {
- /* no resources, run untagged */
- esiop_target->target_c.flags &= ~TARF_TAG;
- return;
- }
+ /* no resources, run untagged */
+ esiop_target->target_c.flags &= ~TARF_TAG;
+ return;
}
- TAILQ_REMOVE(&sc->free_tagtbl, esiop_lun->lun_tagtbl, next);
-
}
+ TAILQ_REMOVE(&sc->free_tagtbl, esiop_lun->lun_tagtbl, next);
+ /* Update LUN DSA table */
+ esiop_script_write(sc, esiop_target->lun_table_offset +
+ lun * 2 + A_target_luntbl_tag / sizeof(u_int32_t),
+ esiop_lun->lun_tagtbl->tbl_dsa);
+ esiop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
void
@@ -1936,39 +1973,6 @@ esiop_del_dev(sc, target, lun)
esiop_target->esiop_lun[lun] = NULL;
}
-struct esiop_cmd *
-esiop_cmd_find(sc, target, dsa)
- struct esiop_softc *sc;
- int target;
- u_int32_t dsa;
-{
- int lun, tag;
- struct esiop_cmd *cmd;
- struct esiop_lun *esiop_lun;
- struct esiop_target *esiop_target =
- (struct esiop_target *)sc->sc_c.targets[target];
-
- if (esiop_target == NULL)
- return NULL;
-
- for (lun = 0; lun < sc->sc_c.sc_chan.chan_nluns; lun++) {
- esiop_lun = esiop_target->esiop_lun[lun];
- if (esiop_lun == NULL)
- continue;
- cmd = esiop_lun->active;
- if (cmd && cmd->cmd_c.dsa == dsa)
- return cmd;
- if (esiop_target->target_c.flags & TARF_TAG) {
- for (tag = 0; tag < ESIOP_NTAG; tag++) {
- cmd = esiop_lun->tactive[tag];
- if (cmd && cmd->cmd_c.dsa == dsa)
- return cmd;
- }
- }
- }
- return NULL;
-}
-
void
esiop_target_register(sc, target)
struct esiop_softc *sc;
@@ -1976,10 +1980,12 @@ esiop_target_register(sc, target)
{
struct esiop_target *esiop_target =
(struct esiop_target *)sc->sc_c.targets[target];
+ struct esiop_lun *esiop_lun;
+ int lun;
/* get a DSA table for this target */
esiop_target->lun_table_offset = sc->sc_free_offset;
- sc->sc_free_offset += sc->sc_c.sc_chan.chan_nluns + 2;
+ sc->sc_free_offset += sc->sc_c.sc_chan.chan_nluns * 2 + 2;
#ifdef SIOP_DEBUG
printf("%s: lun table for target %d offset %d free offset %d\n",
sc->sc_c.sc_dev.dv_xname, target, esiop_target->lun_table_offset,
@@ -1993,6 +1999,16 @@ esiop_target_register(sc, target)
sc->sc_target_table_offset + target,
(esiop_target->lun_table_offset * sizeof(u_int32_t)) +
sc->sc_c.sc_scriptaddr);
+ /* if we have a tag table, register it */
+ for (lun = 0; lun < sc->sc_c.sc_chan.chan_nluns; lun++) {
+ esiop_lun = esiop_target->esiop_lun[lun];
+ if (esiop_lun == NULL)
+ continue;
+ if (esiop_lun->lun_tagtbl)
+ esiop_script_write(sc, esiop_target->lun_table_offset +
+ lun * 2 + A_target_luntbl_tag / sizeof(u_int32_t),
+ esiop_lun->lun_tagtbl->tbl_dsa);
+ }
esiop_script_sync(sc,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
diff --git a/sys/dev/ic/esiopvar.h b/sys/dev/ic/esiopvar.h
index 87eb42c9e4e..fc0c21c8101 100644
--- a/sys/dev/ic/esiopvar.h
+++ b/sys/dev/ic/esiopvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: esiopvar.h,v 1.4 2002/04/24 09:43:14 bouyer Exp $ */
+/* $NetBSD: esiopvar.h,v 1.5 2002/04/25 19:34:02 bouyer Exp $ */
/*
* Copyright (c) 2002 Manuel Bouyer.
@@ -105,7 +105,6 @@ struct esiop_lun {
struct esiop_cmd *active; /* active non-tagged command */
struct esiop_cmd *tactive[ESIOP_NTAG]; /* active tagged commands */
int lun_flags; /* per-lun flags */
-#define LUNF_TAGTABLE 0x01 /* the LUN DSA points to the tag table */
struct esiop_dsatbl *lun_tagtbl; /* the tag DSA table */
};
diff --git a/sys/dev/microcode/siop/esiop.ss b/sys/dev/microcode/siop/esiop.ss
index 629735b960b..463cbc36402 100644
--- a/sys/dev/microcode/siop/esiop.ss
+++ b/sys/dev/microcode/siop/esiop.ss
@@ -1,4 +1,4 @@
-; $NetBSD: esiop.ss,v 1.9 2002/04/24 09:43:14 bouyer Exp $
+; $NetBSD: esiop.ss,v 1.10 2002/04/25 19:34:02 bouyer Exp $
;
; Copyright (c) 2002 Manuel Bouyer.
@@ -46,6 +46,7 @@ ABSOLUTE t_data = 96;
; offsets in the per-target lun table
ABSOLUTE target_id = 0x0;
ABSOLUTE target_luntbl = 0x8;
+ABSOLUTE target_luntbl_tag = 0xc;
;; interrupt codes
; interrupts that needs a valid target/lun/tag
@@ -146,11 +147,13 @@ nextisn:
MOVE SCRATCHC0 | f_c_lun to SCRATCHC0; save LUN
CLEAR ACK and CARRY;
MOVE SCRATCHC2 SHL SFBR;
- MOVE SFBR SHL SFBR; lun * 4
+ MOVE SFBR SHL SFBR;
+ MOVE SFBR SHL SFBR; lun * 8
MOVE DSA0 + SFBR TO DSA0;
MOVE DSA1 + 0x0 TO DSA1 with carry;
MOVE DSA2 + 0x0 TO DSA2 with carry;
MOVE DSA3 + 0x0 TO DSA3 with carry;
+ LOAD SCRATCHB0, 4, from target_luntbl_tag; in case it's a tagged cmd
LOAD DSA0, 4, from target_luntbl; load DSA for this LUN
JUMP REL(waitphase), WHEN NOT MSG_IN;
MOVE 1, abs_msgin2, WHEN MSG_IN;
@@ -161,6 +164,7 @@ nextisn:
MOVE SFBR to SCRATCHA2;
MOVE SFBR to SCRATCHC3;
MOVE SCRATCHC0 | f_c_tag to SCRATCHC0; save TAG
+ CALL REL(restoredsa); switch to tag table DSA
MOVE 0x0 to SCRATCHA3;
CLEAR CARRY;
MOVE SCRATCHA2 SHL SCRATCHA2;
@@ -194,12 +198,11 @@ script_sched:
MOVE SCRATCHD3 to SFBR;
MOVE SFBR to DSA3;
LOAD DSA0,4, from o_cmd_dsa; get DSA and flags for this slot
- MOVE DSA0 to SFBR; to avoid another load later
- MOVE SFBR to SCRATCHA0; to avoid another load later
MOVE DSA0 & f_cmd_free to SFBR; check flags
JUMP REL(no_cmd), IF NOT 0x0;
MOVE DSA0 & f_cmd_ignore to SFBR;
JUMP REL(ignore_cmd), IF NOT 0x0;
+ LOAD SCRATCHC0, 4, FROM tlq_offset;
; this slot is busy, attempt to exec command
SELECT ATN FROM t_id, REL(reselect);
; select either succeeded or timed out.
@@ -207,6 +210,7 @@ script_sched:
; waiting for a valid phase, so we have to do it now. If not a MSG_OUT phase,
; this is an error anyway (we selected with ATN)
INT int_err, WHEN NOT MSG_OUT;
+ignore_cmd:
MOVE SCRATCHD0 to SFBR; restore scheduler DSA
MOVE SFBR to DSA0;
MOVE SCRATCHD1 to SFBR;
@@ -215,7 +219,6 @@ script_sched:
MOVE SFBR to DSA2;
MOVE SCRATCHD3 to SFBR;
MOVE SFBR to DSA3;
-ignore_cmd:
MOVE SCRATCHE0 + 1 to SCRATCHE0;
MOVE SCRATCHD0 + cmd_slot_size to SCRATCHD0;
MOVE SCRATCHD1 + 0 to SCRATCHD1 WITH CARRY;
@@ -234,20 +237,23 @@ cmdr3:
MOVE 0xff to SCRATCHD3;
MOVE 0x00 to SCRATCHE0;
handle_cmd:
- MOVE SCRATCHA0 | f_cmd_free to SCRATCHA0; mark slot as free
- STORE noflush SCRATCHA0, 1, FROM o_cmd_dsa;
- MOVE SCRATCHA0 & f_cmd_ignore to SFBR;
+; to avoid race condition we have to load the DSA value before setting the
+; free flag, so we have to use a temp register.
+; use SCRATCHB0 so that we can CALL restoredsa later
+ LOAD SCRATCHB0, 4, FROM o_cmd_dsa; load DSA for this command in temp reg
+ MOVE SCRATCHB0 | f_cmd_free to SCRATCHB0; mark slot as free
+ STORE noflush SCRATCHB0, 4, FROM o_cmd_dsa;
+ MOVE SCRATCHB0 & f_cmd_ignore to SFBR;
JUMP REL(script_sched), IF NOT 0x00; next command if ignore
+ MOVE SCRATCHB0 & 0xfc to SCRATCHB0; clear f_cmd_*
+ CALL REL(restoredsa); and move SCRATCHB to DSA
; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time
; option "SIOP_SYMLED"
led_on1:
NOP;
- LOAD DSA0, 4, FROM o_cmd_dsa; reload DSA for this command
- MOVE DSA0 & 0xfe to DSA0; clear f_cmd_free
MOVE 0x00 TO SCRATCHA1;
MOVE 0xff TO SCRATCHE1;
- LOAD SCRATCHC0, 4, FROM tlq_offset;
;we can now send our identify message
send_msgout: ; entry point for msgout after a msgin or status phase
SET ATN;