summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/ami.c271
-rw-r--r--sys/dev/ic/amivar.h10
2 files changed, 95 insertions, 186 deletions
diff --git a/sys/dev/ic/ami.c b/sys/dev/ic/ami.c
index 614df98ce38..3038dc6ae72 100644
--- a/sys/dev/ic/ami.c
+++ b/sys/dev/ic/ami.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ami.c,v 1.207 2010/06/21 11:43:38 dlg Exp $ */
+/* $OpenBSD: ami.c,v 1.208 2010/06/23 03:46:25 dlg Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -114,8 +114,6 @@ struct scsi_device ami_raw_dev = {
NULL, NULL, NULL, NULL
};
-void ami_remove_runq(struct ami_ccb *);
-void ami_insert_runq(struct ami_ccb *);
struct ami_ccb *ami_get_ccb(struct ami_softc *);
void ami_put_ccb(struct ami_softc *, struct ami_ccb *);
@@ -131,7 +129,6 @@ int ami_alloc_ccbs(struct ami_softc *, int);
int ami_poll(struct ami_softc *, struct ami_ccb *);
void ami_start(struct ami_softc *, struct ami_ccb *);
void ami_complete(struct ami_softc *, struct ami_ccb *, int);
-int ami_done(struct ami_softc *, int, int);
void ami_runqueue_tick(void *);
void ami_runqueue(struct ami_softc *);
@@ -141,7 +138,6 @@ void ami_done_xs(struct ami_softc *, struct ami_ccb *);
void ami_done_pt(struct ami_softc *, struct ami_ccb *);
void ami_done_flush(struct ami_softc *, struct ami_ccb *);
void ami_done_sysflush(struct ami_softc *, struct ami_ccb *);
-void ami_stimeout(void *);
void ami_done_dummy(struct ami_softc *, struct ami_ccb *);
void ami_done_ioctl(struct ami_softc *, struct ami_ccb *);
@@ -180,24 +176,6 @@ void ami_refresh_sensors(void *);
#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
-void
-ami_remove_runq(struct ami_ccb *ccb)
-{
- splassert(IPL_BIO);
-
- TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link);
- if (ccb->ccb_sc->sc_drainio && TAILQ_EMPTY(&ccb->ccb_sc->sc_ccb_runq))
- wakeup(ccb->ccb_sc);
-}
-
-void
-ami_insert_runq(struct ami_ccb *ccb)
-{
- splassert(IPL_BIO);
-
- TAILQ_INSERT_TAIL(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link);
-}
-
struct ami_ccb *
ami_get_ccb(struct ami_softc *sc)
{
@@ -404,7 +382,8 @@ ami_attach(struct ami_softc *sc)
struct ami_fc_prodinfo *pi;
const char *p;
paddr_t pa;
- int s;
+
+ mtx_init(&sc->sc_cmd_mtx, IPL_BIO);
am = ami_allocmem(sc, NBPG);
if (am == NULL) {
@@ -431,8 +410,6 @@ ami_attach(struct ami_softc *sc)
(sc->sc_init)(sc);
- s = splbio();
-
/* try FC inquiry first */
cmd->acc_cmd = AMI_FCOP;
cmd->acc_io.aio_channel = AMI_FC_EINQ3;
@@ -479,7 +456,6 @@ ami_attach(struct ami_softc *sc)
cmd->acc_io.aio_param = 0;
cmd->acc_io.aio_data = pa;
if (ami_poll(sc, &iccb) != 0) {
- splx(s);
printf(": cannot do inquiry\n");
goto free_mbox;
}
@@ -525,8 +501,6 @@ ami_attach(struct ami_softc *sc)
sc->sc_link.openings = sc->sc_maxcmds;
}
- splx(s);
-
ami_freemem(sc, am);
if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) {
@@ -962,76 +936,66 @@ ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
void
ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs)
{
- timeout_set(&xs->stimeout, ami_stimeout, ccb);
-
- if (xs->flags & SCSI_POLL) {
+ if (xs->flags & SCSI_POLL)
ami_complete(sc, ccb, xs->timeout);
- return;
- }
-
- /* XXX way wrong, this timeout needs to be set later */
- timeout_add_sec(&xs->stimeout, 61);
- ami_start(sc, ccb);
+ else
+ ami_start(sc, ccb);
}
void
ami_start(struct ami_softc *sc, struct ami_ccb *ccb)
{
- int s;
-
- s = splbio();
+ mtx_enter(&sc->sc_cmd_mtx);
ccb->ccb_state = AMI_CCB_PREQUEUED;
TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link);
+ mtx_leave(&sc->sc_cmd_mtx);
+
ami_runqueue(sc);
- splx(s);
}
void
ami_runqueue_tick(void *arg)
{
- struct ami_softc *sc = arg;
- int s;
-
- s = splbio();
- ami_runqueue(sc);
- splx(s);
+ ami_runqueue(arg);
}
void
ami_runqueue(struct ami_softc *sc)
{
struct ami_ccb *ccb;
+ int add = 0;
- splassert(IPL_BIO);
-
- if (sc->sc_drainio)
- return;
+ mtx_enter(&sc->sc_cmd_mtx);
+ if (!sc->sc_drainio) {
+ while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) {
+ if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) {
+ add = 1;
+ break;
+ }
- while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) {
- if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) {
- timeout_add(&sc->sc_run_tmo, 1);
- break;
+ TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
+ ccb->ccb_state = AMI_CCB_QUEUED;
+ TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
}
-
- TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
- ccb->ccb_state = AMI_CCB_QUEUED;
- ami_insert_runq(ccb);
}
+ mtx_leave(&sc->sc_cmd_mtx);
+
+ if (add)
+ timeout_add(&sc->sc_run_tmo, 1);
}
int
ami_poll(struct ami_softc *sc, struct ami_ccb *ccb)
{
int error;
- int s;
- s = splbio();
+ mtx_enter(&sc->sc_cmd_mtx);
error = sc->sc_poll(sc, &ccb->ccb_cmd);
if (error == -1)
ccb->ccb_flags |= AMI_CCB_F_ERR;
+ mtx_leave(&sc->sc_cmd_mtx);
ccb->ccb_done(sc, ccb);
- splx(s);
return (error);
}
@@ -1039,27 +1003,36 @@ ami_poll(struct ami_softc *sc, struct ami_ccb *ccb)
void
ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
{
- struct ami_iocmd mbox;
- int i = 0, j, done = 0;
- int s, ready;
+ void (*done)(struct ami_softc *, struct ami_ccb *);
+ int ready;
+ int i;
+ int s;
- s = splbio();
+ done = ccb->ccb_done;
+ ccb->ccb_done = ami_done_dummy;
/*
* since exec will return if the mbox is busy we have to busy wait
* ourselves. once its in, jam it into the runq.
*/
+ mtx_enter(&sc->sc_cmd_mtx);
while (i < AMI_MAX_BUSYWAIT) {
if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) {
ccb->ccb_state = AMI_CCB_QUEUED;
- ami_insert_runq(ccb);
+ TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
break;
}
DELAY(1000);
i++;
}
- if (ccb->ccb_state != AMI_CCB_QUEUED)
- goto err;
+ ready = (ccb->ccb_state == AMI_CCB_QUEUED);
+ mtx_leave(&sc->sc_cmd_mtx);
+
+ if (!ready) {
+ ccb->ccb_flags |= AMI_CCB_F_ERR;
+ ccb->ccb_state = AMI_CCB_READY;
+ goto done;
+ }
/*
* Override timeout for PERC3. The first command triggers a chip
@@ -1068,97 +1041,27 @@ ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
* firmware to be up again. After the first two commands the
* timeouts are as expected.
*/
- i = 0;
- while (i < 30000 /* timeout */) {
- if (sc->sc_done(sc, &mbox) != 0) {
- for (j = 0; j < mbox.acc_nstat; j++) {
- ready = mbox.acc_cmplidl[j];
- ami_done(sc, ready, mbox.acc_status);
- if (ready == ccb->ccb_cmd.acc_id)
- done = 1;
- }
- if (done)
- break;
- }
+ timeout = MAX(30000, timeout); /* timeout */
- DELAY(1000);
- i++;
- }
- if (!done) {
- printf("%s: timeout ccb %d\n", DEVNAME(sc),
- ccb->ccb_cmd.acc_id);
- ami_remove_runq(ccb);
- goto err;
- }
-
- /* start the runqueue again */
- ami_runqueue(sc);
-
- splx(s);
-
- return;
-
-err:
- ccb->ccb_flags |= AMI_CCB_F_ERR;
- ccb->ccb_state = AMI_CCB_READY;
- ccb->ccb_done(sc, ccb);
- splx(s);
-}
-
-void
-ami_stimeout(void *v)
-{
- struct ami_ccb *ccb = v;
- struct ami_softc *sc = ccb->ccb_sc;
- struct ami_iocmd *cmd = &ccb->ccb_cmd;
- int s;
-
- s = splbio();
- switch (ccb->ccb_state) {
- case AMI_CCB_PREQUEUED:
- /* command never ran, cleanup is easy */
- TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
- ccb->ccb_flags |= AMI_CCB_F_ERR;
- ccb->ccb_done(sc, ccb);
- break;
-
- case AMI_CCB_QUEUED:
- /*
- * ccb has taken more than a minute to finish. we can't take
- * it off the hardware in case it finishes later, but we can
- * warn the user to look at what is happening.
- */
- AMI_DPRINTF(AMI_D_CMD, ("%s: stimeout ccb %d, check volume "
- "state\n", DEVNAME(sc), cmd->acc_id));
- break;
-
- default:
- panic("%s: ami_stimeout(%d) botch", DEVNAME(sc), cmd->acc_id);
- }
-
- splx(s);
-}
-
-int
-ami_done(struct ami_softc *sc, int idx, int status)
-{
- struct ami_ccb *ccb = &sc->sc_ccbs[idx - 1];
-
- AMI_DPRINTF(AMI_D_CMD, ("done(%d) ", ccb->ccb_cmd.acc_id));
+ while (ccb->ccb_state == AMI_CCB_QUEUED) {
+ s = splbio(); /* interrupt handlers are called at their IPL */
+ ready = ami_intr(sc);
+ splx(s);
+
+ if (ready == 0) {
+ if (timeout-- == 0) {
+ /* XXX */
+ printf("%s: timeout\n", DEVNAME(sc));
+ return;
+ }
- if (ccb->ccb_state != AMI_CCB_QUEUED) {
- printf("%s: unqueued ccb %d ready, state = %d\n",
- DEVNAME(sc), idx, ccb->ccb_state);
- return (1);
+ delay(1000);
+ continue;
+ }
}
- ccb->ccb_state = AMI_CCB_READY;
- ccb->ccb_status = status;
- ami_remove_runq(ccb);
-
- ccb->ccb_done(sc, ccb);
-
- return (0);
+done:
+ done(sc, ccb);
}
void
@@ -1182,7 +1085,6 @@ ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb)
bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
}
- timeout_del(&xs->stimeout);
xs->resid = 0;
if (ccb->ccb_flags & AMI_CCB_F_ERR)
@@ -1220,7 +1122,6 @@ ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb)
bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
}
- timeout_del(&xs->stimeout);
xs->resid = 0;
if (ccb->ccb_flags & AMI_CCB_F_ERR)
@@ -1236,7 +1137,6 @@ ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb)
struct scsi_xfer *xs = ccb->ccb_xs;
struct ami_iocmd *cmd = &ccb->ccb_cmd;
- timeout_del(&xs->stimeout);
if (ccb->ccb_flags & AMI_CCB_F_ERR) {
xs->error = XS_DRIVER_STUFFUP;
xs->resid = 0;
@@ -1258,7 +1158,6 @@ ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb)
{
struct scsi_xfer *xs = ccb->ccb_xs;
- timeout_del(&xs->stimeout);
xs->resid = 0;
if (ccb->ccb_flags & AMI_CCB_F_ERR)
xs->error = XS_DRIVER_STUFFUP;
@@ -1627,28 +1526,36 @@ ami_scsi_cmd(struct scsi_xfer *xs)
int
ami_intr(void *v)
{
- struct ami_softc *sc = v;
struct ami_iocmd mbox;
+ struct ami_softc *sc = v;
+ struct ami_ccb *ccb;
int i, rv = 0, ready;
- splassert(IPL_BIO);
-
- if (TAILQ_EMPTY(&sc->sc_ccb_runq))
- return (0);
-
- AMI_DPRINTF(AMI_D_INTR, ("intr "));
-
- while ((sc->sc_done)(sc, &mbox)) {
+ mtx_enter(&sc->sc_cmd_mtx);
+ while (!TAILQ_EMPTY(&sc->sc_ccb_runq) && sc->sc_done(sc, &mbox)) {
AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat));
for (i = 0; i < mbox.acc_nstat; i++ ) {
- ready = mbox.acc_cmplidl[i];
+ ready = mbox.acc_cmplidl[i] - 1;
AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready));
- if (!ami_done(sc, ready, mbox.acc_status))
- rv |= 1;
+
+ ccb = &sc->sc_ccbs[ready];
+ ccb->ccb_status = mbox.acc_status;
+ ccb->ccb_state = AMI_CCB_READY;
+ TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link);
+
+ mtx_leave(&sc->sc_cmd_mtx);
+ ccb->ccb_done(sc, ccb);
+ mtx_enter(&sc->sc_cmd_mtx);
+
+ rv = 1;
}
}
+ ready = (sc->sc_drainio && TAILQ_EMPTY(&sc->sc_ccb_runq));
+ mtx_leave(&sc->sc_cmd_mtx);
- if (rv)
+ if (ready)
+ wakeup(sc);
+ else if (rv)
ami_runqueue(sc);
AMI_DPRINTF(AMI_D_INTR, ("exit "));
@@ -1856,7 +1763,7 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
struct ami_iocmd *cmd;
struct ami_mem *am = NULL;
char *idata = NULL;
- int s, error = 0;
+ int error = 0;
rw_enter_write(&sc->sc_lock);
@@ -1900,17 +1807,17 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
if (opcode != AMI_CHSTATE) {
ami_start(sc, ccb);
- s = splbio();
+ mtx_enter(&sc->sc_cmd_mtx);
while (ccb->ccb_state != AMI_CCB_READY)
- tsleep(ccb, PRIBIO,"ami_mgmt", 0);
- splx(s);
+ msleep(ccb, &sc->sc_cmd_mtx, PRIBIO,"ami_mgmt", 0);
+ mtx_leave(&sc->sc_cmd_mtx);
} else {
/* change state must be run with id 0xfe and MUST be polled */
- s = splbio();
+ mtx_enter(&sc->sc_cmd_mtx);
sc->sc_drainio = 1;
while (!TAILQ_EMPTY(&sc->sc_ccb_runq)) {
- if (tsleep(sc, PRIBIO, "ami_mgmt_drain", hz * 60) ==
- EWOULDBLOCK) {
+ if (msleep(sc, &sc->sc_cmd_mtx, PRIBIO,
+ "amimgmt", hz * 60) == EWOULDBLOCK) {
printf("%s: drain io timeout\n", DEVNAME(sc));
ccb->ccb_flags |= AMI_CCB_F_ERR;
goto restartio;
@@ -1924,8 +1831,8 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
restartio:
/* restart io */
sc->sc_drainio = 0;
+ mtx_leave(&sc->sc_cmd_mtx);
ami_runqueue(sc);
- splx(s);
}
if (ccb->ccb_flags & AMI_CCB_F_ERR)
diff --git a/sys/dev/ic/amivar.h b/sys/dev/ic/amivar.h
index f7a531dbc5c..2fb3e8f8843 100644
--- a/sys/dev/ic/amivar.h
+++ b/sys/dev/ic/amivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: amivar.h,v 1.56 2010/06/21 11:43:38 dlg Exp $ */
+/* $OpenBSD: amivar.h,v 1.57 2010/06/23 03:46:25 dlg Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -107,14 +107,16 @@ struct ami_softc {
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
+ struct ami_ccb *sc_ccbs;
+ struct ami_ccb_list sc_ccb_freeq;
+ struct mutex sc_ccb_freeq_mtx;
+
struct ami_mem *sc_mbox_am;
volatile struct ami_iocmd *sc_mbox;
paddr_t sc_mbox_pa;
- struct ami_ccb *sc_ccbs;
- struct ami_ccb_list sc_ccb_freeq;
- struct mutex sc_ccb_freeq_mtx;
struct ami_ccb_list sc_ccb_preq, sc_ccb_runq;
+ struct mutex sc_cmd_mtx;
struct ami_mem *sc_ccbmem_am;