// SPDX-License-Identifier: GPL-2.0-or-later /****************************************************************************** ** Device driver for the PCI-SCSI NCR538XX controller family. ** ** Copyright (C) 1994 Wolfgang Stanglmeier ** ** **----------------------------------------------------------------------------- ** ** 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. ** ** 2005 by Matthew Wilcox and James Bottomley ** PCI-ectomy. This driver now supports only the 720 chip (see the ** NCR_Q720 and zalon drivers for the bus probe logic). ** *******************************************************************************
*/
/*========================================================== ** ** Simple power of two buddy-like allocator. ** ** This simple code is not intended to be fast, but to ** provide power of 2 aligned memory allocations. ** Since the SCRIPTS processor only supplies 8 bit ** arithmetic, this allocator allows simple and fast ** address calculations from the SCRIPTS code. ** In addition, cache line alignment is guaranteed for ** power of 2 cache line size. ** Enhanced in linux-2.3.44 to provide a memory pool ** per pcidev to support dynamic dma mapping. (I would ** have preferred a real bus abstraction, btw). ** **==========================================================
*/
/* * With pci bus iommu support, we use a default pool of unmapped memory * for memory we donnot need to DMA from/to and one pool per pcidev for * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
*/
static m_addr_t ___mp0_getp(m_pool_s *mp)
{
m_addr_t m = __get_free_pages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER); if (m)
++mp->nump; return m;
}
staticvoid ___mp0_freep(m_pool_s *mp, m_addr_t m)
{
free_pages(m, MEMO_PAGE_ORDER);
--mp->nump;
}
/* * With pci bus iommu support, we maintain one pool per pcidev and a * hashed reverse table for virtual to bus physical address translations.
*/ static m_addr_t ___dma_getp(m_pool_s *mp)
{
m_addr_t vp;
m_vtob_s *vbp;
vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); if (vbp) {
dma_addr_t daddr;
vp = (m_addr_t) dma_alloc_coherent(mp->bush,
PAGE_SIZE<<MEMO_PAGE_ORDER,
&daddr, GFP_ATOMIC); if (vp) { int hc = VTOB_HASH_CODE(vp);
vbp->vaddr = vp;
vbp->baddr = daddr;
vbp->next = mp->vtob[hc];
mp->vtob[hc] = vbp;
++mp->nump; return vp;
}
} if (vbp)
__m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); return 0;
}
staticvoid ___dma_freep(m_pool_s *mp, m_addr_t m)
{
m_vtob_s **vbpp, *vbp; int hc = VTOB_HASH_CODE(m);
/*========================================================== ** ** Driver setup. ** ** This structure is initialized from linux config ** options. It can be overridden at boot-up by the boot ** command line. ** **==========================================================
*/ staticstruct ncr_driver_setup
driver_setup = SCSI_NCR_DRIVER_SETUP;
/*=================================================================== ** ** Driver setup from the boot command line ** **===================================================================
*/
staticint device_queue_depth(int unit, int target, int lun)
{ int c, h, t, u, v; char *p = driver_setup.tag_ctrl; char *ep;
h = -1;
t = NO_TARGET;
u = NO_LUN; while ((c = *p++) != 0) {
v = simple_strtoul(p, &ep, 0); switch(c) { case'/':
++h;
t = ALL_TARGETS;
u = ALL_LUNS; break; case't': if (t != target)
t = (target == v) ? v : NO_TARGET;
u = ALL_LUNS; break; case'u': if (u != lun)
u = (lun == v) ? v : NO_LUN; break; case'q': if (h == unit &&
(t == ALL_TARGETS || t == target) &&
(u == ALL_LUNS || u == lun)) return v; break; case'-':
t = ALL_TARGETS;
u = ALL_LUNS; break; default: break;
}
p = ep;
} return DEF_DEPTH;
}
/*========================================================== ** ** 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. ** **==========================================================
*/
/* ** 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 u64 tagmap_t; #else typedef u32 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.
*/
/* ** 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.
*/
/* ** 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 ...
*/
/* ** 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.
*/
/*========================================================== ** ** Command control block states. ** **==========================================================
*/
/*======================================================================== ** ** 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 */ struct lcb * lp[MAX_LUN]; /* The lcb's of this tcb */
/*---------------------------------------------------------------- ** Pointer to the ccb used for negotiation. ** Prevent from starting a negotiation for all queued commands ** when tagged command queuing is enabled. **----------------------------------------------------------------
*/ struct ccb * nego_cp;
/*---------------------------------------------------------------- ** statistical data **----------------------------------------------------------------
*/
u_long transfers;
u_long bytes;
/* User settable limits and options. */
u_char usrsync;
u_char usrwide;
u_char usrtags;
u_char usrflag; struct scsi_target *starget;
};
/*======================================================================== ** ** 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. **----------------------------------------------------------------
*/
u32 jump_ccb_0; /* Default table if no tags */
u32 *jump_ccb; /* Virtual address */
/*---------------------------------------------------------------- ** CCB queue management. **----------------------------------------------------------------
*/ struct list_head free_ccbq; /* Queue of available CCBs */ struct list_head busy_ccbq; /* Queue of busy CCBs */ struct list_head wait_ccbq; /* Queue of waiting for IO CCBs */ struct list_head 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 */
/*---------------------------------------------------------------- ** QUEUE FULL control and ORDERED tag control. **----------------------------------------------------------------
*/ /*---------------------------------------------------------------- ** QUEUE FULL and ORDERED tag control. **----------------------------------------------------------------
*/
u16 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 */ struct ccb * 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. **----------------------------------------------------------------
*/
u32 savep;
u32 lastp;
u32 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. **----------------------------------------------------------------
*/
u32 wlastp;
u32 wgoalp;
/*---------------------------------------------------------------- ** The virtual address of the ccb containing this header. **----------------------------------------------------------------
*/ struct ccb * 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 chosen offsets. ** xerr_st 0 (0x34) scratcha ** sync_st 1 (0x05) sxfer ** wide_st 3 (0x03) scntl3
*/
/* ** 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
/*========================================================== ** ** 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-changeable data and ** data blocks for the indirect move commands. ** **----------------------------------------------------------
*/
/*======================================================================== ** ** 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. **----------------------------------------------------------------
*/ struct 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; struct ccb * link_ccb; /* Host adapter CCB chain */ struct list_head link_ccbq; /* Link to unit CCB queue */
u32 startp; /* Initial data pointer */
u_long magic; /* Free / busy CCB flag */
};
/*======================================================================== ** ** 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. **----------------------------------------------------------------
*/ struct scsi_cmnd *waiting_list; /* Commands waiting for a CCB */ /* when lcb is not allocated. */ struct scsi_cmnd *done_list; /* Commands waiting for done() */ /* callback to be invoked. */
spinlock_t smp_lock; /* Lock for SMP threading */
/*---------------------------------------------------------------- ** Chip and controller identification. **----------------------------------------------------------------
*/ int unit; /* Unit number */ 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_ctest0, 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_ctest0, 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. **----------------------------------------------------------------
*/ void __iomem *vaddr; /* Virtual and bus address of */ unsignedlong paddr; /* chip's IO registers. */ unsignedlong paddr2; /* On-chip RAM bus address. */ volatile/* Pointer to volatile for */ struct ncr_reg __iomem *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. **----------------------------------------------------------------
*/ struct device *dev;
u_char revision_id; /* PCI device revision id */
u32 irq; /* IRQ level */
u32 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. **----------------------------------------------------------------
*/
u16 squeueput; /* Next free slot of the queue */
u16 actccbs; /* Number of allocated CCBs */
u16 queuedccbs; /* Number of CCBs in start queue*/
u16 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 */
u32 lastmsg; /* Last SCSI message sent */
u_char scratch; /* Scratch for SCSI receive */
/*---------------------------------------------------------------- ** Miscellaneous configuration and status parameters. **----------------------------------------------------------------
*/
u_char disc; /* Disconnection 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 */ volatile u_char release_stage; /* Synchronisation stage on release */
};
/*========================================================== ** ** ** 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! ** **----------------------------------------------------------
*/
/* ** For HP Zalon/53c720 systems, the Zalon interface ** between CPU and 53c720 does prefetches, which causes ** problems with self modifying scripts. The problem ** is overcome by calling a dummy subroutine after each ** modification, to force a refetch of the script on ** return from the subroutine.
*/
/*========================================================== ** ** ** 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. ** **----------------------------------------------------------
*/
staticstruct 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)
*/
/* ** 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 loses 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 MESSAGE_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), /* ** Flush script prefetch if required */ PREFETCH_FLUSH /* ** 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 EXTENDED_SDTR 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, NOP), 0, SCR_COPY (1), RADDR (scratcha), NADDR (msgout), /* ** 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 Documentation/scsi/ncr53c8xx.rst 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),
}/*-------------------------< 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 (COMMAND_COMPLETE)), PADDR (complete), SCR_JUMP ^ IFTRUE (DATA (DISCONNECT)), PADDR (disconnect), SCR_JUMP ^ IFTRUE (DATA (SAVE_POINTERS)), PADDR (save_dp), SCR_JUMP ^ IFTRUE (DATA (RESTORE_POINTERS)), PADDR (restore_dp), SCR_JUMP ^ IFTRUE (DATA (EXTENDED_MESSAGE)), PADDRH (msg_extended), SCR_JUMP ^ IFTRUE (DATA (NOP)), PADDR (clrack), SCR_JUMP ^ IFTRUE (DATA (MESSAGE_REJECT)), PADDRH (msg_reject), SCR_JUMP ^ IFTRUE (DATA (IGNORE_WIDE_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, MESSAGE_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), /* ** Flush script prefetch if required */ PREFETCH_FLUSH 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 (SAM_STAT_GOOD)), PADDRH (bad_status),
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.