diff options
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 103 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.h | 1 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.seq | 1 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_freebsd.c | 39 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.c | 39 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_pci.c | 2 |
6 files changed, 117 insertions, 68 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index 8c709db..2db8998 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -229,6 +229,15 @@ restart_sequencer(struct ahc_softc *ahc) ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); + /* + * Ensure that the sequencer's idea of TQINPOS + * matches our own. The sequencer increments TQINPOS + * only after it sees a DMA complete and a reset could + * occur before the increment leaving the kernel to believe + * the command arrived but the sequencer to not. + */ + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + /* Always allow reselection */ ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); @@ -1045,11 +1054,15 @@ void ahc_clear_critical_section(struct ahc_softc *ahc) { int stepping; + u_int simode0; + u_int simode1; if (ahc->num_critical_sections == 0) return; stepping = FALSE; + simode0 = 0; + simode1 = 0; for (;;) { struct cs *cs; u_int seqaddr; @@ -1068,7 +1081,19 @@ ahc_clear_critical_section(struct ahc_softc *ahc) if (i == ahc->num_critical_sections) break; - if (!stepping) { + if (stepping == FALSE) { + + /* + * Disable all interrupt sources so that the + * sequencer will not be stuck by a pausing + * interrupt condition while we attempt to + * leave a critical section. + */ + simode0 = ahc_inb(ahc, SIMODE0); + ahc_outb(ahc, SIMODE0, 0); + simode1 = ahc_inb(ahc, SIMODE1); + ahc_outb(ahc, SIMODE1, 0); + ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP); stepping = TRUE; } @@ -1077,8 +1102,11 @@ ahc_clear_critical_section(struct ahc_softc *ahc) ahc_delay(200); } while (!sequencer_paused(ahc)); } - if (stepping) + if (stepping) { + ahc_outb(ahc, SIMODE0, simode0); + ahc_outb(ahc, SIMODE1, simode1); ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP); + } } /* @@ -2938,7 +2966,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, AHC_TRANS_CUR, /*paused*/TRUE); ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_SENT_BDR); if (message != NULL && (verbose_level <= bootverbose)) @@ -4818,31 +4846,6 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) if (initiate_reset) ahc_reset_current_bus(ahc); ahc_clear_intstat(ahc); - - /* - * Since we are going to restart the sequencer, avoid - * a race in the sequencer that could cause corruption - * of our Q pointers by starting over from index 1. - */ - *((uint32_t *)(&ahc->qoutfifo[ahc->qoutfifonext & ~0x3])) - = 0xFFFFFFFF; - ahc->qoutfifonext = 0; - if ((ahc->features & AHC_QUEUE_REGS) != 0) - ahc_outb(ahc, SDSCB_QOFF, 0); - else - ahc_outb(ahc, QOUTPOS, 0); - if ((ahc->flags & AHC_TARGETMODE) != 0) { - ahc->tqinfifonext = 1; - ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); - if ((ahc->features & AHC_HS_MAILBOX) != 0) { - u_int hs_mailbox; - - hs_mailbox = ahc_inb(ahc, HS_MAILBOX); - hs_mailbox &= ~HOST_TQINPOS; - ahc_outb(ahc, HS_MAILBOX, hs_mailbox); - } - } restart_needed = TRUE; } @@ -4883,7 +4886,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_BUS_RESET); /* * Revert to async/narrow transfers until we renegotiate. @@ -5122,8 +5125,10 @@ static void ahc_loadseq(struct ahc_softc *ahc) { struct cs cs_table[num_critical_sections]; + u_int begin_set[num_critical_sections]; + u_int end_set[num_critical_sections]; struct patch *cur_patch; - u_int cs_table_size; + u_int cs_count; u_int cur_cs; u_int i; int downloaded; @@ -5135,8 +5140,10 @@ ahc_loadseq(struct ahc_softc *ahc) * Start out with 0 critical sections * that apply to this firmware load. */ - cs_table_size = 0; + cs_count = 0; cur_cs = 0; + memset(begin_set, 0, sizeof(begin_set)); + memset(end_set, 0, sizeof(end_set)); /* Setup downloadable constant table */ download_consts[QOUTFIFO_OFFSET] = 0; @@ -5172,32 +5179,34 @@ ahc_loadseq(struct ahc_softc *ahc) * that might apply to this instruction. */ for (; cur_cs < num_critical_sections; cur_cs++) { - if (critical_sections[cur_cs].end >= i) { - if (critical_sections[cur_cs].begin == i) { - cs_table[cs_table_size].begin = - downloaded; - } - if (critical_sections[cur_cs].end == i) { - cs_table[cs_table_size].end = - downloaded; - cs_table_size++; + if (critical_sections[cur_cs].end <= i) { + if (begin_set[cs_count] == TRUE + && end_set[cs_count] == FALSE) { + cs_table[cs_count].end = downloaded; + end_set[cs_count] = TRUE; + cs_count++; } - break; + continue; + } + if (critical_sections[cur_cs].begin <= i + && begin_set[cs_count] == FALSE) { + cs_table[cs_count].begin = downloaded; + begin_set[cs_count] = TRUE; } + break; } ahc_download_instr(ahc, i, download_consts); downloaded++; } - ahc->num_critical_sections = cs_table_size; - if (cs_table_size != 0) { + ahc->num_critical_sections = cs_count; + if (cs_count != 0) { - cs_table_size *= sizeof(struct cs); - ahc->critical_sections = - malloc(cs_table_size, M_DEVBUF, M_NOWAIT); + cs_count *= sizeof(struct cs); + ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); if (ahc->critical_sections == NULL) panic("ahc_loadseq: Could not malloc"); - memcpy(ahc->critical_sections, cs_table, cs_table_size); + memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); restart_sequencer(ahc); diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h index 7e2bd94..86ecc7d 100644 --- a/sys/dev/aic7xxx/aic7xxx.h +++ b/sys/dev/aic7xxx/aic7xxx.h @@ -475,7 +475,6 @@ typedef enum { SCB_RECOVERY_SCB = 0x0040, SCB_NEGOTIATE = 0x0080, SCB_ABORT = 0x1000, - SCB_QUEUED_MSG = 0x2000, SCB_ACTIVE = 0x4000, SCB_TARGET_IMMEDIATE = 0x8000 } scb_flag; diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index ec9862e..33af1a5 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -1624,7 +1624,6 @@ setup_SCB_tagged: call set_transfer_settings; /* See if the host wants to send a message upon reconnection */ test SCB_CONTROL, MK_MESSAGE jz mesgin_done; - and SCB_CONTROL, ~MK_MESSAGE; mvi HOST_MSG call mk_mesg; jmp mesgin_done; diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.c b/sys/dev/aic7xxx/aic7xxx_freebsd.c index 988ebb4..04d83b9 100644 --- a/sys/dev/aic7xxx/aic7xxx_freebsd.c +++ b/sys/dev/aic7xxx/aic7xxx_freebsd.c @@ -1542,7 +1542,7 @@ bus_reset: } ahc_set_recoveryscb(ahc, active_scb); - ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET); + 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"); @@ -1581,19 +1581,25 @@ bus_reset: ahc_set_recoveryscb(ahc, scb); /* - * Simply set the MK_MESSAGE control bit. - */ - scb->hscb->control |= MK_MESSAGE; - scb->flags |= SCB_QUEUED_MSG - | SCB_DEVICE_RESET; - - /* * 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 @@ -1604,7 +1610,21 @@ bus_reset: lun, scb->hscb->tag, /*stop_on_first*/TRUE, /*remove*/TRUE, - /*save_state*/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 @@ -1630,6 +1650,7 @@ bus_reset: prev_tag); } ahc_qinfifo_requeue(ahc, prev_scb, scb); + ahc_outb(ahc, SCBPTR, active_scb_index); scb->io_ctx->ccb_h.timeout_ch = timeout(ahc_timeout, (caddr_t)scb, 2 * hz); unpause_sequencer(ahc); diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c index 988ebb4..04d83b9 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.c +++ b/sys/dev/aic7xxx/aic7xxx_osm.c @@ -1542,7 +1542,7 @@ bus_reset: } ahc_set_recoveryscb(ahc, active_scb); - ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET); + 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"); @@ -1581,19 +1581,25 @@ bus_reset: ahc_set_recoveryscb(ahc, scb); /* - * Simply set the MK_MESSAGE control bit. - */ - scb->hscb->control |= MK_MESSAGE; - scb->flags |= SCB_QUEUED_MSG - | SCB_DEVICE_RESET; - - /* * 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 @@ -1604,7 +1610,21 @@ bus_reset: lun, scb->hscb->tag, /*stop_on_first*/TRUE, /*remove*/TRUE, - /*save_state*/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 @@ -1630,6 +1650,7 @@ bus_reset: prev_tag); } ahc_qinfifo_requeue(ahc, prev_scb, scb); + ahc_outb(ahc, SCBPTR, active_scb_index); scb->io_ctx->ccb_h.timeout_ch = timeout(ahc_timeout, (caddr_t)scb, 2 * hz); unpause_sequencer(ahc); diff --git a/sys/dev/aic7xxx/aic7xxx_pci.c b/sys/dev/aic7xxx/aic7xxx_pci.c index 91c1889..4179a29 100644 --- a/sys/dev/aic7xxx/aic7xxx_pci.c +++ b/sys/dev/aic7xxx/aic7xxx_pci.c @@ -1711,7 +1711,7 @@ ahc_aic7880_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) if (rev >= 1) { probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG; } else { - probe_config->bugs |= AHC_CACHETHEN_BUG; + probe_config->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; } return (0); } |