patch-2.1.29 linux/drivers/scsi/ncr53c8xx.c
Next file: linux/drivers/scsi/ncr53c8xx.h
Previous file: linux/drivers/scsi/esp.c
Back to the patch index
Back to the overall index
- Lines: 3519
- Date:
Tue Mar 4 13:22:49 1997
- Orig file:
v2.1.28/linux/drivers/scsi/ncr53c8xx.c
- Orig date:
Mon Jan 13 22:21:41 1997
diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
@@ -40,7 +40,7 @@
*/
/*
-** 12 January 1997, version 1.16e
+** 27 February 1997, version 1.18b
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -57,6 +57,7 @@
** 53C825 (Wide, ~53C820 with on board rom BIOS)
** 53C860 (Narrow fast 20, BIOS required)
** 53C875 (Wide fast 40 with on board rom BIOS)
+** 53C895 (Ultra2 80 MB/s with on board rom BIOS)
**
** Other features:
** Memory mapped IO (linux-1.3.X and above only)
@@ -151,24 +152,6 @@
#endif
/*
-** The maximal synchronous frequency in kHz.
-** (0=asynchronous)
-*/
-
-#ifndef SCSI_NCR_MAX_SYNC
-#define SCSI_NCR_MAX_SYNC (10000)
-#endif
-
-/*
-** The maximal bus with (in log2 byte)
-** (0=8 bit, 1=16 bit)
-*/
-
-#ifndef SCSI_NCR_MAX_WIDE
-#define SCSI_NCR_MAX_WIDE (1)
-#endif
-
-/*
** The maximum number of tags per logic unit.
** Used only for disk devices that support tags.
*/
@@ -352,18 +335,66 @@
** I notice that kmalloc() returns NULL during host attach under
** Linux 1.2.13. But this ncr driver is reliable enough to
** accomodate with this joke.
-**/
+**
+** kmalloc() only ensure 8 bytes boundary alignment.
+** The NCR need better alignment for cache line bursting.
+** The global header is moved betewen the NCB and CCBs and need
+** origin and destination addresses to have same lower four bits.
+**
+** We use 32 boundary alignment for NCB and CCBs and offset multiple
+** of 32 for global header fields. That's too much but at least enough.
+*/
+
+#define ALIGN_SIZE(shift) (1UL << shift)
+#define ALIGN_MASK(shift) (~(ALIGN_SIZE(shift)-1))
+
+#define NCB_ALIGN_SHIFT 5
+#define CCB_ALIGN_SHIFT 5
+#define LCB_ALIGN_SHIFT 5
+#define SCR_ALIGN_SHIFT 5
+
+#define NCB_ALIGN_SIZE ALIGN_SIZE(NCB_ALIGN_SHIFT)
+#define NCB_ALIGN_MASK ALIGN_MASK(NCB_ALIGN_SHIFT)
+#define CCB_ALIGN_SIZE ALIGN_SIZE(CCB_ALIGN_SHIFT)
+#define CCB_ALIGN_MASK ALIGN_MASK(CCB_ALIGN_SHIFT)
+#define SCR_ALIGN_SIZE ALIGN_SIZE(SCR_ALIGN_SHIFT)
+#define SCR_ALIGN_MASK ALIGN_MASK(SCR_ALIGN_SHIFT)
+
+static void *m_alloc(int size, int a_shift)
+{
+ u_long addr;
+ void *ptr;
+ u_long a_size, a_mask;
+
+ if (a_shift < 3)
+ a_shift = 3;
+
+ a_size = ALIGN_SIZE(a_shift);
+ a_mask = ALIGN_MASK(a_shift);
+
+ ptr = (void *) kmalloc(size + a_size, GFP_ATOMIC);
+ if (ptr) {
+ addr = (((u_long) ptr) + a_size) & a_mask;
+ *((void **) (addr - sizeof(void *))) = ptr;
+ ptr = (void *) addr;
+ }
-static void *m_alloc(int size)
-{
- void *ptr = (void *) kmalloc(size, GFP_ATOMIC);
- if (((unsigned long) ptr) & 3)
- panic("ncr53c8xx: kmalloc returns misaligned address %lx\n", (unsigned long) ptr);
return ptr;
}
-static inline void m_free(void *ptr, int size)
- { kfree(ptr); }
+#ifdef MODULE
+static void m_free(void *ptr, int size)
+{
+ u_long addr;
+
+ if (ptr) {
+ addr = (u_long) ptr;
+ ptr = *((void **) (addr - sizeof(void *)));
+
+ kfree(ptr);
+ }
+}
+#endif
/*
** Transfer direction
@@ -431,19 +462,27 @@
** This structure is initialized from linux config options.
** It can be overridden at boot-up by the boot command line.
*/
-static struct {
+struct ncr_driver_setup {
unsigned master_parity : 1;
unsigned scsi_parity : 1;
unsigned disconnection : 1;
unsigned special_features : 1;
- unsigned ultra_scsi : 1;
+ unsigned ultra_scsi : 2;
unsigned force_sync_nego: 1;
- unsigned verbose : 8;
- unsigned default_tags;
- unsigned default_sync;
- unsigned debug;
- unsigned burst_max;
-} driver_setup = SCSI_NCR_DRIVER_SETUP;
+ u_char verbose;
+ u_char default_tags;
+ u_short default_sync;
+ u_short debug;
+ u_char burst_max;
+ u_char led_pin;
+ u_char max_wide;
+ u_char settle_time;
+ u_char diff_support;
+ u_char irqm;
+};
+
+static struct ncr_driver_setup driver_setup = SCSI_NCR_DRIVER_SETUP;
+static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP;
/*
** Other Linux definitions
@@ -719,7 +758,6 @@
*/
#define CCB_MAGIC (0xf2691ad2)
-#define MAX_TAGS (16) /* hard limit */
/*==========================================================
**
@@ -1019,9 +1057,9 @@
** the last transfer command.
*/
- u_long savep;
- u_long lastp;
- u_long goalp;
+ u_int32 savep;
+ u_int32 lastp;
+ u_int32 goalp;
/*
** The virtual address of the ccb
@@ -1152,6 +1190,14 @@
struct ccb {
/*
+ ** This field forces 32 bytes alignement for phys.header,
+ ** in order to use cache line bursting when copying it
+ ** to the ncb.
+ */
+
+ struct link filler[2];
+
+ /*
** during reselection the ncr jumps to this point.
** If a "SIMPLE_TAG" message was received,
** then SFBR is set to the tag.
@@ -1278,6 +1324,16 @@
*/
struct ncb {
+ /*
+ ** The global header.
+ ** Accessible to both the host and the
+ ** script-processor.
+ ** Is 32 bytes aligned since ncb is, in order to
+ ** allow cache line bursting when copying it from or
+ ** to ccbs.
+ */
+ struct head header;
+
/*-----------------------------------------------
** Specific Linux fields
**-----------------------------------------------
@@ -1289,6 +1345,7 @@
Scsi_Cmnd *waiting_list; /* Waiting list header for commands */
/* that we can't put into the squeue */
u_char release_stage; /* Synchronisation stage on release */
+ u_char resetting; /* Reset in progess */
/*-----------------------------------------------
** Added field to support differences
@@ -1310,13 +1367,16 @@
u_char sv_ctest3;
u_char sv_ctest4;
u_char sv_ctest5;
+ u_char sv_gpcntl;
+ u_char sv_stest2;
u_char rv_dmode;
u_char rv_dcntl;
u_char rv_ctest3;
u_char rv_ctest4;
u_char rv_ctest5;
- u_char uf_doubler;
+ u_char rv_stest2;
+ u_char multiplier;
/*-----------------------------------------------
** Scripts ..
@@ -1342,6 +1402,9 @@
vm_offset_t vaddr;
vm_offset_t paddr;
+ vm_offset_t vaddr2;
+ vm_offset_t paddr2;
+
/*
** pointer to the chip's registers.
*/
@@ -1349,14 +1412,22 @@
struct ncr_reg* reg;
/*
- ** A copy of the script, relocated for this ncb.
+ ** A copy of the scripts, relocated for this ncb.
+ */
+ struct script *script0;
+ struct scripth *scripth0;
+
+ /*
+ ** Scripts instance virtual address.
*/
struct script *script;
+ struct scripth *scripth;
/*
- ** Physical address of this instance of ncb->script
+ ** Scripts instance physical address.
*/
u_long p_script;
+ u_long p_scripth;
/*
** The SCSI address of the host adapter.
@@ -1374,6 +1445,12 @@
*/
u_char maxoffs;
+ /*
+ ** controller scsi clock frequency and available divisors
+ */
+ u_long clock_khz;
+ int clock_divn;
+
/*-----------------------------------------------
** Link to the generic SCSI driver
**-----------------------------------------------
@@ -1398,7 +1475,7 @@
/*
** Start queue.
*/
- u_long squeue [MAX_START];
+ u_int32 squeue [MAX_START];
u_short squeueput;
u_short actccbs;
@@ -1427,19 +1504,12 @@
u_long disc_ref;
/*
- ** The global header.
- ** Accessible to both the host and the
- ** script-processor.
- */
- struct head header;
-
- /*
** The global control block.
** It's used only during the configuration phase.
** A target control block will be created
** after the first successful transfer.
*/
- struct ccb ccb;
+ struct ccb *ccb;
/*
** message buffers.
@@ -1449,7 +1519,7 @@
*/
u_char msgout[8];
u_char msgin [8];
- u_long lastmsg;
+ u_int32 lastmsg;
/*
** Buffer for STATUS_IN phase.
@@ -1477,7 +1547,8 @@
u_short irq;
};
-#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl))
+#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl))
+#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth, lbl))
/*==========================================================
**
@@ -1500,12 +1571,15 @@
**----------------------------------------------------------
*/
+/*
+** Script fragments which are loaded into the on-board RAM
+** of 825A, 875 and 895 chips.
+*/
struct script {
ncrcmd start [ 7];
ncrcmd start0 [ 2];
ncrcmd start1 [ 3];
ncrcmd startpos [ 1];
- ncrcmd tryloop [MAX_START*5+2];
ncrcmd trysel [ 8];
ncrcmd skip [ 8];
ncrcmd skip2 [ 3];
@@ -1523,14 +1597,6 @@
ncrcmd status [ 27];
ncrcmd msg_in [ 26];
ncrcmd msg_bad [ 6];
- ncrcmd msg_parity [ 6];
- ncrcmd msg_reject [ 8];
- ncrcmd msg_ign_residue [ 32];
- ncrcmd msg_extended [ 18];
- ncrcmd msg_ext_2 [ 18];
- ncrcmd msg_wdtr [ 27];
- ncrcmd msg_ext_3 [ 18];
- ncrcmd msg_sdtr [ 27];
ncrcmd complete [ 13];
ncrcmd cleanup [ 12];
ncrcmd cleanup0 [ 11];
@@ -1542,6 +1608,30 @@
ncrcmd disconnect1 [ 23];
ncrcmd msg_out [ 9];
ncrcmd msg_out_done [ 7];
+ ncrcmd badgetcc [ 6];
+ ncrcmd reselect [ 8];
+ ncrcmd reselect1 [ 8];
+ ncrcmd reselect2 [ 8];
+ ncrcmd resel_tmp [ 5];
+ ncrcmd resel_lun [ 18];
+ ncrcmd resel_tag [ 24];
+ ncrcmd data_io [ 2]; /* MUST be just before data_in */
+ ncrcmd data_in [MAX_SCATTER * 4 + 7];
+};
+
+/*
+** Script fragments which stay in main memory for all chips.
+*/
+struct scripth {
+ ncrcmd tryloop [MAX_START*5+2];
+ ncrcmd msg_parity [ 6];
+ ncrcmd msg_reject [ 8];
+ ncrcmd msg_ign_residue [ 32];
+ ncrcmd msg_extended [ 18];
+ ncrcmd msg_ext_2 [ 18];
+ ncrcmd msg_wdtr [ 27];
+ ncrcmd msg_ext_3 [ 18];
+ ncrcmd msg_sdtr [ 27];
ncrcmd msg_out_abort [ 10];
ncrcmd getcc [ 4];
ncrcmd getcc1 [ 5];
@@ -1551,14 +1641,6 @@
ncrcmd getcc2 [ 14];
#endif
ncrcmd getcc3 [ 10];
- ncrcmd badgetcc [ 6];
- ncrcmd reselect [ 12];
- ncrcmd reselect2 [ 6];
- ncrcmd resel_tmp [ 5];
- ncrcmd resel_lun [ 18];
- ncrcmd resel_tag [ 24];
- ncrcmd data_io [ 2]; /* MUST be just before data_in */
- ncrcmd data_in [MAX_SCATTER * 4 + 7];
ncrcmd data_out [MAX_SCATTER * 4 + 7];
ncrcmd aborttag [ 4];
ncrcmd abort [ 22];
@@ -1579,7 +1661,8 @@
static void ncr_complete (ncb_p np, ccb_p cp);
static void ncr_exception (ncb_p np);
static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l);
-static void ncr_getclock (ncb_p np);
+static void ncr_getclock (ncb_p np, int mult);
+static void ncr_selectclock (ncb_p np, u_char scntl3);
static void ncr_save_bios_setting (ncb_p np);
static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l);
static void ncr_init (ncb_p np, char * msg, u_long code);
@@ -1596,10 +1679,11 @@
#endif
static void ncr_script_copy_and_bind
- (struct script * script, ncb_p np);
-static void ncr_script_fill (struct script * scr);
+ (ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
+static void ncr_script_fill (struct script * scr, struct scripth * scripth);
static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd);
static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long usrtags);
+static int ncr_getsync (ncb_p np, u_char fac, 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_settags (tcb_p tp, lcb_p lp);
static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide);
@@ -1617,11 +1701,12 @@
int irq, int bus, u_char device_fn);
static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
-static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
+static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd);
static void process_waiting_list(ncb_p np, int sts);
+#define remove_from_waiting_list(np, cmd) \
+ retrieve_from_waiting_list(1, (np), (cmd))
#define requeue_waiting_list(np) process_waiting_list((np), DID_OK)
-#define abort_waiting_list(np) process_waiting_list((np), DID_ABORT)
#define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
/*==========================================================
@@ -1687,10 +1772,12 @@
#define RELOC_LABEL 0x50000000
#define RELOC_REGISTER 0x60000000
#define RELOC_KVAR 0x70000000
+#define RELOC_LABELH 0x80000000
#define RELOC_MASK 0xf0000000
#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label))
#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label))
+#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label))
#define RADDR(label) (RELOC_REGISTER | REG(label))
#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
#define KVAR(which) (RELOC_KVAR | (which))
@@ -1747,33 +1834,7 @@
*/
SCR_JUMP,
}/*-------------------------< STARTPOS >--------------------*/,{
- PADDR(tryloop),
-}/*-------------------------< TRYLOOP >---------------------*/,{
-/*
-** Load an entry of the start queue into dsa
-** and try to start it by jumping to TRYSEL.
-**
-** Because the size depends on the
-** #define MAX_START parameter, it is filled
-** in at runtime.
-**
-**-----------------------------------------------------------
-**
-** ##===========< I=0; i<MAX_START >===========
-** || SCR_COPY (4),
-** || NADDR (squeue[i]),
-** || RADDR (dsa),
-** || SCR_CALL,
-** || PADDR (trysel),
-** ##==========================================
-**
-** SCR_JUMP,
-** PADDR(tryloop),
-**
-**-----------------------------------------------------------
-*/
-0
-
+ PADDRH(tryloop),
}/*-------------------------< TRYSEL >----------------------*/,{
/*
** Now:
@@ -2011,7 +2072,7 @@
SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
PADDR (msg_in),
SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
- PADDR (msg_reject),
+ PADDRH (msg_reject),
/*
** normal processing
*/
@@ -2228,7 +2289,7 @@
SCR_FROM_REG (socl),
0,
SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
+ PADDRH (msg_parity),
SCR_FROM_REG (scratcha),
0,
/*
@@ -2243,13 +2304,13 @@
SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
PADDR (disconnect),
SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
- PADDR (msg_extended),
+ PADDRH (msg_extended),
SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
PADDR (clrack),
SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
- PADDR (msg_reject),
+ PADDRH (msg_reject),
SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
- PADDR (msg_ign_residue),
+ PADDRH (msg_ign_residue),
/*
** Rest of the messages left as
** an exercise ...
@@ -2268,196 +2329,624 @@
SCR_JUMP,
PADDR (setmsg),
-}/*-------------------------< MSG_PARITY >---------------*/,{
+}/*-------------------------< COMPLETE >-----------------*/,{
/*
- ** count it
+ ** Complete message.
+ **
+ ** If it's not the get condition code,
+ ** copy TEMP register to LASTP in header.
*/
- SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+ SCR_FROM_REG (SS_REG),
0,
- /*
- ** send a "message parity error" message.
+/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)),
+ 12,
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.lastp),
+/*>>>*/ /*
+ ** When we terminate the cycle by clearing ACK,
+ ** the target may disconnect immediately.
+ **
+ ** We don't want to be told of an
+ ** "unexpected disconnect",
+ ** so we disable this feature.
*/
- SCR_LOAD_REG (scratcha, M_PARITY),
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
0,
- SCR_JUMP,
- PADDR (setmsg),
-}/*-------------------------< MSG_REJECT >---------------*/,{
/*
- ** If a negotiation was in progress,
- ** negotiation failed.
+ ** Terminate cycle ...
*/
- SCR_FROM_REG (HS_REG),
+ SCR_CLR (SCR_ACK|SCR_ATN),
0,
- SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
- SIR_NEGO_FAILED,
/*
- ** else make host log this message
+ ** ... and wait for the disconnect.
*/
- SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
- SIR_REJECT_RECEIVED,
- SCR_JUMP,
- PADDR (clrack),
-
-}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+ SCR_WAIT_DISC,
+ 0,
+}/*-------------------------< CLEANUP >-------------------*/,{
/*
- ** Terminate cycle
+ ** dsa: Pointer to ccb
+ ** or xxxxxxFF (no ccb)
+ **
+ ** HS_REG: Host-Status (<>0!)
*/
- SCR_CLR (SCR_ACK),
+ SCR_FROM_REG (dsa),
0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
+ SCR_JUMP ^ IFTRUE (DATA (0xff)),
+ PADDR (signal),
/*
- ** get residue size.
+ ** dsa is valid.
+ ** save the status registers
*/
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
+ SCR_COPY (4),
+ RADDR (scr0),
+ NADDR (header.status),
/*
- ** Check for message parity error.
+ ** and copy back the header to the ccb.
*/
- SCR_TO_REG (scratcha),
+ SCR_COPY (4),
+ RADDR (dsa),
+ PADDR (cleanup0),
+ SCR_COPY (sizeof (struct head)),
+ NADDR (header),
+}/*-------------------------< CLEANUP0 >--------------------*/,{
0,
- SCR_FROM_REG (socl),
+
+ /*
+ ** If command resulted in "check condition"
+ ** status and is not yet completed,
+ ** try to get the condition code.
+ */
+ SCR_FROM_REG (HS_REG),
0,
- SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
- SCR_FROM_REG (scratcha),
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
+ 16,
+ SCR_FROM_REG (SS_REG),
0,
+ SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
+ PADDRH(getcc2),
/*
- ** Size is 0 .. ignore message.
+ ** And make the DSA register invalid.
*/
- SCR_JUMP ^ IFTRUE (DATA (0)),
- PADDR (clrack),
+/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */
+ 0,
+}/*-------------------------< SIGNAL >----------------------*/,{
/*
- ** Size is not 1 .. have to interrupt.
+ ** if status = queue full,
+ ** reinsert in startqueue and stall queue.
*/
-/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)),
- 40,
+ SCR_FROM_REG (SS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
+ SIR_STALL_QUEUE,
/*
- ** Check for residue byte in swide register
+ ** if job completed ...
*/
- SCR_FROM_REG (scntl2),
+ SCR_FROM_REG (HS_REG),
0,
-/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
- 16,
/*
- ** There IS data in the swide register.
- ** Discard it.
+ ** ... signal completion to the host
*/
- SCR_REG_REG (scntl2, SCR_OR, WSR),
+ SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)),
0,
+ /*
+ ** Auf zu neuen Schandtaten!
+ */
+ SCR_JUMP,
+ PADDR(start),
+
+}/*-------------------------< SAVE_DP >------------------*/,{
+ /*
+ ** SAVE_DP message:
+ ** Copy TEMP register to SAVEP in header.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.savep),
SCR_JUMP,
PADDR (clrack),
+}/*-------------------------< RESTORE_DP >---------------*/,{
/*
- ** Load again the size to the sfbr register.
+ ** RESTORE_DP message:
+ ** Copy SAVEP in header to TEMP register.
*/
-/*>>>*/ SCR_FROM_REG (scratcha),
- 0,
-/*>>>*/ SCR_INT,
- SIR_IGN_RESIDUE,
+ SCR_COPY (4),
+ NADDR (header.savep),
+ RADDR (temp),
SCR_JUMP,
PADDR (clrack),
-}/*-------------------------< MSG_EXTENDED >-------------*/,{
+}/*-------------------------< DISCONNECT >---------------*/,{
/*
- ** Terminate cycle
+ ** If QUIRK_AUTOSAVE is set,
+ ** do an "save pointer" operation.
*/
- SCR_CLR (SCR_ACK),
+ SCR_FROM_REG (QU_REG),
0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
+ 12,
+ /*
+ ** like SAVE_DP message:
+ ** Copy TEMP register to SAVEP in header.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (header.savep),
+/*>>>*/ /*
+ ** Check if temp==savep or temp==goalp:
+ ** if not, log a missing save pointer message.
+ ** In fact, it's a comparison mod 256.
+ **
+ ** Hmmm, I hadn't thought that I would be urged to
+ ** write this kind of ugly self modifying code.
+ **
+ ** It's unbelievable, but the ncr53c8xx isn't able
+ ** to subtract one register from another.
+ */
+ SCR_FROM_REG (temp),
+ 0,
+ /*
+ ** You are not expected to understand this ..
+ **
+ ** CAUTION: only little endian architectures supported! XXX
+ */
+ SCR_COPY (1),
+ NADDR (header.savep),
+ PADDR (disconnect0),
+}/*-------------------------< DISCONNECT0 >--------------*/,{
+/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)),
+ 20,
+ /*
+ ** neither this
+ */
+ SCR_COPY (1),
+ NADDR (header.goalp),
+ PADDR (disconnect1),
+}/*-------------------------< DISCONNECT1 >--------------*/,{
+ SCR_INT ^ IFFALSE (DATA (1)),
+ SIR_MISSING_SAVE,
+/*>>>*/
+
+ /*
+ ** DISCONNECTing ...
+ **
+ ** disable the "unexpected disconnect" feature,
+ ** and remove the ACK signal.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ /*
+ ** Wait for the disconnect.
+ */
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ ** Profiling:
+ ** Set a time stamp,
+ ** and count the disconnects.
+ */
+ SCR_COPY (sizeof (u_long)),
+ KVAR(SCRIPT_KVAR_JIFFIES),
+ NADDR (header.stamp.disconnect),
+ SCR_COPY (4),
+ NADDR (disc_phys),
+ RADDR (temp),
+ SCR_REG_REG (temp, SCR_ADD, 0x01),
+ 0,
+ SCR_COPY (4),
+ RADDR (temp),
+ NADDR (disc_phys),
+ /*
+ ** Status is: DISCONNECTED.
+ */
+ SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+ 0,
+ SCR_JUMP,
+ PADDR (cleanup),
+
+}/*-------------------------< MSG_OUT >-------------------*/,{
+ /*
+ ** The target requests a message.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
+ /*
+ ** 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, ...
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+ PADDR (msg_out),
+}/*-------------------------< MSG_OUT_DONE >--------------*/,{
+ /*
+ ** ... else clear the message ...
+ */
+ SCR_LOAD_REG (scratcha, M_NOOP),
+ 0,
+ SCR_COPY (4),
+ RADDR (scratcha),
+ NADDR (msgout),
+ /*
+ ** ... and process the next phase
+ */
+ SCR_JUMP,
PADDR (dispatch),
+}/*------------------------< BADGETCC >---------------------*/,{
/*
- ** get length.
+ ** If SIGP was set, clear it and try again.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+ PADDRH (getcc2),
+ SCR_INT,
+ SIR_SENSE_FAILED,
+}/*-------------------------< RESELECT >--------------------*/,{
+ /*
+ ** This NOP will be patched with LED OFF
+ ** SCR_REG_REG (gpreg, SCR_OR, 0x01)
+ */
+ SCR_JUMP ^ IFFALSE (0),
+ 0,
+ /*
+ ** make the DSA invalid.
+ */
+ SCR_LOAD_REG (dsa, 0xff),
+ 0,
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ ** Sleep waiting for a reselection.
+ ** If SIGP is set, special treatment.
+ **
+ ** Zu allem bereit ..
+ */
+ SCR_WAIT_RESEL,
+ PADDR(reselect2),
+}/*-------------------------< RESELECT1 >--------------------*/,{
+ /*
+ ** This NOP will be patched with LED ON
+ ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+ */
+ SCR_JUMP ^ IFFALSE (0),
+ 0,
+ /*
+ ** ... zu nichts zu gebrauchen ?
+ **
+ ** load the target id into the SFBR
+ ** and jump to the control block.
+ **
+ ** Look at the declarations of
+ ** - struct ncb
+ ** - struct tcb
+ ** - struct lcb
+ ** - struct ccb
+ ** to understand what's going on.
+ */
+ SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+ 0,
+ SCR_TO_REG (ctest0),
+ 0,
+ SCR_JUMP,
+ NADDR (jump_tcb),
+}/*-------------------------< RESELECT2 >-------------------*/,{
+ /*
+ ** This NOP will be patched with LED ON
+ ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+ */
+ SCR_JUMP ^ IFFALSE (0),
+ 0,
+ /*
+ ** If it's not connected :(
+ ** -> interrupted by SIGP bit.
+ ** Jump to start.
+ */
+ SCR_FROM_REG (ctest2),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+ PADDR (start),
+ SCR_JUMP,
+ PADDR (reselect),
+
+}/*-------------------------< RESEL_TMP >-------------------*/,{
+ /*
+ ** The return address in TEMP
+ ** is in fact the data structure address,
+ ** so copy it to the DSA register.
+ */
+ SCR_COPY (4),
+ RADDR (temp),
+ RADDR (dsa),
+ SCR_JUMP,
+ PADDR (prepare),
+
+}/*-------------------------< RESEL_LUN >-------------------*/,{
+ /*
+ ** come back to this point
+ ** to get an IDENTIFY message
+ ** Wait for a msg_in phase.
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 48,
+ /*
+ ** message phase
+ ** It's not a sony, it's a trick:
+ ** read the data without acknowledging it.
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)),
+ 32,
+ /*
+ ** It WAS an Identify message.
+ ** get it and ack it!
*/
SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
+ NADDR (msgin),
+ SCR_CLR (SCR_ACK),
+ 0,
/*
- ** Check for message parity error.
+ ** Mask out the lun.
*/
- SCR_TO_REG (scratcha),
+ SCR_REG_REG (sfbr, SCR_AND, 0x07),
0,
- SCR_FROM_REG (socl),
+ SCR_RETURN,
0,
- SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
- SCR_FROM_REG (scratcha),
+ /*
+ ** No message phase or no IDENTIFY message:
+ ** return 0.
+ */
+/*>>>*/ SCR_LOAD_SFBR (0),
0,
+ SCR_RETURN,
+ 0,
+
+}/*-------------------------< RESEL_TAG >-------------------*/,{
/*
+ ** come back to this point
+ ** to get a SIMPLE_TAG message
+ ** Wait for a MSG_IN phase.
*/
- SCR_JUMP ^ IFTRUE (DATA (3)),
- PADDR (msg_ext_3),
- SCR_JUMP ^ IFFALSE (DATA (2)),
- PADDR (msg_bad),
-}/*-------------------------< MSG_EXT_2 >----------------*/,{
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 64,
+ /*
+ ** message phase
+ ** It's a trick - read the data
+ ** without acknowledging it.
+ */
+ SCR_FROM_REG (sbdl),
+ 0,
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)),
+ 48,
+ /*
+ ** It WAS a SIMPLE_TAG message.
+ ** get it and ack it!
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin),
SCR_CLR (SCR_ACK),
0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
/*
- ** get extended message code.
+ ** Wait for the second byte (the tag)
+ */
+/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ 24,
+ /*
+ ** Get it and ack it!
*/
SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[2]),
+ NADDR (msgin),
+ SCR_CLR (SCR_ACK|SCR_CARRY),
+ 0,
+ SCR_RETURN,
+ 0,
/*
- ** Check for message parity error.
+ ** No message phase or no SIMPLE_TAG message
+ ** or no second byte: return 0.
*/
- SCR_TO_REG (scratcha),
+/*>>>*/ SCR_LOAD_SFBR (0),
0,
- SCR_FROM_REG (socl),
+ SCR_SET (SCR_CARRY),
0,
- SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
- SCR_FROM_REG (scratcha),
+ SCR_RETURN,
0,
- SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
- PADDR (msg_wdtr),
+
+}/*-------------------------< DATA_IO >--------------------*/,{
+/*
+** Because Linux does not provide xfer data direction
+** to low-level scsi drivers, we must trust the target
+** for actual data direction when we cannot guess it.
+** The programmed interrupt patches savep, lastp, goalp,
+** etc.., and restarts the scsi script at data_out.
+*/
+ SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+ SIR_DATA_IO_IS_OUT,
+
+}/*-------------------------< DATA_IN >--------------------*/,{
+/*
+** Because the size depends on the
+** #define MAX_SCATTER parameter,
+** it is filled in at runtime.
+**
+** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** PADDR (no_data),
+** SCR_COPY (sizeof (u_long)),
+** KVAR(SCRIPT_KVAR_JIFFIES),
+** NADDR (header.stamp.data),
+** SCR_MOVE_TBL ^ SCR_DATA_IN,
+** offsetof (struct dsb, data[ 0]),
+**
+** ##===========< i=1; i<MAX_SCATTER >=========
+** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+** || PADDR (checkatn),
+** || SCR_MOVE_TBL ^ SCR_DATA_IN,
+** || offsetof (struct dsb, data[ i]),
+** ##==========================================
+**
+** SCR_CALL,
+** PADDR (checkatn),
+** SCR_JUMP,
+** PADDR (no_data),
+*/
+0
+}/*--------------------------------------------------------*/
+};
+
+static struct scripth scripth0 = {
+/*-------------------------< TRYLOOP >---------------------*/{
+/*
+** Load an entry of the start queue into dsa
+** and try to start it by jumping to TRYSEL.
+**
+** Because the size depends on the
+** #define MAX_START parameter, it is filled
+** in at runtime.
+**
+**-----------------------------------------------------------
+**
+** ##===========< I=0; i<MAX_START >===========
+** || SCR_COPY (4),
+** || NADDR (squeue[i]),
+** || RADDR (dsa),
+** || SCR_CALL,
+** || PADDR (trysel),
+** ##==========================================
+**
+** SCR_JUMP,
+** PADDRH(tryloop),
+**
+**-----------------------------------------------------------
+*/
+0
+},/*-------------------------< MSG_PARITY >---------------*/{
/*
- ** unknown extended message
+ ** count it
*/
+ SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+ 0,
+ /*
+ ** send a "message parity error" message.
+ */
+ SCR_LOAD_REG (scratcha, M_PARITY),
+ 0,
SCR_JUMP,
- PADDR (msg_bad)
-}/*-------------------------< MSG_WDTR >-----------------*/,{
+ PADDR (setmsg),
+}/*-------------------------< MSG_REJECT >---------------*/,{
+ /*
+ ** If a negotiation was in progress,
+ ** negotiation failed.
+ */
+ SCR_FROM_REG (HS_REG),
+ 0,
+ SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+ SIR_NEGO_FAILED,
+ /*
+ ** else make host log this message
+ */
+ SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
+ SIR_REJECT_RECEIVED,
+ SCR_JUMP,
+ PADDR (clrack),
+
+}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+ /*
+ ** Terminate cycle
+ */
SCR_CLR (SCR_ACK),
0,
SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
PADDR (dispatch),
/*
- ** get data bus width
+ ** get residue size.
*/
SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[3]),
+ NADDR (msgin[1]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
SCR_FROM_REG (socl),
0,
SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
/*
- ** let the host do the real work.
+ ** Size is 0 .. ignore message.
*/
- SCR_INT,
- SIR_NEGO_WIDE,
+ SCR_JUMP ^ IFTRUE (DATA (0)),
+ PADDR (clrack),
/*
- ** let the target fetch our answer.
+ ** Size is not 1 .. have to interrupt.
*/
- SCR_SET (SCR_ATN),
+/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)),
+ 40,
+ /*
+ ** Check for residue byte in swide register
+ */
+ SCR_FROM_REG (scntl2),
0,
- SCR_CLR (SCR_ACK),
+/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+ 16,
+ /*
+ ** There IS data in the swide register.
+ ** Discard it.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
0,
-
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- SIR_NEGO_PROTO,
+ SCR_JUMP,
+ PADDR (clrack),
/*
- ** Send the M_X_WIDE_REQ
+ ** Load again the size to the sfbr register.
*/
- SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_CLR (SCR_ATN),
+/*>>>*/ SCR_FROM_REG (scratcha),
0,
- SCR_COPY (1),
- RADDR (sfbr),
- NADDR (lastmsg),
+/*>>>*/ SCR_INT,
+ SIR_IGN_RESIDUE,
SCR_JUMP,
- PADDR (msg_out_done),
+ PADDR (clrack),
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
+}/*-------------------------< MSG_EXTENDED >-------------*/,{
+ /*
+ ** Terminate cycle
+ */
+ SCR_CLR (SCR_ACK),
+ 0,
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
+ /*
+ ** get length.
+ */
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[1]),
+ /*
+ ** Check for message parity error.
+ */
+ SCR_TO_REG (scratcha),
+ 0,
+ SCR_FROM_REG (socl),
+ 0,
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
+ 0,
+ /*
+ */
+ SCR_JUMP ^ IFTRUE (DATA (3)),
+ PADDRH (msg_ext_3),
+ SCR_JUMP ^ IFFALSE (DATA (2)),
+ PADDR (msg_bad),
+}/*-------------------------< MSG_EXT_2 >----------------*/,{
SCR_CLR (SCR_ACK),
0,
SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
@@ -2475,36 +2964,35 @@
SCR_FROM_REG (socl),
0,
SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
+ PADDRH (msg_parity),
SCR_FROM_REG (scratcha),
0,
- SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
- PADDR (msg_sdtr),
+ SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
+ PADDRH (msg_wdtr),
/*
** unknown extended message
*/
SCR_JUMP,
PADDR (msg_bad)
-
-}/*-------------------------< MSG_SDTR >-----------------*/,{
+}/*-------------------------< MSG_WDTR >-----------------*/,{
SCR_CLR (SCR_ACK),
0,
SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
PADDR (dispatch),
/*
- ** get period and offset
+ ** get data bus width
*/
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
NADDR (msgin[3]),
SCR_FROM_REG (socl),
0,
SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
- PADDR (msg_parity),
+ PADDRH (msg_parity),
/*
** let the host do the real work.
*/
SCR_INT,
- SIR_NEGO_SYNC,
+ SIR_NEGO_WIDE,
/*
** let the target fetch our answer.
*/
@@ -2516,9 +3004,9 @@
SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
SIR_NEGO_PROTO,
/*
- ** Send the M_X_SYNC_REQ
+ ** Send the M_X_WIDE_REQ
*/
- SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+ SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
NADDR (msgout),
SCR_CLR (SCR_ATN),
0,
@@ -2528,257 +3016,77 @@
SCR_JUMP,
PADDR (msg_out_done),
-}/*-------------------------< COMPLETE >-----------------*/,{
- /*
- ** Complete message.
- **
- ** If it's not the get condition code,
- ** copy TEMP register to LASTP in header.
- */
- SCR_FROM_REG (SS_REG),
- 0,
-/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)),
- 12,
- SCR_COPY (4),
- RADDR (temp),
- NADDR (header.lastp),
-/*>>>*/ /*
- ** When we terminate the cycle by clearing ACK,
- ** the target may disconnect immediately.
- **
- ** We don't want to be told of an
- ** "unexpected disconnect",
- ** so we disable this feature.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- /*
- ** Terminate cycle ...
- */
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- /*
- ** ... and wait for the disconnect.
- */
- SCR_WAIT_DISC,
- 0,
-}/*-------------------------< CLEANUP >-------------------*/,{
- /*
- ** dsa: Pointer to ccb
- ** or xxxxxxFF (no ccb)
- **
- ** HS_REG: Host-Status (<>0!)
- */
- SCR_FROM_REG (dsa),
- 0,
- SCR_JUMP ^ IFTRUE (DATA (0xff)),
- PADDR (signal),
- /*
- ** dsa is valid.
- ** save the status registers
- */
- SCR_COPY (4),
- RADDR (scr0),
- NADDR (header.status),
- /*
- ** and copy back the header to the ccb.
- */
- SCR_COPY (4),
- RADDR (dsa),
- PADDR (cleanup0),
- SCR_COPY (sizeof (struct head)),
- NADDR (header),
-}/*-------------------------< CLEANUP0 >--------------------*/,{
- 0,
-
- /*
- ** If command resulted in "check condition"
- ** status and is not yet completed,
- ** try to get the condition code.
- */
- SCR_FROM_REG (HS_REG),
- 0,
-/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
- 16,
- SCR_FROM_REG (SS_REG),
+}/*-------------------------< MSG_EXT_3 >----------------*/,{
+ SCR_CLR (SCR_ACK),
0,
- SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
- PADDR(getcc2),
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
/*
- ** And make the DSA register invalid.
+ ** get extended message code.
*/
-/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */
- 0,
-}/*-------------------------< SIGNAL >----------------------*/,{
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[2]),
/*
- ** if status = queue full,
- ** reinsert in startqueue and stall queue.
+ ** Check for message parity error.
*/
- SCR_FROM_REG (SS_REG),
+ SCR_TO_REG (scratcha),
0,
- SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
- SIR_STALL_QUEUE,
- /*
- ** if job completed ...
- */
- SCR_FROM_REG (HS_REG),
+ SCR_FROM_REG (socl),
0,
- /*
- ** ... signal completion to the host
- */
- SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)),
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
+ SCR_FROM_REG (scratcha),
0,
+ SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
+ PADDRH (msg_sdtr),
/*
- ** Auf zu neuen Schandtaten!
- */
- SCR_JUMP,
- PADDR(start),
-
-}/*-------------------------< SAVE_DP >------------------*/,{
- /*
- ** SAVE_DP message:
- ** Copy TEMP register to SAVEP in header.
- */
- SCR_COPY (4),
- RADDR (temp),
- NADDR (header.savep),
- SCR_JUMP,
- PADDR (clrack),
-}/*-------------------------< RESTORE_DP >---------------*/,{
- /*
- ** RESTORE_DP message:
- ** Copy SAVEP in header to TEMP register.
+ ** unknown extended message
*/
- SCR_COPY (4),
- NADDR (header.savep),
- RADDR (temp),
SCR_JUMP,
- PADDR (clrack),
-
-}/*-------------------------< DISCONNECT >---------------*/,{
- /*
- ** If QUIRK_AUTOSAVE is set,
- ** do an "save pointer" operation.
- */
- SCR_FROM_REG (QU_REG),
- 0,
-/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
- 12,
- /*
- ** like SAVE_DP message:
- ** Copy TEMP register to SAVEP in header.
- */
- SCR_COPY (4),
- RADDR (temp),
- NADDR (header.savep),
-/*>>>*/ /*
- ** Check if temp==savep or temp==goalp:
- ** if not, log a missing save pointer message.
- ** In fact, it's a comparison mod 256.
- **
- ** Hmmm, I hadn't thought that I would be urged to
- ** write this kind of ugly self modifying code.
- **
- ** It's unbelievable, but the ncr53c8xx isn't able
- ** to subtract one register from another.
- */
- SCR_FROM_REG (temp),
- 0,
- /*
- ** You are not expected to understand this ..
- **
- ** CAUTION: only little endian architectures supported! XXX
- */
- SCR_COPY (1),
- NADDR (header.savep),
- PADDR (disconnect0),
-}/*-------------------------< DISCONNECT0 >--------------*/,{
-/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)),
- 20,
- /*
- ** neither this
- */
- SCR_COPY (1),
- NADDR (header.goalp),
- PADDR (disconnect1),
-}/*-------------------------< DISCONNECT1 >--------------*/,{
- SCR_INT ^ IFFALSE (DATA (1)),
- SIR_MISSING_SAVE,
-/*>>>*/
+ PADDR (msg_bad)
- /*
- ** DISCONNECTing ...
- **
- ** disable the "unexpected disconnect" feature,
- ** and remove the ACK signal.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- /*
- ** Wait for the disconnect.
- */
- SCR_WAIT_DISC,
- 0,
- /*
- ** Profiling:
- ** Set a time stamp,
- ** and count the disconnects.
- */
- SCR_COPY (sizeof (u_long)),
- KVAR(SCRIPT_KVAR_JIFFIES),
- NADDR (header.stamp.disconnect),
- SCR_COPY (4),
- NADDR (disc_phys),
- RADDR (temp),
- SCR_REG_REG (temp, SCR_ADD, 0x01),
+}/*-------------------------< MSG_SDTR >-----------------*/,{
+ SCR_CLR (SCR_ACK),
0,
- SCR_COPY (4),
- RADDR (temp),
- NADDR (disc_phys),
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (dispatch),
/*
- ** Status is: DISCONNECTED.
+ ** get period and offset
*/
- SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ NADDR (msgin[3]),
+ SCR_FROM_REG (socl),
0,
- SCR_JUMP,
- PADDR (cleanup),
-
-}/*-------------------------< MSG_OUT >-------------------*/,{
- /*
- ** The target requests a message.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_COPY (1),
- RADDR (sfbr),
- NADDR (lastmsg),
- /*
- ** If it was no ABORT message ...
- */
- SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
- PADDR (msg_out_abort),
+ SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+ PADDRH (msg_parity),
/*
- ** ... wait for the next phase
- ** if it's a message out, send it again, ...
+ ** let the host do the real work.
*/
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
- PADDR (msg_out),
-}/*-------------------------< MSG_OUT_DONE >--------------*/,{
+ SCR_INT,
+ SIR_NEGO_SYNC,
/*
- ** ... else clear the message ...
+ ** let the target fetch our answer.
*/
- SCR_LOAD_REG (scratcha, M_NOOP),
+ SCR_SET (SCR_ATN),
0,
- SCR_COPY (4),
- RADDR (scratcha),
- NADDR (msgout),
+ SCR_CLR (SCR_ACK),
+ 0,
+
+ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ SIR_NEGO_PROTO,
/*
- ** ... and process the next phase
+ ** Send the M_X_SYNC_REQ
*/
+ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+ NADDR (msgout),
+ SCR_CLR (SCR_ATN),
+ 0,
+ SCR_COPY (1),
+ RADDR (sfbr),
+ NADDR (lastmsg),
SCR_JUMP,
- PADDR (dispatch),
+ PADDR (msg_out_done),
+
}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
/*
** After ABORT message,
@@ -2811,7 +3119,7 @@
*/
SCR_COPY (4),
RADDR (dsa),
- PADDR (getcc1),
+ PADDRH (getcc1),
/*
** ... then we do the actual copy.
*/
@@ -2877,7 +3185,7 @@
SCR_FROM_REG (QU_REG),
0,
SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)),
- PADDR(getcc3),
+ PADDRH(getcc3),
/*
** Then try to connect to the target.
** If we are reselected, special treatment
@@ -2941,205 +3249,6 @@
SCR_JUMP,
PADDR (prepare2),
-}/*------------------------< BADGETCC >---------------------*/,{
- /*
- ** If SIGP was set, clear it and try again.
- */
- SCR_FROM_REG (ctest2),
- 0,
- SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
- PADDR (getcc2),
- SCR_INT,
- SIR_SENSE_FAILED,
-}/*-------------------------< RESELECT >--------------------*/,{
- /*
- ** make the DSA invalid.
- */
- SCR_LOAD_REG (dsa, 0xff),
- 0,
- SCR_CLR (SCR_TRG),
- 0,
- /*
- ** Sleep waiting for a reselection.
- ** If SIGP is set, special treatment.
- **
- ** Zu allem bereit ..
- */
- SCR_WAIT_RESEL,
- PADDR(reselect2),
- /*
- ** ... zu nichts zu gebrauchen ?
- **
- ** load the target id into the SFBR
- ** and jump to the control block.
- **
- ** Look at the declarations of
- ** - struct ncb
- ** - struct tcb
- ** - struct lcb
- ** - struct ccb
- ** to understand what's going on.
- */
- SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
- 0,
- SCR_TO_REG (ctest0),
- 0,
- SCR_JUMP,
- NADDR (jump_tcb),
-}/*-------------------------< RESELECT2 >-------------------*/,{
- /*
- ** If it's not connected :(
- ** -> interrupted by SIGP bit.
- ** Jump to start.
- */
- SCR_FROM_REG (ctest2),
- 0,
- SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
- PADDR (start),
- SCR_JUMP,
- PADDR (reselect),
-
-}/*-------------------------< RESEL_TMP >-------------------*/,{
- /*
- ** The return address in TEMP
- ** is in fact the data structure address,
- ** so copy it to the DSA register.
- */
- SCR_COPY (4),
- RADDR (temp),
- RADDR (dsa),
- SCR_JUMP,
- PADDR (prepare),
-
-}/*-------------------------< RESEL_LUN >-------------------*/,{
- /*
- ** come back to this point
- ** to get an IDENTIFY message
- ** Wait for a msg_in phase.
- */
-/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
- 48,
- /*
- ** message phase
- ** It's not a sony, it's a trick:
- ** read the data without acknowledging it.
- */
- SCR_FROM_REG (sbdl),
- 0,
-/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)),
- 32,
- /*
- ** It WAS an Identify message.
- ** get it and ack it!
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** Mask out the lun.
- */
- SCR_REG_REG (sfbr, SCR_AND, 0x07),
- 0,
- SCR_RETURN,
- 0,
- /*
- ** No message phase or no IDENTIFY message:
- ** return 0.
- */
-/*>>>*/ SCR_LOAD_SFBR (0),
- 0,
- SCR_RETURN,
- 0,
-
-}/*-------------------------< RESEL_TAG >-------------------*/,{
- /*
- ** come back to this point
- ** to get a SIMPLE_TAG message
- ** Wait for a MSG_IN phase.
- */
-/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
- 64,
- /*
- ** message phase
- ** It's a trick - read the data
- ** without acknowledging it.
- */
- SCR_FROM_REG (sbdl),
- 0,
-/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)),
- 48,
- /*
- ** It WAS a SIMPLE_TAG message.
- ** get it and ack it!
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** Wait for the second byte (the tag)
- */
-/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
- 24,
- /*
- ** Get it and ack it!
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- SCR_CLR (SCR_ACK|SCR_CARRY),
- 0,
- SCR_RETURN,
- 0,
- /*
- ** No message phase or no SIMPLE_TAG message
- ** or no second byte: return 0.
- */
-/*>>>*/ SCR_LOAD_SFBR (0),
- 0,
- SCR_SET (SCR_CARRY),
- 0,
- SCR_RETURN,
- 0,
-
-}/*-------------------------< DATA_IO >--------------------*/,{
-/*
-** Because Linux does not provide xfer data direction
-** to low-level scsi drivers, we must trust the target
-** for actual data direction when we cannot guess it.
-** The programmed interrupt patches savep, lastp, goalp,
-** etc.., and restarts the scsi script at data_out.
-*/
- SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
- SIR_DATA_IO_IS_OUT,
-
-}/*-------------------------< DATA_IN >--------------------*/,{
-/*
-** Because the size depends on the
-** #define MAX_SCATTER parameter,
-** it is filled in at runtime.
-**
-** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-** PADDR (no_data),
-** SCR_COPY (sizeof (u_long)),
-** KVAR(SCRIPT_KVAR_JIFFIES),
-** NADDR (header.stamp.data),
-** SCR_MOVE_TBL ^ SCR_DATA_IN,
-** offsetof (struct dsb, data[ 0]),
-**
-** ##===========< i=1; i<MAX_SCATTER >=========
-** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-** || PADDR (checkatn),
-** || SCR_MOVE_TBL ^ SCR_DATA_IN,
-** || offsetof (struct dsb, data[ i]),
-** ##==========================================
-**
-** SCR_CALL,
-** PADDR (checkatn),
-** SCR_JUMP,
-** PADDR (no_data),
-*/
-0
}/*-------------------------< DATA_OUT >-------------------*/,{
/*
** Because the size depends on the
@@ -3169,7 +3278,6 @@
**---------------------------------------------------------
*/
0 /* was (u_long)&ident ? */
-
}/*-------------------------< ABORTTAG >-------------------*/,{
/*
** Abort a bad reselection.
@@ -3243,12 +3351,12 @@
**==========================================================
*/
-void ncr_script_fill (struct script * scr)
+void ncr_script_fill (struct script * scr, struct scripth * scrh)
{
int i;
ncrcmd *p;
- p = scr->tryloop;
+ p = scrh->tryloop;
for (i=0; i<MAX_START; i++) {
*p++ =SCR_COPY (4);
*p++ =NADDR (squeue[i]);
@@ -3257,9 +3365,9 @@
*p++ =PADDR (trysel);
};
*p++ =SCR_JUMP;
- *p++ =PADDR(tryloop);
+ *p++ =PADDRH(tryloop);
- assert ((u_long)p == (u_long)&scr->tryloop + sizeof (scr->tryloop));
+ assert ((u_long)p == (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
p = scr->data_in;
@@ -3285,7 +3393,7 @@
assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
- p = scr->data_out;
+ p = scrh->data_out;
*p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
*p++ =PADDR (no_data);
@@ -3307,7 +3415,7 @@
*p++ =SCR_JUMP;
*p++ =PADDR (no_data);
- assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
+ assert ((u_long)p == (u_long)&scrh->data_out + sizeof (scrh->data_out));
}
/*==========================================================
@@ -3319,19 +3427,14 @@
**==========================================================
*/
-static void ncr_script_copy_and_bind (struct script *script, ncb_p np)
+static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
{
ncrcmd opcode, new, old, tmp1, tmp2;
- ncrcmd *src, *dst, *start, *end;
+ ncrcmd *start, *end;
int relocs;
- np->p_script = vtophys(np->script);
-
- src = script->start;
- dst = np->script->start;
-
start = src;
- end = src + (sizeof (struct script) / 4);
+ end = src + len/4;
while (src < end) {
@@ -3418,6 +3521,9 @@
case RELOC_LABEL:
new = (old & ~RELOC_MASK) + np->p_script;
break;
+ case RELOC_LABELH:
+ new = (old & ~RELOC_MASK) + np->p_scripth;
+ break;
case RELOC_SOFTC:
new = (old & ~RELOC_MASK) + vtophys(np);
break;
@@ -3459,10 +3565,6 @@
**==========================================================
*/
-#define MIN_ASYNC_PD 40
-#define MIN_SYNC_PD 20
-
-
/*
** Linux host data structure
**
@@ -3472,12 +3574,22 @@
*/
struct host_data {
- struct ncb ncb_data;
+ struct ncb *ncb;
+
+ char ncb_align[NCB_ALIGN_SIZE-1]; /* Filler for alignment */
+ struct ncb _ncb_data;
+
+ char ccb_align[CCB_ALIGN_SIZE-1]; /* Filler for alignment */
+ struct ccb _ccb_data;
+
+ char scr_align[SCR_ALIGN_SIZE-1]; /* Filler for alignment */
struct script script_data;
+
+ struct scripth scripth_data;
};
/*
-** Print something which allow to retreive the controler type, unit,
+** Print something which allow to retrieve the controler type, unit,
** target, lun concerned by a kernel message.
*/
@@ -3487,7 +3599,7 @@
static inline void PRINT_ADDR(Scsi_Cmnd *cmd)
{
struct host_data *host_data = (struct host_data *) cmd->host->hostdata;
- ncb_p np = &host_data->ncb_data;
+ ncb_p np = host_data->ncb;
if (np) PRINT_LUN(np, cmd->target, cmd->lun);
}
@@ -3530,13 +3642,25 @@
instance->irq = irq;
host_data = (struct host_data *) instance->hostdata;
- np = &host_data->ncb_data;
+ /*
+ ** Align np and first ccb to 32 boundary for cache line
+ ** bursting when copying the global header.
+ */
+ np = (ncb_p) (((u_long) &host_data->_ncb_data) & NCB_ALIGN_MASK);
+ host_data->ncb = np;
bzero (np, sizeof (*np));
+
+ np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
+ bzero (np->ccb, sizeof (*np->ccb));
+
np->unit = unit;
np->chip = chip;
np->device_id = device_id;
np->revision_id = revision_id;
- np->script = &host_data->script_data;
+
+ np->script0 =
+ (struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
+ np->scripth0 = &host_data->scripth_data;
/*
** Initialize timer structure
@@ -3562,7 +3686,7 @@
#endif
}
else
- if (bootverbose)
+ if (bootverbose > 1)
printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr);
/*
@@ -3595,7 +3719,10 @@
np->maxwide = 0;
np->rv_scntl3 = 0x13; /* default: 40MHz clock */
np->ns_sync = 25;
+ np->clock_khz = 40000;
+ np->clock_divn = 4;
np->maxoffs = 8;
+ np->multiplier = 1;
/*
** Get the frequency of the chip's clock.
@@ -3609,21 +3736,67 @@
case PCI_DEVICE_ID_NCR_53C860:
if (driver_setup.ultra_scsi) {
np->rv_scntl3 = 0x15;
+ np->clock_khz = 80000;
np->ns_sync = 12;
}
else
np->rv_scntl3 = 0x35; /* always assume 80MHz clock for 860 */
+ np->clock_divn = 5;
+ break;
+ case PCI_DEVICE_ID_NCR_53C875:
+ np->maxwide = 1;
+ if (driver_setup.special_features)
+ np->maxoffs = 16;
+ np->clock_divn = 5;
+ ncr_getclock(np, revision_id >= 2 ? 2 : 1);
+ break;
+ case PCI_DEVICE_ID_NCR_53C895:
+ np->maxwide = 1;
+ if (driver_setup.special_features)
+ np->maxoffs = 31;
+ np->clock_divn = 7;
+ ncr_getclock(np, 4);
break;
+ }
+
+ /*
+ ** Get on-board RAM bus address when supported
+ */
+ switch (device_id) {
+ case PCI_DEVICE_ID_NCR_53C825:
+ if (revision_id < 0x10)
+ break;
case PCI_DEVICE_ID_NCR_53C875:
- np->maxwide = 1;
- if (driver_setup.special_features)
- np->maxoffs = 16;
- ncr_getclock(np);
+ case PCI_DEVICE_ID_NCR_53C895:
+ if (driver_setup.special_features) {
+ OUTONB(nc_ctest2, 0x8);
+ np->paddr2 = INL(nc_scr0);
+ OUTOFFB(nc_ctest2, 0x8);
+ }
break;
}
+ if (bootverbose && np->paddr2)
+ printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2);
+
if (bootverbose && np->ns_sync < 25)
- printf ("%s: Ultra SCSI support enabled\n", ncr_name(np));
+ printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np),
+ np->ns_sync < 12 ? "-2": "");
+
+#ifndef NCR_IOMAPPED
+ if (np->paddr2 && sizeof(struct script) <= 4096) {
+ np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
+ if (!np->vaddr2) {
+ printf("%s: can't map memory mapped IO region\n", ncr_name(np));
+#ifdef NCR_MEMORYMAPPED
+ goto attach_error;
+#endif
+ }
+ else
+ if (bootverbose > 1)
+ printf("%s: on-board ram mapped at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr);
+ }
+#endif /* !defined NCR_IOMAPPED */
/*
** Fill Linux host instance structure
@@ -3646,16 +3819,24 @@
/*
** Patch script to physical addresses
*/
- ncr_script_fill (&script0);
- ncr_script_copy_and_bind (&script0, np);
- np->ccb.p_ccb = vtophys (&np->ccb);
+ ncr_script_fill (&script0, &scripth0);
+
+ np->scripth = np->scripth0;
+ np->p_scripth = vtophys(np->scripth);
+
+ np->script = (np->vaddr2) ? (struct script *) np->vaddr2 : np->script0;
+ np->p_script = (np->vaddr2) ? np->paddr2 : vtophys(np->script0);
+
+ ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
+ ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
+ np->ccb->p_ccb = vtophys (np->ccb);
/*
** init data structure
*/
np->jump_tcb.l_cmd = SCR_JUMP;
- np->jump_tcb.l_paddr = NCB_SCRIPT_PHYS (np, abort);
+ np->jump_tcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED)
retry_chip_init:
@@ -3701,7 +3882,7 @@
*/
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
# ifdef SCSI_NCR_SHARE_IRQ
- if (bootverbose)
+ if (bootverbose > 1)
printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
ncr_name(np), irq, (u_long) np);
if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT|SA_SHIRQ, "53c8xx", np)) {
@@ -3750,14 +3931,11 @@
** The middle-level SCSI driver does not
** wait devices to settle.
*/
-#ifdef SCSI_NCR_SETTLE_TIME
-#if SCSI_NCR_SETTLE_TIME > 2
- printf("%s: waiting for scsi devices to settle...\n", ncr_name(np));
-#endif
-#if SCSI_NCR_SETTLE_TIME > 0
- DELAY(SCSI_NCR_SETTLE_TIME*1000000);
-#endif
-#endif
+ if (driver_setup.settle_time > 2)
+ printf("%s: waiting %d seconds for scsi devices to settle...\n",
+ ncr_name(np), driver_setup.settle_time);
+ if (driver_setup.settle_time)
+ DELAY(1000000UL * driver_setup.settle_time);
/*
** Now let the generic SCSI driver
@@ -3794,6 +3972,10 @@
printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
}
+ if (np->vaddr2) {
+ printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+ unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
+ }
#endif
if (np->port) {
printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
@@ -3859,7 +4041,7 @@
struct Scsi_Host *host = cmd->host;
/* Scsi_Device *device = cmd->device; */
struct host_data *host_data = (struct host_data *) host->hostdata;
- ncb_p np = &host_data->ncb_data;
+ ncb_p np = host_data->ncb;
tcb_p tp = &np->target[cmd->target];
ccb_p cp;
@@ -3867,7 +4049,7 @@
int segments;
u_char qidx, nego, idmsg, *msgptr;
- u_long msglen, msglen2;
+ u_int msglen, msglen2;
u_long flags;
int xfer_direction;
@@ -4000,7 +4182,7 @@
*/
if (!nego && !tp->period) {
- if (SCSI_NCR_MAX_SYNC
+ if ( 1
#if defined (CDROM_ASYNC)
&& ((tp->inqdata[0] & 0x1f) != 5)
#endif
@@ -4051,7 +4233,7 @@
idmsg = M_IDENTIFY | cmd->lun;
- if (cp != &np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag))
+ if (cp != np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag))
idmsg |= 0x40;
msgptr = cp->scsi_smsg;
@@ -4187,7 +4369,7 @@
cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
break;
case XferOut:
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out);
+ cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
break;
case XferNone:
@@ -4295,7 +4477,7 @@
printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np),
np->squeueput,
(unsigned)(np->script->startpos[0]-
- (NCB_SCRIPT_PHYS (np, tryloop))));
+ (NCB_SCRIPTH_PHYS (np, tryloop))));
/*
** Script processor may be waiting for reselect.
@@ -4329,18 +4511,67 @@
struct Scsi_Host *host = cmd->host;
/* Scsi_Device *device = cmd->device; */
struct host_data *host_data = (struct host_data *) host->hostdata;
- ncb_p np = &host_data->ncb_data;
+ ncb_p np = host_data->ncb;
+ ccb_p cp;
u_long flags;
+ int found;
save_flags(flags); cli();
-
- reset_waiting_list(np);
-
- OUTB (nc_scntl1, CRST);
+/*
+ * Return immediately from recursive call
+ */
+ if (np->resetting) {
+ restore_flags(flags);
+ return SCSI_RESET_PUNT;
+ }
+ ++np->resetting;
+/*
+ * Perform chip reset, SCSI reset, wait 2 seconds
+ */
+ OUTB (nc_istat, SRST);
DELAY (1000);
+ OUTB (nc_istat, 0);
+ OUTB (nc_scntl1, CRST);
+ DELAY (100);
+ OUTB (nc_scntl1, 0);
+ DELAY (2000000);
+/*
+ * First, look in the wakeup list
+ */
+ for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) {
+ /*
+ ** look for the ccb of this command.
+ */
+ if (cp->host_status == HS_IDLE) continue;
+ if (cp->cmd == cmd) {
+ found = 1;
+ break;
+ }
+ }
+/*
+ * Then, look in the waiting list
+ */
+ if (!found && retrieve_from_waiting_list(0, np, cmd))
+ found = 1;
+/*
+ * Reinitialise the NCR and wake-up pending commands
+ */
ncr_init(np, "scsi bus reset", HS_RESET);
-
np->disc = 1;
+/*
+ * Complete awaiting commands with DID_RESET
+ */
+ reset_waiting_list(np);
+/*
+ * If the involved command was not in a driver queue, complete it
+ * with DID_RESET, in order to keep it alive.
+ */
+ if (!found && cmd && cmd->scsi_done) {
+ cmd->result = ScsiResult(DID_RESET, 0);
+ cmd->scsi_done(cmd);
+ }
+
+ --np->resetting;
restore_flags(flags);
@@ -4361,7 +4592,7 @@
struct Scsi_Host *host = cmd->host;
/* Scsi_Device *device = cmd->device; */
struct host_data *host_data = (struct host_data *) host->hostdata;
- ncb_p np = &host_data->ncb_data;
+ ncb_p np = host_data->ncb;
ccb_p cp;
u_long flags;
int found;
@@ -4381,7 +4612,7 @@
/*
* Then, look in the wakeup list
*/
- for (found=0, cp=&np->ccb; cp; cp=cp->link_ccb) {
+ for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) {
/*
** look for the ccb of this command.
*/
@@ -4502,17 +4733,10 @@
OUTB(nc_ctest3, np->sv_ctest3);
OUTB(nc_ctest4, np->sv_ctest4);
OUTB(nc_ctest5, np->sv_ctest5);
+ OUTB(nc_gpcntl, np->sv_gpcntl);
+ OUTB(nc_stest2, np->sv_stest2);
- if (np->uf_doubler) {
- OUTB(nc_stest1, DBLEN); /* Enable clock doubler */
- DELAY(10);
- OUTB(nc_stest3, 0x20); /* Halt the scsi clock */
- OUTB(nc_scntl3, np->sv_scntl3);
- OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock doubler */
- OUTB(nc_stest3, 0x00); /* Restart scsi clock */
- }
- else
- OUTB(nc_scntl3, np->sv_scntl3);
+ ncr_selectclock(np, np->sv_scntl3);
/*
** Release Memory mapped IO region and IO mapped region
@@ -4520,9 +4744,13 @@
#ifndef NCR_IOMAPPED
#ifdef DEBUG
- printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->reg, 128);
+ printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
#endif
unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
+#ifdef DEBUG
+ printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+#endif
+ unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
#endif
#ifdef DEBUG
@@ -4534,8 +4762,8 @@
** Free allocated ccb(s)
*/
- while ((cp=np->ccb.link_ccb) != NULL) {
- np->ccb.link_ccb = cp->link_ccb;
+ while ((cp=np->ccb->link_ccb) != NULL) {
+ np->ccb->link_ccb = cp->link_ccb;
if (cp->host_status) {
printf("%s: shall free an active ccb (host_status=%d)\n",
ncr_name(np), cp->host_status);
@@ -4889,7 +5117,7 @@
** complete all jobs that are not IDLE.
*/
- ccb_p cp = &np->ccb;
+ ccb_p cp = np->ccb;
while (cp) {
switch (cp->host_status) {
@@ -4918,7 +5146,7 @@
/*===============================================================
**
** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
-** transfers. 32,64,128 are only supported by 875 chips.
+** transfers. 32,64,128 are only supported by 875 and 895 chips.
** We use log base 2 (burst length) as internal code, with
** value 0 meaning "burst disabled".
**
@@ -4995,8 +5223,8 @@
*/
np->squeueput = 0;
- np->script->startpos[0] = NCB_SCRIPT_PHYS (np, tryloop);
- np->script->start0 [0] = SCR_INT ^ IFFALSE (0);
+ np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
+ np->script0->start0 [0] = SCR_INT ^ IFFALSE (0);
/*
** Wakeup all pending jobs.
@@ -5043,10 +5271,8 @@
/** NCR53C810A or NCR53C860 **/
if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
- if (!driver_setup.special_features)
- burst_max = burst_max < 4 ? burst_max : 4;
- else {
- burst_max = burst_max < 4 ? burst_max : 4;
+ burst_max = burst_max < 4 ? burst_max : 4;
+ if (driver_setup.special_features) {
np->rv_dmode = BOF | ERMP | ERL;
/* burst op-code fetch, read multiple */
/* read line */
@@ -5056,9 +5282,10 @@
}
}
else
-/** NCR53C825A or NCR53C875 **/
+/** NCR53C825A or NCR53C875 or NCR53C895 **/
if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
- ChipDevice == PCI_DEVICE_ID_NCR_53C875) {
+ ChipDevice == PCI_DEVICE_ID_NCR_53C875 ||
+ ChipDevice == PCI_DEVICE_ID_NCR_53C895) {
if (!driver_setup.special_features)
burst_max = burst_max < 4 ? burst_max : 4;
else {
@@ -5069,7 +5296,7 @@
np->rv_dcntl = PFEN | CLSE;
/* prefetch, cache line size */
np->rv_ctest3 = WRIE; /* write and invalidate */
- np->rv_ctest5 = 0x20; /* dma fifo 536 (0x20) */
+ np->rv_ctest5 = 0x20; /* large dma fifo (0x20) */
}
}
/** OTHERS **/
@@ -5078,26 +5305,60 @@
}
#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+#if 0
+ /*
+ * Do not enable read-multiple for 810A revision 0x11
+ */
+ if (np->device_id == PCI_DEVICE_ID_NCR_53C810 && np->revision_id == 0x11)
+ np->rv_dmode &= (~ERMP);
+#endif
+
/*
* Prepare initial io register bits for burst length
*/
ncr_init_burst(np, burst_max);
- if (bootverbose > 1) {
- printf ("%s: initial value of dmode/ctest4/ctest5 = 0x%02x/0x%02x/0x%02x\n",
- ncr_name(np), np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+ /*
+ ** Set differential mode.
+ */
+ switch(driver_setup.diff_support) {
+ case 3:
+ if (INB(nc_gpreg) & 0x08)
+ break;
+ case 2:
+ np->rv_stest2 |= 0x20;
+ break;
+ case 1:
+ np->rv_stest2 |= (np->sv_stest2 & 0x20);
+ break;
+ default:
+ break;
}
- if (bootverbose) {
- printf ("%s: final value of dmode/ctest4/ctest5 = 0x%02x/0x%02x/0x%02x\n",
- ncr_name(np), np->rv_dmode, np->rv_ctest4, np->rv_ctest5);
+
+ /*
+ ** Set irq mode.
+ */
+ switch(driver_setup.irqm) {
+ case 2:
+ np->rv_dcntl |= IRQM;
+ break;
+ case 1:
+ np->rv_stest2 |= (np->sv_dcntl & IRQM);
+ break;
+ default:
+ break;
}
-#if 0
- printf("%s: bios: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x, ctest5=0x%02x\n",
- ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
- printf("%s: used: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x, ctest5=0x%02x\n",
- ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
-#endif
+ if (bootverbose > 1) {
+ printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+ ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+ }
+ if (bootverbose > 1) {
+ printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n",
+ ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+ if (np->rv_stest2 & 0x20)
+ printf ("%s: setting up differential mode\n", ncr_name(np));
+ }
OUTB (nc_istat, 0x00 ); /* Remove Reset, abort ... */
if (driver_setup.scsi_parity)
@@ -5107,18 +5368,8 @@
OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */
- if (np->uf_doubler) {
- if (bootverbose >= 2)
- printf ("%s: enabling clock doubler\n", ncr_name(np));
- OUTB(nc_stest1, DBLEN); /* Enable clock doubler */
- DELAY(10);
- OUTB(nc_stest3, 0x20); /* Halt the scsi clock */
- OUTB(nc_scntl3, 0x05); /* Safe timing for now */
- OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock doubler */
- OUTB(nc_stest3, 0x00); /* Restart scsi clock */
- }
+ ncr_selectclock(np, np->rv_scntl3);
- OUTB (nc_scntl3, np->rv_scntl3);/* timing prescaler */
OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */
OUTW (nc_respid, 1ul<<np->myaddr);/* id to respond to */
OUTB (nc_istat , SIGP ); /* Signal Process */
@@ -5135,7 +5386,7 @@
else
OUTB (nc_ctest4, 0x00|np->rv_ctest4); /* disable master parity checking */
- OUTB (nc_stest2, EXT ); /* Extended Sreq/Sack filtering */
+ OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
OUTB (nc_stest3, TE ); /* TolerANT enable */
OUTB (nc_stime0, 0x0d ); /* HTH = disable STO = 0.4 sec. */
/* 0.25 sec recommended for scsi 1 */
@@ -5145,17 +5396,15 @@
** Have to renegotiate synch mode.
*/
- usrsync = 255;
-
- if (driver_setup.default_sync && SCSI_NCR_MAX_SYNC) {
- u_long period;
- period =1000000/driver_setup.default_sync; /* ns = 10e6 / kHz */
- if (period <= 11 * 50) {
- if (period < 4 * np->ns_sync)
+ usrsync = driver_setup.default_sync;
+ if (usrsync != 255) {
+ if (4 * usrsync <= 11 * 50) {
+ if (usrsync < np->ns_sync) {
usrsync = np->ns_sync;
- else
- usrsync = period / 4;
- };
+ }
+ }
+ else
+ usrsync = 255;
};
/*
@@ -5163,7 +5412,7 @@
** Have to renegotiate wide mode.
*/
- usrwide = (SCSI_NCR_MAX_WIDE);
+ usrwide = driver_setup.max_wide;
if (usrwide > np->maxwide) usrwide=np->maxwide;
/*
@@ -5189,6 +5438,27 @@
}
/*
+ ** Enable GPIO0 pin for writing.
+ ** Patch the script for LED support.
+ */
+
+ if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) {
+ OUTOFFB (nc_gpcntl, 0x01);
+ np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01);
+ np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+ np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+ }
+
+ /*
+ ** Upload the script into on-board RAM
+ */
+ if (np->vaddr2) {
+ if (bootverbose)
+ printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np));
+ bcopy(np->script0, np->script, sizeof(struct script));
+ }
+
+ /*
** enable ints
*/
@@ -5218,7 +5488,10 @@
u_long minsync = tp->usrsync;
- if (driver_setup.ultra_scsi) {
+ if (driver_setup.ultra_scsi >= 2) {
+ if (minsync < 10) minsync=10;
+ }
+ else if (driver_setup.ultra_scsi == 1) {
if (minsync < 12) minsync=12;
}
else {
@@ -5264,6 +5537,92 @@
/*==========================================================
**
+** Get clock factor and sync divisor.
+**
+**==========================================================
+*/
+
+#define SCSI_NCR_USE_ALL_DIVISORS
+
+/*
+** NCR chip clock divisor table.
+** Multiplied by 2x2000000 in order to avoid useless operations in
+** the code that gets clock factor and sync divisor from sync factor.
+*/
+#define _2M 2000000
+static u_long ncr_div2_2M[] = {2*_2M, 3*_2M, 4*_2M, 6*_2M, 8*_2M, 12*_2M, 16*_2M};
+
+/*
+** Get clock factor and sync divisor for a given sync factor period.
+** Returns the clock factor, scntl3 and resulting period.
+*/
+static int ncr_getsync(ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p)
+{
+ u_long clk = np->clock_khz; /* Clock in kHz */
+ int idiv = np->clock_divn; /* # divisors supported */
+ u_long fak, per, per_clk;
+
+ /*
+ ** Compute the synchronous period in nano-seconds
+ */
+ if (fac <= 10) per = 25;
+ else if (fac == 11) per = 30;
+ else if (fac == 12) per = 50;
+ else per = 4 * fac;
+
+ /*
+ ** Find the greatest divisor that allows an input speed
+ ** faster than the period.
+ */
+ per_clk = per * clk;
+ while (--idiv >= 0) {
+#ifndef SCSI_NCR_USE_ALL_DIVISORS
+ if (idiv & 1) continue;
+#endif
+ if (ncr_div2_2M[idiv] <= per_clk) break;
+ }
+ if (idiv < 0) idiv = 0; /* Should never happen */
+
+ /*
+ ** Calculate the lowest clock factor that allows an output
+ ** speed not faster than the period.
+ */
+ fak = (4 * per_clk - 1) / ncr_div2_2M[idiv] + 1;
+ per = (fak * ncr_div2_2M[idiv]) / (4 * clk);
+
+#ifdef SCSI_NCR_USE_ALL_DIVISORS
+ /*
+ ** Try the next divisor and choose the one that give
+ ** the fastest output speed.
+ */
+ if (idiv >= 1 && fak < 8) {
+ u_long fak2, per2;
+ fak2 = (4 * per_clk - 1) / ncr_div2_2M[idiv-1] + 1;
+ per2 = (fak2 * ncr_div2_2M[idiv-1]) / (4 * clk);
+ if (per2 < per && fak2 <= 8) {
+ fak = fak2;
+ per = per2;
+ --idiv;
+ }
+ }
+#endif
+ if (fak < 4) fak = 4; /* Should never happen */
+
+ /*
+ ** Compute and return sync parameters for the ncr
+ */
+ *fakp = fak - 4;
+ *scntl3p = ((idiv+1) << 4) + (per < 100 ? 0x80 : 0);
+
+#ifdef DEBUG
+printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp);
+#endif
+
+ return per;
+}
+
+/*==========================================================
+**
** Switch sync mode for current job and it's target
**
**==========================================================
@@ -5274,7 +5633,7 @@
Scsi_Cmnd *cmd;
tcb_p tp;
u_char target = INB (nc_ctest0) & 0x0f;
- u_char p2;
+ u_char idiv;
assert (cp);
if (!cp) return;
@@ -5292,18 +5651,16 @@
/*
** Deduce the value of controller sync period from scntl3.
- ** p2 is twice this value since we do integer calculations.
- * (12.5 ns would give inaccurate results)
*/
- p2 = (scntl3 & 0x07) == 0x05 ? 25 : 50;
- switch(scntl3 & 0x70) {
- case 0x50: p2 *= 4; break;
- case 0x30: p2 *= 2; break;
- default: break;
- }
-
- tp->period= sxfer&0x1f ? (((sxfer>>5)+4) * p2)/2 : 0xffff;
+ idiv = ((scntl3 >> 4) & 0x7);
+ if ((sxfer & 0x1f) && idiv)
+ tp->period = (((sxfer>>5)+4)*ncr_div2_2M[idiv-1])/(4*np->clock_khz);
+ else
+ tp->period = 0xffff;
+ /*
+ ** Stop there if sync parameters are unchanged
+ */
if (tp->sval == sxfer && tp->wval == scntl3) return;
tp->sval = sxfer;
tp->wval = scntl3;
@@ -5315,16 +5672,29 @@
if (sxfer & 0x01f) {
unsigned f10 = 10000 << (tp->widedone ? tp->widedone -1 : 0);
unsigned mb10 = (f10 + tp->period/2) / tp->period;
+ char *msg;
+
/*
** Disable extended Sreq/Sack filtering
*/
- if (tp->period <= 200) OUTB (nc_stest2, 0);
- printf ("%s%d.%d MB/s (%d ns, offset %d)\n",
- tp->widedone > 1 ?
- (tp->period < 100 ? "ULTRA WIDE SCSI " :
- (tp->period < 200 ? "FAST WIDE SCSI-2 ":"WIDE ")) :
- (tp->period < 100 ? "ULTRA SCSI " :
- (tp->period < 200 ? "FAST SCSI-2 ":"")),
+ if (tp->period <= 200) OUTOFFB (nc_stest2, EXT);
+
+ /*
+ ** Bells and whistles ;-)
+ */
+ msg = "";
+ if (tp->widedone > 1) {
+ if (tp->period < 50) msg = "ULTRA-2 WIDE SCSI ";
+ else if (tp->period < 100) msg = "ULTRA WIDE SCSI ";
+ else if (tp->period < 200) msg = "FAST WIDE SCSI-2 ";
+ }
+ else {
+ if (tp->period < 50) msg = "ULTRA-2 SCSI ";
+ else if (tp->period < 100) msg = "ULTRA SCSI ";
+ else if (tp->period < 200) msg = "FAST SCSI-2 ";
+ }
+
+ printf ("%s%d.%d MB/s (%d ns, offset %d)\n", msg,
mb10 / 10, mb10 % 10, tp->period, sxfer & 0x1f);
} else printf ("asynchronous.\n");
@@ -5339,7 +5709,7 @@
/*
** patch ALL ccbs of this target.
*/
- for (cp = &np->ccb; cp; cp = cp->link_ccb) {
+ for (cp = np->ccb; cp; cp = cp->link_ccb) {
if (!cp->cmd) continue;
if (cp->cmd->target != target) continue;
cp->sync_status = sxfer;
@@ -5395,7 +5765,7 @@
/*
** patch ALL ccbs of this target.
*/
- for (cp = &np->ccb; cp; cp = cp->link_ccb) {
+ for (cp = np->ccb; cp; cp = cp->link_ccb) {
if (!cp->cmd) continue;
if (cp->cmd->target != target) continue;
cp->wide_status = scntl3;
@@ -5627,6 +5997,7 @@
t = (thistime - np->heartbeat) / HZ;
if (t<2) np->latetime=0; else np->latetime++;
+#if 0
if (np->latetime>5) {
/*
** If there are no requests, the script
@@ -5637,6 +6008,7 @@
OUTB (nc_istat, SIGP);
}
+#endif
/*----------------------------------------------------
**
@@ -5645,7 +6017,7 @@
**----------------------------------------------------
*/
- for (cp=&np->ccb; cp; cp=cp->link_ccb) {
+ for (cp=np->ccb; cp; cp=cp->link_ccb) {
/*
** look for timed out ccbs.
*/
@@ -6077,7 +6449,7 @@
*/
dsa = INL (nc_dsa);
- cp = &np->ccb;
+ cp = np->ccb;
while (cp && (CCB_PHYS (cp, phys) != dsa))
cp = cp->link_ccb;
@@ -6091,7 +6463,7 @@
*/
scratcha = INL (nc_scratcha);
- diff = scratcha - NCB_SCRIPT_PHYS (np, tryloop);
+ diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop);
/* assert ((diff <= MAX_START * 20) && !(diff % 20));*/
@@ -6122,59 +6494,79 @@
{
u_int32 dbc;
u_int32 rest;
- u_int32 dsa;
u_int32 dsp;
+ u_int32 dsa;
u_int32 nxtdsp;
u_int32 *vdsp;
u_int32 oadr, olen;
u_int32 *tblp;
ncrcmd *newcmd;
- u_char cmd, sbcl, ss0, ss2, ctest5;
- u_short delta;
+ u_char cmd, sbcl;
ccb_p cp;
- dsp = INL (nc_dsp);
- dsa = INL (nc_dsa);
- dbc = INL (nc_dbc);
- ss0 = INB (nc_sstat0);
- ss2 = INB (nc_sstat2);
- sbcl= INB (nc_sbcl);
-
- if (driver_setup.special_features)
- ctest5 = INB (nc_ctest5);
- else
- ctest5 = 0;
-
- cmd = dbc >> 24;
- rest= dbc & 0xffffff;
+ dsp = INL (nc_dsp);
+ dbc = INL (nc_dbc);
+ sbcl = INB (nc_sbcl);
- if (ctest5 & 0x20)
- delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
- else
- delta=(INB (nc_dfifo) - rest) & 0x7f;
+ cmd = dbc >> 24;
+ rest = dbc & 0xffffff;
/*
- ** 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.
+ ** Take into account dma fifo and various buffers and latches,
+ ** only if the interrupted phase in an OUTPUT phase.
*/
- if (! (INB(nc_dstat) & DFE)) rest += delta;
- if (ss0 & OLF) rest++;
- if (ss0 & ORF) rest++;
- if (INB(nc_scntl3) & EWS) {
- if (ss2 & OLF1) rest++;
- if (ss2 & ORF1) rest++;
- };
- OUTONB (nc_ctest3, CLF ); /* clear dma fifo */
- OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+ if ((cmd & 1) == 0) {
+ u_char ctest5, ss0, ss2;
+ u_short delta;
+
+ if (!(INB(nc_dstat) & DFE)) {
+ ctest5 = (np->rv_ctest5 & 0x20) ? INB (nc_ctest5) : 0;
+ if (ctest5 & 0x20)
+ delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+ else
+ delta=(INB (nc_dfifo) - rest) & 0x7f;
+ } else {
+ delta = 0;
+ }
+
+ /*
+ ** 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.
+ */
+
+ rest += delta;
+ ss0 = INB (nc_sstat0);
+ if (ss0 & OLF) rest++;
+ if (ss0 & ORF) rest++;
+ if (INB(nc_scntl3) & EWS) {
+ ss2 = INB (nc_sstat2);
+ if (ss2 & OLF1) rest++;
+ if (ss2 & ORF1) rest++;
+ };
+
+ OUTONB (nc_ctest3, CLF ); /* clear dma fifo */
+ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */
+
+ if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+ printf ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
+ (unsigned) rest, (unsigned) delta, ss0);
+
+ } else {
+ if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+ printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
+ if (!(INB(nc_dstat) & DFE))
+ printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n",
+ cmd&7, sbcl&7, rest);
+ }
/*
** locate matching cp
*/
dsa = INL (nc_dsa);
- cp = &np->ccb;
+ cp = np->ccb;
while (cp && (CCB_PHYS (cp, phys) != dsa))
cp = cp->link_ccb;
@@ -6200,19 +6592,18 @@
} else if (dsp == vtophys (&cp->patch[6])) {
vdsp = &cp->patch[4];
nxtdsp = vdsp[3];
- } else {
+ } else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8);
nxtdsp = dsp;
+ } else {
+ vdsp = (u_int32 *) ((char*)np->scripth - np->p_scripth + dsp -8);
+ nxtdsp = dsp;
};
/*
** log the information
*/
- if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) {
- printf ("P%x%x ",cmd&7, sbcl&7);
- printf ("RL=%d D=%d SS0=%x ",
- (unsigned) rest, (unsigned) delta, ss0);
- };
+
if (DEBUG_FLAGS & DEBUG_PHASE) {
printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
cp, np->header.cp,
@@ -6349,7 +6740,7 @@
** lookup the ccb
*/
dsa = INL (nc_dsa);
- cp = &np->ccb;
+ cp = np->ccb;
while (cp && (CCB_PHYS (cp, phys) != dsa))
cp = cp->link_ccb;
@@ -6369,7 +6760,7 @@
** We have to patch the script context with DATA OUT context and
** restart processing at data out script address.
*/
- cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out);
+ cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out);
cp->phys.header.goalp = cp->phys.header.savep +20 +cp->segments*16;
cp->phys.header.lastp = cp->phys.header.savep;
np->header.savep = cp->phys.header.savep;
@@ -6415,7 +6806,7 @@
if (DEBUG_FLAGS & DEBUG_RESTART)
printf ("+ restart job ..\n");
OUTL (nc_dsa, CCB_PHYS (cp, phys));
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, getcc));
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc));
return;
};
@@ -6602,38 +6993,11 @@
/*
** Check against controller limits.
- ** --------------------------------
- ** per < 25 fast20
- ** per < 50 fast
- ** per < 100 slow
- ** Use a value p2 twice the controller limit in order to
- ** not do wrong integer calculation for 80 MHz clock.
- ** (12.5x2 = 25ns).
- ** Compute scntl3&0xf0 sync clock divisor for 50 ns period
- ** from the async pre-scaler.
- ** Ajust it according to actual controller sync period.
- ** - 0x40 divides it by 4 -> 50/4 = 12.5ns
- ** - 0x20 divides it by 2 -> 50/2 = 25 ns
- ** Similar stuff is used in ncr_getclock().
*/
fak = 7;
scntl3 = 0;
if (ofs != 0) {
- u_char p2;
-
- p2 = 100;
- scntl3 = (np->rv_scntl3 & 0x07) << 4;
-
- if (per < 25) {
- p2 = 25;
- scntl3 = (scntl3 - 0x40) | 0x80;
- }
- else if (per < 50) {
- p2 = 50;
- scntl3 = scntl3 - 0x20;
- }
-
- fak = (8 * per - 1) / p2 - 3;
+ (void) ncr_getsync(np, per, &fak, &scntl3);
if (fak > 7) {
chg = 1;
ofs = 0;
@@ -6942,7 +7306,7 @@
/*
** Look for a disconnected job.
*/
- cp = &np->ccb;
+ cp = np->ccb;
while (cp && cp->host_status != HS_DISCONNECT)
cp = cp->link_ccb;
@@ -7020,7 +7384,7 @@
if ((!cp) && lp && lp->actccbs > 0)
return ((ccb_p) 0);
- if (!cp) cp = &np->ccb;
+ if (!cp) cp = np->ccb;
/*
** Wait until available.
@@ -7072,7 +7436,7 @@
cp -> host_status = HS_IDLE;
cp -> magic = 0;
#if 0
- if (cp == &np->ccb)
+ if (cp == np->ccb)
wakeup ((caddr_t) cp);
#endif
}
@@ -7123,7 +7487,7 @@
tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun);
tp->jump_lcb.l_cmd = (SCR_JUMP);
- tp->jump_lcb.l_paddr = NCB_SCRIPT_PHYS (np, abort);
+ tp->jump_lcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
}
@@ -7135,7 +7499,7 @@
/*
** Allocate a lcb
*/
- lp = (lcb_p) m_alloc (sizeof (struct lcb));
+ lp = (lcb_p) m_alloc (sizeof (struct lcb), LCB_ALIGN_SHIFT);
if (!lp) return;
if (DEBUG_FLAGS & DEBUG_ALLOC) {
@@ -7154,7 +7518,7 @@
lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag);
lp->jump_ccb.l_cmd = (SCR_JUMP);
- lp->jump_ccb.l_paddr = NCB_SCRIPT_PHYS (np, aborttag);
+ lp->jump_ccb.l_paddr = NCB_SCRIPTH_PHYS (np, aborttag);
lp->actlink = 1;
@@ -7186,7 +7550,7 @@
/*
** Allocate a ccb
*/
- cp = (ccb_p) m_alloc (sizeof (struct ccb));
+ cp = (ccb_p) m_alloc (sizeof (struct ccb), CCB_ALIGN_SHIFT);
if (!cp)
return;
@@ -7224,8 +7588,8 @@
/*
** Chain into wakeup list
*/
- cp->link_ccb = np->ccb.link_ccb;
- np->ccb.link_ccb = cp;
+ cp->link_ccb = np->ccb->link_ccb;
+ np->ccb->link_ccb = cp;
/*
** Chain into CCB list
@@ -7401,7 +7765,7 @@
/*
** init
*/
- pc = NCB_SCRIPT_PHYS (np, snooptest);
+ pc = NCB_SCRIPTH_PHYS (np, snooptest);
host_wr = 1;
ncr_wr = 2;
/*
@@ -7445,11 +7809,11 @@
/*
** Check termination position.
*/
- if (pc != NCB_SCRIPT_PHYS (np, snoopend)+8) {
+ if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) {
printf ("CACHE TEST FAILED: script execution failed.\n");
printf ("start=%08lx, pc=%08lx, end=%08lx\n",
- (u_long) NCB_SCRIPT_PHYS (np, snooptest), pc,
- (u_long) NCB_SCRIPT_PHYS (np, snoopend) +8);
+ (u_long) NCB_SCRIPTH_PHYS (np, snooptest), pc,
+ (u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
return (0x40);
};
/*
@@ -7482,29 +7846,14 @@
**==========================================================
*/
-
#ifdef SCSI_NCR_PROFILE
-#if 0
-/*
-** Compute the difference in milliseconds.
-*/
-
-static int ncr_delta (u_long from, u_long to)
-{
- if (!from) return (-1);
- if (!to) return (-2);
- return ((to - from) * 1000 / HZ );
-}
-#else
-
/*
** Compute the difference in jiffies ticks.
*/
#define ncr_delta(from, to) \
( ((to) && (from))? (to) - (from) : -1 )
-#endif
#define PROFILE cp->phys.header.stamp
static void ncb_profile (ncb_p np, ccb_p cp)
@@ -7634,10 +7983,6 @@
**----------------------------------------------------------
*/
-#ifndef NCR_CLOCK
-# define NCR_CLOCK 40
-#endif /* NCR_CLOCK */
-
/*
* calculate NCR SCSI clock frequency (in KHz)
*/
@@ -7687,67 +8032,114 @@
return ms ? ((1 << gen) * 4340) / ms : 0;
}
-static void ncr_getclock (ncb_p np)
+/*
+ * Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+ if (np->multiplier < 2) {
+ OUTB(nc_scntl3, scntl3);
+ return;
+ }
+
+ if (bootverbose >= 2)
+ printf ("%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;
+ while (!(INB(nc_stest4) & 0x20) && --i > 0)
+ DELAY(20);
+ if (!i)
+ printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+ } else /* Wait 20 micro-seconds for doubler */
+ DELAY(20);
+ OUTB(nc_stest3, 0x20); /* Halt the scsi clock */
+ OUTB(nc_scntl3, scntl3);
+ OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */
+ OUTB(nc_stest3, 0x00); /* Restart scsi clock */
+}
+
+
+/*
+ * Get/probe NCR SCSI clock frequency
+ */
+static void ncr_getclock (ncb_p np, int mult)
{
unsigned char scntl3 = INB(nc_scntl3);
unsigned char stest1 = INB(nc_stest1);
+ unsigned f1;
+
+ np->multiplier = 1;
+ f1 = 40000;
/*
- ** Always false, except for 875 with clock doubler selected
- ** If true, disable clock doubler and assume 40 MHz clock.
+ ** True with 875 or 895 with clock multiplier selected
*/
- if ((stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
- if (driver_setup.ultra_scsi) {
- if (bootverbose >= 2)
- printf ("%s: clock doubler found\n", ncr_name(np));
- np->uf_doubler = 1;
- scntl3 = 5;
- }
- else {
+ if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
+ if (bootverbose >= 2)
+ printf ("%s: clock multiplier found\n", ncr_name(np));
+ np->multiplier = mult;
+ }
+
+ /*
+ ** 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)) {
+ unsigned f2;
+
+ OUTB(nc_istat, SRST); DELAY(5); OUTB(nc_istat, 0);
+
+ (void) ncrgetfreq (np, 11); /* throw away first result */
+ f1 = ncrgetfreq (np, 11);
+ f2 = ncrgetfreq (np, 11);
+
+ if (bootverbose)
+ printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
+
+ if (f1 > f2) f1 = f2; /* trust lower result */
+
+ if (f1 < 45000) f1 = 40000;
+ else if (f1 < 55000) f1 = 50000;
+ else f1 = 80000;
+
+ if (f1 < 80000 && mult > 1) {
if (bootverbose >= 2)
- printf ("%s: disabling clock doubler\n", ncr_name(np));
- OUTB(nc_stest1, 0);
- np->sv_scntl3 = 3; /* Fix scntl3 for next insmod */
- scntl3 = 3;
+ printf ("%s: clock multiplier assumed\n", ncr_name(np));
+ np->multiplier = mult;
}
} else {
- if ((scntl3 & 7) == 0) {
- unsigned f1, f2;
- /* throw away first result */
- (void) ncrgetfreq (np, 11);
- f1 = ncrgetfreq (np, 11);
- f2 = ncrgetfreq (np, 11);
-
- if (bootverbose)
- printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
- if (f1 > f2) f1 = f2; /* trust lower result */
- if (f1 > 45000) {
- scntl3 = 5; /* >45Mhz: assume 80MHz */
- } else {
- scntl3 = 3; /* <45Mhz: assume 40MHz */
- }
- }
+ if ((scntl3 & 7) == 3) f1 = 40000;
+ else if ((scntl3 & 7) == 5) f1 = 80000;
+ else f1 = 160000;
+
+ f1 /= np->multiplier;
}
/*
- ** Assume 40 Mhz clock if no dependable value supplied by BIOS.
+ ** Compute controller synchronous parameters.
*/
- if ((scntl3 & 7) < 3) {
- scntl3 = 3;
- }
+ f1 *= np->multiplier;
+ np->clock_khz = f1;
+ np->ns_sync = 25;
- if (driver_setup.ultra_scsi && ((scntl3 & 0x7) == 0x5)) {
- np->ns_sync = 12;
- np->rv_scntl3 = ((scntl3 & 0x7) << 4) -0x40 + (scntl3 & 0x7);
+ if (f1 >= 160000) {
+ if (driver_setup.ultra_scsi) np->ns_sync = 10;
+ np->rv_scntl3 = 7;
+ }
+ else if (f1 >= 80000) {
+ if (driver_setup.ultra_scsi) np->ns_sync = 12;
+ np->rv_scntl3 = 5;
}
else {
- np->ns_sync = 25;
- np->rv_scntl3 = ((scntl3 & 0x7) << 4) -0x20 + (scntl3 & 0x7);
+ np->rv_scntl3 = 3;
}
- if (bootverbose) {
+ if (bootverbose > 1) {
printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
- ncr_name(np), INB(nc_scntl3), np->rv_scntl3);
+ ncr_name(np), scntl3, np->rv_scntl3);
}
}
@@ -7768,8 +8160,10 @@
** CTEST4 0x80
** 0x80 burst disabled
** CTEST5 0x24
-** 0x20 dma fifo 536 (875 only)
-** 0x04 burst len 32/64/128 (875 only)
+** 0x20 large dma fifo (875 and 895 only)
+** 0x04 burst len 32/64/128 (875 and 895 only)
+** GPCNTL general purpose control register
+** STEST2 0x20 differential mode
*/
static void ncr_save_bios_setting(ncb_p np)
@@ -7780,6 +8174,8 @@
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;
}
/*===================== LINUX ENTRY POINTS SECTION ==========================*/
@@ -7855,13 +8251,26 @@
driver_setup.default_tags = val;
}
else if (!strncmp(cur, "sync:", 5))
- driver_setup.default_sync = val * 1000;
+ driver_setup.default_sync = val;
else if (!strncmp(cur, "verb:", 5))
driver_setup.verbose = val;
else if (!strncmp(cur, "debug:", 6))
driver_setup.debug = val;
else if (!strncmp(cur, "burst:", 6))
driver_setup.burst_max = val;
+ else if (!strncmp(cur, "led:", 4))
+ driver_setup.led_pin = val;
+ else if (!strncmp(cur, "wide:", 5))
+ driver_setup.max_wide = val? 1:0;
+ else if (!strncmp(cur, "settle:", 7))
+ driver_setup.settle_time= val;
+ else if (!strncmp(cur, "diff:", 5))
+ driver_setup.diff_support= val;
+ else if (!strncmp(cur, "irqm:", 5))
+ driver_setup.irqm = val;
+
+ else if (!strncmp(cur, "safe:", 5) && val)
+ memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
if ((cur = strchr(cur, ',')) != NULL)
++cur;
@@ -7916,19 +8325,24 @@
#define YesNo(y) y ? 'y' : 'n'
if (bootverbose >= 2) {
- printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d\n",
- YesNo(driver_setup.disconnection),
- YesNo(driver_setup.special_features),
- YesNo(driver_setup.ultra_scsi),
- driver_setup.default_tags,
- driver_setup.default_sync/1000,
- driver_setup.burst_max);
- printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x\n",
- YesNo(driver_setup.master_parity),
- YesNo(driver_setup.scsi_parity),
- YesNo(driver_setup.force_sync_nego),
- driver_setup.verbose,
- driver_setup.debug);
+ printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+ YesNo(driver_setup.disconnection),
+ YesNo(driver_setup.special_features),
+ YesNo(driver_setup.ultra_scsi),
+ driver_setup.default_tags,
+ driver_setup.default_sync,
+ driver_setup.burst_max,
+ YesNo(driver_setup.max_wide),
+ driver_setup.diff_support);
+ printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
+ YesNo(driver_setup.master_parity),
+ YesNo(driver_setup.scsi_parity),
+ YesNo(driver_setup.force_sync_nego),
+ driver_setup.verbose,
+ driver_setup.debug,
+ YesNo(driver_setup.led_pin),
+ driver_setup.settle_time,
+ driver_setup.irqm);
}
#undef YesNo
@@ -8053,13 +8467,6 @@
" match expected 0x%04x\n",
(unsigned int) device_id, (unsigned int) expected_id );
- if (max_revision != -1 && revision > max_revision)
- printk("ncr53c8xx: warning : revision %d is greater than expected.\n",
- (int) revision);
- else if (min_revision != -1 && revision < min_revision)
- printk("ncr53c8xx: warning : revision %d is lower than expected.\n",
- (int) revision);
-
if (io_port && check_region (io_port, 128)) {
printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
(int) io_port, (int) (io_port + 127));
@@ -8142,10 +8549,10 @@
host_data = (struct host_data *) host->hostdata;
#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
# ifdef SCSI_NCR_SHARE_IRQ
- if (dev_id == &host_data->ncb_data)
+ if (dev_id == host_data->ncb)
# endif
#endif
- ncr_intr(&host_data->ncb_data);
+ ncr_intr(host_data->ncb);
}
}
}
@@ -8169,9 +8576,7 @@
int ncr53c8xx_reset(Scsi_Cmnd *cmd)
#endif
{
-#ifdef DEBUG
-printk("ncr53c8xx_reset : reset call\n");
-#endif
+ printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid);
return ncr_reset_bus(cmd);
}
@@ -8181,7 +8586,7 @@
int ncr53c8xx_abort(Scsi_Cmnd *cmd)
{
-printk("ncr53c8xx_abort : abort call\n");
+ printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
return ncr_abort_command(cmd);
}
@@ -8196,7 +8601,7 @@
for (host = first_host; host; host = host->next) {
if (host->hostt == the_template) {
host_data = (struct host_data *) host->hostdata;
- ncr_detach(&host_data->ncb_data, host->irq);
+ ncr_detach(host_data->ncb, host->irq);
}
}
@@ -8236,17 +8641,19 @@
}
}
-static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd)
+static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd)
{
Scsi_Cmnd *wcmd;
if (!(wcmd = np->waiting_list)) return 0;
while (wcmd->next_wcmd) {
if (cmd == (Scsi_Cmnd *) wcmd->next_wcmd) {
- wcmd->next_wcmd = cmd->next_wcmd;
- cmd->next_wcmd = 0;
+ if (to_remove) {
+ wcmd->next_wcmd = cmd->next_wcmd;
+ cmd->next_wcmd = 0;
+ }
#ifdef DEBUG_WAITING_LIST
- printf("%s: cmd %lx removed from waiting list\n", ncr_name(np), (u_long) cmd);
+ printf("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
#endif
return cmd;
}
@@ -8583,11 +8990,7 @@
** Copy formatted profile information into the input buffer.
*/
-#if 0
-#define to_ms(t) (t)
-#else
#define to_ms(t) ((t) * 1000 / HZ)
-#endif
static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
{
@@ -8650,7 +9053,7 @@
for (host = first_host; host; host = host->next) {
if (host->hostt == the_template && host->host_no == hostno) {
host_data = (struct host_data *) host->hostdata;
- ncb = &host_data->ncb_data;
+ ncb = host_data->ncb;
break;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov