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 @@ ...@@ -39,7 +39,7 @@
* *
* $FreeBSD$ * $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 * This file is processed by the aic7xxx_asm utility for use in assembling
...@@ -194,7 +194,8 @@ register SEQINTCODE { ...@@ -194,7 +194,8 @@ register SEQINTCODE {
TRACEPOINT1, TRACEPOINT1,
TRACEPOINT2, TRACEPOINT2,
TRACEPOINT3, TRACEPOINT3,
SAW_HWERR SAW_HWERR,
BAD_SCB_STATUS
} }
} }
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* $FreeBSD$ * $FreeBSD$
*/ */
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#90 $" VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd" PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_" PREFIX = "ahd_"
...@@ -175,12 +175,31 @@ END_CRITICAL; ...@@ -175,12 +175,31 @@ END_CRITICAL;
scbdma_tohost_done: scbdma_tohost_done:
test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
/* /*
* A complete SCB upload requires no intervention. * An SCB has been succesfully uploaded to the host.
* The SCB is already on the COMPLETE_SCB list * If the SCB was uploaded for some reason other than
* and its completion notification will now be * bad SCSI status (currently only for underruns), we
* handled just like any other SCB. * 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: fill_qoutfifo_dmadone:
and CCSCBCTL, ~(CCARREN|CCSCBEN); and CCSCBCTL, ~(CCARREN|CCSCBEN);
call qoutfifo_updated; call qoutfifo_updated;
...@@ -325,15 +344,7 @@ fetch_new_scb: ...@@ -325,15 +344,7 @@ fetch_new_scb:
dma_complete_scb: dma_complete_scb:
bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2; bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2;
bmov SCBHADDR, SCB_BUSADDR, 4; bmov SCBHADDR, SCB_BUSADDR, 4;
mvi CCARREN|CCSCBEN|CCSCBRESET call dma_scb; mvi CCARREN|CCSCBEN|CCSCBRESET jmp 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;
END_CRITICAL; END_CRITICAL;
/* /*
...@@ -1615,25 +1626,32 @@ export seq_isr: ...@@ -1615,25 +1626,32 @@ export seq_isr:
* and deffer the test by one instruction. * and deffer the test by one instruction.
*/ */
mov REG_ISR, LQISTAT2; mov REG_ISR, LQISTAT2;
test REG_ISR, LQIWORKONLQ jz data_valid; test REG_ISR, LQIWORKONLQ jz main_isr;
test SEQINTSRC, SAVEPTRS jz data_valid; test SEQINTSRC, SAVEPTRS jz main_isr;
test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo; 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); 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; 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; or DFCNTRL, SCSIEN;
/* FALLTHROUGH */ or SEQINTCTL, IRET ret;
snapshot_other_fifo:
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
/* FALLTHROUGH */
snapshot_saveptr: snapshot_saveptr:
mvi DFFSXFRCTL, CLRCHN; mvi DFFSXFRCTL, CLRCHN;
or SEQINTCTL, IRET ret; or SEQINTCTL, IRET ret;
data_valid: main_isr:
} }
test SEQINTSRC, CFG4DATA jnz cfg4data_intr; test SEQINTSRC, CFG4DATA jnz cfg4data_intr;
test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr;
...@@ -1666,10 +1684,11 @@ saveptr_active_fifo: ...@@ -1666,10 +1684,11 @@ saveptr_active_fifo:
or SEQINTCTL, IRET ret; or SEQINTCTL, IRET ret;
cfg4data_intr: cfg4data_intr:
inc SCB_FIFO_USE_COUNT; test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count;
test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun;
call load_first_seg; call load_first_seg;
call pkt_handle_xfer; call pkt_handle_xfer;
inc SCB_FIFO_USE_COUNT;
interrupt_return:
or SEQINTCTL, IRET ret; or SEQINTCTL, IRET ret;
cfg4istat_intr: cfg4istat_intr:
...@@ -1961,6 +1980,8 @@ illegal_phase: ...@@ -1961,6 +1980,8 @@ illegal_phase:
* data. Otherwise use an overrun buffer in the host to simulate * data. Otherwise use an overrun buffer in the host to simulate
* BITBUCKET. * BITBUCKET.
*/ */
pkt_handle_overrun_inc_use_count:
inc SCB_FIFO_USE_COUNT;
pkt_handle_overrun: pkt_handle_overrun:
SET_SEQINTCODE(CFG4OVERRUN) SET_SEQINTCODE(CFG4OVERRUN)
call freeze_queue; call freeze_queue;
...@@ -1987,8 +2008,8 @@ pkt_overrun_end: ...@@ -1987,8 +2008,8 @@ pkt_overrun_end:
or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID; or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;
test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
dec SCB_FIFO_USE_COUNT; dec SCB_FIFO_USE_COUNT;
test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
or LONGJMP_ADDR[1], INVALID_ADDR; or LONGJMP_ADDR[1], INVALID_ADDR;
test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
mvi DFFSXFRCTL, CLRCHN ret; mvi DFFSXFRCTL, CLRCHN ret;
if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#186 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#189 $
* *
* $FreeBSD$ * $FreeBSD$
*/ */
...@@ -556,6 +556,26 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ...@@ -556,6 +556,26 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_name(ahd), seqintcode); ahd_name(ahd), seqintcode);
#endif #endif
switch (seqintcode) { 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: case ENTERING_NONPACK:
{ {
struct scb *scb; struct scb *scb;
...@@ -7742,7 +7762,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) ...@@ -7742,7 +7762,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
{ {
struct hardware_scb *hscb; struct hardware_scb *hscb;
u_int qfreeze_cnt; u_int qfreeze_cnt;
u_int maxloops;
/* /*
* The sequencer freezes its select-out queue * The sequencer freezes its select-out queue
...@@ -7752,25 +7771,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) ...@@ -7752,25 +7771,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
*/ */
hscb = scb->hscb; 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. */ /* Freeze the queue until the client sees the error. */
ahd_freeze_devq(ahd, scb); ahd_freeze_devq(ahd, scb);
ahd_freeze_scb(scb); ahd_freeze_scb(scb);
...@@ -7784,7 +7784,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) ...@@ -7784,7 +7784,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
if (qfreeze_cnt == 0) if (qfreeze_cnt == 0)
ahd_outb(ahd, SEQ_FLAGS2, ahd_outb(ahd, SEQ_FLAGS2,
ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN); ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
ahd_unpause(ahd);
/* Don't want to clobber the original sense code */ /* Don't want to clobber the original sense code */
if ((scb->flags & SCB_SENSE) != 0) { if ((scb->flags & SCB_SENSE) != 0) {
/* /*
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#44 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#45 $
* *
* $FreeBSD$ * $FreeBSD$
*/ */
...@@ -223,7 +223,7 @@ ahd_unpause(struct ahd_softc *ahd) ...@@ -223,7 +223,7 @@ ahd_unpause(struct ahd_softc *ahd)
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 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_outb(ahd, HCNTRL, ahd->unpause);
ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
......
/* /*
* Adaptec AIC79xx device driver for Linux. * 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. * Copyright (c) 1994-2000 Justin T. Gibbs.
...@@ -2070,7 +2070,6 @@ aic79xx_setup(char *s) ...@@ -2070,7 +2070,6 @@ aic79xx_setup(char *s)
s = aic_parse_brace_option("tag_info", p + n, end, s = aic_parse_brace_option("tag_info", p + n, end,
2, ahd_linux_setup_tag_info, 0); 2, ahd_linux_setup_tag_info, 0);
} else if (strncmp(p, "rd_strm", n) == 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, s = aic_parse_brace_option("rd_strm", p + n, end,
1, ahd_linux_setup_rd_strm_info, 0); 1, ahd_linux_setup_rd_strm_info, 0);
} else if (strncmp(p, "dv", n) == 0) { } else if (strncmp(p, "dv", n) == 0) {
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated * DO NOT EDIT - This file is automatically generated
* from the following source files: * from the following source files:
* *
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#90 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#66 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
*/ */
typedef int (ahd_reg_print_t)(u_int, u_int *, u_int); typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
typedef struct ahd_reg_parse_entry { typedef struct ahd_reg_parse_entry {
...@@ -2360,6 +2360,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print; ...@@ -2360,6 +2360,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
#define SPLTINT 0x01 #define SPLTINT 0x01
#define SEQINTCODE 0x02 #define SEQINTCODE 0x02
#define BAD_SCB_STATUS 0x1a
#define SAW_HWERR 0x19 #define SAW_HWERR 0x19
#define TRACEPOINT3 0x18 #define TRACEPOINT3 0x18
#define TRACEPOINT2 0x17 #define TRACEPOINT2 0x17
...@@ -3767,5 +3768,5 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print; ...@@ -3767,5 +3768,5 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
/* Exported Labels */ /* Exported Labels */
#define LABEL_seq_isr 0x264 #define LABEL_seq_isr 0x270
#define LABEL_timer_isr 0x260 #define LABEL_timer_isr 0x26c
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* DO NOT EDIT - This file is automatically generated * DO NOT EDIT - This file is automatically generated
* from the following source files: * from the following source files:
* *
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#90 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#66 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
*/ */
#include "aic79xx_osm.h" #include "aic79xx_osm.h"
...@@ -65,13 +65,14 @@ static ahd_reg_parse_entry_t SEQINTCODE_parse_table[] = { ...@@ -65,13 +65,14 @@ static ahd_reg_parse_entry_t SEQINTCODE_parse_table[] = {
{ "TRACEPOINT1", 0x16, 0xff }, { "TRACEPOINT1", 0x16, 0xff },
{ "TRACEPOINT2", 0x17, 0xff }, { "TRACEPOINT2", 0x17, 0xff },
{ "TRACEPOINT3", 0x18, 0xff }, { "TRACEPOINT3", 0x18, 0xff },
{ "SAW_HWERR", 0x19, 0xff } { "SAW_HWERR", 0x19, 0xff },
{ "BAD_SCB_STATUS", 0x1a, 0xff }
}; };
int int
ahd_seqintcode_print(u_int regvalue, u_int *cur_col, u_int wrap) 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)); 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