📄 ncr53c8xx.c
字号:
** Io mapped or memory mapped.*/#if defined(SCSI_NCR_IOMAPPED)#define NCR_IOMAPPED#endif/*** other*/#define NCR_SNOOP_TIMEOUT (1000000)/*==========================================================**** Defines for Linux.**** Linux and Bsd kernel functions are quite different.** These defines allow a minimum change of the original** code.****==========================================================*/ /* ** Obvious definitions */#define u_char unsigned char#define u_short unsigned short#define u_int unsigned int#define u_long unsigned longtypedef u_long vm_offset_t;typedef int vm_size_t;#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/*** 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)#if 0 /* not yet needed */static spinlock_t driver_lock;#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&driver_lock, flags)#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&driver_lock, flags)#endif#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)# if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99)# 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_SCSI_DONE(np, flags) do {;} while (0)# define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0)# endif#else#if 0 /* not yet needed */#define NCR_LOCK_DRIVER(flags) do {;} while (0)#define NCR_UNLOCK_DRIVER(flags) do {;} while (0)#endif#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/*** Address translation**** The driver has to provide physical memory addresses to ** the script processor. Because some architectures use ** different physical addresses from the PCI BUS, we must ** use virt_to_bus instead of virt_to_phys.*/#define vtophys(p) virt_to_bus(p)/*** 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#if defined (__sparc__)#include <asm/irq.h>#elif defined (__alpha__)#define bus_dvma_to_mem(p) ((p) & 0xfffffffful)#else#define bus_dvma_to_mem(p) (p)#endif#if defined(__i386__) || !defined(NCR_IOMAPPED)__initfunc(static vm_offset_t 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 (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL);}__initfunc(static void unmap_pci_mem(vm_offset_t vaddr, u_long size)){ if (vaddr) iounmap((void *) (vaddr & PAGE_MASK));}#endif /* __i386__ || !NCR_IOMAPPED *//*** 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#elsestatic void UDELAY(long us) { udelay(us); }static void MDELAY(long ms) { while (ms--) UDELAY(1000); }#endif/*** Internal data structure allocation.**** Linux scsi memory poor pool is adjusted for the need of** middle-level scsi driver.** We allocate our control blocks in the kernel memory pool** to avoid scsi pool shortage.**** kmalloc() only ensures 8 bytes boundary alignment.** The NCR need better alignment for cache line bursting.** The global header is moved between the NCB and CCBs and needs ** origin and destination addresses to have same lower four bits.**** We use 32 boundary alignment for NCB and CCBs and offset multiple ** of 32 for global header fields. That's too much but at least enough.*/#define ALIGN_SIZE(shift) (1UL << shift)#define ALIGN_MASK(shift) (~(ALIGN_SIZE(shift)-1))#define CACHE_LINE_SHIFT 5#define CACHE_LINE_SIZE ALIGN_SIZE(CACHE_LINE_SHIFT)#define CACHE_LINE_MASK ALIGN_MASK(CACHE_LINE_SHIFT)static void *m_alloc(int size, int a_shift){ u_long addr; void *ptr; u_long a_size, a_mask; if (a_shift < 3) a_shift = 3; a_size = ALIGN_SIZE(a_shift); a_mask = ALIGN_MASK(a_shift); ptr = (void *) kmalloc(size + a_size, GFP_ATOMIC); if (ptr) { addr = (((u_long) ptr) + a_size) & a_mask; *((void **) (addr - sizeof(void *))) = ptr; ptr = (void *) addr; } return ptr;}#ifdef MODULEstatic void m_free(void *ptr, int size){ u_long addr; if (ptr) { addr = (u_long) ptr; ptr = *((void **) (addr - sizeof(void *))); kfree(ptr); }}#endif/*** Transfer direction**** Low-level scsi drivers under Linux do not receive the expected ** data transfer direction from upper scsi drivers.** The driver will only check actual data direction for common ** scsi opcodes. Other ones may cause problem, since they may ** depend on device type or be vendor specific.** I would prefer to never trust the device for data direction, ** but that is not possible.**** The original driver requires the expected direction to be known.** The Linux version of the driver has been enhanced in order to ** be able to transfer data in the direction choosen by the target. */#define XFER_IN (1)#define XFER_OUT (2)/*** Head of list of NCR boards**** For kernel version < 1.3.70, host is retrieved by its irq level.** For later kernels, the internal host control block address ** (struct ncb) is used as device id parameter of the irq stuff.*/static struct Scsi_Host *first_host = NULL;static Scsi_Host_Template *the_template = NULL; /*** /proc directory entry and proc_info function*/static struct proc_dir_entry proc_scsi_ncr53c8xx = { PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx", S_IFDIR | S_IRUGO | S_IXUGO, 2};#ifdef SCSI_NCR_PROC_INFO_SUPPORTstatic int ncr53c8xx_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_SUPPORTstatic struct ncr_driver_setup driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;# ifdef MODULEchar *ncr53c8xx = 0; /* command line passed by insmod */# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)MODULE_PARM(ncr53c8xx, "s");# endif# endif#endif/*** Other Linux definitions*/#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))static void ncr53c8xx_select_queue_depths( struct Scsi_Host *host, struct scsi_device *devlist);static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);static void ncr53c8xx_timeout(unsigned long np);#define initverbose (driver_setup.verbose)#define bootverbose (np->verbose)#ifdef SCSI_NCR_NVRAM_SUPPORTstatic u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};#endif /* SCSI_NCR_NVRAM_SUPPORT *//*** Structures used by ncr53c8xx_detect/ncr53c8xx_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; int irq;/* port and reg fields to use INB, OUTB macros */ u_long port; 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 ncr53c8xx_detect/ncr53c8xx_pci_init** to save data on each detected board for ncr_attach().*/typedef struct { ncr_slot slot; ncr_chip chip; ncr_nvram *nvram; u_char host_id; int attach_done;} ncr_device;/*==========================================================**** Debugging tags****==========================================================*/#define DEBUG_ALLOC (0x0001)#define DEBUG_PHASE (0x0002)#define DEBUG_POLL (0x0004)#define DEBUG_QUEUE (0x0008)#define DEBUG_RESULT (0x0010)#define DEBUG_SCATTER (0x0020)#define DEBUG_SCRIPT (0x0040)#define DEBUG_TINY (0x0080)#define DEBUG_TIMING (0x0100)#define DEBUG_NEGO (0x0200)#define DEBUG_TAGS (0x0400)#define DEBUG_FREEZE (0x0800)#define DEBUG_RESTART (0x1000)/*** Enable/Disable debug messages.** Can be changed at runtime too.*/#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT #define DEBUG_FLAGS ncr_debug#else #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS#endif/*==========================================================**** assert ()****==========================================================**** modified copy from 386bsd:/usr/include/sys/assert.h****----------------------------------------------------------*/#define assert(expression) { \ if (!(expression)) { \ (void)printk(KERN_ERR \ "assertion \"%s\" failed: file \"%s\", line %d\n", \ #expression, \ __FILE__, __LINE__); \ } \}/*==========================================================**** Big/Little endian support.****==========================================================*//*** If the NCR uses big endian addressing mode over the ** PCI, actual io register addresses for byte and word ** accesses must be changed according to lane routing.** Btw, ncr_offb() and ncr_offw() macros only apply to ** constants and so donnot generate bloated code.*/#if defined(SCSI_NCR_BIG_ENDIAN)#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3))#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2))#else#define ncr_offb(o) (o)#define ncr_offw(o) (o)#endif/*** If the CPU and the NCR use same endian-ness addressing,** no byte reordering is needed for script patching.** Macro cpu_to_scr() is to be used for script patching.** Macro scr_to_cpu() is to be used for getting a DWORD ** from the script.*/#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -