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

📄 sym_glue.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family  * of PCI-SCSI IO processors. * * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr> * * This driver is derived from the Linux sym53c8xx driver. * Copyright (C) 1998-2000  Gerard Roudier * * The sym53c8xx driver is derived from the ncr53c8xx driver that had been  * a port of the FreeBSD ncr driver to Linux-1.2.13. * * The original ncr driver has been written for 386bsd and FreeBSD by *         Wolfgang Stanglmeier        <wolf@cologne.de> *         Stefan Esser                <se@mi.Uni-Koeln.de> * Copyright (C) 1994  Wolfgang Stanglmeier * * Other major contributions: * * NVRAM detection and reading. * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> * *----------------------------------------------------------------------------- * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of  * the GNU Public License ("GPL") and the terms of the GPL would require the  * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that * conflict with, or are expressly prohibited by, the GPL. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#define SYM_GLUE_C#include <linux/module.h>#include "sym_glue.h"#define NAME53C		"sym53c"#define NAME53C8XX	"sym53c8xx"/* *  Simple Wrapper to kernel PCI bus interface. */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)->irqstatic u_long __initpci_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 __initpci_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}#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)	do { ;} while (0)#endif/* *  Insert a delay in micro-seconds and milli-seconds. */void sym_udelay(int us) { udelay(us); }void sym_mdelay(int ms) { mdelay(ms); }/* *  SMP threading. * *  The whole SCSI sub-system under Linux is basically single-threaded. *  Everything, including low-level driver interrupt routine, happens  *  whith the `io_request_lock' held. *  The sym53c8xx-1.x drivers series ran their interrupt code using a  *  spin mutex per controller. This added complexity without improving  *  scalability significantly. the sym-2 driver still use a spinlock  *  per controller for safety, but basically runs with the damned  *  io_request_lock held. */spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED;#define	SYM_LOCK_DRIVER(flags)    spin_lock_irqsave(&sym53c8xx_lock, flags)#define	SYM_UNLOCK_DRIVER(flags)  spin_unlock_irqrestore(&sym53c8xx_lock,flags)#define SYM_INIT_LOCK_HCB(np)     spin_lock_init(&np->s.smp_lock);#define	SYM_LOCK_HCB(np, flags)   spin_lock_irqsave(&np->s.smp_lock, flags)#define	SYM_UNLOCK_HCB(np, flags) spin_unlock_irqrestore(&np->s.smp_lock, flags)#define	SYM_LOCK_SCSI(np, flags) \		spin_lock_irqsave(&io_request_lock, flags)#define	SYM_UNLOCK_SCSI(np, flags) \		spin_unlock_irqrestore(&io_request_lock, flags)/* Ugly, but will make things easier if this locking will ever disappear */#define	SYM_LOCK_SCSI_NOSAVE(np)	spin_lock_irq(&io_request_lock)#define	SYM_UNLOCK_SCSI_NORESTORE(np)	spin_unlock_irq(&io_request_lock)/* *  These simple macros limit expression involving  *  kernel time values (jiffies) to some that have  *  chance not to be too much incorrect. :-) */#define ktime_get(o)		(jiffies + (u_long) o)#define ktime_exp(b)		((long)(jiffies) - (long)(b) >= 0)#define ktime_dif(a, b)		((long)(a) - (long)(b))#define ktime_add(a, o)		((a) + (u_long)(o))#define ktime_sub(a, o)		((a) - (u_long)(o))/* *  Wrappers to the generic memory allocator. */void *sym_calloc(int size, char *name){	u_long flags;	void *m;	SYM_LOCK_DRIVER(flags);	m = sym_calloc_unlocked(size, name);	SYM_UNLOCK_DRIVER(flags);	return m;}void sym_mfree(void *m, int size, char *name){	u_long flags;	SYM_LOCK_DRIVER(flags);	sym_mfree_unlocked(m, size, name);	SYM_UNLOCK_DRIVER(flags);}#ifdef	SYM_LINUX_DYNAMIC_DMA_MAPPINGvoid *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name){	u_long flags;	void *m;	SYM_LOCK_DRIVER(flags);	m = __sym_calloc_dma_unlocked(dev_dmat, size, name);	SYM_UNLOCK_DRIVER(flags);	return m;}void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name){	u_long flags;	SYM_LOCK_DRIVER(flags);	__sym_mfree_dma_unlocked(dev_dmat, m, size, name);	SYM_UNLOCK_DRIVER(flags);}m_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m){	u_long flags;	m_addr_t b;	SYM_LOCK_DRIVER(flags);	b = __vtobus_unlocked(dev_dmat, m);	SYM_UNLOCK_DRIVER(flags);	return b;}#endif	/* SYM_LINUX_DYNAMIC_DMA_MAPPING *//* *  Map/unmap a PCI memory window. */#ifndef SYM_OPT_NO_BUS_MEMORY_MAPPINGstatic u_long __init pci_map_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 pci_unmap_mem(u_long vaddr, u_long size){	if (vaddr)		iounmap((void *) (vaddr & PAGE_MASK));}#endif/* *  Used to retrieve the host structure when the  *  driver is called from the proc FS. */static struct Scsi_Host	*first_host = NULL;/* *  /proc directory entry and proc_info. */#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/* *  Transfer direction * *  Until some linux kernel version near 2.3.40, low-level scsi  *  drivers were not told about data transfer direction. */#if LINUX_VERSION_CODE > LinuxVersionCode(2, 3, 40)#define scsi_data_direction(cmd)	(cmd->sc_data_direction)#elsestatic __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/* *  Driver host data structure. */struct host_data {     hcb_p ncb;};/* * Some type that fit DMA addresses as seen from BUS. */#ifndef SYM_LINUX_DYNAMIC_DMA_MAPPINGtypedef u_long		bus_addr_t;#else#if	SYM_CONF_DMA_ADDRESSING_MODE > 0typedef dma64_addr_t	bus_addr_t;#elsetypedef dma_addr_t	bus_addr_t;#endif#endif/* *  Used by the eh thread to wait for command completion. *  It is allocated on the eh thread stack. */struct sym_eh_wait {	struct semaphore sem;	struct timer_list timer;	void (*old_done)(Scsi_Cmnd *);	int to_do;	int timed_out;};/* *  Driver private area in the SCSI command structure. */struct sym_ucmd {		/* Override the SCSI pointer structure */	SYM_QUEHEAD link_cmdq;	/* Must stay at offset ZERO */#ifdef SYM_LINUX_DYNAMIC_DMA_MAPPING	bus_addr_t data_mapping;	u_char	data_mapped;#endif	struct sym_eh_wait *eh_wait;};typedef struct sym_ucmd *ucmd_p;#define SYM_UCMD_PTR(cmd)  ((ucmd_p)(&(cmd)->SCp))#define SYM_SCMD_PTR(ucmd) sym_que_entry(ucmd, Scsi_Cmnd, SCp)#define SYM_SOFTC_PTR(cmd) (((struct host_data *)cmd->host->hostdata)->ncb)/* *  Deal with DMA mapping/unmapping. */#ifndef SYM_LINUX_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 bus_sg_dma_address(sc)		vtobus((sc)->address)#define bus_sg_dma_len(sc)		((sc)->length)#else /* Linux version with pci bus iommu kernel interface */#define	bus_unmap_sg(pdev, sgptr, sgcnt, dir)		\	pci_unmap_sg(pdev, sgptr, sgcnt, dir)#define	bus_unmap_single(pdev, mapping, bufptr, dir)	\	pci_unmap_single(pdev, mapping, bufptr, dir)#define	bus_map_single(pdev, bufptr, bufsiz, dir)	\	pci_map_single(pdev, bufptr, bufsiz, dir) #define	bus_map_sg(pdev, sgptr, sgcnt, dir)		\	pci_map_sg(pdev, sgptr, sgcnt, dir)#define	bus_dma_sync_sg(pdev, sgptr, sgcnt, dir)	\	pci_dma_sync_sg(pdev, sgptr, sgcnt, dir)#define	bus_dma_sync_single(pdev, mapping, bufsiz, dir)	\	pci_dma_sync_single(pdev, mapping, bufsiz, dir)#define bus_sg_dma_address(sc)	sg_dma_address(sc)#define bus_sg_dma_len(sc)	sg_dma_len(sc)static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd){	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);	switch(SYM_UCMD_PTR(cmd)->data_mapped) {	case 2:		bus_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);		break;	case 1:		bus_unmap_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,				 cmd->request_bufflen, dma_dir);		break;	}	SYM_UCMD_PTR(cmd)->data_mapped = 0;}static bus_addr_t __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd){	bus_addr_t mapping;	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);	mapping = bus_map_single(pdev, cmd->request_buffer,				 cmd->request_bufflen, dma_dir);	if (mapping) {		SYM_UCMD_PTR(cmd)->data_mapped  = 1;		SYM_UCMD_PTR(cmd)->data_mapping = 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);	use_sg = bus_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);	if (use_sg > 0) {		SYM_UCMD_PTR(cmd)->data_mapped  = 2;		SYM_UCMD_PTR(cmd)->data_mapping = 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(SYM_UCMD_PTR(cmd)->data_mapped) {	case 2:		bus_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);		break;	case 1:		bus_dma_sync_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,				    cmd->request_bufflen, dma_dir);		break;	}}#endif	/* SYM_LINUX_DYNAMIC_DMA_MAPPING */#define unmap_scsi_data(np, cmd)	\		__unmap_scsi_data(np->s.device, cmd)#define map_scsi_single_data(np, cmd)	\		__map_scsi_single_data(np->s.device, cmd)#define map_scsi_sg_data(np, cmd)	\		__map_scsi_sg_data(np->s.device, cmd)#define sync_scsi_data(np, cmd)		\		__sync_scsi_data(np->s.device, cmd)/* *  Complete a pending CAM CCB. */void sym_xpt_done(hcb_p np, Scsi_Cmnd *ccb){	sym_remque(&SYM_UCMD_PTR(ccb)->link_cmdq);	unmap_scsi_data(np, ccb);	ccb->scsi_done(ccb);}void sym_xpt_done2(hcb_p np, Scsi_Cmnd *ccb, int cam_status){	sym_set_cam_status(ccb, cam_status);	sym_xpt_done(np, ccb);}/* *  Print something that identifies the IO. */void sym_print_addr (ccb_p cp){	Scsi_Cmnd *cmd = cp->cam_ccb;	if (cmd)		printf("%s:%d:%d:", sym_name(SYM_SOFTC_PTR(cmd)),		       cmd->target,cmd->lun);}/* *  Tell the SCSI layer about a BUS RESET. */void sym_xpt_async_bus_reset(hcb_p np){	printf_notice("%s: SCSI BUS has been reset.\n", sym_name(np));	np->s.settle_time = ktime_get(sym_driver_setup.settle_delay * HZ);	np->s.settle_time_valid = 1;	if (sym_verbose >= 2)		printf_info("%s: command processing suspended for %d seconds\n",		            sym_name(np), sym_driver_setup.settle_delay);}/* *  Tell the SCSI layer about a BUS DEVICE RESET message sent. */void sym_xpt_async_sent_bdr(hcb_p np, int target){	printf_notice("%s: TARGET %d has been reset.\n", sym_name(np), target);}/* *  Tell the SCSI layer about the new transfer parameters. */void sym_xpt_async_nego_wide(hcb_p np, int target){	if (sym_verbose < 3)		return;	sym_announce_transfer_rate(np, target);}/* *  Choose the more appropriate CAM status if  *  the IO encountered an extended error. */static int sym_xerr_cam_status(int cam_status, int x_status){	if (x_status) {		if	(x_status & XE_PARITY_ERR)			cam_status = DID_PARITY;		else if	(x_status &(XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN))			cam_status = DID_ERROR;		else if	(x_status & XE_BAD_PHASE)			cam_status = DID_ERROR;		else			cam_status = DID_ERROR;	}	return cam_status;}/* *  Build CAM result for a failed or auto-sensed IO. */void sym_set_cam_result_error(hcb_p np, ccb_p cp, int resid){	Scsi_Cmnd *csio = cp->cam_ccb;	u_int cam_status, scsi_status, drv_status;

⌨️ 快捷键说明

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