aic79xx.c:
authorPeter Avalos <pavalos@dragonflybsd.org>
Fri, 6 Jul 2007 02:23:32 +0000 (02:23 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Fri, 6 Jul 2007 02:23:32 +0000 (02:23 +0000)
Allow 500us between pauses in ahd_pause_and_flushwork().
The maximum we will wait is now 500ms.

In the same routine, remove any attempt to clear ENSELO.
Let the firmware do it once the current selection has
completed.  This avoids some race conditions having to
do with non-packetized completions and the auto-clearing
of ENSELO on packetized completions.

Also avoid attempts to clear critical sections when
interrups are pending.  We are going to loop again
anyway, so clearing critical sections is a waste of
time.  It also may not be possible to clear a critical
section if the source of the interrupt was a SEQINT.

aic79xx_pci.c:
Use the Generic 9005 mask when looking for generic 7901B
parts.  This allows the driver to attach to 7901B parts
on motherboards using a non-Adaptec subvendor ID.

aic79xx_inline.h:
Test for the SCBRAM_RD_BUG against the bugs
field, not the flags field in the softc.

aic79xx.c:
Cancel pending transactions on devices that
respond with a selection timeout.  This decreases
the duration of timeout recovery when a device
disappears.

aic79xx.c:
Don't bother forcing renegotiation on a selection
timeout now that we use the device reset handler
to abort any pending commands on the target.
The device reset handler already takes us down
to async narrow and forces a renegotiation.

In the device reset handlers, only send a
BDR sent async event if the status is not
CAM_SEL_TIMEOUT.  This avoids sending this
event in the selection timeout case

aic79xx.c:
Modify the Core timeout handler to verify that another
command has the potential to timeout before passing off
a command timeout as due to some other command.  This
safety measure is added in response to a timeout recovery
failure on H2B where it appears that incoming reselection
status was lost during a drive pull test.  In that case,
the recovery handler continued to wait for the command
that was active on the bus indefinetly.  While the root
cause of the above issue is still being determined seems
a prudent safeguard.

aic79xx_pci.c:
Add a specific probe entry for the Dell OEM 39320(B).

aic79xx.c:
aic79xx.h:
aic79xx.reg:
aic79xx.seq:
Modify the aic79xx firmware to never cross a cacheline or
ADB boundary when DMA'ing completion entries to the host.
In PCI mode, at least in 32/33 configurations, the SCB
DMA engine may lose its place in the data-stream should
the target force a retry on something other than an
8byte aligned boundary. In PCI-X mode, we do this to
avoid split transactions since many chipsets seem to be
unable to format proper split completions to continue
the data transfer.

The above change allows us to drop our completion entries
from 8 bytes to 4.  We were using 8 byte entries to ensure
that PCI retries could only occur on an 8byte aligned
boundary.  Now that the sequencer guarantees this by splitting
up completions, we can safely drop the size to 4 bytes (2
byte tag, one byte SG_RESID, one byte pad).

Both the split-completion and PCI retry problems only show
up under high tag load when interrupt coalescing is being
especially effective.  The switch from a 2byte completion
entry to an 8 byte entry to solve the PCI problem increased
the chance of incurring a split in PCI-X mode when multiple
transactions were completed at once.  Dropping the completion
size to 4 bytes also means that we can complete more commands
in a single DMA (128byte FIFO -> 32 commands instead of 16).

aic79xx.c:
Modify the SCSIINT handler to defer clearing
sequencer critical sections to the individual
interrupt handlers.  This allows us to
immediately disable any outgoing selections in
the case of an unexpected busfree so we don't
inadvertantly clear ENSELO *after* a new selection
has started.  Doing so may cause the sequencer
to miss a successful selection.

In ahd_update_pending_scbs(), only clear ENSELO if
the bus is currently busy and a selection is not
already in progress or the sequencer has yet to
handle a pending selection.  While we want to ensure
that the selection for the SCB at the head of the
selection queue is restarted so that any change in
negotiation request can take effect, we can't clobber
pending selection state without confusing the sequencer
into missing a selection.

Obtained-from: FreeBSD

sys/dev/disk/aic7xxx/aic79xx.c
sys/dev/disk/aic7xxx/aic79xx.h
sys/dev/disk/aic7xxx/aic79xx.reg
sys/dev/disk/aic7xxx/aic79xx.seq
sys/dev/disk/aic7xxx/aic79xx_inline.h
sys/dev/disk/aic7xxx/aic79xx_pci.c

index 4f1e462..8816b5d 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#238 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#246 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.c,v 1.28 2004/02/04 16:38:38 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.c,v 1.19 2007/07/06 00:56:38 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.c,v 1.29 2004/05/11 20:46:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.c,v 1.20 2007/07/06 02:23:31 pavalos Exp $
  */
 
 #include "aic79xx_osm.h"
@@ -220,7 +220,7 @@ static u_int                ahd_resolve_seqaddr(struct ahd_softc *ahd,
 static void            ahd_download_instr(struct ahd_softc *ahd,
                                           u_int instrptr, uint8_t *dconsts);
 static int             ahd_probe_stack_size(struct ahd_softc *ahd);
-static void            ahd_other_scb_timeout(struct ahd_softc *ahd,
+static int             ahd_other_scb_timeout(struct ahd_softc *ahd,
                                              struct scb *scb,
                                              struct scb *other_scb);
 static int             ahd_scb_active_in_fifo(struct ahd_softc *ahd,
@@ -333,6 +333,14 @@ ahd_restart(struct ahd_softc *ahd)
        ahd_outb(ahd, SCSISEQ1,
                 ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));
        ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+
+       /*
+        * Clear any pending sequencer interrupt.  It is no
+        * longer relevant since we're resetting the Program
+        * Counter.
+        */
+       ahd_outb(ahd, CLRINT, CLRSEQINT);
+
        ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET);
        ahd_unpause(ahd);
 }
@@ -1538,9 +1546,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
         && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
                scb = NULL;
 
-       /* Make sure the sequencer is in a safe location. */
-       ahd_clear_critical_section(ahd);
-
        if ((status0 & IOERR) != 0) {
                u_int now_lvd;
 
@@ -1556,26 +1561,35 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                ahd_setup_iocell_workaround(ahd);
                ahd_unpause(ahd);
        } else if ((status0 & OVERRUN) != 0) {
+
                kprintf("%s: SCSI offset overrun detected.  Resetting bus.\n",
                       ahd_name(ahd));
                ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
        } else if ((status & SCSIRSTI) != 0) {
+
                kprintf("%s: Someone reset channel A\n", ahd_name(ahd));
                ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
        } else if ((status & SCSIPERR) != 0) {
+
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                ahd_handle_transmission_error(ahd);
        } else if (lqostat0 != 0) {
+
                kprintf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
                ahd_outb(ahd, CLRLQOINT0, lqostat0);
-               if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
+               if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
                        ahd_outb(ahd, CLRLQOINT1, 0);
-               }
        } else if ((status & SELTO) != 0) {
                u_int  scbid;
 
                /* Stop the selection */
                ahd_outb(ahd, SCSISEQ0, 0);
 
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                /* No more pending messages */
                ahd_clear_msg_state(ahd);
 
@@ -1608,24 +1622,27 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                                       scbid);
                        }
 #endif
-                       /*
-                        * Force a renegotiation with this target just in
-                        * case the cable was pulled and will later be
-                        * re-attached.  The target may forget its negotiation
-                        * settings with us should it attempt to reselect
-                        * during the interruption.  The target will not issue
-                        * a unit attention in this case, so we must always
-                        * renegotiate.
-                        */
                        ahd_scb_devinfo(ahd, &devinfo, scb);
-                       ahd_force_renegotiation(ahd, &devinfo);
                        aic_set_transaction_status(scb, CAM_SEL_TIMEOUT);
                        ahd_freeze_devq(ahd, scb);
+
+                       /*
+                        * Cancel any pending transactions on the device
+                        * now that it seems to be missing.  This will
+                        * also revert us to async/narrow transfers until
+                        * we can renegotiate with the device.
+                        */
+                       ahd_handle_devreset(ahd, &devinfo,
+                                           CAM_LUN_WILDCARD,
+                                           CAM_SEL_TIMEOUT,
+                                           "Selection Timeout",
+                                           /*verbose_level*/1);
                }
                ahd_outb(ahd, CLRINT, CLRSCSIINT);
                ahd_iocell_first_selection(ahd);
                ahd_unpause(ahd);
        } else if ((status0 & (SELDI|SELDO)) != 0) {
+
                ahd_iocell_first_selection(ahd);
                ahd_unpause(ahd);
        } else if (status3 != 0) {
@@ -1633,6 +1650,10 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                       ahd_name(ahd), status3);
                ahd_outb(ahd, CLRSINT3, status3);
        } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
+
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                ahd_handle_lqiphase_error(ahd, lqistat1);
        } else if ((lqistat1 & LQICRCI_NLQ) != 0) {
                /*
@@ -1657,6 +1678,9 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                 */
                ahd_outb(ahd, SCSISEQ0, 0);
 
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                /*
                 * Determine what we were up to at the time of
                 * the busfree.
@@ -1695,6 +1719,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                        packetized =  (lqostat1 & LQOBUSFREE) != 0;
                        if (!packetized
                         && ahd_inb(ahd, LASTPHASE) == P_BUSFREE
+                        && (ahd_inb(ahd, SSTAT0) & SELDI) == 0
                         && ((ahd_inb(ahd, SSTAT0) & SELDO) == 0
                          || (ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0))
                                /*
@@ -3342,11 +3367,15 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
         * Force the sequencer to reinitialize the selection for
         * the command at the head of the execution queue if it
         * has already been setup.  The negotiation changes may
-        * effect whether we select-out with ATN.
+        * effect whether we select-out with ATN.  It is only
+        * safe to clear ENSELO when the bus is not free and no
+        * selection is in progres or completed.
         */
        saved_modes = ahd_save_modes(ahd);
        ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-       ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+       if ((ahd_inb(ahd, SCSISIGI) & BSYI) != 0
+        && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
+               ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
        saved_scbptr = ahd_get_scbptr(ahd);
        /* Ensure that the hscbs down on the card match the new information */
        for (scb_tag = 0; scb_tag < ahd->scb_data.maxhscbs; scb_tag++) {
@@ -5052,10 +5081,12 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
        ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
                      AHD_TRANS_CUR, /*paused*/TRUE);
        ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0,
-                        /*ppr_options*/0, AHD_TRANS_CUR, /*paused*/TRUE);
+                        /*ppr_options*/0, AHD_TRANS_CUR,
+                        /*paused*/TRUE);
        
-       ahd_send_async(ahd, devinfo->channel, devinfo->target,
-                      lun, AC_SENT_BDR, NULL);
+       if (status != CAM_SEL_TIMEOUT)
+               ahd_send_async(ahd, devinfo->channel, devinfo->target,
+                              lun, AC_SENT_BDR, NULL);
 
        if (message != NULL
         && (verbose_level <= bootverbose))
@@ -5990,22 +6021,6 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
                hscb = (struct hardware_scb *)hscb_map->vaddr;
                hscb_busaddr = hscb_map->busaddr;
                scb_data->scbs_left = PAGE_SIZE / sizeof(*hscb);
-               if (ahd->next_queued_hscb == NULL) {
-                       /*
-                        * We need one HSCB to serve as the "next HSCB".  Since
-                        * the tag identifier in this HSCB will never be used,
-                        * there is no point in using a valid SCB from the
-                        * free pool for it.  So, we allocate this "sentinel"
-                        * specially.
-                        */
-                       ahd->next_queued_hscb = hscb;
-                       ahd->next_queued_hscb_map = hscb_map;
-                       memset(hscb, 0, sizeof(*hscb));
-                       hscb->hscb_busaddr = aic_htole32(hscb_busaddr);
-                       hscb++;
-                       hscb_busaddr += sizeof(*hscb);
-                       scb_data->scbs_left--;
-               }
        }
 
        if (scb_data->sgs_left != 0) {
@@ -6249,7 +6264,8 @@ ahd_init(struct ahd_softc *ahd)
         * for the target mode role, we must additionally provide space for
         * the incoming target command fifo.
         */
-       driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo);
+       driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo)
+                        + sizeof(struct hardware_scb);
        if ((ahd->features & AHD_TARGETMODE) != 0)
                driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd);
        if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0)
@@ -6299,6 +6315,17 @@ ahd_init(struct ahd_softc *ahd)
                next_baddr += PKT_OVERRUN_BUFSIZE;
        }
 
+       /*
+        * We need one SCB to serve as the "next SCB".  Since the
+        * tag identifier in this SCB will never be used, there is
+        * no point in using a valid HSCB tag from an SCB pulled from
+        * the standard free pool.  So, we allocate this "sentinel"
+        * specially from the DMA safe memory chunk used for the QOUTFIFO.
+        */
+       ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr;
+       ahd->next_queued_hscb_map = &ahd->shared_data_map;
+       ahd->next_queued_hscb->hscb_busaddr = aic_htole32(next_baddr);
+
        ahd->init_level++;
 
        /* Allocate SCB data now that buffer_dmat is initialized */
@@ -7019,35 +7046,21 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
        ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
        ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN);
        do {
-               struct scb *waiting_scb;
 
                ahd_unpause(ahd);
                /*
                 * Give the sequencer some time to service
                 * any active selections.
                 */
-               aic_delay(200);
+               aic_delay(500);
 
                ahd_intr(ahd);
                ahd_pause(ahd);
-               ahd_clear_critical_section(ahd);
                intstat = ahd_inb(ahd, INTSTAT);
-               ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-               if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
-                       ahd_outb(ahd, SCSISEQ0,
-                                ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
-               /*
-                * In the non-packetized case, the sequencer (for Rev A),
-                * relies on ENSELO remaining set after SELDO.  The hardware
-                * auto-clears ENSELO in the packetized case.
-                */
-               waiting_scb = ahd_lookup_scb(ahd,
-                                            ahd_inw(ahd, WAITING_TID_HEAD));
-               if (waiting_scb != NULL
-                && (waiting_scb->flags & SCB_PACKETIZED) == 0
-                && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)
-                       ahd_outb(ahd, SCSISEQ0,
-                                ahd_inb(ahd, SCSISEQ0) | ENSELO);
+               if ((intstat & INT_PEND) == 0) {
+                       ahd_clear_critical_section(ahd);
+                       intstat = ahd_inb(ahd, INTSTAT);
+               }
        } while (--maxloops
              && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
              && ((intstat & INT_PEND) != 0
@@ -8430,13 +8443,14 @@ ahd_loadseq(struct ahd_softc *ahd)
        u_int   sg_prefetch_cnt_limit;
        u_int   sg_prefetch_align;
        u_int   sg_size;
+       u_int   cacheline_mask;
        uint8_t download_consts[DOWNLOAD_CONST_COUNT];
 
        if (bootverbose)
                kprintf("%s: Downloading Sequencer Program...",
                       ahd_name(ahd));
 
-#if DOWNLOAD_CONST_COUNT != 7
+#if DOWNLOAD_CONST_COUNT != 8
 #error "Download Const Mismatch"
 #endif
        /*
@@ -8472,6 +8486,9 @@ ahd_loadseq(struct ahd_softc *ahd)
        /* Round down to the nearest power of 2. */
        while (powerof2(sg_prefetch_align) == 0)
                sg_prefetch_align--;
+
+       cacheline_mask = sg_prefetch_align - 1;
+
        /*
         * If the cacheline boundary is greater than half our prefetch RAM
         * we risk not being able to fetch even a single complete S/G
@@ -8512,6 +8529,7 @@ ahd_loadseq(struct ahd_softc *ahd)
        download_consts[PKT_OVERRUN_BUFOFFSET] =
                (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256;
        download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN;
+       download_consts[CACHELINE_MASK] = cacheline_mask;
        cur_patch = patches;
        downloaded = 0;
        skip_addr = 0;
@@ -9187,13 +9205,18 @@ bus_reset:
                if (active_scb != NULL) {
 
                        if (active_scb != 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.
+                                * SCB to timeout.  As a safeguard, only
+                                * allow this deferral to continue if some
+                                * untimed-out command is outstanding.
                                 */ 
-                               ahd_other_scb_timeout(ahd, scb, active_scb);
+                               if (ahd_other_scb_timeout(ahd, scb,
+                                                         active_scb) != 0)
+                                       goto bus_reset;
                                continue;
                        } 
 
@@ -9231,7 +9254,8 @@ bus_reset:
                         * some other command.  Reset the timer
                         * and go on.
                         */
-                       ahd_other_scb_timeout(ahd, scb, scb);
+                       if (ahd_other_scb_timeout(ahd, scb, NULL) != 0)
+                               goto bus_reset;
                } else {
                        /*
                         * This SCB is for a disconnected transaction
@@ -9327,20 +9351,55 @@ bus_reset:
        ahd_unlock();
 }
 
-static void
+/*
+ * 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
+ * timeout is still pending.  Limit our search to just "other_scb"
+ * if it is non-NULL.
+ */
+static int
 ahd_other_scb_timeout(struct ahd_softc *ahd, struct scb *scb,
                      struct scb *other_scb)
 {
        u_int   newtimeout;
+       int     found;
 
        ahd_print_path(ahd, scb);
        kprintf("Other SCB Timeout%s",
               (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0
               ? " again\n" : "\n");
+
+       newtimeout = aic_get_timeout(scb);
        scb->flags |= SCB_OTHERTCL_TIMEOUT;
-       newtimeout = MAX(aic_get_timeout(other_scb),
-                        aic_get_timeout(scb));
-       aic_scb_timer_reset(scb, newtimeout);
+       found = 0;
+       if (other_scb != NULL) {
+               if ((other_scb->flags
+                  & (SCB_OTHERTCL_TIMEOUT|SCB_TIMEDOUT)) == 0
+                || (other_scb->flags & SCB_RECOVERY_SCB) != 0) {
+                       found++;
+                       newtimeout = MAX(aic_get_timeout(other_scb),
+                                        newtimeout);
+               }
+       } else {
+               LIST_FOREACH(other_scb, &ahd->pending_scbs, pending_links) {
+                       if ((other_scb->flags
+                          & (SCB_OTHERTCL_TIMEOUT|SCB_TIMEDOUT)) == 0
+                        || (other_scb->flags & SCB_RECOVERY_SCB) != 0) {
+                               found++;
+                               newtimeout = MAX(aic_get_timeout(other_scb),
+                                                newtimeout);
+                       }
+               }
+       }
+
+       if (found != 0)
+               aic_scb_timer_reset(scb, newtimeout);
+       else {
+               ahd_print_path(ahd, scb);
+               kprintf("No other SCB worth waiting for...\n");
+       }
+
+       return (found != 0);
 }
 
 /**************************** Flexport Logic **********************************/
index 723feeb..b8e5a06 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#106 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#107 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.h,v 1.18 2004/02/04 16:38:38 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.h,v 1.7 2007/07/06 00:56:38 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.h,v 1.19 2004/05/11 20:46:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.h,v 1.8 2007/07/06 02:23:31 pavalos Exp $
  */
 
 #ifndef _AIC79XX_H_
@@ -1066,7 +1066,6 @@ struct ahd_completion
 {
        uint16_t        tag;
        uint8_t         sg_status;
-       uint8_t         pad[4];
        uint8_t         valid_tag;
 };
 
index f296873..28bf3d2 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.reg,v 1.16 2004/02/04 16:38:38 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.reg,v 1.3 2007/07/06 00:56:38 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.reg,v 1.17 2004/05/11 20:46:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.reg,v 1.4 2007/07/06 02:23:31 pavalos Exp $
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#75 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -3969,6 +3969,7 @@ const SG_PREFETCH_ADDR_MASK download
 const SG_SIZEOF download
 const PKT_OVERRUN_BUFOFFSET download
 const SCB_TRANSFER_SIZE        download
+const CACHELINE_MASK download
 
 /*
  * BIOS SCB offsets
index 464c342..b7a5b64 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.seq,v 1.15 2004/02/04 16:38:38 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.seq,v 1.6 2007/07/06 00:56:38 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic79xx.seq,v 1.16 2004/05/11 20:46:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx.seq,v 1.7 2007/07/06 02:23:31 pavalos Exp $
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#118 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -365,11 +365,11 @@ fill_qoutfifo:
        bmov    COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2;
        mvi     CCSCBCTL, CCSCBRESET;
        bmov    SCBHADDR, QOUTFIFO_NEXT_ADDR, 4;
+       mov     A, QOUTFIFO_NEXT_ADDR;
        bmov    SCBPTR, COMPLETE_SCB_HEAD, 2;
 fill_qoutfifo_loop:
        bmov    CCSCBRAM, SCBPTR, 2;
        mov     CCSCBRAM, SCB_SGPTR[0];
-       bmov    CCSCBRAM, ALLZEROS, 4;
        mov     CCSCBRAM, QOUTFIFO_ENTRY_VALID_TAG;
        mov     NONE, SDSCB_QOFF;
        inc     INT_COALESCING_CMDCOUNT;
@@ -378,6 +378,18 @@ fill_qoutfifo_loop:
        cmp     SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done;
        cmp     CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done;
        test    QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done;
+       /*
+        * Don't cross an ADB or Cachline boundary when DMA'ing
+        * completion entries.  In PCI mode, at least in 32/33
+        * configurations, the SCB DMA engine may lose its place
+        * in the data-stream should the target force a retry on
+        * something other than an 8byte aligned boundary. In
+        * PCI-X mode, we do this to avoid split transactions since
+        * many chipsets seem to be unable to format proper split
+        * completions to continue the data transfer.
+        */
+       add     SINDEX, A, CCSCBADDR;
+       test    SINDEX, CACHELINE_MASK jz fill_qoutfifo_done;
        bmov    SCBPTR, SCB_NEXT_COMPLETE, 2;
        jmp     fill_qoutfifo_loop;
 fill_qoutfifo_done:
index 3197d75..09b2d44 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#56 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#57 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_inline.h,v 1.14 2004/02/04 16:38:38 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx_inline.h,v 1.6 2007/07/06 00:56:38 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_inline.h,v 1.15 2004/05/11 20:46:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx_inline.h,v 1.7 2007/07/06 02:23:31 pavalos Exp $
  */
 
 #ifndef _AIC79XX_INLINE_H_
@@ -694,7 +694,7 @@ ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
         * Razor #528
         */
        value = ahd_inb(ahd, offset);
-       if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
+       if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
                ahd_inb(ahd, MODE_PTR);
        return (value);
 }
index c703cc7..fb647a2 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#86 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#88 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_pci.c,v 1.18 2004/02/04 16:38:38 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx_pci.c,v 1.10 2007/07/06 00:56:38 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic79xx_pci.c,v 1.19 2004/05/11 20:46:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic79xx_pci.c,v 1.11 2007/07/06 02:23:32 pavalos Exp $
  */
 
 #ifdef __linux__
@@ -84,6 +84,7 @@ ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
 #define ID_AHA_29320                   0x8012900500429005ull
 #define ID_AHA_29320B                  0x8013900500439005ull
 #define ID_AHA_39320_B                 0x8015900500409005ull
+#define ID_AHA_39320_B_DELL            0x8015900501681028ull
 #define ID_AHA_39320A                  0x8016900500409005ull
 #define ID_AHA_39320D                  0x8011900500419005ull
 #define ID_AHA_39320D_B                        0x801C900500419005ull
@@ -168,6 +169,12 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
                "Adaptec 39320 Ultra320 SCSI adapter",
                ahd_aic7902_setup
        },
+       {
+               ID_AHA_39320_B_DELL,
+               ID_ALL_MASK,
+               "Adaptec (Dell OEM) 39320 Ultra320 SCSI adapter",
+               ahd_aic7902_setup
+       },
        {
                ID_AHA_39320A,
                ID_ALL_MASK,
@@ -201,7 +208,7 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
        /* Generic chip probes for devices we don't know 'exactly' */
        {
                ID_AIC7901 & ID_9005_GENERIC_MASK,
-               ID_DEV_VENDOR_MASK,
+               ID_9005_GENERIC_MASK,
                "Adaptec AIC7901 Ultra320 SCSI adapter",
                ahd_aic7901_setup
        },