initio.c

来自「linux 内核源代码」· C语言 代码 · 共 2,386 行 · 第 1/5 页

C
2,386
字号
/************************************************************************** * Initio 9100 device driver for Linux. * * Copyright (c) 1994-1998 Initio Corporation * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl> * Copyright (c) 2004 Christoph Hellwig <hch@lst.de> * Copyright (c) 2007 Red Hat <alan@redhat.com> * * 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. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING.  If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * ************************************************************************* * * DESCRIPTION: * * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host * adapters * * 08/06/97 hc	- v1.01h *		- Support inic-940 and inic-935 * 09/26/97 hc	- v1.01i *		- Make correction from J.W. Schultz suggestion * 10/13/97 hc	- Support reset function * 10/21/97 hc	- v1.01j *		- Support 32 LUN (SCSI 3) * 01/14/98 hc	- v1.01k *		- Fix memory allocation problem * 03/04/98 hc	- v1.01l *		- Fix tape rewind which will hang the system problem *		- Set can_queue to initio_num_scb * 06/25/98 hc	- v1.01m *		- Get it work for kernel version >= 2.1.75 *		- Dynamic assign SCSI bus reset holding time in initio_init() * 07/02/98 hc	- v1.01n *		- Support 0002134A * 08/07/98 hc  - v1.01o *		- Change the initio_abort_srb routine to use scsi_done. <01> * 09/07/98 hl  - v1.02 *              - Change the INI9100U define and proc_dir_entry to *                reflect the newer Kernel 2.1.118, but the v1.o1o *                should work with Kernel 2.1.118. * 09/20/98 wh  - v1.02a *              - Support Abort command. *              - Handle reset routine. * 09/21/98 hl  - v1.03 *              - remove comments. * 12/09/98 bv	- v1.03a *		- Removed unused code * 12/13/98 bv	- v1.03b *		- Remove cli() locking for kernels >= 2.1.95. This uses *		  spinlocks to serialize access to the pSRB_head and *		  pSRB_tail members of the HCS structure. * 09/01/99 bv	- v1.03d *		- Fixed a deadlock problem in SMP. * 21/01/99 bv	- v1.03e *		- Add support for the Domex 3192U PCI SCSI *		  This is a slightly modified patch by *		  Brian Macy <bmacy@sunshinecomputing.com> * 22/02/99 bv	- v1.03f *		- Didn't detect the INIC-950 in 2.0.x correctly. *		  Now fixed. * 05/07/99 bv	- v1.03g *		- Changed the assumption that HZ = 100 * 10/17/03 mc	- v1.04 *		- added new DMA API support * 06/01/04 jmd	- v1.04a *		- Re-add reset_bus support **************************************************************************/#include <linux/module.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/spinlock.h>#include <linux/stat.h>#include <linux/kernel.h>#include <linux/proc_fs.h>#include <linux/string.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/jiffies.h>#include <linux/dma-mapping.h>#include <asm/io.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_tcq.h>#include "initio.h"#define SENSE_SIZE		14#define i91u_MAXQUEUE		2#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"#define I950_DEVICE_ID	0x9500	/* Initio's inic-950 product ID   */#define I940_DEVICE_ID	0x9400	/* Initio's inic-940 product ID   */#define I935_DEVICE_ID	0x9401	/* Initio's inic-935 product ID   */#define I920_DEVICE_ID	0x0002	/* Initio's other product ID      */#ifdef DEBUG_i91ustatic unsigned int i91u_debug = DEBUG_DEFAULT;#endifstatic int initio_tag_enable = 1;#ifdef DEBUG_i91ustatic int setup_debug = 0;#endifstatic void i91uSCBPost(u8 * pHcb, u8 * pScb);/* PCI Devices supported by this driver */static struct pci_device_id i91u_pci_devices[] = {	{ PCI_VENDOR_ID_INIT,  I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{ PCI_VENDOR_ID_INIT,  I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{ PCI_VENDOR_ID_INIT,  I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{ PCI_VENDOR_ID_INIT,  I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{ PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{ }};MODULE_DEVICE_TABLE(pci, i91u_pci_devices);#define DEBUG_INTERRUPT 0#define DEBUG_QUEUE     0#define DEBUG_STATE     0#define INT_DISC	0/*--- forward references ---*/static struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun);static struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host);static int tulip_main(struct initio_host * host);static int initio_next_state(struct initio_host * host);static int initio_state_1(struct initio_host * host);static int initio_state_2(struct initio_host * host);static int initio_state_3(struct initio_host * host);static int initio_state_4(struct initio_host * host);static int initio_state_5(struct initio_host * host);static int initio_state_6(struct initio_host * host);static int initio_state_7(struct initio_host * host);static int initio_xfer_data_in(struct initio_host * host);static int initio_xfer_data_out(struct initio_host * host);static int initio_xpad_in(struct initio_host * host);static int initio_xpad_out(struct initio_host * host);static int initio_status_msg(struct initio_host * host);static int initio_msgin(struct initio_host * host);static int initio_msgin_sync(struct initio_host * host);static int initio_msgin_accept(struct initio_host * host);static int initio_msgout_reject(struct initio_host * host);static int initio_msgin_extend(struct initio_host * host);static int initio_msgout_ide(struct initio_host * host);static int initio_msgout_abort_targ(struct initio_host * host);static int initio_msgout_abort_tag(struct initio_host * host);static int initio_bus_device_reset(struct initio_host * host);static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb);static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb);static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb);static int int_initio_busfree(struct initio_host * host);static int int_initio_scsi_rst(struct initio_host * host);static int int_initio_bad_seq(struct initio_host * host);static int int_initio_resel(struct initio_host * host);static int initio_sync_done(struct initio_host * host);static int wdtr_done(struct initio_host * host);static int wait_tulip(struct initio_host * host);static int initio_wait_done_disc(struct initio_host * host);static int initio_wait_disc(struct initio_host * host);static void tulip_scsi(struct initio_host * host);static int initio_post_scsi_rst(struct initio_host * host);static void initio_se2_ew_en(unsigned long base);static void initio_se2_ew_ds(unsigned long base);static int initio_se2_rd_all(unsigned long base);static void initio_se2_update_all(unsigned long base);	/* setup default pattern */static void initio_read_eeprom(unsigned long base);/* ---- INTERNAL VARIABLES ---- */static NVRAM i91unvram;static NVRAM *i91unvramp;static u8 i91udftNvRam[64] ={	/*----------- header -----------*/	0x25, 0xc9,		/* Signature    */	0x40,			/* Size         */	0x01,			/* Revision     */	/* -- Host Adapter Structure -- */	0x95,			/* ModelByte0   */	0x00,			/* ModelByte1   */	0x00,			/* ModelInfo    */	0x01,			/* NumOfCh      */	NBC1_DEFAULT,		/* BIOSConfig1  */	0,			/* BIOSConfig2  */	0,			/* HAConfig1    */	0,			/* HAConfig2    */	/* SCSI channel 0 and target Structure  */	7,			/* SCSIid       */	NCC1_DEFAULT,		/* SCSIconfig1  */	0,			/* SCSIconfig2  */	0x10,			/* NumSCSItarget */	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	/* SCSI channel 1 and target Structure  */	7,			/* SCSIid       */	NCC1_DEFAULT,		/* SCSIconfig1  */	0,			/* SCSIconfig2  */	0x10,			/* NumSCSItarget */	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	0, 0};			/*      - CheckSum -            */static u8 initio_rate_tbl[8] =	/* fast 20      */{				/* nanosecond devide by 4 */	12,			/* 50ns,  20M   */	18,			/* 75ns,  13.3M */	25,			/* 100ns, 10M   */	31,			/* 125ns, 8M    */	37,			/* 150ns, 6.6M  */	43,			/* 175ns, 5.7M  */	50,			/* 200ns, 5M    */	62			/* 250ns, 4M    */};static void initio_do_pause(unsigned amount){	/* Pause for amount jiffies */	unsigned long the_time = jiffies + amount;	while (time_before_eq(jiffies, the_time))		cpu_relax();}/*-- forward reference --*//****************************************************************** Input: instruction for  Serial E2PROM EX: se2_rd(0 call se2_instr() to send address and read command	 StartBit  OP_Code   Address                Data	 --------- --------  ------------------     -------	 1         1 , 0     A5,A4,A3,A2,A1,A0      D15-D0		 +-----------------------------------------------------		 | CS -----+			+--+  +--+  +--+  +--+  +--+			^  |  ^  |  ^  |  ^  |  ^  |			|  |  |  |  |  |  |  |  |  | CLK -------+  +--+  +--+  +--+  +--+  +-- (leading edge trigger)		 +--1-----1--+		 | SB    OP  |  OP    A5    A4 DI  ----+           +--0------------------ (address and cmd sent to nvram)	 -------------------------------------------+												| DO                                             +--- (data sent from nvram)******************************************************************//** *	initio_se2_instr	-	bitbang an instruction *	@base: Base of InitIO controller *	@instr: Instruction for serial E2PROM * *	Bitbang an instruction out to the serial E2Prom */static void initio_se2_instr(unsigned long base, u8 instr){	int i;	u8 b;	outb(SE2CS | SE2DO, base + TUL_NVRAM);		/* cs+start bit */	udelay(30);	outb(SE2CS | SE2CLK | SE2DO, base + TUL_NVRAM);	/* +CLK */	udelay(30);	for (i = 0; i < 8; i++) {		if (instr & 0x80)			b = SE2CS | SE2DO;		/* -CLK+dataBit */		else			b = SE2CS;			/* -CLK */		outb(b, base + TUL_NVRAM);		udelay(30);		outb(b | SE2CLK, base + TUL_NVRAM);	/* +CLK */		udelay(30);		instr <<= 1;	}	outb(SE2CS, base + TUL_NVRAM);			/* -CLK */	udelay(30);}/** *	initio_se2_ew_en	-	Enable erase/write *	@base: Base address of InitIO controller * *	Enable erase/write state of serial EEPROM */void initio_se2_ew_en(unsigned long base){	initio_se2_instr(base, 0x30);	/* EWEN */	outb(0, base + TUL_NVRAM);	/* -CS  */	udelay(30);}/** *	initio_se2_ew_ds	-	Disable erase/write *	@base: Base address of InitIO controller * *	Disable erase/write state of serial EEPROM */void initio_se2_ew_ds(unsigned long base){	initio_se2_instr(base, 0);	/* EWDS */	outb(0, base + TUL_NVRAM);	/* -CS  */	udelay(30);}/** *	initio_se2_rd		-	read E2PROM word *	@base: Base of InitIO controller *	@addr: Address of word in E2PROM * *	Read a word from the NV E2PROM device */static u16 initio_se2_rd(unsigned long base, u8 addr){	u8 instr, rb;	u16 val = 0;	int i;	instr = (u8) (addr | 0x80);	initio_se2_instr(base, instr);	/* READ INSTR */	for (i = 15; i >= 0; i--) {		outb(SE2CS | SE2CLK, base + TUL_NVRAM);	/* +CLK */		udelay(30);		outb(SE2CS, base + TUL_NVRAM);		/* -CLK */		/* sample data after the following edge of clock  */		rb = inb(base + TUL_NVRAM);		rb &= SE2DI;		val += (rb << i);		udelay(30);	/* 6/20/95 */	}	outb(0, base + TUL_NVRAM);		/* no chip select */	udelay(30);	return val;}/** *	initio_se2_wr		-	read E2PROM word *	@base: Base of InitIO controller *	@addr: Address of word in E2PROM *	@val: Value to write * *	Write a word to the NV E2PROM device. Used when recovering from *	a problem with the NV. */static void initio_se2_wr(unsigned long base, u8 addr, u16 val){	u8 rb;	u8 instr;	int i;	instr = (u8) (addr | 0x40);	initio_se2_instr(base, instr);	/* WRITE INSTR */	for (i = 15; i >= 0; i--) {		if (val & 0x8000)			outb(SE2CS | SE2DO, base + TUL_NVRAM);	/* -CLK+dataBit 1 */		else			outb(SE2CS, base + TUL_NVRAM);		/* -CLK+dataBit 0 */		udelay(30);		outb(SE2CS | SE2CLK, base + TUL_NVRAM);		/* +CLK */		udelay(30);		val <<= 1;	}	outb(SE2CS, base + TUL_NVRAM);				/* -CLK */	udelay(30);	outb(0, base + TUL_NVRAM);				/* -CS  */	udelay(30);	outb(SE2CS, base + TUL_NVRAM);				/* +CS  */	udelay(30);	for (;;) {		outb(SE2CS | SE2CLK, base + TUL_NVRAM);		/* +CLK */		udelay(30);		outb(SE2CS, base + TUL_NVRAM);			/* -CLK */		udelay(30);		if ((rb = inb(base + TUL_NVRAM)) & SE2DI)			break;	/* write complete */	}	outb(0, base + TUL_NVRAM);				/* -CS */}/** *	initio_se2_rd_all	-	read hostadapter NV configuration *	@base: Base address of InitIO controller * *	Reads the E2PROM data into main memory. Ensures that the checksum *	and header marker are valid. Returns 1 on success -1 on error. */static int initio_se2_rd_all(unsigned long base){	int i;	u16 chksum = 0;	u16 *np;	i91unvramp = &i91unvram;	np = (u16 *) i91unvramp;	for (i = 0; i < 32; i++)		*np++ = initio_se2_rd(base, i);	/* Is signature "ini" ok ? */	if (i91unvramp->NVM_Signature != INI_SIGNATURE)		return -1;	/* Is ckecksum ok ? */	np = (u16 *) i91unvramp;	for (i = 0; i < 31; i++)		chksum += *np++;	if (i91unvramp->NVM_CheckSum != chksum)		return -1;	return 1;}/** *	initio_se2_update_all		-	Update E2PROM *	@base: Base of InitIO controller * *	Update the E2PROM by wrting any changes into the E2PROM *	chip, rewriting the checksum. */static void initio_se2_update_all(unsigned long base){				/* setup default pattern */

⌨️ 快捷键说明

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