📄 sym53c8xx_comm.h
字号:
/******************************************************************************** High Performance device driver for the Symbios 53C896 controller.**** Copyright (C) 1998-2000 Gerard Roudier <groudier@club-internet.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@club-internet.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>**********************************************************************************//*** This file contains definitions and code that the ** sym53c8xx and ncr53c8xx drivers should share.** The sharing will be achieved in a further version ** of the driver bundle. For now, only the ncr53c8xx ** driver includes this file.*/#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/*==========================================================**** Io mapped versus memory mapped.****==========================================================*/#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)#define NCR_IOMAPPED#endif/*==========================================================**** Miscallaneous 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 bcmp#define bcmp(s, d, n) memcmp((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/*==========================================================**** 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__); \ } \}/*==========================================================**** Debugging tags****==========================================================*/#define DEBUG_ALLOC (0x0001)#define DEBUG_PHASE (0x0002)#define DEBUG_QUEUE (0x0008)#define DEBUG_RESULT (0x0010)#define DEBUG_POINTER (0x0020)#define DEBUG_SCRIPT (0x0040)#define DEBUG_TINY (0x0080)#define DEBUG_TIMING (0x0100)#define DEBUG_NEGO (0x0200)#define DEBUG_TAGS (0x0400)#define DEBUG_SCATTER (0x0800)#define DEBUG_IC (0x1000)/*** Enable/Disable debug messages.** Can be changed at runtime too.*/#ifdef SCSI_NCR_DEBUG_INFO_SUPPORTstatic int ncr_debug = SCSI_NCR_DEBUG_FLAGS; #define DEBUG_FLAGS ncr_debug#else #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS#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;}/*==========================================================**** On x86 architecture, write buffers management does ** not reorder writes to memory. So, using compiler ** optimization barriers is enough to guarantee some ** ordering when the CPU is writing data accessed by ** the NCR.** On Alpha architecture, explicit memory barriers have ** to be used.** Other architectures are defaulted to mb() macro if ** defined, otherwise use compiler barrier.****==========================================================*/#if defined(__i386__)#define MEMORY_BARRIER() barrier()#elif defined(__alpha__)#define MEMORY_BARRIER() mb()#else# ifdef mb# define MEMORY_BARRIER() mb()# else# define MEMORY_BARRIER() barrier()# endif#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#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)static int __init pci_get_base_address(struct pci_dev *pdev, int index, u_long *base){ *base = pdev->resource[index].start; if ((pdev->resource[index].flags & 0x7) == 0x4) ++index; return ++index;}#elsestatic int __init pci_get_base_address(struct pci_dev *pdev, int index, u_long *base){ *base = pdev->base_address[index++]; if ((*base & 0x7) == 0x4) {#if BITS_PER_LONG > 32 *base |= (((u_long)pdev->base_address[index]) << 32);#endif ++index; } return index;}#endif#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 __initpci_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;}#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) *//*==========================================================**** 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.: by controller).****==========================================================*/#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)spinlock_t DRIVER_SMP_LOCK = SPIN_LOCK_UNLOCKED;#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&DRIVER_SMP_LOCK, flags)#define NCR_UNLOCK_DRIVER(flags) \ spin_unlock_irqrestore(&DRIVER_SMP_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 and iounmap() to unmap it. This 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 pcivtobus(p) bus_dvma_to_mem(p)# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))#elif defined(__alpha__)# define pcivtobus(p) ((p) & 0xfffffffful)# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))#else /* others */# define pcivtobus(p) (p)# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))#endif#if (defined(SCSI_NCR_NVRAM_SUPPORT) && !defined(NCR_IOMAPPED)) || \ (defined(__i386__) && !defined(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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -