summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>2004-05-11 20:46:05 +0000
committergibbs <gibbs@FreeBSD.org>2004-05-11 20:46:05 +0000
commit1eb9cc823fb62418f30d4d1bbb7ef25e300dccf2 (patch)
tree9c8e741a56525645aa1ff9d83090825a9b713fde /sys
parentf18f582b8f08a49281d83af19ae29774fdffd1f9 (diff)
downloadFreeBSD-src-1eb9cc823fb62418f30d4d1bbb7ef25e300dccf2.zip
FreeBSD-src-1eb9cc823fb62418f30d4d1bbb7ef25e300dccf2.tar.gz
aic79xx.c:
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/aic7xxx/aic79xx.c191
-rw-r--r--sys/dev/aic7xxx/aic79xx.h3
-rw-r--r--sys/dev/aic7xxx/aic79xx.reg3
-rw-r--r--sys/dev/aic7xxx/aic79xx.seq16
-rw-r--r--sys/dev/aic7xxx/aic79xx_inline.h4
-rw-r--r--sys/dev/aic7xxx/aic79xx_pci.c11
6 files changed, 153 insertions, 75 deletions
diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c
index c615863..258cf19 100644
--- a/sys/dev/aic7xxx/aic79xx.c
+++ b/sys/dev/aic7xxx/aic79xx.c
@@ -37,7 +37,7 @@
* 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 $
*/
#ifdef __linux__
@@ -225,7 +225,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,
@@ -338,6 +338,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);
}
@@ -1543,9 +1551,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;
@@ -1561,26 +1566,35 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_setup_iocell_workaround(ahd);
ahd_unpause(ahd);
} else if ((status0 & OVERRUN) != 0) {
+
printf("%s: SCSI offset overrun detected. Resetting bus.\n",
ahd_name(ahd));
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
} else if ((status & SCSIRSTI) != 0) {
+
printf("%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) {
+
printf("%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);
@@ -1613,24 +1627,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) {
@@ -1638,6 +1655,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) {
/*
@@ -1662,6 +1683,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.
@@ -1700,6 +1724,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))
/*
@@ -3349,11 +3374,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++) {
@@ -5059,10 +5088,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))
@@ -6013,22 +6044,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) {
@@ -6288,7 +6303,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)
@@ -6338,6 +6354,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 */
@@ -7058,35 +7085,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
@@ -8480,13 +8493,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)
printf("%s: Downloading Sequencer Program...",
ahd_name(ahd));
-#if DOWNLOAD_CONST_COUNT != 7
+#if DOWNLOAD_CONST_COUNT != 8
#error "Download Const Mismatch"
#endif
/*
@@ -8522,6 +8536,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
@@ -8562,6 +8579,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;
@@ -9241,13 +9259,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;
}
@@ -9285,7 +9308,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
@@ -9381,20 +9405,55 @@ bus_reset:
ahd_unlock(ahd, &s);
}
-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);
printf("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);
+ printf("No other SCB worth waiting for...\n");
+ }
+
+ return (found != 0);
}
/**************************** Flexport Logic **********************************/
diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h
index ab07ad8..26c9100 100644
--- a/sys/dev/aic7xxx/aic79xx.h
+++ b/sys/dev/aic7xxx/aic79xx.h
@@ -37,7 +37,7 @@
* 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$
*/
@@ -1065,7 +1065,6 @@ struct ahd_completion
{
uint16_t tag;
uint8_t sg_status;
- uint8_t pad[4];
uint8_t valid_tag;
};
diff --git a/sys/dev/aic7xxx/aic79xx.reg b/sys/dev/aic7xxx/aic79xx.reg
index cff63d6..3a32047 100644
--- a/sys/dev/aic7xxx/aic79xx.reg
+++ b/sys/dev/aic7xxx/aic79xx.reg
@@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
-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
@@ -3968,6 +3968,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
diff --git a/sys/dev/aic7xxx/aic79xx.seq b/sys/dev/aic7xxx/aic79xx.seq
index 7bd3b41..bef1f9d 100644
--- a/sys/dev/aic7xxx/aic79xx.seq
+++ b/sys/dev/aic7xxx/aic79xx.seq
@@ -40,7 +40,7 @@
* $FreeBSD$
*/
-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_"
@@ -364,11 +364,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;
@@ -377,6 +377,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:
diff --git a/sys/dev/aic7xxx/aic79xx_inline.h b/sys/dev/aic7xxx/aic79xx_inline.h
index 80989ed..009ff25 100644
--- a/sys/dev/aic7xxx/aic79xx_inline.h
+++ b/sys/dev/aic7xxx/aic79xx_inline.h
@@ -37,7 +37,7 @@
* 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$
*/
@@ -693,7 +693,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);
}
diff --git a/sys/dev/aic7xxx/aic79xx_pci.c b/sys/dev/aic7xxx/aic79xx_pci.c
index ec5bd4c..afd4498 100644
--- a/sys/dev/aic7xxx/aic79xx_pci.c
+++ b/sys/dev/aic7xxx/aic79xx_pci.c
@@ -38,7 +38,7 @@
* 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 $
*/
#ifdef __linux__
@@ -83,6 +83,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 [] =
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,
"Adaptec 39320A Ultra320 SCSI adapter",
@@ -200,7 +207,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
},
OpenPOWER on IntegriCloud