/*
* 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 <linux/vmalloc.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) */
dma_addr_t 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 */
size_t total_xfer_length; /* Total number of bytes remaining to be transfered */
size_t request_length; /* Total number of bytes in this request */
/*
* 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.
*/
size_t 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;
unsigned long io_port_base;
unsigned long 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;
unsigned int 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
* 101 150ns, 6.6 MHz
* 110 175ns, 5.7 MHz
* 111 200ns, 5.0 MHz
*/
/*static u8 clock_period[] = {12,19,25,31,37,44,50,62};*/
/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */
static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 };
static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 };
/*---------------------------------------------------------------------------
Configuration
---------------------------------------------------------------------------*/
/*
* Module/boot parameters currently effect *all* instances of the
* card in the system.
*/
/*
* Command line parameters are stored in a structure below.
* These are the index's into the structure for the various
* command line options.
*/
#define CFG_ADAPTER_ID 0
#define CFG_MAX_SPEED 1
#define CFG_DEV_MODE 2
#define CFG_ADAPTER_MODE 3
#define CFG_TAGS 4
#define CFG_RESET_DELAY 5
#define CFG_NUM 6 /* number of configuration items */
/*
* Value used to indicate that a command line override
* hasn't been used to modify the value.
*/
#define CFG_PARAM_UNSET -1
/*
* Hold command line parameters.
*/
struct ParameterData {
int value; /* value of this setting */
int min; /* minimum value */
int max; /* maximum value */
int def; /* default value */
int safe; /* safe value */
};
static struct ParameterData __devinitdata cfg_data[] = {
{ /* adapter id */
CFG_PARAM_UNSET,
0,
15,
7,
7
},
{ /* max speed */
CFG_PARAM_UNSET,
0,
7,
1, /* 13.3Mhz */
4, /* 6.7Hmz */
},
{ /* dev mode */
CFG_PARAM_UNSET,
0,
0x3f,
NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO |
NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING |
NTC_DO_SEND_START,
NTC_DO_PARITY_CHK | NTC_DO_SEND_START
},
{ /* adapter mode */
CFG_PARAM_UNSET,
0,
0x2f,
#ifdef CONFIG_SCSI_MULTI_LUN
NAC_SCANLUN |
#endif
NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET
/*| NAC_ACTIVE_NEG*/,
NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08
},
{ /* tags */
CFG_PARAM_UNSET,
0,
5,
3, /* 16 tags (??) */
2,
},
{ /* reset delay */
CFG_PARAM_UNSET,
0,
180,
1, /* 1 second */
10, /* 10 seconds */
}
};
/*
* Safe settings. If set to zero the BIOS/default values with
* command line overrides will be used. If set to 1 then safe and
* slow settings will be used.
*/
static int use_safe_settings = 0;
module_param_named(safe, use_safe_settings, bool, 0);
MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false");
module_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0);
MODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)");
module_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0);
MODULE_PARM_DESC(max_speed, "Maximum bus speed. Default 1 (0-7) Speeds: 0=20, 1=13.3, 2=10, 3=8, 4=6.7, 5=5.8, 6=5, 7=4 Mhz");
module_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0);
MODULE_PARM_DESC(dev_mode, "Device mode.");
module_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0);
MODULE_PARM_DESC(adapter_mode, "Adapter mode.");
module_param_named(tags, cfg_data[CFG_TAGS].value, int, 0);
MODULE_PARM_DESC(tags, "Number of tags (1<<x). Default 3 (0-5)");
module_param_named(reset_delay, cfg_data[CFG_RESET_DELAY].value, int, 0);
MODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)");
/**
* set_safe_settings - if the use_safe_settings option is set then
* set all values to the safe and slow values.
**/
static void __devinit set_safe_settings(void)
{
|