aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMitsuru IWASAKI <iwasaki@FreeBSD.org>2008-02-06 01:44:44 +0000
committerMitsuru IWASAKI <iwasaki@FreeBSD.org>2008-02-06 01:44:44 +0000
commitdbf1af3ead8d9823586cf44961a0ab98193f10c8 (patch)
treecb1543b29717d78654516dded50ddee43e564218 /sys
parent0e6611dfd8544fad765aa6aa419b0b5dafb19337 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ciss/ciss.c98
1 files changed, 97 insertions, 1 deletions
diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c
index 05ca46d7a723..9c9214955a6e 100644
--- a/sys/dev/ciss/ciss.c
+++ b/sys/dev/ciss/ciss.c
@@ -183,6 +183,8 @@ static int ciss_name_device(struct ciss_softc *sc, int bus, int target);
/* periodic status monitoring */
static void ciss_periodic(void *arg);
+static void ciss_nop_complete(struct ciss_request *cr);
+static void ciss_disable_adapter(struct ciss_softc *sc);
static void ciss_notify_event(struct ciss_softc *sc);
static void ciss_notify_complete(struct ciss_request *cr);
static int ciss_notify_abort(struct ciss_softc *sc);
@@ -3068,6 +3070,9 @@ static void
ciss_periodic(void *arg)
{
struct ciss_softc *sc;
+ struct ciss_request *cr = NULL;
+ struct ciss_command *cc = NULL;
+ int error = 0;
debug_called(1);
@@ -3082,7 +3087,8 @@ ciss_periodic(void *arg)
sc->ciss_heartbeat, sc->ciss_heart_attack);
if (sc->ciss_heart_attack == 3) {
ciss_printf(sc, "ADAPTER HEARTBEAT FAILED\n");
- /* XXX should reset adapter here */
+ ciss_disable_adapter(sc);
+ return;
}
} else {
sc->ciss_heartbeat = sc->ciss_cfg->heartbeat;
@@ -3091,6 +3097,24 @@ ciss_periodic(void *arg)
}
/*
+ * Send the NOP message and wait for a response.
+ */
+ if ((error = ciss_get_request(sc, &cr)) == 0) {
+ cc = CISS_FIND_COMMAND(cr);
+ cr->cr_complete = ciss_nop_complete;
+ cc->cdb.cdb_length = 1;
+ cc->cdb.type = CISS_CDB_TYPE_MESSAGE;
+ cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
+ cc->cdb.direction = CISS_CDB_DIRECTION_WRITE;
+ cc->cdb.timeout = 0;
+ cc->cdb.cdb[0] = CISS_OPCODE_MESSAGE_NOP;
+
+ if ((error = ciss_start(cr)) != 0) {
+ ciss_printf(sc, "SENDING NOP MESSAGE FAILED\n");
+ }
+ }
+
+ /*
* If the notify event request has died for some reason, or has
* not started yet, restart it.
*/
@@ -3105,6 +3129,78 @@ ciss_periodic(void *arg)
callout_reset(&sc->ciss_periodic, CISS_HEARTBEAT_RATE * hz, ciss_periodic, sc);
}
+static void
+ciss_nop_complete(struct ciss_request *cr)
+{
+ struct ciss_softc *sc;
+ static int first_time = 1;
+
+ sc = cr->cr_sc;
+ if (ciss_report_request(cr, NULL, NULL) != 0) {
+ if (first_time == 1) {
+ first_time = 0;
+ ciss_printf(sc, "SENDING NOP MESSAGE FAILED (not logging anymore)\n");
+ }
+ }
+
+ ciss_release_request(cr);
+}
+
+/************************************************************************
+ * Disable the adapter.
+ *
+ * The all requests in completed queue is failed with hardware error.
+ * This will cause failover in a multipath configuration.
+ */
+static void
+ciss_disable_adapter(struct ciss_softc *sc)
+{
+ struct ciss_request *cr;
+ struct ciss_command *cc;
+ struct ciss_error_info *ce;
+ int s;
+
+ s = splcam();
+
+ CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc);
+ pci_disable_busmaster(sc->ciss_dev);
+ sc->ciss_flags &= ~CISS_FLAG_RUNNING;
+
+ for (;;) {
+ if ((cr = ciss_dequeue_busy(sc)) == NULL)
+ break;
+
+ cc = CISS_FIND_COMMAND(cr);
+ ce = (struct ciss_error_info *)&(cc->sg[0]);
+ ce->command_status = CISS_CMD_STATUS_HARDWARE_ERROR;
+ ciss_enqueue_complete(cr);
+ }
+
+ for (;;) {
+ if ((cr = ciss_dequeue_complete(sc)) == NULL)
+ break;
+
+ /*
+ * If the request has a callback, invoke it.
+ */
+ if (cr->cr_complete != NULL) {
+ cr->cr_complete(cr);
+ continue;
+ }
+
+ /*
+ * If someone is sleeping on this request, wake them up.
+ */
+ if (cr->cr_flags & CISS_REQ_SLEEP) {
+ cr->cr_flags &= ~CISS_REQ_SLEEP;
+ wakeup(cr);
+ continue;
+ }
+ }
+
+ splx(s);
+}
+
/************************************************************************
* Request a notification response from the adapter.
*