dc395x.c

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

C
2,193
字号
/* * dc395x.c * * Device Driver for Tekram DC395(U/UW/F), DC315(U) * PCI SCSI Bus Master Host Adapter * (SCSI chip set used Tekram ASIC TRM-S1040) * * Authors: *  C.L. Huang <ching@tekram.com.tw> *  Erich Chen <erich@tekram.com.tw> *  (C) Copyright 1995-1999 Tekram Technology Co., Ltd. * *  Kurt Garloff <garloff@suse.de> *  (C) 1999-2000 Kurt Garloff * *  Oliver Neukum <oliver@neukum.name> *  Ali Akcaagac <aliakc@web.de> *  Jamie Lenehan <lenehan@twibble.org> *  (C) 2003 * * License: GNU GPL * ************************************************************************* * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ************************************************************************ */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/delay.h>#include <linux/ctype.h>#include <linux/blkdev.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/pci.h>#include <linux/list.h>#include <asm/io.h>#include <scsi/scsi.h>#include <scsi/scsicam.h>	/* needed for scsicam_bios_param */#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include "dc395x.h"#define DC395X_NAME	"dc395x"#define DC395X_BANNER	"Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040"#define DC395X_VERSION	"v2.05, 2004/03/08"/*---------------------------------------------------------------------------                                  Features ---------------------------------------------------------------------------*//* * Set to disable parts of the driver *//*#define DC395x_NO_DISCONNECT*//*#define DC395x_NO_TAGQ*//*#define DC395x_NO_SYNC*//*#define DC395x_NO_WIDE*//*---------------------------------------------------------------------------                                  Debugging ---------------------------------------------------------------------------*//* * Types of debugging that can be enabled and disabled */#define DBG_KG		0x0001#define DBG_0		0x0002#define DBG_1		0x0004#define DBG_SG		0x0020#define DBG_FIFO	0x0040#define DBG_PIO		0x0080/* * Set set of things to output debugging for. * Undefine to remove all debugging *//*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*//*#define  DEBUG_MASK	DBG_0*//* * Output a kernel mesage at the specified level and append the * driver name and a ": " to the start of the message */#define dprintkl(level, format, arg...)  \    printk(level DC395X_NAME ": " format , ## arg)#ifdef DEBUG_MASK/* * print a debug message - this is formated with KERN_DEBUG, then the * driver name followed by a ": " and then the message is output.  * This also checks that the specified debug level is enabled before * outputing the message */#define dprintkdbg(type, format, arg...) \	do { \		if ((type) & (DEBUG_MASK)) \			dprintkl(KERN_DEBUG , format , ## arg); \	} while (0)/* * Check if the specified type of debugging is enabled */#define debug_enabled(type)	((DEBUG_MASK) & (type))#else/* * No debugging. Do nothing */#define dprintkdbg(type, format, arg...) \	do {} while (0)#define debug_enabled(type)	(0)#endif#ifndef PCI_VENDOR_ID_TEKRAM#define PCI_VENDOR_ID_TEKRAM                    0x1DE1	/* Vendor ID    */#endif#ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040#define PCI_DEVICE_ID_TEKRAM_TRMS1040           0x0391	/* Device ID    */#endif#define DC395x_LOCK_IO(dev,flags)		spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags)#define DC395x_UNLOCK_IO(dev,flags)		spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags)#define DC395x_read8(acb,address)		(u8)(inb(acb->io_port_base + (address)))#define DC395x_read16(acb,address)		(u16)(inw(acb->io_port_base + (address)))#define DC395x_read32(acb,address)		(u32)(inl(acb->io_port_base + (address)))#define DC395x_write8(acb,address,value)	outb((value), acb->io_port_base + (address))#define DC395x_write16(acb,address,value)	outw((value), acb->io_port_base + (address))#define DC395x_write32(acb,address,value)	outl((value), acb->io_port_base + (address))/* cmd->result */#define RES_TARGET		0x000000FF	/* Target State */#define RES_TARGET_LNX  STATUS_MASK	/* Only official ... */#define RES_ENDMSG		0x0000FF00	/* End Message */#define RES_DID			0x00FF0000	/* DID_ codes */#define RES_DRV			0xFF000000	/* DRIVER_ codes */#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); }#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; }#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; }#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }#define TAG_NONE 255/* * srb->segement_x is the hw sg list. It is always allocated as a * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not * cross a page boundy. */#define SEGMENTX_LEN	(sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)struct SGentry {	u32 address;		/* bus! address */	u32 length;};/* The SEEPROM structure for TRM_S1040 */struct NVRamTarget {	u8 cfg0;		/* Target configuration byte 0  */	u8 period;		/* Target period                */	u8 cfg2;		/* Target configuration byte 2  */	u8 cfg3;		/* Target configuration byte 3  */};struct NvRamType {	u8 sub_vendor_id[2];	/* 0,1  Sub Vendor ID   */	u8 sub_sys_id[2];	/* 2,3  Sub System ID   */	u8 sub_class;		/* 4    Sub Class       */	u8 vendor_id[2];	/* 5,6  Vendor ID       */	u8 device_id[2];	/* 7,8  Device ID       */	u8 reserved;		/* 9    Reserved        */	struct NVRamTarget target[DC395x_MAX_SCSI_ID];						/** 10,11,12,13						 ** 14,15,16,17						 ** ....						 ** ....						 ** 70,71,72,73						 */	u8 scsi_id;		/* 74 Host Adapter SCSI ID      */	u8 channel_cfg;		/* 75 Channel configuration     */	u8 delay_time;		/* 76 Power on delay time       */	u8 max_tag;		/* 77 Maximum tags              */	u8 reserved0;		/* 78  */	u8 boot_target;		/* 79  */	u8 boot_lun;		/* 80  */	u8 reserved1;		/* 81  */	u16 reserved2[22];	/* 82,..125 */	u16 cksum;		/* 126,127 */};struct ScsiReqBlk {	struct list_head list;		/* next/prev ptrs for srb lists */	struct DeviceCtlBlk *dcb;	struct scsi_cmnd *cmd;	struct SGentry *segment_x;	/* Linear array of hw sg entries (up to 64 entries) */	u32 sg_bus_addr;	        /* Bus address of sg list (ie, of segment_x) */	u8 sg_count;			/* No of HW sg entries for this request */	u8 sg_index;			/* Index of HW sg entry for this request */	u32 total_xfer_length;		/* Total number of bytes remaining to be transfered */	unsigned char *virt_addr;	/* Virtual address of current transfer position */	/*	 * The sense buffer handling function, request_sense, uses	 * the first hw sg entry (segment_x[0]) and the transfer	 * length (total_xfer_length). While doing this it stores the	 * original values into the last sg hw list	 * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the	 * total_xfer_length in xferred. These values are restored in	 * pci_unmap_srb_sense. This is the only place xferred is used.	 */	u32 xferred;		        /* Saved copy of total_xfer_length */	u16 state;	u8 msgin_buf[6];	u8 msgout_buf[6];	u8 adapter_status;	u8 target_status;	u8 msg_count;	u8 end_message;	u8 tag_number;	u8 status;	u8 retry_count;	u8 flag;	u8 scsi_phase;};struct DeviceCtlBlk {	struct list_head list;		/* next/prev ptrs for the dcb list */	struct AdapterCtlBlk *acb;	struct list_head srb_going_list;	/* head of going srb list */	struct list_head srb_waiting_list;	/* head of waiting srb list */	struct ScsiReqBlk *active_srb;	u32 tag_mask;	u16 max_command;	u8 target_id;		/* SCSI Target ID  (SCSI Only) */	u8 target_lun;		/* SCSI Log.  Unit (SCSI Only) */	u8 identify_msg;	u8 dev_mode;	u8 inquiry7;		/* To store Inquiry flags */	u8 sync_mode;		/* 0:async mode */	u8 min_nego_period;	/* for nego. */	u8 sync_period;		/* for reg.  */	u8 sync_offset;		/* for reg. and nego.(low nibble) */	u8 flag;	u8 dev_type;	u8 init_tcq_flag;};struct AdapterCtlBlk {	struct Scsi_Host *scsi_host;	u16 io_port_base;	u16 io_port_len;	struct list_head dcb_list;		/* head of going dcb list */	struct DeviceCtlBlk *dcb_run_robin;	struct DeviceCtlBlk *active_dcb;	struct list_head srb_free_list;		/* head of free srb list */	struct ScsiReqBlk *tmp_srb;	struct timer_list waiting_timer;	struct timer_list selto_timer;	u16 srb_count;	u8 sel_timeout;	u8 irq_level;	u8 tag_max_num;	u8 acb_flag;	u8 gmode2;	u8 config;	u8 lun_chk;	u8 scan_devices;	u8 hostid_bit;	u8 dcb_map[DC395x_MAX_SCSI_ID];	struct DeviceCtlBlk *children[DC395x_MAX_SCSI_ID][32];	struct pci_dev *dev;	u8 msg_len;	struct ScsiReqBlk srb_array[DC395x_MAX_SRB_CNT];	struct ScsiReqBlk srb;	struct NvRamType eeprom;	/* eeprom settings for this adapter */};/*---------------------------------------------------------------------------                            Forward declarations ---------------------------------------------------------------------------*/static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,		u16 *pscsi_status);static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 		u16 *pscsi_status);static void set_basic_config(struct AdapterCtlBlk *acb);static void cleanup_after_transfer(struct AdapterCtlBlk *acb,		struct ScsiReqBlk *srb);static void reset_scsi_bus(struct AdapterCtlBlk *acb);static void data_io_transfer(struct AdapterCtlBlk *acb,		struct ScsiReqBlk *srb, u16 io_dir);static void disconnect(struct AdapterCtlBlk *acb);static void reselect(struct AdapterCtlBlk *acb);static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,		struct ScsiReqBlk *srb);static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,		struct ScsiReqBlk *srb);static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,		struct ScsiReqBlk *srb);static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code,		struct scsi_cmnd *cmd, u8 force);static void scsi_reset_detect(struct AdapterCtlBlk *acb);static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb);static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,		struct ScsiReqBlk *srb);static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,		struct ScsiReqBlk *srb);static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,		struct ScsiReqBlk *srb);static void set_xfer_rate(struct AdapterCtlBlk *acb,		struct DeviceCtlBlk *dcb);static void waiting_timeout(unsigned long ptr);/*---------------------------------------------------------------------------                                 Static Data ---------------------------------------------------------------------------*/static u16 current_sync_offset = 0;static void *dc395x_scsi_phase0[] = {	data_out_phase0,/* phase:0 */	data_in_phase0,	/* phase:1 */	command_phase0,	/* phase:2 */	status_phase0,	/* phase:3 */	nop0,		/* phase:4 PH_BUS_FREE .. initial phase */	nop0,		/* phase:5 PH_BUS_FREE .. initial phase */	msgout_phase0,	/* phase:6 */	msgin_phase0,	/* phase:7 */};static void *dc395x_scsi_phase1[] = {	data_out_phase1,/* phase:0 */	data_in_phase1,	/* phase:1 */	command_phase1,	/* phase:2 */	status_phase1,	/* phase:3 */	nop1,		/* phase:4 PH_BUS_FREE .. initial phase */	nop1,		/* phase:5 PH_BUS_FREE .. initial phase */	msgout_phase1,	/* phase:6 */	msgin_phase1,	/* phase:7 */};/* *Fast20:	000	 50ns, 20.0 MHz *		001	 75ns, 13.3 MHz *		010	100ns, 10.0 MHz *		011	125ns,  8.0 MHz *		100	150ns,  6.6 MHz *		101	175ns,  5.7 MHz *		110	200ns,  5.0 MHz *		111	250ns,  4.0 MHz * *Fast40(LVDS):	000	 25ns, 40.0 MHz *		001	 50ns, 20.0 MHz *		010	 75ns, 13.3 MHz *		011	100ns, 10.0 MHz *		100	125ns,  8.0 MHz

⌨️ 快捷键说明

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