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

📄 nsp_cs.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*======================================================================    NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>    Ver.2.8   Support 32bit MMIO mode              Support Synchronous Data Transfer Request (SDTR) mode    Ver.2.0   Support 32bit PIO mode    Ver.1.1.2 Fix for scatter list buffer exceeds    Ver.1.1   Support scatter list    Ver.0.1   Initial version    This software may be used and distributed according to the terms of    the GNU General Public License.======================================================================*//***********************************************************************    This driver is for these PCcards.	I-O DATA PCSC-F	 (Workbit NinjaSCSI-3)			"WBT", "NinjaSCSI-3", "R1.0"	I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)			"IO DATA", "CBSC16	 ", "1"***********************************************************************//* $Id: nsp_cs.c,v 1.25 2003/09/24 10:38:18 elca Exp $ */#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/major.h>#include <linux/blkdev.h>#include <linux/stat.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))# include <linux/blk.h>#endif#include <asm/io.h>#include <asm/irq.h>#include <../drivers/scsi/scsi.h>#include <../drivers/scsi/hosts.h>#include <scsi/scsi.h>#include <scsi/scsi_ioctl.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ds.h>#include "nsp_cs.h"MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.25 $");MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");MODULE_LICENSE("GPL");#include "nsp_io.h"/*====================================================================*//* Parameters that can be set with 'insmod' */static unsigned int irq_mask = 0xffff;MODULE_PARM     (irq_mask, "i");MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xffff)");static int       irq_list[4] = { -1 };MODULE_PARM     (irq_list, "1-4i");MODULE_PARM_DESC(irq_list, "Use specified IRQ number. (default: auto select)");static int       nsp_burst_mode = BURST_MEM32;MODULE_PARM     (nsp_burst_mode, "i");MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");/* Release IO ports after configuration? */static int       free_ports = 0;MODULE_PARM     (free_ports, "i");MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");/* /usr/src/linux/drivers/scsi/hosts.h */static Scsi_Host_Template nsp_driver_template = {	.proc_name	         = "nsp_cs",	.proc_info		 = nsp_proc_info,	.name			 = "WorkBit NinjaSCSI-3/32Bi(16bit)",#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))	.detect			 = nsp_detect_old,	.release		 = nsp_release_old,#endif	.info			 = nsp_info,	.queuecommand		 = nsp_queuecommand,/*	.eh_strategy_handler	 = nsp_eh_strategy,*//*	.eh_abort_handler	 = nsp_eh_abort,*//*	.eh_device_reset_handler = nsp_eh_device_reset,*/	.eh_bus_reset_handler	 = nsp_eh_bus_reset,	.eh_host_reset_handler	 = nsp_eh_host_reset,	.can_queue		 = 1,	.this_id		 = NSP_INITIATOR_ID,	.sg_tablesize		 = SG_ALL,	.cmd_per_lun		 = 1,	.use_clustering		 = DISABLE_CLUSTERING,#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))	.use_new_eh_code	 = 1,#endif};static dev_link_t *dev_list = NULL;static dev_info_t dev_info  = "nsp_cs";static nsp_hw_data nsp_data_base; /* attach <-> detect glue *//****************************************************************** * debug, error print */#ifdef NSP_DEBUG# include "nsp_debug.c"#endif	/* NSP_DEBUG */#ifndef NSP_DEBUG# define NSP_DEBUG_MASK		0x000000# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)# define nsp_dbg(mask, args...) /* */#else# define NSP_DEBUG_MASK		0xffffff# define nsp_msg(type, args...) \	nsp_cs_message (__FUNCTION__, __LINE__, (type), args)# define nsp_dbg(mask, args...) \	nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)#endif#define NSP_DEBUG_QUEUECOMMAND		BIT(0)#define NSP_DEBUG_REGISTER		BIT(1)#define NSP_DEBUG_AUTOSCSI		BIT(2)#define NSP_DEBUG_INTR			BIT(3)#define NSP_DEBUG_SGLIST		BIT(4)#define NSP_DEBUG_BUSFREE		BIT(5)#define NSP_DEBUG_CDB_CONTENTS		BIT(6)#define NSP_DEBUG_RESELECTION		BIT(7)#define NSP_DEBUG_MSGINOCCUR		BIT(8)#define NSP_DEBUG_EEPROM		BIT(9)#define NSP_DEBUG_MSGOUTOCCUR		BIT(10)#define NSP_DEBUG_BUSRESET		BIT(11)#define NSP_DEBUG_RESTART		BIT(12)#define NSP_DEBUG_SYNC			BIT(13)#define NSP_DEBUG_WAIT			BIT(14)#define NSP_DEBUG_TARGETFLAG		BIT(15)#define NSP_DEBUG_PROC			BIT(16)#define NSP_DEBUG_INIT			BIT(17)#define NSP_DEBUG_DATA_IO      		BIT(18)#define NSP_SPECIAL_PRINT_REGISTER	BIT(20)#define NSP_DEBUG_BUF_LEN		150static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...){	va_list args;	char buf[NSP_DEBUG_BUF_LEN];	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args);#ifndef NSP_DEBUG	printk("%snsp_cs: %s\n", type, buf);#else	printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);#endif}#ifdef NSP_DEBUGstatic void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...){	va_list args;	char buf[NSP_DEBUG_BUF_LEN];	va_start(args, fmt);	vsnprintf(buf, sizeof(buf), fmt, args);	va_end(args);	if (mask & NSP_DEBUG_MASK) {		printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);	}}#endif/***********************************************************//*==================================================== * Clenaup parameters and call done() functions. * You must be set SCpnt->result before call this function. */static void nsp_scsi_done(Scsi_Cmnd *SCpnt){	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	data->CurrentSC = NULL;	SCpnt->scsi_done(SCpnt);}static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){#ifdef NSP_DEBUG	/*unsigned int host_id = SCpnt->device->host->this_id;*/	/*unsigned int base    = SCpnt->device->host->io_port;*/	unsigned char target = SCpnt->device->id;#endif	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",		   SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);	SCpnt->scsi_done	= done;	if (data->CurrentSC != NULL) {		nsp_msg(KERN_WARNING, "CurrentSC!=NULL this can't be happen");		SCpnt->result   = DID_BAD_TARGET << 16;		nsp_scsi_done(SCpnt);		return SCSI_MLQUEUE_HOST_BUSY;	}	show_command(SCpnt);	data->CurrentSC		= SCpnt;	SCpnt->SCp.Status	= CHECK_CONDITION;	SCpnt->SCp.Message	= 0;	SCpnt->SCp.have_data_in = IO_UNKNOWN;	SCpnt->SCp.sent_command = 0;	SCpnt->SCp.phase	= PH_UNDETERMINED;	SCpnt->resid	        = SCpnt->request_bufflen;	/* setup scratch area	   SCp.ptr		: buffer pointer	   SCp.this_residual	: buffer length	   SCp.buffer		: next buffer	   SCp.buffers_residual : left buffers in list	   SCp.phase		: current state of the command */	if (SCpnt->use_sg) {		SCpnt->SCp.buffer	    = (struct scatterlist *) SCpnt->request_buffer;		SCpnt->SCp.ptr		    = SG_ADDRESS(SCpnt->SCp.buffer);		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;	} else {		SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;		SCpnt->SCp.buffer	    = NULL;		SCpnt->SCp.buffers_residual = 0;	}	if (nsphw_start_selection(SCpnt) == FALSE) {		nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");		SCpnt->result   = DID_BUS_BUSY << 16;		nsp_scsi_done(SCpnt);		return SCSI_MLQUEUE_DEVICE_BUSY;	}	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");#ifdef NSP_DEBUG	data->CmdId++;#endif	return 0;}/* * setup PIO FIFO transfer mode and enable/disable to data out */static void nsp_setup_fifo(nsp_hw_data *data, int enabled){	unsigned int  base = data->BaseAddress;	unsigned char transfer_mode_reg;	//nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);	if (enabled != FALSE) {		transfer_mode_reg = TRANSFER_GO | BRAIND;	} else {		transfer_mode_reg = 0;	}	transfer_mode_reg |= data->TransferMode;	nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);}static void nsphw_init_sync(nsp_hw_data *data){	sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,			       .SyncPeriod      = 0,			       .SyncOffset      = 0	};	int i;	/* setup sync data */	for ( i = 0; i < NUMBER(data->Sync); i++ ) {		data->Sync[i] = tmp_sync;	}}/* * Initialize Ninja hardware */static int nsphw_init(nsp_hw_data *data){	unsigned int base     = data->BaseAddress;	nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);	data->ScsiClockDiv = CLOCK_40M | FAST_20;	data->CurrentSC    = NULL;	data->FifoCount    = 0;	data->TransferMode = MODE_IO8;	nsphw_init_sync(data);	/* block all interrupts */	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALL_CLEAR_AND_MASK);	nsp_write(base,	      IFSELECT,	    0);	data->ChipRev = nsp_read(base, FIFOSTATUS);	/* setup SCSI interface */	nsp_write(base,	      IFSELECT,	    IF_REGSEL);	nsp_index_write(base, SCSIIRQMODE,  0);	nsp_index_write(base, TRANSFERMODE, MODE_IO8);	nsp_index_write(base, CLOCKDIV,	    data->ScsiClockDiv);	nsp_index_write(base, PARITYCTRL,   0);	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |					    ACK_COUNTER_CLEAR |					    REQ_COUNTER_CLEAR |					    HOST_COUNTER_CLEAR);	/* setup fifo asic */	nsp_write(base,	      IFSELECT,	    IF_REGSEL);	nsp_index_write(base, TERMPWRCTRL,  0);	if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {		nsp_msg(KERN_INFO, "terminator power on");		nsp_index_write(base, TERMPWRCTRL, POWER_ON);	}	nsp_index_write(base, TIMERCOUNT,   0);	nsp_index_write(base, TIMERCOUNT,   0); /* requires 2 times!! */	nsp_index_write(base, SYNCREG,	    0);	nsp_index_write(base, ACKWIDTH,	    0);	/* enable interrupts and ack them */	nsp_index_write(base, SCSIIRQMODE,  SCSI_PHASE_CHANGE_EI |					    RESELECT_EI		 |					    SCSI_RESET_IRQ_EI	 );	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALL_CLEAR);	nsp_setup_fifo(data, FALSE);	return TRUE;}/* * Start selection phase */static int nsphw_start_selection(Scsi_Cmnd *SCpnt){	unsigned int  host_id	 = SCpnt->device->host->this_id;	unsigned int  base	 = SCpnt->device->host->io_port;	unsigned char target	 = SCpnt->device->id;	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;	int	      time_out;	unsigned char phase, arbit;	//nsp_dbg(NSP_DEBUG_RESELECTION, "in");	phase = nsp_index_read(base, SCSIBUSMON);	if(phase != BUSMON_BUS_FREE) {		//nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");		return FALSE;	}	/* start arbitration */	//nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");	SCpnt->SCp.phase = PH_ARBSTART;	nsp_index_write(base, SETARBIT, ARBIT_GO);	time_out = 1000;	do {		/* XXX: what a stupid chip! */		arbit = nsp_index_read(base, ARBITSTATUS);		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);		udelay(1); /* hold 1.2us */	} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&		(time_out-- != 0));	if (!(arbit & ARBIT_WIN)) {		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");		nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);		return FALSE;	}	/* assert select line */	//nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");	SCpnt->SCp.phase = PH_SELSTART;	udelay(3); /* wait 2.4us */	nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY                    | SCSI_ATN);	udelay(2); /* wait >1.2us */	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);	nsp_index_write(base, SETARBIT,	     ARBIT_FLAG_CLEAR);	/*udelay(1);*/ /* wait >90ns */	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL            | SCSI_DATAOUT_ENB | SCSI_ATN);	/* check selection timeout */	nsp_start_timer(SCpnt, 1000/51);	data->SelectionTimeOut = 1;	return TRUE;}/*********************************************************************** * Period/AckWidth speed conversion table * * Note: This period/ackwidth speed table must be in descending order. ***********************************************************************/struct nsp_sync_table {	unsigned int chip_period;	unsigned int ack_width;	unsigned int min_period;	unsigned int max_period;};static struct nsp_sync_table nsp_sync_table_40M[] = {     /* {PNo, AW,   SP,   EP}  Speed(MB/s) Period AckWidth */	{0x1,  0, 0x0c, 0x0c},  /*  20.0 :  50ns,  25ns */	{0x2,  0, 0x0d, 0x18},  /*  13.3 :  75ns,  25ns */	{0x3,  1, 0x19, 0x19},  /*  10.0 : 100ns,  50ns */	{0x4,  1, 0x1a, 0x1f},  /*   8.0 : 125ns,  50ns */

⌨️ 快捷键说明

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