blob: 2f48457dfd4cf4e036be4d06b303392e7d817c07 [file] [log] [blame]
/******************************************************************************
** 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/interrupt.h>
#include <linux/signal.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 <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(host, flags) \
spin_lock_irqsave(((host)->host_lock), flags)
#define NCR_UNLOCK_SCSI_DONE(host, flags) \
spin_unlock_irqrestore(((host)->host_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(host, flags) do {;} while (0)
#define NCR_UNLOCK_SCSI_DONE(host, 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) = %p\n", size, (void *) a);
#endif
return (void *) a;
}
static void ___m_free(m_pool_s *mp, void *ptr, int size)
{
int i = 0;
int s = (1 << MEMO_SHIFT);
m_link_s *q;
m_addr_t a, b;
m_link_s *h = mp->h;
#ifdef DEBUG
printk("___m_free(%p, %d)\n", ptr, size);
#endif
if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
return;
while (size > s) {
s <<= 1;
++i;
}
a = (m_addr_t) ptr;
while (1) {
#ifdef MEMO_FREE_UNUSED
if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
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 */
/*
** /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_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 %d\n", \
#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 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 loses arbitration.
** This is ok, because it will try again,
** when the bus becomes idle.
** (But beware of the timeout function!)
**
** (2) The ncr is reselected.
** Then the script processor takes the jump
** to the RESELECT label.
**
** (3) The ncr wins arbitration.
** Then it will execute SCRIPTS instruction until
** the next instruction that checks SCSI phase.
** Then will stop and wait for selection to be
** complete or selection time-out to occur.
**
** 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 ...