Commit 955cf944 authored by Justin T. Gibbs's avatar Justin T. Gibbs

Aic79xx Driver Upate

 o Switch to handling bad SCSI status as a sequencer interrupt
   instead of having the kernel proccess these failures via
   the completion queue.  This is done because:

    - The old scheme required us to pause the sequencer and clear
      critical sections for each SCB.  It seems that these pause
      actions, if coincident with a sequencer FIFO interrupt, would
      result in a FIFO interrupt getting lost or directing to the
      wrong FIFO.  This caused hangs when the driver was stressed
      under high "queue full" loads.
    - The completion code assumed that it was always called with
      the sequencer running.  This may not be the case in timeout
      processing where completions occur manually via
      ahd_pause_and_flushwork().
    - With this scheme, the extra expense of clearing critical
      sections is avoided since the sequencer will only self pause
      once all pending selections have cleared and it is not in
      a critical section.
parent 0dba7c55
......@@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#66 $"
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
......@@ -194,7 +194,8 @@ register SEQINTCODE {
TRACEPOINT1,
TRACEPOINT2,
TRACEPOINT3,
SAW_HWERR
SAW_HWERR,
BAD_SCB_STATUS
}
}
......
......@@ -40,7 +40,7 @@
* $FreeBSD$
*/
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#90 $"
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_"
......@@ -175,12 +175,31 @@ END_CRITICAL;
scbdma_tohost_done:
test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
/*
* A complete SCB upload requires no intervention.
* The SCB is already on the COMPLETE_SCB list
* and its completion notification will now be
* handled just like any other SCB.
* An SCB has been succesfully uploaded to the host.
* If the SCB was uploaded for some reason other than
* bad SCSI status (currently only for underruns), we
* queue the SCB for normal completion. Otherwise, we
* wait until any select-out activity has halted, and
* then notify the host so that the transaction can be
* dealt with.
*/
and CCSCBCTL, ~(CCARREN|CCSCBEN) ret;
test SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host;
and CCSCBCTL, ~(CCARREN|CCSCBEN);
bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
scbdma_notify_host:
SET_MODE(M_SCSI, M_SCSI)
test SCSISEQ0, ENSELO jnz return;
test SSTAT0, (SELDO|SELINGO) jnz return;
SET_MODE(M_CCHAN, M_CCHAN)
/*
* Remove SCB and notify host.
*/
and CCSCBCTL, ~(CCARREN|CCSCBEN);
bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
SET_SEQINTCODE(BAD_SCB_STATUS)
ret;
fill_qoutfifo_dmadone:
and CCSCBCTL, ~(CCARREN|CCSCBEN);
call qoutfifo_updated;
......@@ -325,15 +344,7 @@ fetch_new_scb:
dma_complete_scb:
bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2;
bmov SCBHADDR, SCB_BUSADDR, 4;
mvi CCARREN|CCSCBEN|CCSCBRESET call dma_scb;
/*
* Now that we've started the DMA, push us onto
* the normal completion queue to have our SCBID
* posted to the kernel.
*/
bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
mvi CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb;
END_CRITICAL;
/*
......@@ -1615,25 +1626,32 @@ export seq_isr:
* 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 REG_ISR, LQIWORKONLQ jz main_isr;
test SEQINTSRC, SAVEPTRS jz main_isr;
test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo;
/*
* Switch to the active FIFO.
* Switch to the active FIFO after clearing the snapshot
* savepointer in the current FIFO. We do this so that
* a pending CTXTDONE or SAVEPTR is visible in the active
* FIFO. This status is the only way we can detect if we
* have lost the race (e.g. host paused us) and our attepts
* to disable the channel occurred after all REQs were
* already seen and acked (REQINIT never comes true).
*/
mvi DFFSXFRCTL, CLRCHN;
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
test DFCNTRL, DIRECTION jz snapshot_other_fifo;
test DFCNTRL, DIRECTION jz interrupt_return;
and DFCNTRL, ~SCSIEN;
test SSTAT1, REQINIT jz .;
snapshot_wait_data_valid:
test SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid;
test SSTAT1, REQINIT jz snapshot_wait_data_valid;
snapshot_data_valid:
or DFCNTRL, SCSIEN;
/* FALLTHROUGH */
snapshot_other_fifo:
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
/* FALLTHROUGH */
or SEQINTCTL, IRET ret;
snapshot_saveptr:
mvi DFFSXFRCTL, CLRCHN;
or SEQINTCTL, IRET ret;
data_valid:
main_isr:
}
test SEQINTSRC, CFG4DATA jnz cfg4data_intr;
test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr;
......@@ -1666,10 +1684,11 @@ saveptr_active_fifo:
or SEQINTCTL, IRET ret;
cfg4data_intr:
inc SCB_FIFO_USE_COUNT;
test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun;
test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count;
call load_first_seg;
call pkt_handle_xfer;
inc SCB_FIFO_USE_COUNT;
interrupt_return:
or SEQINTCTL, IRET ret;
cfg4istat_intr:
......@@ -1961,6 +1980,8 @@ illegal_phase:
* data. Otherwise use an overrun buffer in the host to simulate
* BITBUCKET.
*/
pkt_handle_overrun_inc_use_count:
inc SCB_FIFO_USE_COUNT;
pkt_handle_overrun:
SET_SEQINTCODE(CFG4OVERRUN)
call freeze_queue;
......@@ -1987,8 +2008,8 @@ pkt_overrun_end:
or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;
test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
dec SCB_FIFO_USE_COUNT;
test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
or LONGJMP_ADDR[1], INVALID_ADDR;
test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
mvi DFFSXFRCTL, CLRCHN ret;
if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
......
......@@ -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#186 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#189 $
*
* $FreeBSD$
*/
......@@ -556,6 +556,26 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_name(ahd), seqintcode);
#endif
switch (seqintcode) {
case BAD_SCB_STATUS:
{
struct scb *scb;
u_int scbid;
int cmds_pending;
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
if (scb != NULL) {
ahd_complete_scb(ahd, scb);
} else {
printf("%s: WARNING no command for scb %d "
"(bad status)\n", ahd_name(ahd), scbid);
ahd_dump_card_state(ahd);
}
cmds_pending = ahd_inw(ahd, CMDS_PENDING);
if (cmds_pending > 0)
ahd_outw(ahd, CMDS_PENDING, cmds_pending - 1);
break;
}
case ENTERING_NONPACK:
{
struct scb *scb;
......@@ -7742,7 +7762,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
{
struct hardware_scb *hscb;
u_int qfreeze_cnt;
u_int maxloops;
/*
* The sequencer freezes its select-out queue
......@@ -7752,25 +7771,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
*/
hscb = scb->hscb;
/*
* Wait until any pending selections have been processed.
*/
maxloops = 1000;
do {
ahd_pause(ahd);
ahd_clear_critical_section(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
if (((ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0
&& (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
|| (ahd_inb(ahd, SSTAT1) & SELTO) != 0)
break;
ahd_unpause(ahd);
ahd_delay(200);
} while (--maxloops);
if (maxloops == 0)
ahd_pause(ahd);
/* Freeze the queue until the client sees the error. */
ahd_freeze_devq(ahd, scb);
ahd_freeze_scb(scb);
......@@ -7784,7 +7784,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
if (qfreeze_cnt == 0)
ahd_outb(ahd, SEQ_FLAGS2,
ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
ahd_unpause(ahd);
/* Don't want to clobber the original sense code */
if ((scb->flags & SCB_SENSE) != 0) {
/*
......
......@@ -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#44 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#45 $
*
* $FreeBSD$
*/
......@@ -223,7 +223,7 @@ ahd_unpause(struct ahd_softc *ahd)
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
}
if ((ahd_inb(ahd, INTSTAT) & ~(SWTMINT | CMDCMPLT)) == 0)
if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
ahd_outb(ahd, HCNTRL, ahd->unpause);
ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
......
/*
* Adaptec AIC79xx device driver for Linux.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#154 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#155 $
*
* --------------------------------------------------------------------------
* Copyright (c) 1994-2000 Justin T. Gibbs.
......@@ -2070,7 +2070,6 @@ aic79xx_setup(char *s)
s = aic_parse_brace_option("tag_info", p + n, end,
2, ahd_linux_setup_tag_info, 0);
} else if (strncmp(p, "rd_strm", n) == 0) {
printf("Calling brace parse for %s\n", p);
s = aic_parse_brace_option("rd_strm", p + n, end,
1, ahd_linux_setup_rd_strm_info, 0);
} else if (strncmp(p, "dv", n) == 0) {
......
......@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated
* from the following source files:
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#90 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#66 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
*/
typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
typedef struct ahd_reg_parse_entry {
......@@ -2360,6 +2360,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SPLTINT 0x01
#define SEQINTCODE 0x02
#define BAD_SCB_STATUS 0x1a
#define SAW_HWERR 0x19
#define TRACEPOINT3 0x18
#define TRACEPOINT2 0x17
......@@ -3767,5 +3768,5 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
/* Exported Labels */
#define LABEL_seq_isr 0x264
#define LABEL_timer_isr 0x260
#define LABEL_seq_isr 0x270
#define LABEL_timer_isr 0x26c
......@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated
* from the following source files:
*
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#90 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#66 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
*/
#include "aic79xx_osm.h"
......@@ -65,13 +65,14 @@ static ahd_reg_parse_entry_t SEQINTCODE_parse_table[] = {
{ "TRACEPOINT1", 0x16, 0xff },
{ "TRACEPOINT2", 0x17, 0xff },
{ "TRACEPOINT3", 0x18, 0xff },
{ "SAW_HWERR", 0x19, 0xff }
{ "SAW_HWERR", 0x19, 0xff },
{ "BAD_SCB_STATUS", 0x1a, 0xff }
};
int
ahd_seqintcode_print(u_int regvalue, u_int *cur_col, u_int wrap)
{
return (ahd_print_register(SEQINTCODE_parse_table, 26, "SEQINTCODE",
return (ahd_print_register(SEQINTCODE_parse_table, 27, "SEQINTCODE",
0x02, regvalue, cur_col, wrap));
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment