Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/scsi/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 205 kB image not shown  

Quelle  ncr53c8xx.c   Sprache: C

 
// 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).
**
*******************************************************************************
*/


/*
** 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:
** 53C720 (Wide,   Fast SCSI-2, intfly problems)
*/


/* Name and version of the driver */
#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3g"

#define SCSI_NCR_DEBUG_FLAGS (0)

#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/types.h>

#include <asm/dma.h>
#include <asm/io.h>

#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>

#include "ncr53c8xx.h"

#define NAME53C8XX  "ncr53c8xx"

/*==========================================================
**
** Debugging tags
**
**==========================================================
*/


#define DEBUG_ALLOC    (0x0001)
#define DEBUG_PHASE    (0x0002)
#define DEBUG_QUEUE    (0x0008)
#define DEBUG_RESULT   (0x0010)
#define DEBUG_POINTER  (0x0020)
#define DEBUG_SCRIPT   (0x0040)
#define DEBUG_TINY     (0x0080)
#define DEBUG_TIMING   (0x0100)
#define DEBUG_NEGO     (0x0200)
#define DEBUG_TAGS     (0x0400)
#define DEBUG_SCATTER  (0x0800)
#define DEBUG_IC        (0x1000)

/*
**    Enable/Disable debug messages.
**    Can be changed at runtime too.
*/


#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
 #define DEBUG_FLAGS ncr_debug
#else
 #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS
#endif

/*
 * Locally used status flag
 */

#define SAM_STAT_ILLEGAL 0xff

static inline struct list_head *ncr_list_pop(struct list_head *head)
{
 if (!list_empty(head)) {
  struct list_head *elem = head->next;

  list_del(elem);
  return elem;
 }

 return NULL;
}

/*==========================================================
**
** 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).
**
**==========================================================
*/


#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */
#if PAGE_SIZE >= 8192
#define MEMO_PAGE_ORDER 0 /* 1 PAGE  maximum */
#else
#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */
#endif
#define MEMO_FREE_UNUSED /* Free unused pages immediately */
#define MEMO_WARN 1
#define MEMO_GFP_FLAGS GFP_ATOMIC
#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER)
#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT)
#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1)

typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */
typedef struct device *m_bush_t; /* Something that addresses DMAable */

typedef struct m_link {  /* Link between free memory chunks */
 struct m_link *next;
} m_link_s;

typedef struct m_vtob {  /* Virtual to Bus address translation */
 struct m_vtob *next;
 m_addr_t vaddr;
 m_addr_t baddr;
} m_vtob_s;
#define VTOB_HASH_SHIFT  5
#define VTOB_HASH_SIZE  (1UL << VTOB_HASH_SHIFT)
#define VTOB_HASH_MASK  (VTOB_HASH_SIZE-1)
#define VTOB_HASH_CODE(m) \
 ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)

typedef struct m_pool {  /* Memory pool of a given kind */
 m_bush_t bush;
 m_addr_t (*getp)(struct m_pool *);
 void (*freep)(struct m_pool *, m_addr_t);
 int nump;
 m_vtob_s *(vtob[VTOB_HASH_SIZE]);
 struct m_pool *next;
 struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
} m_pool_s;

static void *___m_alloc(m_pool_s *mp, int size)
{
 int i = 0;
 int s = (1 << MEMO_SHIFT);
 int j;
 m_addr_t a;
 m_link_s *h = mp->h;

 if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
  return NULL;

 while (size > s) {
  s <<= 1;
  ++i;
 }

 j = i;
 while (!h[j].next) {
  if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
   h[j].next = (m_link_s *)mp->getp(mp);
   if (h[j].next)
    h[j].next->next = NULL;
   break;
  }
  ++j;
  s <<= 1;
 }
 a = (m_addr_t) h[j].next;
 if (a) {
  h[j].next = h[j].next->next;
  while (j > i) {
   j -= 1;
   s >>= 1;
   h[j].next = (m_link_s *) (a+s);
   h[j].next->next = NULL;
  }
 }
#ifdef DEBUG
 printk("___m_alloc(%d) = %p\n", size, (void *) a);
#endif
 return (void *) a;
}

static void ___m_free(m_pool_s *mp, void *ptr, int size)
{
 int i = 0;
 int s = (1 << MEMO_SHIFT);
 m_link_s *q;
 m_addr_t a, b;
 m_link_s *h = mp->h;

#ifdef DEBUG
 printk("___m_free(%p, %d)\n", ptr, size);
#endif

 if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
  return;

 while (size > s) {
  s <<= 1;
  ++i;
 }

 a = (m_addr_t) ptr;

 while (1) {
#ifdef MEMO_FREE_UNUSED
  if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
   mp->freep(mp, a);
   break;
  }
#endif
  b = a ^ s;
  q = &h[i];
  while (q->next && q->next != (m_link_s *) b) {
   q = q->next;
  }
  if (!q->next) {
   ((m_link_s *) a)->next = h[i].next;
   h[i].next = (m_link_s *) a;
   break;
  }
  q->next = q->next->next;
  a = a & b;
  s <<= 1;
  ++i;
 }
}

static DEFINE_SPINLOCK(ncr53c8xx_lock);

static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
{
 void *p;

 p = ___m_alloc(mp, size);

 if (DEBUG_FLAGS & DEBUG_ALLOC)
  printk ("new %-10s[%4d] @%p.\n", name, size, p);

 if (p)
  memset(p, 0, size);
 else if (uflags & MEMO_WARN)
  printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);

 return p;
}

#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN)

static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
{
 if (DEBUG_FLAGS & DEBUG_ALLOC)
  printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);

 ___m_free(mp, ptr, size);

}

/*
 * 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;
}

static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
{
 free_pages(m, MEMO_PAGE_ORDER);
 --mp->nump;
}

static m_pool_s mp0 = {NULL, ___mp0_getp, ___mp0_freep};

/*
 * DMAable pools.
 */


/*
 * 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;
}

static void ___dma_freep(m_pool_s *mp, m_addr_t m)
{
 m_vtob_s **vbpp, *vbp;
 int hc = VTOB_HASH_CODE(m);

 vbpp = &mp->vtob[hc];
 while (*vbpp && (*vbpp)->vaddr != m)
  vbpp = &(*vbpp)->next;
 if (*vbpp) {
  vbp = *vbpp;
  *vbpp = (*vbpp)->next;
  dma_free_coherent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
      (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
  __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
  --mp->nump;
 }
}

static inline m_pool_s *___get_dma_pool(m_bush_t bush)
{
 m_pool_s *mp;
 for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
 return mp;
}

static m_pool_s *___cre_dma_pool(m_bush_t bush)
{
 m_pool_s *mp;
 mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
 if (mp) {
  memset(mp, 0, sizeof(*mp));
  mp->bush = bush;
  mp->getp = ___dma_getp;
  mp->freep = ___dma_freep;
  mp->next = mp0.next;
  mp0.next = mp;
 }
 return mp;
}

static void ___del_dma_pool(m_pool_s *p)
{
 struct m_pool **pp = &mp0.next;

 while (*pp && *pp != p)
  pp = &(*pp)->next;
 if (*pp) {
  *pp = (*pp)->next;
  __m_free(&mp0, p, sizeof(*p), "MPOOL");
 }
}

static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
{
 u_long flags;
 struct m_pool *mp;
 void *m = NULL;

 spin_lock_irqsave(&ncr53c8xx_lock, flags);
 mp = ___get_dma_pool(bush);
 if (!mp)
  mp = ___cre_dma_pool(bush);
 if (mp)
  m = __m_calloc(mp, size, name);
 if (mp && !mp->nump)
  ___del_dma_pool(mp);
 spin_unlock_irqrestore(&ncr53c8xx_lock, flags);

 return m;
}

static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
{
 u_long flags;
 struct m_pool *mp;

 spin_lock_irqsave(&ncr53c8xx_lock, flags);
 mp = ___get_dma_pool(bush);
 if (mp)
  __m_free(mp, m, size, name);
 if (mp && !mp->nump)
  ___del_dma_pool(mp);
 spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
}

static m_addr_t __vtobus(m_bush_t bush, void *m)
{
 u_long flags;
 m_pool_s *mp;
 int hc = VTOB_HASH_CODE(m);
 m_vtob_s *vp = NULL;
 m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;

 spin_lock_irqsave(&ncr53c8xx_lock, flags);
 mp = ___get_dma_pool(bush);
 if (mp) {
  vp = mp->vtob[hc];
  while (vp && (m_addr_t) vp->vaddr != a)
   vp = vp->next;
 }
 spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
 return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
}

#define _m_calloc_dma(np, s, n)  __m_calloc_dma(np->dev, s, n)
#define _m_free_dma(np, p, s, n) __m_free_dma(np->dev, p, s, n)
#define m_calloc_dma(s, n)  _m_calloc_dma(np, s, n)
#define m_free_dma(p, s, n)  _m_free_dma(np, p, s, n)
#define _vtobus(np, p)   __vtobus(np->dev, p)
#define vtobus(p)   _vtobus(np, p)

/*
 *  Deal with DMA mapping/unmapping.
 */


static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd)
{
 struct ncr_cmd_priv *cmd_priv = scsi_cmd_priv(cmd);

 switch(cmd_priv->data_mapped) {
 case 2:
  scsi_dma_unmap(cmd);
  break;
 }
 cmd_priv->data_mapped = 0;
}

static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
{
 struct ncr_cmd_priv *cmd_priv = scsi_cmd_priv(cmd);
 int use_sg;

 use_sg = scsi_dma_map(cmd);
 if (!use_sg)
  return 0;

 cmd_priv->data_mapped = 2;
 cmd_priv->data_mapping = use_sg;

 return use_sg;
}

#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd)
#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd)

/*==========================================================
**
** Driver setup.
**
** This structure is initialized from linux config 
** options. It can be overridden at boot-up by the boot 
** command line.
**
**==========================================================
*/

static struct ncr_driver_setup
 driver_setup   = SCSI_NCR_DRIVER_SETUP;

#ifndef MODULE
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
static struct ncr_driver_setup
 driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
#endif
#endif /* !MODULE */

#define initverbose (driver_setup.verbose)
#define bootverbose (np->verbose)


/*===================================================================
**
** Driver setup from the boot command line
**
**===================================================================
*/


#ifdef MODULE
#define ARG_SEP ' '
#else
#define ARG_SEP ','
#endif

#define OPT_TAGS  1
#define OPT_MASTER_PARITY 2
#define OPT_SCSI_PARITY  3
#define OPT_DISCONNECTION 4
#define OPT_SPECIAL_FEATURES 5
#define OPT_UNUSED_1  6
#define OPT_FORCE_SYNC_NEGO 7
#define OPT_REVERSE_PROBE 8
#define OPT_DEFAULT_SYNC 9
#define OPT_VERBOSE  10
#define OPT_DEBUG  11
#define OPT_BURST_MAX  12
#define OPT_LED_PIN  13
#define OPT_MAX_WIDE  14
#define OPT_SETTLE_DELAY 15
#define OPT_DIFF_SUPPORT 16
#define OPT_IRQM  17
#define OPT_PCI_FIX_UP  18
#define OPT_BUS_CHECK  19
#define OPT_OPTIMIZE  20
#define OPT_RECOVERY  21
#define OPT_SAFE_SETUP  22
#define OPT_USE_NVRAM  23
#define OPT_EXCLUDE  24
#define OPT_HOST_ID  25

#ifdef SCSI_NCR_IARB_SUPPORT
#define OPT_IARB  26
#endif

#ifdef MODULE
#define ARG_SEP ' '
#else
#define ARG_SEP ','
#endif

#ifndef MODULE
static char setup_token[] __initdata = 
 "tags:"   "mpar:"
 "spar:"   "disc:"
 "specf:"  "ultra:"
 "fsn:"    "revprob:"
 "sync:"   "verb:"
 "debug:"  "burst:"
 "led:"    "wide:"
 "settle:" "diff:"
 "irqm:"   "pcifix:"
 "buschk:" "optim:"
 "recovery:"
 "safe:"   "nvram:"
 "excl:"   "hostid:"
#ifdef SCSI_NCR_IARB_SUPPORT
 "iarb:"
#endif
 ; /* DONNOT REMOVE THIS ';' */

static int __init get_setup_token(char *p)
{
 char *cur = setup_token;
 char *pc;
 int i = 0;

 while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
  ++pc;
  ++i;
  if (!strncmp(p, cur, pc - cur))
   return i;
  cur = pc;
 }
 return 0;
}

static int __init sym53c8xx__setup(char *str)
{
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 char *cur = str;
 char *pc, *pv;
 int i, val, c;
 int xi = 0;

 while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
  char *pe;

  val = 0;
  pv = pc;
  c = *++pv;

  if (c == 'n')
   val = 0;
  else if (c == 'y')
   val = 1;
  else
   val = (int) simple_strtoul(pv, &pe, 0);

  switch (get_setup_token(cur)) {
  case OPT_TAGS:
   driver_setup.default_tags = val;
   if (pe && *pe == '/') {
    i = 0;
    while (*pe && *pe != ARG_SEP && 
     i < sizeof(driver_setup.tag_ctrl)-1) {
     driver_setup.tag_ctrl[i++] = *pe++;
    }
    driver_setup.tag_ctrl[i] = '\0';
   }
   break;
  case OPT_MASTER_PARITY:
   driver_setup.master_parity = val;
   break;
  case OPT_SCSI_PARITY:
   driver_setup.scsi_parity = val;
   break;
  case OPT_DISCONNECTION:
   driver_setup.disconnection = val;
   break;
  case OPT_SPECIAL_FEATURES:
   driver_setup.special_features = val;
   break;
  case OPT_FORCE_SYNC_NEGO:
   driver_setup.force_sync_nego = val;
   break;
  case OPT_REVERSE_PROBE:
   driver_setup.reverse_probe = val;
   break;
  case OPT_DEFAULT_SYNC:
   driver_setup.default_sync = val;
   break;
  case OPT_VERBOSE:
   driver_setup.verbose = val;
   break;
  case OPT_DEBUG:
   driver_setup.debug = val;
   break;
  case OPT_BURST_MAX:
   driver_setup.burst_max = val;
   break;
  case OPT_LED_PIN:
   driver_setup.led_pin = val;
   break;
  case OPT_MAX_WIDE:
   driver_setup.max_wide = val? 1:0;
   break;
  case OPT_SETTLE_DELAY:
   driver_setup.settle_delay = val;
   break;
  case OPT_DIFF_SUPPORT:
   driver_setup.diff_support = val;
   break;
  case OPT_IRQM:
   driver_setup.irqm = val;
   break;
  case OPT_PCI_FIX_UP:
   driver_setup.pci_fix_up = val;
   break;
  case OPT_BUS_CHECK:
   driver_setup.bus_check = val;
   break;
  case OPT_OPTIMIZE:
   driver_setup.optimize = val;
   break;
  case OPT_RECOVERY:
   driver_setup.recovery = val;
   break;
  case OPT_USE_NVRAM:
   driver_setup.use_nvram = val;
   break;
  case OPT_SAFE_SETUP:
   memcpy(&driver_setup, &driver_safe_setup,
    sizeof(driver_setup));
   break;
  case OPT_EXCLUDE:
   if (xi < SCSI_NCR_MAX_EXCLUDES)
    driver_setup.excludes[xi++] = val;
   break;
  case OPT_HOST_ID:
   driver_setup.host_id = val;
   break;
#ifdef SCSI_NCR_IARB_SUPPORT
  case OPT_IARB:
   driver_setup.iarb = val;
   break;
#endif
  default:
   printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
   break;
  }

  if ((cur = strchr(cur, ARG_SEP)) != NULL)
   ++cur;
 }
#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
 return 1;
}
#endif /* !MODULE */

/*===================================================================
**
** Get device queue depth from boot command line.
**
**===================================================================
*/

#define DEF_DEPTH (driver_setup.default_tags)
#define ALL_TARGETS -2
#define NO_TARGET -1
#define ALL_LUNS -2
#define NO_LUN  -1

static int 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.
**
**==========================================================
*/

 
#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 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.
*/


#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)

/*
** Other definitions
*/


#define initverbose (driver_setup.verbose)
#define bootverbose (np->verbose)

/*==========================================================
**
** 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_INTFLY  (18)
#define SIR_MAX   (18)

/*==========================================================
**
** 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)

/*==========================================================
**
** Misc.
**
**==========================================================
*/


#define CCB_MAGIC (0xf2691ad2)

/*==========================================================
**
** Declaration of structs.
**
**==========================================================
*/


static struct scsi_transport_template *ncr53c8xx_transport_template = NULL;

struct tcb;
struct lcb;
struct ccb;
struct ncb;
struct script;

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 */
 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;

 /*----------------------------------------------------------------
** negotiation of wide and synch transfer and device quirks.
**----------------------------------------------------------------
*/

#ifdef SCSI_NCR_BIG_ENDIAN
/*0*/ u16 period;
/*2*/ u_char sval;
/*3*/ u_char minsync;
/*0*/ u_char wval;
/*1*/ u_char widedone;
/*2*/ u_char quirks;
/*3*/ u_char maxoffs;
#else
/*0*/ u_char minsync;
/*1*/ u_char sval;
/*2*/ u16 period;
/*0*/ u_char maxoffs;
/*1*/ u_char quirks;
/*2*/ u_char widedone;
/*3*/ u_char wval;
#endif

 /* 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
*/


/*
** 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)
*/

#ifdef SCSI_NCR_BIG_ENDIAN
#define  actualquirks  phys.header.status[3]
#define  host_status   phys.header.status[2]
#define  scsi_status   phys.header.status[1]
#define  parity_status phys.header.status[0]
#else
#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]
#endif

/*
** 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.
**
**----------------------------------------------------------
*/


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.
**----------------------------------------------------------------
*/

 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 */
};

#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.
**----------------------------------------------------------------
*/

 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 */
 unsigned long paddr;  /*  chip's IO registers. */
 unsigned long 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  */
};

#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!
**
**----------------------------------------------------------
*/


/*
** 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.
*/


#ifdef CONFIG_NCR53C8XX_PREFETCH
#define PREFETCH_FLUSH_CNT 2
#define PREFETCH_FLUSH  SCR_CALL, PADDRH (wait_dma),
#else
#define PREFETCH_FLUSH_CNT 0
#define PREFETCH_FLUSH
#endif

/*
** 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 + PREFETCH_FLUSH_CNT];
 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 + PREFETCH_FLUSH_CNT];
 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 [ 10];
 ncrcmd msg_out  [  9];
 ncrcmd msg_out_done [  7];
 ncrcmd  idle  [  2];
 ncrcmd reselect [  8];
 ncrcmd reselected [  8];
 ncrcmd resel_dsa [  6 + PREFETCH_FLUSH_CNT];
 ncrcmd loadpos1 [  4];
 ncrcmd  resel_lun [  6];
 ncrcmd resel_tag [  6];
 ncrcmd jump_to_nexus [  4 + PREFETCH_FLUSH_CNT];
 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 + PREFETCH_FLUSH_CNT];
 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 + PREFETCH_FLUSH_CNT];
 ncrcmd start_ram0 [  4];
 ncrcmd sto_restart [  5];
 ncrcmd wait_dma [  2];
 ncrcmd snooptest [  9];
 ncrcmd snoopend [  2];
};

/*==========================================================
**
**
**      Function headers.
**
**
**==========================================================
*/


static void ncr_alloc_ccb (struct ncb *np, u_char tn, u_char ln);
static void ncr_complete (struct ncb *np, struct ccb *cp);
static void ncr_exception (struct ncb *np);
static void ncr_free_ccb (struct ncb *np, struct ccb *cp);
static void ncr_init_ccb (struct ncb *np, struct ccb *cp);
static void ncr_init_tcb (struct ncb *np, u_char tn);
static struct lcb * ncr_alloc_lcb (struct ncb *np, u_char tn, u_char ln);
static struct lcb * ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev);
static void ncr_getclock (struct ncb *np, int mult);
static void ncr_selectclock (struct ncb *np, u_char scntl3);
static struct ccb *ncr_get_ccb (struct ncb *np, struct scsi_cmnd *cmd);
static void ncr_chip_reset (struct ncb *np, int delay);
static void ncr_init (struct ncb *np, int reset, char * msg, u_long code);
static int ncr_int_sbmc (struct ncb *np);
static int ncr_int_par (struct ncb *np);
static void ncr_int_ma (struct ncb *np);
static void ncr_int_sir (struct ncb *np);
static  void    ncr_int_sto     (struct ncb *np);
static void ncr_negotiate (struct ncb* np, struct tcb* tp);
static int ncr_prepare_nego(struct ncb *np, struct ccb *cp, u_char *msgptr);

static void ncr_script_copy_and_bind
    (struct ncb *np, ncrcmd *src, ncrcmd *dst, int len);
static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
static int ncr_scatter (struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd);
static void ncr_getsync (struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p);
static void ncr_setsync (struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer);
static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev);
static void ncr_setwide (struct ncb *np, struct ccb *cp, u_char wide, u_char ack);
static int ncr_snooptest (struct ncb *np);
static void ncr_timeout (struct ncb *np);
static  void    ncr_wakeup      (struct ncb *np, u_long code);
static  void    ncr_wakeup_done (struct ncb *np);
static void ncr_start_next_ccb (struct ncb *np, struct lcb * lp, int maxn);
static void ncr_put_start_queue(struct ncb *np, struct ccb *cp);

static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd);
static void process_waiting_list(struct ncb *np, int sts);

#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 (struct ncb *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
#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)))


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 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),

}/*-------------------------< 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 (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
C=91 H=94 G=92

¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.