diff options
-rw-r--r-- | sys/dev/ic/aic79xx.c | 71 | ||||
-rw-r--r-- | sys/dev/ic/aic79xx.h | 6 | ||||
-rw-r--r-- | sys/dev/ic/aic79xx_openbsd.c | 61 | ||||
-rw-r--r-- | sys/dev/ic/aic79xx_openbsd.h | 4 |
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], \ |