- 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:
parent
d3c33c1744
commit
675c12dbcb
132
sys/dev/ic/dpt.c
132
sys/dev/ic/dpt.c
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue