-/* $OpenBSD: aic79xx.c,v 1.60 2016/03/15 20:50:22 krw Exp $ */
+/* $OpenBSD: aic79xx.c,v 1.61 2016/08/17 01:16:11 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
void ahd_fini_scbdata(struct ahd_softc *ahd);
void ahd_setup_iocell_workaround(struct ahd_softc *ahd);
void ahd_iocell_first_selection(struct ahd_softc *ahd);
-void ahd_add_col_list(struct ahd_softc *ahd,
- struct scb *scb, u_int col_idx);
-void ahd_rem_col_list(struct ahd_softc *ahd,
- struct scb *scb);
void ahd_chip_init(struct ahd_softc *ahd);
void ahd_qinfifo_requeue(struct ahd_softc *ahd,
struct scb *prev_scb,
* active transaction on the bus.
*/
pending_scb_count = 0;
- LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(pending_scb, &ahd->pending_scbs, next) {
struct ahd_devinfo devinfo;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
saved_scbptr = ahd_get_scbptr(ahd);
/* Ensure that the hscbs down on the card match the new information */
- LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(pending_scb, &ahd->pending_scbs, next) {
u_int scb_tag;
u_int control;
if (ahd->seep_config == NULL)
return (NULL);
- LIST_INIT(&ahd->pending_scbs);
+ TAILQ_INIT(&ahd->pending_scbs);
LIST_INIT(&ahd->timedout_scbs);
/* We don't know our unit number until the OSM sets it */
scb_data = &ahd->scb_data;
TAILQ_INIT(&scb_data->free_scbs);
- for (i = 0; i < AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT; i++)
- LIST_INIT(&scb_data->free_scb_lists[i]);
- LIST_INIT(&scb_data->any_dev_free_scb_list);
SLIST_INIT(&scb_data->hscb_maps);
SLIST_INIT(&scb_data->sg_maps);
SLIST_INIT(&scb_data->sense_maps);
+ mtx_init(&ahd->sc_scb_mtx, IPL_BIO);
+ scsi_iopool_init(&ahd->sc_iopool, ahd, ahd_scb_alloc, ahd_scb_free);
/* Determine the number of hardware SCBs and initialize them */
scb_data->maxhscbs = ahd_probe_scbs(ahd);
/*
* Look on the pending list.
*/
- LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(scb, &ahd->pending_scbs, next) {
if (SCB_GET_TAG(scb) == tag)
return (scb);
}
- /*
- * Then on all of the collision free lists.
- */
- TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
- struct scb *list_scb;
-
- list_scb = scb;
- do {
- if (SCB_GET_TAG(list_scb) == tag)
- return (list_scb);
- list_scb = LIST_NEXT(list_scb, collision_links);
- } while (list_scb);
- }
-
/*
* And finally on the generic free list.
*/
- LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) {
+ TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, next) {
if (SCB_GET_TAG(scb) == tag)
return (scb);
}
ahd->flags |= AHD_HAD_FIRST_SEL;
}
-/*************************** SCB Management ***********************************/
-void
-ahd_add_col_list(struct ahd_softc *ahd, struct scb *scb, u_int col_idx)
-{
- struct scb_list *free_list;
- struct scb_tailq *free_tailq;
- struct scb *first_scb;
-
- scb->flags |= SCB_ON_COL_LIST;
- AHD_SET_SCB_COL_IDX(scb, col_idx);
- free_list = &ahd->scb_data.free_scb_lists[col_idx];
- free_tailq = &ahd->scb_data.free_scbs;
- first_scb = LIST_FIRST(free_list);
- if (first_scb != NULL) {
- LIST_INSERT_AFTER(first_scb, scb, collision_links);
- } else {
- LIST_INSERT_HEAD(free_list, scb, collision_links);
- TAILQ_INSERT_TAIL(free_tailq, scb, links.tqe);
- }
-}
-
-void
-ahd_rem_col_list(struct ahd_softc *ahd, struct scb *scb)
-{
- struct scb_list *free_list;
- struct scb_tailq *free_tailq;
- struct scb *first_scb;
- u_int col_idx;
-
- scb->flags &= ~SCB_ON_COL_LIST;
- col_idx = AHD_GET_SCB_COL_IDX(ahd, scb);
- free_list = &ahd->scb_data.free_scb_lists[col_idx];
- free_tailq = &ahd->scb_data.free_scbs;
- first_scb = LIST_FIRST(free_list);
- if (first_scb == scb) {
- struct scb *next_scb;
-
- /*
- * Maintain order in the collision free
- * lists for fairness if this device has
- * other colliding tags active.
- */
- next_scb = LIST_NEXT(scb, collision_links);
- if (next_scb != NULL) {
- TAILQ_INSERT_AFTER(free_tailq, scb,
- next_scb, links.tqe);
- }
- TAILQ_REMOVE(free_tailq, scb, links.tqe);
- }
- LIST_REMOVE(scb, collision_links);
-}
-
/*
* Get a free scb. If there are none, see if we can allocate a new SCB.
*/
-struct scb *
-ahd_get_scb(struct ahd_softc *ahd, u_int col_idx)
+void *
+ahd_scb_alloc(void *xahd)
{
+ struct ahd_softc *ahd = xahd;
struct scb *scb;
- TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
- if (AHD_GET_SCB_COL_IDX(ahd, scb) != col_idx) {
- ahd_rem_col_list(ahd, scb);
- goto found;
- }
+ mtx_enter(&ahd->sc_scb_mtx);
+ scb = TAILQ_FIRST(&ahd->scb_data.free_scbs);
+ if (scb) {
+ TAILQ_REMOVE(&ahd->scb_data.free_scbs, scb, next);
+ scb->flags |= SCB_ACTIVE;
}
- if ((scb = LIST_FIRST(&ahd->scb_data.any_dev_free_scb_list)) == NULL) {
- /* All scb's are allocated at initialization in OpenBSD. */
- return (NULL);
- }
- LIST_REMOVE(scb, links.le);
- if (col_idx != AHD_NEVER_COL_IDX
- && (scb->col_scb != NULL)
- && (scb->col_scb->flags & SCB_ACTIVE) == 0) {
- LIST_REMOVE(scb->col_scb, links.le);
- ahd_add_col_list(ahd, scb->col_scb, col_idx);
- }
-found:
- scb->flags |= SCB_ACTIVE;
+ mtx_leave(&ahd->sc_scb_mtx);
+
return (scb);
}
* Return an SCB resource to the free list.
*/
void
-ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
+ahd_scb_free(void *xahd, void *xscb)
{
+ struct ahd_softc *ahd = xahd;
+ struct scb *scb = xscb;
/* Clean up for the next user */
scb->flags = SCB_FLAG_NONE;
scb->hscb->control = 0;
ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL;
- if (scb->col_scb == NULL) {
-
- /*
- * No collision possible. Just free normally.
- */
- LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
- scb, links.le);
- } else if ((scb->col_scb->flags & SCB_ON_COL_LIST) != 0) {
-
- /*
- * The SCB we might have collided with is on
- * a free collision list. Put both SCBs on
- * the generic list.
- */
- ahd_rem_col_list(ahd, scb->col_scb);
- LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
- scb, links.le);
- LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
- scb->col_scb, links.le);
- } else if ((scb->col_scb->flags
- & (SCB_PACKETIZED|SCB_ACTIVE)) == SCB_ACTIVE
- && (scb->col_scb->hscb->control & TAG_ENB) != 0) {
-
- /*
- * The SCB we might collide with on the next allocation
- * is still active in a non-packetized, tagged, context.
- * Put us on the SCB collision list.
- */
- ahd_add_col_list(ahd, scb,
- AHD_GET_SCB_COL_IDX(ahd, scb->col_scb));
- } else {
- /*
- * The SCB we might collide with on the next allocation
- * is either active in a packetized context, or free.
- * Since we can't collide, put this SCB on the generic
- * free list.
- */
- LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
- scb, links.le);
- }
-
+ mtx_enter(&ahd->sc_scb_mtx);
+ TAILQ_INSERT_HEAD(&ahd->scb_data.free_scbs, scb, next);
aic_platform_scb_free(ahd, scb);
+ mtx_leave(&ahd->sc_scb_mtx);
}
void
scb_data->sgs_left -= newcount;
for (i = 0; i < newcount; i++) {
struct scb_platform_data *pdata = NULL;
- u_int col_tag;
int error;
next_scb = (struct scb *)malloc(sizeof(*next_scb),
break;
}
next_scb->hscb->tag = aic_htole16(scb_data->numscbs);
- col_tag = scb_data->numscbs ^ 0x100;
- next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag);
- if (next_scb->col_scb != NULL)
- next_scb->col_scb->col_scb = next_scb;
- ahd_free_scb(ahd, next_scb);
+ ahd_scb_free(ahd, next_scb);
hscb++;
hscb_busaddr += sizeof(*hscb);
segs += ahd_sglist_size(ahd);
ahd_pause_and_flushwork(ahd);
- if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+ if (!TAILQ_EMPTY(&ahd->pending_scbs)) {
ahd_unpause(ahd);
return (EBUSY);
}
ahd_flush_qoutfifo(ahd);
pending_cmds = 0;
- LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(scb, &ahd->pending_scbs, next) {
pending_cmds++;
}
ahd_outw(ahd, CMDS_PENDING, pending_cmds - ahd_qinfifo_count(ahd));
* These are other tagged commands that were
* disconnected when the reset occurred.
*/
- scbp_next = LIST_FIRST(&ahd->pending_scbs);
+ scbp_next = TAILQ_FIRST(&ahd->pending_scbs);
while (scbp_next != NULL) {
scbp = scbp_next;
- scbp_next = LIST_NEXT(scbp, pending_links);
+ scbp_next = TAILQ_NEXT(scbp, next);
if (ahd_match_scb(ahd, scbp, target, channel, lun, tag, role)) {
cam_status ostat;
saved_scb_index = ahd_get_scbptr(ahd);
printf("Pending list:");
i = 0;
- LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(scb, &ahd->pending_scbs, next) {
if (i++ > AHD_SCB_MAX)
break;
cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
printf("Kernel Free SCB list: ");
i = 0;
- TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
- struct scb *list_scb;
-
- list_scb = scb;
- do {
- printf("%d ", SCB_GET_TAG(list_scb));
- list_scb = LIST_NEXT(list_scb, collision_links);
- } while (list_scb && i++ < AHD_SCB_MAX);
- }
-
- LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) {
- if (i++ > AHD_SCB_MAX)
- break;
+ TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, next) {
printf("%d ", SCB_GET_TAG(scb));
}
printf("\n");
* timeouts for them. They're about to be aborted so no need
* for them to timeout.
*/
- LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(list_scb, &ahd->pending_scbs, next) {
if (list_scb->xs)
timeout_del(&list_scb->xs->stimeout);
}
ahd_lock(ahd, &s);
ccb->ccb_h.status = CAM_REQ_CMP;
- LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+ TAILQ_FOREACH(scb, &ahd->pending_scbs, next) {
struct ccb_hdr *ccbh;
ccbh = &scb->io_ctx->ccb_h;
-/* $OpenBSD: aic79xx.h,v 1.25 2015/12/17 19:35:24 tedu Exp $ */
+/* $OpenBSD: aic79xx.h,v 1.26 2016/08/17 01:16:11 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
#define AHD_TMODE_ENABLE 0
#endif
-#define AHD_BUILD_COL_IDX(target, lun) \
- (((lun) << 4) | target)
-
-#define AHD_GET_SCB_COL_IDX(ahd, scb) \
- ((SCB_GET_LUN(scb) << 4) | SCB_GET_TARGET(ahd, scb))
-
-#define AHD_SET_SCB_COL_IDX(scb, col_idx) \
-do { \
- (scb)->hscb->scsiid = ((col_idx) << TID_SHIFT) & TID; \
- (scb)->hscb->lun = ((col_idx) >> 4) & (AHD_NUM_LUNS_NONPKT-1); \
-} while (0)
-
-#define AHD_COPY_SCB_COL_IDX(dst, src) \
-do { \
- dst->hscb->scsiid = src->hscb->scsiid; \
- dst->hscb->lun = src->hscb->lun; \
-} while (0)
-
-#define AHD_NEVER_COL_IDX 0xFFFF
-
/**************************** Driver Constants ********************************/
/*
* The maximum number of supported targets.
} scb_flag;
struct scb {
+ TAILQ_ENTRY(scb) next;
struct hardware_scb *hscb;
- union {
- SLIST_ENTRY(scb) sle;
- LIST_ENTRY(scb) le;
- TAILQ_ENTRY(scb) tqe;
- } links;
- union {
- SLIST_ENTRY(scb) sle;
- LIST_ENTRY(scb) le;
- TAILQ_ENTRY(scb) tqe;
- } links2;
-#define pending_links links2.le
-#define collision_links links2.le
LIST_ENTRY(scb) timedout_links;
- struct scb *col_scb;
struct scsi_xfer *xs;
struct ahd_softc *ahd_softc;
LIST_HEAD(scb_list, scb);
struct scb_data {
- /*
- * TAILQ of lists of free SCBs grouped by device
- * collision domains.
- */
- struct scb_tailq free_scbs;
-
- /*
- * Per-device lists of SCBs whose tag ID would collide
- * with an already active tag on the device.
- */
- struct scb_list free_scb_lists[AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT];
-
/*
* SCBs that will not collide with any active device.
*/
- struct scb_list any_dev_free_scb_list;
+ struct scb_tailq free_scbs;
/*
* Mapping from tag to SCB.
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ TAILQ_HEAD(, scb) pending_scbs;
/*
* SCBs whose timeout routine has been called.
*/
LIST_HEAD(, scb) timedout_scbs;
+ struct mutex sc_scb_mtx;
+ struct scsi_iopool sc_iopool;
+
/*
* Current register window mode information.
*/
struct ahd_softc *ahd_find_softc(struct ahd_softc *ahd);
void ahd_set_unit(struct ahd_softc *, int);
void ahd_set_name(struct ahd_softc *, char *);
-struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
-void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb);
+void *ahd_scb_alloc(void *);
+void ahd_scb_free(void *, void *);
void ahd_alloc_scbs(struct ahd_softc *ahd);
void ahd_free(struct ahd_softc *ahd);
int ahd_reset(struct ahd_softc *ahd, int reinit);
-/* $OpenBSD: aic79xx_openbsd.c,v 1.44 2016/03/19 11:34:22 mpi Exp $ */
+/* $OpenBSD: aic79xx_openbsd.c,v 1.45 2016/08/17 01:16:11 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
ahd->sc_channel.adapter_buswidth = 16;
ahd->sc_channel.adapter_softc = ahd;
ahd->sc_channel.adapter = &ahd_switch;
- ahd->sc_channel.openings = 16;
+ ahd->sc_channel.openings = 16; /* Must ALWAYS be < 256!! */
+ ahd->sc_channel.pool = &ahd->sc_iopool;
if (bootverbose) {
ahd_controller_info(ahd, ahd_info, sizeof ahd_info);
ahd_done(struct ahd_softc *ahd, struct scb *scb)
{
struct scsi_xfer *xs = scb->xs;
- int s;
/* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */
- LIST_REMOVE(scb, pending_links);
+ TAILQ_REMOVE(&ahd->pending_scbs, scb, next);
timeout_del(&xs->stimeout);
xs->error = XS_SENSE;
}
- ahd_lock(ahd, &s);
- ahd_free_scb(ahd, scb);
scsi_done(xs);
- ahd_unlock(ahd, &s);
}
void
int s;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
- u_int col_idx;
u_int16_t quirks;
SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahd_action\n"));
quirks = xs->sc_link->quirks;
- if ((quirks & SDEV_NOTAGS) != 0 ||
- (tinfo->curr.ppr_options & MSG_EXT_PPR_PROT_IUS) != 0)
- col_idx = AHD_NEVER_COL_IDX;
- else
- col_idx = AHD_BUILD_COL_IDX(target_id, xs->sc_link->lun);
-
- if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
- ahd->flags |= AHD_RESOURCE_SHORTAGE;
- xs->error = XS_NO_CCB;
- scsi_done(xs);
- ahd_unlock(ahd, &s);
- return;
- }
ahd_unlock(ahd, &s);
+ scb = xs->io;
hscb = scb->hscb;
+ scb->flags = SCB_FLAG_NONE;
+ scb->hscb->control = 0;
+ ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL;
SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
if (nsegments != 0)
bus_dmamap_unload(ahd->parent_dmat,
scb->dmamap);
- ahd_free_scb(ahd, scb);
ahd_unlock(ahd, &s);
return;
}
/* XXX with ahc there was some bus_dmamap_sync(PREREAD|PREWRITE); */
- LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
+ TAILQ_INSERT_HEAD(&ahd->pending_scbs, scb, next);
if (!(xs->flags & SCSI_POLL))
timeout_add_msec(&xs->stimeout, xs->timeout);
struct scb *scb)
{
struct hardware_scb *hscb;
- int s;
hscb = scb->hscb;
xs->resid = xs->status = 0;
hscb->cdb_len = xs->cmdlen;
if (hscb->cdb_len > MAX_CDB_LEN) {
- ahd_lock(ahd, &s);
- ahd_free_scb(ahd, scb);
xs->error = XS_DRIVER_STUFFUP;
scsi_done(xs);
- ahd_unlock(ahd, &s);
return;
}
printf("%s: in ahd_setup_data(): bus_dmamap_load() "
"= %d\n", ahd_name(ahd), error);
#endif
- ahd_lock(ahd, &s);
- ahd_free_scb(ahd, scb);
xs->error = XS_DRIVER_STUFFUP;
scsi_done(xs);
- ahd_unlock(ahd, &s);
return;
}
ahd_execute_scb(scb, scb->dmamap->dm_segs,