aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>2003-02-27 23:23:16 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>2003-02-27 23:23:16 +0000
commitacae33b02968c2ba2aa711e3efb1c8fddd6172fb (patch)
tree72f08652ef857a214cfc88016f9e4127567b8d2e /sys/dev
parentaa1cd79b7f05f34ccdd322fd569db67ba35eb804 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/aic7xxx/aic79xx.c75
-rw-r--r--sys/dev/aic7xxx/aic79xx.h23
-rw-r--r--sys/dev/aic7xxx/aic79xx.reg19
-rw-r--r--sys/dev/aic7xxx/aic79xx.seq210
-rw-r--r--sys/dev/aic7xxx/aic79xx_inline.h4
-rw-r--r--sys/dev/aic7xxx/aic79xx_osm.c12
-rw-r--r--sys/dev/aic7xxx/aic79xx_pci.c21
7 files changed, 255 insertions, 109 deletions
diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c
index b3807a5fd5ca..ae0f62e5dd28 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#156 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#165 $
*
* $FreeBSD$
*/
@@ -1249,6 +1249,14 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_outb(ahd, CLRSINT3, status3);
} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
ahd_handle_lqiphase_error(ahd, lqistat1);
+ } else if ((lqistat1 & LQICRCI_NLQ) != 0) {
+ /*
+ * This status can be delayed during some
+ * streaming operations. The SCSIPHASE
+ * handler has already dealt with this case
+ * so just clear the error.
+ */
+ ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ);
} else if ((status & BUSFREE) != 0) {
u_int lqostat1;
int restart;
@@ -1627,23 +1635,24 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
if (scb == NULL)
panic("SCB not valid during LQOBUSFREE");
/*
- * Return the LQO manager to its idle loop. It will
- * not do this automatically if the busfree occurs
- * after the first REQ of either the LQ or command
- * packet or between the LQ and command packet.
- */
- ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE);
-
- /*
* Clear the status.
*/
ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE);
if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
ahd_outb(ahd, CLRLQOINT1, 0);
ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+ ahd_flush_device_writes(ahd);
ahd_outb(ahd, CLRSINT0, CLRSELDO);
/*
+ * Return the LQO manager to its idle loop. It will
+ * not do this automatically if the busfree occurs
+ * after the first REQ of either the LQ or command
+ * packet or between the LQ and command packet.
+ */
+ ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE);
+
+ /*
* Update the waiting for selection queue so
* we restart on the correct SCB.
*/
@@ -1653,9 +1662,9 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
ahd_outw(ahd, WAITING_TID_HEAD, scbid);
waiting_t = ahd_inw(ahd, WAITING_TID_TAIL);
- next = SCB_LIST_NULL;
if (waiting_t == waiting_h) {
ahd_outw(ahd, WAITING_TID_TAIL, scbid);
+ next = SCB_LIST_NULL;
} else {
ahd_set_scbptr(ahd, waiting_h);
next = ahd_inw(ahd, SCB_NEXT2);
@@ -1704,6 +1713,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
scb = ahd_lookup_scb(ahd, scbid);
ahd_print_path(ahd, scb);
printf("Unexpected PKT busfree condition\n");
+ ahd_dump_card_state(ahd);
ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A',
SCB_GET_LUN(scb), SCB_GET_TAG(scb),
ROLE_INITIATOR, CAM_UNEXP_BUSFREE);
@@ -4980,6 +4990,7 @@ ahd_reset(struct ahd_softc *ahd)
* to disturb the integrity of the bus.
*/
ahd_pause(ahd);
+ ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
sxfrctl1 = ahd_inb(ahd, SXFRCTL1);
cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
@@ -5028,13 +5039,13 @@ ahd_reset(struct ahd_softc *ahd)
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
cmd, /*bytes*/2);
}
- /* After a reset, we know the state of the mode register. */
- ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
- /* Determine chip configuration */
- ahd->features &= ~AHD_WIDE;
- if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0)
- ahd->features |= AHD_WIDE;
+ /*
+ * Mode should be SCSI after a chip reset, but lets
+ * set it just to be safe.
+ */
+ ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+ ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
/*
* Restore SXFRCTL1.
@@ -5047,9 +5058,14 @@ ahd_reset(struct ahd_softc *ahd)
ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN);
ahd_outb(ahd, SXFRCTL1, sxfrctl1);
+ /* Determine chip configuration */
+ ahd->features &= ~AHD_WIDE;
+ if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0)
+ ahd->features |= AHD_WIDE;
+
/*
* If a recovery action has forced a chip reset,
- * re-initialize the chip to our likeing.
+ * re-initialize the chip to our liking.
*/
if (ahd->init_level > 0)
ahd_chip_init(ahd);
@@ -5158,7 +5174,7 @@ ahd_init_scbdata(struct ahd_softc *ahd)
scb_data->init_level++;
/* DMA tag for our S/G structures. */
- if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
+ if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8,
/*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
@@ -6050,7 +6066,7 @@ ahd_chip_init(struct ahd_softc *ahd)
} else {
ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE);
}
- ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN);
+ ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS);
if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX)
/*
* Do not issue a target abort when a split completion
@@ -6341,7 +6357,7 @@ ahd_default_config(struct ahd_softc *ahd)
#else
tinfo->user.period = AHD_SYNCRATE_160;
#endif
- tinfo->user.offset= ~0;
+ tinfo->user.offset = MAX_OFFSET;
tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM
| MSG_EXT_PPR_WR_FLOW
| MSG_EXT_PPR_HOLD_MCS
@@ -6565,13 +6581,13 @@ ahd_enable_coalessing(struct ahd_softc *ahd, int enable)
void
ahd_pause_and_flushwork(struct ahd_softc *ahd)
{
- u_int intstat;
- u_int maxloops;
- int paused;
+ ahd_mode_state saved_modes;
+ u_int intstat;
+ u_int maxloops;
+ int paused;
maxloops = 1000;
ahd->flags |= AHD_ALL_INTERRUPTS;
- intstat = 0;
paused = FALSE;
do {
struct scb *waiting_scb;
@@ -6582,6 +6598,8 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd_pause(ahd);
paused = TRUE;
ahd_clear_critical_section(ahd);
+ saved_modes = ahd_save_modes(ahd);
+ 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);
@@ -6598,10 +6616,10 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd_outb(ahd, SCSISEQ0,
ahd_inb(ahd, SCSISEQ0) | ENSELO);
- if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0)
- break;
+ intstat = ahd_inb(ahd, INTSTAT);
} while (--maxloops
- && (((intstat = ahd_inb(ahd, INTSTAT)) & INT_PEND) != 0
+ && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
+ && ((intstat & INT_PEND) != 0
|| (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO))));
if (maxloops == 0) {
printf("Infinite interrupt loop, INTSTAT = %x",
@@ -6612,6 +6630,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd_platform_flushwork(ahd);
ahd->flags &= ~AHD_ALL_INTERRUPTS;
+ ahd_restore_modes(ahd, saved_modes);
}
int
@@ -8148,7 +8167,7 @@ ahd_loadseq(struct ahd_softc *ahd)
/* Start by aligning to the nearest cacheline. */
sg_prefetch_align = ahd->pci_cachesize;
if (sg_prefetch_align == 0)
- sg_prefetch_cnt = 8;
+ sg_prefetch_align = 8;
/* Round down to the nearest power of 2. */
while (powerof2(sg_prefetch_align) == 0)
sg_prefetch_align--;
diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h
index 64a97dc8f998..f1607f8f18cd 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#78 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#84 $
*
* $FreeBSD$
*/
@@ -309,7 +309,17 @@ typedef enum {
* Controller write to INTSTAT will lose to a host
* write to CLRINT.
*/
- AHD_INTCOLLISION_BUG = 0x100000
+ AHD_INTCOLLISION_BUG = 0x100000,
+ /*
+ * The GEM318 violates the SCSI spec by not waiting
+ * the mandated bus settle delay between phase changes
+ * in some situations. Some aic79xx chip revs. are more
+ * strict in this regard and will treat REQ assertions
+ * that fall within the bus settle delay window as
+ * glitches. This flag tells the firmware to tolerate
+ * early REQ assertions.
+ */
+ AHD_EARLY_REQ_BUG = 0x200000
} ahd_bug;
/*
@@ -404,14 +414,17 @@ struct target_status {
* Initiator mode SCB shared data area.
* If the embedded CDB is 12 bytes or less, we embed
* the sense buffer address in the SCB. This allows
- * us to retrieve sense information without interupting
+ * us to retrieve sense information without interrupting
* the host in packetized mode.
*/
typedef uint32_t sense_addr_t;
#define MAX_CDB_LEN 16
#define MAX_CDB_LEN_WITH_SENSE_ADDR (MAX_CDB_LEN - sizeof(sense_addr_t))
union initiator_data {
- uint64_t cdbptr;
+ struct {
+ uint64_t cdbptr;
+ uint8_t cdblen;
+ } cdb_from_host;
uint8_t cdb[MAX_CDB_LEN];
struct {
uint8_t cdb[MAX_CDB_LEN_WITH_SENSE_ADDR];
@@ -727,7 +740,7 @@ struct ahd_tmode_lstate;
#define AHD_WIDTH_UNKNOWN 0xFF
#define AHD_PERIOD_UNKNOWN 0xFF
-#define AHD_OFFSET_UNKNOWN 0x0
+#define AHD_OFFSET_UNKNOWN 0xFF
#define AHD_PPR_OPTS_UNKNOWN 0xFF
/*
diff --git a/sys/dev/aic7xxx/aic79xx.reg b/sys/dev/aic7xxx/aic79xx.reg
index 0138ca271031..65c527d7002b 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#60 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#64 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@@ -2071,14 +2071,14 @@ register LQIMODE1 {
address 0x051
access_mode RW
modes M_CFG
- field ENLQIPHASE_LQ 0x80
- field ENLQIPHASE_NLQ 0x40
+ field ENLQIPHASE_LQ 0x80 /* LQIPHASE1 */
+ field ENLQIPHASE_NLQ 0x40 /* LQIPHASE2 */
field ENLIQABORT 0x20
- field ENLQICRCI_LQ 0x10
- field ENLQICRCI_NLQ 0x08
+ field ENLQICRCI_LQ 0x10 /* LQICRCI1 */
+ field ENLQICRCI_NLQ 0x08 /* LQICRCI2 */
field ENLQIBADLQI 0x04
- field ENLQIOVERI_LQ 0x02
- field ENLQIOVERI_NLQ 0x01
+ field ENLQIOVERI_LQ 0x02 /* LQIOVERI1 */
+ field ENLQIOVERI_NLQ 0x01 /* LQIOVERI2 */
}
/*
@@ -3725,7 +3725,7 @@ scratch_ram {
/*
* The minimum number of commands still outstanding required
- * to continue coalessing (2's compliment of value).
+ * to continue coalessing (2's complement of value).
*/
INT_COALESSING_MINCMDS {
size 1
@@ -3769,16 +3769,17 @@ scb {
SCB_RESIDUAL_DATACNT {
size 4
alias SCB_CDB_STORE
+ alias SCB_HOST_CDB_PTR
}
SCB_RESIDUAL_SGPTR {
size 4
- alias SCB_CDB_PTR
field SG_ADDR_MASK 0xf8 /* In the last byte */
field SG_OVERRUN_RESID 0x02 /* In the first byte */
field SG_LIST_NULL 0x01 /* In the first byte */
}
SCB_SCSI_STATUS {
size 1
+ alias SCB_HOST_CDB_LEN
}
SCB_TARGET_PHASES {
size 1
diff --git a/sys/dev/aic7xxx/aic79xx.seq b/sys/dev/aic7xxx/aic79xx.seq
index 31cc29d9d4dd..3a772aad883a 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#78 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#88 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_"
@@ -122,22 +122,24 @@ gsfifo_complete_normally:
/*
* Since this status did not consume a FIFO, we have to
* be a bit more dilligent in how we check for FIFOs pertaining
- * to this transaction. There are three states that a FIFO still
+ * to this transaction. There are two states that a FIFO still
* transferring data may be in.
*
- * 1) Configured and draining to the host, with a pending CLRCHN.
- * 2) Configured and draining to the host, no pending CLRCHN.
- * 3) Pending cfg4data, fifo not empty.
+ * 1) Configured and draining to the host, with a FIFO handler.
+ * 2) Pending cfg4data, fifo not empty.
*
- * Cases 1 and 2 can be detected by noticing that a longjmp is
- * active for the FIFO and LONGJMP_SCB matches our SCB. In this
- * case, we allow the routine servicing the FIFO to complete the SCB.
+ * Case 1 can be detected by noticing that a longjmp is active for
+ * the FIFO and LONGJMP_SCB matches our SCB. In this case, we allow
+ * the routine servicing the FIFO to complete the SCB.
*
- * Case 3 implies either a pending or yet to occur save data
+ * Case 2 implies either a pending or yet to occur save data
* pointers for this same context in the other FIFO. So, if
- * we detect case 2, we will properly defer the post of the SCB
+ * we detect case 1, we will properly defer the post of the SCB
* and achieve the desired result. The pending cfg4data will
* notice that status has been received and complete the SCB.
+ *
+ * If the data-transfer has been completed, or no data transfer
+ * was needed for this SCB, it is safe to complete the command.
*/
test SCB_SGPTR, SG_LIST_NULL jz good_status_check_fifos;
/*
@@ -519,7 +521,7 @@ BEGIN_CRITICAL;
/*
* For packetized, the LQO manager clears ENSELO on
* the assertion of SELDO. If we are non-packetized,
- * LASTSCB and CURRSCB are acuate.
+ * LASTSCB and CURRSCB are accurate.
*/
test SCSISEQ0, ENSELO jnz use_lastscb;
@@ -706,7 +708,7 @@ SET_DST_MODE M_DFF1;
add NONE, -17, SCB_CDB_LEN;
jnc p_command_embedded;
p_command_from_host:
- bmov HADDR[0], SCB_CDB_PTR, 11;
+ bmov HADDR[0], SCB_HOST_CDB_PTR, 9;
mvi SG_CACHE_PRE, LAST_SEG;
mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
jmp p_command_xfer;
@@ -1030,14 +1032,6 @@ queue_arg1_scb_completion:
SET_MODE(M_SCSI, M_SCSI)
bmov SCBPTR, ARG_1, 2;
queue_scb_completion:
- if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) {
- /*
- * Set MK_MESSAGE to trigger an abort should this SCB
- * be referenced by a target even though it is not currently
- * active.
- */
- or SCB_CONTROL, MK_MESSAGE;
- }
test SCB_SCSI_STATUS,0xff jnz bad_status;
/*
* Check for residuals
@@ -1163,7 +1157,28 @@ clear_target_state:
mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
phase_lock:
- test SCSIPHASE, 0xFF jz .;
+ if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) {
+ /*
+ * Don't ignore persistent REQ assertions just because
+ * they were asserted within the bus settle delay window.
+ * This allows us to tolerate devices like the GEM318
+ * that violate the SCSI spec. We are careful not to
+ * count REQ while we are waiting for it to fall during
+ * an async phase due to our asserted ACK. Each
+ * sequencer instruction takes ~25ns, so the REQ must
+ * last at least 100ns in order to be counted as a true
+ * REQ.
+ */
+ test SCSIPHASE, 0xFF jnz phase_locked;
+ test SCSISIGI, ACKI jnz phase_lock;
+ test SCSISIGI, REQI jz phase_lock;
+ test SCSIPHASE, 0xFF jnz phase_locked;
+ test SCSISIGI, ACKI jnz phase_lock;
+ test SCSISIGI, REQI jz phase_lock;
+phase_locked:
+ } else {
+ test SCSIPHASE, 0xFF jz .;
+ }
test SSTAT1, SCSIPERR jnz phase_lock;
phase_lock_latch_phase:
and LASTPHASE, PHASE_MASK, SCSISIGI ret;
@@ -1247,7 +1262,7 @@ service_fifo:
nop;
}
and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
- mvi CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET;
+ mvi CCSGCTL, CCSGEN|CCSGRESET;
or SG_STATE, FETCH_INPROG ret;
idle_sgfetch_complete:
/*
@@ -1261,6 +1276,15 @@ idle_sgfetch_complete:
idle_sg_avail:
/* Does the hardware have space for another SG entry? */
test DFSTATUS, PRELOAD_AVAIL jz return;
+ /*
+ * On the A, preloading a segment before HDMAENACK
+ * comes true can clobber the shaddow address of the
+ * first segment in the S/G FIFO. Wait until it is
+ * safe to proceed.
+ */
+ if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) {
+ test DFCNTRL, HDMAENACK jz return;
+ }
if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
bmov HADDR, CCSGRAM, 8;
} else {
@@ -1290,22 +1314,12 @@ sg_advance:
or SINDEX, LAST_SEG;
clr SG_STATE;
mov SG_CACHE_PRE, SINDEX;
- /*
- * Load the segment. Or in HDMAEN here too
- * just in case HDMAENACK has not come true
- * by the time this segment is loaded. If
- * HDMAENACK is not true, this or will disable
- * HDMAEN mid-transfer. We do not want to simply
- * mvi our original settings as SCSIEN automatically
- * de-asserts and we don't want to accidentally
- * re-enable it.
- */
if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {
/*
* Use SCSIENWRDIS so that SCSIEN is never
* modified by this operation.
*/
- or DFCNTRL, PRELOADEN|SCSIENWRDIS|HDMAEN;
+ or DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS;
} else {
or DFCNTRL, PRELOADEN|HDMAEN;
}
@@ -1510,12 +1524,6 @@ data_phase_done:
* the idle loop and there is no need to perform
* any fixups.
*/
-calc_residual:
- test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg;
- /* Record if we've consumed all S/G entries */
- test MDFFSTAT, SHVALID jz . + 2;
- bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
- or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;
residual_before_last_seg:
test MDFFSTAT, SHVALID jnz sgptr_fixup;
/*
@@ -1525,7 +1533,13 @@ residual_before_last_seg:
*/
call idle_loop_service_fifos;
RESTORE_MODE(SAVED_MODE)
- jmp calc_residual;
+ /* FALLTHROUGH */
+calc_residual:
+ test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg;
+ /* Record if we've consumed all S/G entries */
+ test MDFFSTAT, SHVALID jz . + 2;
+ bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
+ or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;
sgptr_fixup:
/*
@@ -1570,7 +1584,51 @@ export timer_isr:
}
export seq_isr:
- nop; /* Jumps in the first ISR instruction fail on Rev A. */
+ if ((ahd->features & AHD_RTI) == 0) {
+ /*
+ * On RevA Silicon, if the target returns us to data-out
+ * after we have already trained for data-out, it is
+ * possible for us to transition the free running clock to
+ * data-valid before the required 100ns P1 setup time (8 P1
+ * assertions in fast-160 mode). This will only happen if
+ * this L-Q is a continuation of a data transfer for which
+ * we have already prefetched data into our FIFO (LQ/Data
+ * followed by LQ/Data for the same write transaction).
+ * This can cause some target implementations to miss the
+ * first few data transfers on the bus. We detect this
+ * situation by noticing that this is the first data transfer
+ * after an LQ (LQIWORKONLQ true), that the data transfer is
+ * a continuation of a transfer already setup in our FIFO
+ * (SAVEPTRS interrupt), and that the transaction is a write
+ * (DIRECTION set in DFCNTRL). The delay is performed by
+ * disabling SCSIEN until we see the first REQ from the
+ * target.
+ *
+ * First instruction in an ISR cannot be a branch on
+ * Rev A. Snapshot LQISTAT2 so the status is not missed
+ * and deffer the test by one instruction.
+ */
+ mov REG_ISR, LQISTAT2;
+ test REG_ISR, LQIWORKONLQ jz data_valid;
+ test SEQINTSRC, SAVEPTRS jz data_valid;
+ test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo;
+ /*
+ * Switch to the active FIFO.
+ */
+ xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+ test DFCNTRL, DIRECTION jz snapshot_other_fifo;
+ and DFCNTRL, ~SCSIEN;
+ test SSTAT1, REQINIT jz .;
+ or DFCNTRL, SCSIEN;
+ /* FALLTHROUGH */
+snapshot_other_fifo:
+ xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+ /* FALLTHROUGH */
+snapshot_saveptr:
+ mvi DFFSXFRCTL, CLRCHN;
+ or SEQINTCTL, IRET ret;
+data_valid:
+ }
test SEQINTSRC, CFG4DATA jnz cfg4data_intr;
test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr;
test SEQINTSRC, SAVEPTRS jnz saveptr_intr;
@@ -1583,21 +1641,23 @@ export seq_isr:
* active and contains a snapshot of the current poniter information.
* This happens between packets in a stream for a single L_Q. Since we
* are not performing a pointer save, we can safely clear the channel
- * so it can be used for other transactions.
+ * so it can be used for other transactions. On RTI capable controllers,
+ * where snapshots can, and are, disabled, the code to handle this type
+ * of snapshot is not active.
*
* The second case is a save pointers on an active FIFO which occurs
- * if the target changes to a new L_Q or busfrees/QAS' and the transfer
+ * if the target changes to a new L_Q or busfrees/QASes and the transfer
* has a residual. This should occur coincident with a ctxtdone. We
* disable the interrupt and allow our active routine to handle the
* save.
*/
saveptr_intr:
- test DFCNTRL, HDMAENACK jz snapshot_saveptr;
+ if ((ahd->features & AHD_RTI) == 0) {
+ test LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr;
+ }
+saveptr_active_fifo:
and SEQIMODE, ~ENSAVEPTRS;
or SEQINTCTL, IRET ret;
-snapshot_saveptr:
- mvi DFFSXFRCTL, CLRCHN;
- or SEQINTCTL, IRET ret;
cfg4data_intr:
test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun;
@@ -1633,6 +1693,18 @@ cfg4istat_no_taskmgmt_func:
call pkt_handle_status;
or SEQINTCTL, IRET ret;
+cfg4icmd_intr:
+ /*
+ * In the case of DMAing a CDB from the host, the normal
+ * CDB buffer is formatted with an 8 byte address followed
+ * by a 1 byte count.
+ */
+ bmov HADDR[0], SCB_HOST_CDB_PTR, 9;
+ mvi SG_CACHE_PRE, LAST_SEG;
+ mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
+ call pkt_handle_cdb;
+ or SEQINTCTL, IRET ret;
+
/*
* See if the target has gone on in this context creating an
* overrun condition. For the write case, the hardware cannot
@@ -1672,7 +1744,7 @@ pkt_service_fifo:
pkt_last_seg:
call setjmp;
test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs;
- test SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_done;
+ test SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_xfer_done;
test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2;
test SCSISIGO, ATNO jnz . + 2;
test SSTAT2, NONPACKREQ jz return;
@@ -1716,7 +1788,7 @@ pkt_saveptrs_clrchn:
mvi DFFSXFRCTL, CLRCHN ret;
END_CRITICAL;
-last_pkt_done:
+last_pkt_xfer_done:
BEGIN_CRITICAL;
if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
or DFCNTRL, FIFOFLUSH;
@@ -1765,13 +1837,15 @@ BEGIN_CRITICAL;
mvi DFFSXFRCTL, CLRCHN ret;
END_CRITICAL;
-check_status_overrun:
- test SHCNT[2], 0xFF jz status_IU_done;
- SET_SEQINTCODE(STATUS_OVERRUN)
- jmp status_IU_done;
+/*
+ * Watch over the status transfer. Our host sense buffer is
+ * large enough to take the maximum allowed status packet.
+ * None-the-less, we must still catch and report overruns to
+ * the host.
+ */
pkt_handle_status:
call setjmp_setscb;
- test MDFFSTAT, LASTSDONE jnz check_status_overrun;
+ test SG_CACHE_SHADOW, LAST_SEG_DONE jz check_status_overrun;
test SEQINTSRC, CTXTDONE jz return;
status_IU_done:
BEGIN_CRITICAL;
@@ -1783,6 +1857,21 @@ BEGIN_CRITICAL;
or SCB_CONTROL, STATUS_RCVD;
jmp last_pkt_complete;
END_CRITICAL;
+check_status_overrun:
+ /*
+ * We've filled the entire sense buffer.
+ * Wait for either context done or a negative
+ * shaddow count. If the context completes without
+ * causing the shaddow count to go negative, then
+ * this was a successful transfer up to the status
+ * limit. Otherwise we report the error.
+ */
+ test SHCNT[2], 0xFF jnz report_status_overrun;
+ test SEQINTSRC, CTXTDONE jz return;
+ test SHCNT[2], 0xFF jz status_IU_done;
+report_status_overrun:
+ SET_SEQINTCODE(STATUS_OVERRUN)
+ jmp status_IU_done;
SET_SRC_MODE M_DFF0;
SET_DST_MODE M_DFF0;
@@ -1797,6 +1886,16 @@ check_fifo:
END_CRITICAL;
/*
+ * Must wait until CDB xfer is over before issuing the
+ * clear channel.
+ */
+pkt_handle_cdb:
+ call setjmp_setscb;
+ test SG_CACHE_SHADOW, LAST_SEG_DONE jz return;
+ or LONGJMP_ADDR[1], INVALID_ADDR;
+ mvi DFFSXFRCTL, CLRCHN ret;
+
+/*
* Nonpackreq is a polled status. It can come true in three situations:
* we have received an L_Q, we have sent one or more L_Qs, or there is no
* L_Q context associated with this REQ (REQ occurs immediately after a
@@ -1865,6 +1964,7 @@ pkt_overrun_end:
or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;
test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
test SCB_CONTROL, STATUS_RCVD jnz last_pkt_queue_scb;
+ or LONGJMP_ADDR[1], INVALID_ADDR;
mvi DFFSXFRCTL, CLRCHN ret;
if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
@@ -1885,5 +1985,3 @@ load_overrun_buf:
mvi HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF);
clr HCNT[2] ret;
}
-
-cfg4icmd_intr:
diff --git a/sys/dev/aic7xxx/aic79xx_inline.h b/sys/dev/aic7xxx/aic79xx_inline.h
index e41701472bfc..d5963ce92f36 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#41 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#43 $
*
* $FreeBSD$
*/
@@ -769,7 +769,7 @@ ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
ahd_setup_scb_common(ahd, scb);
/*
- * Make sure our data is consistant from the
+ * Make sure our data is consistent from the
* perspective of the adapter.
*/
ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
diff --git a/sys/dev/aic7xxx/aic79xx_osm.c b/sys/dev/aic7xxx/aic79xx_osm.c
index 7e4a8d9f0686..365375eda8e4 100644
--- a/sys/dev/aic7xxx/aic79xx_osm.c
+++ b/sys/dev/aic7xxx/aic79xx_osm.c
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#25 $
+ * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#26 $
*
* $FreeBSD$
*/
@@ -1188,6 +1188,11 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
&& (ccb_h->flags & CAM_CDB_PHYS) == 0) {
u_long s;
+ /*
+ * Should CAM start to support CDB sizes
+ * greater than 16 bytes, we could use
+ * the sense buffer to store the CDB.
+ */
ahd_set_transaction_status(scb,
CAM_REQ_INVALID);
ahd_lock(ahd, &s);
@@ -1197,8 +1202,11 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
return;
}
if ((ccb_h->flags & CAM_CDB_PHYS) != 0) {
- hscb->shared_data.idata.cdbptr =
+ hscb->shared_data.idata.cdb_from_host.cdbptr =
ahd_htole64((uintptr_t)csio->cdb_io.cdb_ptr);
+ hscb->shared_data.idata.cdb_from_host.cdblen =
+ csio->cdb_len;
+ hscb->cdb_len |= SCB_CDB_LEN_PTR;
} else {
memcpy(hscb->shared_data.idata.cdb,
csio->cdb_io.cdb_ptr,
diff --git a/sys/dev/aic7xxx/aic79xx_pci.c b/sys/dev/aic7xxx/aic79xx_pci.c
index 79b1a172d6be..4869afbece0c 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#61 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#66 $
*
* $FreeBSD$
*/
@@ -80,6 +80,7 @@ ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define ID_AIC7902_B 0x801D9005FFFF9005ull
#define ID_AIC7902_B_IROC 0x809D9005FFFF9005ull
#define ID_AHA_39320 0x8010900500409005ull
+#define ID_AHA_39320A 0x8016900500409005ull
#define ID_AHA_39320D 0x8011900500419005ull
#define ID_AHA_39320D_B 0x801C900500419005ull
#define ID_AHA_39320D_HP 0x8011900500AC0E11ull
@@ -138,6 +139,12 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
ahd_aic7902_setup
},
{
+ ID_AHA_39320A,
+ ID_ALL_MASK,
+ "Adaptec 39320A Ultra320 SCSI adapter",
+ ahd_aic7902_setup
+ },
+ {
ID_AHA_39320D,
ID_ALL_MASK,
"Adaptec 39320D Ultra320 SCSI adapter",
@@ -691,14 +698,14 @@ static const char *pci_status_source[] =
static const char *split_status_strings[] =
{
- "%s: Received split response in %s.\n"
+ "%s: Received split response in %s.\n",
"%s: Received split completion error message in %s\n",
"%s: Receive overrun in %s\n",
"%s: Count not complete in %s\n",
"%s: Split completion data bucket in %s\n",
"%s: Split completion address error in %s\n",
"%s: Split completion byte count error in %s\n",
- "%s: Signaled Target-abort to early terminate a split in %s\n",
+ "%s: Signaled Target-abort to early terminate a split in %s\n"
};
static const char *pci_status_strings[] =
@@ -740,7 +747,7 @@ ahd_pci_intr(struct ahd_softc *ahd)
if (i == 5)
continue;
pci_status[i] = ahd_inb(ahd, reg);
- /* Clear latched errors. So our interupt deasserts. */
+ /* Clear latched errors. So our interrupt deasserts. */
ahd_outb(ahd, reg, pci_status[i]);
}
@@ -796,14 +803,14 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0);
split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1);
- /* Clear latched errors. So our interupt deasserts. */
+ /* Clear latched errors. So our interrupt deasserts. */
ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]);
ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]);
if (i != 0)
continue;
sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0);
sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1);
- /* Clear latched errors. So our interupt deasserts. */
+ /* Clear latched errors. So our interrupt deasserts. */
ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]);
ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]);
}
@@ -898,7 +905,7 @@ ahd_aic7902_setup(struct ahd_softc *ahd)
ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS
| AHD_NEW_DFCNTRL_OPTS;
ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_ABORT_LQI_BUG
- | AHD_INTCOLLISION_BUG;
+ | AHD_INTCOLLISION_BUG|AHD_EARLY_REQ_BUG;
/*
* IO Cell paramter setup.