patch-2.4.0-test2 linux/drivers/scsi/sym53c8xx.c
Next file: linux/drivers/scsi/sym53c8xx_comm.h
Previous file: linux/drivers/scsi/st.c
Back to the patch index
Back to the overall index
- Lines: 3425
- Date:
Mon Jun 19 17:59:42 2000
- Orig file:
v2.4.0-test1/linux/drivers/scsi/sym53c8xx.c
- Orig date:
Wed Apr 26 16:34:08 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
@@ -55,7 +55,7 @@
*/
/*
-** April 24 2000, sym53c8xx 1.5m
+** May 11 2000, sym53c8xx 1.6b
**
** Supported SCSI features:
** Synchronous data transfers
@@ -73,7 +73,10 @@
** 53C895 (Wide, Fast 40, on-board rom BIOS)
** 53C895A (Wide, Fast 40, on-board rom BIOS)
** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS)
+** 53C897 (Wide, Fast 40 Dual, on-board rom BIOS)
** 53C1510D (Wide, Fast 40 Dual, on-board rom BIOS)
+** 53C1010 (Wide, Fast 80 Dual, on-board rom BIOS)
+** 53C1010_66(Wide, Fast 80 Dual, on-board rom BIOS, 33/66MHz PCI)
**
** Other features:
** Memory mapped IO
@@ -84,7 +87,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5m"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.6b"
/* #define DEBUG_896R1 */
#define SCSI_NCR_OPTIMIZE_896
@@ -174,6 +177,14 @@
#include "sym53c8xx.h"
+/*
+** Donnot compile integrity checking code for Linux-2.3.0
+** and above since SCSI data structures are not ready yet.
+*/
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0)
+#define SCSI_NCR_INTEGRITY_CHECKING
+#endif
+
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
@@ -606,6 +617,7 @@
#define DEBUG_TIMING (0x0100)
#define DEBUG_NEGO (0x0200)
#define DEBUG_TAGS (0x0400)
+#define DEBUG_IC (0x0800)
/*
** Enable/Disable debug messages.
@@ -1654,6 +1666,8 @@
#define XE_EXTRA_DATA (1) /* unexpected data phase */
#define XE_BAD_PHASE (2) /* illegal phase (4/5) */
#define XE_PARITY_ERR (4) /* unrecovered SCSI parity error */
+#define XE_SODL_UNRUN (1<<3)
+#define XE_SWIDE_OVRUN (1<<4)
/*==========================================================
**
@@ -1663,8 +1677,10 @@
**==========================================================
*/
+#define NS_NOCHANGE (0)
#define NS_SYNC (1)
#define NS_WIDE (2)
+#define NS_PPR (4)
/*==========================================================
**
@@ -1819,7 +1835,7 @@
/*----------------------------------------------------------------
** negotiation of wide and synch transfer and device quirks.
- ** sval and wval are read from SCRIPTS and so have alignment
+ ** sval, wval and uval are read from SCRIPTS and so have alignment
** constraints.
**----------------------------------------------------------------
*/
@@ -1830,6 +1846,15 @@
/*1*/ u_char quirks;
/*2*/ u_char widedone;
/*3*/ u_char wval;
+/*0*/ u_char uval;
+
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ u_char ic_min_sync;
+ u_char ic_max_width;
+ u_char ic_done;
+#endif
+ u_char ic_maximums_set;
+ u_char ppr_negotiation;
/*----------------------------------------------------------------
** User settable limits and options.
@@ -1838,8 +1863,8 @@
*/
u_char usrsync;
u_char usrwide;
- u_char usrflag;
u_short usrtags;
+ u_char usrflag;
};
/*========================================================================
@@ -2049,6 +2074,7 @@
#define HF_AUTO_SENSE (1u<<4)
#define HF_DATA_IN (1u<<5)
#define HF_PM_TO_C (1u<<6)
+#define HF_EXT_ERR (1u<<7)
#ifdef SCSI_NCR_IARB_SUPPORT
#define HF_HINT_IARB (1u<<7)
@@ -2106,6 +2132,7 @@
struct scr_tblmove smsg_ext ;
struct scr_tblmove cmd ;
struct scr_tblmove sense ;
+ struct scr_tblmove wresid;
struct scr_tblmove data [MAX_SCATTER];
/*
@@ -2269,7 +2296,7 @@
**----------------------------------------------------------------
*/
u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
- sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1;
+ sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1, sv_scntl4;
/*----------------------------------------------------------------
** Actual initial value of IO register bits used by the
@@ -2278,7 +2305,7 @@
**----------------------------------------------------------------
*/
u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4,
- rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1;
+ rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4;
/*----------------------------------------------------------------
** Target data.
@@ -2393,8 +2420,8 @@
** written with a script command.
**----------------------------------------------------------------
*/
- u_char msgout[8]; /* Buffer for MESSAGE OUT */
- u_char msgin [8]; /* Buffer for MESSAGE IN */
+ u_char msgout[12]; /* Buffer for MESSAGE OUT */
+ u_char msgin [12]; /* Buffer for MESSAGE IN */
u_int32 lastmsg; /* Last SCSI message sent */
u_char scratch; /* Scratch for SCSI receive */
@@ -2466,6 +2493,17 @@
*/
struct usrcmd user; /* Command from user */
u_char release_stage; /* Synchronisation stage on release */
+
+ /*----------------------------------------------------------------
+ ** Fields that are used (primarily) for integrity check
+ **----------------------------------------------------------------
+ */
+ unsigned char check_integrity; /* Enable midlayer integ. check on
+ * bus scan. */
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ unsigned char check_integ_par; /* Set if par or Init. Det. error
+ * used only during integ check */
+#endif
};
#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl))
@@ -2511,20 +2549,20 @@
ncrcmd select2 [ 2];
#endif
ncrcmd command [ 2];
- ncrcmd dispatch [ 28];
+ ncrcmd dispatch [ 30];
ncrcmd sel_no_cmd [ 10];
ncrcmd init [ 6];
ncrcmd clrack [ 4];
- ncrcmd disp_msg_in [ 2];
ncrcmd disp_status [ 4];
- ncrcmd datai_done [ 16];
- ncrcmd datao_done [ 10];
+ ncrcmd datai_done [ 26];
+ ncrcmd datao_done [ 12];
ncrcmd ign_i_w_r_msg [ 4];
#ifdef SCSI_NCR_PROFILE_SUPPORT
- ncrcmd dataphase [ 4];
+ ncrcmd datai_phase [ 4];
#else
- ncrcmd dataphase [ 2];
+ ncrcmd datai_phase [ 2];
#endif
+ ncrcmd datao_phase [ 4];
ncrcmd msg_in [ 2];
ncrcmd msg_in2 [ 10];
#ifdef SCSI_NCR_IARB_SUPPORT
@@ -2562,16 +2600,17 @@
ncrcmd ungetjob [ 4];
#endif
ncrcmd reselect [ 4];
- ncrcmd reselected [ 48];
+ ncrcmd reselected [ 20];
+ ncrcmd resel_scntl4 [ 30];
#if MAX_TASKS*4 > 512
- ncrcmd resel_tag [ 16];
+ ncrcmd resel_tag [ 18];
#elif MAX_TASKS*4 > 256
- ncrcmd resel_tag [ 10];
+ ncrcmd resel_tag [ 12];
#else
- ncrcmd resel_tag [ 6];
+ ncrcmd resel_tag [ 8];
#endif
ncrcmd resel_go [ 6];
- ncrcmd resel_notag [ 4];
+ ncrcmd resel_notag [ 2];
ncrcmd resel_dsa [ 8];
ncrcmd data_in [MAX_SCATTER * SCR_SG_SIZE];
ncrcmd data_in2 [ 4];
@@ -2591,6 +2630,7 @@
*/
struct scripth {
ncrcmd start64 [ 2];
+ ncrcmd no_data [ 2];
ncrcmd sel_for_abort [ 18];
ncrcmd sel_for_abort_1 [ 2];
ncrcmd select_no_atn [ 8];
@@ -2608,11 +2648,13 @@
ncrcmd send_wdtr [ 4];
ncrcmd sdtr_resp [ 6];
ncrcmd send_sdtr [ 4];
+ ncrcmd ppr_resp [ 6];
+ ncrcmd send_ppr [ 4];
ncrcmd nego_bad_phase [ 4];
- ncrcmd msg_out_abort [ 12];
- ncrcmd msg_out [ 6];
+ ncrcmd msg_out [ 4];
ncrcmd msg_out_done [ 4];
- ncrcmd no_data [ 28];
+ ncrcmd data_ovrun [ 18];
+ ncrcmd data_ovrun1 [ 20];
ncrcmd abort_resel [ 16];
ncrcmd resend_ident [ 4];
ncrcmd ident_break [ 4];
@@ -2621,7 +2663,7 @@
ncrcmd data_io [ 2];
ncrcmd data_io_com [ 8];
ncrcmd data_io_out [ 12];
- ncrcmd bad_identify [ 12];
+ ncrcmd resel_bad_lun [ 4];
ncrcmd bad_i_t_l [ 4];
ncrcmd bad_i_t_l_q [ 4];
ncrcmd bad_status [ 6];
@@ -2632,14 +2674,13 @@
ncrcmd pm0_save [ 14];
ncrcmd pm1_save [ 14];
- /* SWIDE handling */
- ncrcmd swide_ma_32 [ 4];
- ncrcmd swide_ma_64 [ 6];
- ncrcmd swide_scr_64 [ 26];
- ncrcmd swide_scr_64_1 [ 12];
- ncrcmd swide_com_64 [ 6];
- ncrcmd swide_common [ 10];
- ncrcmd swide_fin_32 [ 24];
+ /* WSR handling */
+#ifdef SYM_DEBUG_PM_WITH_WSR
+ ncrcmd pm_wsr_handle [ 44];
+#else
+ ncrcmd pm_wsr_handle [ 42];
+#endif
+ ncrcmd wsr_ma_helper [ 4];
/* Data area */
ncrcmd zero [ 1];
@@ -2697,6 +2738,9 @@
static void ncr_int_udc (ncb_p np);
static void ncr_negotiate (ncb_p np, tcb_p tp);
static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
+#endif
#ifdef SCSI_NCR_PROFILE_SUPPORT
static void ncb_profile (ncb_p np, ccb_p cp);
#endif
@@ -2706,9 +2750,12 @@
static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
-static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer);
+static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, u_char *offset, u_char *width);
+static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4);
+static void ncr_set_sync_wide_status (ncb_p np, u_char target);
static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln);
static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack);
+static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4, u_char wide);
static int ncr_show_msg (u_char * msg);
static void ncr_print_msg (ccb_p cp, char *label, u_char * msg);
static int ncr_snooptest (ncb_p np);
@@ -2978,9 +3025,9 @@
SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
PADDR (msg_in),
SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
- PADDR (dataphase),
+ PADDR (datao_phase),
SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
- PADDR (dataphase),
+ PADDR (datai_phase),
SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
PADDR (status),
SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
@@ -2988,6 +3035,12 @@
SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
PADDRH (msg_out),
/*
+ * Set the extended error flag.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR),
+ 0,
+
+ /*
** Discard one illegal phase byte, if required.
*/
SCR_LOAD_REL (scratcha, 1),
@@ -3056,17 +3109,6 @@
SCR_JUMP,
PADDR (dispatch),
-}/*-------------------------< DISP_MSG_IN >----------------------*/,{
- /*
- ** Anticipate MSG_IN phase then STATUS phase.
- **
- ** May spare 2 SCRIPTS instructions when we have
- ** completed the OUTPUT of the data and the device
- ** goes directly to STATUS phase.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR (msg_in),
-
}/*-------------------------< DISP_STATUS >----------------------*/,{
/*
** Anticipate STATUS phase.
@@ -3081,6 +3123,12 @@
}/*-------------------------< DATAI_DONE >-------------------*/,{
/*
+ * If the device wants us to send more data,
+ * we must count the extra bytes.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)),
+ PADDRH (data_ovrun),
+ /*
** If the SWIDE is not full, jump to dispatcher.
** We anticipate a STATUS phase.
** If we get later an IGNORE WIDE RESIDUE, we
@@ -3097,36 +3145,56 @@
SCR_REG_REG (scntl2, SCR_OR, WSR),
0,
/*
- ** Since the device is required to send any
- ** IGNORE WIDE RESIDUE message prior to any
- ** other information, we just snoop the SCSI
- ** BUS to check for such a message.
+ * We are expecting an IGNORE RESIDUE message
+ * from the device, otherwise we are in data
+ * overrun condition. Check against MSG_IN phase.
*/
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ SIR_SWIDE_OVERRUN,
SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
PADDR (disp_status),
- SCR_FROM_REG (sbdl),
- 0,
+ /*
+ * We are in MSG_IN phase,
+ * Read the first byte of the message.
+ * If it is not an IGNORE RESIDUE message,
+ * signal overrun and jump to message
+ * processing.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[0]),
+ SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ SIR_SWIDE_OVERRUN,
SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
- PADDR (disp_status),
+ PADDR (msg_in2),
+
/*
- ** We have been ODD at the end of the transfer,
- ** but the device hasn't be so.
- ** Signal a DATA OVERRUN condition to the C code.
- */
- SCR_INT,
- SIR_SWIDE_OVERRUN,
+ * We got the message we expected.
+ * Read the 2nd byte, and jump to dispatcher.
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[1]),
+ SCR_CLR (SCR_ACK),
+ 0,
SCR_JUMP,
- PADDR (dispatch),
+ PADDR (disp_status),
}/*-------------------------< DATAO_DONE >-------------------*/,{
/*
+ * If the device wants us to send more data,
+ * we must count the extra bytes.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+ PADDRH (data_ovrun),
+ /*
** If the SODL is not full jump to dispatcher.
** We anticipate a MSG IN phase or a STATUS phase.
*/
SCR_FROM_REG (scntl2),
0,
SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
- PADDR (disp_msg_in),
+ PADDR (disp_status),
/*
** The SODL is full, clear this condition.
*/
@@ -3157,13 +3225,25 @@
SCR_JUMP,
PADDR (clrack),
-}/*-------------------------< DATAPHASE >------------------*/,{
+}/*-------------------------< DATAI_PHASE >------------------*/,{
#ifdef SCSI_NCR_PROFILE_SUPPORT
SCR_REG_REG (QU_REG, SCR_OR, HF_DATA_ST),
0,
#endif
SCR_RETURN,
0,
+}/*-------------------------< DATAO_PHASE >------------------*/,{
+ /*
+ ** Patch for 53c1010_66 only - to allow A0 part
+ ** to operate properly in a 33MHz PCI bus.
+ **
+ ** SCR_REG_REG(scntl4, SCR_OR, 0x0c),
+ ** 0,
+ */
+ SCR_NO_OP,
+ 0,
+ SCR_RETURN,
+ 0,
}/*-------------------------< MSG_IN >--------------------*/,{
/*
** Get the first byte of the message.
@@ -3524,31 +3604,42 @@
offsetof(struct tcb, wval),
SCR_LOAD_REL (sxfer, 1),
offsetof(struct tcb, sval),
+}/*-------------------------< RESEL_SCNTL4 >------------------*/,{
/*
- ** If MESSAGE IN phase as expected,
- ** read the data directly from the BUS DATA lines.
- ** This helps to support very old SCSI devices that
- ** may reselect without sending an IDENTIFY.
+ ** Write with uval value. Patch if device
+ ** does not support Ultra3.
+ **
+ ** SCR_LOAD_REL (scntl4, 1),
+ ** offsetof(struct tcb, uval),
*/
+
+ SCR_NO_OP,
+ 0,
+ /*
+ * We expect MESSAGE IN phase.
+ * If not, get help from the C code.
+ */
SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
SIR_RESEL_NO_MSG_IN,
- SCR_FROM_REG (sbdl),
- 0,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin),
+
/*
- ** If message phase but not an IDENTIFY,
- ** get some help from the C code.
- ** Old SCSI device may behave so.
- */
+ * If IDENTIFY LUN #0, use a faster path
+ * to find the LCB structure.
+ */
+ SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)),
+ 56,
+ /*
+ * If message isn't an IDENTIFY,
+ * tell the C code about.
+ */
SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
SIR_RESEL_NO_IDENTIFY,
/*
- ** It is an IDENTIFY message,
- ** Load the LUN control block address.
- ** If LUN 0, avoid a PCI BUS ownership by loading
- ** directly 'b_lun0' from the TCB.
- */
- SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
- 48,
+ * It is an IDENTIFY message,
+ * Load the LUN control block address.
+ */
SCR_LOAD_REL (dsa, 4),
offsetof(struct tcb, b_luntbl),
SCR_SFBR_REG (dsa, SCR_SHL, 0),
@@ -3578,15 +3669,20 @@
offsetof(struct lcb, b_tasktbl),
SCR_RETURN,
0,
-
}/*-------------------------< RESEL_TAG >-------------------*/,{
/*
+ ** ACK the IDENTIFY or TAG previously received
+ */
+
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
** Read IDENTIFY + SIMPLE + TAG using a single MOVE.
** Agressive optimization, is'nt it?
** No need to test the SIMPLE TAG message, since the
** driver only supports conformant devices for tags. ;-)
*/
- SCR_MOVE_ABS (3) ^ SCR_MSG_IN,
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
NADDR (msgin),
/*
** Read the TAG from the SIDL.
@@ -3627,14 +3723,9 @@
offsetof(struct ccb, phys.header.go.restart),
SCR_RETURN,
0,
+ /* In normal situations we branch to RESEL_DSA */
}/*-------------------------< RESEL_NOTAG >-------------------*/,{
/*
- ** No tag expected.
- ** Read an throw away the IDENTIFY.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- /*
** JUMP indirectly to the restart point of the CCB.
*/
SCR_JUMP,
@@ -3681,7 +3772,7 @@
SCR_CALL,
PADDR (datai_done),
SCR_JUMP,
- PADDRH (no_data),
+ PADDRH (data_ovrun),
}/*-------------------------< DATA_OUT >--------------------*/,{
/*
** Because the size depends on the
@@ -3700,7 +3791,7 @@
SCR_CALL,
PADDR (datao_done),
SCR_JUMP,
- PADDRH (no_data),
+ PADDRH (data_ovrun),
}/*-------------------------< PM0_DATA >--------------------*/,{
/*
@@ -3719,7 +3810,7 @@
** Check against expected direction.
*/
SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (no_data),
+ PADDRH (data_ovrun),
/*
** Keep track we are moving data from the
** PM0 DATA mini-script.
@@ -3739,7 +3830,7 @@
** Check against expected direction.
*/
SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (no_data),
+ PADDRH (data_ovrun),
/*
** Keep track we are moving data from the
** PM0 DATA mini-script.
@@ -3784,7 +3875,7 @@
** Check against expected direction.
*/
SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (no_data),
+ PADDRH (data_ovrun),
/*
** Keep track we are moving data from the
** PM1 DATA mini-script.
@@ -3804,7 +3895,7 @@
** Check against expected direction.
*/
SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (no_data),
+ PADDRH (data_ovrun),
/*
** Keep track we are moving data from the
** PM1 DATA mini-script.
@@ -3835,6 +3926,7 @@
}/*---------------------------------------------------------*/
};
+
static struct scripth scripth0 __initdata = {
/*------------------------< START64 >-----------------------*/{
/*
@@ -3844,7 +3936,9 @@
*/
SCR_JUMP,
PADDR (init),
-
+}/*-------------------------< NO_DATA >-------------------*/,{
+ SCR_JUMP,
+ PADDRH (data_ovrun),
}/*-----------------------< SEL_FOR_ABORT >------------------*/,{
/*
** We are jumped here by the C code, if we have
@@ -4078,33 +4172,31 @@
SCR_JUMP,
PADDRH (msg_out_done),
-}/*-------------------------< NEGO_BAD_PHASE >------------*/,{
- SCR_INT,
- SIR_NEGO_PROTO,
- SCR_JUMP,
- PADDR (dispatch),
-
-}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
+}/*-------------------------< PPR_RESP >-------------*/,{
/*
- ** After ABORT message,
- **
- ** expect an immediate disconnect, ...
+ ** let the target fetch our answer.
*/
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_CLR (SCR_ACK|SCR_ATN),
+ SCR_SET (SCR_ATN),
0,
- SCR_WAIT_DISC,
+ SCR_CLR (SCR_ACK),
0,
- SCR_INT,
- SIR_MSG_OUT_DONE,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ PADDRH (nego_bad_phase),
+
+}/*-------------------------< SEND_PPR >-------------*/,{
/*
- ** ... and set the status to "ABORTED"
+ ** Send the M_X_PPR_REQ
*/
- SCR_LOAD_REG (HS_REG, HS_ABORTED),
- 0,
+ SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_JUMP,
+ PADDRH (msg_out_done),
+
+}/*-------------------------< NEGO_BAD_PHASE >------------*/,{
+ SCR_INT,
+ SIR_NEGO_PROTO,
SCR_JUMP,
- PADDR (complete2),
+ PADDR (dispatch),
}/*-------------------------< MSG_OUT >-------------------*/,{
/*
@@ -4113,11 +4205,6 @@
SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
NADDR (msgout),
/*
- ** If it was no ABORT message ...
- */
- SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
- PADDRH (msg_out_abort),
- /*
** ... wait for the next phase
** if it's a message out, send it again, ...
*/
@@ -4135,34 +4222,56 @@
SCR_JUMP,
PADDR (dispatch),
-}/*-------------------------< NO_DATA >--------------------*/,{
+}/*-------------------------< DATA_OVRUN >--------------------*/,{
/*
- ** The target wants to tranfer too much data
- ** or in the wrong direction.
- ** Remember that in extended error.
- */
+ * The target may want to transfer too much data.
+ *
+ * If phase is DATA OUT write 1 byte and count it.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+ 16,
+ SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
+ NADDR (scratch),
+ SCR_JUMP,
+ PADDRH (data_ovrun1),
+ /*
+ * If WSR is set, clear this condition, and
+ * count this byte.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+ 16,
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ SCR_JUMP,
+ PADDRH (data_ovrun1),
+ /*
+ * Finally check against DATA IN phase.
+ * Jump to dispatcher if not so.
+ * Read 1 byte otherwise and count it.
+ */
+ SCR_JUMP ^ IFFALSE (IF (SCR_DATA_IN)),
+ PADDR (dispatch),
+ SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
+ NADDR (scratch),
+}/*-------------------------< DATA_OVRUN1 >--------------------*/,{
+ /*
+ * Set the extended error flag.
+ */
+ SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR),
+ 0,
SCR_LOAD_REL (scratcha, 1),
offsetof (struct ccb, xerr_status),
- SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA),
+ SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA),
0,
SCR_STORE_REL (scratcha, 1),
offsetof (struct ccb, xerr_status),
/*
- ** Discard one data byte, if required.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
- 8,
- SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
- NADDR (scratch),
- SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
- 8,
- SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
- NADDR (scratch),
- /*
- ** Count this byte.
- ** This will allow to return a positive
- ** residual to user.
- */
+ * Count this byte.
+ * This will allow to return a negative
+ * residual to user.
+ */
SCR_LOAD_REL (scratcha, 4),
offsetof (struct ccb, phys.extra_bytes),
SCR_REG_REG (scratcha, SCR_ADD, 0x01),
@@ -4174,12 +4283,10 @@
SCR_STORE_REL (scratcha, 4),
offsetof (struct ccb, phys.extra_bytes),
/*
- ** .. and repeat as required.
- */
- SCR_CALL,
- PADDR (dispatch),
+ * .. and repeat as required.
+ */
SCR_JUMP,
- PADDRH (no_data),
+ PADDRH (data_ovrun),
}/*-------------------------< ABORT_RESEL >----------------*/,{
SCR_SET (SCR_ATN),
@@ -4227,10 +4334,9 @@
SCR_CHMOV_TBL ^ SCR_DATA_IN,
offsetof (struct dsb, sense),
SCR_CALL,
- PADDR (dispatch),
+ PADDR (datai_done),
SCR_JUMP,
- PADDRH (no_data),
-
+ PADDRH (data_ovrun),
}/*-------------------------< DATA_IO >--------------------*/,{
/*
** We jump here if the data direction was unknown at the
@@ -4280,29 +4386,14 @@
SCR_JUMP,
PADDRH(data_io_com),
-}/*-------------------------< BAD_IDENTIFY >---------------*/,{
- /*
- ** If message phase but not an IDENTIFY,
- ** get some help from the C code.
- ** Old SCSI device may behave so.
- */
- SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)),
- 16,
- SCR_INT,
- SIR_RESEL_NO_IDENTIFY,
- SCR_JUMP,
- PADDRH (abort_resel),
+}/*-------------------------< RESEL_BAD_LUN >---------------*/,{
/*
** Message is an IDENTIFY, but lun is unknown.
- ** Read the message, since we got it directly
- ** from the SCSI BUS data lines.
** Signal problem to C code for logging the event.
** Send a M_ABORT to clear all pending tasks.
*/
SCR_INT,
SIR_RESEL_BAD_LUN,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
SCR_JUMP,
PADDRH (abort_resel),
}/*-------------------------< BAD_I_T_L >------------------*/,{
@@ -4441,7 +4532,7 @@
SCR_FROM_REG (scntl2),
0,
SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
- PADDRH (swide_scr_64),
+ PADDRH (pm_wsr_handle),
/*
** Save the remaining byte count, the updated
** address and the return address.
@@ -4468,7 +4559,7 @@
SCR_FROM_REG (scntl2),
0,
SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
- PADDRH (swide_scr_64),
+ PADDRH (pm_wsr_handle),
/*
** Save the remaining byte count, the updated
** address and the return address.
@@ -4484,101 +4575,32 @@
PADDRH (pm1_data_addr),
SCR_JUMP,
PADDR (dispatch),
-
-}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{
- /*
- ** Handling of the SWIDE for 32 bit chips.
- **
- ** We jump here from the C code with SCRATCHA
- ** containing the address to write the SWIDE.
- ** - Save 32 bit address in <scratch>.
- */
- SCR_STORE_ABS (scratcha, 4),
- PADDRH (scratch),
- SCR_JUMP,
- PADDRH (swide_common),
-}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{
- /*
- ** Handling of the SWIDE for 64 bit chips when the
- ** hardware handling of phase mismatch is disabled.
- **
- ** We jump here from the C code with SCRATCHA
- ** containing the address to write the SWIDE and
- ** SBR containing bit 32..39 of this address.
- ** - Save 32 bit address in <scratch>.
- ** - Move address bit 32..39 to SFBR.
- */
- SCR_STORE_ABS (scratcha, 4),
- PADDRH (scratch),
- SCR_FROM_REG (sbr),
- 0,
- SCR_JUMP,
- PADDRH (swide_com_64),
-}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{
- /*
- ** Handling of the SWIDE for 64 bit chips when
- ** hardware phase mismatch is enabled.
- ** We are entered with a SCR_CALL from PMO_SAVE
- ** and PM1_SAVE sub-scripts.
- **
- ** Snoop the SCSI BUS in case of the device
- ** willing to ignore this residue.
- ** If it does, we must only increment the RBC,
- ** since this register does reflect all bytes
- ** received from the SCSI BUS including the SWIDE.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDRH (swide_scr_64_1),
- SCR_FROM_REG (sbdl),
- 0,
- SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
- PADDRH (swide_scr_64_1),
- SCR_REG_REG (rbc, SCR_ADD, 1),
- 0,
- SCR_REG_REG (rbc1, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (rbc2, SCR_ADDC, 0),
- 0,
+}/*--------------------------< PM_WSR_HANDLE >-----------------------*/,{
/*
- ** Save UA and RBC, since the PM0/1_SAVE
- ** sub-scripts haven't moved them to the
- ** context yet and the below MOV may just
- ** change their value.
- */
- SCR_STORE_ABS (ua, 4),
- PADDRH (scratch),
- SCR_STORE_ABS (rbc, 4),
- PADDRH (scratch1),
+ * Phase mismatch handling from SCRIPT with WSR set.
+ * Such a condition can occur if the chip wants to
+ * execute a CHMOV(size > 1) when the WSR bit is
+ * set and the target changes PHASE.
+ */
+#ifdef SYM_DEBUG_PM_WITH_WSR
/*
- ** Throw away the IGNORE WIDE RESIDUE message.
- ** since we just did take care of it.
- */
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
- NADDR (scratch),
- SCR_CLR (SCR_ACK),
- 0,
+ * Some debugging may still be needed.:)
+ */
+ SCR_INT,
+ SIR_PM_WITH_WSR,
+#endif
/*
- ** Restore UA and RBC registers and return.
- */
- SCR_LOAD_ABS (ua, 4),
- PADDRH (scratch),
- SCR_LOAD_ABS (rbc, 4),
- PADDRH (scratch1),
- SCR_RETURN,
- 0,
-}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{
+ * We must move the residual byte to memory.
+ *
+ * UA contains bit 0..31 of the address to
+ * move the residual byte.
+ * Move it to the table indirect.
+ */
+ SCR_STORE_REL (ua, 4),
+ offsetof (struct ccb, phys.wresid.addr),
/*
- ** We must grab the SWIDE and move it to
- ** memory.
- **
- ** - Save UA (32 bit address) in <scratch>.
- ** - Move address bit 32..39 to SFBR.
- ** - Increment UA (updated address).
- */
- SCR_STORE_ABS (ua, 4),
- PADDRH (scratch),
- SCR_FROM_REG (rbc3),
- 0,
+ * Increment UA (move address to next position).
+ */
SCR_REG_REG (ua, SCR_ADD, 1),
0,
SCR_REG_REG (ua1, SCR_ADDC, 0),
@@ -4587,70 +4609,45 @@
0,
SCR_REG_REG (ua3, SCR_ADDC, 0),
0,
-}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{
/*
- ** - Save DRS.
- ** - Load DRS with address bit 32..39 of the
- ** location to write the SWIDE.
- ** SFBR has been loaded with these bits.
- ** (Look above).
- */
- SCR_STORE_ABS (drs, 4),
- PADDRH (saved_drs),
- SCR_LOAD_ABS (drs, 4),
+ * Compute SCRATCHA as:
+ * - size to transfer = 1 byte.
+ * - bit 24..31 = high address bit [32...39].
+ */
+ SCR_LOAD_ABS (scratcha, 4),
PADDRH (zero),
- SCR_TO_REG (drs),
+ SCR_REG_REG (scratcha, SCR_OR, 1),
0,
-}/*--------------------------< SWIDE_COMMON >-----------------------*/,{
- /*
- ** - Save current DSA
- ** - Load DSA with bit 0..31 of the memory
- ** location to write the SWIDE.
- */
- SCR_STORE_ABS (dsa, 4),
- PADDRH (saved_dsa),
- SCR_LOAD_ABS (dsa, 4),
- PADDRH (scratch),
- /*
- ** Move the SWIDE to memory.
- ** Clear the WSR bit.
- */
- SCR_STORE_REL (swide, 1),
+ SCR_FROM_REG (rbc3),
0,
- SCR_REG_REG (scntl2, SCR_OR, WSR),
+ SCR_TO_REG (scratcha3),
0,
/*
- ** Restore the original DSA.
- */
- SCR_LOAD_ABS (dsa, 4),
- PADDRH (saved_dsa),
-}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{
- /*
- ** For 32 bit chip, the following SCRIPTS
- ** instruction is patched with a JUMP to dispatcher.
- ** (Look into the C code).
- */
- SCR_LOAD_ABS (drs, 4),
- PADDRH (saved_drs),
+ * Move this value to the table indirect.
+ */
+ SCR_STORE_REL (scratcha, 4),
+ offsetof (struct ccb, phys.wresid.size),
/*
- ** 64 bit chip only.
- ** If PM handling from SCRIPTS, we are just
- ** a helper for the C code, so jump to
- ** dispatcher now.
- */
- SCR_FROM_REG (ccntl0),
+ * Wait for a valid phase.
+ * While testing with bogus QUANTUM drives, the C1010
+ * sometimes raised a spurious phase mismatch with
+ * WSR and the CHMOV(1) triggered another PM.
+ * Waiting explicitely for the PHASE seemed to avoid
+ * the nested phase mismatch. Btw, this didn't happen
+ * using my IBM drives.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
0,
- SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)),
- PADDR (dispatch),
/*
- ** 64 bit chip with hardware PM handling enabled.
- **
- ** Since we are paranoid:), we donnot want
- ** a SWIDE followed by a CHMOV(1) to lead to
- ** a CHMOV(0) in our PM context.
- ** We check against such a condition.
- ** Also does the C code.
- */
+ * Perform the move of the residual byte.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct ccb, phys.wresid),
+ /*
+ * We can now handle the phase mismatch with UA fixed.
+ * RBC[0..23]=0 is a special case that does not require
+ * a PM context. The C code also checks against this.
+ */
SCR_FROM_REG (rbc),
0,
SCR_RETURN ^ IFFALSE (DATA (0)),
@@ -4664,19 +4661,29 @@
SCR_RETURN ^ IFFALSE (DATA (0)),
0,
/*
- ** If we are there, RBC(0..23) is zero,
- ** and we just have to load the current
- ** DATA SCRIPTS address (register TEMP)
- ** with the IA and go to dispatch.
- ** No PM context is needed.
- */
+ * RBC[0..23]=0.
+ * Not only we donnot need a PM context, but this would
+ * lead to a bogus CHMOV(0). This condition means that
+ * the residual was the last byte to move from this CHMOV.
+ * So, we just have to move the current data script pointer
+ * (i.e. TEMP) to the SCRIPTS address following the
+ * interrupted CHMOV and jump to dispatcher.
+ */
SCR_STORE_ABS (ia, 4),
PADDRH (scratch),
SCR_LOAD_ABS (temp, 4),
PADDRH (scratch),
SCR_JUMP,
PADDR (dispatch),
-
+}/*--------------------------< WSR_MA_HELPER >-----------------------*/,{
+ /*
+ * Helper for the C code when WSR bit is set.
+ * Perform the move of the residual byte.
+ */
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ offsetof (struct ccb, phys.wresid),
+ SCR_JUMP,
+ PADDR (dispatch),
}/*-------------------------< ZERO >------------------------*/,{
SCR_DATA_ZERO,
}/*-------------------------< SCRATCH >---------------------*/,{
@@ -4792,6 +4799,7 @@
assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
p = scr->data_out;
+
for (i=0; i<MAX_SCATTER; i++) {
*p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
*p++ =offsetof (struct dsb, data[i]);
@@ -4963,6 +4971,7 @@
break;
#ifdef RELOC_KVAR
case RELOC_KVAR:
+ new=0;
if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) ||
((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST))
panic("ncr KVAR out of range");
@@ -5152,16 +5161,30 @@
static void __init ncr_save_initial_setting(ncb_p np)
{
np->sv_scntl0 = INB(nc_scntl0) & 0x0a;
- np->sv_scntl3 = INB(nc_scntl3) & 0x07;
np->sv_dmode = INB(nc_dmode) & 0xce;
np->sv_dcntl = INB(nc_dcntl) & 0xa8;
np->sv_ctest3 = INB(nc_ctest3) & 0x01;
np->sv_ctest4 = INB(nc_ctest4) & 0x80;
- np->sv_ctest5 = INB(nc_ctest5) & 0x24;
np->sv_gpcntl = INB(nc_gpcntl);
np->sv_stest2 = INB(nc_stest2) & 0x20;
np->sv_stest4 = INB(nc_stest4);
np->sv_stest1 = INB(nc_stest1);
+
+ np->sv_scntl3 = INB(nc_scntl3) & 0x07;
+
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) ){
+ /*
+ ** C1010 always uses large fifo, bit 5 rsvd
+ ** scntl4 used ONLY with C1010
+ */
+ np->sv_ctest5 = INB(nc_ctest5) & 0x04 ;
+ np->sv_scntl4 = INB(nc_scntl4);
+ }
+ else {
+ np->sv_ctest5 = INB(nc_ctest5) & 0x24 ;
+ np->sv_scntl4 = 0;
+ }
}
/*
@@ -5200,15 +5223,35 @@
/*
* Divisor to be used for async (timer pre-scaler).
+ *
+ * Note: For C1010 the async divisor is 2(8) if he
+ * quadrupler is disabled (enabled).
*/
- i = np->clock_divn - 1;
- while (--i >= 0) {
- if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) {
- ++i;
- break;
+
+ if ( (np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+
+ np->rv_scntl3 = 0;
+ }
+ else
+ {
+ i = np->clock_divn - 1;
+ while (--i >= 0) {
+ if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz
+ > div_10M[i]) {
+ ++i;
+ break;
+ }
}
+ np->rv_scntl3 = i+1;
}
- np->rv_scntl3 = i+1;
+
+
+ /*
+ * Save the ultra3 register for the C1010/C1010_66
+ */
+
+ np->rv_scntl4 = np->sv_scntl4;
/*
* Minimum synchronous period factor supported by the chip.
@@ -5222,13 +5265,28 @@
else np->minsync = (period + 40 - 1) / 40;
/*
+ * Fix up. If sync. factor is 10 (160000Khz clock) and chip
+ * supports ultra3, then min. sync. period 12.5ns and the factor is 9
+ */
+
+ if ((np->minsync == 10) && (np->features & FE_ULTRA3))
+ np->minsync = 9;
+
+ /*
* Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
+ *
+ * Transfer period minimums: SCSI-1 200 (50); Fast 100 (25)
+ * Ultra 50 (12); Ultra2 (6); Ultra3 (3)
*/
- if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2)))
+ if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3)))
np->minsync = 25;
- else if (np->minsync < 12 && !(np->features & FE_ULTRA2))
+ else if (np->minsync < 12 && (np->features & FE_ULTRA))
np->minsync = 12;
+ else if (np->minsync < 10 && (np->features & FE_ULTRA2))
+ np->minsync = 10;
+ else if (np->minsync < 9 && (np->features & FE_ULTRA3))
+ np->minsync = 9;
/*
* Maximum synchronous period factor supported by the chip.
@@ -5248,7 +5306,7 @@
#endif
/*
- ** Phase mismatch handled by SCRIPTS (53C895A or 53C896) ?
+ ** Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ?
*/
if (np->features & FE_NOPM)
np->rv_ccntl0 |= (ENPMJ);
@@ -5292,6 +5350,14 @@
np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP);
/*
+ ** DEL ? - 53C1010 Rev 1 - Part Number 609-0393638
+ ** 64-bit Slave Cycles must be disabled.
+ */
+ if ( ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) && (np->revision_id < 0x02) )
+ || (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) )
+ np->rv_ccntl1 |= 0x10;
+
+ /*
** Select all supported special features.
** If we are using on-board RAM for scripts, prefetch (PFEN)
** does not help, but burst op fetch (BOF) does.
@@ -5313,8 +5379,13 @@
np->rv_dcntl |= CLSE; /* Cache Line Size Enable */
if (np->features & FE_WRIE)
np->rv_ctest3 |= WRIE; /* Write and Invalidate */
- if (np->features & FE_DFS)
+
+
+ if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) &&
+ (np->features & FE_DFS))
np->rv_ctest5 |= DFS; /* Dma Fifo Size */
+ /* C1010/C1010_66 always large fifo */
/*
** Select some other
@@ -5362,14 +5433,15 @@
/*
** Set SCSI BUS mode.
**
- ** - ULTRA2 chips (895/895A/896) report the current
+ ** - ULTRA2 chips (895/895A/896)
+ ** and ULTRA 3 chips (1010) report the current
** BUS mode through the STEST4 IO register.
** - For previous generation chips (825/825A/875),
** user has to tell us how to check against HVD,
** since a 100% safe algorithm is not possible.
*/
np->scsi_mode = SMODE_SE;
- if (np->features & FE_ULTRA2)
+ if (np->features & (FE_ULTRA2 | FE_ULTRA3))
np->scsi_mode = (np->sv_stest4 & SMODE);
else if (np->features & FE_DIFF) {
switch(driver_setup.diff_support) {
@@ -5471,7 +5543,8 @@
i == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " :
(i == SCSI_NCR_TEKRAM_NVRAM ? "Tekram format NVRAM, " : ""),
np->myaddr,
- np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10),
+ np->minsync < 10 ? 80 :
+ (np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10) ),
(np->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity",
(np->rv_stest2 & 0x20) ? ", Differential" : "");
@@ -5864,14 +5937,6 @@
ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
/*
- ** If not 64 bit chip, patch some places in SCRIPTS.
- */
- if (!(np->features & FE_64BIT)) {
- np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP);
- np->scripth0->swide_fin_32[1] =
- cpu_to_scr(NCB_SCRIPT_PHYS(np, dispatch));
- }
- /*
** Patch some variables in SCRIPTS
*/
np->scripth0->pm0_data_addr[0] =
@@ -5879,6 +5944,15 @@
np->scripth0->pm1_data_addr[0] =
cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data));
+ /*
+ ** Patch if not Ultra 3 - Do not write to scntl4
+ */
+ if (np->features & FE_ULTRA3) {
+ np->script0->resel_scntl4[0] = cpu_to_scr(SCR_LOAD_REL (scntl4, 1));
+ np->script0->resel_scntl4[1] = cpu_to_scr(offsetof(struct tcb, uval));
+ }
+
+
#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
np->scripth0->script0_ba[0] = cpu_to_scr(vtobus(np->script0));
np->scripth0->script0_ba64[0] = cpu_to_scr(vtobus(np->script0));
@@ -5912,7 +5986,7 @@
goto attach_error;
assert (offsetof(struct lcb, resel_task) == 0);
- np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify));
+ np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, resel_bad_lun));
for (i = 0 ; i < 64 ; i++)
np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun));
@@ -5940,6 +6014,15 @@
cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
}
+ /*
+ ** Patch the script to provide an extra clock cycle on
+ ** data out phase - 53C1010_66MHz part only.
+ */
+ if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66){
+ np->script0->datao_phase[0] =
+ cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c));
+ }
+
#ifdef SCSI_NCR_IARB_SUPPORT
/*
** If user does not want to use IMMEDIATE ARBITRATION
@@ -5968,8 +6051,11 @@
#else
#define XXX 2
#endif
- np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP);
- np->script0->dataphase[XXX+1] =
+ np->script0->datai_phase[XXX] = cpu_to_scr(SCR_JUMP);
+ np->script0->datai_phase[XXX+1] =
+ cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj));
+ np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP);
+ np->script0->datao_phase[1] =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj));
#undef XXX
}
@@ -5985,6 +6071,9 @@
** We should use ncr_soft_reset(), but we donnot want to do
** so, since we may not be safe if ABRT interrupt occurs due
** to the BIOS or previous O/S having enable this interrupt.
+ **
+ ** For C1010 need to set ABRT bit prior to SRST if SCRIPTs
+ ** are running. Not true in this case.
*/
ncr_chip_reset(np);
@@ -6089,6 +6178,19 @@
instance->dma_channel = 0;
instance->cmd_per_lun = MAX_TAGS;
instance->can_queue = (MAX_START-4);
+
+ np->check_integrity = 0;
+
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ instance->check_integrity = 0;
+
+#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK
+ if ( !(driver_setup.bus_check & 0x04) ) {
+ np->check_integrity = 1;
+ instance->check_integrity = 1;
+ }
+#endif
+#endif
instance->select_queue_depths = sym53c8xx_select_queue_depths;
@@ -6214,6 +6316,299 @@
/*==========================================================
**
**
+** Prepare the next negotiation message for integrity check,
+** if needed.
+**
+** Fill in the part of message buffer that contains the
+** negotiation and the nego_status field of the CCB.
+** Returns the size of the message in bytes.
+**
+** If tp->ppr_negotiation is 1 and a M_REJECT occurs, then
+** we disable ppr_negotiation. If the first ppr_negotiation is
+** successful, set this flag to 2.
+**
+**==========================================================
+*/
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr)
+{
+ tcb_p tp = &np->target[cp->target];
+ int msglen = 0;
+ int nego = 0;
+ u_char new_width, new_offset, new_period;
+ u_char no_increase;
+
+ if (tp->ppr_negotiation == 1) /* PPR message successful */
+ tp->ppr_negotiation = 2;
+
+ if (tp->inq_done) {
+
+ if (!tp->ic_maximums_set) {
+ tp->ic_maximums_set = 1;
+
+ /*
+ * Check against target, host and user limits
+ */
+ if ( (tp->inq_byte7 & INQ7_WIDE16) &&
+ np->maxwide && tp->usrwide)
+ tp->ic_max_width = 1;
+ else
+ tp->ic_max_width = 0;
+
+
+ if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs)
+ tp->ic_min_sync = (tp->minsync < np->minsync) ?
+ np->minsync : tp->minsync;
+ else
+ tp->ic_min_sync = 255;
+
+ tp->period = 1;
+ tp->widedone = 1;
+
+ /*
+ * Enable PPR negotiation - only if Ultra3 support
+ * is accessible.
+ */
+
+#if 0
+ if (tp->ic_max_width && (tp->ic_min_sync != 255 ))
+ tp->ppr_negotiation = 1;
+#endif
+ tp->ppr_negotiation = 0;
+ if (np->features & FE_ULTRA3) {
+ if (tp->ic_max_width && (tp->ic_min_sync == 0x09))
+ tp->ppr_negotiation = 1;
+ }
+
+ if (!tp->ppr_negotiation)
+ cmd->ic_nego &= ~NS_PPR;
+ }
+
+ if (DEBUG_FLAGS & DEBUG_IC) {
+ printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n",
+ ncr_name(np), cmd->ic_nego, cmd->cmnd[0]);
+ }
+
+ /* Previous command recorded a parity or an initiator
+ * detected error condition. Force bus to narrow for this
+ * target. Clear flag. Negotation on request sense.
+ * Note: kernel forces 2 bus resets :o( but clears itself out.
+ * Minor bug? in scsi_obsolete.c (ugly)
+ */
+ if (np->check_integ_par) {
+ printk("%s: Parity Error. Target set to narrow.\n",
+ ncr_name(np));
+ tp->ic_max_width = 0;
+ tp->widedone = tp->period = 0;
+ }
+
+ /* Initializing:
+ * If ic_nego == NS_PPR, we are in the initial test for
+ * PPR messaging support. If driver flag is clear, then
+ * either we don't support PPR nego (narrow or async device)
+ * or this is the second TUR and we have had a M. REJECT
+ * or unexpected disconnect on the first PPR negotiation.
+ * Do not negotiate, reset nego flags (in case a reset has
+ * occurred), clear ic_nego and return.
+ * General case: Kernel will clear flag on a fallback.
+ * Do only SDTR or WDTR in the future.
+ */
+ if (!tp->ppr_negotiation && (cmd->ic_nego == NS_PPR )) {
+ tp->ppr_negotiation = 0;
+ cmd->ic_nego &= ~NS_PPR;
+ tp->widedone = tp->period = 1;
+ return msglen;
+ }
+ else if (( tp->ppr_negotiation && !(cmd->ic_nego & NS_PPR )) ||
+ (!tp->ppr_negotiation && (cmd->ic_nego & NS_PPR )) ) {
+ tp->ppr_negotiation = 0;
+ cmd->ic_nego &= ~NS_PPR;
+ }
+
+ /*
+ * Always check the PPR nego. flag bit if ppr_negotiation
+ * is set. If the ic_nego PPR bit is clear,
+ * there must have been a fallback. Do only
+ * WDTR / SDTR in the future.
+ */
+ if ((tp->ppr_negotiation) && (!(cmd->ic_nego & NS_PPR)))
+ tp->ppr_negotiation = 0;
+
+ /* In case of a bus reset, ncr_negotiate will reset
+ * the flags tp->widedone and tp->period to 0, forcing
+ * a new negotiation. Do WDTR then SDTR. If PPR, do both.
+ * Do NOT increase the period. It is possible for the Scsi_Cmnd
+ * flags to be set to increase the period when a bus reset
+ * occurs - we don't want to change anything.
+ */
+
+ no_increase = 0;
+
+ if (tp->ppr_negotiation && (!tp->widedone) && (!tp->period) ) {
+ cmd->ic_nego = NS_PPR;
+ tp->widedone = tp->period = 1;
+ no_increase = 1;
+ }
+ else if (!tp->widedone) {
+ cmd->ic_nego = NS_WIDE;
+ tp->widedone = 1;
+ no_increase = 1;
+ }
+ else if (!tp->period) {
+ cmd->ic_nego = NS_SYNC;
+ tp->period = 1;
+ no_increase = 1;
+ }
+
+ new_width = cmd->ic_nego_width & tp->ic_max_width;
+
+ switch (cmd->ic_nego_sync) {
+ case 2: /* increase the period */
+ if (!no_increase) {
+ if (tp->ic_min_sync <= 0x09)
+ tp->ic_min_sync = 0x0A;
+ else if (tp->ic_min_sync <= 0x0A)
+ tp->ic_min_sync = 0x0C;
+ else if (tp->ic_min_sync <= 0x0C)
+ tp->ic_min_sync = 0x19;
+ else if (tp->ic_min_sync <= 0x19)
+ tp->ic_min_sync *= 2;
+ else {
+ tp->ic_min_sync = 255;
+ cmd->ic_nego_sync = 0;
+ tp->maxoffs = 0;
+ }
+ }
+ new_period = tp->maxoffs?tp->ic_min_sync:0;
+ new_offset = tp->maxoffs;
+ break;
+
+ case 1: /* nego. to maximum */
+ new_period = tp->maxoffs?tp->ic_min_sync:0;
+ new_offset = tp->maxoffs;
+ break;
+
+ case 0: /* nego to async */
+ default:
+ new_period = 0;
+ new_offset = 0;
+ break;
+ };
+
+
+ nego = NS_NOCHANGE;
+ if (tp->ppr_negotiation) {
+ u_char options_byte = 0;
+
+ /*
+ ** Must make sure data is consistent.
+ ** If period is 9 and sync, must be wide and DT bit set.
+ ** else period must be larger. If the width is 0,
+ ** reset bus to wide but increase the period to 0x0A.
+ ** Note: The strange else clause is due to the integrity check.
+ ** If fails at 0x09, wide, the I.C. code will redo at the same
+ ** speed but a narrow bus. The driver must take care of slowing
+ ** the bus speed down.
+ **
+ ** The maximum offset in ST mode is 31, in DT mode 62 (1010/1010_66 only)
+ */
+ if ( (new_period==0x09) && new_offset) {
+ if (new_width)
+ options_byte = 0x02;
+ else {
+ tp->ic_min_sync = 0x0A;
+ new_period = 0x0A;
+ cmd->ic_nego_width = 1;
+ new_width = 1;
+ new_offset &= 0x1f;
+ }
+ }
+ else if (new_period > 0x09)
+ new_offset &= 0x1f;
+
+ nego = NS_PPR;
+
+ msgptr[msglen++] = M_EXTENDED;
+ msgptr[msglen++] = 6;
+ msgptr[msglen++] = M_X_PPR_REQ;
+ msgptr[msglen++] = new_period;
+ msgptr[msglen++] = 0;
+ msgptr[msglen++] = new_offset;
+ msgptr[msglen++] = new_width;
+ msgptr[msglen++] = options_byte;
+
+ }
+ else {
+ switch (cmd->ic_nego & ~NS_PPR) {
+ case NS_WIDE:
+ /*
+ ** WDTR negotiation on if device supports
+ ** wide or if wide device forced narrow
+ ** due to a parity error.
+ */
+
+ cmd->ic_nego_width &= tp->ic_max_width;
+
+ if (tp->ic_max_width | np->check_integ_par) {
+ nego = NS_WIDE;
+ msgptr[msglen++] = M_EXTENDED;
+ msgptr[msglen++] = 2;
+ msgptr[msglen++] = M_X_WIDE_REQ;
+ msgptr[msglen++] = new_width;
+ }
+ break;
+
+ case NS_SYNC:
+ /*
+ ** negotiate synchronous transfers
+ ** Target must support sync transfers.
+ ** Min. period = 0x0A, maximum offset of 31=0x1f.
+ */
+
+ if (tp->inq_byte7 & INQ7_SYNC) {
+
+ if (new_offset && (new_period < 0x0A)) {
+ tp->ic_min_sync = 0x0A;
+ new_period = 0x0A;
+ }
+ nego = NS_SYNC;
+ msgptr[msglen++] = M_EXTENDED;
+ msgptr[msglen++] = 3;
+ msgptr[msglen++] = M_X_SYNC_REQ;
+ msgptr[msglen++] = new_period;
+ msgptr[msglen++] = new_offset & 0x1f;
+ }
+ else
+ cmd->ic_nego_sync = 0;
+ break;
+
+ case NS_NOCHANGE:
+ break;
+ }
+ }
+
+ };
+
+ cp->nego_status = nego;
+ np->check_integ_par = 0;
+
+ if (nego) {
+ tp->nego_cp = cp;
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, nego == NS_WIDE ?
+ "wide/narrow msgout":
+ (nego == NS_SYNC ? "sync/async msgout" : "ppr msgout"),
+ msgptr);
+ };
+ };
+
+ return msglen;
+}
+#endif /* SCSI_NCR_INTEGRITY_CHECKING */
+
+/*==========================================================
+**
+**
** Prepare the next negotiation message if needed.
**
** Fill in the part of message buffer that contains the
@@ -6224,13 +6619,42 @@
**==========================================================
*/
+
static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr)
{
tcb_p tp = &np->target[cp->target];
int msglen = 0;
int nego = 0;
+ u_char width, offset, factor, last_byte;
+
+ if (!np->check_integrity) {
+ /* If integrity checking disabled, enable PPR messaging
+ * if device supports wide, sync and ultra 3
+ */
+ if (tp->ppr_negotiation == 1) /* PPR message successful */
+ tp->ppr_negotiation = 2;
+
+ if ((tp->inq_done) && (!tp->ic_maximums_set)) {
+ tp->ic_maximums_set = 1;
+
+ /*
+ * Issue PPR only if board is capable
+ * and set-up for Ultra3 transfers.
+ */
+ tp->ppr_negotiation = 0;
+ if ( (np->features & FE_ULTRA3) &&
+ (tp->usrwide) && (tp->maxoffs) &&
+ (tp->minsync == 0x09) )
+ tp->ppr_negotiation = 1;
+ }
+ }
if (tp->inq_done) {
+ /*
+ * Get the current width, offset and period
+ */
+ ncr_get_xfer_info( np, tp, &factor,
+ &offset, &width);
/*
** negotiate wide transfers ?
@@ -6238,19 +6662,50 @@
if (!tp->widedone) {
if (tp->inq_byte7 & INQ7_WIDE16) {
- nego = NS_WIDE;
+ if (tp->ppr_negotiation)
+ nego = NS_PPR;
+ else
+ nego = NS_WIDE;
+
+ width = tp->usrwide;
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ if (tp->ic_done)
+ width &= tp->ic_max_width;
+#endif
} else
tp->widedone=1;
+
};
/*
** negotiate synchronous transfers?
*/
- if (!nego && !tp->period) {
+ if ((nego != NS_WIDE) && !tp->period) {
if (tp->inq_byte7 & INQ7_SYNC) {
- nego = NS_SYNC;
+ if (tp->ppr_negotiation)
+ nego = NS_PPR;
+ else
+ nego = NS_SYNC;
+
+ /* Check for async flag */
+ if (tp->maxoffs == 0) {
+ offset = 0;
+ factor = 0;
+ }
+ else {
+ offset = tp->maxoffs;
+ factor = tp->minsync;
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ if ((tp->ic_done) &&
+ (factor < tp->ic_min_sync))
+ factor = tp->ic_min_sync;
+#endif
+ }
+
} else {
+ offset = 0;
+ factor = 0;
tp->period =0xffff;
PRINT_TARGET(np, cp->target);
printk ("target did not report SYNC.\n");
@@ -6259,18 +6714,54 @@
};
switch (nego) {
+ case NS_PPR:
+ /*
+ ** Must make sure data is consistent.
+ ** If period is 9 and sync, must be wide and DT bit set
+ ** else period must be larger.
+ ** Maximum offset is 31=0x1f is ST mode, 62 if DT mode
+ */
+ last_byte = 0;
+ if ( (factor==9) && offset) {
+ if (!width) {
+ factor = 0x0A;
+ offset &= 0x1f;
+ }
+ else
+ last_byte = 0x02;
+ }
+ else if (factor > 0x09)
+ offset &= 0x1f;
+
+ msgptr[msglen++] = M_EXTENDED;
+ msgptr[msglen++] = 6;
+ msgptr[msglen++] = M_X_PPR_REQ;
+ msgptr[msglen++] = factor;
+ msgptr[msglen++] = 0;
+ msgptr[msglen++] = offset;
+ msgptr[msglen++] = width;
+ msgptr[msglen++] = last_byte;
+ break;
case NS_SYNC:
+ /*
+ ** Never negotiate faster than Ultra 2 (25ns periods)
+ */
+ if (offset && (factor < 0x0A)) {
+ factor = 0x0A;
+ tp->minsync = 0x0A;
+ }
+
msgptr[msglen++] = M_EXTENDED;
msgptr[msglen++] = 3;
msgptr[msglen++] = M_X_SYNC_REQ;
- msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
- msgptr[msglen++] = tp->maxoffs;
+ msgptr[msglen++] = factor;
+ msgptr[msglen++] = offset & 0x1f;
break;
case NS_WIDE:
msgptr[msglen++] = M_EXTENDED;
msgptr[msglen++] = 2;
msgptr[msglen++] = M_X_WIDE_REQ;
- msgptr[msglen++] = tp->usrwide;
+ msgptr[msglen++] = width;
break;
};
@@ -6280,7 +6771,9 @@
tp->nego_cp = cp;
if (DEBUG_FLAGS & DEBUG_NEGO) {
ncr_print_msg(cp, nego == NS_WIDE ?
- "wide msgout":"sync_msgout", msgptr);
+ "wide msgout":
+ (nego == NS_SYNC ? "sync msgout" : "ppr msgout"),
+ msgptr);
};
};
@@ -6464,6 +6957,73 @@
cp->segments = 0;
}
+ /*---------------------------------------------------
+ **
+ ** negotiation required?
+ **
+ ** (nego_status is filled by ncr_prepare_nego())
+ **
+ **---------------------------------------------------
+ */
+
+ cp->nego_status = 0;
+
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ if ((np->check_integrity && tp->ic_done) || !np->check_integrity) {
+ if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+ msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
+ }
+ }
+ else if (np->check_integrity && (cmd->ic_in_progress)) {
+ msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen);
+ }
+ else if (np->check_integrity && cmd->ic_complete) {
+ u_long current_period;
+ u_char current_offset, current_width, current_factor;
+
+ ncr_get_xfer_info (np, tp, ¤t_factor,
+ ¤t_offset, ¤t_width);
+
+ tp->ic_max_width = current_width;
+ tp->ic_min_sync = current_factor;
+
+ if (current_factor == 9) current_period = 125;
+ else if (current_factor == 10) current_period = 250;
+ else if (current_factor == 11) current_period = 303;
+ else if (current_factor == 12) current_period = 500;
+ else current_period = current_factor * 40;
+
+ /*
+ * Negotiation for this target is complete. Update flags.
+ */
+ tp->period = current_period;
+ tp->widedone = 1;
+ tp->ic_done = 1;
+
+ printk("%s: Integrity Check Complete: \n", ncr_name(np));
+
+ printk("%s: %s %s SCSI", ncr_name(np),
+ current_offset?"SYNC":"ASYNC",
+ tp->ic_max_width?"WIDE":"NARROW");
+ if (current_offset) {
+ u_long mbs = 10000 * (tp->ic_max_width + 1);
+
+ printk(" %d.%d MB/s",
+ (int) (mbs / current_period), (int) (mbs % current_period));
+
+ printk(" (%d ns, %d offset)\n",
+ (int) current_period/10, current_offset);
+ }
+ else
+ printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5);
+ }
+#else
+ if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+ msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
+ }
+#endif /* SCSI_NCR_INTEGRITY_CHECKING */
+
+
/*----------------------------------------------------
**
** Determine xfer direction.
@@ -6524,19 +7084,6 @@
cp->startp = cp->phys.header.savep;
cp->lastp0 = cp->phys.header.lastp;
- /*---------------------------------------------------
- **
- ** negotiation required?
- **
- ** (nego_status is filled by ncr_prepare_nego())
- **
- **---------------------------------------------------
- */
-
- cp->nego_status = 0;
- if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp)
- msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
-
/*----------------------------------------------------
**
** fill in ccb
@@ -6559,6 +7106,7 @@
cp->phys.select.sel_id = cp->target;
cp->phys.select.sel_scntl3 = tp->wval;
cp->phys.select.sel_sxfer = tp->sval;
+ cp->phys.select.sel_scntl4 = tp->uval;
/*
** message
*/
@@ -7091,6 +7639,14 @@
PRINT_ADDR(cmd);
printk ("illegal scsi phase (4/5).\n");
}
+ if (cp->xerr_status & XE_SODL_UNRUN) {
+ PRINT_ADDR(cmd);
+ printk ("ODD transfer in DATA OUT phase.\n");
+ }
+ if (cp->xerr_status & XE_SWIDE_OVRUN){
+ PRINT_ADDR(cmd);
+ printk ("ODD transfer in DATA IN phase.\n");
+ }
if (cp->host_status==HS_COMPLETE)
cp->host_status = HS_FAIL;
@@ -7167,6 +7723,12 @@
PRINT_ADDR(cmd);
ncr_printl_hex("sense data:", cmd->sense_buffer, 14);
}
+ } else if ((cp->host_status == HS_COMPLETE)
+ && (cp->scsi_status == S_CONFLICT)) {
+ /*
+ ** Reservation Conflict condition code
+ */
+ SetScsiResult(cmd, DID_OK, S_CONFLICT);
} else if ((cp->host_status == HS_COMPLETE)
&& (cp->scsi_status == S_BUSY ||
@@ -7418,7 +7980,11 @@
OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */
OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */
- OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)){
+ OUTB (nc_stest2, EXT|np->rv_stest2);
+ /* Extended Sreq/Sack filtering, not supported in C1010/C1010_66 */
+ }
OUTB (nc_stest3, TE); /* TolerANT enable */
OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */
@@ -7427,14 +7993,24 @@
** Disable overlapped arbitration for all dual-function
** devices, regardless revision id.
** We may consider it is a post-chip-design feature. ;-)
+ **
+ ** Errata applies to all 896 and 1010 parts.
*/
if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
OUTB (nc_ctest0, (1<<5));
- else if (np->device_id == PCI_DEVICE_ID_NCR_53C896)
+ else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 ||
+ np->device_id == PCI_DEVICE_ID_LSI_53C1010 ||
+ np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 )
np->rv_ccntl0 |= DPR;
/*
- ** If 64 bit (895A/896/1010) write the CCNTL1 register to
+ ** C1010_66MHz rev 0 part requies AIPCNTL1 bit 3 to be set.
+ */
+ if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)
+ OUTB(nc_aipcntl1, (1<<3));
+
+ /*
+ ** If 64 bit (895A/896/1010/1010_66) write the CCNTL1 register to
** enable 40 bit address table indirect addressing for MOVE.
** Also write CCNTL0 if 64 bit chip, since this register seems
** to only be used by 64 bit cores.
@@ -7445,8 +8021,8 @@
}
/*
- ** If phase mismatch handled by scripts (53C895A or 53C896),
- ** set PM jump addresses.
+ ** If phase mismatch handled by scripts (53C895A or 53C896
+ ** or 53C1010 or 53C1010_66), set PM jump addresses.
*/
if (np->features & FE_NOPM) {
@@ -7475,9 +8051,10 @@
OUTB (nc_dien , MDPE|BF|SSI|SIR|IID);
/*
- ** For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+ ** For 895/895A/896/c1010
+ ** Enable SBMC interrupt and save current SCSI bus mode.
*/
- if (np->features & FE_ULTRA2) {
+ if ( (np->features & FE_ULTRA2) || (np->features & FE_ULTRA3) ) {
OUTONW (nc_sien, SBMC);
np->scsi_mode = INB (nc_stest4) & SMODE;
}
@@ -7496,6 +8073,7 @@
tp->sval = 0;
tp->wval = np->rv_scntl3;
+ tp->uval = np->rv_scntl4;
if (tp->usrsync != 255) {
if (tp->usrsync <= np->maxsync) {
@@ -7626,6 +8204,10 @@
/*
** Compute the synchronous period in tenths of nano-seconds
+ ** from sfac.
+ **
+ ** Note, if sfac == 9, DT is being used. Double the period of 125
+ ** to 250.
*/
if (sfac <= 10) per = 250;
else if (sfac == 11) per = 303;
@@ -7673,7 +8255,76 @@
** Compute and return sync parameters for the ncr
*/
*fakp = fak - 4;
- *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+
+ /*
+ ** If sfac < 25, and 8xx parts, desire that the chip operate at
+ ** least at Ultra speeds. Must set bit 7 of scntl3.
+ ** For C1010, do not set this bit. If operating at Ultra3 speeds,
+ ** set the U3EN bit instead.
+ */
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ *scntl3p = (div+1) << 4;
+ *fakp = 0;
+ }
+ else {
+ *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+ *fakp = fak - 4;
+ }
+}
+
+/*==========================================================
+**
+** Utility routine to return the current bus width
+** synchronous period and offset.
+** Utilizes target sval, wval and uval
+**
+**==========================================================
+*/
+static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor,
+ u_char *offset, u_char *width)
+{
+
+ u_char idiv;
+ u_long period;
+
+ *width = (tp->wval & EWS) ? 1 : 0;
+
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+ *offset = (tp->sval & 0x3f);
+ else
+ *offset = (tp->sval & 0x1f);
+
+ /*
+ * Midlayer signal to the driver that all of the scsi commands
+ * for the integrity check have completed. Save the negotiated
+ * parameters (extracted from sval, wval and uval).
+ * See ncr_setsync for alg. details.
+ */
+
+ idiv = (tp->wval>>4) & 0x07;
+
+ if ( *offset && idiv ) {
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){
+ if (tp->uval & 0x80)
+ period = (2*div_10M[idiv-1])/np->clock_khz;
+ else
+ period = (4*div_10M[idiv-1])/np->clock_khz;
+ }
+ else
+ period = (((tp->sval>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+ }
+ else
+ period = 0xffff;
+
+ if (period <= 125) *factor = 9;
+ else if (period <= 250) *factor = 10;
+ else if (period <= 303) *factor = 11;
+ else if (period <= 500) *factor = 12;
+ else *factor = (period + 40 - 1) / 40;
+
}
@@ -7687,14 +8338,20 @@
static void ncr_set_sync_wide_status (ncb_p np, u_char target)
{
- ccb_p cp;
+ ccb_p cp = np->ccbc;
tcb_p tp = &np->target[target];
/*
** set actual value and sync_status
+ **
+ ** TEMP register contains current scripts address
+ ** which is data type/direction/dependent.
*/
OUTB (nc_sxfer, tp->sval);
OUTB (nc_scntl3, tp->wval);
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+ OUTB (nc_scntl4, tp->uval);
/*
** patch ALL ccbs of this target.
@@ -7706,6 +8363,9 @@
continue;
cp->phys.select.sel_scntl3 = tp->wval;
cp->phys.select.sel_sxfer = tp->sval;
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+ cp->phys.select.sel_scntl4 = tp->uval;
};
}
@@ -7716,11 +8376,13 @@
**==========================================================
*/
-static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer)
+static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer,
+ u_char scntl4)
{
tcb_p tp;
u_char target = INB (nc_sdid) & 0x0f;
u_char idiv;
+ u_char offset;
assert (cp);
if (!cp) return;
@@ -7729,9 +8391,21 @@
tp = &np->target[target];
- if (!scntl3 || !(sxfer & 0x1f))
- scntl3 = np->rv_scntl3;
- scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07);
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ offset = sxfer & 0x3f; /* bits 5-0 */
+ scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS);
+ scntl4 = (scntl4 & 0x80);
+ }
+ else {
+ offset = sxfer & 0x1f; /* bits 4-0 */
+ if (!scntl3 || !offset)
+ scntl3 = np->rv_scntl3;
+
+ scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) |
+ (np->rv_scntl3 & 0x07);
+ }
+
/*
** Deduce the value of controller sync period from scntl3.
@@ -7739,27 +8413,42 @@
*/
idiv = ((scntl3 >> 4) & 0x7);
- if ((sxfer & 0x1f) && idiv)
- tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+ if ( offset && idiv) {
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ /* Note: If extra data hold clocks are used,
+ * the formulas below must be modified.
+ * When scntl4 == 0, ST mode.
+ */
+ if (scntl4 & 0x80)
+ tp->period = (2*div_10M[idiv-1])/np->clock_khz;
+ else
+ tp->period = (4*div_10M[idiv-1])/np->clock_khz;
+ }
+ else
+ tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+ }
else
tp->period = 0xffff;
+
/*
** Stop there if sync parameters are unchanged
*/
- if (tp->sval == sxfer && tp->wval == scntl3) return;
+ if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return;
tp->sval = sxfer;
tp->wval = scntl3;
+ tp->uval = scntl4;
/*
** Bells and whistles ;-)
** Donnot announce negotiations due to auto-sense,
** unless user really want us to be verbose. :)
*/
- if (bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+ if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
goto next;
PRINT_TARGET(np, target);
- if (sxfer & 0x01f) {
+ if (offset) {
unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
unsigned mb10 = (f10 + tp->period/2) / tp->period;
char *scsi;
@@ -7767,19 +8456,23 @@
/*
** Disable extended Sreq/Sack filtering
*/
- if (tp->period <= 2000) OUTOFFB (nc_stest2, EXT);
+ if ((tp->period <= 2000) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+ OUTOFFB (nc_stest2, EXT);
/*
** Bells and whistles ;-)
*/
- if (tp->period < 500) scsi = "FAST-40";
+ if (tp->period < 250) scsi = "FAST-80";
+ else if (tp->period < 500) scsi = "FAST-40";
else if (tp->period < 1000) scsi = "FAST-20";
else if (tp->period < 2000) scsi = "FAST-10";
else scsi = "FAST-5";
printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
tp->widedone > 1 ? "WIDE " : "",
- mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
+ mb10 / 10, mb10 % 10, tp->period / 10, offset);
} else
printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
next:
@@ -7790,6 +8483,7 @@
ncr_set_sync_wide_status(np, target);
}
+
/*==========================================================
**
** Switch wide mode for current job and it's target
@@ -7843,6 +8537,126 @@
ncr_set_sync_wide_status(np, target);
}
+
+/*==========================================================
+**
+** Switch sync/wide mode for current job and it's target
+** PPR negotiations only
+**
+**==========================================================
+*/
+
+static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer,
+ u_char scntl4, u_char wide)
+{
+ tcb_p tp;
+ u_char target = INB (nc_sdid) & 0x0f;
+ u_char idiv;
+ u_char offset;
+
+ assert (cp);
+ if (!cp) return;
+
+ assert (target == (cp->target & 0xf));
+
+ tp = &np->target[target];
+ tp->widedone = wide+1;
+
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ offset = sxfer & 0x3f; /* bits 5-0 */
+ scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0);
+ scntl4 = (scntl4 & 0x80);
+ }
+ else {
+ offset = sxfer & 0x1f; /* bits 4-0 */
+ if (!scntl3 || !offset)
+ scntl3 = np->rv_scntl3;
+
+ scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0) |
+ (np->rv_scntl3 & 0x07);
+ }
+
+
+ /*
+ ** Deduce the value of controller sync period from scntl3.
+ ** period is in tenths of nano-seconds.
+ */
+
+ idiv = ((scntl3 >> 4) & 0x7);
+ if ( offset && idiv) {
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ /* Note: If extra data hold clocks are used,
+ * the formulas below must be modified.
+ * When scntl4 == 0, ST mode.
+ */
+ if (scntl4 & 0x80)
+ tp->period = (2*div_10M[idiv-1])/np->clock_khz;
+ else
+ tp->period = (4*div_10M[idiv-1])/np->clock_khz;
+ }
+ else
+ tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+ }
+ else
+ tp->period = 0xffff;
+
+
+ /*
+ ** Stop there if sync parameters are unchanged
+ */
+ if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return;
+ tp->sval = sxfer;
+ tp->wval = scntl3;
+ tp->uval = scntl4;
+
+ /*
+ ** Bells and whistles ;-)
+ ** Donnot announce negotiations due to auto-sense,
+ ** unless user really want us to be verbose. :)
+ */
+ if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+ goto next;
+ PRINT_TARGET(np, target);
+ if (offset) {
+ unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
+ unsigned mb10 = (f10 + tp->period/2) / tp->period;
+ char *scsi;
+
+ /*
+ ** Disable extended Sreq/Sack filtering
+ */
+ if ((tp->period <= 2000) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+ OUTOFFB (nc_stest2, EXT);
+
+ /*
+ ** Bells and whistles ;-)
+ */
+ if (tp->period < 250) scsi = "FAST-80";
+ else if (tp->period < 500) scsi = "FAST-40";
+ else if (tp->period < 1000) scsi = "FAST-20";
+ else if (tp->period < 2000) scsi = "FAST-10";
+ else scsi = "FAST-5";
+
+ printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+ tp->widedone > 1 ? "WIDE " : "",
+ mb10 / 10, mb10 % 10, tp->period / 10, offset);
+ } else
+ printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
+next:
+ /*
+ ** set actual value and sync_status
+ ** patch ALL ccbs of this target.
+ */
+ ncr_set_sync_wide_status(np, target);
+}
+
+
+
+
/*==========================================================
**
** Switch tagged mode for a target.
@@ -8452,6 +9266,28 @@
ncr_log_hard_error(np, sist, dstat);
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ u_char ctest4_o, ctest4_m;
+ u_char shadow;
+
+ /*
+ * Get shadow register data
+ * Write 1 to ctest4
+ */
+ ctest4_o = INB(nc_ctest4);
+
+ OUTB(nc_ctest4, ctest4_o | 0x10);
+
+ ctest4_m = INB(nc_ctest4);
+ shadow = INW_OFF(0x42);
+
+ OUTB(nc_ctest4, ctest4_o);
+
+ printk("%s: ctest4/sist original 0x%x/0x%X mod: 0x%X/0x%x\n",
+ ncr_name(np), ctest4_o, sist, ctest4_m, shadow);
+ }
+
if ((sist & (GEN|HTH|SGE)) ||
(dstat & (MDPE|BF|ABRT|IID))) {
ncr_start_reset(np);
@@ -8577,6 +9413,20 @@
*/
void ncr_int_udc (ncb_p np)
{
+ u_int32 dsa = INL (nc_dsa);
+ ccb_p cp = ncr_ccb_from_dsa(np, dsa);
+ tcb_p tp = &np->target[cp->target];
+
+ /*
+ * Fix Up. Some disks respond to a PPR negotation with
+ * a bus free instead of a message reject.
+ * Disable ppr negotiation if this is first time
+ * tried ppr negotiation.
+ */
+
+ if (tp->ppr_negotiation == 1)
+ tp->ppr_negotiation = 0;
+
printk ("%s: unexpected disconnect\n", ncr_name(np));
ncr_recover_scsi_int(np, HS_UNEXPECTED);
}
@@ -8688,6 +9538,7 @@
/*
** Keep track of the parity error.
*/
+ OUTONB (HF_PRT, HF_EXT_ERR);
cp->xerr_status |= XE_PARITY_ERR;
/*
@@ -8695,14 +9546,22 @@
*/
np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR;
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ /*
+ ** Save error message. For integrity check use only.
+ */
+ if (np->check_integrity)
+ np->check_integ_par = np->msgout[0];
+#endif
+
/*
- ** If the old phase was DATA IN phase, we have to deal with
- ** the 3 situations described above.
+ ** If the old phase was DATA IN or DT DATA IN phase,
+ ** we have to deal with the 3 situations described above.
** For other input phases (MSG IN and STATUS), the device
** must resend the whole thing that failed parity checking
** or signal error. So, jumping to dispatcher should be OK.
*/
- if (phase == 1) {
+ if ((phase == 1) || (phase == 5)) {
/* Phase mismatch handled by SCRIPTS */
if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle))
OUTL (nc_dsp, dsp);
@@ -8772,45 +9631,64 @@
*/
cp = ncr_ccb_from_dsa(np, dsa);
+ if (DEBUG_FLAGS & DEBUG_PHASE)
+ printk("CCB = %2x %2x %2x %2x %2x %2x\n",
+ cp->cmd->cmnd[0], cp->cmd->cmnd[1], cp->cmd->cmnd[2],
+ cp->cmd->cmnd[3], cp->cmd->cmnd[4], cp->cmd->cmnd[5]);
+
/*
** Donnot take into account dma fifo and various buffers in
** INPUT phase since the chip flushes everything before
** raising the MA interrupt for interrupted INPUT phases.
** For DATA IN phase, we will check for the SWIDE later.
*/
- if ((cmd & 7) != 1) {
+ if ( !(((cmd & 7) == 1) || ((cmd & 7) == 5) ) ) {
u_int32 dfifo;
u_char ss0, ss2;
/*
- ** Read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
+ ** If C1010, DFBC contains number of bytes in DMA fifo.
+ ** else read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
*/
- dfifo = INL(nc_dfifo);
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+ delta = INL(nc_dfbc) & 0xffff;
+ else {
+ dfifo = INL(nc_dfifo);
- /*
- ** Calculate remaining bytes in DMA fifo.
- ** (CTEST5 = dfifo >> 16)
- */
- if (dfifo & (DFS << 16))
- delta = ((((dfifo >> 8) & 0x300) |
- (dfifo & 0xff)) - rest) & 0x3ff;
- else
- delta = ((dfifo & 0xff) - rest) & 0x7f;
+ /*
+ ** Calculate remaining bytes in DMA fifo.
+ ** C1010 - always large fifo, value in dfbc
+ ** Otherwise, (CTEST5 = dfifo >> 16)
+ */
+ if (dfifo & (DFS << 16))
+ delta = ((((dfifo >> 8) & 0x300) |
+ (dfifo & 0xff)) - rest) & 0x3ff;
+ else
+ delta = ((dfifo & 0xff) - rest) & 0x7f;
- /*
- ** The data in the dma fifo has not been transfered to
- ** the target -> add the amount to the rest
- ** and clear the data.
- ** Check the sstat2 register in case of wide transfer.
- */
+ /*
+ ** The data in the dma fifo has not been
+ ** transferred to the target -> add the amount
+ ** to the rest and clear the data.
+ ** Check the sstat2 register in case of wide
+ ** transfer.
+ */
+
+ }
+
rest += delta;
ss0 = INB (nc_sstat0);
if (ss0 & OLF) rest++;
- if (ss0 & ORF) rest++;
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss0 & ORF))
+ rest++;
if (cp && (cp->phys.select.sel_scntl3 & EWS)) {
ss2 = INB (nc_sstat2);
if (ss2 & OLF1) rest++;
- if (ss2 & ORF1) rest++;
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss2 & ORF))
+ rest++;
};
/*
@@ -8902,9 +9780,10 @@
/*
** if old phase not dataphase, leave here.
+ ** C/D line is low if data.
*/
- if (cmd & 0x06) {
+ if (cmd & 0x02) {
PRINT_ADDR(cp->cmd);
printk ("phase change %x-%x %d@%08x resid=%d.\n",
cmd&7, INB(nc_sbcl)&7, (unsigned)olen,
@@ -8962,45 +9841,42 @@
** - move current data pointer context by one byte.
*/
nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
- if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
+ if ( ((cmd & 7) == 1 || (cmd & 7) == 5)
+ && cp && (cp->phys.select.sel_scntl3 & EWS) &&
(INB (nc_scntl2) & WSR)) {
- /*
- ** Hmmm... The device may want to also ignore
- ** this residue but it must send immediately the
- ** appropriate message. We snoop the SCSI BUS
- ** and will just throw away this message from
- ** SCRIPTS if the SWIDE is to be ignored.
- */
- if ((INB (nc_sbcl) & 7) == 7 &&
- INB (nc_sbdl) == M_IGN_RESIDUE) {
- nxtdsp = NCB_SCRIPT_PHYS (np, ign_i_w_r_msg);
- }
- /*
- ** We must grab the SWIDE.
- ** We will use some complex SCRIPTS for that.
- */
- else {
- OUTL (nc_scratcha, pm->sg.addr);
- nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_32);
- if (np->features & FE_64BIT) {
- OUTB (nc_sbr, (pm->sg.size >> 24));
- nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_64);
- }
- /*
- ** Adjust our data pointer context.
- */
- ++pm->sg.addr;
- --pm->sg.size;
- /*
- ** Hmmm... Could it be possible that a SWIDE that
- ** is followed by a 1 byte CHMOV would lead to
- ** a CHMOV(0). Anyway, we handle it by just
- ** skipping context that would attempt a CHMOV(0).
- */
- if (!pm->sg.size)
- newcmd = pm->ret;
- }
- }
+ u32 tmp;
+
+#ifdef SYM_DEBUG_PM_WITH_WSR
+ PRINT_ADDR(cp);
+ printf ("MA interrupt with WSR set - "
+ "pm->sg.addr=%x - pm->sg.size=%d\n",
+ pm->sg.addr, pm->sg.size);
+#endif
+ /*
+ * Set up the table indirect for the MOVE
+ * of the residual byte and adjust the data
+ * pointer context.
+ */
+ tmp = scr_to_cpu(pm->sg.addr);
+ cp->phys.wresid.addr = cpu_to_scr(tmp);
+ pm->sg.addr = cpu_to_scr(tmp + 1);
+ tmp = scr_to_cpu(pm->sg.size);
+ cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1);
+ pm->sg.size = cpu_to_scr(tmp - 1);
+
+ /*
+ * If only the residual byte is to be moved,
+ * no PM context is needed.
+ */
+ if ((tmp&0xffffff) == 1)
+ newcmd = pm->ret;
+
+ /*
+ * Prepare the address of SCRIPTS that will
+ * move the residual byte to memory.
+ */
+ nxtdsp = NCB_SCRIPTH_PHYS (np, wsr_ma_helper);
+ }
if (DEBUG_FLAGS & DEBUG_PHASE) {
PRINT_ADDR(cp->cmd);
@@ -9076,7 +9952,8 @@
nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break);
}
else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) ||
- dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) {
+ dsp == NCB_SCRIPTH_PHYS (np, send_sdtr) ||
+ dsp == NCB_SCRIPTH_PHYS (np, send_ppr)) {
nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase);
}
break;
@@ -9277,12 +10154,56 @@
** to be stuck with WIDE and/or SYNC data transfer.
**
** cp->nego_status is filled by ncr_prepare_nego().
+ **
+ ** Do NOT negotiate if performing integrity check
+ ** or if integrity check has completed, all check
+ ** conditions will have been cleared.
+ */
+
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+ if (DEBUG_FLAGS & DEBUG_IC) {
+ printk("%s: ncr_sir_to_redo: ic_done %2X, in_progress %2X\n",
+ ncr_name(np), tp->ic_done, cp->cmd->ic_in_progress);
+ }
+
+ /*
+ ** If parity error during integrity check,
+ ** set the target width to narrow. Otherwise,
+ ** do not negotiate on a request sense.
*/
+ if ( np->check_integ_par && np->check_integrity
+ && cp->cmd->ic_in_progress ) {
+ cp->nego_status = 0;
+ msglen +=
+ ncr_ic_nego (np, cp, cmd ,&cp->scsi_smsg2[msglen]);
+ }
+
+ if (!np->check_integrity ||
+ (np->check_integrity &&
+ (!cp->cmd->ic_in_progress && !tp->ic_done)) ) {
+ ncr_negotiate(np, tp);
+ cp->nego_status = 0;
+ {
+ u_char sync_offset;
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+ sync_offset = tp->sval & 0x3f;
+ else
+ sync_offset = tp->sval & 0x1f;
+
+ if ((tp->wval & EWS) || sync_offset)
+ msglen +=
+ ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+ }
+
+ }
+#else
ncr_negotiate(np, tp);
cp->nego_status = 0;
if ((tp->wval & EWS) || (tp->sval & 0x1f))
msglen +=
ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+#endif /* SCSI_NCR_INTEGRITY_CHECKING */
/*
** Message table indirect structure.
@@ -9489,6 +10410,7 @@
np->abrt_sel.sel_id = target;
np->abrt_sel.sel_scntl3 = tp->wval;
np->abrt_sel.sel_sxfer = tp->sval;
+ np->abrt_sel.sel_scntl4 = tp->uval;
OUTL(nc_dsa, np->p_ncb);
OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
return;
@@ -9696,6 +10618,7 @@
if (np->abrt_msg[0] == M_RESET) {
tp->sval = 0;
tp->wval = np->rv_scntl3;
+ tp->uval = np->rv_scntl4;
ncr_set_sync_wide_status(np, target);
ncr_negotiate(np, tp);
}
@@ -10014,11 +10937,30 @@
static int ncr_compute_residual(ncb_p np, ccb_p cp)
{
- int dp_sg, dp_sgmin, resid, tmp;
+ int dp_sg, dp_sgmin, tmp;
+ int resid=0;
int dp_ofs = 0;
/*
- ** Should have been checked by the caller.
+ * Check for some data lost or just thrown away.
+ * We are not required to be quite accurate in this
+ * situation. Btw, if we are odd for output and the
+ * device claims some more data, it may well happen
+ * than our residual be zero. :-)
+ */
+ if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) {
+ if (cp->xerr_status & XE_EXTRA_DATA)
+ resid -= scr_to_cpu(cp->phys.extra_bytes);
+ if (cp->xerr_status & XE_SODL_UNRUN)
+ ++resid;
+ if (cp->xerr_status & XE_SWIDE_OVRUN)
+ --resid;
+ }
+
+
+ /*
+ ** If all data has been transferred,
+ ** there is no residual.
*/
if (cp->phys.header.lastp == cp->phys.header.goalp)
return 0;
@@ -10159,7 +11101,7 @@
*/
static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp)
{
- u_char scntl3;
+ u_char scntl3, scntl4;
u_char chg, ofs, per, fak;
/*
@@ -10203,6 +11145,7 @@
*/
fak = 7;
scntl3 = 0;
+ scntl4 = 0;
if (ofs != 0) {
ncr_getsync(np, per, &fak, &scntl3);
if (fak > 7) {
@@ -10214,13 +11157,14 @@
fak = 7;
per = 0;
scntl3 = 0;
+ scntl4 = 0;
tp->minsync = 0;
}
if (DEBUG_FLAGS & DEBUG_NEGO) {
PRINT_ADDR(cp->cmd);
- printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
- per, scntl3, ofs, fak, chg);
+ printk ("sync: per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n",
+ per, scntl3, scntl4, ofs, fak, chg);
}
if (INB (HS_PRT) == HS_NEGOTIATE) {
@@ -10234,13 +11178,18 @@
/*
** Answer wasn't acceptable.
*/
- ncr_setsync (np, cp, 0, 0xe0);
+ ncr_setsync (np, cp, 0, 0xe0, 0);
OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
} else {
/*
** Answer is ok.
*/
- ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+ ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0);
+ else
+ ncr_setsync (np, cp, scntl3, ofs, scntl4);
+
OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
};
return;
@@ -10256,7 +11205,11 @@
** prepare an answer message
*/
- ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+ ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0);
+ else
+ ncr_setsync (np, cp, scntl3, ofs, scntl4);
np->msgout[0] = M_EXTENDED;
np->msgout[1] = 3;
@@ -10350,7 +11303,7 @@
return;
case NS_SYNC:
- ncr_setsync (np, cp, 0, 0xe0);
+ ncr_setsync (np, cp, 0, 0xe0, 0);
break;
};
};
@@ -10377,6 +11330,205 @@
OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp));
}
+/*==========================================================
+**
+** ncr chip handler for PARALLEL PROTOCOL REQUEST
+** (PPR) message.
+**
+**==========================================================
+**
+** Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_ppr_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+ u_char scntl3, scntl4;
+ u_char chg, ofs, per, fak, wth, dt;
+
+ /*
+ ** PPR message received.
+ */
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, "ppr msg in", np->msgin);
+ };
+
+ /*
+ ** get requested values.
+ */
+
+ chg = 0;
+ per = np->msgin[3];
+ ofs = np->msgin[5];
+ wth = np->msgin[6];
+ dt = np->msgin[7];
+ if (ofs==0) per=255;
+
+ /*
+ ** if target sends sync (wide),
+ ** it CAN transfer synch (wide).
+ */
+
+ if (ofs)
+ tp->inq_byte7 |= INQ7_SYNC;
+
+ if (wth)
+ tp->inq_byte7 |= INQ7_WIDE16;
+
+ /*
+ ** check values against driver limits.
+ */
+
+ if (wth > tp->usrwide)
+ {chg = 1; wth = tp->usrwide;}
+ if (per < np->minsync)
+ {chg = 1; per = np->minsync;}
+ if (per < tp->minsync)
+ {chg = 1; per = tp->minsync;}
+ if (ofs > tp->maxoffs)
+ {chg = 1; ofs = tp->maxoffs;}
+
+ /*
+ ** Check against controller limits.
+ */
+ fak = 7;
+ scntl3 = 0;
+ scntl4 = 0;
+ if (ofs != 0) {
+ scntl4 = dt ? 0x80 : 0;
+ ncr_getsync(np, per, &fak, &scntl3);
+ if (fak > 7) {
+ chg = 1;
+ ofs = 0;
+ }
+ }
+ if (ofs == 0) {
+ fak = 7;
+ per = 0;
+ scntl3 = 0;
+ scntl4 = 0;
+ tp->minsync = 0;
+ }
+
+ /*
+ ** If target responds with Ultra 3 speed
+ ** but narrow or not DT, reject.
+ ** If target responds with DT request
+ ** but not Ultra3 speeds, reject message,
+ ** reset min sync for target to 0x0A and
+ ** set flags to re-negotiate.
+ */
+
+ if ((per == 0x09) && ofs && (!wth || !dt))
+ chg = 1;
+ else if (( (per > 0x09) && dt) )
+ chg = 2;
+
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->cmd);
+ printk ("ppr: wth=%d per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n",
+ wth, per, scntl3, scntl4, ofs, fak, chg);
+ }
+
+ if (INB (HS_PRT) == HS_NEGOTIATE) {
+ OUTB (HS_PRT, HS_BUSY);
+ switch (cp->nego_status) {
+ case NS_PPR:
+ /*
+ ** This was an answer message
+ */
+ if (chg) {
+ /*
+ ** Answer wasn't acceptable.
+ */
+ if (chg == 2) {
+ /* Send message reject and reset flags for
+ ** host to re-negotiate with min period 0x0A.
+ */
+ tp->minsync = 0x0A;
+ tp->period = 0;
+ tp->widedone = 0;
+ }
+ ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0);
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+ } else {
+ /*
+ ** Answer is ok.
+ */
+
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+ ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth);
+ else
+ ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
+
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+
+ };
+ return;
+
+ case NS_SYNC:
+ ncr_setsync (np, cp, 0, 0xe0, 0);
+ break;
+
+ case NS_WIDE:
+ ncr_setwide (np, cp, 0, 0);
+ break;
+ };
+ };
+
+ /*
+ ** It was a request. Set value and
+ ** prepare an answer message
+ **
+ ** If narrow or not DT and requesting Ultra3
+ ** slow the bus down and force ST. If not
+ ** requesting Ultra3, force ST.
+ ** Max offset is 31=0x1f if ST mode.
+ */
+
+ if ((per == 0x09) && ofs && (!wth || !dt)) {
+ per = 0x0A;
+ dt = 0;
+ ofs &= 0x1f;
+ }
+ else if ( (per > 0x09) && dt) {
+ dt = 0;
+ ofs &= 0x1f;
+ }
+
+ if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+ ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth);
+ else
+ ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
+
+ np->msgout[0] = M_EXTENDED;
+ np->msgout[1] = 6;
+ np->msgout[2] = M_X_PPR_REQ;
+ np->msgout[3] = per;
+ np->msgout[4] = 0;
+ np->msgout[5] = ofs;
+ np->msgout[6] = wth;
+ np->msgout[7] = dt;
+
+ cp->nego_status = NS_PPR;
+
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, "ppr msgout", np->msgout);
+ }
+
+ np->msgin [0] = M_NOOP;
+
+ if (!ofs)
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+ else
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, ppr_resp));
+}
+
+
/*
** Reset SYNC or WIDE to default settings.
@@ -10392,13 +11544,45 @@
switch (cp->nego_status) {
case NS_SYNC:
- ncr_setsync (np, cp, 0, 0xe0);
+ ncr_setsync (np, cp, 0, 0xe0, 0);
break;
case NS_WIDE:
ncr_setwide (np, cp, 0, 0);
break;
+ case NS_PPR:
+ /*
+ * ppr_negotiation is set to 1 on the first ppr nego command.
+ * If ppr is successful, it is reset to 2.
+ * If unsuccessful it is reset to 0.
+ */
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ tcb_p tp=&np->target[cp->target];
+ u_char factor, offset, width;
+
+ ncr_get_xfer_info ( np, tp, &factor, &offset, &width);
+
+ printk("Current factor %d offset %d width %d\n",
+ factor, offset, width);
+ }
+ if (tp->ppr_negotiation == 2)
+ ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0);
+ else if (tp->ppr_negotiation == 1) {
+
+ /* First ppr command has received a M REJECT.
+ * Do not change the existing wide/sync parameter
+ * values (asyn/narrow if this as the first nego;
+ * may be different if target initiates nego.).
+ */
+ tp->ppr_negotiation = 0;
+ }
+ else
+ {
+ tp->ppr_negotiation = 0;
+ ncr_setwide (np, cp, 0, 0);
+ }
+ break;
};
np->msgin [0] = M_NOOP;
np->msgout[0] = M_NOOP;
@@ -10410,6 +11594,9 @@
** ncr chip handler for MESSAGE REJECT received for
** a WIDE or SYNCHRONOUS negotiation.
**
+** clear the PPR negotiation flag, all future nego.
+** will be SDTR and WDTR
+**
**==========================================================
**
** Read comments above.
@@ -10451,6 +11638,7 @@
case SIR_DUMMY_INTERRUPT:
goto out;
#endif
+
/*
** The C code is currently trying to recover from something.
** Typically, user want to abort some command.
@@ -10529,8 +11717,11 @@
np->msgout[0] = M_NOOP;
/* Should we really care of that */
if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
- if (cp)
+ if (cp) {
cp->xerr_status &= ~XE_PARITY_ERR;
+ if (!cp->xerr_status)
+ OUTOFFB (HF_PRT, HF_EXT_ERR);
+ }
}
goto out;
/*
@@ -10558,8 +11749,10 @@
** It is a data overrun condition.
*/
case SIR_SWIDE_OVERRUN:
- if (cp)
- cp->xerr_status |= XE_EXTRA_DATA;
+ if (cp) {
+ OUTONB (HF_PRT, HF_EXT_ERR);
+ cp->xerr_status |= XE_SWIDE_OVRUN;
+ }
goto out;
/*
** We have been ODD at the end of a DATA OUT
@@ -10567,8 +11760,10 @@
** It is a data underrun condition.
*/
case SIR_SODL_UNDERRUN:
- if (cp)
- cp->xerr_status |= XE_EXTRA_DATA;
+ if (cp) {
+ OUTONB (HF_PRT, HF_EXT_ERR);
+ cp->xerr_status |= XE_SODL_UNRUN;
+ }
goto out;
/*
** We received a message.
@@ -10597,6 +11792,9 @@
case M_X_WIDE_REQ:
ncr_wide_nego(np, tp, cp);
return;
+ case M_X_PPR_REQ:
+ ncr_ppr_nego(np, tp, cp);
+ return;
default:
goto out_reject;
}
@@ -10910,6 +12108,11 @@
offsetof(struct tcb , sval )) &3) == 0);
assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
offsetof(struct tcb , wval )) &3) == 0);
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){
+ assert (( (offsetof(struct ncr_reg, nc_scntl4) ^
+ offsetof(struct tcb , uval )) &3) == 0);
+ }
}
/*------------------------------------------------------------------------
@@ -11446,7 +12649,8 @@
** do not have a clock doubler and so are provided with a
** 80 MHz clock. All other fast20 boards incorporate a doubler
** and so should be delivered with a 40 MHz clock.
-** The recent fast40 chips (895/896/895A) use a 40 Mhz base clock
+** The recent fast40 chips (895/896/895A) and the
+** fast80 chip (C1010) use a 40 Mhz base clock
** and provide a clock quadrupler (160 Mhz). The code below
** tries to deal as cleverly as possible with all this stuff.
**
@@ -11467,14 +12671,20 @@
printk ("%s: enabling clock multiplier\n", ncr_name(np));
OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */
- if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */
- int i = 20;
+
+ if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+ (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) &&
+ (np->multiplier > 2)) {
+ int i = 20; /* Poll bit 5 of stest4 for quadrupler */
while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
UDELAY (20);
if (!i)
- printk("%s: the chip cannot lock the frequency\n", ncr_name(np));
- } else /* Wait 20 micro-seconds for doubler */
- UDELAY (20);
+ printk("%s: the chip cannot lock the frequency\n",
+ ncr_name(np));
+
+ } else /* Wait 120 micro-seconds for multiplier*/
+ UDELAY (120);
+
OUTB(nc_stest3, HSC); /* Halt the scsi clock */
OUTB(nc_scntl3, scntl3);
OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
@@ -11489,6 +12699,7 @@
{
unsigned int ms = 0;
unsigned int f;
+ int count;
/*
* Measure GEN timer delay in order
@@ -11505,15 +12716,21 @@
* performed trust the higher delay
* (lower frequency returned).
*/
- OUTW (nc_sien , 0); /* mask all scsi interrupts */
+ OUTW (nc_sien , 0x0);/* mask all scsi interrupts */
+ /* enable general purpose timer */
(void) INW (nc_sist); /* clear pending scsi interrupt */
OUTB (nc_dien , 0); /* mask all dma interrupts */
(void) INW (nc_sist); /* another one, just to be sure :) */
OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */
OUTB (nc_stime1, 0); /* disable general purpose timer */
OUTB (nc_stime1, gen); /* set to nominal delay of 1<<gen * 125us */
- while (!(INW(nc_sist) & GEN) && ms++ < 100000)
- UDELAY (1000); /* count ms */
+ /* Temporary fix for udelay issue with Alpha
+ platform */
+ while (!(INW(nc_sist) & GEN) && ms++ < 100000) {
+ /* count 1ms */
+ for (count = 0; count < 10; count++)
+ UDELAY (100);
+ }
OUTB (nc_stime1, 0); /* disable general purpose timer */
/*
* set prescaler to divide by whatever 0 means
@@ -11524,7 +12741,14 @@
/*
* adjust for prescaler, and convert into KHz
+ * scale values derived empirically. C1010 uses
+ * different dividers
*/
+#if 0
+ if (np->device_id == PCI_DEVICE_ID_LSI_53C1010)
+ f = ms ? ((1 << gen) * 2866 ) / ms : 0;
+ else
+#endif
f = ms ? ((1 << gen) * 4340) / ms : 0;
if (bootverbose >= 2)
@@ -11568,11 +12792,19 @@
}
/*
+ ** If multiplier not found but a C1010, assume a mult of 4.
** If multiplier not found or scntl3 not 7,5,3,
** reset chip and get frequency from general purpose timer.
** Otherwise trust scntl3 BIOS setting.
*/
- if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
+ if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+ f1=40000;
+ np->multiplier = mult;
+ if (bootverbose >= 2)
+ printk ("%s: clock multiplier assumed\n", ncr_name(np));
+ }
+ else if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
OUTB (nc_stest1, 0); /* make sure doubler is OFF */
f1 = ncr_getfreq (np);
@@ -11587,8 +12819,14 @@
** to make sure our frequency calculation algorithm
** is not too biased.
*/
- np->pciclock_min = (33000*55+80-1)/80;
- np->pciclock_max = (33000*55)/40;
+ if (np->features & FE_66MHZ) {
+ np->pciclock_min = (66000*55+80-1)/80;
+ np->pciclock_max = (66000*55)/40;
+ }
+ else {
+ np->pciclock_min = (33000*55+80-1)/80;
+ np->pciclock_max = (33000*55)/40;
+ }
if (f1 == 40000 && mult > 1) {
if (bootverbose >= 2)
@@ -11728,7 +12966,8 @@
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
char *cur = str;
char *pc, *pv;
- int i, val, c;
+ unsigned long val;
+ int i, c;
int xi = 0;
while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
@@ -12165,7 +13404,7 @@
static int __init
sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
{
- u_short vendor_id, device_id, command;
+ u_short vendor_id, device_id, command, status_reg;
u_char cache_line_size, latency_timer;
u_char suggested_cache_line_size = 0;
u_char pci_fix_up = driver_setup.pci_fix_up;
@@ -12205,6 +13444,7 @@
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size);
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_timer);
+ pci_read_config_word(pdev, PCI_STATUS, &status_reg);
#ifdef SCSI_NCR_PQS_PDS_SUPPORT
/*
@@ -12402,14 +13642,51 @@
if (driver_setup.special_features & 4)
chip->features &= ~FE_NOPM;
}
+
+ /*
+ ** Work around for errant bit in 895A. The 66Mhz
+ ** capable bit is set erroneously. Clear this bit.
+ ** (Item 1 DEL 533)
+ **
+ ** Make sure Config space and Features agree.
+ **
+ ** Recall: writes are not normal to status register -
+ ** write a 1 to clear and a 0 to leave unchanged.
+ ** Can only reset bits.
+ */
+ if (chip->features & FE_66MHZ) {
+ if (!(status_reg & PCI_STATUS_66MHZ))
+ chip->features &= ~FE_66MHZ;
+ }
+ else {
+ if (status_reg & PCI_STATUS_66MHZ) {
+ status_reg = PCI_STATUS_66MHZ;
+ pci_write_config_word(pdev, PCI_STATUS, status_reg);
+ pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+ }
+ }
+
+ if (driver_setup.ultra_scsi < 3 && (chip->features & FE_ULTRA3)) {
+ chip->features |= FE_ULTRA2;
+ chip->features &= ~FE_ULTRA3;
+ }
if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
chip->features |= FE_ULTRA;
chip->features &= ~FE_ULTRA2;
}
if (driver_setup.ultra_scsi < 1)
chip->features &= ~FE_ULTRA;
+
if (!driver_setup.max_wide)
chip->features &= ~FE_WIDE;
+
+ /*
+ * C1010 Ultra3 support requires 16 bit data transfers.
+ */
+ if (!driver_setup.max_wide && (chip->features & FE_ULTRA3)) {
+ chip->features |= FE_ULTRA2;
+ chip->features |= ~FE_ULTRA3;
+ }
/*
** Some features are required to be enabled in order to
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)