Get rid of UMA zones and instead allocate all ecb's up front and track them

in a TAILQ.  Re-arrange some of the ecb elements so that they can stay
stable through alloc/free cycles while the rest get bzero'd.

- Use the tag_id from the ecb rather than fro the ccb.  The latter is only
for target mode.

- Honor the ccb flags for tag_action when deciding whether to do a tagged
or untagged transaction.

- Re-arrange autosense completion so that it works correctly in failure
cases.

- Turn on the PI_TAG_ABLE flag so that CAM will send us tagged transactions.

This enables tagged queueing in the driver.
This commit is contained in:
Scott Long 2004-06-13 09:08:44 +00:00
parent 0ddcf11c52
commit 1da2ceea66
2 changed files with 48 additions and 25 deletions

View File

@ -117,7 +117,6 @@ __FBSDID("$FreeBSD$");
#include <sys/queue.h>
#include <sys/time.h>
#include <sys/callout.h>
#include <vm/uma.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@ -185,9 +184,6 @@ static __inline void ncr53c9x_setsync(struct ncr53c9x_softc *,
((ms +0u) * hz) /1000u)
#endif
static int ecb_zone_initialized = 0;
static uma_zone_t ecb_zone;
/*
* Names for the NCR53c9x variants, correspnding to the variant tags
* in ncr53c9xvar.h.
@ -228,6 +224,8 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
struct cam_devq *devq;
struct cam_sim *sim;
struct cam_path *path;
struct ncr53c9x_ecb *ecb;
int i;
mtx_init(&sc->sc_lock, "ncr", "ncr53c9x lock", MTX_DEF);
@ -304,7 +302,8 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
return (ENOMEM);
sim = cam_sim_alloc(ncr53c9x_action, ncr53c9x_poll, "esp", sc,
device_get_unit(sc->sc_dev), 256, 256, devq);
device_get_unit(sc->sc_dev), 1,
NCR_TAG_DEPTH, devq);
if (sim == NULL) {
cam_simq_free(devq);
return (ENOMEM);
@ -332,6 +331,19 @@ ncr53c9x_attach(struct ncr53c9x_softc *sc)
sc->sc_state = 0;
ncr53c9x_init(sc, 1);
TAILQ_INIT(&sc->free_list);
if ((sc->ecb_array = malloc(sizeof(struct ncr53c9x_ecb) * NCR_TAG_DEPTH,
M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
device_printf(sc->sc_dev, "Cannot allocate ecb array!\n");
return (ENOMEM);
}
for (i = 0; i < NCR_TAG_DEPTH; i++) {
ecb = &sc->ecb_array[i];
ecb->sc = sc;
ecb->tag_id = i;
TAILQ_INSERT_HEAD(&sc->free_list, ecb, free_links);
}
callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc);
return (0);
@ -453,14 +465,6 @@ ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset)
NCR_MISC(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state));
if (!ecb_zone_initialized) {
/* All instances share this zone */
ecb_zone = uma_zcreate("ncr53c9x ecb zone",
sizeof(struct ncr53c9x_ecb), NULL, NULL,
NULL, NULL, 0, 0);
ecb_zone_initialized = 1;
}
if (sc->sc_state == 0) {
/* First time through; initialize. */
@ -791,7 +795,7 @@ ncr53c9x_free_ecb(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
{
ecb->flags = 0;
uma_zfree(ecb_zone, (void *)ecb);
TAILQ_INSERT_TAIL(&sc->free_list, ecb, free_links);
return;
}
@ -800,11 +804,14 @@ ncr53c9x_get_ecb(struct ncr53c9x_softc *sc)
{
struct ncr53c9x_ecb *ecb;
ecb = (struct ncr53c9x_ecb *)uma_zalloc(ecb_zone, M_NOWAIT);
ecb = TAILQ_FIRST(&sc->free_list);
if (ecb) {
bzero(ecb, sizeof(struct ncr53c9x_ecb));
ecb->flags |= ECB_ALLOC;
ecb->sc = sc;
if (ecb->flags != 0)
panic("ecb flags not cleared\n");
TAILQ_REMOVE(&sc->free_list, ecb, free_links);
ecb->flags = ECB_ALLOC;
bzero(&ecb->ccb, sizeof(struct ncr53c9x_ecb) -
offsetof(struct ncr53c9x_ecb, ccb));
}
return (ecb);
}
@ -847,7 +854,7 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb)
struct ccb_pathinq *cpi = &ccb->cpi;
cpi->version_num = 1;
cpi->hba_inquiry = PI_SDTR_ABLE/*|PI_TAG_ABLE*/;
cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
cpi->hba_inquiry |=
(sc->sc_rev == NCR_VARIANT_FAS366) ? PI_WIDE_16 : 0;
cpi->target_sprt = 0;
@ -1000,6 +1007,7 @@ ncr53c9x_action(struct cam_sim *sim, union ccb *ccb)
ti->flags &= ~T_WIDE;
ti->width = 0;
}
ti->flags |= T_NEGOTIATE;
}
if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
@ -1088,6 +1096,10 @@ ncr53c9x_sched(struct ncr53c9x_softc *sc)
tag = 0;
else if ((ecb->flags & ECB_SENSE) != 0)
tag = 0;
else if ((ecb->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0)
tag = 0;
else if (ecb->ccb->csio.tag_action == CAM_TAG_ACTION_NONE)
tag = 0;
else
tag = ecb->ccb->csio.tag_action;
@ -1122,8 +1134,8 @@ ncr53c9x_sched(struct ncr53c9x_softc *sc)
}
ecb->tag[0] = tag;
if (tag != 0) {
li->queued[ecb->ccb->csio.tag_id] = ecb;
ecb->tag[1] = ecb->ccb->csio.tag_id;
li->queued[ecb->tag_id] = ecb;
ecb->tag[1] = ecb->tag_id;
li->used++;
}
if (li->untagged != NULL && (li->busy != 1)) {
@ -1218,7 +1230,8 @@ ncr53c9x_done(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
if (ccb->ccb_h.status == CAM_REQ_CMP) {
if ((ecb->flags & ECB_ABORT) != 0) {
ccb->ccb_h.status = CAM_CMD_TIMEOUT;
} else if ((ecb->flags & ECB_SENSE) != 0) {
} else if ((ecb->flags & ECB_SENSE) != 0 &&
(ecb->stat != SCSI_STATUS_CHECK_COND)) {
ccb->ccb_h.status = CAM_AUTOSNS_VALID;
} else if (ecb->stat == SCSI_STATUS_CHECK_COND) {
if ((ecb->flags & ECB_SENSE) != 0)

View File

@ -101,6 +101,9 @@
#define NCR_VARIANT_NCR53C90_86C01 10
#define NCR_VARIANT_MAX 11
/* XXX Max tag depth. Should this be defined in the register header? */
#define NCR_TAG_DEPTH 256
/*
* ECB. Holds additional information for each SCSI command Comments: We
* need a separate scsi command block because we may need to overwrite it
@ -110,10 +113,14 @@
* occasionally xs->retries.
*/
struct ncr53c9x_ecb {
TAILQ_ENTRY(ncr53c9x_ecb) chain;
union ccb *ccb; /* SCSI xfer ctrl block from above */
/* These fields are preserved between alloc and free */
struct ncr53c9x_softc *sc;
int tag_id;
int flags;
union ccb *ccb; /* SCSI xfer ctrl block from above */
TAILQ_ENTRY(ncr53c9x_ecb) free_links;
TAILQ_ENTRY(ncr53c9x_ecb) chain;
#define ECB_ALLOC 0x01
#define ECB_READY 0x02
#define ECB_SENSE 0x04
@ -168,7 +175,7 @@ struct ncr53c9x_linfo {
unsigned char avail; /* where to start scanning */
unsigned char busy;
struct ncr53c9x_ecb *untagged;
struct ncr53c9x_ecb *queued[256];
struct ncr53c9x_ecb *queued[NCR_TAG_DEPTH];
};
struct ncr53c9x_tinfo {
@ -348,6 +355,9 @@ struct ncr53c9x_softc {
int sc_extended_geom; /* Should we return extended geometry */
struct mtx sc_lock; /* driver mutex */
struct ncr53c9x_ecb *ecb_array;
TAILQ_HEAD(,ncr53c9x_ecb) free_list;
};
/* values for sc_state */