sym53c8xx.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:368k
- /******************************************************************************
- ** High Performance device driver for the Symbios 53C896 controller.
- **
- ** Copyright (C) 1998-2001 Gerard Roudier <groudier@free.fr>
- **
- ** This driver also supports all the Symbios 53C8XX controller family,
- ** except 53C810 revisions < 16, 53C825 revisions < 16 and all
- ** revisions of 53C815 controllers.
- **
- ** This driver is based on the Linux port of the FreeBSD ncr driver.
- **
- ** Copyright (C) 1994 Wolfgang Stanglmeier
- **
- **-----------------------------------------------------------------------------
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- **
- **-----------------------------------------------------------------------------
- **
- ** The Linux port of the FreeBSD ncr driver has been achieved in
- ** november 1995 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>
- **
- **-----------------------------------------------------------------------------
- **
- ** Major contributions:
- ** --------------------
- **
- ** NVRAM detection and reading.
- ** Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
- **
- *******************************************************************************
- */
- /*
- ** Supported SCSI features:
- ** Synchronous data transfers
- ** Wide16 SCSI BUS
- ** Disconnection/Reselection
- ** Tagged command queuing
- ** SCSI Parity checking
- **
- ** Supported NCR/SYMBIOS chips:
- ** 53C810A (8 bits, Fast 10, no rom BIOS)
- ** 53C825A (Wide, Fast 10, on-board rom BIOS)
- ** 53C860 (8 bits, Fast 20, no rom BIOS)
- ** 53C875 (Wide, Fast 20, on-board rom BIOS)
- ** 53C876 (Wide, Fast 20 Dual, on-board rom BIOS)
- ** 53C895 (Wide, Fast 40, on-board rom BIOS)
- ** 53C895A (Wide, Fast 40, on-board rom BIOS)
- ** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS)
- ** 53C897 (Wide, Fast 40 Dual, on-board rom BIOS)
- ** 53C1510D (Wide, Fast 40 Dual, on-board rom BIOS)
- ** 53C1010 (Wide, Fast 80 Dual, on-board rom BIOS)
- ** 53C1010_66(Wide, Fast 80 Dual, on-board rom BIOS, 33/66MHz PCI)
- **
- ** Other features:
- ** Memory mapped IO
- ** Module
- ** Shared IRQ
- */
- /*
- ** Name and version of the driver
- */
- #define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3c-20010512"
- #define SCSI_NCR_DEBUG_FLAGS (0)
- #define NAME53C "sym53c"
- #define NAME53C8XX "sym53c8xx"
- /*==========================================================
- **
- ** Include files
- **
- **==========================================================
- */
- #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
- #include <linux/module.h>
- #include <asm/dma.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
- #include <linux/spinlock.h>
- #elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
- #include <asm/spinlock.h>
- #endif
- #include <linux/delay.h>
- #include <linux/signal.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/pci.h>
- #include <linux/string.h>
- #include <linux/mm.h>
- #include <linux/ioport.h>
- #include <linux/time.h>
- #include <linux/timer.h>
- #include <linux/stat.h>
- #include <linux/version.h>
- #include <linux/blk.h>
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
- #include <linux/init.h>
- #endif
- #ifndef __init
- #define __init
- #endif
- #ifndef __initdata
- #define __initdata
- #endif
- #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
- #include <linux/bios32.h>
- #endif
- #include "scsi.h"
- #include "hosts.h"
- #include "constants.h"
- #include "sd.h"
- #include <linux/types.h>
- /*
- ** Define BITS_PER_LONG for earlier linux versions.
- */
- #ifndef BITS_PER_LONG
- #if (~0UL) == 0xffffffffUL
- #define BITS_PER_LONG 32
- #else
- #define BITS_PER_LONG 64
- #endif
- #endif
- /*
- ** Define the BSD style u_int32 and u_int64 type.
- ** Are in fact u_int32_t and u_int64_t :-)
- */
- typedef u32 u_int32;
- typedef u64 u_int64;
- #include "sym53c8xx.h"
- /*
- ** Donnot compile integrity checking code for Linux-2.3.0
- ** and above since SCSI data structures are not ready yet.
- */
- /* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */
- #if 0
- #define SCSI_NCR_INTEGRITY_CHECKING
- #endif
- #define MIN(a,b) (((a) < (b)) ? (a) : (b))
- #define MAX(a,b) (((a) > (b)) ? (a) : (b))
- /*
- ** Hmmm... What complex some PCI-HOST bridges actually are,
- ** despite the fact that the PCI specifications are looking
- ** so smart and simple! ;-)
- */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47)
- #define SCSI_NCR_DYNAMIC_DMA_MAPPING
- #endif
- /*==========================================================
- **
- ** A la VMS/CAM-3 queue management.
- ** Implemented from linux list management.
- **
- **==========================================================
- */
- typedef struct xpt_quehead {
- struct xpt_quehead *flink; /* Forward pointer */
- struct xpt_quehead *blink; /* Backward pointer */
- } XPT_QUEHEAD;
- #define xpt_que_init(ptr) do {
- (ptr)->flink = (ptr); (ptr)->blink = (ptr);
- } while (0)
- static inline void __xpt_que_add(struct xpt_quehead * new,
- struct xpt_quehead * blink,
- struct xpt_quehead * flink)
- {
- flink->blink = new;
- new->flink = flink;
- new->blink = blink;
- blink->flink = new;
- }
- static inline void __xpt_que_del(struct xpt_quehead * blink,
- struct xpt_quehead * flink)
- {
- flink->blink = blink;
- blink->flink = flink;
- }
- static inline int xpt_que_empty(struct xpt_quehead *head)
- {
- return head->flink == head;
- }
- static inline void xpt_que_splice(struct xpt_quehead *list,
- struct xpt_quehead *head)
- {
- struct xpt_quehead *first = list->flink;
- if (first != list) {
- struct xpt_quehead *last = list->blink;
- struct xpt_quehead *at = head->flink;
- first->blink = head;
- head->flink = first;
- last->flink = at;
- at->blink = last;
- }
- }
- #define xpt_que_entry(ptr, type, member)
- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
- #define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink)
- #define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink)
- #define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink)
- static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
- {
- struct xpt_quehead *elem = head->flink;
- if (elem != head)
- __xpt_que_del(head, elem->flink);
- else
- elem = 0;
- return elem;
- }
- #define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head)
- static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
- {
- struct xpt_quehead *elem = head->blink;
- if (elem != head)
- __xpt_que_del(elem->blink, head);
- else
- elem = 0;
- return elem;
- }
- /*==========================================================
- **
- ** 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 devices that support tags.
- */
- #ifndef SCSI_NCR_MAX_TAGS
- #define SCSI_NCR_MAX_TAGS (8)
- #endif
- /*
- ** TAGS are actually unlimited (256 tags/lun).
- ** But Linux only supports 255. :)
- */
- #if SCSI_NCR_MAX_TAGS > 255
- #define MAX_TAGS 255
- #else
- #define MAX_TAGS SCSI_NCR_MAX_TAGS
- #endif
- /*
- ** Since the ncr chips only have a 8 bit ALU, we try to be clever
- ** about offset calculation in the TASK TABLE per LUN that is an
- ** array of DWORDS = 4 bytes.
- */
- #if MAX_TAGS > (512/4)
- #define MAX_TASKS (1024/4)
- #elif MAX_TAGS > (256/4)
- #define MAX_TASKS (512/4)
- #else
- #define MAX_TASKS (256/4)
- #endif
- /*
- ** This one means 'NO TAG for this job'
- */
- #define NO_TAG (256)
- /*
- ** 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 64
- #else
- #define MAX_LUN (1)
- #endif
- /*
- ** Asynchronous pre-scaler (ns). Shall be 40 for
- ** the SCSI timings to be compliant.
- */
-
- #ifndef SCSI_NCR_MIN_ASYNC
- #define SCSI_NCR_MIN_ASYNC (40)
- #endif
- /*
- ** The maximum number of jobs scheduled for starting.
- ** We allocate 4 entries more than the value we announce
- ** to the SCSI upper layer. Guess why ! :-)
- */
- #ifdef SCSI_NCR_CAN_QUEUE
- #define MAX_START (SCSI_NCR_CAN_QUEUE + 4)
- #else
- #define MAX_START (MAX_TARGET + 7 * MAX_TAGS)
- #endif
- /*
- ** We donnot want to allocate more than 1 PAGE for the
- ** the start queue and the done queue. We hard-code entry
- ** size to 8 in order to let cpp do the checking.
- ** Allows 512-4=508 pending IOs for i386 but Linux seems for
- ** now not able to provide the driver with this amount of IOs.
- */
- #if MAX_START > PAGE_SIZE/8
- #undef MAX_START
- #define MAX_START (PAGE_SIZE/8)
- #endif
- /*
- ** The maximum number of segments a transfer is split into.
- ** We support up to 127 segments for both read and write.
- */
- #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
- #define SCR_SG_SIZE (2)
- /*
- ** other
- */
- #define NCR_SNOOP_TIMEOUT (1000000)
- /*==========================================================
- **
- ** Miscallaneous BSDish defines.
- **
- **==========================================================
- */
- #define u_char unsigned char
- #define u_short unsigned short
- #define u_int unsigned int
- #define u_long unsigned long
- #ifndef bcopy
- #define bcopy(s, d, n) memcpy((d), (s), (n))
- #endif
- #ifndef bzero
- #define bzero(d, n) memset((d), 0, (n))
- #endif
-
- #ifndef offsetof
- #define offsetof(t, m) ((size_t) (&((t *)0)->m))
- #endif
- /*
- ** Simple Wrapper to kernel PCI bus interface.
- **
- ** This wrapper allows to get rid of old kernel PCI interface
- ** and still allows to preserve linux-2.0 compatibilty.
- ** In fact, it is mostly an incomplete emulation of the new
- ** PCI code for pre-2.2 kernels. When kernel-2.0 support
- ** will be dropped, we will just have to remove most of this
- ** code.
- */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0)
- typedef struct pci_dev *pcidev_t;
- #define PCIDEV_NULL (0)
- #define PciBusNumber(d) (d)->bus->number
- #define PciDeviceFn(d) (d)->devfn
- #define PciVendorId(d) (d)->vendor
- #define PciDeviceId(d) (d)->device
- #define PciIrqLine(d) (d)->irq
- static u_long __init
- pci_get_base_cookie(struct pci_dev *pdev, int index)
- {
- u_long base;
- #if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
- base = pdev->resource[index].start;
- #else
- base = pdev->base_address[index];
- #if BITS_PER_LONG > 32
- if ((base & 0x7) == 0x4)
- *base |= (((u_long)pdev->base_address[++index]) << 32);
- #endif
- #endif
- return (base & ~0x7ul);
- }
- static int __init
- pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
- {
- u32 tmp;
- #define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
- pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
- *base = tmp;
- ++index;
- if ((tmp & 0x7) == 0x4) {
- #if BITS_PER_LONG > 32
- pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
- *base |= (((u_long)tmp) << 32);
- #endif
- ++index;
- }
- return index;
- #undef PCI_BAR_OFFSET
- }
- #else /* Incomplete emulation of current PCI code for pre-2.2 kernels */
- typedef unsigned int pcidev_t;
- #define PCIDEV_NULL (~0u)
- #define PciBusNumber(d) ((d)>>8)
- #define PciDeviceFn(d) ((d)&0xff)
- #define __PciDev(busn, devfn) (((busn)<<8)+(devfn))
- #define pci_present pcibios_present
- #define pci_read_config_byte(d, w, v)
- pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
- #define pci_read_config_word(d, w, v)
- pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
- #define pci_read_config_dword(d, w, v)
- pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
- #define pci_write_config_byte(d, w, v)
- pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
- #define pci_write_config_word(d, w, v)
- pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
- #define pci_write_config_dword(d, w, v)
- pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
- static pcidev_t __init
- pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev)
- {
- static unsigned short pci_index;
- int retv;
- unsigned char bus_number, device_fn;
- if (prev == PCIDEV_NULL)
- pci_index = 0;
- else
- ++pci_index;
- retv = pcibios_find_device (vendor, device, pci_index,
- &bus_number, &device_fn);
- return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn);
- }
- static u_short __init PciVendorId(pcidev_t dev)
- {
- u_short vendor_id;
- pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
- return vendor_id;
- }
- static u_short __init PciDeviceId(pcidev_t dev)
- {
- u_short device_id;
- pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
- return device_id;
- }
- static u_int __init PciIrqLine(pcidev_t dev)
- {
- u_char irq;
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
- return irq;
- }
- static int __init
- pci_get_base_address(pcidev_t dev, int offset, u_long *base)
- {
- u_int32 tmp;
-
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
- *base = tmp;
- offset += sizeof(u_int32);
- if ((tmp & 0x7) == 0x4) {
- #if BITS_PER_LONG > 32
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
- *base |= (((u_long)tmp) << 32);
- #endif
- offset += sizeof(u_int32);
- }
- return offset;
- }
- static u_long __init
- pci_get_base_cookie(struct pci_dev *pdev, int offset)
- {
- u_long base;
- (void) pci_get_base_address(dev, offset, &base);
- return base;
- }
- #endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
- /* Does not make sense in earlier kernels */
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
- #define pci_enable_device(pdev) (0)
- #endif
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
- #define scsi_set_pci_device(inst, pdev) (0)
- #endif
- /*==========================================================
- **
- ** 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_IC (0x0800)
- /*
- ** 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
- /*
- ** SMP threading.
- **
- ** Assuming that SMP systems are generally high end systems and may
- ** use several SCSI adapters, we are using one lock per controller
- ** instead of some global one. For the moment (linux-2.1.95), driver's
- ** entry points are called with the 'io_request_lock' lock held, so:
- ** - We are uselessly loosing a couple of micro-seconds to lock the
- ** controller data structure.
- ** - But the driver is not broken by design for SMP and so can be
- ** more resistant to bugs or bad changes in the IO sub-system code.
- ** - A small advantage could be that the interrupt code is grained as
- ** wished (e.g.: threaded by controller).
- */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
- spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED;
- #define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags)
- #define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags)
- #define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock);
- #define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags)
- #define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags)
- #define NCR_LOCK_SCSI_DONE(np, flags)
- spin_lock_irqsave(&io_request_lock, flags)
- #define NCR_UNLOCK_SCSI_DONE(np, flags)
- spin_unlock_irqrestore(&io_request_lock, flags)
- #else
- #define NCR_LOCK_DRIVER(flags) do { save_flags(flags); cli(); } while (0)
- #define NCR_UNLOCK_DRIVER(flags) do { restore_flags(flags); } while (0)
- #define NCR_INIT_LOCK_NCB(np) do { } while (0)
- #define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0)
- #define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0)
- #define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0)
- #define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0)
- #endif
- /*
- ** Memory mapped IO
- **
- ** Since linux-2.1, we must use ioremap() to map the io memory space.
- ** iounmap() to unmap it. That allows portability.
- ** Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater
- ** than the highest physical memory address to kernel virtual pages with
- ** vremap() / vfree(). That was not portable but worked with i386
- ** architecture.
- */
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
- #define ioremap vremap
- #define iounmap vfree
- #endif
- #ifdef __sparc__
- # include <asm/irq.h>
- # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
- #elif defined(__alpha__)
- # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
- #else /* others */
- # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
- #endif
- #ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
- static u_long __init remap_pci_mem(u_long base, u_long size)
- {
- u_long page_base = ((u_long) base) & PAGE_MASK;
- u_long page_offs = ((u_long) base) - page_base;
- u_long page_remapped = (u_long) ioremap(page_base, page_offs+size);
- return page_remapped? (page_remapped + page_offs) : 0UL;
- }
- static void __init unmap_pci_mem(u_long vaddr, u_long size)
- {
- if (vaddr)
- iounmap((void *) (vaddr & PAGE_MASK));
- }
- #endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
- /*
- ** Insert a delay in micro-seconds and milli-seconds.
- ** -------------------------------------------------
- ** Under Linux, udelay() is restricted to delay < 1 milli-second.
- ** In fact, it generally works for up to 1 second delay.
- ** Since 2.1.105, the mdelay() function is provided for delays
- ** in milli-seconds.
- ** Under 2.0 kernels, udelay() is an inline function that is very
- ** inaccurate on Pentium processors.
- */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
- #define UDELAY udelay
- #define MDELAY mdelay
- #else
- static void UDELAY(long us) { udelay(us); }
- static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
- #endif
- /*
- ** 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 astraction, btw).
- */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
- #define __GetFreePages(flags, order) __get_free_pages(flags, order)
- #else
- #define __GetFreePages(flags, order) __get_free_pages(flags, order, 0)
- #endif
- #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 pcidev_t m_bush_t; /* Something that addresses DMAable */
- typedef struct m_link { /* Link between free memory chunks */
- struct m_link *next;
- } m_link_s;
- #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
- 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)
- #endif
- typedef struct m_pool { /* Memory pool of a given kind */
- #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
- m_bush_t bush;
- m_addr_t (*getp)(struct m_pool *);
- void (*freep)(struct m_pool *, m_addr_t);
- #define M_GETP() mp->getp(mp)
- #define M_FREEP(p) mp->freep(mp, p)
- #define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
- #define FreePages(p) free_pages(p, MEMO_PAGE_ORDER)
- int nump;
- m_vtob_s *(vtob[VTOB_HASH_SIZE]);
- struct m_pool *next;
- #else
- #define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
- #define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER)
- #endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
- 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 0;
- 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 *) M_GETP();
- if (h[j].next)
- h[j].next->next = 0;
- 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 = 0;
- }
- }
- #ifdef DEBUG
- printk("___m_alloc(%d) = %pn", 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)) {
- M_FREEP(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 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)
- bzero(p, 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.
- */
- #ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
- static m_pool_s mp0;
- #else
- static m_addr_t ___mp0_getp(m_pool_s *mp)
- {
- m_addr_t m = GetPages();
- if (m)
- ++mp->nump;
- return m;
- }
- static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
- {
- FreePages(m);
- --mp->nump;
- }
- static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep};
- #endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
- static void *m_calloc(int size, char *name)
- {
- u_long flags;
- void *m;
- NCR_LOCK_DRIVER(flags);
- m = __m_calloc(&mp0, size, name);
- NCR_UNLOCK_DRIVER(flags);
- return m;
- }
- static void m_free(void *ptr, int size, char *name)
- {
- u_long flags;
- NCR_LOCK_DRIVER(flags);
- __m_free(&mp0, ptr, size, name);
- NCR_UNLOCK_DRIVER(flags);
- }
- /*
- * DMAable pools.
- */
- #ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
- /* Without pci bus iommu support, all the memory is assumed DMAable */
- #define __m_calloc_dma(b, s, n) m_calloc(s, n)
- #define __m_free_dma(b, p, s, n) m_free(p, s, n)
- #define __vtobus(b, p) virt_to_bus(p)
- #else
- /*
- * 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) pci_alloc_consistent(mp->bush,
- PAGE_SIZE<<MEMO_PAGE_ORDER,
- &daddr);
- 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;
- }
- else
- __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;
- pci_free_consistent(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) {
- bzero(mp, 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 = 0;
- NCR_LOCK_DRIVER(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);
- NCR_UNLOCK_DRIVER(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;
- NCR_LOCK_DRIVER(flags);
- mp = ___get_dma_pool(bush);
- if (mp)
- __m_free(mp, m, size, name);
- if (mp && !mp->nump)
- ___del_dma_pool(mp);
- NCR_UNLOCK_DRIVER(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 = 0;
- m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
- NCR_LOCK_DRIVER(flags);
- mp = ___get_dma_pool(bush);
- if (mp) {
- vp = mp->vtob[hc];
- while (vp && (m_addr_t) vp->vaddr != a)
- vp = vp->next;
- }
- NCR_UNLOCK_DRIVER(flags);
- return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
- }
- #endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
- #define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n)
- #define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, 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->pdev, p)
- #define vtobus(p) _vtobus(np, p)
- /*
- * Deal with DMA mapping/unmapping.
- */
- #ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
- /* Linux versions prior to pci bus iommu kernel interface */
- #define __unmap_scsi_data(pdev, cmd) do {; } while (0)
- #define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer))
- #define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg)
- #define __sync_scsi_data(pdev, cmd) do {; } while (0)
- #define scsi_sg_dma_address(sc) vtobus((sc)->address)
- #define scsi_sg_dma_len(sc) ((sc)->length)
- #else
- /* Linux version with pci bus iommu kernel interface */
- /* To keep track of the dma mapping (sg/single) that has been set */
- #define __data_mapped(cmd) (cmd)->SCp.phase
- #define __data_mapping(cmd) (cmd)->SCp.dma_handle
- static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
- {
- int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
- switch(__data_mapped(cmd)) {
- case 2:
- pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
- break;
- case 1:
- pci_unmap_page(pdev, __data_mapping(cmd),
- cmd->request_bufflen, dma_dir);
- break;
- }
- __data_mapped(cmd) = 0;
- }
- static dma_addr_t __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
- {
- dma_addr_t mapping;
- int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
- if (cmd->request_bufflen == 0)
- return 0;
- mapping = pci_map_page(pdev,
- virt_to_page(cmd->request_buffer),
- ((unsigned long)cmd->request_buffer &
- ~PAGE_MASK),
- cmd->request_bufflen, dma_dir);
- __data_mapped(cmd) = 1;
- __data_mapping(cmd) = mapping;
- return mapping;
- }
- static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd)
- {
- int use_sg;
- int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
- if (cmd->use_sg == 0)
- return 0;
- use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
- __data_mapped(cmd) = 2;
- __data_mapping(cmd) = use_sg;
- return use_sg;
- }
- static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
- {
- int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
- switch(__data_mapped(cmd)) {
- case 2:
- pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
- break;
- case 1:
- pci_dma_sync_single(pdev, __data_mapping(cmd),
- cmd->request_bufflen, dma_dir);
- break;
- }
- }
- #define scsi_sg_dma_address(sc) sg_dma_address(sc)
- #define scsi_sg_dma_len(sc) sg_dma_len(sc)
- #endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
- #define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd)
- #define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd)
- #define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd)
- #define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd)
- /*
- * Print out some buffer.
- */
- static void ncr_print_hex(u_char *p, int n)
- {
- while (n-- > 0)
- printk (" %x", *p++);
- }
- static void ncr_printl_hex(char *label, u_char *p, int n)
- {
- printk("%s", label);
- ncr_print_hex(p, n);
- printk (".n");
- }
- /*
- ** Transfer direction
- **
- ** Until some linux kernel version near 2.3.40, low-level scsi
- ** drivers were not told about data transfer direction.
- ** We check the existence of this feature that has been expected
- ** for a _long_ time by all SCSI driver developers by just
- ** testing against the definition of SCSI_DATA_UNKNOWN. Indeed
- ** this is a hack, but testing against a kernel version would
- ** have been a shame. ;-)
- */
- #ifdef SCSI_DATA_UNKNOWN
- #define scsi_data_direction(cmd) (cmd->sc_data_direction)
- #else
- #define SCSI_DATA_UNKNOWN 0
- #define SCSI_DATA_WRITE 1
- #define SCSI_DATA_READ 2
- #define SCSI_DATA_NONE 3
- static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd)
- {
- int direction;
- switch((int) cmd->cmnd[0]) {
- case 0x08: /* READ(6) 08 */
- case 0x28: /* READ(10) 28 */
- case 0xA8: /* READ(12) A8 */
- direction = SCSI_DATA_READ;
- break;
- case 0x0A: /* WRITE(6) 0A */
- case 0x2A: /* WRITE(10) 2A */
- case 0xAA: /* WRITE(12) AA */
- direction = SCSI_DATA_WRITE;
- break;
- default:
- direction = SCSI_DATA_UNKNOWN;
- break;
- }
- return direction;
- }
- #endif /* SCSI_DATA_UNKNOWN */
- /*
- ** Head of list of NCR boards
- **
- ** For kernel version < 1.3.70, host is retrieved by its irq level.
- ** For later kernels, the internal host control block address
- ** (struct ncb) is used as device id parameter of the irq stuff.
- */
- static struct Scsi_Host *first_host = NULL;
- /*
- ** /proc directory entry and proc_info function
- */
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
- static struct proc_dir_entry proc_scsi_sym53c8xx = {
- PROC_SCSI_SYM53C8XX, 9, NAME53C8XX,
- S_IFDIR | S_IRUGO | S_IXUGO, 2
- };
- #endif
- #ifdef SCSI_NCR_PROC_INFO_SUPPORT
- static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
- int length, int hostno, int func);
- #endif
- /*
- ** 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;
- #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
- static struct ncr_driver_setup
- driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
- # ifdef MODULE
- char *sym53c8xx = 0; /* command line passed by insmod */
- # if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
- MODULE_PARM(sym53c8xx, "s");
- # endif
- # endif
- #endif
- /*
- ** Other Linux definitions
- */
- #define SetScsiResult(cmd, h_sts, s_sts)
- cmd->result = (((h_sts) << 16) + ((s_sts) & 0x7f))
- /* We may have to remind our amnesiac SCSI layer of the reason of the abort */
- #if 0
- #define SetScsiAbortResult(cmd)
- SetScsiResult(
- cmd,
- (cmd)->abort_reason == DID_TIME_OUT ? DID_TIME_OUT : DID_ABORT,
- 0xff)
- #else
- #define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff)
- #endif
- static void sym53c8xx_select_queue_depths(
- struct Scsi_Host *host, struct scsi_device *devlist);
- static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
- static void sym53c8xx_timeout(unsigned long np);
- #define initverbose (driver_setup.verbose)
- #define bootverbose (np->verbose)
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- static u_char Tekram_sync[16] __initdata =
- {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
- #endif /* SCSI_NCR_NVRAM_SUPPORT */
- /*
- ** Structures used by sym53c8xx_detect/sym53c8xx_pci_init to
- ** transmit device configuration to the ncr_attach() function.
- */
- typedef struct {
- int bus;
- u_char device_fn;
- u_long base;
- u_long base_2;
- u_long io_port;
- u_long base_c;
- u_long base_2_c;
- int irq;
- /* port and reg fields to use INB, OUTB macros */
- u_long base_io;
- volatile struct ncr_reg *reg;
- } ncr_slot;
- typedef struct {
- int type;
- #define SCSI_NCR_SYMBIOS_NVRAM (1)
- #define SCSI_NCR_TEKRAM_NVRAM (2)
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- union {
- Symbios_nvram Symbios;
- Tekram_nvram Tekram;
- } data;
- #endif
- } ncr_nvram;
- /*
- ** Structure used by sym53c8xx_detect/sym53c8xx_pci_init
- ** to save data on each detected board for ncr_attach().
- */
- typedef struct {
- pcidev_t pdev;
- ncr_slot slot;
- ncr_chip chip;
- ncr_nvram *nvram;
- u_char host_id;
- #ifdef SCSI_NCR_PQS_PDS_SUPPORT
- u_char pqs_pds;
- #endif
- int attach_done;
- } ncr_device;
- /*==========================================================
- **
- ** assert ()
- **
- **==========================================================
- **
- ** modified copy from 386bsd:/usr/include/sys/assert.h
- **
- **----------------------------------------------------------
- */
- #define assert(expression) {
- if (!(expression)) {
- (void)panic(
- "assertion "%s" failed: file "%s", line %dn",
- #expression,
- __FILE__, __LINE__);
- }
- }
- /*==========================================================
- **
- ** 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 */
- #define DSA_INVALID 0xffffffff
- /*==========================================================
- **
- ** Software Interrupt Codes
- **
- **==========================================================
- */
- #define SIR_BAD_STATUS (1)
- #define SIR_SEL_ATN_NO_MSG_OUT (2)
- #define SIR_MSG_RECEIVED (3)
- #define SIR_MSG_WEIRD (4)
- #define SIR_NEGO_FAILED (5)
- #define SIR_NEGO_PROTO (6)
- #define SIR_SCRIPT_STOPPED (7)
- #define SIR_REJECT_TO_SEND (8)
- #define SIR_SWIDE_OVERRUN (9)
- #define SIR_SODL_UNDERRUN (10)
- #define SIR_RESEL_NO_MSG_IN (11)
- #define SIR_RESEL_NO_IDENTIFY (12)
- #define SIR_RESEL_BAD_LUN (13)
- #define SIR_TARGET_SELECTED (14)
- #define SIR_RESEL_BAD_I_T_L (15)
- #define SIR_RESEL_BAD_I_T_L_Q (16)
- #define SIR_ABORT_SENT (17)
- #define SIR_RESEL_ABORTED (18)
- #define SIR_MSG_OUT_DONE (19)
- #define SIR_AUTO_SENSE_DONE (20)
- #define SIR_DUMMY_INTERRUPT (21)
- #define SIR_DATA_OVERRUN (22)
- #define SIR_BAD_PHASE (23)
- #define SIR_MAX (23)
- /*==========================================================
- **
- ** Extended error bits.
- ** xerr_status field of struct ccb.
- **
- **==========================================================
- */
- #define XE_EXTRA_DATA (1) /* unexpected data phase */
- #define XE_BAD_PHASE (2) /* illegal phase (4/5) */
- #define XE_PARITY_ERR (4) /* unrecovered SCSI parity error */
- #define XE_SODL_UNRUN (1<<3)
- #define XE_SWIDE_OVRUN (1<<4)
- /*==========================================================
- **
- ** Negotiation status.
- ** nego_status field of struct ccb.
- **
- **==========================================================
- */
- #define NS_NOCHANGE (0)
- #define NS_SYNC (1)
- #define NS_WIDE (2)
- #define NS_PPR (4)
- /*==========================================================
- **
- ** "Special features" of targets.
- ** quirks field of struct tcb.
- ** actualquirks field of struct ccb.
- **
- **==========================================================
- */
- #define QUIRK_AUTOSAVE (0x01)
- /*==========================================================
- **
- ** Capability bits in Inquire response byte 7.
- **
- **==========================================================
- */
- #define INQ7_QUEUE (0x02)
- #define INQ7_SYNC (0x10)
- #define INQ7_WIDE16 (0x20)
- /*==========================================================
- **
- ** A CCB hashed table is used to retrieve CCB address
- ** from DSA value.
- **
- **==========================================================
- */
- #define CCB_HASH_SHIFT 8
- #define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT)
- #define CCB_HASH_MASK (CCB_HASH_SIZE-1)
- #define CCB_HASH_CODE(dsa) (((dsa) >> 11) & CCB_HASH_MASK)
- /*==========================================================
- **
- ** Declaration of structs.
- **
- **==========================================================
- */
- struct tcb;
- struct lcb;
- struct ccb;
- struct ncb;
- struct script;
- typedef struct ncb * ncb_p;
- typedef struct tcb * tcb_p;
- typedef struct lcb * lcb_p;
- typedef struct ccb * ccb_p;
- struct link {
- ncrcmd l_cmd;
- ncrcmd l_paddr;
- };
- struct usrcmd {
- u_long target;
- u_long lun;
- u_long data;
- u_long cmd;
- };
- #define UC_SETSYNC 10
- #define UC_SETTAGS 11
- #define UC_SETDEBUG 12
- #define UC_SETORDER 13
- #define UC_SETWIDE 14
- #define UC_SETFLAG 15
- #define UC_SETVERBOSE 17
- #define UC_RESETDEV 18
- #define UC_CLEARDEV 19
- #define UF_TRACE (0x01)
- #define UF_NODISC (0x02)
- #define UF_NOSCAN (0x04)
- /*========================================================================
- **
- ** Declaration of structs: target control block
- **
- **========================================================================
- */
- struct tcb {
- /*----------------------------------------------------------------
- ** LUN tables.
- ** An array of bus addresses is used on reselection by
- ** the SCRIPT.
- **----------------------------------------------------------------
- */
- u_int32 *luntbl; /* lcbs bus address table */
- u_int32 b_luntbl; /* bus address of this table */
- u_int32 b_lun0; /* bus address of lun0 */
- lcb_p l0p; /* lcb of LUN #0 (normal case) */
- #if MAX_LUN > 1
- lcb_p *lmp; /* Other lcb's [1..MAX_LUN] */
- #endif
- /*----------------------------------------------------------------
- ** Target capabilities.
- **----------------------------------------------------------------
- */
- u_char inq_done; /* Target capabilities received */
- u_char inq_byte7; /* Contains these capabilities */
- /*----------------------------------------------------------------
- ** Some flags.
- **----------------------------------------------------------------
- */
- u_char to_reset; /* This target is to be reset */
- /*----------------------------------------------------------------
- ** Pointer to the ccb used for negotiation.
- ** Prevent from starting a negotiation for all queued commands
- ** when tagged command queuing is enabled.
- **----------------------------------------------------------------
- */
- ccb_p nego_cp;
- /*----------------------------------------------------------------
- ** negotiation of wide and synch transfer and device quirks.
- ** sval, wval and uval are read from SCRIPTS and so have alignment
- ** constraints.
- **----------------------------------------------------------------
- */
- /*0*/ u_char uval;
- /*1*/ u_char sval;
- /*2*/ u_char filler2;
- /*3*/ u_char wval;
- u_short period;
- u_char minsync;
- u_char maxoffs;
- u_char quirks;
- u_char widedone;
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- u_char ic_min_sync;
- u_char ic_max_width;
- u_char ic_done;
- #endif
- u_char ic_maximums_set;
- u_char ppr_negotiation;
- /*----------------------------------------------------------------
- ** User settable limits and options.
- ** These limits are read from the NVRAM if present.
- **----------------------------------------------------------------
- */
- u_char usrsync;
- u_char usrwide;
- u_short usrtags;
- u_char usrflag;
- };
- /*========================================================================
- **
- ** Declaration of structs: lun control block
- **
- **========================================================================
- */
- struct lcb {
- /*----------------------------------------------------------------
- ** On reselection, SCRIPTS use this value as a JUMP address
- ** after the IDENTIFY has been successfully received.
- ** This field is set to 'resel_tag' if TCQ is enabled and
- ** to 'resel_notag' if TCQ is disabled.
- ** (Must be at zero due to bad lun handling on reselection)
- **----------------------------------------------------------------
- */
- /*0*/ u_int32 resel_task;
- /*----------------------------------------------------------------
- ** Task table used by the script processor to retrieve the
- ** task corresponding to a reselected nexus. The TAG is used
- ** as offset to determine the corresponding entry.
- ** Each entry contains the associated CCB bus address.
- **----------------------------------------------------------------
- */
- u_int32 tasktbl_0; /* Used if TCQ not enabled */
- u_int32 *tasktbl;
- u_int32 b_tasktbl;
- /*----------------------------------------------------------------
- ** CCB queue management.
- **----------------------------------------------------------------
- */
- XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */
- XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */
- u_short busyccbs; /* CCBs busy for this lun */
- u_short queuedccbs; /* CCBs queued to the controller*/
- u_short queuedepth; /* Queue depth for this lun */
- u_short scdev_depth; /* SCSI device queue depth */
- u_short 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_short ia_tag; /* Tag allocation index */
- u_short if_tag; /* Tag release index */
- u_char *cb_tags; /* Circular tags buffer */
- u_char inq_byte7; /* Store unit CmdQ capability */
- u_char usetags; /* Command queuing is active */
- u_char to_clear; /* User wants to clear all tasks*/
- u_short maxtags; /* Max NR of tags asked by user */
- u_short numtags; /* Current number of tags */
- /*----------------------------------------------------------------
- ** QUEUE FULL and ORDERED tag control.
- **----------------------------------------------------------------
- */
- u_short num_good; /* Nr of GOOD since QUEUE FULL */
- u_short tags_sum[2]; /* Tags sum counters */
- u_char tags_si; /* Current index to tags sum */
- u_long tags_stime; /* Last time we switch tags_sum */
- };
- /*========================================================================
- **
- ** Declaration of structs: actions for a task.
- **
- **========================================================================
- **
- ** It is part of the CCB and is called by the scripts processor to
- ** start or restart the data structure (nexus).
- **
- **------------------------------------------------------------------------
- */
- struct action {
- u_int32 start;
- u_int32 restart;
- };
- /*========================================================================
- **
- ** Declaration of structs: Phase mismatch context.
- **
- **========================================================================
- **
- ** It is part of the CCB and is used as parameters for the DATA
- ** pointer. We need two contexts to handle correctly the SAVED
- ** DATA POINTER.
- **
- **------------------------------------------------------------------------
- */
- struct pm_ctx {
- struct scr_tblmove sg; /* Updated interrupted SG block */
- u_int32 ret; /* SCRIPT return address */
- };
- /*========================================================================
- **
- ** Declaration of structs: global HEADER.
- **
- **========================================================================
- **
- ** In earlier driver versions, this substructure was copied from the
- ** ccb to a global address after selection (or reselection) and copied
- ** back before disconnect. Since we are now using LOAD/STORE DSA
- ** RELATIVE instructions, the script is able to access directly these
- ** fields, and so, this header is no more copied.
- **
- **------------------------------------------------------------------------
- */
- struct head {
- /*----------------------------------------------------------------
- ** Start and restart SCRIPTS addresses (must be at 0).
- **----------------------------------------------------------------
- */
- struct action go;
- /*----------------------------------------------------------------
- ** Saved data pointer.
- ** Points to the position in the script responsible for the
- ** actual transfer of data.
- ** It's written after reception of a SAVE_DATA_POINTER message.
- ** The goalpointer points after the last transfer command.
- **----------------------------------------------------------------
- */
- u_int32 savep;
- u_int32 lastp;
- u_int32 goalp;
- /*----------------------------------------------------------------
- ** Alternate data pointer.
- ** They are copied back to savep/lastp/goalp by the SCRIPTS
- ** when the direction is unknown and the device claims data out.
- **----------------------------------------------------------------
- */
- u_int32 wlastp;
- u_int32 wgoalp;
- /*----------------------------------------------------------------
- ** Status fields.
- **----------------------------------------------------------------
- */
- u_char status[4]; /* host status */
- };
- /*
- ** LUN control block lookup.
- ** We use a direct pointer for LUN #0, and a table of pointers
- ** which is only allocated for devices that support LUN(s) > 0.
- */
- #if MAX_LUN <= 1
- #define ncr_lp(np, tp, lun) (!lun) ? (tp)->l0p : 0
- #else
- #define ncr_lp(np, tp, lun)
- (!lun) ? (tp)->l0p : (tp)->lmp ? (tp)->lmp[(lun)] : 0
- #endif
- /*
- ** The status bytes are used by the host and the script processor.
- **
- ** The 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.
- */
- /*
- ** 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 HF_REG scr3
- #define HF_PRT nc_scr3
- /*
- ** Last four bytes (host)
- */
- #define actualquirks phys.header.status[0]
- #define host_status phys.header.status[1]
- #define scsi_status phys.header.status[2]
- #define host_flags phys.header.status[3]
- /*
- ** Host flags
- */
- #define HF_IN_PM0 1u
- #define HF_IN_PM1 (1u<<1)
- #define HF_ACT_PM (1u<<2)
- #define HF_DP_SAVED (1u<<3)
- #define HF_AUTO_SENSE (1u<<4)
- #define HF_DATA_IN (1u<<5)
- #define HF_PM_TO_C (1u<<6)
- #define HF_EXT_ERR (1u<<7)
- #ifdef SCSI_NCR_IARB_SUPPORT
- #define HF_HINT_IARB (1u<<7)
- #endif
- /*
- ** This one is stolen from QU_REG.:)
- */
- #define HF_DATA_ST (1u<<7)
- /*==========================================================
- **
- ** Declaration of structs: Data structure block
- **
- **==========================================================
- **
- ** During execution of a ccb by the script processor,
- ** the DSA (data structure address) register points
- ** to this substructure of the ccb.
- ** This substructure contains the header with
- ** the script-processor-changable data and
- ** data blocks for the indirect move commands.
- **
- **----------------------------------------------------------
- */
- struct dsb {
- /*
- ** Header.
- */
- struct head header;
- /*
- ** Table data for Script
- */
- struct scr_tblsel select;
- struct scr_tblmove smsg ;
- struct scr_tblmove smsg_ext ;
- struct scr_tblmove cmd ;
- struct scr_tblmove sense ;
- struct scr_tblmove wresid;
- struct scr_tblmove data [MAX_SCATTER];
- /*
- ** Phase mismatch contexts.
- ** We need two to handle correctly the
- ** SAVED DATA POINTER.
- */
- struct pm_ctx pm0;
- struct pm_ctx pm1;
- };
- /*========================================================================
- **
- ** 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.
- **----------------------------------------------------------------
- */
- struct dsb phys;
- /*----------------------------------------------------------------
- ** The general SCSI driver provides a
- ** pointer to a control block.
- **----------------------------------------------------------------
- */
- Scsi_Cmnd *cmd; /* SCSI command */
- u_char cdb_buf[16]; /* Copy of CDB */
- u_char sense_buf[64];
- int data_len; /* Total data length */
- int segments; /* Number of SG segments */
- /*----------------------------------------------------------------
- ** Message areas.
- ** We prepare a message to be sent after selection.
- ** We may use a second one if the command is rescheduled
- ** due to CHECK_CONDITION or QUEUE FULL status.
- ** Contents are IDENTIFY and SIMPLE_TAG.
- ** While negotiating sync or wide transfer,
- ** a SDTR or WDTR message is appended.
- **----------------------------------------------------------------
- */
- u_char scsi_smsg [12];
- u_char scsi_smsg2[12];
- /*----------------------------------------------------------------
- ** Miscellaneous status'.
- **----------------------------------------------------------------
- */
- u_char nego_status; /* Negotiation status */
- u_char xerr_status; /* Extended error flags */
- u_int32 extra_bytes; /* Extraneous bytes transferred */
- /*----------------------------------------------------------------
- ** Saved info for auto-sense
- **----------------------------------------------------------------
- */
- u_char sv_scsi_status;
- u_char sv_xerr_status;
- /*----------------------------------------------------------------
- ** Other fields.
- **----------------------------------------------------------------
- */
- u_long p_ccb; /* BUS address of this CCB */
- u_char sensecmd[6]; /* Sense command */
- u_char to_abort; /* This CCB is to be aborted */
- u_short tag; /* Tag for this transfer */
- /* NO_TAG means no tag */
- u_char tags_si; /* Lun tags sum index (0,1) */
- u_char target;
- u_char lun;
- u_short queued;
- ccb_p link_ccb; /* Host adapter CCB chain */
- ccb_p link_ccbh; /* Host adapter CCB hash chain */
- XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */
- u_int32 startp; /* Initial data pointer */
- u_int32 lastp0; /* Initial 'lastp' */
- int ext_sg; /* Extreme data pointer, used */
- int ext_ofs; /* to calculate the residual. */
- int resid;
- };
- #define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl))
- /*========================================================================
- **
- ** Declaration of structs: NCR device descriptor
- **
- **========================================================================
- */
- struct ncb {
- /*----------------------------------------------------------------
- ** Idle task and invalid task actions and their bus
- ** addresses.
- **----------------------------------------------------------------
- */
- struct action idletask;
- struct action notask;
- struct action bad_i_t_l;
- struct action bad_i_t_l_q;
- u_long p_idletask;
- u_long p_notask;
- u_long p_bad_i_t_l;
- u_long p_bad_i_t_l_q;
- /*----------------------------------------------------------------
- ** Dummy lun table to protect us against target returning bad
- ** lun number on reselection.
- **----------------------------------------------------------------
- */
- u_int32 *badluntbl; /* Table physical address */
- u_int32 resel_badlun; /* SCRIPT handler BUS address */
- /*----------------------------------------------------------------
- ** Bit 32-63 of the on-chip RAM bus address in LE format.
- ** The START_RAM64 script loads the MMRS and MMWS from this
- ** field.
- **----------------------------------------------------------------
- */
- u_int32 scr_ram_seg;
- /*----------------------------------------------------------------
- ** CCBs management queues.
- **----------------------------------------------------------------
- */
- Scsi_Cmnd *waiting_list; /* Commands waiting for a CCB */
- /* when lcb is not allocated. */
- Scsi_Cmnd *done_list; /* Commands waiting for done() */
- /* callback to be invoked. */
- #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
- spinlock_t smp_lock; /* Lock for SMP threading */
- #endif
- /*----------------------------------------------------------------
- ** Chip and controller indentification.
- **----------------------------------------------------------------
- */
- int unit; /* Unit number */
- char chip_name[8]; /* Chip name */
- char inst_name[16]; /* ncb instance name */
- /*----------------------------------------------------------------
- ** Initial value of some IO register bits.
- ** These values are assumed to have been set by BIOS, and may
- ** be used for probing adapter implementation differences.
- **----------------------------------------------------------------
- */
- u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
- sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_stest1, sv_scntl4;
- /*----------------------------------------------------------------
- ** Actual initial value of IO register bits used by the
- ** driver. They are loaded at initialisation according to
- ** features that are to be enabled.
- **----------------------------------------------------------------
- */
- u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4,
- rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4;
- /*----------------------------------------------------------------
- ** Target data.
- ** Target control block bus address array used by the SCRIPT
- ** on reselection.
- **----------------------------------------------------------------
- */
- struct tcb target[MAX_TARGET];
- u_int32 *targtbl;
- /*----------------------------------------------------------------
- ** Virtual and physical bus addresses of the chip.
- **----------------------------------------------------------------
- */
- #ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
- u_long base_va; /* MMIO base virtual address */
- u_long base2_va; /* On-chip RAM virtual address */
- #endif
- u_long base_ba; /* MMIO base bus address */
- u_long base_io; /* IO space base address */
- u_long base_ws; /* (MM)IO window size */
- u_long base2_ba; /* On-chip RAM bus address */
- u_long base2_ws; /* On-chip RAM window size */
- u_int irq; /* IRQ number */
- volatile /* Pointer to volatile for */
- struct ncr_reg *reg; /* memory mapped IO. */
- /*----------------------------------------------------------------
- ** SCRIPTS virtual and physical bus addresses.
- ** 'script' is loaded in the on-chip RAM if present.
- ** 'scripth' stays in main memory for all chips except the
- ** 53C895A and 53C896 that provide 8K on-chip RAM.
- **----------------------------------------------------------------
- */
- struct script *script0; /* Copies of script and scripth */
- struct scripth *scripth0; /* relocated for this ncb. */
- u_long p_script; /* Actual script and scripth */
- u_long p_scripth; /* bus addresses. */
- u_long p_scripth0;
- /*----------------------------------------------------------------
- ** General controller parameters and configuration.
- **----------------------------------------------------------------
- */
- pcidev_t pdev;
- u_short device_id; /* PCI device id */
- u_char revision_id; /* PCI device revision id */
- u_char bus; /* PCI BUS number */
- u_char device_fn; /* PCI BUS device and function */
- u_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 maxoffs_st; /* Max scsi offset in ST mode */
- 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 */
- u_int features; /* Chip features map */
- /*----------------------------------------------------------------
- ** Range for the PCI clock frequency measurement result
- ** that ensures the algorithm used by the driver can be
- ** trusted for the SCSI clock frequency measurement.
- ** (Assuming a PCI clock frequency of 33 MHz).
- **----------------------------------------------------------------
- */
- u_int pciclock_min;
- u_int pciclock_max;
- /*----------------------------------------------------------------
- ** Start queue management.
- ** It is filled up by the host processor and accessed by the
- ** SCRIPTS processor in order to start SCSI commands.
- **----------------------------------------------------------------
- */
- u_long p_squeue; /* Start queue BUS address */
- u_int32 *squeue; /* Start queue virtual address */
- u_short squeueput; /* Next free slot of the queue */
- u_short actccbs; /* Number of allocated CCBs */
- u_short queuedepth; /* Start queue depth */
- /*----------------------------------------------------------------
- ** Command completion queue.
- ** It is the same size as the start queue to avoid overflow.
- **----------------------------------------------------------------
- */
- u_short dqueueget; /* Next position to scan */
- u_int32 *dqueue; /* Completion (done) queue */
- /*----------------------------------------------------------------
- ** 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 script command.
- **----------------------------------------------------------------
- */
- u_char msgout[12]; /* Buffer for MESSAGE OUT */
- u_char msgin [12]; /* Buffer for MESSAGE IN */
- u_int32 lastmsg; /* Last SCSI message sent */
- u_char scratch; /* Scratch for SCSI receive */
- /*----------------------------------------------------------------
- ** Miscellaneous configuration and status parameters.
- **----------------------------------------------------------------
- */
- u_char scsi_mode; /* Current SCSI BUS mode */
- u_char order; /* Tag order to use */
- u_char verbose; /* Verbosity for this controller*/
- u_int32 ncr_cache; /* Used for cache test at init. */
- u_long p_ncb; /* BUS address of this NCB */
- /*----------------------------------------------------------------
- ** CCB lists and queue.
- **----------------------------------------------------------------
- */
- ccb_p ccbh[CCB_HASH_SIZE]; /* CCB hashed by DSA value */
- struct ccb *ccbc; /* CCB chain */
- XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */
- /*----------------------------------------------------------------
- ** IMMEDIATE ARBITRATION (IARB) control.
- ** We keep track in 'last_cp' of the last CCB that has been
- ** queued to the SCRIPTS processor and clear 'last_cp' when
- ** this CCB completes. If last_cp is not zero at the moment
- ** we queue a new CCB, we set a flag in 'last_cp' that is
- ** used by the SCRIPTS as a hint for setting IARB.
- ** We donnot set more than 'iarb_max' consecutive hints for
- ** IARB in order to leave devices a chance to reselect.
- ** By the way, any non zero value of 'iarb_max' is unfair. :)
- **----------------------------------------------------------------
- */
- #ifdef SCSI_NCR_IARB_SUPPORT
- struct ccb *last_cp; /* Last queud CCB used for IARB */
- u_short iarb_max; /* Max. # consecutive IARB hints*/
- u_short iarb_count; /* Actual # of these hints */
- #endif
- /*----------------------------------------------------------------
- ** We need the LCB in order to handle disconnections and
- ** to count active CCBs for task management. So, we use
- ** a unique CCB for LUNs we donnot have the LCB yet.
- ** This queue normally should have at most 1 element.
- **----------------------------------------------------------------
- */
- XPT_QUEHEAD b0_ccbq;
- /*----------------------------------------------------------------
- ** We use a different scatter function for 896 rev 1.
- **----------------------------------------------------------------
- */
- int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *);
- /*----------------------------------------------------------------
- ** Command abort handling.
- ** We need to synchronize tightly with the SCRIPTS
- ** processor in order to handle things correctly.
- **----------------------------------------------------------------
- */
- u_char abrt_msg[4]; /* Message to send buffer */
- struct scr_tblmove abrt_tbl; /* Table for the MOV of it */
- struct scr_tblsel abrt_sel; /* Sync params for selection */
- u_char istat_sem; /* Tells the chip to stop (SEM) */
- /*----------------------------------------------------------------
- ** Fields that should be removed or changed.
- **----------------------------------------------------------------
- */
- struct usrcmd user; /* Command from user */
- volatile u_char release_stage; /* Synchronisation stage on release */
- /*----------------------------------------------------------------
- ** Fields that are used (primarily) for integrity check
- **----------------------------------------------------------------
- */
- unsigned char check_integrity; /* Enable midlayer integ. check on
- * bus scan. */
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- unsigned char check_integ_par; /* Set if par or Init. Det. error
- * used only during integ check */
- #endif
- };
- #define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl))
- #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))
- #define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl))
- /*==========================================================
- **
- **
- ** Script for NCR-Processor.
- **
- ** Use ncr_script_fill() to create the variable parts.
- ** Use ncr_script_copy_and_bind() to make a copy and
- ** bind to physical addresses.
- **
- **
- **==========================================================
- **
- ** We have to know the offsets of all labels before
- ** we reach them (for forward jumps).
- ** Therefore we declare a struct here.
- ** If you make changes inside the script,
- ** DONT FORGET TO CHANGE THE LENGTHS HERE!
- **
- **----------------------------------------------------------
- */
- /*
- ** Script fragments which are loaded into the on-chip RAM
- ** of 825A, 875, 876, 895, 895A and 896 chips.
- */
- struct script {
- ncrcmd start [ 14];
- ncrcmd getjob_begin [ 4];
- ncrcmd getjob_end [ 4];
- ncrcmd select [ 8];
- ncrcmd wf_sel_done [ 2];
- ncrcmd send_ident [ 2];
- #ifdef SCSI_NCR_IARB_SUPPORT
- ncrcmd select2 [ 8];
- #else
- ncrcmd select2 [ 2];
- #endif
- ncrcmd command [ 2];
- ncrcmd dispatch [ 28];
- ncrcmd sel_no_cmd [ 10];
- ncrcmd init [ 6];
- ncrcmd clrack [ 4];
- ncrcmd disp_status [ 4];
- ncrcmd datai_done [ 26];
- ncrcmd datao_done [ 12];
- ncrcmd ign_i_w_r_msg [ 4];
- ncrcmd datai_phase [ 2];
- ncrcmd datao_phase [ 4];
- ncrcmd msg_in [ 2];
- ncrcmd msg_in2 [ 10];
- #ifdef SCSI_NCR_IARB_SUPPORT
- ncrcmd status [ 14];
- #else
- ncrcmd status [ 10];
- #endif
- ncrcmd complete [ 8];
- #ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
- ncrcmd complete2 [ 12];
- #else
- ncrcmd complete2 [ 10];
- #endif
- #ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
- ncrcmd done [ 18];
- #else
- ncrcmd done [ 14];
- #endif
- ncrcmd done_end [ 2];
- ncrcmd save_dp [ 8];
- ncrcmd restore_dp [ 4];
- ncrcmd disconnect [ 20];
- #ifdef SCSI_NCR_IARB_SUPPORT
- ncrcmd idle [ 4];
- #else
- ncrcmd idle [ 2];
- #endif
- #ifdef SCSI_NCR_IARB_SUPPORT
- ncrcmd ungetjob [ 6];
- #else
- ncrcmd ungetjob [ 4];
- #endif
- ncrcmd reselect [ 4];
- ncrcmd reselected [ 20];
- ncrcmd resel_scntl4 [ 30];
- #if MAX_TASKS*4 > 512
- ncrcmd resel_tag [ 18];
- #elif MAX_TASKS*4 > 256
- ncrcmd resel_tag [ 12];
- #else
- ncrcmd resel_tag [ 8];
- #endif
- ncrcmd resel_go [ 6];
- ncrcmd resel_notag [ 2];
- ncrcmd resel_dsa [ 8];
- ncrcmd data_in [MAX_SCATTER * SCR_SG_SIZE];
- ncrcmd data_in2 [ 4];
- ncrcmd data_out [MAX_SCATTER * SCR_SG_SIZE];
- ncrcmd data_out2 [ 4];
- ncrcmd pm0_data [ 12];
- ncrcmd pm0_data_out [ 6];
- ncrcmd pm0_data_end [ 6];
- ncrcmd pm1_data [ 12];
- ncrcmd pm1_data_out [ 6];
- ncrcmd pm1_data_end [ 6];
- };
- /*
- ** Script fragments which stay in main memory for all chips
- ** except for the 895A and 896 that support 8K on-chip RAM.
- */
- struct scripth {
- ncrcmd start64 [ 2];
- ncrcmd no_data [ 2];
- ncrcmd sel_for_abort [ 18];
- ncrcmd sel_for_abort_1 [ 2];
- ncrcmd select_no_atn [ 8];
- ncrcmd wf_sel_done_no_atn [ 4];
- ncrcmd msg_in_etc [ 14];
- ncrcmd msg_received [ 4];
- ncrcmd msg_weird_seen [ 4];
- ncrcmd msg_extended [ 20];
- ncrcmd msg_bad [ 6];
- ncrcmd msg_weird [ 4];
- ncrcmd msg_weird1 [ 8];
- ncrcmd wdtr_resp [ 6];
- ncrcmd send_wdtr [ 4];
- ncrcmd sdtr_resp [ 6];
- ncrcmd send_sdtr [ 4];
- ncrcmd ppr_resp [ 6];
- ncrcmd send_ppr [ 4];
- ncrcmd nego_bad_phase [ 4];
- ncrcmd msg_out [ 4];
- ncrcmd msg_out_done [ 4];
- ncrcmd data_ovrun [ 2];
- ncrcmd data_ovrun1 [ 22];
- ncrcmd data_ovrun2 [ 8];
- ncrcmd abort_resel [ 16];
- ncrcmd resend_ident [ 4];
- ncrcmd ident_break [ 4];
- ncrcmd ident_break_atn [ 4];
- ncrcmd sdata_in [ 6];
- ncrcmd data_io [ 2];
- ncrcmd data_io_com [ 8];
- ncrcmd data_io_out [ 12];
- ncrcmd resel_bad_lun [ 4];
- ncrcmd bad_i_t_l [ 4];
- ncrcmd bad_i_t_l_q [ 4];
- ncrcmd bad_status [ 6];
- ncrcmd tweak_pmj [ 12];
- ncrcmd pm_handle [ 20];
- ncrcmd pm_handle1 [ 4];
- ncrcmd pm_save [ 4];
- ncrcmd pm0_save [ 14];
- ncrcmd pm1_save [ 14];
- /* WSR handling */
- #ifdef SYM_DEBUG_PM_WITH_WSR
- ncrcmd pm_wsr_handle [ 44];
- #else
- ncrcmd pm_wsr_handle [ 42];
- #endif
- ncrcmd wsr_ma_helper [ 4];
- /* Data area */
- ncrcmd zero [ 1];
- ncrcmd scratch [ 1];
- ncrcmd scratch1 [ 1];
- ncrcmd pm0_data_addr [ 1];
- ncrcmd pm1_data_addr [ 1];
- ncrcmd saved_dsa [ 1];
- ncrcmd saved_drs [ 1];
- ncrcmd done_pos [ 1];
- ncrcmd startpos [ 1];
- ncrcmd targtbl [ 1];
- /* End of data area */
- #ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
- ncrcmd start_ram [ 1];
- ncrcmd script0_ba [ 4];
- ncrcmd start_ram64 [ 3];
- ncrcmd script0_ba64 [ 3];
- ncrcmd scripth0_ba64 [ 6];
- ncrcmd ram_seg64 [ 1];
- #endif
- ncrcmd snooptest [ 6];
- ncrcmd snoopend [ 2];
- };
- /*==========================================================
- **
- **
- ** Function headers.
- **
- **
- **==========================================================
- */
- static ccb_p ncr_alloc_ccb (ncb_p np);
- static void ncr_complete (ncb_p np, ccb_p cp);
- static void ncr_exception (ncb_p np);
- static void ncr_free_ccb (ncb_p np, ccb_p cp);
- static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa);
- static void ncr_init_tcb (ncb_p np, u_char tn);
- static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln);
- static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln,
- u_char *inq_data);
- static void ncr_getclock (ncb_p np, int mult);
- static u_int ncr_getpciclock (ncb_p np);
- static void ncr_selectclock (ncb_p np, u_char scntl3);
- static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln);
- static void ncr_init (ncb_p np, int reset, char * msg, u_long code);
- static void ncr_int_sbmc (ncb_p np);
- static void ncr_int_par (ncb_p np, u_short sist);
- static void ncr_int_ma (ncb_p np);
- static void ncr_int_sir (ncb_p np);
- static void ncr_int_sto (ncb_p np);
- static void ncr_int_udc (ncb_p np);
- static void ncr_negotiate (ncb_p np, tcb_p tp);
- static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
- #ifdef SCSI_NCR_INTEGRITY_CHECKING
- static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
- #endif
- static void ncr_script_copy_and_bind
- (ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
- static void ncr_script_fill (struct script * scr, struct scripth * scripth);
- static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
- static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
- static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
- static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, u_char *offset, u_char *width);
- static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4);
- static void ncr_set_sync_wide_status (ncb_p np, u_char target);
- static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln);
- static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack);
- static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4, u_char wide);
- static int ncr_show_msg (u_char * msg);
- static void ncr_print_msg (ccb_p cp, char *label, u_char * msg);
- static int ncr_snooptest (ncb_p np);
- static void ncr_timeout (ncb_p np);
- static void ncr_wakeup (ncb_p np, u_long code);
- static int ncr_wakeup_done (ncb_p np);
- static void ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn);
- static void ncr_put_start_queue(ncb_p np, ccb_p cp);
- static void ncr_chip_reset (ncb_p np);
- static void ncr_soft_reset (ncb_p np);
- static void ncr_start_reset (ncb_p np);
- static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
- static int ncr_compute_residual (ncb_p np, ccb_p cp);
- #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
- static void ncr_usercmd (ncb_p np);
- #endif
- static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device);
- static void ncr_free_resources(ncb_p np);
- static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
- static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd);
- static void process_waiting_list(ncb_p np, int sts);
- #define remove_from_waiting_list(np, cmd)
- retrieve_from_waiting_list(1, (np), (cmd))
- #define requeue_waiting_list(np) process_waiting_list((np), DID_OK)
- #define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- static void ncr_get_nvram (ncr_device *devp, ncr_nvram *nvp);
- static int sym_read_Tekram_nvram (ncr_slot *np, u_short device_id,
- Tekram_nvram *nvram);
- static int sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram);
- #endif
- /*==========================================================
- **
- **
- ** Global static data.
- **
- **
- **==========================================================
- */
- static inline char *ncr_name (ncb_p np)
- {
- return np->inst_name;
- }
- /*==========================================================
- **
- **
- ** Scripts for NCR-Processor.
- **
- ** Use ncr_script_bind for binding to physical addresses.
- **
- **
- **==========================================================
- **
- ** NADDR generates a reference to a field of the controller data.
- ** PADDR generates a reference to another part of the script.
- ** RADDR generates a reference to a script processor register.
- ** FADDR generates a reference to a script processor register
- ** with offset.
- **
- **----------------------------------------------------------
- */
- #define RELOC_SOFTC 0x40000000
- #define RELOC_LABEL 0x50000000
- #define RELOC_REGISTER 0x60000000
- #if 0
- #define RELOC_KVAR 0x70000000
- #endif
- #define RELOC_LABELH 0x80000000
- #define RELOC_MASK 0xf0000000
- #define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label))
- #define PADDR(label) (RELOC_LABEL | offsetof(struct script, label))
- #define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label))
- #define RADDR(label) (RELOC_REGISTER | REG(label))
- #define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
- #define KVAR(which) (RELOC_KVAR | (which))
- #define SCR_DATA_ZERO 0xf00ff00f
- #ifdef RELOC_KVAR
- #define SCRIPT_KVAR_JIFFIES (0)
- #define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES
- #define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES
- /*
- * Kernel variables referenced in the scripts.
- * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
- */
- static void *script_kvars[] __initdata =
- { (void *)&jiffies };
- #endif
- static struct script script0 __initdata = {
- /*--------------------------< START >-----------------------*/ {
- /*
- ** This NOP will be patched with LED ON
- ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
- */
- SCR_NO_OP,
- 0,
- /*
- ** Clear SIGP.
- */
- SCR_FROM_REG (ctest2),
- 0,
- /*
- ** Stop here if the C code wants to perform
- ** some error recovery procedure manually.
- ** (Indicate this by setting SEM in ISTAT)
- */
- SCR_FROM_REG (istat),
- 0,
- /*
- ** Report to the C code the next position in
- ** the start queue the SCRIPTS will schedule.
- ** The C code must not change SCRATCHA.
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDRH (startpos),
- SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
- SIR_SCRIPT_STOPPED,
- /*
- ** Start the next job.
- **
- ** @DSA = start point for this job.
- ** SCRATCHA = address of this job in the start queue.
- **
- ** We will restore startpos with SCRATCHA if we fails the
- ** arbitration or if it is the idle job.
- **
- ** The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS
- ** is a critical path. If it is partially executed, it then
- ** may happen that the job address is not yet in the DSA
- ** and the the next queue position points to the next JOB.
- */
- SCR_LOAD_ABS (dsa, 4),
- PADDRH (startpos),
- SCR_LOAD_REL (temp, 4),
- 4,
- }/*-------------------------< GETJOB_BEGIN >------------------*/,{
- SCR_STORE_ABS (temp, 4),
- PADDRH (startpos),
- SCR_LOAD_REL (dsa, 4),
- 0,
- }/*-------------------------< GETJOB_END >--------------------*/,{
- SCR_LOAD_REL (temp, 4),
- 0,
- SCR_RETURN,
- 0,
- }/*-------------------------< SELECT >----------------------*/,{
- /*
- ** DSA contains the address of a scheduled
- ** data structure.
- **
- ** SCRATCHA contains the address of the start queue
- ** entry which points to the next job.
- **
- ** Set Initiator mode.
- **
- ** (Target mode is left as an exercise for the reader)
- */
- SCR_CLR (SCR_TRG),
- 0,
- /*
- ** And try to select this target.
- */
- SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
- PADDR (ungetjob),
- /*
- ** Now there are 4 possibilities:
- **
- ** (1) The ncr looses arbitration.
- ** This is ok, because it will try again,
- ** when the bus becomes idle.
- ** (But beware of the timeout function!)
- **
- ** (2) The ncr is reselected.
- ** Then the script processor takes the jump
- ** to the RESELECT label.
- **
- ** (3) The ncr wins arbitration.
- ** Then it will execute SCRIPTS instruction until
- ** the next instruction that checks SCSI phase.
- ** Then will stop and wait for selection to be
- ** complete or selection time-out to occur.
- **
- ** After having won arbitration, the ncr SCRIPTS
- ** processor is able to execute instructions while
- ** the SCSI core is performing SCSI selection. But
- ** some script instruction that is not waiting for
- ** a valid phase (or selection timeout) to occur
- ** breaks the selection procedure, by probably
- ** affecting timing requirements.
- ** So we have to wait immediately for the next phase
- ** or the selection to complete or time-out.
- */
- /*
- ** load the savep (saved pointer) into
- ** the actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- /*
- ** Initialize the status registers
- */
- SCR_LOAD_REL (scr0, 4),
- offsetof (struct ccb, phys.header.status),
- }/*-------------------------< WF_SEL_DONE >----------------------*/,{
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- SIR_SEL_ATN_NO_MSG_OUT,
- }/*-------------------------< SEND_IDENT >----------------------*/,{
- /*
- ** Selection complete.
- ** Send the IDENTIFY and SIMPLE_TAG messages
- ** (and the M_X_SYNC_REQ / M_X_WIDE_REQ message)
- */
- SCR_MOVE_TBL ^ SCR_MSG_OUT,
- offsetof (struct dsb, smsg),
- }/*-------------------------< SELECT2 >----------------------*/,{
- #ifdef SCSI_NCR_IARB_SUPPORT
- /*
- ** Set IMMEDIATE ARBITRATION if we have been given
- ** a hint to do so. (Some job to do after this one).
- */
- SCR_FROM_REG (HF_REG),
- 0,
- SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
- 8,
- SCR_REG_REG (scntl1, SCR_OR, IARB),
- 0,
- #endif
- /*
- ** Anticipate the COMMAND phase.
- ** This is the PHASE we expect at this point.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
- PADDR (sel_no_cmd),
- }/*-------------------------< COMMAND >--------------------*/,{
- /*
- ** ... and send the command
- */
- SCR_MOVE_TBL ^ SCR_COMMAND,
- offsetof (struct dsb, cmd),
- }/*-----------------------< 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_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
- PADDR (datao_phase),
- SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
- PADDR (datai_phase),
- SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
- PADDR (status),
- SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
- PADDR (command),
- SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
- PADDRH (msg_out),
- /*
- * Discard as many illegal phases as
- * required and tell the C code about.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
- 16,
- SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
- NADDR (scratch),
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
- -16,
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
- 16,
- SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
- NADDR (scratch),
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
- -16,
- SCR_INT,
- SIR_BAD_PHASE,
- SCR_JUMP,
- PADDR (dispatch),
- }/*---------------------< SEL_NO_CMD >----------------------*/,{
- /*
- ** The target does not switch to command
- ** phase after IDENTIFY has been sent.
- **
- ** If it stays in MSG OUT phase send it
- ** the IDENTIFY again.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
- PADDRH (resend_ident),
- /*
- ** If target does not switch to MSG IN phase
- ** and we sent a negotiation, assert the
- ** failure immediately.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- SCR_FROM_REG (HS_REG),
- 0,
- SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
- SIR_NEGO_FAILED,
- /*
- ** Jump to dispatcher.
- */
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< INIT >------------------------*/,{
- /*
- ** Wait for the SCSI RESET signal to be
- ** inactive before restarting operations,
- ** since the chip may hang on SEL_ATN
- ** if SCSI RESET is active.
- */
- SCR_FROM_REG (sstat0),
- 0,
- SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
- -16,
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< CLRACK >----------------------*/,{
- /*
- ** Terminate possible pending message phase.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< DISP_STATUS >----------------------*/,{
- /*
- ** Anticipate STATUS phase.
- **
- ** Does spare 3 SCRIPTS instructions when we have
- ** completed the INPUT of the data.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
- PADDR (status),
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< DATAI_DONE >-------------------*/,{
- /*
- * If the device wants us to send more data,
- * we must count the extra bytes.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)),
- PADDRH (data_ovrun),
- /*
- ** If the SWIDE is not full, jump to dispatcher.
- ** We anticipate a STATUS phase.
- ** If we get later an IGNORE WIDE RESIDUE, we
- ** will alias it as a MODIFY DP (-1).
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
- PADDR (disp_status),
- /*
- ** The SWIDE is full.
- ** Clear this condition.
- */
- SCR_REG_REG (scntl2, SCR_OR, WSR),
- 0,
- /*
- * We are expecting an IGNORE RESIDUE message
- * from the device, otherwise we are in data
- * overrun condition. Check against MSG_IN phase.
- */
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
- SIR_SWIDE_OVERRUN,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (disp_status),
- /*
- * We are in MSG_IN phase,
- * Read the first byte of the message.
- * If it is not an IGNORE RESIDUE message,
- * signal overrun and jump to message
- * processing.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[0]),
- SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
- SIR_SWIDE_OVERRUN,
- SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
- PADDR (msg_in2),
- /*
- * We got the message we expected.
- * Read the 2nd byte, and jump to dispatcher.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP,
- PADDR (disp_status),
- }/*-------------------------< DATAO_DONE >-------------------*/,{
- /*
- * If the device wants us to send more data,
- * we must count the extra bytes.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
- PADDRH (data_ovrun),
- /*
- ** If the SODL is not full jump to dispatcher.
- ** We anticipate a MSG IN phase or a STATUS phase.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
- PADDR (disp_status),
- /*
- ** The SODL is full, clear this condition.
- */
- SCR_REG_REG (scntl2, SCR_OR, WSS),
- 0,
- /*
- ** And signal a DATA UNDERRUN condition
- ** to the C code.
- */
- SCR_INT,
- SIR_SODL_UNDERRUN,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< IGN_I_W_R_MSG >--------------*/,{
- /*
- ** We jump here from the phase mismatch interrupt,
- ** When we have a SWIDE and the device has presented
- ** a IGNORE WIDE RESIDUE message on the BUS.
- ** We just have to throw away this message and then
- ** to jump to dispatcher.
- */
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
- NADDR (scratch),
- /*
- ** Clear ACK and jump to dispatcher.
- */
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< DATAI_PHASE >------------------*/,{
- SCR_RETURN,
- 0,
- }/*-------------------------< DATAO_PHASE >------------------*/,{
- /*
- ** Patch for 53c1010_66 only - to allow A0 part
- ** to operate properly in a 33MHz PCI bus.
- **
- ** SCR_REG_REG(scntl4, SCR_OR, 0x0c),
- ** 0,
- */
- SCR_NO_OP,
- 0,
- SCR_RETURN,
- 0,
- }/*-------------------------< MSG_IN >--------------------*/,{
- /*
- ** Get the first byte of the message.
- **
- ** The script processor doesn't negate the
- ** ACK signal after this transfer.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[0]),
- }/*-------------------------< MSG_IN2 >--------------------*/,{
- /*
- ** Check first against 1 byte messages
- ** that we handle from SCRIPTS.
- */
- SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
- PADDR (complete),
- SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
- PADDR (disconnect),
- SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
- PADDR (save_dp),
- SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
- PADDR (restore_dp),
- /*
- ** We handle all other messages from the
- ** C code, so no need to waste on-chip RAM
- ** for those ones.
- */
- SCR_JUMP,
- PADDRH (msg_in_etc),
- }/*-------------------------< STATUS >--------------------*/,{
- /*
- ** get the status
- */
- SCR_MOVE_ABS (1) ^ SCR_STATUS,
- NADDR (scratch),
- #ifdef SCSI_NCR_IARB_SUPPORT
- /*
- ** If STATUS is not GOOD, clear IMMEDIATE ARBITRATION,
- ** since we may have to tamper the start queue from
- ** the C code.
- */
- SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
- 8,
- SCR_REG_REG (scntl1, SCR_AND, ~IARB),
- 0,
- #endif
- /*
- ** save status to scsi_status.
- ** mark as complete.
- */
- SCR_TO_REG (SS_REG),
- 0,
- SCR_LOAD_REG (HS_REG, HS_COMPLETE),
- 0,
- /*
- ** Anticipate the MESSAGE PHASE for
- ** the TASK COMPLETE message.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
- PADDR (msg_in),
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< COMPLETE >-----------------*/,{
- /*
- ** Complete message.
- **
- ** Copy the data pointer to LASTP in header.
- */
- SCR_STORE_REL (temp, 4),
- offsetof (struct ccb, phys.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,
- }/*-------------------------< COMPLETE2 >-----------------*/,{
- /*
- ** Save host status to header.
- */
- SCR_STORE_REL (scr0, 4),
- offsetof (struct ccb, phys.header.status),
- #ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
- /*
- ** Some bridges may reorder DMA writes to memory.
- ** We donnot want the CPU to deal with completions
- ** without all the posted write having been flushed
- ** to memory. This DUMMY READ should flush posted
- ** buffers prior to the CPU having to deal with
- ** completions.
- */
- SCR_LOAD_REL (scr0, 4), /* DUMMY READ */
- offsetof (struct ccb, phys.header.status),
- #endif
- /*
- ** If command resulted in not GOOD status,
- ** call the C code if needed.
- */
- SCR_FROM_REG (SS_REG),
- 0,
- SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
- PADDRH (bad_status),
- /*
- ** If we performed an auto-sense, call
- ** the C code to synchronyze task aborts
- ** with UNIT ATTENTION conditions.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)),
- SIR_AUTO_SENSE_DONE,
- }/*------------------------< DONE >-----------------*/,{
- #ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
- /*
- ** It seems that some bridges flush everything
- ** when the INTR line is raised. For these ones,
- ** we can just ensure that the INTR line will be
- ** raised before each completion. So, if it happens
- ** that we have been faster that the CPU, we just
- ** have to synchronize with it. A dummy programmed
- ** interrupt will do the trick.
- ** Note that we overlap at most 1 IO with the CPU
- ** in this situation and that the IRQ line must not
- ** be shared.
- */
- SCR_FROM_REG (istat),
- 0,
- SCR_INT ^ IFTRUE (MASK (INTF, INTF)),
- SIR_DUMMY_INTERRUPT,
- #endif
- /*
- ** Copy the DSA to the DONE QUEUE and
- ** signal completion to the host.
- ** If we are interrupted between DONE
- ** and DONE_END, we must reset, otherwise
- ** the completed CCB will be lost.
- */
- SCR_STORE_ABS (dsa, 4),
- PADDRH (saved_dsa),
- SCR_LOAD_ABS (dsa, 4),
- PADDRH (done_pos),
- SCR_LOAD_ABS (scratcha, 4),
- PADDRH (saved_dsa),
- SCR_STORE_REL (scratcha, 4),
- 0,
- /*
- ** The instruction below reads the DONE QUEUE next
- ** free position from memory.
- ** In addition it ensures that all PCI posted writes
- ** are flushed and so the DSA value of the done
- ** CCB is visible by the CPU before INTFLY is raised.
- */
- SCR_LOAD_REL (temp, 4),
- 4,
- SCR_INT_FLY,
- 0,
- SCR_STORE_ABS (temp, 4),
- PADDRH (done_pos),
- }/*------------------------< DONE_END >-----------------*/,{
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< SAVE_DP >------------------*/,{
- /*
- ** Clear ACK immediately.
- ** No need to delay it.
- */
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** Keep track we received a SAVE DP, so
- ** we will switch to the other PM context
- ** on the next PM since the DP may point
- ** to the current PM context.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
- 0,
- /*
- ** SAVE_DP message:
- ** Copy the data pointer to SAVEP in header.
- */
- SCR_STORE_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< RESTORE_DP >---------------*/,{
- /*
- ** RESTORE_DP message:
- ** Copy SAVEP in header to actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< DISCONNECT >---------------*/,{
- /*
- ** DISCONNECTing ...
- **
- ** disable the "unexpected disconnect" feature,
- ** and remove the ACK signal.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- /*
- ** Wait for the disconnect.
- */
- SCR_WAIT_DISC,
- 0,
- /*
- ** Status is: DISCONNECTED.
- */
- SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
- 0,
- /*
- ** Save host status to header.
- */
- SCR_STORE_REL (scr0, 4),
- offsetof (struct ccb, phys.header.status),
- /*
- ** If QUIRK_AUTOSAVE is set,
- ** do an "save pointer" operation.
- */
- SCR_FROM_REG (QU_REG),
- 0,
- SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
- PADDR (start),
- /*
- ** like SAVE_DP message:
- ** Remember we saved the data pointer.
- ** Copy data pointer to SAVEP in header.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
- 0,
- SCR_STORE_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< IDLE >------------------------*/,{
- /*
- ** Nothing to do?
- ** Wait for reselect.
- ** This NOP will be patched with LED OFF
- ** SCR_REG_REG (gpreg, SCR_OR, 0x01)
- */
- SCR_NO_OP,
- 0,
- #ifdef SCSI_NCR_IARB_SUPPORT
- SCR_JUMPR,
- 8,
- #endif
- }/*-------------------------< UNGETJOB >-----------------*/,{
- #ifdef SCSI_NCR_IARB_SUPPORT
- /*
- ** Set IMMEDIATE ARBITRATION, for the next time.
- ** This will give us better chance to win arbitration
- ** for the job we just wanted to do.
- */
- SCR_REG_REG (scntl1, SCR_OR, IARB),
- 0,
- #endif
- /*
- ** We are not able to restart the SCRIPTS if we are
- ** interrupted and these instruction haven't been
- ** all executed. BTW, this is very unlikely to
- ** happen, but we check that from the C code.
- */
- SCR_LOAD_REG (dsa, 0xff),
- 0,
- SCR_STORE_ABS (scratcha, 4),
- PADDRH (startpos),
- }/*-------------------------< RESELECT >--------------------*/,{
- /*
- ** make the host status invalid.
- */
- SCR_CLR (SCR_TRG),
- 0,
- /*
- ** Sleep waiting for a reselection.
- ** If SIGP is set, special treatment.
- **
- ** Zu allem bereit ..
- */
- SCR_WAIT_RESEL,
- PADDR(start),
- }/*-------------------------< RESELECTED >------------------*/,{
- /*
- ** This NOP will be patched with LED ON
- ** SCR_REG_REG (gpreg, SCR_AND, 0xfe)
- */
- SCR_NO_OP,
- 0,
- /*
- ** load the target id into the sdid
- */
- SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
- 0,
- SCR_TO_REG (sdid),
- 0,
- /*
- ** load the target control block address
- */
- SCR_LOAD_ABS (dsa, 4),
- PADDRH (targtbl),
- SCR_SFBR_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_AND, 0x3c),
- 0,
- SCR_LOAD_REL (dsa, 4),
- 0,
- /*
- ** Load the synchronous transfer registers.
- */
- SCR_LOAD_REL (scntl3, 1),
- offsetof(struct tcb, wval),
- SCR_LOAD_REL (sxfer, 1),
- offsetof(struct tcb, sval),
- }/*-------------------------< RESEL_SCNTL4 >------------------*/,{
- /*
- ** Write with uval value. Patch if device
- ** does not support Ultra3.
- **
- ** SCR_LOAD_REL (scntl4, 1),
- ** offsetof(struct tcb, uval),
- */
- SCR_NO_OP,
- 0,
- /*
- * We expect MESSAGE IN phase.
- * If not, get help from the C code.
- */
- SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
- SIR_RESEL_NO_MSG_IN,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin),
- /*
- * If IDENTIFY LUN #0, use a faster path
- * to find the LCB structure.
- */
- SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)),
- 56,
- /*
- * If message isn't an IDENTIFY,
- * tell the C code about.
- */
- SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
- SIR_RESEL_NO_IDENTIFY,
- /*
- * It is an IDENTIFY message,
- * Load the LUN control block address.
- */
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct tcb, b_luntbl),
- SCR_SFBR_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_SHL, 0),
- 0,
- SCR_REG_REG (dsa, SCR_AND, 0xfc),
- 0,
- SCR_LOAD_REL (dsa, 4),
- 0,
- SCR_JUMPR,
- 8,
- /*
- ** LUN 0 special case (but usual one :))
- */
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct tcb, b_lun0),
- /*
- ** Load the reselect task action for this LUN.
- ** Load the tasks DSA array for this LUN.
- ** Call the action.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof(struct lcb, resel_task),
- SCR_LOAD_REL (dsa, 4),
- offsetof(struct lcb, b_tasktbl),
- SCR_RETURN,
- 0,
- }/*-------------------------< RESEL_TAG >-------------------*/,{
- /*
- ** ACK the IDENTIFY or TAG previously received
- */
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** Read IDENTIFY + SIMPLE + TAG using a single MOVE.
- ** Agressive optimization, is'nt it?
- ** No need to test the SIMPLE TAG message, since the
- ** driver only supports conformant devices for tags. ;-)
- */
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
- NADDR (msgin),
- /*
- ** Read the TAG from the SIDL.
- ** Still an aggressive optimization. ;-)
- ** Compute the CCB indirect jump address which
- ** is (#TAG*2 & 0xfc) due to tag numbering using
- ** 1,3,5..MAXTAGS*2+1 actual values.
- */
- SCR_REG_SFBR (sidl, SCR_SHL, 0),
- 0,
- #if MAX_TASKS*4 > 512
- SCR_JUMPR ^ IFFALSE (CARRYSET),
- 8,
- SCR_REG_REG (dsa1, SCR_OR, 2),
- 0,
- SCR_REG_REG (sfbr, SCR_SHL, 0),
- 0,
- SCR_JUMPR ^ IFFALSE (CARRYSET),
- 8,
- SCR_REG_REG (dsa1, SCR_OR, 1),
- 0,
- #elif MAX_TASKS*4 > 256
- SCR_JUMPR ^ IFFALSE (CARRYSET),
- 8,
- SCR_REG_REG (dsa1, SCR_OR, 1),
- 0,
- #endif
- /*
- ** Retrieve the DSA of this task.
- ** JUMP indirectly to the restart point of the CCB.
- */
- SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
- 0,
- }/*-------------------------< RESEL_GO >-------------------*/,{
- SCR_LOAD_REL (dsa, 4),
- 0,
- SCR_LOAD_REL (temp, 4),
- offsetof(struct ccb, phys.header.go.restart),
- SCR_RETURN,
- 0,
- /* In normal situations we branch to RESEL_DSA */
- }/*-------------------------< RESEL_NOTAG >-------------------*/,{
- /*
- ** JUMP indirectly to the restart point of the CCB.
- */
- SCR_JUMP,
- PADDR (resel_go),
- }/*-------------------------< RESEL_DSA >-------------------*/,{
- /*
- ** Ack the IDENTIFY or TAG previously received.
- */
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** load the savep (saved pointer) into
- ** the actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- /*
- ** Initialize the status registers
- */
- SCR_LOAD_REL (scr0, 4),
- offsetof (struct ccb, phys.header.status),
- /*
- ** Jump to dispatcher.
- */
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< DATA_IN >--------------------*/,{
- /*
- ** Because the size depends on the
- ** #define MAX_SCATTER parameter,
- ** it is filled in at runtime.
- **
- ** ##===========< i=0; i<MAX_SCATTER >=========
- ** || SCR_CHMOV_TBL ^ SCR_DATA_IN,
- ** || offsetof (struct dsb, data[ i]),
- ** ##==========================================
- **
- **---------------------------------------------------------
- */
- 0
- }/*-------------------------< DATA_IN2 >-------------------*/,{
- SCR_CALL,
- PADDR (datai_done),
- SCR_JUMP,
- PADDRH (data_ovrun),
- }/*-------------------------< DATA_OUT >--------------------*/,{
- /*
- ** Because the size depends on the
- ** #define MAX_SCATTER parameter,
- ** it is filled in at runtime.
- **
- ** ##===========< i=0; i<MAX_SCATTER >=========
- ** || SCR_CHMOV_TBL ^ SCR_DATA_OUT,
- ** || offsetof (struct dsb, data[ i]),
- ** ##==========================================
- **
- **---------------------------------------------------------
- */
- 0
- }/*-------------------------< DATA_OUT2 >-------------------*/,{
- SCR_CALL,
- PADDR (datao_done),
- SCR_JUMP,
- PADDRH (data_ovrun),
- }/*-------------------------< PM0_DATA >--------------------*/,{
- /*
- ** Read our host flags to SFBR, so we will be able
- ** to check against the data direction we expect.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- /*
- ** Check against actual DATA PHASE.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
- PADDR (pm0_data_out),
- /*
- ** Actual phase is DATA IN.
- ** Check against expected direction.
- */
- SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (data_ovrun),
- /*
- ** Keep track we are moving data from the
- ** PM0 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
- 0,
- /*
- ** Move the data to memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct ccb, phys.pm0.sg),
- SCR_JUMP,
- PADDR (pm0_data_end),
- }/*-------------------------< PM0_DATA_OUT >----------------*/,{
- /*
- ** Actual phase is DATA OUT.
- ** Check against expected direction.
- */
- SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (data_ovrun),
- /*
- ** Keep track we are moving data from the
- ** PM0 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
- 0,
- /*
- ** Move the data from memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_OUT,
- offsetof (struct ccb, phys.pm0.sg),
- }/*-------------------------< PM0_DATA_END >----------------*/,{
- /*
- ** Clear the flag that told we were moving
- ** data from the PM0 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
- 0,
- /*
- ** Return to the previous DATA script which
- ** is guaranteed by design (if no bug) to be
- ** the main DATA script for this transfer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.pm0.ret),
- SCR_RETURN,
- 0,
- }/*-------------------------< PM1_DATA >--------------------*/,{
- /*
- ** Read our host flags to SFBR, so we will be able
- ** to check against the data direction we expect.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- /*
- ** Check against actual DATA PHASE.
- */
- SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
- PADDR (pm1_data_out),
- /*
- ** Actual phase is DATA IN.
- ** Check against expected direction.
- */
- SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (data_ovrun),
- /*
- ** Keep track we are moving data from the
- ** PM1 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
- 0,
- /*
- ** Move the data to memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct ccb, phys.pm1.sg),
- SCR_JUMP,
- PADDR (pm1_data_end),
- }/*-------------------------< PM1_DATA_OUT >----------------*/,{
- /*
- ** Actual phase is DATA OUT.
- ** Check against expected direction.
- */
- SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
- PADDRH (data_ovrun),
- /*
- ** Keep track we are moving data from the
- ** PM1 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
- 0,
- /*
- ** Move the data from memory.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_OUT,
- offsetof (struct ccb, phys.pm1.sg),
- }/*-------------------------< PM1_DATA_END >----------------*/,{
- /*
- ** Clear the flag that told we were moving
- ** data from the PM1 DATA mini-script.
- */
- SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
- 0,
- /*
- ** Return to the previous DATA script which
- ** is guaranteed by design (if no bug) to be
- ** the main DATA script for this transfer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.pm1.ret),
- SCR_RETURN,
- 0,
- }/*---------------------------------------------------------*/
- };
- static struct scripth scripth0 __initdata = {
- /*------------------------< START64 >-----------------------*/{
- /*
- ** SCRIPT entry point for the 895A and the 896.
- ** For now, there is no specific stuff for that
- ** chip at this point, but this may come.
- */
- SCR_JUMP,
- PADDR (init),
- }/*-------------------------< NO_DATA >-------------------*/,{
- SCR_JUMP,
- PADDRH (data_ovrun),
- }/*-----------------------< SEL_FOR_ABORT >------------------*/,{
- /*
- ** We are jumped here by the C code, if we have
- ** some target to reset or some disconnected
- ** job to abort. Since error recovery is a serious
- ** busyness, we will really reset the SCSI BUS, if
- ** case of a SCSI interrupt occuring in this path.
- */
- /*
- ** Set initiator mode.
- */
- SCR_CLR (SCR_TRG),
- 0,
- /*
- ** And try to select this target.
- */
- SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel),
- PADDR (reselect),
- /*
- ** Wait for the selection to complete or
- ** the selection to time out.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- -8,
- /*
- ** Call the C code.
- */
- SCR_INT,
- SIR_TARGET_SELECTED,
- /*
- ** The C code should let us continue here.
- ** Send the 'kiss of death' message.
- ** We expect an immediate disconnect once
- ** the target has eaten the message.
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_MOVE_TBL ^ SCR_MSG_OUT,
- offsetof (struct ncb, abrt_tbl),
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- SCR_WAIT_DISC,
- 0,
- /*
- ** Tell the C code that we are done.
- */
- SCR_INT,
- SIR_ABORT_SENT,
- }/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{
- /*
- ** Jump at scheduler.
- */
- SCR_JUMP,
- PADDR (start),
- }/*------------------------< SELECT_NO_ATN >-----------------*/,{
- /*
- ** Set Initiator mode.
- ** And try to select this target without ATN.
- */
- SCR_CLR (SCR_TRG),
- 0,
- SCR_SEL_TBL ^ offsetof (struct dsb, select),
- PADDR (ungetjob),
- /*
- ** load the savep (saved pointer) into
- ** the actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- /*
- ** Initialize the status registers
- */
- SCR_LOAD_REL (scr0, 4),
- offsetof (struct ccb, phys.header.status),
- }/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{
- /*
- ** Wait immediately for the next phase or
- ** the selection to complete or time-out.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- 0,
- SCR_JUMP,
- PADDR (select2),
- }/*-------------------------< MSG_IN_ETC >--------------------*/,{
- /*
- ** If it is an EXTENDED (variable size message)
- ** Handle it.
- */
- SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
- PADDRH (msg_extended),
- /*
- ** Let the C code handle any other
- ** 1 byte message.
- */
- SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
- PADDRH (msg_received),
- SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
- PADDRH (msg_received),
- /*
- ** We donnot handle 2 bytes messages from SCRIPTS.
- ** So, let the C code deal with these ones too.
- */
- SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
- PADDRH (msg_weird_seen),
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
- SCR_JUMP,
- PADDRH (msg_received),
- }/*-------------------------< MSG_RECEIVED >--------------------*/,{
- SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
- 0,
- SCR_INT,
- SIR_MSG_RECEIVED,
- }/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
- SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
- 0,
- SCR_INT,
- SIR_MSG_WEIRD,
- }/*-------------------------< MSG_EXTENDED >--------------------*/,{
- /*
- ** Clear ACK and get the next byte
- ** assumed to be the message length.
- */
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
- /*
- ** Try to catch some unlikely situations as 0 length
- ** or too large the length.
- */
- SCR_JUMP ^ IFTRUE (DATA (0)),
- PADDRH (msg_weird_seen),
- SCR_TO_REG (scratcha),
- 0,
- SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
- 0,
- SCR_JUMP ^ IFTRUE (CARRYSET),
- PADDRH (msg_weird_seen),
- /*
- ** We donnot handle extended messages from SCRIPTS.
- ** Read the amount of data correponding to the
- ** message length and call the C code.
- */
- SCR_STORE_REL (scratcha, 1),
- offsetof (struct dsb, smsg_ext.size),
- SCR_CLR (SCR_ACK),
- 0,
- SCR_MOVE_TBL ^ SCR_MSG_IN,
- offsetof (struct dsb, smsg_ext),
- SCR_JUMP,
- PADDRH (msg_received),
- }/*-------------------------< MSG_BAD >------------------*/,{
- /*
- ** unimplemented message - reject it.
- */
- SCR_INT,
- SIR_REJECT_TO_SEND,
- SCR_SET (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR (clrack),
- }/*-------------------------< MSG_WEIRD >--------------------*/,{
- /*
- ** weird message received
- ** ignore all MSG IN phases and reject it.
- */
- SCR_INT,
- SIR_REJECT_TO_SEND,
- SCR_SET (SCR_ATN),
- 0,
- }/*-------------------------< MSG_WEIRD1 >--------------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (scratch),
- SCR_JUMP,
- PADDRH (msg_weird1),
- }/*-------------------------< WDTR_RESP >----------------*/,{
- /*
- ** let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDRH (nego_bad_phase),
- }/*-------------------------< SEND_WDTR >----------------*/,{
- /*
- ** Send the M_X_WIDE_REQ
- */
- SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_JUMP,
- PADDRH (msg_out_done),
- }/*-------------------------< SDTR_RESP >-------------*/,{
- /*
- ** let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDRH (nego_bad_phase),
- }/*-------------------------< SEND_SDTR >-------------*/,{
- /*
- ** Send the M_X_SYNC_REQ
- */
- SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_JUMP,
- PADDRH (msg_out_done),
- }/*-------------------------< PPR_RESP >-------------*/,{
- /*
- ** let the target fetch our answer.
- */
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
- PADDRH (nego_bad_phase),
- }/*-------------------------< SEND_PPR >-------------*/,{
- /*
- ** Send the M_X_PPR_REQ
- */
- SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_JUMP,
- PADDRH (msg_out_done),
- }/*-------------------------< NEGO_BAD_PHASE >------------*/,{
- SCR_INT,
- SIR_NEGO_PROTO,
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< MSG_OUT >-------------------*/,{
- /*
- ** The target requests a message.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- NADDR (msgout),
- /*
- ** ... wait for the next phase
- ** if it's a message out, send it again, ...
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
- PADDRH (msg_out),
- }/*-------------------------< MSG_OUT_DONE >--------------*/,{
- /*
- ** ... else clear the message ...
- */
- SCR_INT,
- SIR_MSG_OUT_DONE,
- /*
- ** ... and process the next phase
- */
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< DATA_OVRUN >-----------------------*/,{
- /*
- * Use scratcha to count the extra bytes.
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDRH (zero),
- }/*-------------------------< DATA_OVRUN1 >----------------------*/,{
- /*
- * The target may want to transfer too much data.
- *
- * If phase is DATA OUT write 1 byte and count it.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
- 16,
- SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
- NADDR (scratch),
- SCR_JUMP,
- PADDRH (data_ovrun2),
- /*
- * If WSR is set, clear this condition, and
- * count this byte.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
- 16,
- SCR_REG_REG (scntl2, SCR_OR, WSR),
- 0,
- SCR_JUMP,
- PADDRH (data_ovrun2),
- /*
- * Finally check against DATA IN phase.
- * Signal data overrun to the C code
- * and jump to dispatcher if not so.
- * Read 1 byte otherwise and count it.
- */
- SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
- 16,
- SCR_INT,
- SIR_DATA_OVERRUN,
- SCR_JUMP,
- PADDR (dispatch),
- SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
- NADDR (scratch),
- }/*-------------------------< DATA_OVRUN2 >----------------------*/,{
- /*
- * Count this byte.
- * This will allow to return a negative
- * residual to user.
- */
- SCR_REG_REG (scratcha, SCR_ADD, 0x01),
- 0,
- SCR_REG_REG (scratcha1, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (scratcha2, SCR_ADDC, 0),
- 0,
- /*
- * .. and repeat as required.
- */
- SCR_JUMP,
- PADDRH (data_ovrun1),
- }/*-------------------------< ABORT_RESEL >----------------*/,{
- SCR_SET (SCR_ATN),
- 0,
- SCR_CLR (SCR_ACK),
- 0,
- /*
- ** send the abort/abortag/reset message
- ** we expect an immediate disconnect
- */
- SCR_REG_REG (scntl2, SCR_AND, 0x7f),
- 0,
- SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
- NADDR (msgout),
- SCR_CLR (SCR_ACK|SCR_ATN),
- 0,
- SCR_WAIT_DISC,
- 0,
- SCR_INT,
- SIR_RESEL_ABORTED,
- SCR_JUMP,
- PADDR (start),
- }/*-------------------------< RESEND_IDENT >-------------------*/,{
- /*
- ** The target stays in MSG OUT phase after having acked
- ** Identify [+ Tag [+ Extended message ]]. Targets shall
- ** behave this way on parity error.
- ** We must send it again all the messages.
- */
- SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */
- 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */
- SCR_JUMP,
- PADDR (send_ident),
- }/*-------------------------< IDENT_BREAK >-------------------*/,{
- SCR_CLR (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR (select2),
- }/*-------------------------< IDENT_BREAK_ATN >----------------*/,{
- SCR_SET (SCR_ATN),
- 0,
- SCR_JUMP,
- PADDR (select2),
- }/*-------------------------< SDATA_IN >-------------------*/,{
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct dsb, sense),
- SCR_CALL,
- PADDR (datai_done),
- SCR_JUMP,
- PADDRH (data_ovrun),
- }/*-------------------------< DATA_IO >--------------------*/,{
- /*
- ** We jump here if the data direction was unknown at the
- ** time we had to queue the command to the scripts processor.
- ** Pointers had been set as follow in this situation:
- ** savep --> DATA_IO
- ** lastp --> start pointer when DATA_IN
- ** goalp --> goal pointer when DATA_IN
- ** wlastp --> start pointer when DATA_OUT
- ** wgoalp --> goal pointer when DATA_OUT
- ** This script sets savep/lastp/goalp according to the
- ** direction chosen by the target.
- */
- SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
- PADDRH(data_io_out),
- }/*-------------------------< DATA_IO_COM >-----------------*/,{
- /*
- ** Direction is DATA IN.
- ** Warning: we jump here, even when phase is DATA OUT.
- */
- SCR_LOAD_REL (scratcha, 4),
- offsetof (struct ccb, phys.header.lastp),
- SCR_STORE_REL (scratcha, 4),
- offsetof (struct ccb, phys.header.savep),
- /*
- ** Jump to the SCRIPTS according to actual direction.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- SCR_RETURN,
- 0,
- }/*-------------------------< DATA_IO_OUT >-----------------*/,{
- /*
- ** Direction is DATA OUT.
- */
- SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)),
- 0,
- SCR_LOAD_REL (scratcha, 4),
- offsetof (struct ccb, phys.header.wlastp),
- SCR_STORE_REL (scratcha, 4),
- offsetof (struct ccb, phys.header.lastp),
- SCR_LOAD_REL (scratcha, 4),
- offsetof (struct ccb, phys.header.wgoalp),
- SCR_STORE_REL (scratcha, 4),
- offsetof (struct ccb, phys.header.goalp),
- SCR_JUMP,
- PADDRH(data_io_com),
- }/*-------------------------< RESEL_BAD_LUN >---------------*/,{
- /*
- ** Message is an IDENTIFY, but lun is unknown.
- ** Signal problem to C code for logging the event.
- ** Send a M_ABORT to clear all pending tasks.
- */
- SCR_INT,
- SIR_RESEL_BAD_LUN,
- SCR_JUMP,
- PADDRH (abort_resel),
- }/*-------------------------< BAD_I_T_L >------------------*/,{
- /*
- ** We donnot have a task for that I_T_L.
- ** Signal problem to C code for logging the event.
- ** Send a M_ABORT message.
- */
- SCR_INT,
- SIR_RESEL_BAD_I_T_L,
- SCR_JUMP,
- PADDRH (abort_resel),
- }/*-------------------------< BAD_I_T_L_Q >----------------*/,{
- /*
- ** We donnot have a task that matches the tag.
- ** Signal problem to C code for logging the event.
- ** Send a M_ABORTTAG message.
- */
- SCR_INT,
- SIR_RESEL_BAD_I_T_L_Q,
- SCR_JUMP,
- PADDRH (abort_resel),
- }/*-------------------------< BAD_STATUS >-----------------*/,{
- /*
- ** Anything different from INTERMEDIATE
- ** CONDITION MET should be a bad SCSI status,
- ** given that GOOD status has already been tested.
- ** Call the C code.
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDRH (startpos),
- SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
- SIR_BAD_STATUS,
- SCR_RETURN,
- 0,
- }/*-------------------------< TWEAK_PMJ >------------------*/,{
- /*
- ** Disable PM handling from SCRIPTS for the data phase
- ** and so force PM to be handled from C code if HF_PM_TO_C
- ** flag is set.
- */
- SCR_FROM_REG(HF_REG),
- 0,
- SCR_JUMPR ^ IFTRUE (MASK (HF_PM_TO_C, HF_PM_TO_C)),
- 16,
- SCR_REG_REG (ccntl0, SCR_OR, ENPMJ),
- 0,
- SCR_RETURN,
- 0,
- SCR_REG_REG (ccntl0, SCR_AND, (~ENPMJ)),
- 0,
- SCR_RETURN,
- 0,
- }/*-------------------------< PM_HANDLE >------------------*/,{
- /*
- ** Phase mismatch handling.
- **
- ** Since we have to deal with 2 SCSI data pointers
- ** (current and saved), we need at least 2 contexts.
- ** Each context (pm0 and pm1) has a saved area, a
- ** SAVE mini-script and a DATA phase mini-script.
- */
- /*
- ** Get the PM handling flags.
- */
- SCR_FROM_REG (HF_REG),
- 0,
- /*
- ** If no flags (1rst PM for example), avoid
- ** all the below heavy flags testing.
- ** This makes the normal case a bit faster.
- */
- SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))),
- PADDRH (pm_handle1),
- /*
- ** If we received a SAVE DP, switch to the
- ** other PM context since the savep may point
- ** to the current PM context.
- */
- SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)),
- 8,
- SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM),
- 0,
- /*
- ** If we have been interrupt in a PM DATA mini-script,
- ** we take the return address from the corresponding
- ** saved area.
- ** This ensure the return address always points to the
- ** main DATA script for this transfer.
- */
- SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))),
- PADDRH (pm_handle1),
- SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)),
- 16,
- SCR_LOAD_REL (ia, 4),
- offsetof(struct ccb, phys.pm0.ret),
- SCR_JUMP,
- PADDRH (pm_save),
- SCR_LOAD_REL (ia, 4),
- offsetof(struct ccb, phys.pm1.ret),
- SCR_JUMP,
- PADDRH (pm_save),
- }/*-------------------------< PM_HANDLE1 >-----------------*/,{
- /*
- ** Normal case.
- ** Update the return address so that it
- ** will point after the interrupted MOVE.
- */
- SCR_REG_REG (ia, SCR_ADD, 8),
- 0,
- SCR_REG_REG (ia1, SCR_ADDC, 0),
- 0,
- }/*-------------------------< PM_SAVE >--------------------*/,{
- /*
- ** Clear all the flags that told us if we were
- ** interrupted in a PM DATA mini-script and/or
- ** we received a SAVE DP.
- */
- SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))),
- 0,
- /*
- ** Choose the current PM context.
- */
- SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
- PADDRH (pm1_save),
- }/*-------------------------< PM0_SAVE >-------------------*/,{
- SCR_STORE_REL (ia, 4),
- offsetof(struct ccb, phys.pm0.ret),
- /*
- ** If WSR bit is set, either UA and RBC may
- ** have to be changed whatever the device wants
- ** to ignore this residue ot not.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
- PADDRH (pm_wsr_handle),
- /*
- ** Save the remaining byte count, the updated
- ** address and the return address.
- */
- SCR_STORE_REL (rbc, 4),
- offsetof(struct ccb, phys.pm0.sg.size),
- SCR_STORE_REL (ua, 4),
- offsetof(struct ccb, phys.pm0.sg.addr),
- /*
- ** Set the current pointer at the PM0 DATA mini-script.
- */
- SCR_LOAD_ABS (temp, 4),
- PADDRH (pm0_data_addr),
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< PM1_SAVE >-------------------*/,{
- SCR_STORE_REL (ia, 4),
- offsetof(struct ccb, phys.pm1.ret),
- /*
- ** If WSR bit is set, either UA and RBC may
- ** have been changed whatever the device wants
- ** to ignore this residue or not.
- */
- SCR_FROM_REG (scntl2),
- 0,
- SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
- PADDRH (pm_wsr_handle),
- /*
- ** Save the remaining byte count, the updated
- ** address and the return address.
- */
- SCR_STORE_REL (rbc, 4),
- offsetof(struct ccb, phys.pm1.sg.size),
- SCR_STORE_REL (ua, 4),
- offsetof(struct ccb, phys.pm1.sg.addr),
- /*
- ** Set the current pointer at the PM1 DATA mini-script.
- */
- SCR_LOAD_ABS (temp, 4),
- PADDRH (pm1_data_addr),
- SCR_JUMP,
- PADDR (dispatch),
- }/*--------------------------< PM_WSR_HANDLE >-----------------------*/,{
- /*
- * Phase mismatch handling from SCRIPT with WSR set.
- * Such a condition can occur if the chip wants to
- * execute a CHMOV(size > 1) when the WSR bit is
- * set and the target changes PHASE.
- */
- #ifdef SYM_DEBUG_PM_WITH_WSR
- /*
- * Some debugging may still be needed.:)
- */
- SCR_INT,
- SIR_PM_WITH_WSR,
- #endif
- /*
- * We must move the residual byte to memory.
- *
- * UA contains bit 0..31 of the address to
- * move the residual byte.
- * Move it to the table indirect.
- */
- SCR_STORE_REL (ua, 4),
- offsetof (struct ccb, phys.wresid.addr),
- /*
- * Increment UA (move address to next position).
- */
- SCR_REG_REG (ua, SCR_ADD, 1),
- 0,
- SCR_REG_REG (ua1, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (ua2, SCR_ADDC, 0),
- 0,
- SCR_REG_REG (ua3, SCR_ADDC, 0),
- 0,
- /*
- * Compute SCRATCHA as:
- * - size to transfer = 1 byte.
- * - bit 24..31 = high address bit [32...39].
- */
- SCR_LOAD_ABS (scratcha, 4),
- PADDRH (zero),
- SCR_REG_REG (scratcha, SCR_OR, 1),
- 0,
- SCR_FROM_REG (rbc3),
- 0,
- SCR_TO_REG (scratcha3),
- 0,
- /*
- * Move this value to the table indirect.
- */
- SCR_STORE_REL (scratcha, 4),
- offsetof (struct ccb, phys.wresid.size),
- /*
- * Wait for a valid phase.
- * While testing with bogus QUANTUM drives, the C1010
- * sometimes raised a spurious phase mismatch with
- * WSR and the CHMOV(1) triggered another PM.
- * Waiting explicitely for the PHASE seemed to avoid
- * the nested phase mismatch. Btw, this didn't happen
- * using my IBM drives.
- */
- SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
- 0,
- /*
- * Perform the move of the residual byte.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct ccb, phys.wresid),
- /*
- * We can now handle the phase mismatch with UA fixed.
- * RBC[0..23]=0 is a special case that does not require
- * a PM context. The C code also checks against this.
- */
- SCR_FROM_REG (rbc),
- 0,
- SCR_RETURN ^ IFFALSE (DATA (0)),
- 0,
- SCR_FROM_REG (rbc1),
- 0,
- SCR_RETURN ^ IFFALSE (DATA (0)),
- 0,
- SCR_FROM_REG (rbc2),
- 0,
- SCR_RETURN ^ IFFALSE (DATA (0)),
- 0,
- /*
- * RBC[0..23]=0.
- * Not only we donnot need a PM context, but this would
- * lead to a bogus CHMOV(0). This condition means that
- * the residual was the last byte to move from this CHMOV.
- * So, we just have to move the current data script pointer
- * (i.e. TEMP) to the SCRIPTS address following the
- * interrupted CHMOV and jump to dispatcher.
- */
- SCR_STORE_ABS (ia, 4),
- PADDRH (scratch),
- SCR_LOAD_ABS (temp, 4),
- PADDRH (scratch),
- SCR_JUMP,
- PADDR (dispatch),
- }/*--------------------------< WSR_MA_HELPER >-----------------------*/,{
- /*
- * Helper for the C code when WSR bit is set.
- * Perform the move of the residual byte.
- */
- SCR_CHMOV_TBL ^ SCR_DATA_IN,
- offsetof (struct ccb, phys.wresid),
- SCR_JUMP,
- PADDR (dispatch),
- }/*-------------------------< ZERO >------------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< SCRATCH >---------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< SCRATCH1 >--------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< PM0_DATA_ADDR >---------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< PM1_DATA_ADDR >---------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< SAVED_DSA >-------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< SAVED_DRS >-------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< DONE_POS >--------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< STARTPOS >--------------------*/,{
- SCR_DATA_ZERO,
- }/*-------------------------< TARGTBL >---------------------*/,{
- SCR_DATA_ZERO,
- /*
- ** We may use MEMORY MOVE instructions to load the on chip-RAM,
- ** if it happens that mapping PCI memory is not possible.
- ** But writing the RAM from the CPU is the preferred method,
- ** since PCI 2.2 seems to disallow PCI self-mastering.
- */
- #ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
- }/*-------------------------< START_RAM >-------------------*/,{
- /*
- ** Load the script into on-chip RAM,
- ** and jump to start point.
- */
- SCR_COPY (sizeof (struct script)),
- }/*-------------------------< SCRIPT0_BA >--------------------*/,{
- 0,
- PADDR (start),
- SCR_JUMP,
- PADDR (init),
- }/*-------------------------< START_RAM64 >--------------------*/,{
- /*
- ** Load the RAM and start for 64 bit PCI (895A,896).
- ** Both scripts (script and scripth) are loaded into
- ** the RAM which is 8K (4K for 825A/875/895).
- ** We also need to load some 32-63 bit segments
- ** address of the SCRIPTS processor.
- ** LOAD/STORE ABSOLUTE always refers to on-chip RAM
- ** in our implementation. The main memory is
- ** accessed using LOAD/STORE DSA RELATIVE.
- */
- SCR_LOAD_REL (mmws, 4),
- offsetof (struct ncb, scr_ram_seg),
- SCR_COPY (sizeof(struct script)),
- }/*-------------------------< SCRIPT0_BA64 >--------------------*/,{
- 0,
- PADDR (start),
- SCR_COPY (sizeof(struct scripth)),
- }/*-------------------------< SCRIPTH0_BA64 >--------------------*/,{
- 0,
- PADDRH (start64),
- SCR_LOAD_REL (mmrs, 4),
- offsetof (struct ncb, scr_ram_seg),
- SCR_JUMP64,
- PADDRH (start64),
- }/*-------------------------< RAM_SEG64 >--------------------*/,{
- 0,
- #endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
- }/*-------------------------< SNOOPTEST >-------------------*/,{
- /*
- ** Read the variable.
- */
- SCR_LOAD_REL (scratcha, 4),
- offsetof(struct ncb, ncr_cache),
- SCR_STORE_REL (temp, 4),
- offsetof(struct ncb, ncr_cache),
- SCR_LOAD_REL (temp, 4),
- offsetof(struct ncb, ncr_cache),
- }/*-------------------------< SNOOPEND >-------------------*/,{
- /*
- ** And stop.
- */
- SCR_INT,
- 99,
- }/*--------------------------------------------------------*/
- };
- /*==========================================================
- **
- **
- ** Fill in #define dependent parts of the script
- **
- **
- **==========================================================
- */
- void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
- {
- int i;
- ncrcmd *p;
- p = scr->data_in;
- for (i=0; i<MAX_SCATTER; i++) {
- *p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
- p = scr->data_out;
- for (i=0; i<MAX_SCATTER; i++) {
- *p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
- }
- /*==========================================================
- **
- **
- ** Copy and rebind a script.
- **
- **
- **==========================================================
- */
- static void __init
- ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
- {
- ncrcmd opcode, new, old, tmp1, tmp2;
- ncrcmd *start, *end;
- int relocs;
- int opchanged = 0;
- start = src;
- end = src + len/4;
- while (src < end) {
- opcode = *src++;
- *dst++ = cpu_to_scr(opcode);
- /*
- ** If we forget to change the length
- ** in struct script, a field will be
- ** padded with 0. This is an illegal
- ** command.
- */
- if (opcode == 0) {
- printk (KERN_INFO "%s: ERROR0 IN SCRIPT at %d.n",
- ncr_name(np), (int) (src-start-1));
- MDELAY (10000);
- continue;
- };
- /*
- ** We use the bogus value 0xf00ff00f ;-)
- ** to reserve data area in SCRIPTS.
- */
- if (opcode == SCR_DATA_ZERO) {
- dst[-1] = 0;
- continue;
- }
- if (DEBUG_FLAGS & DEBUG_SCRIPT)
- printk (KERN_INFO "%p: <%x>n",
- (src-1), (unsigned)opcode);
- /*
- ** We don't have to decode ALL commands
- */
- switch (opcode >> 28) {
- case 0xf:
- /*
- ** LOAD / STORE DSA relative, don't relocate.
- */
- relocs = 0;
- break;
- case 0xe:
- /*
- ** LOAD / STORE absolute.
- */
- relocs = 1;
- break;
- case 0xc:
- /*
- ** COPY has TWO arguments.
- */
- relocs = 2;
- tmp1 = src[0];
- tmp2 = src[1];
- #ifdef RELOC_KVAR
- if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
- tmp1 = 0;
- if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
- tmp2 = 0;
- #endif
- if ((tmp1 ^ tmp2) & 3) {
- printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.n",
- ncr_name(np), (int) (src-start-1));
- MDELAY (1000);
- }
- /*
- ** If PREFETCH feature not enabled, remove
- ** the NO FLUSH bit if present.
- */
- if ((opcode & SCR_NO_FLUSH) &&
- !(np->features & FE_PFEN)) {
- dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
- ++opchanged;
- }
- break;
- case 0x0:
- /*
- ** MOVE/CHMOV (absolute address)
- */
- if (!(np->features & FE_WIDE))
- dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
- relocs = 1;
- break;
- case 0x1:
- /*
- ** MOVE/CHMOV (table indirect)
- */
- if (!(np->features & FE_WIDE))
- dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
- relocs = 0;
- break;
- case 0x8:
- /*
- ** JUMP / CALL
- ** dont't relocate if relative :-)
- */
- if (opcode & 0x00800000)
- relocs = 0;
- else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
- relocs = 2;
- else
- relocs = 1;
- break;
- case 0x4:
- case 0x5:
- case 0x6:
- case 0x7:
- relocs = 1;
- break;
- default:
- relocs = 0;
- break;
- };
- if (!relocs) {
- *dst++ = cpu_to_scr(*src++);
- continue;
- }
- while (relocs--) {
- old = *src++;
- switch (old & RELOC_MASK) {
- case RELOC_REGISTER:
- new = (old & ~RELOC_MASK) + np->base_ba;
- break;
- case RELOC_LABEL:
- new = (old & ~RELOC_MASK) + np->p_script;
- break;
- case RELOC_LABELH:
- new = (old & ~RELOC_MASK) + np->p_scripth;
- break;
- case RELOC_SOFTC:
- new = (old & ~RELOC_MASK) + np->p_ncb;
- break;
- #ifdef RELOC_KVAR
- case RELOC_KVAR:
- new=0;
- if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) ||
- ((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST))
- panic("ncr KVAR out of range");
- new = vtobus(script_kvars[old & ~RELOC_MASK]);
- #endif
- break;
- case 0:
- /* Don't relocate a 0 address. */
- if (old == 0) {
- new = old;
- break;
- }
- /* fall through */
- default:
- new = 0; /* For 'cc' not to complain */
- panic("ncr_script_copy_and_bind: "
- "weird relocation %xn", old);
- break;
- }
- *dst++ = cpu_to_scr(new);
- }
- };
- }
- /*==========================================================
- **
- **
- ** Auto configuration: attach and init a host adapter.
- **
- **
- **==========================================================
- */
- /*
- ** Linux host data structure.
- */
- struct host_data {
- struct ncb *ncb;
- };
- /*
- ** Print something which allows to retrieve the controler type, unit,
- ** target, lun concerned by a kernel message.
- */
- static void PRINT_TARGET(ncb_p np, int target)
- {
- printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target);
- }
- static void PRINT_LUN(ncb_p np, int target, int lun)
- {
- printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun);
- }
- static void PRINT_ADDR(Scsi_Cmnd *cmd)
- {
- struct host_data *host_data = (struct host_data *) cmd->host->hostdata;
- PRINT_LUN(host_data->ncb, cmd->target, cmd->lun);
- }
- /*==========================================================
- **
- ** NCR chip clock divisor table.
- ** Divisors are multiplied by 10,000,000 in order to make
- ** calculations more simple.
- **
- **==========================================================
- */
- #define _5M 5000000
- static u_long div_10M[] =
- {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
- /*===============================================================
- **
- ** Prepare io register values used by ncr_init() according
- ** to selected and supported features.
- **
- ** NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
- ** 128 transfers. All chips support at least 16 transfers bursts.
- ** The 825A, 875 and 895 chips support bursts of up to 128
- ** transfers and the 895A and 896 support bursts of up to 64
- ** transfers. All other chips support up to 16 transfers bursts.
- **
- ** For PCI 32 bit data transfers each transfer is a DWORD (4 bytes).
- ** It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
- ** Only the 896 is able to perform 64 bit data transfers.
- **
- ** We use log base 2 (burst length) as internal code, with
- ** value 0 meaning "burst disabled".
- **
- **===============================================================
- */
- /*
- * Burst length from burst code.
- */
- #define burst_length(bc) (!(bc))? 0 : 1 << (bc)
- /*
- * Burst code from io register bits.
- */
- #define burst_code(dmode, ctest4, ctest5)
- (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
- /*
- * Set initial io register bits from burst code.
- */
- static inline void ncr_init_burst(ncb_p np, u_char bc)
- {
- np->rv_ctest4 &= ~0x80;
- np->rv_dmode &= ~(0x3 << 6);
- np->rv_ctest5 &= ~0x4;
- if (!bc) {
- np->rv_ctest4 |= 0x80;
- }
- else {
- --bc;
- np->rv_dmode |= ((bc & 0x3) << 6);
- np->rv_ctest5 |= (bc & 0x4);
- }
- }
- #ifdef SCSI_NCR_NVRAM_SUPPORT
- /*
- ** Get target set-up from Symbios format NVRAM.
- */
- static void __init
- ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
- {
- tcb_p tp = &np->target[target];
- Symbios_target *tn = &nvram->target[target];
- tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
- tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
- tp->usrtags =
- (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
- if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
- tp->usrflag |= UF_NODISC;
- if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
- tp->usrflag |= UF_NOSCAN;
- }
- /*
- ** Get target set-up from Tekram format NVRAM.
- */
- static void __init
- ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
- {
- tcb_p tp = &np->target[target];
- struct Tekram_target *tn = &nvram->target[target];
- int i;
- if (tn->flags & TEKRAM_SYNC_NEGO) {
- i = tn->sync_index & 0xf;
- tp->usrsync = Tekram_sync[i];
- }
- tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
- if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
- tp->usrtags = 2 << nvram->max_tags_index;
- }
- if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE))
- tp->usrflag = UF_NODISC;
-
- /* If any device does not support parity, we will not use this option */
- if (!(tn->flags & TEKRAM_PARITY_CHECK))
- np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */
- }
- #endif /* SCSI_NCR_NVRAM_SUPPORT */
- /*
- ** Save initial settings of some IO registers.
- ** Assumed to have been set by BIOS.
- */
- static void __init ncr_save_initial_setting(ncb_p np)
- {
- np->sv_scntl0 = INB(nc_scntl0) & 0x0a;
- np->sv_dmode = INB(nc_dmode) & 0xce;
- np->sv_dcntl = INB(nc_dcntl) & 0xa8;
- np->sv_ctest3 = INB(nc_ctest3) & 0x01;
- np->sv_ctest4 = INB(nc_ctest4) & 0x80;
- np->sv_gpcntl = INB(nc_gpcntl);
- np->sv_stest2 = INB(nc_stest2) & 0x20;
- np->sv_stest4 = INB(nc_stest4);
- np->sv_stest1 = INB(nc_stest1);
- np->sv_scntl3 = INB(nc_scntl3) & 0x07;
-
- if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
- (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) ){
- /*
- ** C1010 always uses large fifo, bit 5 rsvd
- ** scntl4 used ONLY with C1010
- */
- np->sv_ctest5 = INB(nc_ctest5) & 0x04 ;
- np->sv_scntl4 = INB(nc_scntl4);
- }
- else {
- np->sv_ctest5 = INB(nc_ctest5) & 0x24 ;
- np->sv_scntl4 = 0;
- }
- }
- /*