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 + -
显示快捷键?