ncr53c8xx.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:225k
- /******************************************************************************
- ** Device driver for the PCI-SCSI NCR538XX controller family.
- **
- ** Copyright (C) 1994 Wolfgang Stanglmeier
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- **
- **-----------------------------------------------------------------------------
- **
- ** This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
- ** and is currently maintained by
- **
- ** Gerard Roudier <groudier@free.fr>
- **
- ** Being given that this driver originates from the FreeBSD version, and
- ** in order to keep synergy on both, any suggested enhancements and corrections
- ** received on Linux are automatically a potential candidate for the FreeBSD
- ** version.
- **
- ** The original driver has been written for 386bsd and FreeBSD by
- ** Wolfgang Stanglmeier <wolf@cologne.de>
- ** Stefan Esser <se@mi.Uni-Koeln.de>
- **
- ** And has been ported to NetBSD by
- ** Charles M. Hannum <mycroft@gnu.ai.mit.edu>
- **
- **-----------------------------------------------------------------------------
- **
- ** Brief history
- **
- ** December 10 1995 by Gerard Roudier:
- ** Initial port to Linux.
- **
- ** June 23 1996 by Gerard Roudier:
- ** Support for 64 bits architectures (Alpha).
- **
- ** November 30 1996 by Gerard Roudier:
- ** Support for Fast-20 scsi.
- ** Support for large DMA fifo and 128 dwords bursting.
- **
- ** February 27 1997 by Gerard Roudier:
- ** Support for Fast-40 scsi.
- ** Support for on-Board RAM.
- **
- ** May 3 1997 by Gerard Roudier:
- ** Full support for scsi scripts instructions pre-fetching.
- **
- ** May 19 1997 by Richard Waltham <dormouse@farsrobt.demon.co.uk>:
- ** Support for NvRAM detection and reading.
- **
- ** August 18 1997 by Cort <cort@cs.nmt.edu>:
- ** Support for Power/PC (Big Endian).
- **
- ** June 20 1998 by Gerard Roudier
- ** Support for up to 64 tags per lun.
- ** O(1) everywhere (C and SCRIPTS) for normal cases.
- ** Low PCI traffic for command handling when on-chip RAM is present.
- ** Aggressive SCSI SCRIPTS optimizations.
- **
- *******************************************************************************
- */
- /*
- ** Supported SCSI-II features:
- ** Synchronous negotiation
- ** Wide negotiation (depends on the NCR Chip)
- ** Enable disconnection
- ** Tagged command queuing
- ** Parity checking
- ** Etc...
- **
- ** Supported NCR/SYMBIOS chips:
- ** 53C810 (8 bits, Fast SCSI-2, no rom BIOS)
- ** 53C815 (8 bits, Fast SCSI-2, on board rom BIOS)
- ** 53C820 (Wide, Fast SCSI-2, no rom BIOS)
- ** 53C825 (Wide, Fast SCSI-2, on board rom BIOS)
- ** 53C860 (8 bits, Fast 20, no rom BIOS)
- ** 53C875 (Wide, Fast 20, on board rom BIOS)
- ** 53C895 (Wide, Fast 40, on board rom BIOS)
- ** 53C895A (Wide, Fast 40, on board rom BIOS)
- ** 53C896 (Wide, Fast 40, on board rom BIOS)
- ** 53C897 (Wide, Fast 40, on board rom BIOS)
- ** 53C1510D (Wide, Fast 40, on board rom BIOS)
- **
- ** Other features:
- ** Memory mapped IO (linux-1.3.X and above only)
- ** Module
- ** Shared IRQ (since linux-1.3.72)
- */
- /*
- ** Name and version of the driver
- */
- #define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3b-20010512"
- #define SCSI_NCR_DEBUG_FLAGS (0)
- /*==========================================================
- **
- ** Include files
- **
- **==========================================================
- */
- #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
- #include <linux/module.h>
- #include <asm/dma.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
- #include <linux/spinlock.h>
- #elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
- #include <asm/spinlock.h>
- #endif
- #include <linux/delay.h>
- #include <linux/signal.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/pci.h>
- #include <linux/string.h>
- #include <linux/mm.h>
- #include <linux/ioport.h>
- #include <linux/time.h>
- #include <linux/timer.h>
- #include <linux/stat.h>
- #include <linux/version.h>
- #include <linux/blk.h>
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
- #include <linux/init.h>
- #endif
- #ifndef __init
- #define __init
- #endif
- #ifndef __initdata
- #define __initdata
- #endif
- #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
- #include <linux/bios32.h>
- #endif
- #include "scsi.h"
- #include "hosts.h"
- #include "constants.h"
- #include "sd.h"
- #include <linux/types.h>
- /*
- ** Define BITS_PER_LONG for earlier linux versions.
- */
- #ifndef BITS_PER_LONG
- #if (~0UL) == 0xffffffffUL
- #define BITS_PER_LONG 32
- #else
- #define BITS_PER_LONG 64
- #endif
- #endif
- /*
- ** Define the BSD style u_int32 and u_int64 type.
- ** Are in fact u_int32_t and u_int64_t :-)
- */
- typedef u32 u_int32;
- typedef u64 u_int64;
- typedef u_long vm_offset_t;
- #include "ncr53c8xx.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) */
- #if 0
- #define SCSI_NCR_INTEGRITY_CHECKING
- #endif
- #define NAME53C "ncr53c"
- #define NAME53C8XX "ncr53c8xx"
- #define DRIVER_SMP_LOCK ncr53c8xx_lock
- #include "sym53c8xx_comm.h"
- /*==========================================================
- **
- ** The CCB done queue uses an array of CCB virtual
- ** addresses. Empty entries are flagged using the bogus
- ** virtual address 0xffffffff.
- **
- ** Since PCI ensures that only aligned DWORDs are accessed
- ** atomically, 64 bit little-endian architecture requires
- ** to test the high order DWORD of the entry to determine
- ** if it is empty or valid.
- **
- ** BTW, I will make things differently as soon as I will
- ** have a better idea, but this is simple and should work.
- **
- **==========================================================
- */
-
- #define SCSI_NCR_CCB_DONE_SUPPORT
- #ifdef SCSI_NCR_CCB_DONE_SUPPORT
- #define MAX_DONE 24
- #define CCB_DONE_EMPTY 0xffffffffUL
- /* All 32 bit architectures */
- #if BITS_PER_LONG == 32
- #define CCB_DONE_VALID(cp) (((u_long) cp) != CCB_DONE_EMPTY)
- /* All > 32 bit (64 bit) architectures regardless endian-ness */
- #else
- #define CCB_DONE_VALID(cp)
- ((((u_long) cp) & 0xffffffff00000000ul) &&
- (((u_long) cp) & 0xfffffffful) != CCB_DONE_EMPTY)
- #endif
- #endif /* SCSI_NCR_CCB_DONE_SUPPORT */
- /*==========================================================
- **
- ** Configuration and Debugging
- **
- **==========================================================
- */
- /*
- ** SCSI address of this device.
- ** The boot routines should have set it.
- ** If not, use this.
- */
- #ifndef SCSI_NCR_MYADDR
- #define SCSI_NCR_MYADDR (7)
- #endif
- /*
- ** The maximum number of tags per logic unit.
- ** Used only for disk devices that support tags.
- */
- #ifndef SCSI_NCR_MAX_TAGS
- #define SCSI_NCR_MAX_TAGS (8)
- #endif
- /*
- ** TAGS are actually limited to 64 tags/lun.
- ** We need to deal with power of 2, for alignment constraints.
- */
- #if SCSI_NCR_MAX_TAGS > 64
- #define MAX_TAGS (64)
- #else
- #define MAX_TAGS SCSI_NCR_MAX_TAGS
- #endif
- #define NO_TAG (255)
- /*
- ** Choose appropriate type for tag bitmap.
- */
- #if MAX_TAGS > 32
- typedef u_int64 tagmap_t;
- #else
- typedef u_int32 tagmap_t;
- #endif
- /*
- ** Number of targets supported by the driver.
- ** n permits target numbers 0..n-1.
- ** Default is 16, meaning targets #0..#15.
- ** #7 .. is myself.
- */
- #ifdef SCSI_NCR_MAX_TARGET
- #define MAX_TARGET (SCSI_NCR_MAX_TARGET)
- #else
- #define MAX_TARGET (16)
- #endif
- /*
- ** Number of logic units supported by the driver.
- ** n enables logic unit numbers 0..n-1.
- ** The common SCSI devices require only
- ** one lun, so take 1 as the default.
- */
- #ifdef SCSI_NCR_MAX_LUN
- #define MAX_LUN SCSI_NCR_MAX_LUN
- #else
- #define MAX_LUN (1)
- #endif
- /*
- ** Asynchronous pre-scaler (ns). Shall be 40
- */
-
- #ifndef SCSI_NCR_MIN_ASYNC
- #define SCSI_NCR_MIN_ASYNC (40)
- #endif
- /*
- ** The maximum number of jobs scheduled for starting.
- ** There should be one slot per target, and one slot
- ** for each tag of each target in use.
- ** The calculation below is actually quite silly ...
- */
- #ifdef SCSI_NCR_CAN_QUEUE
- #define MAX_START (SCSI_NCR_CAN_QUEUE + 4)
- #else
- #define MAX_START (MAX_TARGET + 7 * MAX_TAGS)
- #endif
- /*
- ** We limit the max number of pending IO to 250.
- ** since we donnot want to allocate more than 1
- ** PAGE for 'scripth'.
- */
- #if MAX_START > 250
- #undef MAX_START
- #define MAX_START 250
- #endif
- /*
- ** The maximum number of segments a transfer is split into.
- ** We support up to 127 segments for both read and write.
- ** The data scripts are broken into 2 sub-scripts.
- ** 80 (MAX_SCATTERL) segments are moved from a sub-script
- ** in on-chip RAM. This makes data transfers shorter than
- ** 80k (assuming 1k fs) as fast as possible.
- */
- #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
- #if (MAX_SCATTER > 80)
- #define MAX_SCATTERL 80
- #define MAX_SCATTERH (MAX_SCATTER - MAX_SCATTERL)
- #else
- #define MAX_SCATTERL (MAX_SCATTER-1)
- #define MAX_SCATTERH 1
- #endif
- /*
- ** other
- */
- #define NCR_SNOOP_TIMEOUT (1000000)
- /*
- ** Head of list of NCR boards
- **
- ** For kernel version < 1.3.70, host is retrieved by its irq level.
- ** For later kernels, the internal host control block address
- ** (struct ncb) is used as device id parameter of the irq stuff.
- */
- static struct Scsi_Host *first_host = NULL;
- static Scsi_Host_Template *the_template = NULL;
- /*
- ** Other definitions
- */
- #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
- static void ncr53c8xx_select_queue_depths(
- struct Scsi_Host *host, struct scsi_device *devlist);
- static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
- static void ncr53c8xx_timeout(unsigned long np);
- #define initverbose (driver_setup.verbose)
- #define bootverbose (np->verbose)
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- static u_char Tekram_sync[16] __initdata =
- {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
- #endif /* SCSI_NCR_NVRAM_SUPPORT */
- /*==========================================================
- **
- ** Command control block states.
- **
- **==========================================================
- */
- #define HS_IDLE (0)
- #define HS_BUSY (1)
- #define HS_NEGOTIATE (2) /* sync/wide data transfer*/
- #define HS_DISCONNECT (3) /* Disconnected by target */
- #define HS_DONEMASK (0x80)
- #define HS_COMPLETE (4|HS_DONEMASK)
- #define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */
- #define HS_RESET (6|HS_DONEMASK) /* SCSI reset */
- #define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */
- #define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */
- #define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */
- #define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */
- /*
- ** Invalid host status values used by the SCRIPTS processor
- ** when the nexus is not fully identified.
- ** Shall never appear in a CCB.
- */
- #define HS_INVALMASK (0x40)
- #define HS_SELECTING (0|HS_INVALMASK)
- #define HS_IN_RESELECT (1|HS_INVALMASK)
- #define HS_STARTING (2|HS_INVALMASK)
- /*
- ** Flags set by the SCRIPT processor for commands
- ** that have been skipped.
- */
- #define HS_SKIPMASK (0x20)
- /*==========================================================
- **
- ** Software Interrupt Codes
- **
- **==========================================================
- */
- #define SIR_BAD_STATUS (1)
- #define SIR_XXXXXXXXXX (2)
- #define SIR_NEGO_SYNC (3)
- #define SIR_NEGO_WIDE (4)
- #define SIR_NEGO_FAILED (5)
- #define SIR_NEGO_PROTO (6)
- #define SIR_REJECT_RECEIVED (7)
- #define SIR_REJECT_SENT (8)
- #define SIR_IGN_RESIDUE (9)
- #define SIR_MISSING_SAVE (10)
- #define SIR_RESEL_NO_MSG_IN (11)
- #define SIR_RESEL_NO_IDENTIFY (12)
- #define SIR_RESEL_BAD_LUN (13)
- #define SIR_RESEL_BAD_TARGET (14)
- #define SIR_RESEL_BAD_I_T_L (15)
- #define SIR_RESEL_BAD_I_T_L_Q (16)
- #define SIR_DONE_OVERFLOW (17)
- #define SIR_MAX (17)
- /*==========================================================
- **
- ** Extended error codes.
- ** xerr_status field of struct ccb.
- **
- **==========================================================
- */
- #define XE_OK (0)
- #define XE_EXTRA_DATA (1) /* unexpected data phase */
- #define XE_BAD_PHASE (2) /* illegal phase (4/5) */
- /*==========================================================
- **
- ** Negotiation status.
- ** nego_status field of struct ccb.
- **
- **==========================================================
- */
- #define NS_NOCHANGE (0)
- #define NS_SYNC (1)
- #define NS_WIDE (2)
- #define NS_PPR (4)
- /*==========================================================
- **
- ** "Special features" of targets.
- ** quirks field of struct tcb.
- ** actualquirks field of struct ccb.
- **
- **==========================================================
- */
- #define QUIRK_AUTOSAVE (0x01)
- #define QUIRK_NOMSG (0x02)
- #define QUIRK_NOSYNC (0x10)
- #define QUIRK_NOWIDE16 (0x20)
- /*==========================================================
- **
- ** Capability bits in Inquire response byte 7.
- **
- **==========================================================
- */
- #define INQ7_QUEUE (0x02)
- #define INQ7_SYNC (0x10)
- #define INQ7_WIDE16 (0x20)
- /*==========================================================
- **
- ** Misc.
- **
- **==========================================================
- */
- #define CCB_MAGIC (0xf2691ad2)
- /*==========================================================
- **
- ** Declaration of structs.
- **
- **==========================================================
- */
- struct tcb;
- struct lcb;
- struct ccb;
- struct ncb;
- struct script;
- typedef struct ncb * ncb_p;
- typedef struct tcb * tcb_p;
- typedef struct lcb * lcb_p;
- typedef struct ccb * ccb_p;
- struct link {
- ncrcmd l_cmd;
- ncrcmd l_paddr;
- };
- struct usrcmd {
- u_long target;
- u_long lun;
- u_long data;
- u_long cmd;
- };
- #define UC_SETSYNC 10
- #define UC_SETTAGS 11
- #define UC_SETDEBUG 12
- #define UC_SETORDER 13
- #define UC_SETWIDE 14
- #define UC_SETFLAG 15
- #define UC_SETVERBOSE 17
- #define UF_TRACE (0x01)
- #define UF_NODISC (0x02)
- #define UF_NOSCAN (0x04)
- /*========================================================================
- **
- ** Declaration of structs: target control block
- **
- **========================================================================
- */
- struct tcb {
- /*----------------------------------------------------------------
- ** During reselection the ncr jumps to this point with SFBR
- ** set to the encoded target number with bit 7 set.
- ** if it's not this target, jump to the next.
- **
- ** JUMP IF (SFBR != #target#), @(next tcb)
- **----------------------------------------------------------------
- */
- struct link jump_tcb;
- /*----------------------------------------------------------------
- ** Load the actual values for the sxfer and the scntl3
- ** register (sync/wide mode).
- **
- ** SCR_COPY (1), @(sval field of this tcb), @(sxfer register)
- ** SCR_COPY (1), @(wval field of this tcb), @(scntl3 register)
- **----------------------------------------------------------------
- */
- ncrcmd getscr[6];
- /*----------------------------------------------------------------
- ** Get the IDENTIFY message and load the LUN to SFBR.
- **
- ** CALL, <RESEL_LUN>
- **----------------------------------------------------------------
- */
- struct link call_lun;
- /*----------------------------------------------------------------
- ** Now look for the right lun.
- **
- ** For i = 0 to 3
- ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(first lcb mod. i)
- **
- ** Recent chips will prefetch the 4 JUMPS using only 1 burst.
- ** It is kind of hashcoding.
- **----------------------------------------------------------------
- */
- struct link jump_lcb[4]; /* JUMPs for reselection */
- lcb_p lp[MAX_LUN]; /* The lcb's of this tcb */
- u_char inq_done; /* Target capabilities received */
- u_char inq_byte7; /* Contains these capabilities */
- /*----------------------------------------------------------------
- ** Pointer to the ccb used for negotiation.
- ** Prevent from starting a negotiation for all queued commands
- ** when tagged command queuing is enabled.
- **----------------------------------------------------------------
- */
- ccb_p nego_cp;
- /*----------------------------------------------------------------
- ** statistical data
- **----------------------------------------------------------------
- */
- u_long transfers;
- u_long bytes;
- /*----------------------------------------------------------------
- ** negotiation of wide and synch transfer and device quirks.
- **----------------------------------------------------------------
- */
- /*0*/ u_char minsync;
- /*1*/ u_char sval;
- /*2*/ u_short period;
- /*0*/ u_char maxoffs;
- /*1*/ u_char quirks;
- /*2*/ u_char widedone;
- /*3*/ u_char wval;
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- u_char ic_min_sync;
- u_char ic_max_width;
- u_char ic_maximums_set;
- u_char ic_done;
- #endif
- /*----------------------------------------------------------------
- ** User settable limits and options.
- ** These limits are read from the NVRAM if present.
- **----------------------------------------------------------------
- */
- u_char usrsync;
- u_char usrwide;
- u_char usrtags;
- u_char usrflag;
- };
- /*========================================================================
- **
- ** Declaration of structs: lun control block
- **
- **========================================================================
- */
- struct lcb {
- /*----------------------------------------------------------------
- ** During reselection the ncr jumps to this point
- ** with SFBR set to the "Identify" message.
- ** if it's not this lun, jump to the next.
- **
- ** JUMP IF (SFBR != #lun#), @(next lcb of this target)
- **
- ** It is this lun. Load TEMP with the nexus jumps table
- ** address and jump to RESEL_TAG (or RESEL_NOTAG).
- **
- ** SCR_COPY (4), p_jump_ccb, TEMP,
- ** SCR_JUMP, <RESEL_TAG>
- **----------------------------------------------------------------
- */
- struct link jump_lcb;
- ncrcmd load_jump_ccb[3];
- struct link jump_tag;
- ncrcmd p_jump_ccb; /* Jump table bus address */
- /*----------------------------------------------------------------
- ** Jump table used by the script processor to directly jump
- ** to the CCB corresponding to the reselected nexus.
- ** Address is allocated on 256 bytes boundary in order to
- ** allow 8 bit calculation of the tag jump entry for up to
- ** 64 possible tags.
- **----------------------------------------------------------------
- */
- u_int32 jump_ccb_0; /* Default table if no tags */
- u_int32 *jump_ccb; /* Virtual address */
- /*----------------------------------------------------------------
- ** CCB queue management.
- **----------------------------------------------------------------
- */
- XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */
- XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */
- XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */
- XPT_QUEHEAD skip_ccbq; /* Queue of skipped CCBs */
- u_char actccbs; /* Number of allocated CCBs */
- u_char busyccbs; /* CCBs busy for this lun */
- u_char queuedccbs; /* CCBs queued to the controller*/
- u_char queuedepth; /* Queue depth for this lun */
- u_char scdev_depth; /* SCSI device queue depth */
- u_char maxnxs; /* Max possible nexuses */
- /*----------------------------------------------------------------
- ** Control of tagged command queuing.
- ** Tags allocation is performed using a circular buffer.
- ** This avoids using a loop for tag allocation.
- **----------------------------------------------------------------
- */
- u_char ia_tag; /* Allocation index */
- u_char if_tag; /* Freeing index */
- u_char cb_tags[MAX_TAGS]; /* Circular tags buffer */
- u_char usetags; /* Command queuing is active */
- u_char maxtags; /* Max nr of tags asked by user */
- u_char numtags; /* Current number of tags */
- u_char inq_byte7; /* Store unit CmdQ capabitility */
- /*----------------------------------------------------------------
- ** QUEUE FULL control and ORDERED tag control.
- **----------------------------------------------------------------
- */
- /*----------------------------------------------------------------
- ** QUEUE FULL and ORDERED tag control.
- **----------------------------------------------------------------
- */
- u_short num_good; /* Nr of GOOD since QUEUE FULL */
- tagmap_t tags_umap; /* Used tags bitmap */
- tagmap_t tags_smap; /* Tags in use at 'tag_stime' */
- u_long tags_stime; /* Last time we set smap=umap */
- ccb_p held_ccb; /* CCB held for QUEUE FULL */
- };
- /*========================================================================
- **
- ** Declaration of structs: the launch script.
- **
- **========================================================================
- **
- ** It is part of the CCB and is called by the scripts processor to
- ** start or restart the data structure (nexus).
- ** This 6 DWORDs mini script makes use of prefetching.
- **
- **------------------------------------------------------------------------
- */
- struct launch {
- /*----------------------------------------------------------------
- ** SCR_COPY(4), @(p_phys), @(dsa register)
- ** SCR_JUMP, @(scheduler_point)
- **----------------------------------------------------------------
- */
- ncrcmd setup_dsa[3]; /* Copy 'phys' address to dsa */
- struct link schedule; /* Jump to scheduler point */
- ncrcmd p_phys; /* 'phys' header bus address */
- };
- /*========================================================================
- **
- ** Declaration of structs: global HEADER.
- **
- **========================================================================
- **
- ** This substructure is copied from the ccb to a global address after
- ** selection (or reselection) and copied back before disconnect.
- **
- ** These fields are accessible to the script processor.
- **
- **------------------------------------------------------------------------
- */
- struct head {
- /*----------------------------------------------------------------
- ** Saved data pointer.
- ** Points to the position in the script responsible for the
- ** actual transfer transfer of data.
- ** It's written after reception of a SAVE_DATA_POINTER message.
- ** The goalpointer points after the last transfer command.
- **----------------------------------------------------------------
- */
- u_int32 savep;
- u_int32 lastp;
- u_int32 goalp;
- /*----------------------------------------------------------------
- ** Alternate data pointer.
- ** They are copied back to savep/lastp/goalp by the SCRIPTS
- ** when the direction is unknown and the device claims data out.
- **----------------------------------------------------------------
- */
- u_int32 wlastp;
- u_int32 wgoalp;
- /*----------------------------------------------------------------
- ** The virtual address of the ccb containing this header.
- **----------------------------------------------------------------
- */
- ccb_p cp;
- /*----------------------------------------------------------------
- ** Status fields.
- **----------------------------------------------------------------
- */
- u_char scr_st[4]; /* script status */
- u_char status[4]; /* host status. must be the */
- /* last DWORD of the header. */
- };
- /*
- ** The status bytes are used by the host and the script processor.
- **
- ** The byte corresponding to the host_status must be stored in the
- ** last DWORD of the CCB header since it is used for command
- ** completion (ncr_wakeup()). Doing so, we are sure that the header
- ** has been entirely copied back to the CCB when the host_status is
- ** seen complete by the CPU.
- **
- ** The last four bytes (status[4]) are copied to the scratchb register
- ** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
- ** and copied back just after disconnecting.
- ** Inside the script the XX_REG are used.
- **
- ** The first four bytes (scr_st[4]) are used inside the script by
- ** "COPY" commands.
- ** Because source and destination must have the same alignment
- ** in a DWORD, the fields HAVE to be at the choosen offsets.
- ** xerr_st 0 (0x34) scratcha
- ** sync_st 1 (0x05) sxfer
- ** wide_st 3 (0x03) scntl3
- */
- /*
- ** Last four bytes (script)
- */
- #define QU_REG scr0
- #define HS_REG scr1
- #define HS_PRT nc_scr1
- #define SS_REG scr2
- #define SS_PRT nc_scr2
- #define PS_REG scr3
- /*
- ** Last four bytes (host)
- */
- #define actualquirks phys.header.status[0]
- #define host_status phys.header.status[1]
- #define scsi_status phys.header.status[2]
- #define parity_status phys.header.status[3]
- /*
- ** First four bytes (script)
- */
- #define xerr_st header.scr_st[0]
- #define sync_st header.scr_st[1]
- #define nego_st header.scr_st[2]
- #define wide_st header.scr_st[3]
- /*
- ** First four bytes (host)
- */
- #define xerr_status phys.xerr_st
- #define nego_status phys.nego_st
- #if 0
- #define sync_status phys.sync_st
- #define wide_status phys.wide_st
- #endif
- /*==========================================================
- **
- ** Declaration of structs: Data structure block
- **
- **==========================================================
- **
- ** During execution of a ccb by the script processor,
- ** the DSA (data structure address) register points
- ** to this substructure of the ccb.
- ** This substructure contains the header with
- ** the script-processor-changable data and
- ** data blocks for the indirect move commands.
- **
- **----------------------------------------------------------
- */
- struct dsb {
- /*
- ** Header.
- */
- struct head header;
- /*
- ** Table data for Script
- */
- struct scr_tblsel select;
- struct scr_tblmove smsg ;
- struct scr_tblmove cmd ;
- struct scr_tblmove sense ;
- struct scr_tblmove data [MAX_SCATTER];
- };
- /*========================================================================
- **
- ** Declaration of structs: Command control block.
- **
- **========================================================================
- */
- struct ccb {
- /*----------------------------------------------------------------
- ** This is the data structure which is pointed by the DSA
- ** register when it is executed by the script processor.
- ** It must be the first entry because it contains the header
- ** as first entry that must be cache line aligned.
- **----------------------------------------------------------------
- */
- struct dsb phys;
- /*----------------------------------------------------------------
- ** Mini-script used at CCB execution start-up.
- ** Load the DSA with the data structure address (phys) and
- ** jump to SELECT. Jump to CANCEL if CCB is to be canceled.
- **----------------------------------------------------------------
- */
- struct launch start;
- /*----------------------------------------------------------------
- ** Mini-script used at CCB relection to restart the nexus.
- ** Load the DSA with the data structure address (phys) and
- ** jump to RESEL_DSA. Jump to ABORT if CCB is to be aborted.
- **----------------------------------------------------------------
- */
- struct launch restart;
- /*----------------------------------------------------------------
- ** If a data transfer phase is terminated too early
- ** (after reception of a message (i.e. DISCONNECT)),
- ** we have to prepare a mini script to transfer
- ** the rest of the data.
- **----------------------------------------------------------------
- */
- ncrcmd patch[8];
- /*----------------------------------------------------------------
- ** The general SCSI driver provides a
- ** pointer to a control block.
- **----------------------------------------------------------------
- */
- Scsi_Cmnd *cmd; /* SCSI command */
- u_char cdb_buf[16]; /* Copy of CDB */
- u_char sense_buf[64];
- int data_len; /* Total data length */
- /*----------------------------------------------------------------
- ** Message areas.
- ** We prepare a message to be sent after selection.
- ** We may use a second one if the command is rescheduled
- ** due to GETCC or QFULL.
- ** Contents are IDENTIFY and SIMPLE_TAG.
- ** While negotiating sync or wide transfer,
- ** a SDTR or WDTR message is appended.
- **----------------------------------------------------------------
- */
- u_char scsi_smsg [8];
- u_char scsi_smsg2[8];
- /*----------------------------------------------------------------
- ** Other fields.
- **----------------------------------------------------------------
- */
- u_long p_ccb; /* BUS address of this CCB */
- u_char sensecmd[6]; /* Sense command */
- u_char tag; /* Tag for this transfer */
- /* 255 means no tag */
- u_char target;
- u_char lun;
- u_char queued;
- u_char auto_sense;
- ccb_p link_ccb; /* Host adapter CCB chain */
- XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */
- u_int32 startp; /* Initial data pointer */
- u_long magic; /* Free / busy CCB flag */
- };
- #define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl))
- /*========================================================================
- **
- ** Declaration of structs: NCR device descriptor
- **
- **========================================================================
- */
- struct ncb {
- /*----------------------------------------------------------------
- ** The global header.
- ** It is accessible to both the host and the script processor.
- ** Must be cache line size aligned (32 for x86) in order to
- ** allow cache line bursting when it is copied to/from CCB.
- **----------------------------------------------------------------
- */
- struct head header;
- /*----------------------------------------------------------------
- ** CCBs management queues.
- **----------------------------------------------------------------
- */
- Scsi_Cmnd *waiting_list; /* Commands waiting for a CCB */
- /* when lcb is not allocated. */
- Scsi_Cmnd *done_list; /* Commands waiting for done() */
- /* callback to be invoked. */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
- spinlock_t smp_lock; /* Lock for SMP threading */
- #endif
- /*----------------------------------------------------------------
- ** Chip and controller indentification.
- **----------------------------------------------------------------
- */
- int unit; /* Unit number */
- char chip_name[8]; /* Chip name */
- char inst_name[16]; /* ncb instance name */
- /*----------------------------------------------------------------
- ** Initial value of some IO register bits.
- ** These values are assumed to have been set by BIOS, and may
- ** be used for probing adapter implementation differences.
- **----------------------------------------------------------------
- */
- u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
- sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4;
- /*----------------------------------------------------------------
- ** Actual initial value of IO register bits used by the
- ** driver. They are loaded at initialisation according to
- ** features that are to be enabled.
- **----------------------------------------------------------------
- */
- u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4,
- rv_ctest5, rv_stest2;
- /*----------------------------------------------------------------
- ** Targets management.
- ** During reselection the ncr jumps to jump_tcb.
- ** The SFBR register is loaded with the encoded target id.
- ** For i = 0 to 3
- ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(next tcb mod. i)
- **
- ** Recent chips will prefetch the 4 JUMPS using only 1 burst.
- ** It is kind of hashcoding.
- **----------------------------------------------------------------
- */
- struct link jump_tcb[4]; /* JUMPs for reselection */
- struct tcb target[MAX_TARGET]; /* Target data */
- /*----------------------------------------------------------------
- ** Virtual and physical bus addresses of the chip.
- **----------------------------------------------------------------
- */
- vm_offset_t vaddr; /* Virtual and bus address of */
- vm_offset_t paddr; /* chip's IO registers. */
- vm_offset_t paddr2; /* On-chip RAM bus address. */
- volatile /* Pointer to volatile for */
- struct ncr_reg *reg; /* memory mapped IO. */
- /*----------------------------------------------------------------
- ** SCRIPTS virtual and physical bus addresses.
- ** 'script' is loaded in the on-chip RAM if present.
- ** 'scripth' stays in main memory.
- **----------------------------------------------------------------
- */
- struct script *script0; /* Copies of script and scripth */
- struct scripth *scripth0; /* relocated for this ncb. */
- struct scripth *scripth; /* Actual scripth virt. address */
- u_long p_script; /* Actual script and scripth */
- u_long p_scripth; /* bus addresses. */
- /*----------------------------------------------------------------
- ** General controller parameters and configuration.
- **----------------------------------------------------------------
- */
- pcidev_t pdev;
- u_short device_id; /* PCI device id */
- u_char revision_id; /* PCI device revision id */
- u_char bus; /* PCI BUS number */
- u_char device_fn; /* PCI BUS device and function */
- u_long base_io; /* IO space base address */
- u_int irq; /* IRQ level */
- u_int features; /* Chip features map */
- u_char myaddr; /* SCSI id of the adapter */
- u_char maxburst; /* log base 2 of dwords burst */
- u_char maxwide; /* Maximum transfer width */
- u_char minsync; /* Minimum sync period factor */
- u_char maxsync; /* Maximum sync period factor */
- u_char maxoffs; /* Max scsi offset */
- u_char multiplier; /* Clock multiplier (1,2,4) */
- u_char clock_divn; /* Number of clock divisors */
- u_long clock_khz; /* SCSI clock frequency in KHz */
- /*----------------------------------------------------------------
- ** Start queue management.
- ** It is filled up by the host processor and accessed by the
- ** SCRIPTS processor in order to start SCSI commands.
- **----------------------------------------------------------------
- */
- u_short squeueput; /* Next free slot of the queue */
- u_short actccbs; /* Number of allocated CCBs */
- u_short queuedccbs; /* Number of CCBs in start queue*/
- u_short queuedepth; /* Start queue depth */
- /*----------------------------------------------------------------
- ** Timeout handler.
- **----------------------------------------------------------------
- */
- struct timer_list timer; /* Timer handler link header */
- u_long lasttime;
- u_long settle_time; /* Resetting the SCSI BUS */
- /*----------------------------------------------------------------
- ** Debugging and profiling.
- **----------------------------------------------------------------
- */
- struct ncr_reg regdump; /* Register dump */
- u_long regtime; /* Time it has been done */
- /*----------------------------------------------------------------
- ** Miscellaneous buffers accessed by the scripts-processor.
- ** They shall be DWORD aligned, because they may be read or
- ** written with a SCR_COPY script command.
- **----------------------------------------------------------------
- */
- u_char msgout[8]; /* Buffer for MESSAGE OUT */
- u_char msgin [8]; /* Buffer for MESSAGE IN */
- u_int32 lastmsg; /* Last SCSI message sent */
- u_char scratch; /* Scratch for SCSI receive */
- /*----------------------------------------------------------------
- ** Miscellaneous configuration and status parameters.
- **----------------------------------------------------------------
- */
- u_char disc; /* Diconnection allowed */
- u_char scsi_mode; /* Current SCSI BUS mode */
- u_char order; /* Tag order to use */
- u_char verbose; /* Verbosity for this controller*/
- int ncr_cache; /* Used for cache test at init. */
- u_long p_ncb; /* BUS address of this NCB */
- /*----------------------------------------------------------------
- ** Command completion handling.
- **----------------------------------------------------------------
- */
- #ifdef SCSI_NCR_CCB_DONE_SUPPORT
- struct ccb *(ccb_done[MAX_DONE]);
- int ccb_done_ic;
- #endif
- /*----------------------------------------------------------------
- ** Fields that should be removed or changed.
- **----------------------------------------------------------------
- */
- struct ccb *ccb; /* Global CCB */
- struct usrcmd user; /* Command from user */
- u_char release_stage; /* Synchronisation stage on release */
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- /*----------------------------------------------------------------
- ** Fields that are used for integrity check
- **----------------------------------------------------------------
- */
- unsigned char check_integrity; /* Enable midlayer integ.check on
- * bus scan. */
- unsigned char check_integ_par; /* Set if par or Init. Det. error
- * used only during integ check */
- #endif
- };
- #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))
- /*==========================================================
- **
- **
- ** Script for NCR-Processor.
- **
- ** Use ncr_script_fill() to create the variable parts.
- ** Use ncr_script_copy_and_bind() to make a copy and
- ** bind to physical addresses.
- **
- **
- **==========================================================
- **
- ** We have to know the offsets of all labels before
- ** we reach them (for forward jumps).
- ** Therefore we declare a struct here.
- ** If you make changes inside the script,
- ** DONT FORGET TO CHANGE THE LENGTHS HERE!
- **
- **----------------------------------------------------------
- */
- /*
- ** Script fragments which are loaded into the on-chip RAM
- ** of 825A, 875 and 895 chips.
- */
- struct script {
- ncrcmd start [ 5];
- ncrcmd startpos [ 1];
- ncrcmd select [ 6];
- ncrcmd select2 [ 9];
- ncrcmd loadpos [ 4];
- ncrcmd send_ident [ 9];
- ncrcmd prepare [ 6];
- ncrcmd prepare2 [ 7];
- ncrcmd command [ 6];
- ncrcmd dispatch [ 32];
- ncrcmd clrack [ 4];
- ncrcmd no_data [ 17];
- ncrcmd status [ 8];
- ncrcmd msg_in [ 2];
- ncrcmd msg_in2 [ 16];
- ncrcmd msg_bad [ 4];
- ncrcmd setmsg [ 7];
- ncrcmd cleanup [ 6];
- ncrcmd complete [ 9];
- ncrcmd cleanup_ok [ 8];
- ncrcmd cleanup0 [ 1];
- #ifndef SCSI_NCR_CCB_DONE_SUPPORT
- ncrcmd signal [ 12];
- #else
- ncrcmd signal [ 9];
- ncrcmd done_pos [ 1];
- ncrcmd done_plug [ 2];
- ncrcmd done_end [ 7];
- #endif
- ncrcmd save_dp [ 7];
- ncrcmd restore_dp [ 5];
- ncrcmd disconnect [ 17];
- ncrcmd msg_out [ 9];
- ncrcmd msg_out_done [ 7];
- ncrcmd idle [ 2];
- ncrcmd reselect [ 8];
- ncrcmd reselected [ 8];
- ncrcmd resel_dsa [ 6];
- ncrcmd loadpos1 [ 4];
- ncrcmd resel_lun [ 6];
- ncrcmd resel_tag [ 6];
- ncrcmd jump_to_nexus [ 4];
- ncrcmd nexus_indirect [ 4];
- ncrcmd resel_notag [ 4];
- ncrcmd data_in [MAX_SCATTERL * 4];
- ncrcmd data_in2 [ 4];
- ncrcmd data_out [MAX_SCATTERL * 4];
- ncrcmd data_out2 [ 4];
- };
- /*
- ** Script fragments which stay in main memory for all chips.
- */
- struct scripth {
- ncrcmd tryloop [MAX_START*2];
- ncrcmd tryloop2 [ 2];
- #ifdef SCSI_NCR_CCB_DONE_SUPPORT
- ncrcmd done_queue [MAX_DONE*5];
- ncrcmd done_queue2 [ 2];
- #endif
- ncrcmd select_no_atn [ 8];
- ncrcmd cancel [ 4];
- ncrcmd skip [ 9];
- ncrcmd skip2 [ 19];
- ncrcmd par_err_data_in [ 6];
- ncrcmd par_err_other [ 4];
- ncrcmd msg_reject [ 8];
- ncrcmd msg_ign_residue [ 24];
- ncrcmd msg_extended [ 10];
- ncrcmd msg_ext_2 [ 10];
- ncrcmd msg_wdtr [ 14];
- ncrcmd send_wdtr [ 7];
- ncrcmd msg_ext_3 [ 10];
- ncrcmd msg_sdtr [ 14];
- ncrcmd send_sdtr [ 7];
- ncrcmd nego_bad_phase [ 4];
- ncrcmd msg_out_abort [ 10];
- ncrcmd hdata_in [MAX_SCATTERH * 4];
- ncrcmd hdata_in2 [ 2];
- ncrcmd hdata_out [MAX_SCATTERH * 4];
- ncrcmd hdata_out2 [ 2];
- ncrcmd reset [ 4];
- ncrcmd aborttag [ 4];
- ncrcmd abort [ 2];
- ncrcmd abort_resel [ 20];
- ncrcmd resend_ident [ 4];
- ncrcmd clratn_go_on [ 3];
- ncrcmd nxtdsp_go_on [ 1];
- ncrcmd sdata_in [ 8];
- ncrcmd data_io [ 18];
- ncrcmd bad_identify [ 12];
- ncrcmd bad_i_t_l [ 4];
- ncrcmd bad_i_t_l_q [ 4];
- ncrcmd bad_target [ 8];
- ncrcmd bad_status [ 8];
- ncrcmd start_ram [ 4];
- ncrcmd start_ram0 [ 4];
- ncrcmd sto_restart [ 5];
- ncrcmd snooptest [ 9];
- ncrcmd snoopend [ 2];
- };
- /*==========================================================
- **
- **
- ** Function headers.
- **
- **
- **==========================================================
- */
- static void ncr_alloc_ccb (ncb_p np, u_char tn, u_char ln);
- 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);
- static void ncr_init_ccb (ncb_p np, ccb_p cp);
- static void ncr_init_tcb (ncb_p np, u_char tn);
- static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln);
- static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln,
- u_char *inq_data);
- static void ncr_getclock (ncb_p np, int mult);
- static void ncr_selectclock (ncb_p np, u_char scntl3);
- static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln);
- static void ncr_init (ncb_p np, int reset, char * msg, u_long code);
- static int ncr_int_sbmc (ncb_p np);
- static int ncr_int_par (ncb_p np);
- static void ncr_int_ma (ncb_p np);
- static void ncr_int_sir (ncb_p np);
- static void ncr_int_sto (ncb_p np);
- static u_long ncr_lookup (char* id);
- static void ncr_negotiate (struct ncb* np, struct tcb* 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
- static void ncr_script_copy_and_bind
- (ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
- static void ncr_script_fill (struct script * scr, struct scripth * scripth);
- 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_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 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);
- static void ncr_timeout (ncb_p np);
- static void ncr_wakeup (ncb_p np, u_long code);
- static void ncr_wakeup_done (ncb_p np);
- static void ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn);
- static void ncr_put_start_queue(ncb_p np, ccb_p cp);
- static void ncr_start_reset (ncb_p np);
- static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
- #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
- static void ncr_usercmd (ncb_p np);
- #endif
- static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device);
- static void insert_into_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 reset_waiting_list(np) process_waiting_list((np), DID_RESET)
- static inline char *ncr_name (ncb_p np)
- {
- return np->inst_name;
- }
- /*==========================================================
- **
- **
- ** Scripts for NCR-Processor.
- **
- ** Use ncr_script_bind for binding to physical addresses.
- **
- **
- **==========================================================
- **
- ** NADDR generates a reference to a field of the controller data.
- ** PADDR generates a reference to another part of the script.
- ** RADDR generates a reference to a script processor register.
- ** FADDR generates a reference to a script processor register
- ** with offset.
- **
- **----------------------------------------------------------
- */
- #define RELOC_SOFTC 0x40000000
- #define RELOC_LABEL 0x50000000
- #define RELOC_REGISTER 0x60000000
- #if 0
- #define RELOC_KVAR 0x70000000
- #endif
- #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)))
- #if 0
- #define KVAR(which) (RELOC_KVAR | (which))
- #endif
- #if 0
- #define SCRIPT_KVAR_JIFFIES (0)
- #define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES
- #define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES
- /*
- * Kernel variables referenced in the scripts.
- * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
- */
- static void *script_kvars[] __initdata =
- { (void *)&jiffies };
- #endif
- static struct script script0 __initdata = {
- /*--------------------------< START >-----------------------*/ {
- /*
- ** This NOP will be patched with LED ON
- ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
- */
- SCR_NO_OP,
- 0,
- /*
- ** Clear SIGP.
- */
- SCR_FROM_REG (ctest2),
- 0,
- /*
- ** Then jump to a certain point in tryloop.
- ** Due to the lack of indirect addressing the code
- ** is self modifying here.
- */
- SCR_JUMP,
- }/*-------------------------< STARTPOS >--------------------*/,{
- PADDRH(tryloop),
- }/*-------------------------< SELECT >----------------------*/,{
- /*
- ** DSA contains the address of a scheduled
- ** data structure.
- **
- ** SCRATCHA contains the address of the script,
- ** which starts the next entry.
- **
- ** Set Initiator mode.
- **
- ** (Target mode is left as an exercise for the reader)
- */
- SCR_CLR (SCR_TRG),
- 0,
- SCR_LOAD_REG (HS_REG, HS_SELECTING),
- 0,
- /*
- ** And try to select this target.
- */
- SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
- PADDR (reselect),
- }/*-------------------------< SELECT2 >----------------------*/,{
- /*
- ** Now there are 4 possibilities:
- **
- ** (1) The ncr looses arbitration.
- ** This is ok, because it will try again,
- ** when the bus becomes idle.
- ** (But beware of the timeout function!)
- **
- ** (2) The ncr is reselected.
- ** Then the script processor takes the jump
- ** to the RESELECT label.
- **
- ** (3) The ncr wins arbitration.
- ** Then it will execute SCRIPTS instruction until
- ** the next instruction that checks SCSI phase.
- ** Then will stop and wait for selection to be
- ** complete or selection time-out to occur.
- ** As a result the SCRIPTS instructions until
- ** LOADPOS + 2 should be executed in parallel with
- ** the SCSI core performing selection.
- */
- /*
- ** The M_REJECT problem seems to be due to a selection
- ** timing problem.
- ** Wait immediately for the selection to complete.
- ** (2.5x behaves so)
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- 0,
- /*
- ** Next time use the next slot.
- */
- SCR_COPY (4),
- RADDR (temp),
- PADDR (startpos),
- /*
- ** The ncr doesn't have an indirect load
- ** or store command. So we have to
- ** copy part of the control block to a
- ** fixed place, where we can access it.
- **
- ** We patch the address part of a
- ** COPY command with the DSA-register.
- */
- SCR_COPY_F (4),
- RADDR (dsa),
- PADDR (loadpos),
- /*
- ** then we do the actual copy.
- */
- SCR_COPY (sizeof (struct head)),
- /*
- ** continued after the next label ...
- */
- }/*-------------------------< LOADPOS >---------------------*/,{
- 0,
- NADDR (header),
- /*
- ** Wait for the next phase or the selection
- ** to complete or time-out.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDR (prepare),
- }/*-------------------------< SEND_IDENT >----------------------*/,{
- /*
- ** Selection complete.
- ** Send the IDENTIFY and SIMPLE_TAG messages
- ** (and the M_X_SYNC_REQ message)
- */
- SCR_MOVE_TBL ^ SCR_MSG_OUT,
- offsetof (struct dsb, smsg),
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
- PADDRH (resend_ident),
- SCR_LOAD_REG (scratcha, 0x80),
- 0,
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (lastmsg),
- }/*-------------------------< PREPARE >----------------------*/,{
- /*
- ** load the savep (saved pointer) into
- ** the TEMP register (actual pointer)
- */
- SCR_COPY (4),
- NADDR (header.savep),
- RADDR (temp),
- /*
- ** Initialize the status registers
- */
- SCR_COPY (4),
- NADDR (header.status),
- RADDR (scr0),
- }/*-------------------------< PREPARE2 >---------------------*/,{
- /*
- ** Initialize the msgout buffer with a NOOP message.
- */
- SCR_LOAD_REG (scratcha, M_NOOP),
- 0,
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (msgout),
- #if 0
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (msgin),
- #endif
- /*
- ** Anticipate the COMMAND phase.
- ** This is the normal case for initial selection.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
- PADDR (dispatch),
- }/*-------------------------< COMMAND >--------------------*/,{
- /*
- ** ... and send the command
- */
- SCR_MOVE_TBL ^ SCR_COMMAND,
- offsetof (struct dsb, cmd),
- /*
- ** If status is still HS_NEGOTIATE, negotiation failed.
- ** We check this here, since we want to do that
- ** only once.
- */
- SCR_FROM_REG (HS_REG),
- 0,
- SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
- SIR_NEGO_FAILED,
- }/*-----------------------< DISPATCH >----------------------*/,{
- /*
- ** MSG_IN is the only phase that shall be
- ** entered at least once for each (re)selection.
- ** So we test it first.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR (msg_in),
- SCR_RETURN ^ IFTRUE (IF (SCR_DATA_OUT)),
- 0,
- /*
- ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4.
- ** Possible data corruption during Memory Write and Invalidate.
- ** This work-around resets the addressing logic prior to the
- ** start of the first MOVE of a DATA IN phase.
- ** (See README.ncr53c8xx for more information)
- */
- SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
- 20,
- SCR_COPY (4),
- RADDR (scratcha),
- RADDR (scratcha),
- SCR_RETURN,
- 0,
- SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
- PADDR (status),
- SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
- PADDR (command),
- SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
- PADDR (msg_out),
- /*
- ** Discard one illegal phase byte, if required.
- */
- SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
- 0,
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (xerr_st),
- SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
- 8,
- SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
- NADDR (scratch),
- SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
- 8,
- SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
- NADDR (scratch),
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< CLRACK >----------------------*/,{
- /*
- ** Terminate possible pending message phase.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< NO_DATA >--------------------*/,{
- /*
- ** The target wants to tranfer too much data
- ** or in the wrong direction.
- ** Remember that in extended error.
- */
- SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
- 0,
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (xerr_st),
- /*
- ** 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),
- /*
- ** .. and repeat as required.
- */
- SCR_CALL,
- PADDR (dispatch),
- SCR_JUMP,
- PADDR (no_data),
- }/*-------------------------< STATUS >--------------------*/,{
- /*
- ** get the status
- */
- SCR_MOVE_ABS (1) ^ SCR_STATUS,
- NADDR (scratch),
- /*
- ** save status to scsi_status.
- ** mark as complete.
- */
- SCR_TO_REG (SS_REG),
- 0,
- SCR_LOAD_REG (HS_REG, HS_COMPLETE),
- 0,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< MSG_IN >--------------------*/,{
- /*
- ** Get the first byte of the message
- ** and save it to SCRATCHA.
- **
- ** The script processor doesn't negate the
- ** ACK signal after this transfer.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[0]),
- }/*-------------------------< MSG_IN2 >--------------------*/,{
- /*
- ** Handle this message.
- */
- SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
- PADDR (complete),
- SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
- PADDR (disconnect),
- SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
- PADDR (save_dp),
- SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
- PADDR (restore_dp),
- SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
- PADDRH (msg_extended),
- SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
- PADDR (clrack),
- SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
- PADDRH (msg_reject),
- SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
- PADDRH (msg_ign_residue),
- /*
- ** Rest of the messages left as
- ** an exercise ...
- **
- ** Unimplemented messages:
- ** fall through to MSG_BAD.
- */
- }/*-------------------------< MSG_BAD >------------------*/,{
- /*
- ** unimplemented message - reject it.
- */
- SCR_INT,
- SIR_REJECT_SENT,
- SCR_LOAD_REG (scratcha, M_REJECT),
- 0,
- }/*-------------------------< SETMSG >----------------------*/,{
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (msgout),
- SCR_SET (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< 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 (start),
- /*
- ** dsa is valid.
- ** complete the cleanup.
- */
- SCR_JUMP,
- PADDR (cleanup_ok),
- }/*-------------------------< COMPLETE >-----------------*/,{
- /*
- ** Complete message.
- **
- ** Copy TEMP register to LASTP in header.
- */
- 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_OK >----------------*/,{
- /*
- ** Save host status to header.
- */
- SCR_COPY (4),
- RADDR (scr0),
- NADDR (header.status),
- /*
- ** and copy back the header to the ccb.
- */
- SCR_COPY_F (4),
- RADDR (dsa),
- PADDR (cleanup0),
- SCR_COPY (sizeof (struct head)),
- NADDR (header),
- }/*-------------------------< CLEANUP0 >--------------------*/,{
- 0,
- }/*-------------------------< SIGNAL >----------------------*/,{
- /*
- ** if job not completed ...
- */
- SCR_FROM_REG (HS_REG),
- 0,
- /*
- ** ... start the next command.
- */
- SCR_JUMP ^ IFTRUE (MASK (0, (HS_DONEMASK|HS_SKIPMASK))),
- PADDR(start),
- /*
- ** If command resulted in not GOOD status,
- ** call the C code if needed.
- */
- SCR_FROM_REG (SS_REG),
- 0,
- SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
- PADDRH (bad_status),
- #ifndef SCSI_NCR_CCB_DONE_SUPPORT
- /*
- ** ... signal completion to the host
- */
- SCR_INT_FLY,
- 0,
- /*
- ** Auf zu neuen Schandtaten!
- */
- SCR_JUMP,
- PADDR(start),
- #else /* defined SCSI_NCR_CCB_DONE_SUPPORT */
- /*
- ** ... signal completion to the host
- */
- SCR_JUMP,
- }/*------------------------< DONE_POS >---------------------*/,{
- PADDRH (done_queue),
- }/*------------------------< DONE_PLUG >--------------------*/,{
- SCR_INT,
- SIR_DONE_OVERFLOW,
- }/*------------------------< DONE_END >---------------------*/,{
- SCR_INT_FLY,
- 0,
- SCR_COPY (4),
- RADDR (temp),
- PADDR (done_pos),
- SCR_JUMP,
- PADDR (start),
- #endif /* SCSI_NCR_CCB_DONE_SUPPORT */
- }/*-------------------------< SAVE_DP >------------------*/,{
- /*
- ** SAVE_DP message:
- ** Copy TEMP register to SAVEP in header.
- */
- SCR_COPY (4),
- RADDR (temp),
- NADDR (header.savep),
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< RESTORE_DP >---------------*/,{
- /*
- ** RESTORE_DP message:
- ** Copy SAVEP in header to TEMP register.
- */
- SCR_COPY (4),
- NADDR (header.savep),
- RADDR (temp),
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< DISCONNECT >---------------*/,{
- /*
- ** 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,
- /*
- ** Status is: DISCONNECTED.
- */
- SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
- 0,
- /*
- ** If QUIRK_AUTOSAVE is set,
- ** do an "save pointer" operation.
- */
- SCR_FROM_REG (QU_REG),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
- PADDR (cleanup_ok),
- /*
- ** like SAVE_DP message:
- ** Copy TEMP register to SAVEP in header.
- */
- SCR_COPY (4),
- RADDR (temp),
- NADDR (header.savep),
- SCR_JUMP,
- PADDR (cleanup_ok),
- }/*-------------------------< MSG_OUT >-------------------*/,{
- /*
- ** The target requests a message.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_COPY (1),
- NADDR (msgout),
- 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),
- }/*-------------------------< IDLE >------------------------*/,{
- /*
- ** Nothing to do?
- ** Wait for reselect.
- ** This NOP will be patched with LED OFF
- ** SCR_REG_REG (gpreg, SCR_OR, 0x01)
- */
- SCR_NO_OP,
- 0,
- }/*-------------------------< RESELECT >--------------------*/,{
- /*
- ** make the DSA invalid.
- */
- SCR_LOAD_REG (dsa, 0xff),
- 0,
- SCR_CLR (SCR_TRG),
- 0,
- SCR_LOAD_REG (HS_REG, HS_IN_RESELECT),
- 0,
- /*
- ** Sleep waiting for a reselection.
- ** If SIGP is set, special treatment.
- **
- ** Zu allem bereit ..
- */
- SCR_WAIT_RESEL,
- PADDR(start),
- }/*-------------------------< RESELECTED >------------------*/,{
- /*
- ** This NOP will be patched with LED ON
- ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
- */
- SCR_NO_OP,
- 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 (sdid),
- 0,
- SCR_JUMP,
- NADDR (jump_tcb),
- }/*-------------------------< RESEL_DSA >-------------------*/,{
- /*
- ** Ack the IDENTIFY or TAG previously received.
- */
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** The ncr doesn't have an indirect load
- ** or store command. So we have to
- ** copy part of the control block to a
- ** fixed place, where we can access it.
- **
- ** We patch the address part of a
- ** COPY command with the DSA-register.
- */
- SCR_COPY_F (4),
- RADDR (dsa),
- PADDR (loadpos1),
- /*
- ** then we do the actual copy.
- */
- SCR_COPY (sizeof (struct head)),
- /*
- ** continued after the next label ...
- */
- }/*-------------------------< LOADPOS1 >-------------------*/,{
- 0,
- NADDR (header),
- /*
- ** The DSA contains the data structure address.
- */
- SCR_JUMP,
- PADDR (prepare),
- }/*-------------------------< RESEL_LUN >-------------------*/,{
- /*
- ** come back to this point
- ** to get an IDENTIFY message
- ** Wait for a msg_in phase.
- */
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
- SIR_RESEL_NO_MSG_IN,
- /*
- ** message phase.
- ** Read the data directly from the BUS DATA lines.
- ** This helps to support very old SCSI devices that
- ** may reselect without sending an IDENTIFY.
- */
- SCR_FROM_REG (sbdl),
- 0,
- /*
- ** It should be an Identify message.
- */
- SCR_RETURN,
- 0,
- }/*-------------------------< RESEL_TAG >-------------------*/,{
- /*
- ** 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,
- NADDR (msgin),
- /*
- ** Read the TAG from the SIDL.
- ** Still an aggressive optimization. ;-)
- ** Compute the CCB indirect jump address which
- ** is (#TAG*2 & 0xfc) due to tag numbering using
- ** 1,3,5..MAXTAGS*2+1 actual values.
- */
- SCR_REG_SFBR (sidl, SCR_SHL, 0),
- 0,
- SCR_SFBR_REG (temp, SCR_AND, 0xfc),
- 0,
- }/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{
- SCR_COPY_F (4),
- RADDR (temp),
- PADDR (nexus_indirect),
- SCR_COPY (4),
- }/*-------------------------< NEXUS_INDIRECT >-------------------*/,{
- 0,
- RADDR (temp),
- SCR_RETURN,
- 0,
- }/*-------------------------< RESEL_NOTAG >-------------------*/,{
- /*
- ** No tag expected.
- ** Read an throw away the IDENTIFY.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- SCR_JUMP,
- PADDR (jump_to_nexus),
- }/*-------------------------< DATA_IN >--------------------*/,{
- /*
- ** Because the size depends on the
- ** #define MAX_SCATTERL parameter,
- ** it is filled in at runtime.
- **
- ** ##===========< i=0; i<MAX_SCATTERL >=========
- ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
- ** || PADDR (dispatch),
- ** || SCR_MOVE_TBL ^ SCR_DATA_IN,
- ** || offsetof (struct dsb, data[ i]),
- ** ##==========================================
- **
- **---------------------------------------------------------
- */
- 0
- }/*-------------------------< DATA_IN2 >-------------------*/,{
- SCR_CALL,
- PADDR (dispatch),
- SCR_JUMP,
- PADDR (no_data),
- }/*-------------------------< DATA_OUT >--------------------*/,{
- /*
- ** Because the size depends on the
- ** #define MAX_SCATTERL parameter,
- ** it is filled in at runtime.
- **
- ** ##===========< i=0; i<MAX_SCATTERL >=========
- ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
- ** || PADDR (dispatch),
- ** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
- ** || offsetof (struct dsb, data[ i]),
- ** ##==========================================
- **
- **---------------------------------------------------------
- */
- 0
- }/*-------------------------< DATA_OUT2 >-------------------*/,{
- SCR_CALL,
- PADDR (dispatch),
- SCR_JUMP,
- PADDR (no_data),
- }/*--------------------------------------------------------*/
- };
- static struct scripth scripth0 __initdata = {
- /*-------------------------< TRYLOOP >---------------------*/{
- /*
- ** Start the next entry.
- ** Called addresses point to the launch script in the CCB.
- ** They are patched by the main processor.
- **
- ** Because the size depends on the
- ** #define MAX_START parameter, it is filled
- ** in at runtime.
- **
- **-----------------------------------------------------------
- **
- ** ##===========< I=0; i<MAX_START >===========
- ** || SCR_CALL,
- ** || PADDR (idle),
- ** ##==========================================
- **
- **-----------------------------------------------------------
- */
- 0
- }/*------------------------< TRYLOOP2 >---------------------*/,{
- SCR_JUMP,
- PADDRH(tryloop),
- #ifdef SCSI_NCR_CCB_DONE_SUPPORT
- }/*------------------------< DONE_QUEUE >-------------------*/,{
- /*
- ** Copy the CCB address to the next done entry.
- ** Because the size depends on the
- ** #define MAX_DONE parameter, it is filled
- ** in at runtime.
- **
- **-----------------------------------------------------------
- **
- ** ##===========< I=0; i<MAX_DONE >===========
- ** || SCR_COPY (sizeof(ccb_p)),
- ** || NADDR (header.cp),
- ** || NADDR (ccb_done[i]),
- ** || SCR_CALL,
- ** || PADDR (done_end),
- ** ##==========================================
- **
- **-----------------------------------------------------------
- */
- 0
- }/*------------------------< DONE_QUEUE2 >------------------*/,{
- SCR_JUMP,
- PADDRH (done_queue),
- #endif /* SCSI_NCR_CCB_DONE_SUPPORT */
- }/*------------------------< SELECT_NO_ATN >-----------------*/,{
- /*
- ** Set Initiator mode.
- ** And try to select this target without ATN.
- */
- SCR_CLR (SCR_TRG),
- 0,
- SCR_LOAD_REG (HS_REG, HS_SELECTING),
- 0,
- SCR_SEL_TBL ^ offsetof (struct dsb, select),
- PADDR (reselect),
- SCR_JUMP,
- PADDR (select2),
- }/*-------------------------< CANCEL >------------------------*/,{
- SCR_LOAD_REG (scratcha, HS_ABORTED),
- 0,
- SCR_JUMPR,
- 8,
- }/*-------------------------< SKIP >------------------------*/,{
- SCR_LOAD_REG (scratcha, 0),
- 0,
- /*
- ** This entry has been canceled.
- ** Next time use the next slot.
- */
- SCR_COPY (4),
- RADDR (temp),
- PADDR (startpos),
- /*
- ** The ncr doesn't have an indirect load
- ** or store command. So we have to
- ** copy part of the control block to a
- ** fixed place, where we can access it.
- **
- ** We patch the address part of a
- ** COPY command with the DSA-register.
- */
- SCR_COPY_F (4),
- RADDR (dsa),
- PADDRH (skip2),
- /*
- ** then we do the actual copy.
- */
- SCR_COPY (sizeof (struct head)),
- /*
- ** continued after the next label ...
- */
- }/*-------------------------< SKIP2 >---------------------*/,{
- 0,
- NADDR (header),
- /*
- ** Initialize the status registers
- */
- SCR_COPY (4),
- NADDR (header.status),
- RADDR (scr0),
- /*
- ** Force host status.
- */
- SCR_FROM_REG (scratcha),
- 0,
- SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
- 16,
- SCR_REG_REG (HS_REG, SCR_OR, HS_SKIPMASK),
- 0,
- SCR_JUMPR,
- 8,
- SCR_TO_REG (HS_REG),
- 0,
- SCR_LOAD_REG (SS_REG, S_GOOD),
- 0,
- SCR_JUMP,
- PADDR (cleanup_ok),
- },/*-------------------------< PAR_ERR_DATA_IN >---------------*/{
- /*
- ** Ignore all data in byte, until next phase
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
- PADDRH (par_err_other),
- SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
- NADDR (scratch),
- SCR_JUMPR,
- -24,
- },/*-------------------------< PAR_ERR_OTHER >------------------*/{
- /*
- ** count it.
- */
- SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
- 0,
- /*
- ** jump to dispatcher.
- */
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< MSG_REJECT >---------------*/,{
- /*
- ** If a negotiation was in progress,
- ** negotiation failed.
- ** Otherwise, let the C code print
- ** some message.
- */
- SCR_FROM_REG (HS_REG),
- 0,
- SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
- SIR_REJECT_RECEIVED,
- SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
- SIR_NEGO_FAILED,
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
- /*
- ** Terminate cycle
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get residue size.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
- /*
- ** Size is 0 .. ignore message.
- */
- SCR_JUMP ^ IFTRUE (DATA (0)),
- PADDR (clrack),
- /*
- ** Size is not 1 .. have to interrupt.
- */
- SCR_JUMPR ^ IFFALSE (DATA (1)),
- 40,
- /*
- ** Check for residue byte in swide register
- */
- SCR_FROM_REG (scntl2),
- 0,
- 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_JUMP,
- PADDR (clrack),
- /*
- ** Load again the size to the sfbr register.
- */
- SCR_FROM_REG (scratcha),
- 0,
- SCR_INT,
- SIR_IGN_RESIDUE,
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< 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]),
- /*
- */
- 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)),
- PADDR (dispatch),
- /*
- ** get extended message code.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[2]),
- SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
- PADDRH (msg_wdtr),
- /*
- ** unknown extended message
- */
- SCR_JUMP,
- PADDR (msg_bad)
- }/*-------------------------< MSG_WDTR >-----------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get data bus width
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[3]),
- /*
- ** let the host do the real work.
- */
- SCR_INT,
- SIR_NEGO_WIDE,
- /*
- ** let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDRH (nego_bad_phase),
- }/*-------------------------< SEND_WDTR >----------------*/,{
- /*
- ** Send the M_X_WIDE_REQ
- */
- SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_COPY (1),
- NADDR (msgout),
- NADDR (lastmsg),
- SCR_JUMP,
- PADDR (msg_out_done),
- }/*-------------------------< MSG_EXT_3 >----------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get extended message code.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[2]),
- SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
- PADDRH (msg_sdtr),
- /*
- ** unknown extended message
- */
- SCR_JUMP,
- PADDR (msg_bad)
- }/*-------------------------< MSG_SDTR >-----------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get period and offset
- */
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
- NADDR (msgin[3]),
- /*
- ** let the host do the real work.
- */
- SCR_INT,
- SIR_NEGO_SYNC,
- /*
- ** let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDRH (nego_bad_phase),
- }/*-------------------------< SEND_SDTR >-------------*/,{
- /*
- ** Send the M_X_SYNC_REQ
- */
- SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_COPY (1),
- NADDR (msgout),
- NADDR (lastmsg),
- SCR_JUMP,
- PADDR (msg_out_done),
- }/*-------------------------< NEGO_BAD_PHASE >------------*/,{
- SCR_INT,
- SIR_NEGO_PROTO,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< MSG_OUT_ABORT >-------------*/,{
- /*
- ** After ABORT message,
- **
- ** expect an immediate disconnect, ...
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- SCR_WAIT_DISC,
- 0,
- /*
- ** ... and set the status to "ABORTED"
- */
- SCR_LOAD_REG (HS_REG, HS_ABORTED),
- 0,
- SCR_JUMP,
- PADDR (cleanup),
- }/*-------------------------< HDATA_IN >-------------------*/,{
- /*
- ** Because the size depends on the
- ** #define MAX_SCATTERH parameter,
- ** it is filled in at runtime.
- **
- ** ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
- ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
- ** || PADDR (dispatch),
- ** || SCR_MOVE_TBL ^ SCR_DATA_IN,
- ** || offsetof (struct dsb, data[ i]),
- ** ##===================================================
- **
- **---------------------------------------------------------
- */
- 0
- }/*-------------------------< HDATA_IN2 >------------------*/,{
- SCR_JUMP,
- PADDR (data_in),
- }/*-------------------------< HDATA_OUT >-------------------*/,{
- /*
- ** Because the size depends on the
- ** #define MAX_SCATTERH parameter,
- ** it is filled in at runtime.
- **
- ** ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
- ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
- ** || PADDR (dispatch),
- ** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
- ** || offsetof (struct dsb, data[ i]),
- ** ##===================================================
- **
- **---------------------------------------------------------
- */
- 0
- }/*-------------------------< HDATA_OUT2 >------------------*/,{
- SCR_JUMP,
- PADDR (data_out),
- }/*-------------------------< RESET >----------------------*/,{
- /*
- ** Send a M_RESET message if bad IDENTIFY
- ** received on reselection.
- */
- SCR_LOAD_REG (scratcha, M_ABORT_TAG),
- 0,
- SCR_JUMP,
- PADDRH (abort_resel),
- }/*-------------------------< ABORTTAG >-------------------*/,{
- /*
- ** Abort a wrong tag received on reselection.
- */
- SCR_LOAD_REG (scratcha, M_ABORT_TAG),
- 0,
- SCR_JUMP,
- PADDRH (abort_resel),
- }/*-------------------------< ABORT >----------------------*/,{
- /*
- ** Abort a reselection when no active CCB.
- */
- SCR_LOAD_REG (scratcha, M_ABORT),
- 0,
- }/*-------------------------< ABORT_RESEL >----------------*/,{
- SCR_COPY (1),
- RADDR (scratcha),
- NADDR (msgout),
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** and send it.
- ** we expect an immediate disconnect
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_COPY (1),
- NADDR (msgout),
- NADDR (lastmsg),
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- SCR_WAIT_DISC,
- 0,
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< RESEND_IDENT >-------------------*/,{
- /*
- ** The target stays in MSG OUT phase after having acked
- ** Identify [+ Tag [+ Extended message ]]. Targets shall
- ** behave this way on parity error.
- ** We must send it again all the messages.
- */
- SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */
- 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */
- SCR_JUMP,
- PADDR (send_ident),
- }/*-------------------------< CLRATN_GO_ON >-------------------*/,{
- SCR_CLR (SCR_ATN),
- 0,
- SCR_JUMP,
- }/*-------------------------< NXTDSP_GO_ON >-------------------*/,{
- 0,
- }/*-------------------------< SDATA_IN >-------------------*/,{
- SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
- PADDR (dispatch),
- SCR_MOVE_TBL ^ SCR_DATA_IN,
- offsetof (struct dsb, sense),
- SCR_CALL,
- PADDR (dispatch),
- SCR_JUMP,
- PADDR (no_data),
- }/*-------------------------< DATA_IO >--------------------*/,{
- /*
- ** We jump here if the data direction was unknown at the
- ** time we had to queue the command to the scripts processor.
- ** Pointers had been set as follow in this situation:
- ** savep --> DATA_IO
- ** lastp --> start pointer when DATA_IN
- ** goalp --> goal pointer when DATA_IN
- ** wlastp --> start pointer when DATA_OUT
- ** wgoalp --> goal pointer when DATA_OUT
- ** This script sets savep/lastp/goalp according to the
- ** direction chosen by the target.
- */
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_OUT)),
- 32,
- /*
- ** Direction is DATA IN.
- ** Warning: we jump here, even when phase is DATA OUT.
- */
- SCR_COPY (4),
- NADDR (header.lastp),
- NADDR (header.savep),
- /*
- ** Jump to the SCRIPTS according to actual direction.
- */
- SCR_COPY (4),
- NADDR (header.savep),
- RADDR (temp),
- SCR_RETURN,
- 0,
- /*
- ** Direction is DATA OUT.
- */
- SCR_COPY (4),
- NADDR (header.wlastp),
- NADDR (header.lastp),
- SCR_COPY (4),
- NADDR (header.wgoalp),
- NADDR (header.goalp),
- SCR_JUMPR,
- -64,
- }/*-------------------------< 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 (reset),
- /*
- ** 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),
- }/*-------------------------< BAD_I_T_L >------------------*/,{
- /*
- ** We donnot have a task for that I_T_L.
- ** Signal problem to C code for logging the event.
- ** Send a M_ABORT message.
- */
- SCR_INT,
- SIR_RESEL_BAD_I_T_L,
- SCR_JUMP,
- PADDRH (abort),
- }/*-------------------------< BAD_I_T_L_Q >----------------*/,{
- /*
- ** We donnot have a task that matches the tag.
- ** Signal problem to C code for logging the event.
- ** Send a M_ABORTTAG message.
- */
- SCR_INT,
- SIR_RESEL_BAD_I_T_L_Q,
- SCR_JUMP,
- PADDRH (aborttag),
- }/*-------------------------< BAD_TARGET >-----------------*/,{
- /*
- ** We donnot know the target that reselected us.
- ** Grab the first message if any (IDENTIFY).
- ** Signal problem to C code for logging the event.
- ** M_RESET message.
- */
- SCR_INT,
- SIR_RESEL_BAD_TARGET,
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
- 8,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- SCR_JUMP,
- PADDRH (reset),
- }/*-------------------------< BAD_STATUS >-----------------*/,{
- /*
- ** If command resulted in either QUEUE FULL,
- ** CHECK CONDITION or COMMAND TERMINATED,
- ** call the C code.
- */
- SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
- SIR_BAD_STATUS,
- SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
- SIR_BAD_STATUS,
- SCR_INT ^ IFTRUE (DATA (S_TERMINATED)),
- SIR_BAD_STATUS,
- SCR_RETURN,
- 0,
- }/*-------------------------< START_RAM >-------------------*/,{
- /*
- ** Load the script into on-chip RAM,
- ** and jump to start point.
- */
- SCR_COPY_F (4),
- RADDR (scratcha),
- PADDRH (start_ram0),
- SCR_COPY (sizeof (struct script)),
- }/*-------------------------< START_RAM0 >--------------------*/,{
- 0,
- PADDR (start),
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< STO_RESTART >-------------------*/,{
- /*
- **
- ** Repair start queue (e.g. next time use the next slot)
- ** and jump to start point.
- */
- SCR_COPY (4),
- RADDR (temp),
- PADDR (startpos),
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< SNOOPTEST >-------------------*/,{
- /*
- ** Read the variable.
- */
- SCR_COPY (4),
- NADDR(ncr_cache),
- RADDR (scratcha),
- /*
- ** Write the variable.
- */
- SCR_COPY (4),
- RADDR (temp),
- NADDR(ncr_cache),
- /*
- ** Read back the variable.
- */
- SCR_COPY (4),
- NADDR(ncr_cache),
- RADDR (temp),
- }/*-------------------------< SNOOPEND >-------------------*/,{
- /*
- ** And stop.
- */
- SCR_INT,
- 99,
- }/*--------------------------------------------------------*/
- };
- /*==========================================================
- **
- **
- ** Fill in #define dependent parts of the script
- **
- **
- **==========================================================
- */
- void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
- {
- int i;
- ncrcmd *p;
- p = scrh->tryloop;
- for (i=0; i<MAX_START; i++) {
- *p++ =SCR_CALL;
- *p++ =PADDR (idle);
- };
- assert ((u_long)p == (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
- #ifdef SCSI_NCR_CCB_DONE_SUPPORT
- p = scrh->done_queue;
- for (i = 0; i<MAX_DONE; i++) {
- *p++ =SCR_COPY (sizeof(ccb_p));
- *p++ =NADDR (header.cp);
- *p++ =NADDR (ccb_done[i]);
- *p++ =SCR_CALL;
- *p++ =PADDR (done_end);
- }
- assert ((u_long)p ==(u_long)&scrh->done_queue+sizeof(scrh->done_queue));
- #endif /* SCSI_NCR_CCB_DONE_SUPPORT */
- p = scrh->hdata_in;
- for (i=0; i<MAX_SCATTERH; i++) {
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
- *p++ =PADDR (dispatch);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
- p = scr->data_in;
- for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
- *p++ =PADDR (dispatch);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
- p = scrh->hdata_out;
- for (i=0; i<MAX_SCATTERH; i++) {
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
- *p++ =PADDR (dispatch);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p==(u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
- p = scr->data_out;
- for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
- *p++ =PADDR (dispatch);
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
- }
- /*==========================================================
- **
- **
- ** Copy and rebind a script.
- **
- **
- **==========================================================
- */
- static void __init
- ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
- {
- ncrcmd opcode, new, old, tmp1, tmp2;
- ncrcmd *start, *end;
- int relocs;
- int opchanged = 0;
- start = src;
- end = src + len/4;
- while (src < end) {
- opcode = *src++;
- *dst++ = cpu_to_scr(opcode);
- /*
- ** If we forget to change the length
- ** in struct script, a field will be
- ** padded with 0. This is an illegal
- ** command.
- */
- if (opcode == 0) {
- printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.n",
- ncr_name(np), (int) (src-start-1));
- MDELAY (1000);
- };
- if (DEBUG_FLAGS & DEBUG_SCRIPT)
- printk (KERN_DEBUG "%p: <%x>n",
- (src-1), (unsigned)opcode);
- /*
- ** We don't have to decode ALL commands
- */
- switch (opcode >> 28) {
- case 0xc:
- /*
- ** COPY has TWO arguments.
- */
- relocs = 2;
- tmp1 = src[0];
- #ifdef RELOC_KVAR
- if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
- tmp1 = 0;
- #endif
- tmp2 = src[1];
- #ifdef RELOC_KVAR
- if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
- tmp2 = 0;
- #endif
- if ((tmp1 ^ tmp2) & 3) {
- printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.n",
- ncr_name(np), (int) (src-start-1));
- MDELAY (1000);
- }
- /*
- ** If PREFETCH feature not enabled, remove
- ** the NO FLUSH bit if present.
- */
- if ((opcode & SCR_NO_FLUSH) && !(np->features & FE_PFEN)) {
- dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
- ++opchanged;
- }
- break;
- case 0x0:
- /*
- ** MOVE (absolute address)
- */
- relocs = 1;
- break;
- case 0x8:
- /*
- ** JUMP / CALL
- ** dont't relocate if relative :-)
- */
- if (opcode & 0x00800000)
- relocs = 0;
- else
- relocs = 1;
- break;
- case 0x4:
- case 0x5:
- case 0x6:
- case 0x7:
- relocs = 1;
- break;
- default:
- relocs = 0;
- break;
- };
- if (relocs) {
- while (relocs--) {
- old = *src++;
- switch (old & RELOC_MASK) {
- case RELOC_REGISTER:
- new = (old & ~RELOC_MASK) + np->paddr;
- break;
- 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) + np->p_ncb;
- break;
- #ifdef RELOC_KVAR
- case RELOC_KVAR:
- if (((old & ~RELOC_MASK) <
- SCRIPT_KVAR_FIRST) ||
- ((old & ~RELOC_MASK) >
- SCRIPT_KVAR_LAST))
- panic("ncr KVAR out of range");
- new = vtophys(script_kvars[old &
- ~RELOC_MASK]);
- break;
- #endif
- case 0:
- /* Don't relocate a 0 address. */
- if (old == 0) {
- new = old;
- break;
- }
- /* fall through */
- default:
- panic("ncr_script_copy_and_bind: weird relocation %xn", old);
- break;
- }
- *dst++ = cpu_to_scr(new);
- }
- } else
- *dst++ = cpu_to_scr(*src++);
- };
- }
- /*==========================================================
- **
- **
- ** Auto configuration: attach and init a host adapter.
- **
- **
- **==========================================================
- */
- /*
- ** Linux host data structure
- **
- ** The script area is allocated in the host data structure
- ** because kmalloc() returns NULL during scsi initialisations
- ** with Linux 1.2.X
- */
- struct host_data {
- struct ncb *ncb;
- };
- /*
- ** Print something which allows to retrieve the controller type, unit,
- ** target, lun concerned by a kernel message.
- */
- static void PRINT_TARGET(ncb_p np, int target)
- {
- printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target);
- }
- static void PRINT_LUN(ncb_p np, int target, int lun)
- {
- printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun);
- }
- static void PRINT_ADDR(Scsi_Cmnd *cmd)
- {
- struct host_data *host_data = (struct host_data *) cmd->host->hostdata;
- PRINT_LUN(host_data->ncb, cmd->target, cmd->lun);
- }
- /*==========================================================
- **
- ** NCR chip clock divisor table.
- ** Divisors are multiplied by 10,000,000 in order to make
- ** calculations more simple.
- **
- **==========================================================
- */
- #define _5M 5000000
- static u_long div_10M[] =
- {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
- /*===============================================================
- **
- ** Prepare io register values used by ncr_init() according
- ** to selected and supported features.
- **
- ** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
- ** 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".
- **
- **===============================================================
- */
- /*
- * Burst length from burst code.
- */
- #define burst_length(bc) (!(bc))? 0 : 1 << (bc)
- /*
- * Burst code from io register bits.
- */
- #define burst_code(dmode, ctest4, ctest5)
- (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
- /*
- * Set initial io register bits from burst code.
- */
- static inline void ncr_init_burst(ncb_p np, u_char bc)
- {
- np->rv_ctest4 &= ~0x80;
- np->rv_dmode &= ~(0x3 << 6);
- np->rv_ctest5 &= ~0x4;
- if (!bc) {
- np->rv_ctest4 |= 0x80;
- }
- else {
- --bc;
- np->rv_dmode |= ((bc & 0x3) << 6);
- np->rv_ctest5 |= (bc & 0x4);
- }
- }
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- /*
- ** Get target set-up from Symbios format NVRAM.
- */
- static void __init
- ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
- {
- tcb_p tp = &np->target[target];
- Symbios_target *tn = &nvram->target[target];
- tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
- tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
- tp->usrtags =
- (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
- if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
- tp->usrflag |= UF_NODISC;
- if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
- tp->usrflag |= UF_NOSCAN;
- }
- /*
- ** Get target set-up from Tekram format NVRAM.
- */
- static void __init
- ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
- {
- tcb_p tp = &np->target[target];
- struct Tekram_target *tn = &nvram->target[target];
- int i;
- if (tn->flags & TEKRAM_SYNC_NEGO) {
- i = tn->sync_index & 0xf;
- tp->usrsync = Tekram_sync[i];
- }
- tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
- if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
- tp->usrtags = 2 << nvram->max_tags_index;
- }
- if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE))
- tp->usrflag = UF_NODISC;
-
- /* If any device does not support parity, we will not use this option */
- if (!(tn->flags & TEKRAM_PARITY_CHECK))
- np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */
- }
- #endif /* SCSI_NCR_NVRAM_SUPPORT */
- static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
- {
- u_char burst_max;
- u_long period;
- int i;
- /*
- ** Save assumed BIOS setting
- */
- 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);
- /*
- ** Wide ?
- */
- np->maxwide = (np->features & FE_WIDE)? 1 : 0;
- /*
- * Guess the frequency of the chip's clock.
- */
- if (np->features & (FE_ULTRA3 | FE_ULTRA2))
- np->clock_khz = 160000;
- else if (np->features & FE_ULTRA)
- np->clock_khz = 80000;
- else
- np->clock_khz = 40000;
- /*
- * Get the clock multiplier factor.
- */
- if (np->features & FE_QUAD)
- np->multiplier = 4;
- else if (np->features & FE_DBLR)
- np->multiplier = 2;
- else
- np->multiplier = 1;
- /*
- * Measure SCSI clock frequency for chips
- * it may vary from assumed one.
- */
- if (np->features & FE_VARCLK)
- ncr_getclock(np, np->multiplier);
- /*
- * Divisor to be used for async (timer pre-scaler).
- */
- 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;
- /*
- * Minimum synchronous period factor supported by the chip.
- * Btw, 'period' is in tenths of nanoseconds.
- */
- period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
- if (period <= 250) np->minsync = 10;
- else if (period <= 303) np->minsync = 11;
- else if (period <= 500) np->minsync = 12;
- else np->minsync = (period + 40 - 1) / 40;
- /*
- * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
- */
- if (np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2)))
- np->minsync = 25;
- else if (np->minsync < 12 && !(np->features & FE_ULTRA2))
- np->minsync = 12;
- /*
- * Maximum synchronous period factor supported by the chip.
- */
- period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
- np->maxsync = period > 2540 ? 254 : period / 10;
- /*
- ** Prepare initial value of other IO registers
- */
- #if defined SCSI_NCR_TRUST_BIOS_SETTING
- np->rv_scntl0 = np->sv_scntl0;
- np->rv_dmode = np->sv_dmode;
- np->rv_dcntl = np->sv_dcntl;
- np->rv_ctest3 = np->sv_ctest3;
- np->rv_ctest4 = np->sv_ctest4;
- np->rv_ctest5 = np->sv_ctest5;
- burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
- #else
- /*
- ** Select burst length (dwords)
- */
- burst_max = driver_setup.burst_max;
- if (burst_max == 255)
- burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
- if (burst_max > 7)
- burst_max = 7;
- if (burst_max > np->maxburst)
- burst_max = np->maxburst;
- /*
- ** Select all supported special features
- */
- if (np->features & FE_ERL)
- np->rv_dmode |= ERL; /* Enable Read Line */
- if (np->features & FE_BOF)
- np->rv_dmode |= BOF; /* Burst Opcode Fetch */
- if (np->features & FE_ERMP)
- np->rv_dmode |= ERMP; /* Enable Read Multiple */
- if (np->features & FE_PFEN)
- np->rv_dcntl |= PFEN; /* Prefetch Enable */
- if (np->features & FE_CLSE)
- 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)
- np->rv_ctest5 |= DFS; /* Dma Fifo Size */
- /*
- ** Select some other
- */
- if (driver_setup.master_parity)
- np->rv_ctest4 |= MPEE; /* Master parity checking */
- if (driver_setup.scsi_parity)
- np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- /*
- ** Get parity checking, host ID and verbose mode from NVRAM
- **/
- if (nvram) {
- switch(nvram->type) {
- case SCSI_NCR_TEKRAM_NVRAM:
- np->myaddr = nvram->data.Tekram.host_id & 0x0f;
- break;
- case SCSI_NCR_SYMBIOS_NVRAM:
- if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
- np->rv_scntl0 &= ~0x0a;
- np->myaddr = nvram->data.Symbios.host_id & 0x0f;
- if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
- np->verbose += 1;
- break;
- }
- }
- #endif
- /*
- ** Get SCSI addr of host adapter (set by bios?).
- */
- if (np->myaddr == 255) {
- np->myaddr = INB(nc_scid) & 0x07;
- if (!np->myaddr)
- np->myaddr = SCSI_NCR_MYADDR;
- }
- #endif /* SCSI_NCR_TRUST_BIOS_SETTING */
- /*
- * Prepare initial io register bits for burst length
- */
- ncr_init_burst(np, burst_max);
- /*
- ** Set SCSI BUS mode.
- **
- ** - ULTRA2 chips (895/895A/896) 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)
- np->scsi_mode = (np->sv_stest4 & SMODE);
- else if (np->features & FE_DIFF) {
- switch(driver_setup.diff_support) {
- case 4: /* Trust previous settings if present, then GPIO3 */
- if (np->sv_scntl3) {
- if (np->sv_stest2 & 0x20)
- np->scsi_mode = SMODE_HVD;
- break;
- }
- case 3: /* SYMBIOS controllers report HVD through GPIO3 */
- if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
- break;
- if (INB(nc_gpreg) & 0x08)
- break;
- case 2: /* Set HVD unconditionally */
- np->scsi_mode = SMODE_HVD;
- case 1: /* Trust previous settings for HVD */
- if (np->sv_stest2 & 0x20)
- np->scsi_mode = SMODE_HVD;
- break;
- default:/* Don't care about HVD */
- break;
- }
- }
- if (np->scsi_mode == SMODE_HVD)
- np->rv_stest2 |= 0x20;
- /*
- ** Set LED support from SCRIPTS.
- ** Ignore this feature for boards known to use a
- ** specific GPIO wiring and for the 895A or 896
- ** that drive the LED directly.
- ** Also probe initial setting of GPIO0 as output.
- */
- if ((driver_setup.led_pin ||
- (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
- !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
- np->features |= FE_LED0;
- /*
- ** Set irq mode.
- */
- switch(driver_setup.irqm & 3) {
- case 2:
- np->rv_dcntl |= IRQM;
- break;
- case 1:
- np->rv_dcntl |= (np->sv_dcntl & IRQM);
- break;
- default:
- break;
- }
- /*
- ** Configure targets according to driver setup.
- ** If NVRAM present get targets setup from NVRAM.
- ** Allow to override sync, wide and NOSCAN from
- ** boot command line.
- */
- for (i = 0 ; i < MAX_TARGET ; i++) {
- tcb_p tp = &np->target[i];
- tp->usrsync = 255;
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- if (nvram) {
- switch(nvram->type) {
- case SCSI_NCR_TEKRAM_NVRAM:
- ncr_Tekram_setup_target(np, i, &nvram->data.Tekram);
- break;
- case SCSI_NCR_SYMBIOS_NVRAM:
- ncr_Symbios_setup_target(np, i, &nvram->data.Symbios);
- break;
- }
- if (driver_setup.use_nvram & 0x2)
- tp->usrsync = driver_setup.default_sync;
- if (driver_setup.use_nvram & 0x4)
- tp->usrwide = driver_setup.max_wide;
- if (driver_setup.use_nvram & 0x8)
- tp->usrflag &= ~UF_NOSCAN;
- }
- else {
- #else
- if (1) {
- #endif
- tp->usrsync = driver_setup.default_sync;
- tp->usrwide = driver_setup.max_wide;
- tp->usrtags = MAX_TAGS;
- if (!driver_setup.disconnection)
- np->target[i].usrflag = UF_NODISC;
- }
- }
- /*
- ** Announce all that stuff to user.
- */
- i = nvram ? nvram->type : 0;
- printk(KERN_INFO "%s: %sID %d, Fast-%d%s%sn", ncr_name(np),
- 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->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity",
- (np->rv_stest2 & 0x20) ? ", Differential" : "");
- if (bootverbose > 1) {
- printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
- "(hex) %02x/%02x/%02x/%02x/%02x/%02xn",
- ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl,
- np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
- printk (KERN_INFO "%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
- "(hex) %02x/%02x/%02x/%02x/%02x/%02xn",
- ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl,
- np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
- }
- if (bootverbose && np->paddr2)
- printk (KERN_INFO "%s: on-chip RAM at 0x%lxn",
- ncr_name(np), np->paddr2);
- return 0;
- }
- /*
- ** Host attach and initialisations.
- **
- ** Allocate host data and ncb structure.
- ** Request IO region and remap MMIO region.
- ** Do chip initialization.
- ** If all is OK, install interrupt handling and
- ** start the timer daemon.
- */
- static int __init
- ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
- {
- struct host_data *host_data;
- ncb_p np = 0;
- struct Scsi_Host *instance = 0;
- u_long flags = 0;
- ncr_nvram *nvram = device->nvram;
- int i;
- printk(KERN_INFO "ncr53c%s-%d: rev 0x%x on pci bus %d device %d function %d "
- #ifdef __sparc__
- "irq %sn",
- #else
- "irq %dn",
- #endif
- device->chip.name, unit, device->chip.revision_id,
- device->slot.bus, (device->slot.device_fn & 0xf8) >> 3,
- device->slot.device_fn & 7,
- #ifdef __sparc__
- __irq_itoa(device->slot.irq));
- #else
- device->slot.irq);
- #endif
- /*
- ** Allocate host_data structure
- */
- if (!(instance = scsi_register(tpnt, sizeof(*host_data))))
- goto attach_error;
- host_data = (struct host_data *) instance->hostdata;
- /*
- ** Allocate the host control block.
- */
- np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB");
- if (!np)
- goto attach_error;
- NCR_INIT_LOCK_NCB(np);
- np->pdev = device->pdev;
- np->p_ncb = vtobus(np);
- host_data->ncb = np;
- /*
- ** Allocate the default CCB.
- */
- np->ccb = (ccb_p) m_calloc_dma(sizeof(struct ccb), "CCB");
- if (!np->ccb)
- goto attach_error;
- /*
- ** Store input informations in the host data structure.
- */
- strncpy(np->chip_name, device->chip.name, sizeof(np->chip_name) - 1);
- np->unit = unit;
- np->verbose = driver_setup.verbose;
- sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
- np->device_id = device->chip.device_id;
- np->revision_id = device->chip.revision_id;
- np->bus = device->slot.bus;
- np->device_fn = device->slot.device_fn;
- np->features = device->chip.features;
- np->clock_divn = device->chip.nr_divisor;
- np->maxoffs = device->chip.offset_max;
- np->maxburst = device->chip.burst_max;
- np->myaddr = device->host_id;
- /*
- ** Allocate SCRIPTS areas.
- */
- np->script0 = (struct script *)
- m_calloc_dma(sizeof(struct script), "SCRIPT");
- if (!np->script0)
- goto attach_error;
- np->scripth0 = (struct scripth *)
- m_calloc_dma(sizeof(struct scripth), "SCRIPTH");
- if (!np->scripth0)
- goto attach_error;
- /*
- ** Initialize timer structure
- **
- */
- init_timer(&np->timer);
- np->timer.data = (unsigned long) np;
- np->timer.function = ncr53c8xx_timeout;
- /*
- ** Try to map the controller chip to
- ** virtual and physical memory.
- */
- np->paddr = device->slot.base;
- np->paddr2 = (np->features & FE_RAM)? device->slot.base_2 : 0;
- #ifndef SCSI_NCR_IOMAPPED
- np->vaddr = remap_pci_mem(device->slot.base_c, (u_long) 128);
- if (!np->vaddr) {
- printk(KERN_ERR
- "%s: can't map memory mapped IO regionn",ncr_name(np));
- goto attach_error;
- }
- else
- if (bootverbose > 1)
- printk(KERN_INFO
- "%s: using memory mapped IO at virtual address 0x%lxn", ncr_name(np), (u_long) np->vaddr);
- /*
- ** Make the controller's registers available.
- ** Now the INB INW INL OUTB OUTW OUTL macros
- ** can be used safely.
- */
- np->reg = (struct ncr_reg*) np->vaddr;
- #endif /* !defined SCSI_NCR_IOMAPPED */
- /*
- ** Try to map the controller chip into iospace.
- */
- request_region(device->slot.io_port, 128, "ncr53c8xx");
- np->base_io = device->slot.io_port;
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- if (nvram) {
- switch(nvram->type) {
- case SCSI_NCR_SYMBIOS_NVRAM:
- #ifdef SCSI_NCR_DEBUG_NVRAM
- ncr_display_Symbios_nvram(&nvram->data.Symbios);
- #endif
- break;
- case SCSI_NCR_TEKRAM_NVRAM:
- #ifdef SCSI_NCR_DEBUG_NVRAM
- ncr_display_Tekram_nvram(&nvram->data.Tekram);
- #endif
- break;
- default:
- nvram = 0;
- #ifdef SCSI_NCR_DEBUG_NVRAM
- printk(KERN_DEBUG "%s: NVRAM: None or invalid data.n", ncr_name(np));
- #endif
- }
- }
- #endif
- /*
- ** Do chip dependent initialization.
- */
- (void)ncr_prepare_setting(np, nvram);
- if (np->paddr2 && sizeof(struct script) > 4096) {
- np->paddr2 = 0;
- printk(KERN_WARNING "%s: script too large, NOT using on chip RAM.n",
- ncr_name(np));
- }
- /*
- ** Fill Linux host instance structure
- */
- instance->max_channel = 0;
- instance->this_id = np->myaddr;
- instance->max_id = np->maxwide ? 16 : 8;
- instance->max_lun = SCSI_NCR_MAX_LUN;
- #ifndef SCSI_NCR_IOMAPPED
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29)
- instance->base = (unsigned long) np->reg;
- #else
- instance->base = (char *) np->reg;
- #endif
- #endif
- instance->irq = device->slot.irq;
- instance->unique_id = device->slot.io_port;
- instance->io_port = device->slot.io_port;
- instance->n_io_port = 128;
- instance->dma_channel = 0;
- instance->cmd_per_lun = MAX_TAGS;
- instance->can_queue = (MAX_START-4);
- instance->select_queue_depths = ncr53c8xx_select_queue_depths;
- scsi_set_pci_device(instance, device->pdev);
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- np->check_integrity = 0;
- 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
- /*
- ** Patch script to physical addresses
- */
- ncr_script_fill (&script0, &scripth0);
- np->scripth = np->scripth0;
- np->p_scripth = vtobus(np->scripth);
- np->p_script = (np->paddr2) ? np->paddr2 : vtobus(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 = vtobus (np->ccb);
- /*
- ** Patch the script for LED support.
- */
- if (np->features & FE_LED0) {
- np->script0->idle[0] =
- cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR, 0x01));
- np->script0->reselected[0] =
- cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
- np->script0->start[0] =
- cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
- }
- /*
- ** Look for the target control block of this nexus.
- ** For i = 0 to 3
- ** JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb)
- */
- for (i = 0 ; i < 4 ; i++) {
- np->jump_tcb[i].l_cmd =
- cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3))));
- np->jump_tcb[i].l_paddr =
- cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_target));
- }
- /*
- ** Reset chip.
- */
- OUTB (nc_istat, SRST);
- UDELAY (100);
- OUTB (nc_istat, 0 );
- /*
- ** Now check the cache handling of the pci chipset.
- */
- if (ncr_snooptest (np)) {
- printk (KERN_ERR "CACHE INCORRECTLY CONFIGURED.n");
- goto attach_error;
- };
- /*
- ** Install the interrupt handler.
- */
- if (request_irq(device->slot.irq, ncr53c8xx_intr,
- ((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) |
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
- ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
- #else
- 0,
- #endif
- "ncr53c8xx", np)) {
- #ifdef __sparc__
- printk(KERN_ERR "%s: request irq %s failuren",
- ncr_name(np), __irq_itoa(device->slot.irq));
- #else
- printk(KERN_ERR "%s: request irq %d failuren",
- ncr_name(np), device->slot.irq);
- #endif
- goto attach_error;
- }
- np->irq = device->slot.irq;
- /*
- ** Initialize the fixed part of the default ccb.
- */
- ncr_init_ccb(np, np->ccb);
- /*
- ** After SCSI devices have been opened, we cannot
- ** reset the bus safely, so we do it here.
- ** Interrupt handler does the real work.
- ** Process the reset exception,
- ** if interrupts are not enabled yet.
- ** Then enable disconnects.
- */
- NCR_LOCK_NCB(np, flags);
- if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
- printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!n", ncr_name(np));
- NCR_UNLOCK_NCB(np, flags);
- goto attach_error;
- }
- ncr_exception (np);
- np->disc = 1;
- /*
- ** The middle-level SCSI driver does not
- ** wait for devices to settle.
- ** Wait synchronously if more than 2 seconds.
- */
- if (driver_setup.settle_delay > 2) {
- printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...n",
- ncr_name(np), driver_setup.settle_delay);
- MDELAY (1000 * driver_setup.settle_delay);
- }
- /*
- ** Now let the generic SCSI driver
- ** look for the SCSI devices on the bus ..
- */
- /*
- ** start the timeout daemon
- */
- np->lasttime=0;
- ncr_timeout (np);
- /*
- ** use SIMPLE TAG messages by default
- */
- #ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG
- np->order = M_SIMPLE_TAG;
- #endif
- /*
- ** Done.
- */
- if (!the_template) {
- the_template = instance->hostt;
- first_host = instance;
- }
- NCR_UNLOCK_NCB(np, flags);
- return 0;
- attach_error:
- if (!instance) return -1;
- printk(KERN_INFO "%s: detaching...n", ncr_name(np));
- if (!np)
- goto unregister;
- #ifndef SCSI_NCR_IOMAPPED
- if (np->vaddr) {
- #ifdef DEBUG_NCR53C8XX
- printk(KERN_DEBUG "%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);
- }
- #endif /* !SCSI_NCR_IOMAPPED */
- if (np->base_io) {
- #ifdef DEBUG_NCR53C8XX
- printk(KERN_DEBUG "%s: releasing IO region %x[%d]n", ncr_name(np), np->base_io, 128);
- #endif
- release_region(np->base_io, 128);
- }
- if (np->irq) {
- #ifdef DEBUG_NCR53C8XX
- #ifdef __sparc__
- printk(KERN_INFO "%s: freeing irq %sn", ncr_name(np),
- __irq_itoa(np->irq));
- #else
- printk(KERN_INFO "%s: freeing irq %dn", ncr_name(np), np->irq);
- #endif
- #endif
- free_irq(np->irq, np);
- }
- if (np->scripth0)
- m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
- if (np->script0)
- m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
- if (np->ccb)
- m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
- m_free_dma(np, sizeof(struct ncb), "NCB");
- unregister:
- scsi_unregister(instance);
- return -1;
- }
- /*==========================================================
- **
- **
- ** Done SCSI commands list management.
- **
- ** We donnot enter the scsi_done() callback immediately
- ** after a command has been seen as completed but we
- ** insert it into a list which is flushed outside any kind
- ** of driver critical section.
- ** This allows to do minimal stuff under interrupt and
- ** inside critical sections and to also avoid locking up
- ** on recursive calls to driver entry points under SMP.
- ** In fact, the only kernel point which is entered by the
- ** driver with a driver lock set is kmalloc(GFP_ATOMIC)
- ** that shall not reenter the driver under any circumstances,
- ** AFAIK.
- **
- **==========================================================
- */
- static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
- {
- unmap_scsi_data(np, cmd);
- cmd->host_scribble = (char *) np->done_list;
- np->done_list = cmd;
- }
- static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd)
- {
- Scsi_Cmnd *cmd;
- while (lcmd) {
- cmd = lcmd;
- lcmd = (Scsi_Cmnd *) cmd->host_scribble;
- cmd->scsi_done(cmd);
- }
- }
- /*==========================================================
- **
- **
- ** 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.
- **
- **
- **==========================================================
- */
- #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 no_increase;
- if (tp->inq_done) {
- if (!tp->ic_maximums_set) {
- tp->ic_maximums_set = 1;
- /* check target and host adapter capabilities */
- 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;
- }
- if (DEBUG_FLAGS & DEBUG_IC) {
- printk("%s: cmd->ic_nego %d, 1st byte 0x%2Xn",
- ncr_name(np), cmd->ic_nego, cmd->cmnd[0]);
- }
- /* First command from integrity check routine will request
- * a PPR message. Disable.
- */
- if ((cmd->ic_nego & NS_PPR) == NS_PPR)
- cmd->ic_nego &= ~NS_PPR;
- /* 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;
- }
-
- /* In case of a bus reset, ncr_negotiate will reset
- * the flags tp->widedone and tp->period to 0, forcing
- * a new negotiation.
- */
- no_increase = 0;
- if (tp->widedone == 0) {
- cmd->ic_nego = NS_WIDE;
- tp->widedone = 1;
- no_increase = 1;
- }
- else if (tp->period == 0) {
- cmd->ic_nego = NS_SYNC;
- tp->period = 1;
- no_increase = 1;
- }
-
- switch (cmd->ic_nego) {
- case NS_WIDE:
- /*
- ** negotiate wide transfers ?
- ** Do NOT negotiate if device only supports
- ** narrow.
- */
- 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++] = cmd->ic_nego_width & tp->ic_max_width;
- }
- else
- cmd->ic_nego_width &= tp->ic_max_width;
-
- break;
- case NS_SYNC:
- /*
- ** negotiate synchronous transfers?
- ** Target must support sync transfers.
- **
- ** If period becomes longer than max, reset to async
- */
- if (tp->inq_byte7 & INQ7_SYNC) {
- nego = NS_SYNC;
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 3;
- msgptr[msglen++] = M_X_SYNC_REQ;
- switch (cmd->ic_nego_sync) {
- case 2: /* increase the period */
- if (!no_increase) {
- 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;
- }
- }
- msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0;
- msgptr[msglen++] = tp->maxoffs;
- break;
- case 1: /* nego. to maximum */
- msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0;
- msgptr[msglen++] = tp->maxoffs;
- break;
- case 0: /* nego to async */
- default:
- msgptr[msglen++] = 0;
- msgptr[msglen++] = 0;
- break;
- };
- }
- else
- cmd->ic_nego_sync = 0;
- break;
- case NS_NOCHANGE:
- default:
- 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": "sync/async 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
- ** negotiation and the nego_status field of the CCB.
- ** Returns the size of the message in bytes.
- **
- **
- **==========================================================
- */
- 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;
- if (tp->inq_done) {
- /*
- ** negotiate wide transfers ?
- */
- if (!tp->widedone) {
- if (tp->inq_byte7 & INQ7_WIDE16) {
- nego = NS_WIDE;
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- if (tp->ic_done)
- tp->usrwide &= tp->ic_max_width;
- #endif
- } else
- tp->widedone=1;
- };
- /*
- ** negotiate synchronous transfers?
- */
- if (!nego && !tp->period) {
- if (tp->inq_byte7 & INQ7_SYNC) {
- nego = NS_SYNC;
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- if ((tp->ic_done) &&
- (tp->minsync < tp->ic_min_sync))
- tp->minsync = tp->ic_min_sync;
- #endif
- } else {
- tp->period =0xffff;
- PRINT_TARGET(np, cp->target);
- printk ("target did not report SYNC.n");
- };
- };
- };
- switch (nego) {
- case NS_SYNC:
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 3;
- msgptr[msglen++] = M_X_SYNC_REQ;
- msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
- msgptr[msglen++] = tp->maxoffs;
- break;
- case NS_WIDE:
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 2;
- msgptr[msglen++] = M_X_WIDE_REQ;
- msgptr[msglen++] = tp->usrwide;
- break;
- };
- cp->nego_status = nego;
- if (nego) {
- tp->nego_cp = cp;
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- ncr_print_msg(cp, nego == NS_WIDE ?
- "wide msgout":"sync_msgout", msgptr);
- };
- };
- return msglen;
- }
- /*==========================================================
- **
- **
- ** Start execution of a SCSI command.
- ** This is called from the generic SCSI driver.
- **
- **
- **==========================================================
- */
- static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
- {
- /* Scsi_Device *device = cmd->device; */
- tcb_p tp = &np->target[cmd->target];
- lcb_p lp = tp->lp[cmd->lun];
- ccb_p cp;
- int segments;
- u_char idmsg, *msgptr;
- u_int msglen;
- int direction;
- u_int32 lastp, goalp;
- /*---------------------------------------------
- **
- ** Some shortcuts ...
- **
- **---------------------------------------------
- */
- if ((cmd->target == np->myaddr ) ||
- (cmd->target >= MAX_TARGET) ||
- (cmd->lun >= MAX_LUN )) {
- return(DID_BAD_TARGET);
- }
- /*---------------------------------------------
- **
- ** Complete the 1st TEST UNIT READY command
- ** with error condition if the device is
- ** flagged NOSCAN, in order to speed up
- ** the boot.
- **
- **---------------------------------------------
- */
- if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) &&
- (tp->usrflag & UF_NOSCAN)) {
- tp->usrflag &= ~UF_NOSCAN;
- return DID_BAD_TARGET;
- }
- if (DEBUG_FLAGS & DEBUG_TINY) {
- PRINT_ADDR(cmd);
- printk ("CMD=%x ", cmd->cmnd[0]);
- }
- /*---------------------------------------------------
- **
- ** Assign a ccb / bind cmd.
- ** If resetting, shorten settle_time if necessary
- ** in order to avoid spurious timeouts.
- ** If resetting or no free ccb,
- ** insert cmd into the waiting list.
- **
- **----------------------------------------------------
- */
- if (np->settle_time && cmd->timeout_per_command >= HZ) {
- u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
- if (ktime_dif(np->settle_time, tlimit) > 0)
- np->settle_time = tlimit;
- }
- if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
- insert_into_waiting_list(np, cmd);
- return(DID_OK);
- }
- cp->cmd = cmd;
- /*---------------------------------------------------
- **
- ** Enable tagged queue if asked by scsi ioctl
- **
- **----------------------------------------------------
- */
- #if 0 /* This stuff was only useful for linux-1.2.13 */
- if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
- lp->numtags = tp->usrtags;
- ncr_setup_tags (np, cmd->target, cmd->lun);
- }
- #endif
- /*----------------------------------------------------
- **
- ** Build the identify / tag / sdtr message
- **
- **----------------------------------------------------
- */
- idmsg = M_IDENTIFY | cmd->lun;
- if (cp ->tag != NO_TAG ||
- (cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC)))
- idmsg |= 0x40;
- msgptr = cp->scsi_smsg;
- msglen = 0;
- msgptr[msglen++] = idmsg;
- if (cp->tag != NO_TAG) {
- char order = np->order;
- /*
- ** Force ordered tag if necessary to avoid timeouts
- ** and to preserve interactivity.
- */
- if (lp && ktime_exp(lp->tags_stime)) {
- if (lp->tags_smap) {
- order = M_ORDERED_TAG;
- if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){
- PRINT_ADDR(cmd);
- printk("ordered tag forced.n");
- }
- }
- lp->tags_stime = ktime_get(3*HZ);
- lp->tags_smap = lp->tags_umap;
- }
- if (order == 0) {
- /*
- ** Ordered write ops, unordered read ops.
- */
- switch (cmd->cmnd[0]) {
- case 0x08: /* READ_SMALL (6) */
- case 0x28: /* READ_BIG (10) */
- case 0xa8: /* READ_HUGE (12) */
- order = M_SIMPLE_TAG;
- break;
- default:
- order = M_ORDERED_TAG;
- }
- }
- msgptr[msglen++] = order;
- /*
- ** Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
- ** since we may have to deal with devices that have
- ** problems with #TAG 0 or too great #TAG numbers.
- */
- msgptr[msglen++] = (cp->tag << 1) + 1;
- }
- /*----------------------------------------------------
- **
- ** Build the data descriptors
- **
- **----------------------------------------------------
- */
- direction = scsi_data_direction(cmd);
- if (direction != SCSI_DATA_NONE) {
- segments = ncr_scatter (np, cp, cp->cmd);
- if (segments < 0) {
- ncr_free_ccb(np, cp);
- return(DID_ERROR);
- }
- }
- else {
- cp->data_len = 0;
- 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) {
- /*
- * Midlayer signal to the driver that all of the scsi commands
- * for the integrity check have completed. Save the negotiated
- * parameters (extracted from sval and wval).
- */
- {
- u_char idiv;
- idiv = (tp->wval>>4) & 0x07;
- if ((tp->sval&0x1f) && idiv )
- tp->period = (((tp->sval>>5)+4)
- *div_10M[idiv-1])/np->clock_khz;
- else
- tp->period = 0xffff;
- }
- /*
- * tp->period contains 10 times the transfer period,
- * which itself is 4 * the requested negotiation rate.
- */
- if (tp->period <= 250) tp->ic_min_sync = 10;
- else if (tp->period <= 303) tp->ic_min_sync = 11;
- else if (tp->period <= 500) tp->ic_min_sync = 12;
- else
- tp->ic_min_sync = (tp->period + 40 - 1) / 40;
- /*
- * Negotiation for this target it complete.
- */
- tp->ic_max_width = (tp->wval & EWS) ? 1: 0;
- tp->ic_done = 1;
- tp->widedone = 1;
- printk("%s: Integrity Check Complete: n", ncr_name(np));
- printk("%s: %s %s SCSI", ncr_name(np),
- (tp->sval&0x1f)?"SYNC":"ASYNC",
- tp->ic_max_width?"WIDE":"NARROW");
- if (tp->sval&0x1f) {
- u_long mbs = 10000 * (tp->ic_max_width + 1);
- printk(" %d.%d MB/s",
- (int) (mbs / tp->period), (int) (mbs % tp->period));
- printk(" (%d ns, %d offset)n",
- tp->period/10, tp->sval&0x1f);
- }
- 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.
- **
- **----------------------------------------------------
- */
- if (!cp->data_len)
- direction = SCSI_DATA_NONE;
- /*
- ** If data direction is UNKNOWN, speculate DATA_READ
- ** but prepare alternate pointers for WRITE in case
- ** of our speculation will be just wrong.
- ** SCRIPTS will swap values if needed.
- */
- switch(direction) {
- case SCSI_DATA_UNKNOWN:
- case SCSI_DATA_WRITE:
- goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
- if (segments <= MAX_SCATTERL)
- lastp = goalp - 8 - (segments * 16);
- else {
- lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
- lastp -= (segments - MAX_SCATTERL) * 16;
- }
- if (direction != SCSI_DATA_UNKNOWN)
- break;
- cp->phys.header.wgoalp = cpu_to_scr(goalp);
- cp->phys.header.wlastp = cpu_to_scr(lastp);
- /* fall through */
- case SCSI_DATA_READ:
- goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
- if (segments <= MAX_SCATTERL)
- lastp = goalp - 8 - (segments * 16);
- else {
- lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
- lastp -= (segments - MAX_SCATTERL) * 16;
- }
- break;
- default:
- case SCSI_DATA_NONE:
- lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
- break;
- }
- /*
- ** Set all pointers values needed by SCRIPTS.
- ** If direction is unknown, start at data_io.
- */
- cp->phys.header.lastp = cpu_to_scr(lastp);
- cp->phys.header.goalp = cpu_to_scr(goalp);
- if (direction == SCSI_DATA_UNKNOWN)
- cp->phys.header.savep =
- cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
- else
- cp->phys.header.savep= cpu_to_scr(lastp);
- /*
- ** Save the initial data pointer in order to be able
- ** to redo the command.
- */
- cp->startp = cp->phys.header.savep;
- /*----------------------------------------------------
- **
- ** fill in ccb
- **
- **----------------------------------------------------
- **
- **
- ** physical -> virtual backlink
- ** Generic SCSI command
- */
- /*
- ** Startqueue
- */
- cp->start.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
- cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_dsa));
- /*
- ** select
- */
- cp->phys.select.sel_id = cmd->target;
- cp->phys.select.sel_scntl3 = tp->wval;
- cp->phys.select.sel_sxfer = tp->sval;
- /*
- ** message
- */
- cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
- cp->phys.smsg.size = cpu_to_scr(msglen);
- /*
- ** command
- */
- memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf)));
- cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0]));
- cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len);
- /*
- ** status
- */
- cp->actualquirks = tp->quirks;
- cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
- cp->scsi_status = S_ILLEGAL;
- cp->parity_status = 0;
- cp->xerr_status = XE_OK;
- #if 0
- cp->sync_status = tp->sval;
- cp->wide_status = tp->wval;
- #endif
- /*----------------------------------------------------
- **
- ** Critical region: start this job.
- **
- **----------------------------------------------------
- */
- /*
- ** activate this job.
- */
- cp->magic = CCB_MAGIC;
- /*
- ** insert next CCBs into start queue.
- ** 2 max at a time is enough to flush the CCB wait queue.
- */
- cp->auto_sense = 0;
- if (lp)
- ncr_start_next_ccb(np, lp, 2);
- else
- ncr_put_start_queue(np, cp);
- /*
- ** Command is successfully queued.
- */
- return(DID_OK);
- }
- /*==========================================================
- **
- **
- ** Insert a CCB into the start queue and wake up the
- ** SCRIPTS processor.
- **
- **
- **==========================================================
- */
- static void ncr_start_next_ccb(ncb_p np, lcb_p lp, int maxn)
- {
- XPT_QUEHEAD *qp;
- ccb_p cp;
- if (lp->held_ccb)
- return;
- while (maxn-- && lp->queuedccbs < lp->queuedepth) {
- qp = xpt_remque_head(&lp->wait_ccbq);
- if (!qp)
- break;
- ++lp->queuedccbs;
- cp = xpt_que_entry(qp, struct ccb, link_ccbq);
- xpt_insque_tail(qp, &lp->busy_ccbq);
- lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag] =
- cpu_to_scr(CCB_PHYS (cp, restart));
- ncr_put_start_queue(np, cp);
- }
- }
- static void ncr_put_start_queue(ncb_p np, ccb_p cp)