summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2009-01-09 21:47:09 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2009-01-09 21:47:09 +0000
commit26aa67ec25df9c471b21f8340d8cf3df6bef0f19 (patch)
tree0ca2f07cd3a589c778bc7c040f0f5cd48133063c /sys
parent01022ca7032cb25372ee27b162bea8f39bcb5425 (diff)
Implement command timeouts. With some helpful tips from miod@, thanks.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/ips.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/sys/dev/pci/ips.c b/sys/dev/pci/ips.c
index db873c0c345..0ba29855d3d 100644
--- a/sys/dev/pci/ips.c
+++ b/sys/dev/pci/ips.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ips.c,v 1.30 2007/09/17 01:33:33 krw Exp $ */
+/* $OpenBSD: ips.c,v 1.31 2009/01/09 21:47:08 grange Exp $ */
/*
* Copyright (c) 2006, 2007 Alexander Yurchenko <grange@openbsd.org>
@@ -233,6 +233,7 @@ int ips_cmd(struct ips_softc *, int, int, u_int32_t, void *, size_t, int,
int ips_poll(struct ips_softc *, struct ips_ccb *);
void ips_done(struct ips_softc *, struct ips_ccb *);
int ips_intr(void *);
+void ips_timeout(void *);
int ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *);
int ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *);
@@ -696,9 +697,14 @@ ips_cmd(struct ips_softc *sc, int code, int drive, u_int32_t lba, void *data,
TAILQ_INSERT_TAIL(&sc->sc_ccbq_run, ccb, c_link);
ips_exec(sc, ccb);
- if (flags & IPS_CCB_POLL)
+ if (flags & IPS_CCB_POLL) {
/* Wait for command to complete */
error = ips_poll(sc, ccb);
+ } else {
+ /* Set watchdog timer */
+ timeout_set(&xs->stimeout, ips_timeout, ccb);
+ timeout_add_msec(&xs->stimeout, xs->timeout);
+ }
return (error);
}
@@ -752,6 +758,9 @@ ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
return;
}
+ if (xs != NULL)
+ timeout_del(&xs->stimeout);
+
if (flags & (IPS_CCB_READ | IPS_CCB_WRITE)) {
bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
ccb->c_dmam->dm_mapsize, flags & IPS_CCB_READ ?
@@ -814,6 +823,34 @@ ips_intr(void *arg)
return (1);
}
+void
+ips_timeout(void *arg)
+{
+ struct ips_ccb *ccb = arg;
+ struct scsi_xfer *xs = ccb->c_xfer;
+ struct ips_softc *sc = xs->sc_link->adapter_softc;
+ int s;
+
+ /*
+ * Command never completed. Cleanup and recover.
+ */
+ s = splbio();
+ sc_print_addr(xs->sc_link);
+ printf("timeout");
+ DPRINTF(IPS_D_ERR, (", command 0x%02x", ccb->c_id));
+ printf("\n");
+
+ TAILQ_REMOVE(&sc->sc_ccbq_run, ccb, c_link);
+ ips_ccb_put(sc, ccb);
+
+ xs->error = XS_TIMEOUT;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+
+ ips_reset(sc);
+ splx(s);
+}
+
int
ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai)
{