summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authortsutsui <tsutsui@NetBSD.org>2002-02-09 15:13:00 +0000
committertsutsui <tsutsui@NetBSD.org>2002-02-09 15:13:00 +0000
commit0f5d20e20bb6f5ca012599067d159b6f7da500cd (patch)
treedb26a8f0c58acceed5ab8ac41bd2154f24f69c7b /sys/dev
parent86f2021f79c65357f2a2d821ac217bddea486f2a (diff)
- rename struct iha_scsi_req_q -> struct iha_scb
- reorder some functions - some more cosmetics
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/iha.c1903
-rw-r--r--sys/dev/ic/ihavar.h34
2 files changed, 962 insertions, 975 deletions
diff --git a/sys/dev/ic/iha.c b/sys/dev/ic/iha.c
index ba3faaf57c6..3d64a90e0f5 100644
--- a/sys/dev/ic/iha.c
+++ b/sys/dev/ic/iha.c
@@ -1,4 +1,4 @@
-/* $NetBSD: iha.c,v 1.14 2001/12/16 04:18:12 tsutsui Exp $ */
+/* $NetBSD: iha.c,v 1.15 2002/02/09 15:13:00 tsutsui Exp $ */
/*
* Initio INI-9xxxU/UW SCSI Device Driver
*
@@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: iha.c,v 1.14 2001/12/16 04:18:12 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: iha.c,v 1.15 2002/02/09 15:13:00 tsutsui Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -141,53 +141,41 @@ static u_int16_t eeprom_default[EEPROM_SIZE] = {
};
#endif
-static u_int8_t iha_data_over_run(struct iha_scsi_req_q *);
+static void iha_append_free_scb(struct iha_softc *, struct iha_scb *);
+static void iha_append_done_scb(struct iha_softc *, struct iha_scb *, u_int8_t);
+static __inline struct iha_scb *iha_pop_done_scb(struct iha_softc *);
+
+static struct iha_scb *iha_find_pend_scb(struct iha_softc *);
+static __inline void iha_append_pend_scb(struct iha_softc *, struct iha_scb *);
+static __inline void iha_push_pend_scb(struct iha_softc *, struct iha_scb *);
+static __inline void iha_del_pend_scb(struct iha_softc *, struct iha_scb *);
+static __inline void iha_mark_busy_scb(struct iha_scb *);
+
+static __inline void iha_set_ssig(struct iha_softc *, u_int8_t, u_int8_t);
-static int iha_push_sense_request(struct iha_softc *, struct iha_scsi_req_q *);
-static void iha_timeout(void *);
static int iha_alloc_sglist(struct iha_softc *);
-static void iha_read_eeprom(struct iha_softc *, struct iha_eeprom *);
-static int iha_se2_rd_all(struct iha_softc *, u_int16_t *);
-static void iha_se2_instr(struct iha_softc *, int);
-static u_int16_t iha_se2_rd(struct iha_softc *, int);
-#ifdef notused
-static void iha_se2_update_all(struct iha_softc *);
-static void iha_se2_wr(struct iha_softc *, int, u_int16_t);
-#endif
+static void iha_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t,
+ void *arg);
+static void iha_update_xfer_mode(struct iha_softc *, int);
static void iha_reset_scsi_bus(struct iha_softc *);
static void iha_reset_chip(struct iha_softc *);
static void iha_reset_dma(struct iha_softc *);
-
static void iha_reset_tcs(struct tcs *, u_int8_t);
-static void iha_done_scb(struct iha_softc *, struct iha_scsi_req_q *);
-static void iha_exec_scb(struct iha_softc *, struct iha_scsi_req_q *);
-
static void iha_main(struct iha_softc *);
static void iha_scsi(struct iha_softc *);
+static void iha_select(struct iha_softc *, struct iha_scb *, u_int8_t);
+static int iha_wait(struct iha_softc *, u_int8_t);
-static int iha_wait(struct iha_softc *, u_int8_t);
+static void iha_exec_scb(struct iha_softc *, struct iha_scb *);
+static void iha_done_scb(struct iha_softc *, struct iha_scb *);
+static int iha_push_sense_request(struct iha_softc *, struct iha_scb *);
-static __inline void iha_mark_busy_scb(struct iha_scsi_req_q *);
-
-static void iha_append_free_scb(struct iha_softc *, struct iha_scsi_req_q *);
-static void iha_append_done_scb(struct iha_softc *, struct iha_scsi_req_q *,
- u_int8_t);
-static __inline struct iha_scsi_req_q *iha_pop_done_scb(struct iha_softc *);
-
-static __inline void iha_append_pend_scb(struct iha_softc *,
- struct iha_scsi_req_q *);
-static __inline void iha_push_pend_scb(struct iha_softc *,
- struct iha_scsi_req_q *);
-static __inline void iha_del_pend_scb(struct iha_softc *,
- struct iha_scsi_req_q *);
-static struct iha_scsi_req_q *iha_find_pend_scb(struct iha_softc *);
-
-static void iha_sync_done(struct iha_softc *);
-static void iha_wide_done(struct iha_softc *);
-static void iha_bad_seq(struct iha_softc *);
+static void iha_timeout(void *);
+static void iha_abort_xs(struct iha_softc *, struct scsipi_xfer *, u_int8_t);
+static u_int8_t iha_data_over_run(struct iha_scb *);
static int iha_next_state(struct iha_softc *);
static int iha_state_1(struct iha_softc *);
@@ -198,187 +186,314 @@ static int iha_state_5(struct iha_softc *);
static int iha_state_6(struct iha_softc *);
static int iha_state_8(struct iha_softc *);
-static void iha_set_ssig(struct iha_softc *, u_int8_t, u_int8_t);
-
+static int iha_xfer_data(struct iha_softc *, struct iha_scb *, int);
static int iha_xpad_in(struct iha_softc *);
static int iha_xpad_out(struct iha_softc *);
-static int iha_xfer_data(struct iha_softc *, struct iha_scsi_req_q *,
- int direction);
-
static int iha_status_msg(struct iha_softc *);
+static void iha_busfree(struct iha_softc *);
+static int iha_resel(struct iha_softc *);
static int iha_msgin(struct iha_softc *);
-static int iha_msgin_sdtr(struct iha_softc *);
static int iha_msgin_extended(struct iha_softc *);
+static int iha_msgin_sdtr(struct iha_softc *);
static int iha_msgin_ignore_wid_resid(struct iha_softc *);
static int iha_msgout(struct iha_softc *, u_int8_t);
-static int iha_msgout_extended(struct iha_softc *);
static void iha_msgout_abort(struct iha_softc *, u_int8_t);
static int iha_msgout_reject(struct iha_softc *);
-static int iha_msgout_sdtr(struct iha_softc *);
+static int iha_msgout_extended(struct iha_softc *);
static int iha_msgout_wdtr(struct iha_softc *);
+static int iha_msgout_sdtr(struct iha_softc *);
-static void iha_select(struct iha_softc *, struct iha_scsi_req_q *, u_int8_t);
-
-static void iha_busfree(struct iha_softc *);
-static int iha_resel(struct iha_softc *);
+static void iha_wide_done(struct iha_softc *);
+static void iha_sync_done(struct iha_softc *);
-static void iha_abort_xs(struct iha_softc *, struct scsipi_xfer *, u_int8_t);
+static void iha_bad_seq(struct iha_softc *);
-void iha_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t,
- void *arg);
-void iha_update_xfer_mode(struct iha_softc *, int);
+static void iha_read_eeprom(struct iha_softc *, struct iha_eeprom *);
+static int iha_se2_rd_all(struct iha_softc *, u_int16_t *);
+static void iha_se2_instr(struct iha_softc *, int);
+static u_int16_t iha_se2_rd(struct iha_softc *, int);
+#ifdef notused
+static void iha_se2_update_all(struct iha_softc *);
+static void iha_se2_wr(struct iha_softc *, int, u_int16_t);
+#endif
/*
- * iha_intr - the interrupt service routine for the iha driver
+ * iha_append_free_scb - append the supplied SCB to the tail of the
+ * sc_freescb queue after clearing and resetting
+ * everything possible.
*/
-int
-iha_intr(arg)
- void *arg;
+static void
+iha_append_free_scb(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
{
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
+ int s;
+
+ s = splbio();
+
+ if (scb == sc->sc_actscb)
+ sc->sc_actscb = NULL;
+
+ scb->status = STATUS_QUEUED;
+ scb->ha_stat = HOST_OK;
+ scb->ta_stat = SCSI_OK;
+
+ scb->nextstat = 0;
+ scb->scb_tagmsg = 0;
+
+ scb->xs = NULL;
+ scb->tcs = NULL;
+
+ /*
+ * scb_tagid, sg_addr, sglist
+ * SCB_SensePtr are set at initialization
+ * and never change
+ */
+
+ TAILQ_INSERT_TAIL(&sc->sc_freescb, scb, chain);
+
+ splx(s);
+}
+
+static void
+iha_append_done_scb(sc, scb, hastat)
struct iha_softc *sc;
+ struct iha_scb *scb;
+ u_int8_t hastat;
+{
+ struct tcs *tcs;
int s;
- sc = (struct iha_softc *)arg;
- iot = sc->sc_iot;
- ioh = sc->sc_ioh;
+ s = splbio();
- if ((bus_space_read_1(iot, ioh, TUL_STAT0) & INTPD) == 0)
- return (0);
+ if (scb->xs != NULL)
+ callout_stop(&scb->xs->xs_callout);
- s = splbio(); /* XXX - Or are interrupts off when ISR's are called? */
+ if (scb == sc->sc_actscb)
+ sc->sc_actscb = NULL;
- if (sc->sc_semaph != SEMAPH_IN_MAIN) {
- /* XXX - need these inside a splbio()/splx()? */
- bus_space_write_1(iot, ioh, TUL_IMSK, MASK_ALL);
- sc->sc_semaph = SEMAPH_IN_MAIN;
+ tcs = scb->tcs;
- iha_main(sc);
+ if (scb->scb_tagmsg != 0) {
+ if (tcs->tagcnt)
+ tcs->tagcnt--;
+ } else if (tcs->ntagscb == scb)
+ tcs->ntagscb = NULL;
- sc->sc_semaph = ~SEMAPH_IN_MAIN;
- bus_space_write_1(iot, ioh, TUL_IMSK, (MASK_ALL & ~MSCMP));
+ scb->status = STATUS_QUEUED;
+ scb->ha_stat = hastat;
+
+ TAILQ_INSERT_TAIL(&sc->sc_donescb, scb, chain);
+
+ splx(s);
+}
+
+static __inline struct iha_scb *
+iha_pop_done_scb(sc)
+ struct iha_softc *sc;
+{
+ struct iha_scb *scb;
+ int s;
+
+ s = splbio();
+
+ scb = TAILQ_FIRST(&sc->sc_donescb);
+
+ if (scb != NULL) {
+ scb->status = STATUS_RENT;
+ TAILQ_REMOVE(&sc->sc_donescb, scb, chain);
}
splx(s);
- return (1);
+ return (scb);
}
-void
-iha_scsipi_request(chan, req, arg)
- struct scsipi_channel *chan;
- scsipi_adapter_req_t req;
- void *arg;
-{
- struct scsipi_xfer *xs;
- struct scsipi_periph *periph;
- struct iha_scsi_req_q *scb;
+/*
+ * iha_find_pend_scb - scan the pending queue for a SCB that can be
+ * processed immediately. Return NULL if none found
+ * and a pointer to the SCB if one is found. If there
+ * is an active SCB, return NULL!
+ */
+static struct iha_scb *
+iha_find_pend_scb(sc)
struct iha_softc *sc;
- int error, s;
-
- sc = (struct iha_softc *)chan->chan_adapter->adapt_dev;
+{
+ struct iha_scb *scb;
+ struct tcs *tcs;
+ int s;
- switch (req) {
- case ADAPTER_REQ_RUN_XFER:
- xs = arg;
- periph = xs->xs_periph;
+ s = splbio();
- if (xs->cmdlen > sizeof(struct scsi_generic) ||
- periph->periph_target >= IHA_MAX_TARGETS) {
- xs->error = XS_DRIVER_STUFFUP;
- return;
- }
+ if (sc->sc_actscb != NULL)
+ scb = NULL;
- s = splbio();
- scb = TAILQ_FIRST(&sc->sc_freescb);
- if (scb != NULL) {
- scb->status = STATUS_RENT;
- TAILQ_REMOVE(&sc->sc_freescb, scb, chain);
- }
-#ifdef DIAGNOSTIC
- else {
- scsipi_printaddr(periph);
- printf("unable to allocate scb\n");
- panic("iha_scsipi_request");
- }
-#endif
- splx(s);
+ else
+ TAILQ_FOREACH(scb, &sc->sc_pendscb, chain) {
+ if ((scb->xs->xs_control & XS_CTL_RESET) != 0)
+ /* ALWAYS willing to reset a device */
+ break;
- scb->target = periph->periph_target;
- scb->lun = periph->periph_lun;
- scb->tcs = &sc->sc_tcs[scb->target];
- scb->scb_id = MSG_IDENTIFY(periph->periph_lun,
- (xs->xs_control & XS_CTL_REQSENSE) == 0);
+ tcs = scb->tcs;
- scb->xs = xs;
- scb->cmdlen = xs->cmdlen;
- memcpy(&scb->cmd, xs->cmd, xs->cmdlen);
- scb->buflen = xs->datalen;
- scb->flags = 0;
- if (xs->xs_control & XS_CTL_DATA_OUT)
- scb->flags |= FLAG_DATAOUT;
- if (xs->xs_control & XS_CTL_DATA_IN)
- scb->flags |= FLAG_DATAIN;
+ if ((scb->scb_tagmsg) != 0) {
+ /*
+ * A Tagged I/O. OK to start If no
+ * non-tagged I/O is active on the same
+ * target
+ */
+ if (tcs->ntagscb == NULL)
+ break;
- if (scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) {
- error = bus_dmamap_load(sc->sc_dmat, scb->dmap,
- xs->data, scb->buflen, NULL,
- ((xs->xs_control & XS_CTL_NOSLEEP) ?
- BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
- BUS_DMA_STREAMING |
- ((scb->flags & FLAG_DATAIN) ?
- BUS_DMA_READ : BUS_DMA_WRITE));
+ } else if (scb->cmd[0] == REQUEST_SENSE) {
+ /*
+ * OK to do a non-tagged request sense
+ * even if a non-tagged I/O has been
+ * started, 'cuz we don't allow any
+ * disconnect during a request sense op
+ */
+ break;
- if (error) {
- printf("%s: error %d loading dma map\n",
- sc->sc_dev.dv_xname, error);
- iha_append_free_scb(sc, scb);
- xs->error = XS_DRIVER_STUFFUP;
- scsipi_done(xs);
- return;
+ } else if (tcs->tagcnt == 0) {
+ /*
+ * No tagged I/O active on this target,
+ * ok to start a non-tagged one if one
+ * is not already active
+ */
+ if (tcs->ntagscb == NULL)
+ break;
}
- bus_dmamap_sync(sc->sc_dmat, scb->dmap,
- 0, scb->dmap->dm_mapsize,
- (scb->flags & FLAG_DATAIN) ?
- BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
}
- iha_exec_scb(sc, scb);
- return;
+ splx(s);
- case ADAPTER_REQ_GROW_RESOURCES:
- return; /* XXX */
+ return (scb);
+}
- case ADAPTER_REQ_SET_XFER_MODE:
- {
- struct tcs *tcs;
- struct scsipi_xfer_mode *xm = arg;
+static __inline void
+iha_append_pend_scb(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+{
+ /* ASSUMPTION: only called within a splbio()/splx() pair */
- tcs = &sc->sc_tcs[xm->xm_target];
+ if (scb == sc->sc_actscb)
+ sc->sc_actscb = NULL;
- if ((xm->xm_mode & PERIPH_CAP_WIDE16) != 0 &&
- (tcs->flags & FLAG_NO_WIDE) == 0)
- tcs->flags &= ~(FLAG_WIDE_DONE|FLAG_SYNC_DONE);
+ scb->status = STATUS_QUEUED;
- if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 &&
- (tcs->flags & FLAG_NO_SYNC) == 0)
- tcs->flags &= ~FLAG_SYNC_DONE;
+ TAILQ_INSERT_TAIL(&sc->sc_pendscb, scb, chain);
+}
- /*
- * If we're not going to negotiate, send the
- * notification now, since it won't happen later.
- */
- if ((tcs->flags & (FLAG_WIDE_DONE|FLAG_SYNC_DONE)) ==
- (FLAG_WIDE_DONE|FLAG_SYNC_DONE))
- iha_update_xfer_mode(sc, xm->xm_target);
+static __inline void
+iha_push_pend_scb(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+{
+ int s;
- return;
- }
+ s = splbio();
+
+ if (scb == sc->sc_actscb)
+ sc->sc_actscb = NULL;
+
+ scb->status = STATUS_QUEUED;
+
+ TAILQ_INSERT_HEAD(&sc->sc_pendscb, scb, chain);
+
+ splx(s);
+}
+
+/*
+ * iha_del_pend_scb - remove scb from sc_pendscb
+ */
+static __inline void
+iha_del_pend_scb(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+{
+ int s;
+
+ s = splbio();
+
+ TAILQ_REMOVE(&sc->sc_pendscb, scb, chain);
+
+ splx(s);
+}
+
+static __inline void
+iha_mark_busy_scb(scb)
+ struct iha_scb *scb;
+{
+ int s;
+
+ s = splbio();
+
+ scb->status = STATUS_BUSY;
+
+ if (scb->scb_tagmsg == 0)
+ scb->tcs->ntagscb = scb;
+ else
+ scb->tcs->tagcnt++;
+
+ splx(s);
+}
+
+/*
+ * iha_set_ssig - read the current scsi signal mask, then write a new
+ * one which turns off/on the specified signals.
+ */
+static __inline void
+iha_set_ssig(sc, offsigs, onsigs)
+ struct iha_softc *sc;
+ u_int8_t offsigs, onsigs;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t currsigs;
+
+ currsigs = bus_space_read_1(iot, ioh, TUL_SSIGI);
+ bus_space_write_1(iot, ioh, TUL_SSIGO, (currsigs & ~offsigs) | onsigs);
+}
+
+/*
+ * iha_intr - the interrupt service routine for the iha driver
+ */
+int
+iha_intr(arg)
+ void *arg;
+{
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct iha_softc *sc;
+ int s;
+
+ sc = (struct iha_softc *)arg;
+ iot = sc->sc_iot;
+ ioh = sc->sc_ioh;
+
+ if ((bus_space_read_1(iot, ioh, TUL_STAT0) & INTPD) == 0)
+ return (0);
+
+ s = splbio(); /* XXX - Or are interrupts off when ISR's are called? */
+
+ if (sc->sc_semaph != SEMAPH_IN_MAIN) {
+ /* XXX - need these inside a splbio()/splx()? */
+ bus_space_write_1(iot, ioh, TUL_IMSK, MASK_ALL);
+ sc->sc_semaph = SEMAPH_IN_MAIN;
+
+ iha_main(sc);
+
+ sc->sc_semaph = ~SEMAPH_IN_MAIN;
+ bus_space_write_1(iot, ioh, TUL_IMSK, (MASK_ALL & ~MSCMP));
}
+
+ splx(s);
+
+ return (1);
}
void
@@ -387,7 +502,7 @@ iha_attach(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
struct iha_eeprom eeprom;
struct eeprom_adapter *conf;
int i, error, reg;
@@ -413,7 +528,7 @@ iha_attach(sc)
return;
}
- sc->sc_scb = malloc(sizeof(struct iha_scsi_req_q) * IHA_MAX_SCB,
+ sc->sc_scb = malloc(sizeof(struct iha_scb) * IHA_MAX_SCB,
M_DEVBUF, M_NOWAIT|M_ZERO);
if (sc->sc_scb == NULL) {
printf(": cannot allocate SCB\n");
@@ -513,360 +628,283 @@ iha_attach(sc)
}
/*
- * iha_reset_dma - abort any active DMA xfer, reset tulip FIFO.
+ * iha_alloc_sglist - allocate and map sglist for SCB's
*/
-static void
-iha_reset_dma(sc)
+static int
+iha_alloc_sglist(sc)
struct iha_softc *sc;
{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
+ bus_dma_segment_t seg;
+ int error, rseg;
- if ((bus_space_read_1(iot, ioh, TUL_ISTUS1) & XPEND) != 0) {
- /* if DMA xfer is pending, abort DMA xfer */
- bus_space_write_1(iot, ioh, TUL_DCMD, ABTXFR);
- /* wait Abort DMA xfer done */
- while ((bus_space_read_1(iot, ioh, TUL_ISTUS0) & DABT) == 0)
- ;
+ /*
+ * Allocate dma-safe memory for the SCB's sglist
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat,
+ IHA_SG_SIZE * IHA_MAX_SCB,
+ PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ printf(": unable to allocate sglist, error = %d\n", error);
+ return (error);
+ }
+ if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
+ IHA_SG_SIZE * IHA_MAX_SCB, (caddr_t *)&sc->sc_sglist,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ printf(": unable to map sglist, error = %d\n", error);
+ return (error);
}
-
- bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
-}
-
-/*
- * iha_append_free_scb - append the supplied SCB to the tail of the
- * sc_freescb queue after clearing and resetting
- * everything possible.
- */
-static void
-iha_append_free_scb(sc, scb)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
-{
- int s;
-
- s = splbio();
-
- if (scb == sc->sc_actscb)
- sc->sc_actscb = NULL;
-
- scb->status = STATUS_QUEUED;
- scb->ha_stat = HOST_OK;
- scb->ta_stat = SCSI_OK;
-
- scb->nextstat = 0;
- scb->scb_tagmsg = 0;
-
- scb->xs = NULL;
- scb->tcs = NULL;
/*
- * scb_tagid, sg_addr, sglist
- * SCB_SensePtr are set at initialization
- * and never change
+ * Create and load the DMA map used for the SCBs
*/
+ if ((error = bus_dmamap_create(sc->sc_dmat,
+ IHA_SG_SIZE * IHA_MAX_SCB, 1, IHA_SG_SIZE * IHA_MAX_SCB,
+ 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
+ printf(": unable to create control DMA map, error = %d\n",
+ error);
+ return (error);
+ }
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
+ sc->sc_sglist, IHA_SG_SIZE * IHA_MAX_SCB,
+ NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf(": unable to load control DMA map, error = %d\n", error);
+ return (error);
+ }
- TAILQ_INSERT_TAIL(&sc->sc_freescb, scb, chain);
+ memset(sc->sc_sglist, 0, IHA_SG_SIZE * IHA_MAX_SCB);
- splx(s);
+ return (0);
}
-static __inline void
-iha_append_pend_scb(sc, scb)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
+void
+iha_scsipi_request(chan, req, arg)
+ struct scsipi_channel *chan;
+ scsipi_adapter_req_t req;
+ void *arg;
{
- /* ASSUMPTION: only called within a splbio()/splx() pair */
-
- if (scb == sc->sc_actscb)
- sc->sc_actscb = NULL;
+ struct scsipi_xfer *xs;
+ struct scsipi_periph *periph;
+ struct iha_scb *scb;
+ struct iha_softc *sc;
+ int error, s;
- scb->status = STATUS_QUEUED;
+ sc = (struct iha_softc *)chan->chan_adapter->adapt_dev;
- TAILQ_INSERT_TAIL(&sc->sc_pendscb, scb, chain);
-}
+ switch (req) {
+ case ADAPTER_REQ_RUN_XFER:
+ xs = arg;
+ periph = xs->xs_periph;
-static __inline void
-iha_push_pend_scb(sc, scb)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
-{
- int s;
+ if (xs->cmdlen > sizeof(struct scsi_generic) ||
+ periph->periph_target >= IHA_MAX_TARGETS) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return;
+ }
- s = splbio();
+ s = splbio();
+ scb = TAILQ_FIRST(&sc->sc_freescb);
+ if (scb != NULL) {
+ scb->status = STATUS_RENT;
+ TAILQ_REMOVE(&sc->sc_freescb, scb, chain);
+ }
+#ifdef DIAGNOSTIC
+ else {
+ scsipi_printaddr(periph);
+ printf("unable to allocate scb\n");
+ panic("iha_scsipi_request");
+ }
+#endif
+ splx(s);
- if (scb == sc->sc_actscb)
- sc->sc_actscb = NULL;
+ scb->target = periph->periph_target;
+ scb->lun = periph->periph_lun;
+ scb->tcs = &sc->sc_tcs[scb->target];
+ scb->scb_id = MSG_IDENTIFY(periph->periph_lun,
+ (xs->xs_control & XS_CTL_REQSENSE) == 0);
- scb->status = STATUS_QUEUED;
+ scb->xs = xs;
+ scb->cmdlen = xs->cmdlen;
+ memcpy(&scb->cmd, xs->cmd, xs->cmdlen);
+ scb->buflen = xs->datalen;
+ scb->flags = 0;
+ if (xs->xs_control & XS_CTL_DATA_OUT)
+ scb->flags |= FLAG_DATAOUT;
+ if (xs->xs_control & XS_CTL_DATA_IN)
+ scb->flags |= FLAG_DATAIN;
- TAILQ_INSERT_HEAD(&sc->sc_pendscb, scb, chain);
+ if (scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) {
+ error = bus_dmamap_load(sc->sc_dmat, scb->dmap,
+ xs->data, scb->buflen, NULL,
+ ((xs->xs_control & XS_CTL_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
+ BUS_DMA_STREAMING |
+ ((scb->flags & FLAG_DATAIN) ?
+ BUS_DMA_READ : BUS_DMA_WRITE));
- splx(s);
-}
+ if (error) {
+ printf("%s: error %d loading dma map\n",
+ sc->sc_dev.dv_xname, error);
+ iha_append_free_scb(sc, scb);
+ xs->error = XS_DRIVER_STUFFUP;
+ scsipi_done(xs);
+ return;
+ }
+ bus_dmamap_sync(sc->sc_dmat, scb->dmap,
+ 0, scb->dmap->dm_mapsize,
+ (scb->flags & FLAG_DATAIN) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+ }
-/*
- * iha_find_pend_scb - scan the pending queue for a SCB that can be
- * processed immediately. Return NULL if none found
- * and a pointer to the SCB if one is found. If there
- * is an active SCB, return NULL!
- */
-static struct iha_scsi_req_q *
-iha_find_pend_scb(sc)
- struct iha_softc *sc;
-{
- struct iha_scsi_req_q *scb;
- struct tcs *tcs;
- int s;
+ iha_exec_scb(sc, scb);
+ return;
- s = splbio();
+ case ADAPTER_REQ_GROW_RESOURCES:
+ return; /* XXX */
- if (sc->sc_actscb != NULL)
- scb = NULL;
+ case ADAPTER_REQ_SET_XFER_MODE:
+ {
+ struct tcs *tcs;
+ struct scsipi_xfer_mode *xm = arg;
- else
- TAILQ_FOREACH(scb, &sc->sc_pendscb, chain) {
- if ((scb->xs->xs_control & XS_CTL_RESET) != 0)
- /* ALWAYS willing to reset a device */
- break;
+ tcs = &sc->sc_tcs[xm->xm_target];
- tcs = scb->tcs;
+ if ((xm->xm_mode & PERIPH_CAP_WIDE16) != 0 &&
+ (tcs->flags & FLAG_NO_WIDE) == 0)
+ tcs->flags &= ~(FLAG_WIDE_DONE|FLAG_SYNC_DONE);
- if ((scb->scb_tagmsg) != 0) {
- /*
- * A Tagged I/O. OK to start If no
- * non-tagged I/O is active on the same
- * target
- */
- if (tcs->ntagscb == NULL)
- break;
+ if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 &&
+ (tcs->flags & FLAG_NO_SYNC) == 0)
+ tcs->flags &= ~FLAG_SYNC_DONE;
- } else if (scb->cmd[0] == REQUEST_SENSE) {
- /*
- * OK to do a non-tagged request sense
- * even if a non-tagged I/O has been
- * started, 'cuz we don't allow any
- * disconnect during a request sense op
- */
- break;
+ /*
+ * If we're not going to negotiate, send the
+ * notification now, since it won't happen later.
+ */
+ if ((tcs->flags & (FLAG_WIDE_DONE|FLAG_SYNC_DONE)) ==
+ (FLAG_WIDE_DONE|FLAG_SYNC_DONE))
+ iha_update_xfer_mode(sc, xm->xm_target);
- } else if (tcs->tagcnt == 0) {
- /*
- * No tagged I/O active on this target,
- * ok to start a non-tagged one if one
- * is not already active
- */
- if (tcs->ntagscb == NULL)
- break;
- }
+ return;
}
-
- splx(s);
-
- return (scb);
+ }
}
-/*
- * iha_del_pend_scb - remove scb from sc_pendscb
- */
-static __inline void
-iha_del_pend_scb(sc, scb)
+void
+iha_update_xfer_mode(sc, target)
struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
-{
- int s;
-
- s = splbio();
-
- TAILQ_REMOVE(&sc->sc_pendscb, scb, chain);
-
- splx(s);
-}
-
-static __inline void
-iha_mark_busy_scb(scb)
- struct iha_scsi_req_q *scb;
+ int target;
{
- int s;
+ struct tcs *tcs = &sc->sc_tcs[target];
+ struct scsipi_xfer_mode xm;
- s = splbio();
+ xm.xm_target = target;
+ xm.xm_mode = 0;
+ xm.xm_period = 0;
+ xm.xm_offset = 0;
- scb->status = STATUS_BUSY;
+ if (tcs->syncm & PERIOD_WIDE_SCSI)
+ xm.xm_mode |= PERIPH_CAP_WIDE16;
- if (scb->scb_tagmsg == 0)
- scb->tcs->ntagscb = scb;
- else
- scb->tcs->tagcnt++;
+ if (tcs->period) {
+ xm.xm_mode |= PERIPH_CAP_SYNC;
+ xm.xm_period = tcs->period;
+ xm.xm_offset = tcs->offset;
+ }
- splx(s);
+ scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
}
static void
-iha_append_done_scb(sc, scb, hastat)
+iha_reset_scsi_bus(sc)
struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
- u_int8_t hastat;
{
+ struct iha_scb *scb;
struct tcs *tcs;
- int s;
+ int i, s;
s = splbio();
- if (scb->xs != NULL)
- callout_stop(&scb->xs->xs_callout);
-
- if (scb == sc->sc_actscb)
- sc->sc_actscb = NULL;
+ iha_reset_dma(sc);
- tcs = scb->tcs;
+ for (i = 0, scb = sc->sc_scb; i < IHA_MAX_SCB; i++, scb++)
+ switch (scb->status) {
+ case STATUS_BUSY:
+ iha_append_done_scb(sc, scb, HOST_SCSI_RST);
+ break;
- if (scb->scb_tagmsg != 0) {
- if (tcs->tagcnt)
- tcs->tagcnt--;
- } else if (tcs->ntagscb == scb)
- tcs->ntagscb = NULL;
+ case STATUS_SELECT:
+ iha_push_pend_scb(sc, scb);
+ break;
- scb->status = STATUS_QUEUED;
- scb->ha_stat = hastat;
+ default:
+ break;
+ }
- TAILQ_INSERT_TAIL(&sc->sc_donescb, scb, chain);
+ for (i = 0, tcs = sc->sc_tcs; i < IHA_MAX_TARGETS; i++, tcs++)
+ iha_reset_tcs(tcs, sc->sc_sconf1);
splx(s);
}
-static __inline struct iha_scsi_req_q *
-iha_pop_done_scb(sc)
+void
+iha_reset_chip(sc)
struct iha_softc *sc;
{
- struct iha_scsi_req_q *scb;
- int s;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
- s = splbio();
+ /* reset tulip chip */
- scb = TAILQ_FIRST(&sc->sc_donescb);
+ bus_space_write_1(iot, ioh, TUL_SCTRL0, RSCSI);
- if (scb != NULL) {
- scb->status = STATUS_RENT;
- TAILQ_REMOVE(&sc->sc_donescb, scb, chain);
- }
+ do {
+ sc->sc_sistat = bus_space_read_1(iot, ioh, TUL_SISTAT);
+ } while ((sc->sc_sistat & SRSTD) == 0);
- splx(s);
+ iha_set_ssig(sc, 0, 0);
- return (scb);
+ bus_space_read_1(iot, ioh, TUL_SISTAT); /* Clear any active interrupt*/
}
/*
- * iha_abort_xs - find the SCB associated with the supplied xs and
- * stop all processing on it, moving it to the done
- * queue with the supplied host status value.
+ * iha_reset_dma - abort any active DMA xfer, reset tulip FIFO.
*/
static void
-iha_abort_xs(sc, xs, hastat)
+iha_reset_dma(sc)
struct iha_softc *sc;
- struct scsipi_xfer *xs;
- u_int8_t hastat;
{
- struct iha_scsi_req_q *scb;
- int i, s;
-
- s = splbio();
-
- /* Check the pending queue for the SCB pointing to xs */
-
- TAILQ_FOREACH(scb, &sc->sc_pendscb, chain)
- if (scb->xs == xs) {
- iha_del_pend_scb(sc, scb);
- iha_append_done_scb(sc, scb, hastat);
- splx(s);
- return;
- }
-
- /*
- * If that didn't work, check all BUSY/SELECTING SCB's for one
- * pointing to xs
- */
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
- for (i = 0, scb = sc->sc_scb; i < IHA_MAX_SCB; i++, scb++)
- switch (scb->status) {
- case STATUS_BUSY:
- case STATUS_SELECT:
- if (scb->xs == xs) {
- iha_append_done_scb(sc, scb, hastat);
- splx(s);
- return;
- }
- break;
- default:
- break;
- }
+ if ((bus_space_read_1(iot, ioh, TUL_ISTUS1) & XPEND) != 0) {
+ /* if DMA xfer is pending, abort DMA xfer */
+ bus_space_write_1(iot, ioh, TUL_DCMD, ABTXFR);
+ /* wait Abort DMA xfer done */
+ while ((bus_space_read_1(iot, ioh, TUL_ISTUS0) & DABT) == 0)
+ ;
+ }
- splx(s);
+ bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
}
/*
- * iha_bad_seq - a SCSI bus phase was encountered out of the
- * correct/expected sequence. Reset the SCSI bus.
+ * iha_reset_tcs - reset the target control structure pointed
+ * to by tcs to default values. tcs flags
+ * only has the negotiation done bits reset as
+ * the other bits are fixed at initialization.
*/
static void
-iha_bad_seq(sc)
- struct iha_softc *sc;
-{
- struct iha_scsi_req_q *scb = sc->sc_actscb;
-
- if (scb != NULL)
- iha_append_done_scb(sc, scb, HOST_BAD_PHAS);
-
- iha_reset_scsi_bus(sc);
- iha_reset_chip(sc);
-}
-
-/*
- * iha_push_sense_request - obtain auto sense data by pushing the
- * SCB needing it back onto the pending
- * queue with a REQUEST_SENSE CDB.
- */
-static int
-iha_push_sense_request(sc, scb)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
+iha_reset_tcs(tcs, config0)
+ struct tcs *tcs;
+ u_int8_t config0;
{
- struct scsipi_xfer *xs = scb->xs;
- struct scsipi_periph *periph = xs->xs_periph;
- struct scsipi_sense *ss = (struct scsipi_sense *)scb->cmd;
- int lun = periph->periph_lun;
- int err;
-
- ss->opcode = REQUEST_SENSE;
- ss->byte2 = lun << SCSI_CMD_LUN_SHIFT;
- ss->unused[0] = ss->unused[1] = 0;
- ss->length = sizeof(struct scsipi_sense_data);
- ss->control = 0;
-
- scb->flags = FLAG_RSENS | FLAG_DATAIN;
-
- scb->scb_id &= ~MSG_IDENTIFY_DISCFLAG;
-
- scb->scb_tagmsg = 0;
- scb->ta_stat = SCSI_OK;
-
- scb->cmdlen = sizeof(struct scsipi_sense);
- scb->buflen = ss->length;
-
- err = bus_dmamap_load(sc->sc_dmat, scb->dmap,
- &xs->sense.scsi_sense, scb->buflen, NULL,
- BUS_DMA_READ|BUS_DMA_NOWAIT);
- if (err != 0) {
- printf("iha_push_sense_request: cannot bus_dmamap_load()\n");
- xs->error = XS_DRIVER_STUFFUP;
- return 1;
- }
- bus_dmamap_sync(sc->sc_dmat, scb->dmap,
- 0, scb->buflen, BUS_DMASYNC_PREREAD);
-
- /* XXX What about queued command? */
- iha_exec_scb(sc, scb);
- return 0;
+ tcs->flags &= ~(FLAG_SYNC_DONE | FLAG_WIDE_DONE);
+ tcs->period = 0;
+ tcs->offset = 0;
+ tcs->tagcnt = 0;
+ tcs->ntagscb = NULL;
+ tcs->syncm = 0;
+ tcs->sconfig0 = config0;
}
/*
@@ -881,7 +919,7 @@ iha_main(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh =sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
for (;;) {
iha_scsi(sc);
@@ -911,7 +949,7 @@ iha_scsi(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
struct tcs *tcs;
u_int8_t stat;
@@ -1001,6 +1039,417 @@ iha_scsi(sc)
}
}
+static void
+iha_select(sc, scb, select_type)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+ u_int8_t select_type;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ switch (select_type) {
+ case SEL_ATN:
+ bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_id);
+ bus_space_write_multi_1(iot, ioh, TUL_SFIFO,
+ scb->cmd, scb->cmdlen);
+
+ scb->nextstat = 2;
+ break;
+
+ case SELATNSTOP:
+ scb->nextstat = 1;
+ break;
+
+ case SEL_ATN3:
+ bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_id);
+ bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_tagmsg);
+ bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_tagid);
+
+ bus_space_write_multi_1(iot, ioh, TUL_SFIFO, scb->cmd,
+ scb->cmdlen);
+
+ scb->nextstat = 2;
+ break;
+
+ default:
+ printf("[debug] iha_select() - unknown select type = 0x%02x\n",
+ select_type);
+ return;
+ }
+
+ iha_del_pend_scb(sc, scb);
+ scb->status = STATUS_SELECT;
+
+ sc->sc_actscb = scb;
+
+ bus_space_write_1(iot, ioh, TUL_SCMD, select_type);
+}
+
+/*
+ * iha_wait - wait for an interrupt to service or a SCSI bus phase change
+ * after writing the supplied command to the tulip chip. If
+ * the command is NO_OP, skip the command writing.
+ */
+static int
+iha_wait(sc, cmd)
+ struct iha_softc *sc;
+ u_int8_t cmd;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ if (cmd != NO_OP)
+ bus_space_write_1(iot, ioh, TUL_SCMD, cmd);
+
+ /*
+ * Have to do this here, in addition to in iha_isr, because
+ * interrupts might be turned off when we get here.
+ */
+ do {
+ sc->sc_status0 = bus_space_read_1(iot, ioh, TUL_STAT0);
+ } while ((sc->sc_status0 & INTPD) == 0);
+
+ sc->sc_status1 = bus_space_read_1(iot, ioh, TUL_STAT1);
+ sc->sc_sistat = bus_space_read_1(iot, ioh, TUL_SISTAT);
+
+ sc->sc_phase = sc->sc_status0 & PH_MASK;
+
+ if ((sc->sc_sistat & SRSTD) != 0) {
+ /* SCSI bus reset interrupt */
+ iha_reset_scsi_bus(sc);
+ return (-1);
+ }
+
+ if ((sc->sc_sistat & RSELED) != 0)
+ /* Reselection interrupt */
+ return (iha_resel(sc));
+
+ if ((sc->sc_sistat & STIMEO) != 0) {
+ /* selected/reselected timeout interrupt */
+ iha_busfree(sc);
+ return (-1);
+ }
+
+ if ((sc->sc_sistat & DISCD) != 0) {
+ /* BUS disconnection interrupt */
+ if ((sc->sc_flags & FLAG_EXPECT_DONE_DISC) != 0) {
+ bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
+ bus_space_write_1(iot, ioh, TUL_SCONFIG0,
+ SCONFIG0DEFAULT);
+ bus_space_write_1(iot, ioh, TUL_SCTRL1, EHRSL);
+ iha_append_done_scb(sc, sc->sc_actscb, HOST_OK);
+ sc->sc_flags &= ~FLAG_EXPECT_DONE_DISC;
+
+ } else if ((sc->sc_flags & FLAG_EXPECT_DISC) != 0) {
+ bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
+ bus_space_write_1(iot, ioh, TUL_SCONFIG0,
+ SCONFIG0DEFAULT);
+ bus_space_write_1(iot, ioh, TUL_SCTRL1, EHRSL);
+ sc->sc_actscb = NULL;
+ sc->sc_flags &= ~FLAG_EXPECT_DISC;
+
+ } else
+ iha_busfree(sc);
+
+ return (-1);
+ }
+
+ return (sc->sc_phase);
+}
+
+static void
+iha_exec_scb(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+{
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_dmamap_t dm;
+ struct scsipi_xfer *xs = scb->xs;
+ int nseg, s;
+
+ dm = scb->dmap;
+ nseg = dm->dm_nsegs;
+
+ if (nseg > 1) {
+ struct iha_sg_element *sg = scb->sglist;
+ int i;
+
+ for (i = 0; i < nseg; i++) {
+ sg[i].sg_len = htole32(dm->dm_segs[i].ds_len);
+ sg[i].sg_addr = htole32(dm->dm_segs[i].ds_addr);
+ }
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
+ scb->sgoffset, IHA_SG_SIZE,
+ BUS_DMASYNC_PREWRITE);
+
+ scb->flags |= FLAG_SG;
+ scb->sg_size = scb->sg_max = nseg;
+ scb->sg_index = 0;
+
+ scb->bufaddr = scb->sg_addr;
+ } else
+ scb->bufaddr = dm->dm_segs[0].ds_addr;
+
+ if ((xs->xs_control & XS_CTL_POLL) == 0) {
+ int timeout = xs->timeout;
+ timeout = (timeout > 100000) ?
+ timeout / 1000 * hz : timeout * hz / 1000;
+ if (timeout == 0)
+ timeout = 1;
+ callout_reset(&xs->xs_callout, timeout, iha_timeout, scb);
+ }
+
+ s = splbio();
+
+ if (((scb->xs->xs_control & XS_RESET) != 0) ||
+ (scb->cmd[0] == REQUEST_SENSE))
+ iha_push_pend_scb(sc, scb); /* Insert SCB at head of Pend */
+ else
+ iha_append_pend_scb(sc, scb); /* Append SCB to tail of Pend */
+
+ /*
+ * Run through iha_main() to ensure something is active, if
+ * only this new SCB.
+ */
+ if (sc->sc_semaph != SEMAPH_IN_MAIN) {
+ iot = sc->sc_iot;
+ ioh = sc->sc_ioh;
+
+ bus_space_write_1(iot, ioh, TUL_IMSK, MASK_ALL);
+ sc->sc_semaph = SEMAPH_IN_MAIN;;
+
+ splx(s);
+ iha_main(sc);
+ s = splbio();
+
+ sc->sc_semaph = ~SEMAPH_IN_MAIN;;
+ bus_space_write_1(iot, ioh, TUL_IMSK, (MASK_ALL & ~MSCMP));
+ }
+
+ splx(s);
+}
+
+/*
+ * iha_done_scb - We have a scb which has been processed by the
+ * adaptor, now we look to see how the operation went.
+ */
+static void
+iha_done_scb(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+{
+ struct scsipi_xfer *xs = scb->xs;
+
+ if (xs != NULL) {
+ /* Cancel the timeout. */
+ callout_stop(&xs->xs_callout);
+
+ if (scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) {
+ bus_dmamap_sync(sc->sc_dmat, scb->dmap,
+ 0, scb->dmap->dm_mapsize,
+ (scb->flags & FLAG_DATAIN) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, scb->dmap);
+ }
+
+ xs->status = scb->ta_stat;
+
+ switch (scb->ha_stat) {
+ case HOST_OK:
+ switch (scb->ta_stat) {
+ case SCSI_OK:
+ case SCSI_CONDITION_MET:
+ case SCSI_INTERM:
+ case SCSI_INTERM_COND_MET:
+ xs->resid = scb->buflen;
+ xs->error = XS_NOERROR;
+ if ((scb->flags & FLAG_RSENS) != 0)
+ xs->error = XS_SENSE;
+ break;
+
+ case SCSI_RESV_CONFLICT:
+ case SCSI_BUSY:
+ case SCSI_QUEUE_FULL:
+ xs->error = XS_BUSY;
+ break;
+
+ case SCSI_TERMINATED:
+ case SCSI_ACA_ACTIVE:
+ case SCSI_CHECK:
+ scb->tcs->flags &=
+ ~(FLAG_SYNC_DONE | FLAG_WIDE_DONE);
+
+ if ((scb->flags & FLAG_RSENS) != 0 ||
+ iha_push_sense_request(sc, scb) != 0) {
+ scb->flags &= ~FLAG_RSENS;
+ printf("%s: request sense failed\n",
+ sc->sc_dev.dv_xname);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ xs->error = XS_SENSE;
+ return;
+
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ break;
+
+ case HOST_SEL_TOUT:
+ xs->error = XS_SELTIMEOUT;
+ break;
+
+ case HOST_SCSI_RST:
+ case HOST_DEV_RST:
+ xs->error = XS_RESET;
+ break;
+
+ case HOST_SPERR:
+ printf("%s: SCSI Parity error detected\n",
+ sc->sc_dev.dv_xname);
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case HOST_TIMED_OUT:
+ xs->error = XS_TIMEOUT;
+ break;
+
+ case HOST_DO_DU:
+ case HOST_BAD_PHAS:
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ scsipi_done(xs);
+ }
+
+ iha_append_free_scb(sc, scb);
+}
+
+/*
+ * iha_push_sense_request - obtain auto sense data by pushing the
+ * SCB needing it back onto the pending
+ * queue with a REQUEST_SENSE CDB.
+ */
+static int
+iha_push_sense_request(sc, scb)
+ struct iha_softc *sc;
+ struct iha_scb *scb;
+{
+ struct scsipi_xfer *xs = scb->xs;
+ struct scsipi_periph *periph = xs->xs_periph;
+ struct scsipi_sense *ss = (struct scsipi_sense *)scb->cmd;
+ int lun = periph->periph_lun;
+ int err;
+
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = lun << SCSI_CMD_LUN_SHIFT;
+ ss->unused[0] = ss->unused[1] = 0;
+ ss->length = sizeof(struct scsipi_sense_data);
+ ss->control = 0;
+
+ scb->flags = FLAG_RSENS | FLAG_DATAIN;
+
+ scb->scb_id &= ~MSG_IDENTIFY_DISCFLAG;
+
+ scb->scb_tagmsg = 0;
+ scb->ta_stat = SCSI_OK;
+
+ scb->cmdlen = sizeof(struct scsipi_sense);
+ scb->buflen = ss->length;
+
+ err = bus_dmamap_load(sc->sc_dmat, scb->dmap,
+ &xs->sense.scsi_sense, scb->buflen, NULL,
+ BUS_DMA_READ|BUS_DMA_NOWAIT);
+ if (err != 0) {
+ printf("iha_push_sense_request: cannot bus_dmamap_load()\n");
+ xs->error = XS_DRIVER_STUFFUP;
+ return 1;
+ }
+ bus_dmamap_sync(sc->sc_dmat, scb->dmap,
+ 0, scb->buflen, BUS_DMASYNC_PREREAD);
+
+ /* XXX What about queued command? */
+ iha_exec_scb(sc, scb);
+
+ return 0;
+}
+
+static void
+iha_timeout(arg)
+ void *arg;
+{
+ struct iha_scb *scb = (struct iha_scb *)arg;
+ struct scsipi_xfer *xs = scb->xs;
+ struct scsipi_periph *periph = xs->xs_periph;
+ struct iha_softc *sc;
+
+ sc = (void *)periph->periph_channel->chan_adapter->adapt_dev;
+
+ if (xs == NULL)
+ printf("[debug] iha_timeout called with xs == NULL\n");
+
+ else {
+ scsipi_printaddr(periph);
+ printf("SCSI OpCode 0x%02x timed out\n", xs->cmd->opcode);
+
+ iha_abort_xs(sc, xs, HOST_TIMED_OUT);
+ }
+}
+
+/*
+ * iha_abort_xs - find the SCB associated with the supplied xs and
+ * stop all processing on it, moving it to the done
+ * queue with the supplied host status value.
+ */
+static void
+iha_abort_xs(sc, xs, hastat)
+ struct iha_softc *sc;
+ struct scsipi_xfer *xs;
+ u_int8_t hastat;
+{
+ struct iha_scb *scb;
+ int i, s;
+
+ s = splbio();
+
+ /* Check the pending queue for the SCB pointing to xs */
+
+ TAILQ_FOREACH(scb, &sc->sc_pendscb, chain)
+ if (scb->xs == xs) {
+ iha_del_pend_scb(sc, scb);
+ iha_append_done_scb(sc, scb, hastat);
+ splx(s);
+ return;
+ }
+
+ /*
+ * If that didn't work, check all BUSY/SELECTING SCB's for one
+ * pointing to xs
+ */
+
+ for (i = 0, scb = sc->sc_scb; i < IHA_MAX_SCB; i++, scb++)
+ switch (scb->status) {
+ case STATUS_BUSY:
+ case STATUS_SELECT:
+ if (scb->xs == xs) {
+ iha_append_done_scb(sc, scb, hastat);
+ splx(s);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ splx(s);
+}
+
/*
* iha_data_over_run - return HOST_OK for all SCSI opcodes where BufLen
* is an 'Allocation Length'. All other SCSI opcodes
@@ -1013,7 +1462,7 @@ iha_scsi(sc)
*/
static u_int8_t
iha_data_over_run(scb)
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
{
switch (scb->cmd[0]) {
case 0x03: /* Request Sense SPC-2 */
@@ -1153,7 +1602,7 @@ iha_state_1(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
struct tcs *tcs;
int flags;
@@ -1214,7 +1663,7 @@ iha_state_2(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
iha_mark_busy_scb(scb);
@@ -1241,7 +1690,7 @@ iha_state_3(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
int flags;
for (;;) {
@@ -1296,7 +1745,7 @@ static int
iha_state_4(sc)
struct iha_softc *sc;
{
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
if ((scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) ==
(FLAG_DATAIN | FLAG_DATAOUT))
@@ -1359,7 +1808,7 @@ iha_state_5(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
struct iha_sg_element *sg;
u_int32_t cnt;
u_int8_t period, stat;
@@ -1507,7 +1956,7 @@ iha_state_8(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
int i;
u_int8_t tar;
@@ -1554,7 +2003,7 @@ iha_state_8(sc)
static int
iha_xfer_data(sc, scb, direction)
struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
int direction;
{
bus_space_tag_t iot = sc->sc_iot;
@@ -1595,7 +2044,7 @@ iha_xpad_in(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
if ((scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) != 0)
scb->ha_stat = HOST_DO_DU;
@@ -1627,7 +2076,7 @@ iha_xpad_out(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb = sc->sc_actscb;
+ struct iha_scb *scb = sc->sc_actscb;
if ((scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) != 0)
scb->ha_stat = HOST_DO_DU;
@@ -1662,7 +2111,7 @@ iha_status_msg(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
u_int8_t msg;
int phase;
@@ -1734,7 +2183,7 @@ iha_busfree(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
bus_space_write_1(iot, ioh, TUL_SCONFIG0, SCONFIG0DEFAULT);
@@ -1752,38 +2201,6 @@ iha_busfree(sc)
}
}
-static void
-iha_reset_scsi_bus(sc)
- struct iha_softc *sc;
-{
- struct iha_scsi_req_q *scb;
- struct tcs *tcs;
- int i, s;
-
- s = splbio();
-
- iha_reset_dma(sc);
-
- for (i = 0, scb = sc->sc_scb; i < IHA_MAX_SCB; i++, scb++)
- switch (scb->status) {
- case STATUS_BUSY:
- iha_append_done_scb(sc, scb, HOST_SCSI_RST);
- break;
-
- case STATUS_SELECT:
- iha_push_pend_scb(sc, scb);
- break;
-
- default:
- break;
- }
-
- for (i = 0, tcs = sc->sc_tcs; i < IHA_MAX_TARGETS; i++, tcs++)
- iha_reset_tcs(tcs, sc->sc_sconf1);
-
- splx(s);
-}
-
/*
* iha_resel - handle a detected SCSI bus reselection request.
*/
@@ -1793,7 +2210,7 @@ iha_resel(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct iha_scsi_req_q *scb;
+ struct iha_scb *scb;
struct tcs *tcs;
u_int8_t tag, target, lun, msg, abortmsg;
@@ -1943,31 +2360,6 @@ iha_msgin(sc)
}
static int
-iha_msgin_ignore_wid_resid(sc)
- struct iha_softc *sc;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
- int phase;
-
- phase = iha_wait(sc, MSG_ACCEPT);
-
- if (phase == PHASE_MSG_IN) {
- phase = iha_wait(sc, XF_FIFO_IN);
-
- if (phase != -1) {
- bus_space_write_1(iot, ioh, TUL_SFIFO, 0);
- bus_space_read_1(iot, ioh, TUL_SFIFO);
- bus_space_read_1(iot, ioh, TUL_SFIFO);
-
- phase = iha_wait(sc, MSG_ACCEPT);
- }
- }
-
- return (phase);
-}
-
-static int
iha_msgin_extended(sc)
struct iha_softc *sc;
{
@@ -2099,6 +2491,31 @@ iha_msgin_sdtr(sc)
}
static int
+iha_msgin_ignore_wid_resid(sc)
+ struct iha_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int phase;
+
+ phase = iha_wait(sc, MSG_ACCEPT);
+
+ if (phase == PHASE_MSG_IN) {
+ phase = iha_wait(sc, XF_FIFO_IN);
+
+ if (phase != -1) {
+ bus_space_write_1(iot, ioh, TUL_SFIFO, 0);
+ bus_space_read_1(iot, ioh, TUL_SFIFO);
+ bus_space_read_1(iot, ioh, TUL_SFIFO);
+
+ phase = iha_wait(sc, MSG_ACCEPT);
+ }
+ }
+
+ return (phase);
+}
+
+static int
iha_msgout(sc, msg)
struct iha_softc *sc;
u_int8_t msg;
@@ -2253,411 +2670,28 @@ iha_sync_done(sc)
bus_space_write_1(iot, ioh, TUL_SYNCM, tcs->syncm);
}
-void
-iha_reset_chip(sc)
- struct iha_softc *sc;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
-
- /* reset tulip chip */
-
- bus_space_write_1(iot, ioh, TUL_SCTRL0, RSCSI);
-
- do {
- sc->sc_sistat = bus_space_read_1(iot, ioh, TUL_SISTAT);
- } while ((sc->sc_sistat & SRSTD) == 0);
-
- iha_set_ssig(sc, 0, 0);
-
- bus_space_read_1(iot, ioh, TUL_SISTAT); /* Clear any active interrupt*/
-}
-
-static void
-iha_select(sc, scb, select_type)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
- u_int8_t select_type;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
-
- switch (select_type) {
- case SEL_ATN:
- bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_id);
- bus_space_write_multi_1(iot, ioh, TUL_SFIFO,
- scb->cmd, scb->cmdlen);
-
- scb->nextstat = 2;
- break;
-
- case SELATNSTOP:
- scb->nextstat = 1;
- break;
-
- case SEL_ATN3:
- bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_id);
- bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_tagmsg);
- bus_space_write_1(iot, ioh, TUL_SFIFO, scb->scb_tagid);
-
- bus_space_write_multi_1(iot, ioh, TUL_SFIFO, scb->cmd,
- scb->cmdlen);
-
- scb->nextstat = 2;
- break;
-
- default:
- printf("[debug] iha_select() - unknown select type = 0x%02x\n",
- select_type);
- return;
- }
-
- iha_del_pend_scb(sc, scb);
- scb->status = STATUS_SELECT;
-
- sc->sc_actscb = scb;
-
- bus_space_write_1(iot, ioh, TUL_SCMD, select_type);
-}
-
/*
- * iha_wait - wait for an interrupt to service or a SCSI bus phase change
- * after writing the supplied command to the tulip chip. If
- * the command is NO_OP, skip the command writing.
- */
-static int
-iha_wait(sc, cmd)
- struct iha_softc *sc;
- u_int8_t cmd;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
-
- if (cmd != NO_OP)
- bus_space_write_1(iot, ioh, TUL_SCMD, cmd);
-
- /*
- * Have to do this here, in addition to in iha_isr, because
- * interrupts might be turned off when we get here.
- */
- do {
- sc->sc_status0 = bus_space_read_1(iot, ioh, TUL_STAT0);
- } while ((sc->sc_status0 & INTPD) == 0);
-
- sc->sc_status1 = bus_space_read_1(iot, ioh, TUL_STAT1);
- sc->sc_sistat = bus_space_read_1(iot, ioh, TUL_SISTAT);
-
- sc->sc_phase = sc->sc_status0 & PH_MASK;
-
- if ((sc->sc_sistat & SRSTD) != 0) {
- /* SCSI bus reset interrupt */
- iha_reset_scsi_bus(sc);
- return (-1);
- }
-
- if ((sc->sc_sistat & RSELED) != 0)
- /* Reselection interrupt */
- return (iha_resel(sc));
-
- if ((sc->sc_sistat & STIMEO) != 0) {
- /* selected/reselected timeout interrupt */
- iha_busfree(sc);
- return (-1);
- }
-
- if ((sc->sc_sistat & DISCD) != 0) {
- /* BUS disconnection interrupt */
- if ((sc->sc_flags & FLAG_EXPECT_DONE_DISC) != 0) {
- bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
- bus_space_write_1(iot, ioh, TUL_SCONFIG0,
- SCONFIG0DEFAULT);
- bus_space_write_1(iot, ioh, TUL_SCTRL1, EHRSL);
- iha_append_done_scb(sc, sc->sc_actscb, HOST_OK);
- sc->sc_flags &= ~FLAG_EXPECT_DONE_DISC;
-
- } else if ((sc->sc_flags & FLAG_EXPECT_DISC) != 0) {
- bus_space_write_1(iot, ioh, TUL_SCTRL0, RSFIFO);
- bus_space_write_1(iot, ioh, TUL_SCONFIG0,
- SCONFIG0DEFAULT);
- bus_space_write_1(iot, ioh, TUL_SCTRL1, EHRSL);
- sc->sc_actscb = NULL;
- sc->sc_flags &= ~FLAG_EXPECT_DISC;
-
- } else
- iha_busfree(sc);
-
- return (-1);
- }
-
- return (sc->sc_phase);
-}
-
-/*
- * iha_done_scb - We have a scb which has been processed by the
- * adaptor, now we look to see how the operation went.
- */
-static void
-iha_done_scb(sc, scb)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
-{
- struct scsipi_xfer *xs = scb->xs;
-
- if (xs != NULL) {
- /* Cancel the timeout. */
- callout_stop(&xs->xs_callout);
-
- if (scb->flags & (FLAG_DATAIN | FLAG_DATAOUT)) {
- bus_dmamap_sync(sc->sc_dmat, scb->dmap,
- 0, scb->dmap->dm_mapsize,
- (scb->flags & FLAG_DATAIN) ?
- BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->sc_dmat, scb->dmap);
- }
-
- xs->status = scb->ta_stat;
-
- switch (scb->ha_stat) {
- case HOST_OK:
- switch (scb->ta_stat) {
- case SCSI_OK:
- case SCSI_CONDITION_MET:
- case SCSI_INTERM:
- case SCSI_INTERM_COND_MET:
- xs->resid = scb->buflen;
- xs->error = XS_NOERROR;
- if ((scb->flags & FLAG_RSENS) != 0)
- xs->error = XS_SENSE;
- break;
-
- case SCSI_RESV_CONFLICT:
- case SCSI_BUSY:
- case SCSI_QUEUE_FULL:
- xs->error = XS_BUSY;
- break;
-
- case SCSI_TERMINATED:
- case SCSI_ACA_ACTIVE:
- case SCSI_CHECK:
- scb->tcs->flags &=
- ~(FLAG_SYNC_DONE | FLAG_WIDE_DONE);
-
- if ((scb->flags & FLAG_RSENS) != 0 ||
- iha_push_sense_request(sc, scb) != 0) {
- scb->flags &= ~FLAG_RSENS;
- printf("%s: request sense failed\n",
- sc->sc_dev.dv_xname);
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
-
- xs->error = XS_SENSE;
- return;
-
- default:
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
- break;
-
- case HOST_SEL_TOUT:
- xs->error = XS_SELTIMEOUT;
- break;
-
- case HOST_SCSI_RST:
- case HOST_DEV_RST:
- xs->error = XS_RESET;
- break;
-
- case HOST_SPERR:
- printf("%s: SCSI Parity error detected\n",
- sc->sc_dev.dv_xname);
- xs->error = XS_DRIVER_STUFFUP;
- break;
-
- case HOST_TIMED_OUT:
- xs->error = XS_TIMEOUT;
- break;
-
- case HOST_DO_DU:
- case HOST_BAD_PHAS:
- default:
- xs->error = XS_DRIVER_STUFFUP;
- break;
- }
-
- scsipi_done(xs);
- }
-
- iha_append_free_scb(sc, scb);
-}
-
-static void
-iha_timeout(arg)
- void *arg;
-{
- struct iha_scsi_req_q *scb = (struct iha_scsi_req_q *)arg;
- struct scsipi_xfer *xs = scb->xs;
- struct scsipi_periph *periph = xs->xs_periph;
- struct iha_softc *sc;
-
- sc = (void *)periph->periph_channel->chan_adapter->adapt_dev;
-
- if (xs == NULL)
- printf("[debug] iha_timeout called with xs == NULL\n");
-
- else {
- scsipi_printaddr(periph);
- printf("SCSI OpCode 0x%02x timed out\n", xs->cmd->opcode);
-
- iha_abort_xs(sc, xs, HOST_TIMED_OUT);
- }
-}
-
-static void
-iha_exec_scb(sc, scb)
- struct iha_softc *sc;
- struct iha_scsi_req_q *scb;
-{
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
- bus_dmamap_t dm;
- struct scsipi_xfer *xs = scb->xs;
- int nseg, s;
-
- dm = scb->dmap;
- nseg = dm->dm_nsegs;
-
- if (nseg > 1) {
- struct iha_sg_element *sg = scb->sglist;
- int i;
-
- for (i = 0; i < nseg; i++) {
- sg[i].sg_len = htole32(dm->dm_segs[i].ds_len);
- sg[i].sg_addr = htole32(dm->dm_segs[i].ds_addr);
- }
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- scb->sgoffset, IHA_SG_SIZE,
- BUS_DMASYNC_PREWRITE);
-
- scb->flags |= FLAG_SG;
- scb->sg_size = scb->sg_max = nseg;
- scb->sg_index = 0;
-
- scb->bufaddr = scb->sg_addr;
- } else
- scb->bufaddr = dm->dm_segs[0].ds_addr;
-
- if ((xs->xs_control & XS_CTL_POLL) == 0) {
- int timeout = xs->timeout;
- timeout = (timeout > 100000) ?
- timeout / 1000 * hz : timeout * hz / 1000;
- if (timeout == 0)
- timeout = 1;
- callout_reset(&xs->xs_callout, timeout, iha_timeout, scb);
- }
-
- s = splbio();
-
- if (((scb->xs->xs_control & XS_RESET) != 0) ||
- (scb->cmd[0] == REQUEST_SENSE))
- iha_push_pend_scb(sc, scb); /* Insert SCB at head of Pend */
- else
- iha_append_pend_scb(sc, scb); /* Append SCB to tail of Pend */
-
- /*
- * Run through iha_main() to ensure something is active, if
- * only this new SCB.
- */
- if (sc->sc_semaph != SEMAPH_IN_MAIN) {
- iot = sc->sc_iot;
- ioh = sc->sc_ioh;
-
- bus_space_write_1(iot, ioh, TUL_IMSK, MASK_ALL);
- sc->sc_semaph = SEMAPH_IN_MAIN;;
-
- splx(s);
- iha_main(sc);
- s = splbio();
-
- sc->sc_semaph = ~SEMAPH_IN_MAIN;;
- bus_space_write_1(iot, ioh, TUL_IMSK, (MASK_ALL & ~MSCMP));
- }
-
- splx(s);
-}
-
-
-/*
- * iha_set_ssig - read the current scsi signal mask, then write a new
- * one which turns off/on the specified signals.
+ * iha_bad_seq - a SCSI bus phase was encountered out of the
+ * correct/expected sequence. Reset the SCSI bus.
*/
static void
-iha_set_ssig(sc, offsigs, onsigs)
- struct iha_softc *sc;
- u_int8_t offsigs, onsigs;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
- u_int8_t currsigs;
-
- currsigs = bus_space_read_1(iot, ioh, TUL_SSIGI);
- bus_space_write_1(iot, ioh, TUL_SSIGO, (currsigs & ~offsigs) | onsigs);
-}
-
-/*
- * iha_alloc_sglist - allocate and map sglist for SCB's
- */
-static int
-iha_alloc_sglist(sc)
+iha_bad_seq(sc)
struct iha_softc *sc;
{
- bus_dma_segment_t seg;
- int error, rseg;
-
- /*
- * Allocate dma-safe memory for the SCB's sglist
- */
- if ((error = bus_dmamem_alloc(sc->sc_dmat,
- IHA_SG_SIZE * IHA_MAX_SCB,
- PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
- printf(": unable to allocate sglist, error = %d\n", error);
- return (error);
- }
- if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
- IHA_SG_SIZE * IHA_MAX_SCB, (caddr_t *)&sc->sc_sglist,
- BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
- printf(": unable to map sglist, error = %d\n", error);
- return (error);
- }
-
- /*
- * Create and load the DMA map used for the SCBs
- */
- if ((error = bus_dmamap_create(sc->sc_dmat,
- IHA_SG_SIZE * IHA_MAX_SCB, 1, IHA_SG_SIZE * IHA_MAX_SCB,
- 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
- printf(": unable to create control DMA map, error = %d\n",
- error);
- return (error);
- }
- if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
- sc->sc_sglist, IHA_SG_SIZE * IHA_MAX_SCB,
- NULL, BUS_DMA_NOWAIT)) != 0) {
- printf(": unable to load control DMA map, error = %d\n", error);
- return (error);
- }
+ struct iha_scb *scb = sc->sc_actscb;
- memset(sc->sc_sglist, 0, IHA_SG_SIZE * IHA_MAX_SCB);
+ if (scb != NULL)
+ iha_append_done_scb(sc, scb, HOST_BAD_PHAS);
- return (0);
+ iha_reset_scsi_bus(sc);
+ iha_reset_chip(sc);
}
/*
* iha_read_eeprom - read Serial EEPROM value & set to defaults
* if required. XXX - Writing does NOT work!
*/
-void
+static void
iha_read_eeprom(sc, eeprom)
struct iha_softc *sc;
struct iha_eeprom *eeprom;
@@ -2687,7 +2721,7 @@ iha_read_eeprom(sc, eeprom)
* change those values different from the values
* in iha_eeprom.
*/
-void
+static void
iha_se2_update_all(sc)
struct iha_softc *sc;
{
@@ -2722,7 +2756,7 @@ iha_se2_update_all(sc)
* iha_se2_wr - write the given 16 bit value into the Serial EEPROM
* at the specified offset
*/
-void
+static void
iha_se2_wr(sc, addr, writeword)
struct iha_softc *sc;
int addr;
@@ -2772,7 +2806,7 @@ iha_se2_wr(sc, addr, writeword)
* offset in the Serial E2PROM
*
*/
-u_int16_t
+static u_int16_t
iha_se2_rd(sc, addr)
struct iha_softc *sc;
int addr;
@@ -2806,7 +2840,7 @@ iha_se2_rd(sc, addr)
/*
* iha_se2_rd_all - Read SCSI H/A config parameters from serial EEPROM
*/
-int
+static int
iha_se2_rd_all(sc, buf)
struct iha_softc *sc;
u_int16_t *buf;
@@ -2830,7 +2864,7 @@ iha_se2_rd_all(sc, buf)
/*
* iha_se2_instr - write an octet to serial E2PROM one bit at a time
*/
-void
+static void
iha_se2_instr(sc, instr)
struct iha_softc *sc;
int instr;
@@ -2860,50 +2894,3 @@ iha_se2_instr(sc, instr)
bus_space_write_1(iot, ioh, TUL_NVRAM, NVRCS);
}
-
-/*
- * iha_reset_tcs - reset the target control structure pointed
- * to by tcs to default values. tcs flags
- * only has the negotiation done bits reset as
- * the other bits are fixed at initialization.
- */
-void
-iha_reset_tcs(tcs, config0)
- struct tcs *tcs;
- u_int8_t config0;
-{
-
- tcs->flags &= ~(FLAG_SYNC_DONE | FLAG_WIDE_DONE);
- tcs->period = 0;
- tcs->offset = 0;
- tcs->tagcnt = 0;
- tcs->ntagscb = NULL;
- tcs->syncm = 0;
- tcs->sconfig0 = config0;
-}
-
-void
-iha_update_xfer_mode(sc, target)
- struct iha_softc *sc;
- int target;
-{
- struct tcs *tcs = &sc->sc_tcs[target];
- struct scsipi_xfer_mode xm;
-
- xm.xm_target = target;
- xm.xm_mode = 0;
- xm.xm_period = 0;
- xm.xm_offset = 0;
-
- if (tcs->syncm & PERIOD_WIDE_SCSI)
- xm.xm_mode |= PERIPH_CAP_WIDE16;
-
- if (tcs->period) {
- xm.xm_mode |= PERIPH_CAP_SYNC;
- xm.xm_period = tcs->period;
- xm.xm_offset = tcs->offset;
- }
-
- scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
-}
-
diff --git a/sys/dev/ic/ihavar.h b/sys/dev/ic/ihavar.h
index a45e1ffdd57..6197d9d780d 100644
--- a/sys/dev/ic/ihavar.h
+++ b/sys/dev/ic/ihavar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ihavar.h,v 1.6 2001/11/17 21:26:12 tsutsui Exp $ */
+/* $NetBSD: ihavar.h,v 1.7 2002/02/09 15:13:01 tsutsui Exp $ */
/*
* Initio INI-9xxxU/UW SCSI Device Driver
*
@@ -68,12 +68,12 @@ struct iha_sg_element {
#define IHA_SG_SIZE (sizeof(struct iha_sg_element) * IHA_MAX_SG_ENTRIES)
/*
- * iha_scsi_req_q - SCSI Request structure used by the
+ * iha_scb - SCSI Request structure used by the
* Tulip (aka inic-940/950).
*/
-struct iha_scsi_req_q {
- TAILQ_ENTRY(iha_scsi_req_q) chain;
+struct iha_scb {
+ TAILQ_ENTRY(iha_scb) chain;
bus_dmamap_t dmap; /* maps xs->buf xfer buffer */
@@ -141,10 +141,10 @@ struct tcs {
int offset;
int tagcnt;
- struct iha_scsi_req_q *ntagscb;
+ struct iha_scb *ntagscb;
- u_int8_t syncm;
- u_int8_t sconfig0;
+ u_int8_t syncm;
+ u_int8_t sconfig0;
};
struct iha_softc {
@@ -180,21 +180,21 @@ struct iha_softc {
#define PHASE_MSG_OUT 0x06 /* 1 1 0 */
#define PHASE_MSG_IN 0x07 /* 1 1 1 */
- struct iha_scsi_req_q *sc_scb; /* SCB array */
- struct iha_scsi_req_q *sc_actscb; /* SCB using SCSI bus */
+ struct iha_scb *sc_scb; /* SCB array */
+ struct iha_scb *sc_actscb; /* SCB using SCSI bus */
struct iha_sg_element *sc_sglist;
- TAILQ_HEAD(, iha_scsi_req_q) sc_freescb,
- sc_pendscb,
- sc_donescb;
+ TAILQ_HEAD(, iha_scb) sc_freescb,
+ sc_pendscb,
+ sc_donescb;
struct tcs sc_tcs[IHA_MAX_TARGETS];
- u_int8_t sc_msg[IHA_MAX_EXTENDED_MSG]; /* [0] len, [1] Msg Code */
- u_int8_t sc_sistat;
- u_int8_t sc_status0;
- u_int8_t sc_status1;
- u_int8_t sc_sconf1;
+ u_int8_t sc_msg[IHA_MAX_EXTENDED_MSG]; /* [0] len, [1] Msg Code */
+ u_int8_t sc_sistat;
+ u_int8_t sc_status0;
+ u_int8_t sc_status1;
+ u_int8_t sc_sconf1;
};
/*