summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/aic79xx.c71
-rw-r--r--sys/dev/ic/aic79xx.h6
-rw-r--r--sys/dev/ic/aic79xx_openbsd.c61
-rw-r--r--sys/dev/ic/aic79xx_openbsd.h4
4 files changed, 94 insertions, 48 deletions
diff --git a/sys/dev/ic/aic79xx.c b/sys/dev/ic/aic79xx.c
index 979cd38b77a..2cc6d0995d4 100644
--- a/sys/dev/ic/aic79xx.c
+++ b/sys/dev/ic/aic79xx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aic79xx.c,v 1.24 2004/12/20 20:56:32 krw Exp $ */
+/* $OpenBSD: aic79xx.c,v 1.25 2004/12/30 17:29:55 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
@@ -253,11 +253,9 @@ u_int ahd_resolve_seqaddr(struct ahd_softc *ahd,
void ahd_download_instr(struct ahd_softc *ahd,
u_int instrptr, uint8_t *dconsts);
int ahd_probe_stack_size(struct ahd_softc *ahd);
-#if 0
int ahd_other_scb_timeout(struct ahd_softc *ahd,
struct scb *scb,
struct scb *other_scb);
-#endif
int ahd_scb_active_in_fifo(struct ahd_softc *ahd,
struct scb *scb);
void ahd_run_data_fifo(struct ahd_softc *ahd,
@@ -8232,9 +8230,14 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
ahd_queue_scb(ahd, scb);
/*
* Ensure we have enough time to actually
- * retrieve the sense.
+ * retrieve the sense, but only schedule
+ * the timer if we are not in recovery or
+ * this is a recovery SCB that is allowed
+ * to have an active timer.
*/
- aic_scb_timer_reset(scb, 5 * 1000);
+ if (ahd->scb_data.recovery_scbs == 0
+ || (scb->flags & SCB_RECOVERY_SCB) != 0)
+ aic_scb_timer_reset(scb, 5 * 1000);
break;
}
case SCSI_STATUS_OK:
@@ -9143,21 +9146,37 @@ ahd_dump_scbs(struct ahd_softc *ahd)
void
ahd_timeout(void *arg)
{
- struct scb *scb;
+ struct scb *scb = (struct scb *)arg;
struct ahd_softc *ahd;
- int s;
-#if 0
- int found;
- u_int last_phase;
- int target;
- int lun;
- int i;
- int channel;
-#endif
- int was_paused;
- scb = (struct scb *)arg;
- ahd = (struct ahd_softc *)scb->xs->sc_link->adapter_softc;
+ ahd = scb->ahd_softc;
+ if ((scb->flags & SCB_ACTIVE) != 0) {
+ if ((scb->flags & SCB_TIMEDOUT) == 0) {
+ LIST_INSERT_HEAD(&ahd->timedout_scbs, scb,
+ timedout_links);
+ scb->flags |= SCB_TIMEDOUT;
+ }
+ ahd_recover_commands(ahd);
+ }
+}
+
+/*
+ * ahd_recover_commands determines if any of the commands that have currently
+ * timedout are the root cause for this timeout. Innocent commands are given
+ * a new timeout while we wait for the command executing on the bus to timeout.
+ * This routine is invoked from a thread context so we are allowed to sleep.
+ * Our lock is not held on entry.
+ */
+void
+ahd_recover_commands(struct ahd_softc *ahd)
+{
+ struct scb *scb;
+ struct scb *active_scb;
+ long s;
+ int found;
+ int was_paused;
+ u_int active_scbptr;
+ u_int last_phase;
ahd_lock(ahd, &s);
@@ -9174,23 +9193,22 @@ ahd_timeout(void *arg)
ahd_pause_and_flushwork(ahd);
- if ((scb->flags & SCB_ACTIVE) == 0) {
+ if (LIST_EMPTY(&ahd->timedout_scbs) != 0) {
/*
- * The timed out commands have already
+ * The timedout commands have already
* completed. This typically means
* that either the timeout value was on
* the hairy edge of what the device
* requires or - more likely - interrupts
* are not happening.
*/
- printf("%s: Timed out SCBs already complete. "
+ printf("%s: Timedout SCBs already complete. "
"Interrupts may not be functioning.\n", ahd_name(ahd));
ahd_unpause(ahd);
ahd_unlock(ahd, &s);
return;
}
-#if 0
/*
* Determine identity of SCB acting on the bus.
* This test only catches non-packetized transactions.
@@ -9216,7 +9234,7 @@ ahd_timeout(void *arg)
lun = SCB_GET_LUN(scb);
ahd_print_path(ahd, scb);
- printf("SCB 0x%x - timed out\n", scb->hscb->tag);
+ printf("SCB %d - timed out\n", SCB_GET_TAG(scb));
if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) {
/*
@@ -9283,7 +9301,7 @@ bus_reset:
"Identify Msg.\n", ahd_name(ahd));
goto bus_reset;
} else if (ahd_search_qinfifo(ahd, target, channel, lun,
- scb->hscb->tag, ROLE_INITIATOR,
+ SCB_GET_TAG(scb), ROLE_INITIATOR,
/*status*/0, SEARCH_COUNT) > 0) {
/*
@@ -9375,12 +9393,11 @@ bus_reset:
LIST_REMOVE(scb, timedout_links);
scb->flags &= ~SCB_TIMEDOUT;
}
-#endif
+
ahd_unpause(ahd);
ahd_unlock(ahd, &s);
}
-#if 0
/*
* Re-schedule a timeout for the passed in SCB if we determine that some
* other SCB is in the process of recovery or an SCB with a longer
@@ -9431,7 +9448,7 @@ ahd_other_scb_timeout(struct ahd_softc *ahd, struct scb *scb,
return (found != 0);
}
-#endif
+
/**************************** Flexport Logic **********************************/
/*
* Read count 16bit words from 16bit word address start_addr from the
diff --git a/sys/dev/ic/aic79xx.h b/sys/dev/ic/aic79xx.h
index 7e1f887555d..1a917cf6eda 100644
--- a/sys/dev/ic/aic79xx.h
+++ b/sys/dev/ic/aic79xx.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: aic79xx.h,v 1.17 2004/12/19 06:17:54 krw Exp $ */
+/* $OpenBSD: aic79xx.h,v 1.18 2004/12/30 17:29:55 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
@@ -1095,6 +1095,8 @@ struct ahd_completion
uint8_t valid_tag;
};
+#define AIC_SCB_DATA(softc) (&(softc)->scb_data)
+
struct ahd_softc {
struct device sc_dev;
struct scsi_link sc_channel;
@@ -1588,4 +1590,6 @@ int ahd_print_register(ahd_reg_parse_entry_t *table,
u_int *cur_column,
u_int wrap_point);
void ahd_dump_scbs(struct ahd_softc *ahd);
+void ahd_set_recoveryscb(struct ahd_softc *, struct scb *);
+
#endif /* _AIC79XX_H_ */
diff --git a/sys/dev/ic/aic79xx_openbsd.c b/sys/dev/ic/aic79xx_openbsd.c
index 9d00225b80a..9e866230a44 100644
--- a/sys/dev/ic/aic79xx_openbsd.c
+++ b/sys/dev/ic/aic79xx_openbsd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aic79xx_openbsd.c,v 1.19 2004/12/28 04:12:24 krw Exp $ */
+/* $OpenBSD: aic79xx_openbsd.c,v 1.20 2004/12/30 17:29:55 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
@@ -170,6 +170,7 @@ void
ahd_done(struct ahd_softc *ahd, struct scb *scb)
{
struct scsi_xfer *xs = scb->xs;
+ struct scb *list_scb;
int s;
/* XXX in ahc there is some bus_dmamap_sync(PREREAD|PREWRITE); */
@@ -195,25 +196,29 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
* out of our timeout.
*/
if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
- struct scb *list_scb;
+ ahd->scb_data.recovery_scbs--;
- /*
- * We were able to complete the command successfully,
- * so reinstate the timeouts for all other pending
- * commands.
- */
- LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
- struct scsi_xfer *txs = list_scb->xs;
- if (!(txs->flags & SCSI_POLL))
- timeout_add(&list_scb->xs->stimeout,
- (list_scb->xs->timeout * hz)/1000);
- }
-
- if (aic_get_transaction_status(scb) != CAM_REQ_INPROG)
+ if (aic_get_transaction_status(scb) == CAM_BDR_SENT
+ || aic_get_transaction_status(scb) == CAM_REQ_ABORTED)
aic_set_transaction_status(scb, CAM_CMD_TIMEOUT);
- ahd_print_path(ahd, scb);
- printf("%s: no longer in timeout, status = %x\n",
- ahd_name(ahd), xs->status);
+
+ if (ahd->scb_data.recovery_scbs == 0) {
+ /*
+ * All recovery actions have completed successfully,
+ * so reinstate the timeouts for all other pending
+ * commands.
+ */
+ LIST_FOREACH(list_scb, &ahd->pending_scbs,
+ pending_links) {
+ if (!(list_scb->xs->flags & SCSI_POLL))
+ aic_scb_timer_reset(scb,
+ aic_get_timeout(scb));
+ }
+
+ ahd_print_path(ahd, scb);
+ printf("%s: no longer in timeout, status = %x\n",
+ ahd_name(ahd), aic_get_transaction_status(scb));
+ }
}
/* Translate the CAM status code to a SCSI error code. */
@@ -819,4 +824,24 @@ ahd_platform_flushwork(struct ahd_softc *ahd)
{
}
+void
+ahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb)
+{
+
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0) {
+ struct scb *list_scb;
+
+ scb->flags |= SCB_RECOVERY_SCB;
+
+ AIC_SCB_DATA(ahd)->recovery_scbs++;
+ /*
+ * Go through all of our pending SCBs and remove
+ * any scheduled timeouts for them. We will reschedule
+ * them after we've successfully fixed this problem.
+ */
+ LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) {
+ timeout_del(&list_scb->xs->stimeout);
+ }
+ }
+}
diff --git a/sys/dev/ic/aic79xx_openbsd.h b/sys/dev/ic/aic79xx_openbsd.h
index 51931af62e1..0b4e60aecca 100644
--- a/sys/dev/ic/aic79xx_openbsd.h
+++ b/sys/dev/ic/aic79xx_openbsd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: aic79xx_openbsd.h,v 1.14 2004/12/24 22:17:56 krw Exp $ */
+/* $OpenBSD: aic79xx_openbsd.h,v 1.15 2004/12/30 17:29:55 krw Exp $ */
/*
* Copyright (c) 2004 Milos Urbanek, Kenneth R. Westerback & Marco Peereboom
@@ -162,7 +162,7 @@ void aic_timer_reset(aic_timer_t *, u_int, ahd_callback_t *, void *);
void aic_scb_timer_reset(struct scb *, u_int);
#define aic_timer_stop timeout_del
-
+#define aic_get_timeout(scb) ((scb)->xs->timeout)
/*************************** Device Access ************************************/
#define ahd_inb(ahd, port) \
bus_space_read_1((ahd)->tags[(port) >> 8], \