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

📄 nsp_cs.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/*======================================================================    NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI hostadapter card driver      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>    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.42 2001/09/10 10:30:58 elca Exp $ */#ifdef NSP_KERNEL_2_2#include <pcmcia/config.h>#include <pcmcia/k_compat.h>#endif#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/tqueue.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/major.h>#include <linux/blk.h>#include <linux/stat.h>#include <asm/io.h>#include <asm/irq.h>#include <../drivers/scsi/scsi.h>#include <../drivers/scsi/hosts.h>#include <../drivers/scsi/sd.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/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");MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");MODULE_LICENSE("GPL");#ifdef PCMCIA_DEBUGstatic int pc_debug = PCMCIA_DEBUG;MODULE_PARM(pc_debug, "i");MODULE_PARM_DESC(pc_debug, "set debug level");static char *version = "$Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $";#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)#else#define DEBUG(n, args...) /* */#endif#include "nsp_io.h"/*====================================================================*/typedef struct scsi_info_t {	dev_link_t             link;	struct Scsi_Host      *host;	int	               ndev;	dev_node_t             node[8];	int                    stop;	struct bus_operations *bus;} scsi_info_t;/*----------------------------------------------------------------*/#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE)#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */static struct proc_dir_entry proc_scsi_nsp = {	PROC_SCSI_NSP, 6, "nsp_cs",	S_IFDIR | S_IRUGO | S_IXUGO, 2};#endif/*====================================================================*//* 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");static int irq_list[4] = { -1 };MODULE_PARM(irq_list, "1-4i");MODULE_PARM_DESC(irq_list, "IRQ number list");/*----------------------------------------------------------------*//* driver state info, local to driver */static char nspinfo[100];     /* description *//* /usr/src/linux/drivers/scsi/hosts.h */static Scsi_Host_Template driver_template = {/*	next:			NULL,*/#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)	proc_dir:	       &proc_scsi_nsp, /* kernel 2.2 */#else	proc_name:	       "nsp_cs",       /* kernel 2.4 */#endif/*	proc_info:		NULL,*/	name:			"WorkBit NinjaSCSI-3/32Bi",	detect:			nsp_detect,	release:		nsp_release,	info:			nsp_info,/*	command:		NULL,*/	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,	abort:			nsp_abort,	reset:			nsp_reset,/*	slave_attach:		NULL,*//*	bios_param:		NULL,*/	can_queue:		1,	this_id:		SCSI_INITIATOR_ID,	sg_tablesize:		SG_ALL,	cmd_per_lun:		1,/*	present:		0,*//*	unchecked_isa_dma:	0,*/	use_clustering:		DISABLE_CLUSTERING,	use_new_eh_code:	0,/*	emulated:		0,*/};static dev_link_t *dev_list = NULL;static dev_info_t dev_info  = {"nsp_cs"};static nsp_hw_data nsp_data;/***********************************************************/static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){#ifdef PCMCIA_DEBUG	//unsigned int host_id = SCpnt->host->this_id;	//unsigned int base    = SCpnt->host->io_port;	unsigned char target = SCpnt->target;#endif	nsp_hw_data *data = &nsp_data;	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",	      SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);	//DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC);	if(data->CurrentSC != NULL) {		printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n");		data->CurrentSC = NULL;		SCpnt->result   = DID_BAD_TARGET << 16;		done(SCpnt);		return -1;	}	show_command(SCpnt);	SCpnt->scsi_done	= done;	data->CurrentSC		= SCpnt;	RESID		        = SCpnt->request_bufflen;	SCpnt->SCp.Status	= -1;	SCpnt->SCp.Message	= -1;	SCpnt->SCp.have_data_in = IO_UNKNOWN;	SCpnt->SCp.sent_command = 0;	SCpnt->SCp.phase	= PH_UNDETERMINED;	/* 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		    = SCpnt->SCp.buffer->address;		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, data) == FALSE) {		DEBUG(0, " selection fail\n");		data->CurrentSC = NULL;		SCpnt->result   = DID_NO_CONNECT << 16;		done(SCpnt);		return -1;	}	//DEBUG(0, __FUNCTION__ "() out\n");	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;	//DEBUG(0, __FUNCTION__ "() enabled=%d\n", 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);}/* * Initialize Ninja hardware */static int nsphw_init(nsp_hw_data *data){	unsigned int base     = data->BaseAddress;	int	     i, j;	sync_data    tmp_sync = { SyncNegotiation: SYNC_NOT_YET,				  SyncPeriod:	   0,				  SyncOffset:	   0	};	DEBUG(0, __FUNCTION__ "() in base=0x%x\n", base);	data->ScsiClockDiv = CLOCK_40M;	data->CurrentSC    = NULL;	data->FifoCount    = 0;	data->TransferMode = MODE_IO8;	/* setup sync data */	for ( i = 0; i < N_TARGET; i++ ) {		for ( j = 0; j < N_LUN; j++ ) {			data->Sync[i][j] = tmp_sync;		}	}	/* block all interrupts */	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLMASK);	/* setup SCSI interface */	nsp_write(base,	      IFSELECT,	    IF_IFSEL);	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) {		printk(KERN_INFO "nsp_cs: terminator power on\n");		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_ALLCLEAR);	nsp_setup_fifo(data, FALSE);	return TRUE;}/* * Start selection phase */static unsigned int nsphw_start_selection(Scsi_Cmnd   *SCpnt,					  nsp_hw_data *data){	unsigned int  host_id	 = SCpnt->host->this_id;	unsigned int  base	 = SCpnt->host->io_port;	unsigned char target	 = SCpnt->target;	int	      wait_count;	unsigned char phase, arbit;	//DEBUG(0, __FUNCTION__ "()in\n");	phase = nsp_index_read(base, SCSIBUSMON);	if(phase != BUSMON_BUS_FREE) {		//DEBUG(0, " bus busy\n");		return FALSE;	}	/* start arbitration */	//DEBUG(0, " start arbit\n");	SCpnt->SCp.phase = PH_ARBSTART;	nsp_index_write(base, SETARBIT, ARBIT_GO);	wait_count = jiffies + 10 * HZ;	do {		/* XXX: what a stupid chip! */		arbit = nsp_index_read(base, ARBITSTATUS);		//DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count);		udelay(1); /* hold 1.2us */	} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&		time_before(jiffies, wait_count));	if((arbit & ARBIT_WIN) == 0) {		//DEBUG(0, " arbit fail\n");		nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);		return FALSE;	}	/* assert select line */	//DEBUG(0, " assert SEL line\n");	SCpnt->SCp.phase = PH_SELSTART;	udelay(3);	nsp_index_write(base, SCSIDATALATCH, (1 << host_id) | (1 << target));	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_ATN);	udelay(3);	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);	nsp_index_write(base, SETARBIT,	     ARBIT_FLAG_CLEAR);	udelay(3);	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);	/* check selection timeout */	nsp_start_timer(SCpnt, data, 1000/51);	data->SelectionTimeOut = 1;	return TRUE;}struct nsp_sync_table {	unsigned int min_period;	unsigned int max_period;	unsigned int chip_period;	unsigned int ack_width;};static struct nsp_sync_table nsp_sync_table_40M[] = {	{0x0c,0x0c,0x1,0},	/* 20MB	 50ns*/	{0x19,0x19,0x3,1},	/* 10MB	 100ns*/ 	{0x1a,0x25,0x5,2},	/* 7.5MB 150ns*/ 	{0x26,0x32,0x7,3},	/* 5MB	 200ns*/	{0x0, 0,   0,  0}};static struct nsp_sync_table nsp_sync_table_20M[] = {	{0x19,0x19,0x1,0},	/* 10MB	 100ns*/ 	{0x1a,0x25,0x2,0},	/* 7.5MB 150ns*/ 	{0x26,0x32,0x3,1},	/* 5MB	 200ns*/	{0x0, 0,   0,  0}};/* * setup synchronous data transfer mode */static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data){	unsigned char	       target = SCpnt->target;	unsigned char	       lun    = SCpnt->lun;	sync_data	      *sync   = &(data->Sync[target][lun]);	struct nsp_sync_table *sync_table;	unsigned int	       period, offset;	int		       i;	DEBUG(0, __FUNCTION__ "()\n");/**!**/	period = sync->SyncPeriod;	offset = sync->SyncOffset;	DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset);	if (data->ScsiClockDiv == CLOCK_20M) {		sync_table = &nsp_sync_table_20M[0];	} else {		sync_table = &nsp_sync_table_40M[0];	}	for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {		if ( period >= sync_table->min_period &&		     period <= sync_table->max_period	 ) {			break;		}	}	if (period != 0 && sync_table->max_period == 0) {		/*		 * No proper period/offset found		 */		DEBUG(0, " no proper period/offset\n");		sync->SyncPeriod      = 0;		sync->SyncOffset      = 0;		sync->SyncRegister    = 0;		sync->AckWidth	      = 0;		sync->SyncNegotiation = SYNC_OK;		return FALSE;	}	sync->SyncRegister    = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |		                (offset & SYNCREG_OFFSET_MASK);	sync->AckWidth	      = sync_table->ack_width;	sync->SyncNegotiation = SYNC_OK;	DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth);	return TRUE;}/* * start ninja hardware timer */static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time){	unsigned int base = SCpnt->host->io_port;	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time);	data->TimerCount = time;	nsp_index_write(base, TIMERCOUNT, time);}/* * wait for bus phase change */static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str){	unsigned int  base = SCpnt->host->io_port;	unsigned char reg;	int	      count, i = TRUE;	//DEBUG(0, __FUNCTION__ "()\n");	count = jiffies + HZ;	do {		reg = nsp_index_read(base, SCSIBUSMON);		if (reg == 0xff) {			break;		}	} while ((i = time_before(jiffies, count)) && (reg & mask) != 0);	if (!i) {		printk(KERN_DEBUG __FUNCTION__ " %s signal off timeut\n", str);	}	return 0;}/* * expect Ninja Irq */static int nsp_expect_signal(Scsi_Cmnd	   *SCpnt,			     unsigned char  current_phase,			     unsigned char  mask){	unsigned int  base	 = SCpnt->host->io_port;	int	      wait_count;	unsigned char phase, i_src;	//DEBUG(0, __FUNCTION__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask);	wait_count = jiffies + HZ;	do {		phase = nsp_index_read(base, SCSIBUSMON);		if (phase == 0xff) {			//DEBUG(0, " ret -1\n");			return -1;		}		i_src = nsp_read(base, IRQSTATUS);		if (i_src & IRQSTATUS_SCSI) {			//DEBUG(0, " ret 0 found scsi signal\n");			return 0;		}		if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {			//DEBUG(0, " ret 1 phase=0x%x\n", phase);			return 1;		}	} while(time_before(jiffies, wait_count));	//DEBUG(0, __FUNCTION__ " : " __FUNCTION__ " timeout\n");	return -1;}/* * transfer SCSI message */static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase){	unsigned int  base = SCpnt->host->io_port;	char	     *buf  = data->MsgBuffer;	int	      len  = MIN(MSGBUF_SIZE, data->MsgLen);	int	      ptr;	int	      ret;	//DEBUG(0, __FUNCTION__ "()\n");	for (ptr = 0; len > 0; len --, ptr ++) {		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);		if (ret <= 0) {			DEBUG(0, " xfer quit\n");			return 0;		}		/* if last byte, negate ATN */		if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);		}		/* read & write message */		if (phase & BUSMON_IO) {			DEBUG(0, " read msg\n");			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);		} else {			DEBUG(0, " write msg\n");			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);		}		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");	}	return len;}/* * get extra SCSI data from fifo */static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data){	unsigned int count;	//DEBUG(0, __FUNCTION__ "()\n");	if (SCpnt->SCp.have_data_in != IO_IN) {		return 0;	}	count = nsp_fifo_count(SCpnt);

⌨️ 快捷键说明

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