Do simple tagged queueing, enabled by default.

This commit is contained in:
fvdl 2000-03-25 19:52:12 +00:00
parent 398dafb09a
commit 97688d9a83
1 changed files with 90 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: aic7xxx.c,v 1.44 2000/03/23 07:01:29 thorpej Exp $ */ /* $NetBSD: aic7xxx.c,v 1.45 2000/03/25 19:52:12 fvdl Exp $ */
/* /*
* Generic driver for the aic7xxx based adaptec SCSI controllers * Generic driver for the aic7xxx based adaptec SCSI controllers
@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.41 2000/02/09 21:24:58 gibbs Exp $ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.42 2000/03/18 22:28:18 gibbs Exp $
*/ */
/* /*
* A few notes on features of the driver. * A few notes on features of the driver.
@ -325,6 +325,8 @@ static void ahcminphys(struct buf *);
static __inline struct scsipi_xfer *ahc_first_xs(struct ahc_softc *); static __inline struct scsipi_xfer *ahc_first_xs(struct ahc_softc *);
static __inline void ahc_swap_hscb(struct hardware_scb *); static __inline void ahc_swap_hscb(struct hardware_scb *);
static __inline void ahc_swap_sg(struct ahc_dma_seg *); static __inline void ahc_swap_sg(struct ahc_dma_seg *);
static void ahc_check_tags(struct ahc_softc *, struct scsipi_xfer *);
static int ahc_istagged_device(struct ahc_softc *, struct scsipi_xfer *);
#if defined(AHC_DEBUG) && 0 #if defined(AHC_DEBUG) && 0
static void ahc_dumptinfo(struct ahc_softc *, struct ahc_initiator_tinfo *); static void ahc_dumptinfo(struct ahc_softc *, struct ahc_initiator_tinfo *);
@ -353,8 +355,9 @@ ahc_first_xs(struct ahc_softc *ahc)
while (xs != NULL) { while (xs != NULL) {
target = xs->sc_link->scsipi_scsi.target; target = xs->sc_link->scsipi_scsi.target;
if (ahc->devqueue_blocked[target] == 0 && if (ahc->devqueue_blocked[target] == 0 &&
ahc_index_busy_tcl(ahc, XS_TCL(ahc, xs), FALSE) == (!ahc_istagged_device(ahc, xs) &&
SCB_LIST_NULL) ahc_index_busy_tcl(ahc, XS_TCL(ahc, xs), FALSE) ==
SCB_LIST_NULL))
break; break;
xs = TAILQ_NEXT(xs, adapter_q); xs = TAILQ_NEXT(xs, adapter_q);
} }
@ -808,8 +811,8 @@ static const int num_phases = (sizeof(phase_table)/sizeof(phase_table[0])) - 1;
*/ */
#define AHC_SYNCRATE_DT 0 #define AHC_SYNCRATE_DT 0
#define AHC_SYNCRATE_ULTRA2 1 #define AHC_SYNCRATE_ULTRA2 1
#define AHC_SYNCRATE_ULTRA 2 #define AHC_SYNCRATE_ULTRA 3
#define AHC_SYNCRATE_FAST 5 #define AHC_SYNCRATE_FAST 6
static struct ahc_syncrate ahc_syncrates[] = { static struct ahc_syncrate ahc_syncrates[] = {
/* ultra2 fast/ultra period rate */ /* ultra2 fast/ultra period rate */
{ 0x42, 0x000, 9, "80.0" }, { 0x42, 0x000, 9, "80.0" },
@ -3340,7 +3343,8 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
* XXX if we are holding two commands per lun, * XXX if we are holding two commands per lun,
* send the next command. * send the next command.
*/ */
ahc_index_busy_tcl(ahc, scb->hscb->tcl, /*unbusy*/TRUE); if (!(scb->hscb->control & TAG_ENB))
ahc_index_busy_tcl(ahc, scb->hscb->tcl, /*unbusy*/TRUE);
/* /*
* If the recovery SCB completes, we have to be * If the recovery SCB completes, we have to be
@ -3420,6 +3424,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
splx(s); splx(s);
} else { } else {
xs->xs_status |= XS_STS_DONE; xs->xs_status |= XS_STS_DONE;
ahc_check_tags(ahc, xs);
scsipi_done(xs); scsipi_done(xs);
} }
@ -3887,10 +3892,11 @@ ahc_action(struct scsipi_xfer *xs)
* private queue to wait for our turn. * private queue to wait for our turn.
*/ */
tcl = XS_TCL(ahc, xs); tcl = XS_TCL(ahc, xs);
if (ahc->queue_blocked || if (ahc->queue_blocked ||
ahc->devqueue_blocked[xs->sc_link->scsipi_scsi.target] || ahc->devqueue_blocked[xs->sc_link->scsipi_scsi.target] ||
ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL) { (!ahc_istagged_device(ahc, xs) &&
ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL)) {
if (dontqueue) { if (dontqueue) {
splx(s); splx(s);
xs->error = XS_DRIVER_STUFFUP; xs->error = XS_DRIVER_STUFFUP;
@ -3965,7 +3971,8 @@ get_scb:
tcl = XS_TCL(ahc, xs); tcl = XS_TCL(ahc, xs);
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
if (ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL) if (!ahc_istagged_device(ahc, xs) &&
ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL)
panic("ahc: queuing for busy target"); panic("ahc: queuing for busy target");
#endif #endif
@ -3973,7 +3980,10 @@ get_scb:
hscb = scb->hscb; hscb = scb->hscb;
hscb->tcl = tcl; hscb->tcl = tcl;
ahc_busy_tcl(ahc, scb); if (ahc_istagged_device(ahc, xs))
scb->hscb->control |= MSG_SIMPLE_Q_TAG;
else
ahc_busy_tcl(ahc, scb);
splx(s); splx(s);
@ -4075,7 +4085,8 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments)
* be aborted. * be aborted.
*/ */
if (xs->xs_status & XS_STS_DONE) { if (xs->xs_status & XS_STS_DONE) {
ahc_index_busy_tcl(ahc, scb->hscb->tcl, TRUE); if (!ahc_istagged_device(ahc, xs))
ahc_index_busy_tcl(ahc, scb->hscb->tcl, TRUE);
if (nsegments != 0) if (nsegments != 0)
bus_dmamap_unload(ahc->parent_dmat, scb->dmamap); bus_dmamap_unload(ahc->parent_dmat, scb->dmamap);
ahcfreescb(ahc, scb); ahcfreescb(ahc, scb);
@ -4205,7 +4216,8 @@ ahc_setup_data(struct ahc_softc *ahc, struct scsipi_xfer *xs,
(xs->xs_control & XS_CTL_NOSLEEP) ? (xs->xs_control & XS_CTL_NOSLEEP) ?
BUS_DMA_NOWAIT : BUS_DMA_WAITOK); BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
if (error) { if (error) {
ahc_index_busy_tcl(ahc, hscb->tcl, TRUE); if (!ahc_istagged_device(ahc, xs))
ahc_index_busy_tcl(ahc, hscb->tcl, TRUE);
return (TRY_AGAIN_LATER); /* XXX fvdl */ return (TRY_AGAIN_LATER); /* XXX fvdl */
} }
error = ahc_execute_scb(scb, error = ahc_execute_scb(scb,
@ -5564,3 +5576,68 @@ ahc_dumptinfo(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo)
tinfo->user.offset, tinfo->user.ppr_flags); tinfo->user.offset, tinfo->user.ppr_flags);
} }
#endif #endif
static void
ahc_check_tags(struct ahc_softc *ahc, struct scsipi_xfer *xs)
{
struct scsipi_inquiry_data *inq;
struct ahc_devinfo devinfo;
int target_id, our_id;
if (xs->cmd->opcode != INQUIRY || xs->error != XS_NOERROR)
return;
target_id = xs->sc_link->scsipi_scsi.target;
our_id = SIM_SCSI_ID(ahc, xs->sc_link);
/*
* Sneak a look at the results of the SCSI Inquiry
* command and see if we can do Tagged queing. This
* should really be done by the higher level drivers.
*/
inq = (struct scsipi_inquiry_data *)xs->data;
if ((inq->flags & SID_CmdQue) && !(ahc_istagged_device(ahc, xs))) {
printf("%s: target %d using tagged queuing\n",
ahc_name(ahc), xs->sc_link->scsipi_scsi.target);
ahc_compile_devinfo(&devinfo,
our_id, target_id, xs->sc_link->scsipi_scsi.lun,
SIM_CHANNEL(ahc, xs->sc_link), ROLE_INITIATOR);
ahc_set_tags(ahc, &devinfo, TRUE);
if (ahc->scb_data->maxhscbs >= 16 ||
(ahc->flags & AHC_PAGESCBS)) {
/* Default to 8 tags */
xs->sc_link->openings += 6;
} else {
/*
* Default to 4 tags on whimpy
* cards that don't have much SCB
* space and can't page. This prevents
* a single device from hogging all
* slots. We should really have a better
* way of providing fairness.
*/
xs->sc_link->openings += 2;
}
}
}
static int
ahc_istagged_device(struct ahc_softc *ahc, struct scsipi_xfer *xs)
{
char channel;
u_int our_id, target;
struct tmode_tstate *tstate;
struct ahc_devinfo devinfo;
channel = SIM_CHANNEL(ahc, xs->sc_link);
our_id = SIM_SCSI_ID(ahc, xs->sc_link);
target = xs->sc_link->scsipi_scsi.target;
(void)ahc_fetch_transinfo(ahc, channel, our_id, target, &tstate);
ahc_compile_devinfo(&devinfo, our_id, target,
xs->sc_link->scsipi_scsi.lun, channel, ROLE_INITIATOR);
return (tstate->tagenable & devinfo.target_mask);
}