📄 sym53c8xx.c
字号:
/******************************************************************************** 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>**********************************************************************************//*** May 11 2000, sym53c8xx 1.6b**** 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 - version 1.6b"/* #define DEBUG_896R1 */#define SCSI_NCR_OPTIMIZE_896/* #define SCSI_NCR_OPTIMIZE_896_1 */#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/config.h>#ifdef MODULE#include <linux/module.h>#endif#include <asm/dma.h>#include <asm/io.h>#include <asm/system.h>#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)#include <linux/spinlock.h>#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)#include <asm/spinlock.h>#endif#include <linux/delay.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/time.h>#include <linux/timer.h>#include <linux/stat.h>#include <linux/version.h>#include <linux/blk.h>#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)#include <linux/init.h>#endif#ifndef __init#define __init#endif#ifndef __initdata#define __initdata#endif#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)#include <linux/bios32.h>#endif#include "scsi.h"#include "hosts.h"#include "constants.h"#include "sd.h"#include <linux/types.h>/*** Define BITS_PER_LONG for earlier linux versions.*/#ifndef BITS_PER_LONG#if (~0UL) == 0xffffffffUL#define BITS_PER_LONG 32#else#define BITS_PER_LONG 64#endif#endif/*** Define the BSD style u_int32 and u_int64 type.** Are in fact u_int32_t and u_int64_t :-)*/typedef u32 u_int32;typedef u64 u_int64;#include "sym53c8xx.h"/*** Donnot compile integrity checking code for Linux-2.3.0 ** and above since SCSI data structures are not ready yet.*/#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0)#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;}/*==========================================================**** 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/*==========================================================**** 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)/*** Io mapped or memory mapped.*/#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)#define NCR_IOMAPPED#endif/*** 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -