- Don't get stalled by a bogus HA_ST_MORE condition.

- Don't trust HA_ST_MORE again if the above situation occurs.
- Nuke bitfields in 'struct eata_sp'.
- Don't bother using scatter-gather if DMA map contains only 1 segment.
- Return TRY_AGAIN_LATER and not COMPLETE if an EATA command times out.
- Check SCSI status in dpt_inquire(), not just HBA status.
- Some cosmetic changes and sanity checks.
This commit is contained in:
ad 1999-10-19 20:16:48 +00:00
parent d3c33c1744
commit 675c12dbcb
2 changed files with 78 additions and 66 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: dpt.c,v 1.8 1999/10/04 23:57:32 thorpej Exp $ */
/* $NetBSD: dpt.c,v 1.9 1999/10/19 20:16:48 ad Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dpt.c,v 1.8 1999/10/04 23:57:32 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: dpt.c,v 1.9 1999/10/19 20:16:48 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -157,6 +157,7 @@ dpt_intr(xxx_sc)
struct dpt_softc *sc;
struct dpt_ccb *ccb;
struct eata_sp *sp;
static int moretimo;
int more;
sc = xxx_sc;
@ -168,6 +169,10 @@ dpt_intr(xxx_sc)
printf("%s: spurious intr\n", sc->sc_dv.dv_xname);
#endif
/* Don't get stalled by HA_ST_MORE */
if (moretimo < DPT_MORE_TIMEOUT / 10)
moretimo = 0;
for (;;) {
/*
* HBA might have interrupted while we were dealing with the
@ -177,7 +182,7 @@ dpt_intr(xxx_sc)
* around.
*/
if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0) {
if (more != 0) {
if (more != 0 && moretimo++ < DPT_MORE_TIMEOUT / 10) {
DELAY(10);
continue;
}
@ -215,7 +220,7 @@ dpt_intr(xxx_sc)
CCB_OFF(sc, ccb), sizeof(struct dpt_ccb),
BUS_DMASYNC_POSTWRITE);
ccb->ccb_hba_status = sp->sp_hba_status;
ccb->ccb_hba_status = sp->sp_hba_status & 0x7F;
ccb->ccb_scsi_status = sp->sp_scsi_status;
/*
@ -235,6 +240,10 @@ dpt_intr(xxx_sc)
sp->sp_ccbid = -1;
more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
}
/* Don't get stalled by HA_ST_MORE */
if (moretimo < DPT_MORE_TIMEOUT / 10)
moretimo = 0;
}
return (0);
@ -335,7 +344,7 @@ dpt_init(sc, intrstr)
model[i] = '\0';
/* Find the cannonical name for the board */
for (i = 0; dpt_cname[i]; i += 2)
for (i = 0; dpt_cname[i] != NULL; i += 2)
if (memcmp(ei->ei_model, dpt_cname[i], 6) == 0)
break;
@ -478,9 +487,10 @@ dpt_poll(sc, ccb)
panic("dpt_poll: called for non-CCB_PRIVATE request\n");
#endif
if ((ccb->ccb_flg & CCB_INTR) != 0)
return (0);
for (i = ccb->ccb_timeout * 20; i; i--) {
if ((ccb->ccb_flg & CCB_INTR) != 0)
return (0);
if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) != 0)
dpt_intr(sc);
if ((ccb->ccb_flg & CCB_INTR) != 0)
@ -545,7 +555,8 @@ dpt_readcfg(sc)
p = (u_int16_t *)ec;
if (dpt_wait(sc, 0xFF, HA_ST_DATA_RDY, 2000)) {
printf("%s: cfg data didn't appear\n", sc->sc_dv.dv_xname);
printf("%s: cfg data didn't appear (status:%02x)\n",
sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS));
return (-1);
}
@ -687,9 +698,9 @@ dpt_create_ccbs(sc, ccbstore, count)
}
/*
* Get a free ccb. If there are none, see if we can allocate a new one.
* Otherwise either return an error or if we are permitted to, sleep until
* one becomes free.
* Get a free ccb. If there are none, see if we can allocate a new one. If
* none are available right now and we are permitted to sleep, then wait
* until one becomes free, otherwise return an error.
*/
struct dpt_ccb *
dpt_alloc_ccb(sc, flg)
@ -702,7 +713,7 @@ dpt_alloc_ccb(sc, flg)
s = splbio();
for (;;) {
ccb = sc->sc_free_ccb.tqh_first;
ccb = TAILQ_FIRST(&sc->sc_free_ccb);
if (ccb) {
TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_chain);
break;
@ -803,10 +814,10 @@ dpt_done_ccb(sc, ccb)
scsipi_done(xs);
/*
* If there are queue entries in the software queue, try to run the
* first one. We should be more or less guaranteed to succeed, since
* we just freed an CCB. NOTE: dpt_scsi_cmd() relies on our calling
* it with the first entry in the queue.
* If there are entries in the software queue, try to run the first
* one. We should be more or less guaranteed to succeed, since we
* just freed an CCB. NOTE: dpt_scsi_cmd() relies on our calling it
* with the first entry in the queue.
*/
if ((xs = TAILQ_FIRST(&sc->sc_queue)) != NULL)
dpt_scsi_cmd(xs);
@ -819,13 +830,14 @@ int
dpt_scsi_cmd(xs)
struct scsipi_xfer *xs;
{
int error, seg, flags, s, fromqueue, dontqueue;
int error, i, flags, s, fromqueue, dontqueue;
struct scsipi_link *sc_link;
struct dpt_softc *sc;
struct dpt_ccb *ccb;
struct eata_sg *sg;
struct eata_cp *cp;
bus_dma_tag_t dmat;
bus_dmamap_t xfer;
sc_link = xs->sc_link;
flags = xs->xs_control;
@ -866,8 +878,8 @@ dpt_scsi_cmd(xs)
/* If there are jobs in the queue, run them first */
if (TAILQ_FIRST(&sc->sc_queue) != NULL) {
/*
* If we can't queue, we have to abort, since we have
* to preserve the queue order.
* If we can't queue we abort, since we must
* preserve the queue order.
*/
if (dontqueue) {
splx(s);
@ -883,10 +895,7 @@ dpt_scsi_cmd(xs)
}
}
/*
* Get a CCB. If the transfer is from a buf (possibly from interrupt
* time) then we can't allow it to sleep.
*/
/* Get a CCB */
if ((ccb = dpt_alloc_ccb(sc, flags)) == NULL) {
/* If we can't queue, we lose */
if (dontqueue) {
@ -897,7 +906,7 @@ dpt_scsi_cmd(xs)
/*
* Stuff request into the queue, in front if we came off
* in the first place.
* it in the first place.
*/
if (fromqueue)
TAILQ_INSERT_HEAD(&sc->sc_queue, xs, adapter_q);
@ -909,10 +918,6 @@ dpt_scsi_cmd(xs)
splx(s);
/* Synchronous xfers musn't write-back through the cache */
if (xs->bp != NULL && (xs->bp->b_flags & (B_ASYNC | B_READ)) == 0)
ccb->ccb_flg |= CCB_SYNC;
ccb->ccb_xs = xs;
ccb->ccb_timeout = xs->timeout;
@ -927,32 +932,33 @@ dpt_scsi_cmd(xs)
cp->cp_dispri = 1;
cp->cp_identify = 1;
cp->cp_autosense = 1;
cp->cp_nocache = ((ccb->ccb_flg & CCB_SYNC) != 0);
cp->cp_datain = ((flags & XS_CTL_DATA_IN) != 0);
cp->cp_dataout = ((flags & XS_CTL_DATA_OUT) != 0);
cp->cp_interpret = (sc->sc_hbaid[sc_link->scsipi_scsi.channel] ==
sc_link->scsipi_scsi.target);
/* Synchronous xfers musn't write-back through the cache */
if (xs->bp != NULL && (xs->bp->b_flags & (B_ASYNC | B_READ)) == 0)
cp->cp_nocache = 1;
else
cp->cp_nocache = 0;
cp->cp_senseaddr = SWAP32(sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
CCB_OFF(sc, ccb) + offsetof(struct dpt_ccb, ccb_sense));
if (xs->datalen) {
sg = ccb->ccb_sg;
seg = 0;
xfer = ccb->ccb_dmamap_xfer;
#ifdef TFS
if (flags & XS_CTL_DATA_UIO) {
error = bus_dmamap_load_uio(dmat,
ccb->ccb_dmamap_xfer, (struct uio *)xs->data,
(flags & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
if ((flags & XS_CTL_DATA_UIO) != 0) {
error = bus_dmamap_load_uio(dmat, xfer,
(struct uio *)xs->data, (flags & XS_CTL_NOSLEEP) ?
BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
} else
#endif /*TFS */
{
error = bus_dmamap_load(dmat,
ccb->ccb_dmamap_xfer,
xs->data, xs->datalen, NULL,
(flags & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
error = bus_dmamap_load(dmat, xfer, xs->data,
xs->datalen, NULL, (flags & XS_CTL_NOSLEEP) ?
BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
}
if (error) {
@ -967,26 +973,31 @@ dpt_scsi_cmd(xs)
return (COMPLETE);
}
bus_dmamap_sync(dmat, ccb->ccb_dmamap_xfer, 0,
ccb->ccb_dmamap_xfer->dm_mapsize,
bus_dmamap_sync(dmat, xfer, 0, xfer->dm_mapsize,
(flags & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD :
BUS_DMASYNC_PREWRITE);
/*
* Load the hardware scatter/gather map with the
* contents of the DMA map.
*/
for (seg = 0; seg < ccb->ccb_dmamap_xfer->dm_nsegs; seg++) {
ccb->ccb_sg[seg].sg_addr =
SWAP32(ccb->ccb_dmamap_xfer->dm_segs[seg].ds_addr);
ccb->ccb_sg[seg].sg_len =
SWAP32(ccb->ccb_dmamap_xfer->dm_segs[seg].ds_len);
/* Don't bother using scatter/gather for just 1 segment */
if (xfer->dm_nsegs == 1) {
cp->cp_dataaddr = SWAP32(xfer->dm_segs[0].ds_addr);
cp->cp_datalen = SWAP32(xfer->dm_segs[0].ds_len);
cp->cp_scatter = 0;
} else {
/*
* Load the hardware scatter/gather map with the
* contents of the DMA map.
*/
sg = ccb->ccb_sg;
for (i = 0; i < xfer->dm_nsegs; i++, sg++) {
sg->sg_addr = SWAP32(xfer->dm_segs[i].ds_addr);
sg->sg_len = SWAP32(xfer->dm_segs[i].ds_len);
}
cp->cp_dataaddr = SWAP32(CCB_OFF(sc, ccb) +
sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
offsetof(struct dpt_ccb, ccb_sg));
cp->cp_datalen = SWAP32(i * sizeof(struct eata_sg));
cp->cp_scatter = 1;
}
cp->cp_dataaddr = SWAP32(sc->sc_dmamap_ccb->dm_segs[0].ds_addr
+ CCB_OFF(sc, ccb) + offsetof(struct dpt_ccb, ccb_sg));
cp->cp_datalen = SWAP32(seg * sizeof(struct eata_sg));
cp->cp_scatter = 1;
} else {
cp->cp_dataaddr = 0;
cp->cp_datalen = 0;
@ -1010,8 +1021,8 @@ dpt_scsi_cmd(xs)
if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa, CP_DMA_CMD, 0)) {
printf("%s: dpt_cmd failed\n", sc->sc_dv.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
dpt_done_ccb(sc, ccb);
return (COMPLETE);
dpt_free_ccb(sc, ccb);
return (TRY_AGAIN_LATER);
}
if (dontqueue == 0)
@ -1084,7 +1095,6 @@ dpt_dump_sp(sp)
int i;
printf("\thba_status\t%02x\n", sp->sp_hba_status);
printf("\teoc\t\t%d\n", sp->sp_eoc);
printf("\tscsi_status\t%02x\n", sp->sp_scsi_status);
printf("\tinv_residue\t%d\n", sp->sp_inv_residue);
printf("\tccbid\t\t%d\n", sp->sp_ccbid);
@ -1162,7 +1172,7 @@ dpt_hba_inquire(sc, ei)
if (dpt_poll(sc, ccb))
panic("%s: inquiry timed out", sc->sc_dv.dv_xname);
if (ccb->ccb_hba_status != HA_NO_ERROR ||
if (ccb->ccb_hba_status != HA_NO_ERROR ||
ccb->ccb_scsi_status != SCSI_OK)
panic("%s: inquiry failed (hba:%02x scsi:%02x",
sc->sc_dv.dv_xname, ccb->ccb_hba_status,

View File

@ -1,4 +1,4 @@
/* $NetBSD: dptreg.h,v 1.3 1999/10/01 12:08:51 ad Exp $ */
/* $NetBSD: dptreg.h,v 1.4 1999/10/19 20:16:48 ad Exp $ */
/*
* Copyright (c) 1999 Andy Doran <ad@NetBSD.org>
@ -39,7 +39,8 @@
#define DPT_MAX_XFER ((DPT_SG_SIZE - 1) << PGSHIFT)
#define DPT_MAX_CCBS 256
#define DPT_SG_SIZE 64
#define DPT_ABORT_TIMEOUT 2000
#define DPT_ABORT_TIMEOUT 2000 /* milliseconds */
#define DPT_MORE_TIMEOUT 1000 /* microseconds */
#ifdef _KERNEL
@ -181,8 +182,7 @@ struct eata_cp {
* contains status, message info and a handle on the initiating CCB.
*/
struct eata_sp {
u_int8_t sp_hba_status : 7; /* host adapter status */
u_int8_t sp_eoc : 1; /* end of command (unsafe) */
u_int8_t sp_hba_status; /* host adapter status */
u_int8_t sp_scsi_status; /* SCSI bus status */
u_int8_t sp_reserved[2]; /* reserved */
u_int32_t sp_inv_residue; /* bytes not transfered */
@ -193,7 +193,9 @@ struct eata_sp {
u_int8_t sp_messages[9];
};
/* HBA status as returned by status packet */
/*
* HBA status as returned by status packet. Bit 7 signals end of command.
*/
#define HA_NO_ERROR 0x00 /* No error on command */
#define HA_ERROR_SEL_TO 0x01 /* Device selection timeout */
#define HA_ERROR_CMD_TO 0x02 /* Device command timeout */