diff options
-rw-r--r-- | sys/dev/ic/aic7xxx.c | 7 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxx_openbsd.c | 302 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxxvar.h | 11 |
3 files changed, 28 insertions, 292 deletions
diff --git a/sys/dev/ic/aic7xxx.c b/sys/dev/ic/aic7xxx.c index e2dbc949fe4..4037f07a738 100644 --- a/sys/dev/ic/aic7xxx.c +++ b/sys/dev/ic/aic7xxx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aic7xxx.c,v 1.70 2005/12/04 03:56:17 krw Exp $ */ +/* $OpenBSD: aic7xxx.c,v 1.71 2005/12/28 03:00:07 krw Exp $ */ /* $NetBSD: aic7xxx.c,v 1.108 2003/11/02 11:07:44 wiz Exp $ */ /* @@ -40,7 +40,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: aic7xxx.c,v 1.70 2005/12/04 03:56:17 krw Exp $ + * $Id: aic7xxx.c,v 1.71 2005/12/28 03:00:07 krw Exp $ */ /* * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003 @@ -953,8 +953,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) devinfo.lun); scbindex = ahc_inb(ahc, SCB_TAG); scb = ahc_lookup_scb(ahc, scbindex); - if (scb != NULL - && (scb->flags & SCB_RECOVERY_SCB) != 0) + if (scb != NULL) /* * Ensure that we didn't put a second instance of this * SCB into the QINFIFO. diff --git a/sys/dev/ic/aic7xxx_openbsd.c b/sys/dev/ic/aic7xxx_openbsd.c index b78db6f37e5..9933f9ecfbe 100644 --- a/sys/dev/ic/aic7xxx_openbsd.c +++ b/sys/dev/ic/aic7xxx_openbsd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aic7xxx_openbsd.c,v 1.30 2005/11/02 03:27:39 krw Exp $ */ +/* $OpenBSD: aic7xxx_openbsd.c,v 1.31 2005/12/28 03:00:07 krw Exp $ */ /* $NetBSD: aic7xxx_osm.c,v 1.14 2003/11/02 11:07:44 wiz Exp $ */ /* @@ -55,7 +55,6 @@ int ahc_action(struct scsi_xfer *); int ahc_execute_scb(void *, bus_dma_segment_t *, int); int ahc_poll(struct ahc_softc *, int); int ahc_setup_data(struct ahc_softc *, struct scsi_xfer *, struct scb *); -void ahc_set_recoveryscb(struct ahc_softc *, struct scb *); void ahc_minphys(struct buf *); void ahc_adapter_req_set_xfer_mode(struct ahc_softc *, struct scb *); @@ -196,31 +195,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) bus_dmamap_unload(ahc->parent_dmat, scb->dmamap); } - /* - * If the recovery SCB completes, we have to be - * out of our timeout. - */ - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - struct scb *list_scb; - - /* - * We were able to complete the command successfully, - * so reinstate the timeouts for all other pending - * commands. - */ - LIST_FOREACH(list_scb, &ahc->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 (xs->error != CAM_REQ_INPROG) - ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); - ahc_print_path(ahc, scb); - printf("no longer in timeout, status = %x\n", xs->status); - } - /* Translate the CAM status code to a SCSI error code. */ switch (xs->error) { case CAM_SCSI_STATUS_ERROR: @@ -644,35 +618,12 @@ ahc_setup_data(struct ahc_softc *ahc, struct scsi_xfer *xs, } void -ahc_set_recoveryscb(struct ahc_softc *ahc, struct scb *scb) { - - if ((scb->flags & SCB_RECOVERY_SCB) == 0) { - struct scb *list_scb; - - scb->flags |= SCB_RECOVERY_SCB; - - /* - * 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, &ahc->pending_scbs, pending_links) { - timeout_del(&list_scb->xs->stimeout); - } - } -} - -void ahc_timeout(void *arg) { - struct scb *scb; + struct scb *scb, *list_scb; struct ahc_softc *ahc; int s; int found; - u_int last_phase; - int target; - int lun; - int i; char channel; scb = (struct scb *)arg; @@ -680,242 +631,33 @@ ahc_timeout(void *arg) ahc_lock(ahc, &s); - ahc_pause_and_flushwork(ahc); - - if ((scb->flags & SCB_ACTIVE) == 0) { - /* Previous timeout took care of me already */ - printf("%s: Timed out SCB already complete. " - "Interrupts may not be functioning.\n", ahc_name(ahc)); - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - return; - } +#ifdef AHC_DEBUG + printf("%s: SCB %d timed out\n", ahc_name(ahc), scb->hscb->tag); + ahc_dump_card_state(ahc); +#endif - target = SCB_GET_TARGET(ahc, scb); - channel = SCB_GET_CHANNEL(ahc, scb); - lun = SCB_GET_LUN(scb); + ahc_pause(ahc); - ahc_print_path(ahc, scb); - printf("SCB 0x%x - timed out\n", scb->hscb->tag); - ahc_dump_card_state(ahc); - last_phase = ahc_inb(ahc, LASTPHASE); - if (scb->sg_count > 0) { - for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x : Length %d\n", - i, - scb->sg_list[i].addr, - scb->sg_list[i].len & AHC_SG_LEN_MASK); - } - } - if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) { - /* - * Been down this road before. - * Do a full bus reset. - */ -bus_reset: + if (scb->flags & SCB_ACTIVE) { + channel = SCB_GET_CHANNEL(ahc, scb); ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); - found = ahc_reset_channel(ahc, channel, /*Initiate Reset*/TRUE); - printf("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), channel, found); - } else { /* - * If we are a target, transition to bus free and report - * the timeout. - * - * The target/initiator that is holding up the bus may not - * be the same as the one that triggered this timeout - * (different commands have different timeout lengths). - * If the bus is idle and we are acting as the initiator - * for this request, queue a BDR message to the timed out - * target. Otherwise, if the timed out transaction is - * active: - * Initiator transaction: - * Stuff the message buffer with a BDR message and assert - * ATN in the hopes that the target will let go of the bus - * and go to the mesgout phase. If this fails, we'll - * get another timeout 2 seconds later which will attempt - * a bus reset. - * - * Target transaction: - * Transition to BUS FREE and report the error. - * It's good to be the target! + * Go through all of our pending SCBs and remove + * any scheduled timeouts for them. They're about to be + * aborted so no need for them to timeout. */ - u_int active_scb_index; - u_int saved_scbptr; - - bus_dmamap_sync(ahc->parent_dmat, - ahc->scb_data->hscb_dmamap, - 0, ahc->scb_data->hscb_dmamap->dm_mapsize, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - saved_scbptr = ahc_inb(ahc, SCBPTR); - active_scb_index = ahc_inb(ahc, SCB_TAG); - - if ((ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) == 0 - && (active_scb_index < ahc->scb_data->numscbs)) { - struct scb *active_scb; - - /* - * If the active SCB is not us, assume that - * the active SCB has a longer timeout than - * the timedout SCB, and wait for the active - * SCB to timeout. - */ - active_scb = ahc_lookup_scb(ahc, active_scb_index); - if (active_scb != scb) { - u_int newtimeout; - - ahc_print_path(ahc, active_scb); - printf("Other SCB Timeout%s", - (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 - ? " again\n" : "\n"); - scb->flags |= SCB_OTHERTCL_TIMEOUT; - newtimeout = MAX(active_scb->xs->timeout, - scb->xs->timeout); - timeout_add(&scb->xs->stimeout, - (newtimeout * hz) / 1000); - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - return; - } - - /* It's us */ - if ((scb->flags & SCB_TARGET_SCB) != 0) { - - /* - * Send back any queued up transactions - * and properly record the error condition. - */ - ahc_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), - scb->hscb->tag, - ROLE_TARGET, - CAM_CMD_TIMEOUT); - - /* Will clear us from the bus */ - ahc_restart(ahc); - ahc_unlock(ahc, &s); - return; - } - - ahc_set_recoveryscb(ahc, active_scb); - ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, last_phase|ATNO); - ahc_print_path(ahc, active_scb); - printf("BDR message in message buffer\n"); - active_scb->flags |= SCB_DEVICE_RESET; - timeout_add(&active_scb->xs->stimeout, 2 * hz); - ahc_unpause(ahc); - } else { - int disconnected; - - bus_dmamap_sync(ahc->parent_dmat, - ahc->scb_data->hscb_dmamap, - 0, ahc->scb_data->hscb_dmamap->dm_mapsize, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - /* XXX Shouldn't panic. Just punt instead */ - if ((scb->flags & SCB_TARGET_SCB) != 0) - panic("Timed-out target SCB but bus idle"); - - if (last_phase != P_BUSFREE - && (ahc_inb(ahc, SSTAT0) & TARGET) != 0) { - /* XXX What happened to the SCB? */ - /* Hung target selection. Goto busfree */ - printf("%s: Hung target selection\n", - ahc_name(ahc)); - ahc_restart(ahc); - ahc_unlock(ahc, &s); - return; - } - - if (ahc_search_qinfifo(ahc, target, channel, lun, - scb->hscb->tag, ROLE_INITIATOR, - /*status*/0, SEARCH_COUNT) > 0) { - disconnected = FALSE; - } else { - disconnected = TRUE; - } - - if (disconnected) { - - ahc_set_recoveryscb(ahc, scb); - /* - * Actually re-queue this SCB in an attempt - * to select the device before it reconnects. - * In either case (selection or reselection), - * we will now issue a target reset to the - * timed-out device. - * - * Set the MK_MESSAGE control bit indicating - * that we desire to send a message. We - * also set the disconnected flag since - * in the paging case there is no guarantee - * that our SCB control byte matches the - * version on the card. We don't want the - * sequencer to abort the command thinking - * an unsolicited reselection occurred. - */ - scb->hscb->control |= MK_MESSAGE|DISCONNECTED; - scb->flags |= SCB_DEVICE_RESET; - - /* - * Remove any cached copy of this SCB in the - * disconnected list in preparation for the - * queuing of our abort SCB. We use the - * same element in the SCB, SCB_NEXT, for - * both the qinfifo and the disconnected list. - */ - ahc_search_disc_list(ahc, target, channel, - lun, scb->hscb->tag, - /*stop_on_first*/TRUE, - /*remove*/TRUE, - /*save_state*/FALSE); - - /* - * In the non-paging case, the sequencer will - * never re-reference the in-core SCB. - * To make sure we are notified during - * reslection, set the MK_MESSAGE flag in - * the card's copy of the SCB. - */ - if ((ahc->flags & AHC_PAGESCBS) == 0) { - ahc_outb(ahc, SCBPTR, scb->hscb->tag); - ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) - | MK_MESSAGE); - } - - /* - * Clear out any entries in the QINFIFO first - * so we are the next SCB for this target - * to run. - */ - ahc_search_qinfifo(ahc, - SCB_GET_TARGET(ahc, scb), - channel, SCB_GET_LUN(scb), - SCB_LIST_NULL, - ROLE_INITIATOR, - CAM_REQUEUE_REQ, - SEARCH_COMPLETE); - ahc_print_path(ahc, scb); - printf("Queuing a BDR SCB\n"); - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, SCBPTR, saved_scbptr); - timeout_add(&scb->xs->stimeout, 2 * hz); - ahc_unpause(ahc); - } else { - /* Go "immediately" to the bus reset. */ - /* This shouldn't happen. */ - ahc_set_recoveryscb(ahc, scb); - ahc_print_path(ahc, scb); - printf("SCB %d: Immediate reset. " - "Flags = 0x%x\n", scb->hscb->tag, - scb->flags); - goto bus_reset; - } + LIST_FOREACH(list_scb, &ahc->pending_scbs, pending_links) { + if (list_scb->xs) + timeout_del(&list_scb->xs->stimeout); } + found = ahc_reset_channel(ahc, channel, /*Initiate Reset*/TRUE); +#ifdef AHC_DEBUG + printf("%s: Issued Channel %c Bus Reset %d SCBs aborted\n", + ahc_name(ahc), channel, found); +#endif } + + ahc_unpause(ahc); ahc_unlock(ahc, &s); } diff --git a/sys/dev/ic/aic7xxxvar.h b/sys/dev/ic/aic7xxxvar.h index 48e1925ce6f..584f9e27492 100644 --- a/sys/dev/ic/aic7xxxvar.h +++ b/sys/dev/ic/aic7xxxvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: aic7xxxvar.h,v 1.20 2004/08/01 01:36:23 krw Exp $ */ +/* $OpenBSD: aic7xxxvar.h,v 1.21 2005/12/28 03:00:07 krw Exp $ */ /* * Core definitions and data structures shareable across OS platforms. * @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: aic7xxxvar.h,v 1.20 2004/08/01 01:36:23 krw Exp $ + * $Id: aic7xxxvar.h,v 1.21 2005/12/28 03:00:07 krw Exp $ * * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.50 2003/12/17 00:02:09 gibbs Exp $ */ @@ -561,7 +561,6 @@ typedef enum { SCB_DEVICE_RESET = 0x0004, SCB_SENSE = 0x0008, SCB_CDB32_PTR = 0x0010, - SCB_RECOVERY_SCB = 0x0020, SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */ SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */ SCB_ABORT = 0x0100, @@ -579,16 +578,12 @@ typedef enum { * to report the error. */ SCB_TARGET_SCB = 0x2000, - SCB_SILENT = 0x4000,/* + SCB_SILENT = 0x4000 /* * Be quiet about transmission type * errors. They are expected and we * don't want to upset the user. This * flag is typically used during DV. */ - SCB_TIMEDOUT = 0x8000 /* - * SCB has timed out and is on the - * timedout list. - */ } scb_flag; struct scb { |