⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ncr53c8xx.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************************************************************  Device driver for the PCI-SCSI NCR538XX controller family.****  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.****-----------------------------------------------------------------------------****  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver**  and is currently maintained 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>****  And has been ported to NetBSD by**          Charles M. Hannum           <mycroft@gnu.ai.mit.edu>****-----------------------------------------------------------------------------****                     Brief history****  December 10 1995 by Gerard Roudier:**     Initial port to Linux.****  June 23 1996 by Gerard Roudier:**     Support for 64 bits architectures (Alpha).****  November 30 1996 by Gerard Roudier:**     Support for Fast-20 scsi.**     Support for large DMA fifo and 128 dwords bursting.****  February 27 1997 by Gerard Roudier:**     Support for Fast-40 scsi.**     Support for on-Board RAM.****  May 3 1997 by Gerard Roudier:**     Full support for scsi scripts instructions pre-fetching.****  May 19 1997 by Richard Waltham <dormouse@farsrobt.demon.co.uk>:**     Support for NvRAM detection and reading.****  August 18 1997 by Cort <cort@cs.nmt.edu>:**     Support for Power/PC (Big Endian).**********************************************************************************//***	30 January 1998, version 2.5f.1****	Supported SCSI-II features:**	    Synchronous negotiation**	    Wide negotiation        (depends on the NCR Chip)**	    Enable disconnection**	    Tagged command queuing**	    Parity checking**	    Etc...****	Supported NCR chips:**		53C810		(8 bits, Fast SCSI-2, no rom BIOS) **		53C815		(8 bits, Fast SCSI-2, on board rom BIOS)**		53C820		(Wide,   Fast SCSI-2, no rom BIOS)**		53C825		(Wide,   Fast SCSI-2, on board rom BIOS)**		53C860		(8 bits, Fast 20,     no rom BIOS)**		53C875		(Wide,   Fast 20,     on board rom BIOS)**		53C895		(Wide,   Fast 40,     on board rom BIOS)****	Other features:**		Memory mapped IO (linux-1.3.X and above only)**		Module**		Shared IRQ (since linux-1.3.72)*/#define SCSI_NCR_DEBUG_FLAGS	(0)		#define NCR_GETCC_WITHMSG/*==========================================================****      Include files****==========================================================*/#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))#ifdef MODULE#include <linux/module.h>#endif#include <asm/dma.h>#include <asm/io.h>#include <asm/system.h>#include <linux/delay.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/bios32.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>#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)#include <linux/blk.h>#else#include "../block/blk.h"#endif#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)#include <linux/init.h>#else#ifndef	__initdata#define	__initdata#endif#ifndef	__initfunc#define	__initfunc(__arginit) __arginit#endif#endif#include "scsi.h"#include "hosts.h"#include "constants.h"#include "sd.h"#include <linux/types.h>/***	Define the BSD style u_int32 type*/typedef u32 u_int32;#include "ncr53c8xx.h"/*==========================================================****	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 disk devices that support tags.*/#ifndef SCSI_NCR_MAX_TAGS#define SCSI_NCR_MAX_TAGS    (4)#endif/***    Number of targets supported by the driver.**    n permits target numbers 0..n-1.**    Default is 7, meaning targets #0..#6.**    #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    SCSI_NCR_MAX_LUN#else#define MAX_LUN    (1)#endif/***    Asynchronous pre-scaler (ns). Shall be 40*/ #ifndef SCSI_NCR_MIN_ASYNC#define SCSI_NCR_MIN_ASYNC (40)#endif/***    The maximum number of jobs scheduled for starting.**    There should be one slot per target, and one slot**    for each tag of each target in use.**    The calculation below is actually quite silly ...*/#ifdef SCSI_NCR_CAN_QUEUE#define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)#else#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)#endif/***    The maximum number of segments a transfer is split into.*/#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)/***    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 printf		printk#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;#define bcopy(s, d, n)	memcpy((d), (s), (n))#define bzero(d, n)	memset((d), 0, (n))#ifndef offsetof#define offsetof(t, m)	((size_t) (&((t *)0)->m))#endif/***	Address translation****	On Linux 1.3.X, virt_to_bus() must be used to translate**	virtual memory addresses of the kernel data segment into**	IO bus adresses.**	On i386 architecture, IO bus addresses match the physical**	addresses. But on other architectures they can be different.**	In the original Bsd driver, vtophys() is called to translate**	data addresses to IO bus addresses. In order to minimize**	change, I decide to define vtophys() as virt_to_bus().*/#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)#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.*/#ifndef 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;#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)	u_long page_remapped	= (u_long) ioremap(page_base, page_offs+size);#else	u_long page_remapped	= (u_long) vremap(page_base, page_offs+size);#endif	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)#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)		iounmap((void *) (vaddr & PAGE_MASK));#else		vfree((void *) (vaddr & PAGE_MASK));#endif}#endif	/* !NCR_IOMAPPED */#else /* linux-1.2.13 *//***	Linux 1.2.X assumes that addresses (virtual, physical, bus)**	are the same.****	I have not found how to do MMIO. It seems that only processes can**	map high physical pages to virtual (Xservers can do MMIO).*/#define vtophys(p)	((u_long) (p))#endif/***	Insert a delay in micro-seconds.*/static void DELAY(long us){	for (;us>1000;us-=1000) udelay(1000);	if (us) udelay(us);}/***	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.**	I notice that kmalloc() returns NULL during host attach under**	Linux 1.2.13. But this ncr driver is reliable enough to**	accomodate with this joke.****	kmalloc() only ensure 8 bytes boundary alignment.**	The NCR need better alignment for cache line bursting.**	The global header is moved betewen the NCB and CCBs and need **	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 NCB_ALIGN_SHIFT		5#define CCB_ALIGN_SHIFT		5#define LCB_ALIGN_SHIFT		5#define SCR_ALIGN_SHIFT		5#define NCB_ALIGN_SIZE		ALIGN_SIZE(NCB_ALIGN_SHIFT)#define NCB_ALIGN_MASK		ALIGN_MASK(NCB_ALIGN_SHIFT)#define CCB_ALIGN_SIZE		ALIGN_SIZE(CCB_ALIGN_SHIFT)#define CCB_ALIGN_MASK		ALIGN_MASK(CCB_ALIGN_SHIFT)#define SCR_ALIGN_SIZE		ALIGN_SIZE(SCR_ALIGN_SHIFT)#define SCR_ALIGN_MASK		ALIGN_MASK(SCR_ALIGN_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 XferNone	0#define XferIn		1#define XferOut		2#define XferBoth	3static int guess_xfer_direction(int opcode);/***	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*/#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)struct proc_dir_entry proc_scsi_ncr53c8xx = {    PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx",    S_IFDIR | S_IRUGO | S_IXUGO, 2};# ifdef SCSI_NCR_PROC_INFO_SUPPORTint ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,			int length, int hostno, int func);# endif#endif/***	Table of target capabilities.****	This bitmap is anded with the byte 7 of inquiry data on completion of**	INQUIRY command.** 	The driver never see zeroed bits and will ignore the corresponding**	capabilities of the target.*/static struct {	unsigned char and_map[MAX_TARGET];} target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES };/***	Driver setup.****	This structure is initialized from linux config options.**	It can be overridden at boot-up by the boot command line.*/struct ncr_driver_setup {	unsigned master_parity	: 1;	unsigned scsi_parity	: 1;	unsigned disconnection	: 1;	unsigned special_features : 2;	unsigned ultra_scsi	: 2;	unsigned force_sync_nego: 1;	unsigned reverse_probe: 1;	unsigned pci_fix_up: 4;	u_char	use_nvram;	u_char	verbose;	u_char	default_tags;	u_short	default_sync;	u_short	debug;	u_char	burst_max;	u_char	led_pin;	u_char	max_wide;	u_char	settle_delay;	u_char	diff_support;	u_char	irqm;	u_char	bus_check;};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 */#endif#endif/***	Other Linux definitions*/#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist);#endif#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);#elsestatic void ncr53c8xx_intr(int irq, struct pt_regs * regs);#endifstatic void ncr53c8xx_timeout(unsigned long np);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -