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