nsp32.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页

C
2,409
字号
/* * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver * Copyright (C) 2001, 2002, 2003 *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> *      GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org> * * 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, 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. * * * Revision History: *   1.0: Initial Release. *   1.1: Add /proc SDTR status. *        Remove obsolete error handler nsp32_reset. *        Some clean up. *   1.2: PowerPC (big endian) support. */#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/major.h>#include <linux/blkdev.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/ctype.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include "scsi.h"#include <scsi/scsi_host.h>#include <scsi/scsi_ioctl.h>#include <scsi/scsi.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))# include <linux/blk.h>#endif#include "nsp32.h"/*********************************************************************** * Module parameters */static int       trans_mode = 0;	/* default: BIOS */MODULE_PARM     (trans_mode, "i");MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M");#define ASYNC_MODE    1#define ULTRA20M_MODE 2static int       auto_param = 0;	/* default: ON */MODULE_PARM     (auto_param, "i");MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");static int       disc_priv  = 1;	/* default: OFF */MODULE_PARM     (disc_priv,  "i");MODULE_PARM_DESC(disc_priv,  "disconnection privilege mode (0: ON 1: OFF(default))");MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module");MODULE_LICENSE("GPL");static const char *nsp32_release_version = "1.2";/**************************************************************************** * Supported hardware */static struct pci_device_id nsp32_pci_table[] __devinitdata = {	{		.vendor      = PCI_VENDOR_ID_IODATA,		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_IODATA,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_KME,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_KME,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_WBT,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_WORKBIT,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_WORKBIT_STANDARD,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_PCI_WORKBIT,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_LOGITEC,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_PCI_LOGITEC,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_PCI_MELCO,	},	{		.vendor      = PCI_VENDOR_ID_WORKBIT,		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II,		.subvendor   = PCI_ANY_ID,		.subdevice   = PCI_ANY_ID,		.driver_data = MODEL_PCI_MELCO,	},	{0,0,},};MODULE_DEVICE_TABLE(pci, nsp32_pci_table);static nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue *//* * Period/AckWidth speed conversion table * * Note: This period/ackwidth speed table must be in descending order. */static nsp32_sync_table nsp32_sync_table_40M[] = {     /* {PNo, AW,   SP,   EP, SREQ smpl}  Speed(MB/s) Period AckWidth */	{0x1,  0, 0x0c, 0x0c, SMPL_40M},  /*  20.0 :  50ns,  25ns */	{0x2,  0, 0x0d, 0x18, SMPL_40M},  /*  13.3 :  75ns,  25ns */	{0x3,  1, 0x19, 0x19, SMPL_40M},  /*  10.0 : 100ns,  50ns */	{0x4,  1, 0x1a, 0x1f, SMPL_20M},  /*   8.0 : 125ns,  50ns */	{0x5,  2, 0x20, 0x25, SMPL_20M},  /*   6.7 : 150ns,  75ns */	{0x6,  2, 0x26, 0x31, SMPL_20M},  /*   5.7 : 175ns,  75ns */	{0x7,  3, 0x32, 0x32, SMPL_20M},  /*   5.0 : 200ns, 100ns */	{0x8,  3, 0x33, 0x38, SMPL_10M},  /*   4.4 : 225ns, 100ns */	{0x9,  3, 0x39, 0x3e, SMPL_10M},  /*   4.0 : 250ns, 100ns */};static nsp32_sync_table nsp32_sync_table_20M[] = {	{0x1,  0, 0x19, 0x19, SMPL_40M},  /* 10.0 : 100ns,  50ns */	{0x2,  0, 0x1a, 0x25, SMPL_20M},  /*  6.7 : 150ns,  50ns */	{0x3,  1, 0x26, 0x32, SMPL_20M},  /*  5.0 : 200ns, 100ns */	{0x4,  1, 0x33, 0x3e, SMPL_10M},  /*  4.0 : 250ns, 100ns */	{0x5,  2, 0x3f, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 150ns */	{0x6,  2, 0x4c, 0x57, SMPL_10M},  /*  2.8 : 350ns, 150ns */	{0x7,  3, 0x58, 0x64, SMPL_10M},  /*  2.5 : 400ns, 200ns */	{0x8,  3, 0x65, 0x70, SMPL_10M},  /*  2.2 : 450ns, 200ns */	{0x9,  3, 0x71, 0x7d, SMPL_10M},  /*  2.0 : 500ns, 200ns */};static nsp32_sync_table nsp32_sync_table_pci[] = {	{0x1,  0, 0x0c, 0x0f, SMPL_40M},  /* 16.6 :  60ns,  30ns */	{0x2,  0, 0x10, 0x16, SMPL_40M},  /* 11.1 :  90ns,  30ns */	{0x3,  1, 0x17, 0x1e, SMPL_20M},  /*  8.3 : 120ns,  60ns */	{0x4,  1, 0x1f, 0x25, SMPL_20M},  /*  6.7 : 150ns,  60ns */	{0x5,  2, 0x26, 0x2d, SMPL_20M},  /*  5.6 : 180ns,  90ns */	{0x6,  2, 0x2e, 0x34, SMPL_10M},  /*  4.8 : 210ns,  90ns */	{0x7,  3, 0x35, 0x3c, SMPL_10M},  /*  4.2 : 240ns, 120ns */	{0x8,  3, 0x3d, 0x43, SMPL_10M},  /*  3.7 : 270ns, 120ns */	{0x9,  3, 0x44, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 120ns */};/* * function declaration *//* module entry point */static int  __devinit nsp32_probe (struct pci_dev *, const struct pci_device_id *);static void __devexit nsp32_remove(struct pci_dev *);static int  __init    init_nsp32  (void);static void __exit    exit_nsp32  (void);/* struct Scsi_Host_Template */#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))static int         nsp32_proc_info   (struct Scsi_Host *, char *, char **, off_t, int, int);#elsestatic int         nsp32_proc_info   (char *, char **, off_t, int, int, int);#endif#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))static int         nsp32_detect      (struct pci_dev *pdev);#elsestatic int         nsp32_detect      (Scsi_Host_Template *);#endifstatic int         nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));static const char *nsp32_info        (struct Scsi_Host *);static int         nsp32_release     (struct Scsi_Host *);/* SCSI error handler */static int         nsp32_eh_abort     (Scsi_Cmnd *);static int         nsp32_eh_bus_reset (Scsi_Cmnd *);static int         nsp32_eh_host_reset(Scsi_Cmnd *);/* generate SCSI message */static void nsp32_build_identify(Scsi_Cmnd *);static void nsp32_build_nop     (Scsi_Cmnd *);static void nsp32_build_reject  (Scsi_Cmnd *);static void nsp32_build_sdtr    (Scsi_Cmnd *, unsigned char, unsigned char);/* SCSI message handler */static int  nsp32_busfree_occur(Scsi_Cmnd *, unsigned short);static void nsp32_msgout_occur (Scsi_Cmnd *);static void nsp32_msgin_occur  (Scsi_Cmnd *, unsigned long, unsigned short);static int  nsp32_setup_sg_table    (Scsi_Cmnd *);static int  nsp32_selection_autopara(Scsi_Cmnd *);static int  nsp32_selection_autoscsi(Scsi_Cmnd *);static void nsp32_scsi_done         (Scsi_Cmnd *);static int  nsp32_arbitration       (Scsi_Cmnd *, unsigned int);static int  nsp32_reselection       (Scsi_Cmnd *, unsigned char);static void nsp32_adjust_busfree    (Scsi_Cmnd *, unsigned int);static void nsp32_restart_autoscsi  (Scsi_Cmnd *, unsigned short);/* SCSI SDTR */static void nsp32_analyze_sdtr       (Scsi_Cmnd *);static int  nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char);static void nsp32_set_async          (nsp32_hw_data *, nsp32_target *);static void nsp32_set_max_sync       (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *);static void nsp32_set_sync_entry     (nsp32_hw_data *, nsp32_target *, int, unsigned char);/* SCSI bus status handler */static void nsp32_wait_req    (nsp32_hw_data *, int);static void nsp32_wait_sack   (nsp32_hw_data *, int);static void nsp32_sack_assert (nsp32_hw_data *);static void nsp32_sack_negate (nsp32_hw_data *);static void nsp32_do_bus_reset(nsp32_hw_data *);/* hardware interrupt handler */static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *);/* initialize hardware */static int  nsp32hw_init(nsp32_hw_data *);/* EEPROM handler */static        int  nsp32_getprom_param (nsp32_hw_data *);static        int  nsp32_getprom_at24  (nsp32_hw_data *);static        int  nsp32_getprom_c16   (nsp32_hw_data *);static        void nsp32_prom_start    (nsp32_hw_data *);static        void nsp32_prom_stop     (nsp32_hw_data *);static        int  nsp32_prom_read     (nsp32_hw_data *, int);static        int  nsp32_prom_read_bit (nsp32_hw_data *);static        void nsp32_prom_write_bit(nsp32_hw_data *, int);static        void nsp32_prom_set      (nsp32_hw_data *, int, int);static        int  nsp32_prom_get      (nsp32_hw_data *, int);/* debug/warning/info message */static void nsp32_message (const char *, int, char *, char *, ...);#ifdef NSP32_DEBUGstatic void nsp32_dmessage(const char *, int, int,    char *, ...);#endif/* * max_sectors is currently limited up to 128. */static Scsi_Host_Template nsp32_template = {	.proc_name			= "nsp32",	.name				= "Workbit NinjaSCSI-32Bi/UDE",	.proc_info			= nsp32_proc_info,	.info				= nsp32_info,	.queuecommand			= nsp32_queuecommand,	.can_queue			= 1,	.sg_tablesize			= NSP32_SG_SIZE,	.max_sectors			= 128,	.cmd_per_lun			= 1,	.this_id			= NSP32_HOST_SCSIID,	.use_clustering			= DISABLE_CLUSTERING,	.eh_abort_handler       	= nsp32_eh_abort,/*	.eh_device_reset_handler	= NULL, */	.eh_bus_reset_handler		= nsp32_eh_bus_reset,	.eh_host_reset_handler		= nsp32_eh_host_reset,#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74))	.detect				= nsp32_detect,	.release			= nsp32_release,#endif#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))	.use_new_eh_code        	= 1,#else/*	.highmem_io			= 1, */#endif};#include "nsp32_io.h"/*********************************************************************** * debug, error print */#ifndef NSP32_DEBUG# define NSP32_DEBUG_MASK	      0x000000# define nsp32_msg(type, args...)     nsp32_message ("", 0, (type), args)# define nsp32_dbg(mask, args...)     /* */#else# define NSP32_DEBUG_MASK	      0xffffff# define nsp32_msg(type, args...) \	nsp32_message (__FUNCTION__, __LINE__, (type), args)# define nsp32_dbg(mask, args...) \	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args)#endif#define NSP32_DEBUG_QUEUECOMMAND	BIT(0)#define NSP32_DEBUG_REGISTER		BIT(1)#define NSP32_DEBUG_AUTOSCSI		BIT(2)#define NSP32_DEBUG_INTR		BIT(3)#define NSP32_DEBUG_SGLIST		BIT(4)#define NSP32_DEBUG_BUSFREE		BIT(5)#define NSP32_DEBUG_CDB_CONTENTS	BIT(6)#define NSP32_DEBUG_RESELECTION		BIT(7)#define NSP32_DEBUG_MSGINOCCUR		BIT(8)#define NSP32_DEBUG_EEPROM		BIT(9)#define NSP32_DEBUG_MSGOUTOCCUR		BIT(10)#define NSP32_DEBUG_BUSRESET		BIT(11)#define NSP32_DEBUG_RESTART		BIT(12)#define NSP32_DEBUG_SYNC		BIT(13)#define NSP32_DEBUG_WAIT		BIT(14)#define NSP32_DEBUG_TARGETFLAG		BIT(15)#define NSP32_DEBUG_PROC		BIT(16)#define NSP32_DEBUG_INIT		BIT(17)#define NSP32_SPECIAL_PRINT_REGISTER	BIT(20)#define NSP32_DEBUG_BUF_LEN		100static void nsp32_message(const char *func, int line, char *type, char *fmt, ...){	va_list args;	char buf[NSP32_DEBUG_BUF_LEN];	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args);#ifndef NSP32_DEBUG	printk("%snsp32: %s\n", type, buf);#else	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);#endif}#ifdef NSP32_DEBUGstatic void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...){	va_list args;	char buf[NSP32_DEBUG_BUF_LEN];	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args);	if (mask & NSP32_DEBUG_MASK) {		printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);	}}#endif#ifdef NSP32_DEBUG# include "nsp32_debug.c"#else# define show_command(arg)   /* */# define show_busphase(arg)  /* */# define show_autophase(arg) /* */#endif/* * IDENTIFY Message */static void nsp32_build_identify(Scsi_Cmnd *SCpnt){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	int pos             = data->msgout_len;	int mode            = FALSE;	/* XXX: Auto DiscPriv detection is progressing... */	if (disc_priv == 0) {		/* mode = TRUE; */	}	data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++;	data->msgout_len = pos;}/* * SDTR Message Routine */static void nsp32_build_sdtr(Scsi_Cmnd    *SCpnt,			     unsigned char period,			     unsigned char offset){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	int pos             = data->msgout_len;	data->msgoutbuf[pos] = EXTENDED_MESSAGE;  pos++;	data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++;	data->msgoutbuf[pos] = EXTENDED_SDTR;     pos++;	data->msgoutbuf[pos] = period;            pos++;	data->msgoutbuf[pos] = offset;            pos++;	data->msgout_len = pos;}/* * No Operation Message */static void nsp32_build_nop(Scsi_Cmnd *SCpnt){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	int            pos  = data->msgout_len;	if (pos != 0) {		nsp32_msg(KERN_WARNING,			  "Some messages are already contained!");		return;	}	data->msgoutbuf[pos] = NOP; pos++;	data->msgout_len = pos;}/* * Reject Message */static void nsp32_build_reject(Scsi_Cmnd *SCpnt){	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	int            pos  = data->msgout_len;	data->msgoutbuf[pos] = MESSAGE_REJECT; pos++;	data->msgout_len = pos;}	/* * timer */#if 0static void nsp32_start_timer(Scsi_Cmnd *SCpnt, int time){	unsigned int base = SCpnt->host->io_port;	nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time);	if (time & (~TIMER_CNT_MASK)) {		nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow");	}	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);}#endif/* * set SCSI command and other parameter to asic, and start selection phase */static int nsp32_selection_autopara(Scsi_Cmnd *SCpnt){	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;	unsigned int	base    = SCpnt->device->host->io_port;	unsigned int	host_id = SCpnt->device->host->this_id;

⌨️ 快捷键说明

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