summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2014-04-04 11:27:42 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2014-04-04 11:27:42 +0000
commit3237631577d37ead37ce0b7a8ee5a1894023254e (patch)
tree036d9c1887e6d6729126a9f185af70ab4d4e79e2
parentaf45ec9fcd3826c573102d076d7c30ccb43c60aa (diff)
Rework the command polling loop so it can handle multiple responses in a single
interrupt. With this we can talk to Hitachi disk arrays, which sometimes return so much sense data that a status continuation response is generated in addition to the normal status response. tested by deraadt@
-rw-r--r--sys/dev/ic/qla.c46
1 files changed, 17 insertions, 29 deletions
diff --git a/sys/dev/ic/qla.c b/sys/dev/ic/qla.c
index fcd27d4b20f..620e5879984 100644
--- a/sys/dev/ic/qla.c
+++ b/sys/dev/ic/qla.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: qla.c,v 1.31 2014/03/31 11:25:45 jmatthew Exp $ */
+/* $OpenBSD: qla.c,v 1.32 2014/04/04 11:27:41 jmatthew Exp $ */
/*
* Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
@@ -67,7 +67,6 @@ struct cfdriver qla_cd = {
};
void qla_scsi_cmd(struct scsi_xfer *);
-struct qla_ccb *qla_scsi_cmd_poll(struct qla_softc *);
int qla_scsi_probe(struct scsi_link *);
u_int16_t qla_read(struct qla_softc *, bus_size_t);
@@ -857,8 +856,8 @@ qla_scsi_cmd(struct scsi_xfer *xs)
struct qla_ccb *ccb;
struct qla_iocb_req34 *iocb;
struct qla_ccb_list list;
- u_int16_t req;
- int offset, error;
+ u_int16_t req, rspin;
+ int offset, error, done;
bus_dmamap_t dmap;
if (xs->cmdlen > sizeof(iocb->req_cdb)) {
@@ -931,27 +930,9 @@ qla_scsi_cmd(struct scsi_xfer *xs)
return;
}
+ done = 0;
SIMPLEQ_INIT(&list);
do {
- ccb = qla_scsi_cmd_poll(sc);
- SIMPLEQ_INSERT_TAIL(&list, ccb, ccb_link);
- } while (xs->io != ccb);
-
- mtx_leave(&sc->sc_queue_mtx);
-
- while ((ccb = SIMPLEQ_FIRST(&list)) != NULL) {
- SIMPLEQ_REMOVE_HEAD(&list, ccb_link);
- scsi_done(ccb->ccb_xs);
- }
-}
-
-struct qla_ccb *
-qla_scsi_cmd_poll(struct qla_softc *sc)
-{
- u_int16_t rspin;
- struct qla_ccb *ccb = NULL;
-
- while (ccb == NULL) {
u_int16_t isr, info;
delay(100);
@@ -966,21 +947,28 @@ qla_scsi_cmd_poll(struct qla_softc *sc)
}
rspin = qla_queue_read(sc, sc->sc_regs->res_in);
- if (rspin != sc->sc_last_resp_id) {
+ while (rspin != sc->sc_last_resp_id) {
ccb = qla_handle_resp(sc, sc->sc_last_resp_id);
sc->sc_last_resp_id++;
if (sc->sc_last_resp_id == sc->sc_maxcmds)
sc->sc_last_resp_id = 0;
- qla_queue_write(sc, sc->sc_regs->res_out,
- sc->sc_last_resp_id);
+ if (ccb != NULL)
+ SIMPLEQ_INSERT_TAIL(&list, ccb, ccb_link);
+ if (ccb == xs->io)
+ done = 1;
}
-
+ qla_queue_write(sc, sc->sc_regs->res_out, rspin);
qla_clear_isr(sc, isr);
- }
+ } while (done == 0);
- return (ccb);
+ mtx_leave(&sc->sc_queue_mtx);
+
+ while ((ccb = SIMPLEQ_FIRST(&list)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&list, ccb_link);
+ scsi_done(ccb->ccb_xs);
+ }
}
u_int16_t