📄 ips.c
字号:
/*****************************************************************************//* ips.c -- driver for the IBM ServeRAID controller *//* *//* Written By: Keith Mitchell, IBM Corporation *//* *//* Copyright (C) 1999 IBM Corporation *//* *//* 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 of the License, 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. *//* *//* NO WARRANTY *//* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR *//* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT *//* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, *//* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is *//* solely responsible for determining the appropriateness of using and *//* distributing the Program and assumes all risks associated with its *//* exercise of rights under this Agreement, including but not limited to *//* the risks and costs of program errors, damage to or loss of data, *//* programs or equipment, and unavailability or interruption of operations. *//* *//* DISCLAIMER OF LIABILITY *//* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY *//* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *//* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED *//* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES *//* *//* You should have received a copy of the GNU General Public License *//* along with this program; if not, write to the Free Software *//* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* *//* Bugs/Comments/Suggestions should be mailed to: *//* ipslinux@us.ibm.com *//* *//*****************************************************************************//*****************************************************************************//* Change Log *//* *//* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size *//* 0.99.03 - Make interrupt routine handle all completed request on the *//* adapter not just the first one *//* - Make sure passthru commands get woken up if we run out of *//* SCBs *//* - Send all of the commands on the queue at once rather than *//* one at a time since the card will support it. *//* 0.99.04 - Fix race condition in the passthru mechanism -- this required *//* the interface to the utilities to change *//* - Fix error recovery code *//* 0.99.05 - Fix an oops when we get certain passthru commands *//* 1.00.00 - Initial Public Release *//* Functionally equivalent to 0.99.05 *//* 3.60.00 - Bump max commands to 128 for use with ServeRAID firmware 3.60 *//* - Change version to 3.60 to coincide with ServeRAID release *//* numbering. *//* 3.60.01 - Remove bogus error check in passthru routine *//* 3.60.02 - Make DCDB direction based on lookup table *//* - Only allow one DCDB command to a SCSI ID at a time *//* 4.00.00 - Add support for ServeRAID 4 *//* 4.00.01 - Add support for First Failure Data Capture *//* 4.00.02 - Fix problem with PT DCDB with no buffer *//* 4.00.03 - Add alternative passthru interface *//* - Add ability to flash ServeRAID BIOS *//* 4.00.04 - Rename structures/constants to be prefixed with IPS_ *//* 4.00.05 - Remove wish_block from init routine *//* - Use linux/spinlock.h instead of asm/spinlock.h for kernels *//* 2.3.18 and later *//* - Sync with other changes from the 2.3 kernels *//* 4.00.06 - Fix timeout with initial FFDC command *//* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@caldera.de> *//* 4.10.00 - Add support for ServeRAID 4M/4L *//* 4.10.13 - Fix for dynamic unload and proc file system *//* 4.20.03 - Rename version to coincide with new release schedules *//* Performance fixes *//* Fix truncation of /proc files with cat *//* Merge in changes through kernel 2.4.0test1ac21 *//* 4.20.13 - Fix some failure cases / reset code *//* - Hook into the reboot_notifier to flush the controller cache *//* *//*****************************************************************************//* * Conditional Compilation directives for this driver: * * IPS_DEBUG - Turn on debugging info * * * Parameters: * * debug:<number> - Set debug level to <number> * NOTE: only works when IPS_DEBUG compile directive * is used. * * 1 - Normal debug messages * 2 - Verbose debug messages * 11 - Method trace (non interrupt) * 12 - Method trace (includes interrupt) * * noreset - Don't reset the controller * nocmdline - Turn off passthru support * noi2o - Don't use I2O Queues (ServeRAID 4 only) * nommap - Don't use memory mapped I/O */ #include <linux/module.h>#include <asm/io.h>#include <asm/byteorder.h>#include <linux/stddef.h>#include <linux/version.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/reboot.h>#include <linux/blk.h>#include <linux/types.h>#ifndef NO_IPS_CMDLINE#include <scsi/sg.h>#endif#include "sd.h"#include "scsi.h"#include "hosts.h"#include "ips.h"#include <linux/stat.h>#include <linux/config.h>#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,18)#include <linux/spinlock.h>#else#include <asm/spinlock.h>#endif#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)#include <linux/init.h>#endif#include <linux/smp.h>#ifdef MODULE static char *ips = NULL; MODULE_PARM(ips, "s");#endif/* * DRIVER_VER */#define IPS_VERSION_HIGH "4.20"#define IPS_VERSION_LOW ".20 "#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)struct proc_dir_entry proc_scsi_ips = { 0, 3, "ips", S_IFDIR | S_IRUGO | S_IXUGO, 2};#endif#if !defined(__i386__) #error "This driver has only been tested on the x86 platform"#endif#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) #error "This driver only works with kernel 2.2.0 and later"#endif#if !defined(NO_IPS_CMDLINE) && ((SG_BIG_BUFF < 8192) || !defined(SG_BIG_BUFF)) #error "To use the command-line interface you need to define SG_BIG_BUFF"#endif#ifdef IPS_DEBUG #define METHOD_TRACE(s, i) if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); #define DEBUG(i, s) if (ips_debug >= i) printk(KERN_NOTICE s "\n"); #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);#else #define METHOD_TRACE(s, i) #define DEBUG(i, s) #define DEBUG_VAR(i, s, v...)#endif/* * global variables */static const char * ips_name = "ips";static struct Scsi_Host * ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */static ips_ha_t * ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */static unsigned int ips_next_controller = 0;static unsigned int ips_num_controllers = 0;static unsigned int ips_released_controllers = 0;static int ips_cmd_timeout = 60;static int ips_reset_timeout = 60 * 5;static int ips_force_memio = 1; /* Always use Memory Mapped I/O */static int ips_force_i2o = 1; /* Always use I2O command delivery */static int ips_resetcontroller = 1; /* Reset the controller */static int ips_cmdline = 1; /* Support for passthru */#ifdef IPS_DEBUGstatic int ips_debug = 0; /* Debug mode */#endif/* * Necessary forward function protoypes */static int ips_halt(struct notifier_block *nb, ulong event, void *buf);#define MAX_ADAPTER_NAME 9static char ips_adapter_name[][30] = { "ServeRAID", "ServeRAID II", "ServeRAID on motherboard", "ServeRAID on motherboard", "ServeRAID 3H", "ServeRAID 3L", "ServeRAID 4H", "ServeRAID 4M", "ServeRAID 4L"};static struct notifier_block ips_notifier = { ips_halt, NULL, 0};/* * Direction table */static char ips_command_direction[] = {IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK};/* * Function prototypes */int ips_detect(Scsi_Host_Template *);int ips_release(struct Scsi_Host *);int ips_eh_abort(Scsi_Cmnd *);int ips_eh_reset(Scsi_Cmnd *);int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));int ips_biosparam(Disk *, kdev_t, int *);const char * ips_info(struct Scsi_Host *);void do_ipsintr(int, void *, struct pt_regs *);static int ips_hainit(ips_ha_t *);static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);static int ips_send(ips_ha_t *, ips_scb_t *, ips_scb_callback);static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);static int ips_send_cmd(ips_ha_t *, ips_scb_t *);static int ips_online(ips_ha_t *, ips_scb_t *);static int ips_inquiry(ips_ha_t *, ips_scb_t *);static int ips_rdcap(ips_ha_t *, ips_scb_t *);static int ips_msense(ips_ha_t *, ips_scb_t *);static int ips_reqsen(ips_ha_t *, ips_scb_t *);static int ips_allocatescbs(ips_ha_t *);static int ips_reset_copperhead(ips_ha_t *);static int ips_reset_copperhead_memio(ips_ha_t *);static int ips_reset_morpheus(ips_ha_t *);static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);static int ips_isintr_copperhead(ips_ha_t *);static int ips_isintr_copperhead_memio(ips_ha_t *);static int ips_isintr_morpheus(ips_ha_t *);static int ips_wait(ips_ha_t *, int, int);static int ips_write_driver_status(ips_ha_t *, int);static int ips_read_adapter_status(ips_ha_t *, int);static int ips_read_subsystem_parameters(ips_ha_t *, int);static int ips_read_config(ips_ha_t *, int);static int ips_clear_adapter(ips_ha_t *, int);static int ips_readwrite_page5(ips_ha_t *, int, int);static int ips_init_copperhead(ips_ha_t *);static int ips_init_copperhead_memio(ips_ha_t *);static int ips_init_morpheus(ips_ha_t *);static int ips_isinit_copperhead(ips_ha_t *);static int ips_isinit_copperhead_memio(ips_ha_t *);static int ips_isinit_morpheus(ips_ha_t *);static u32 ips_statupd_copperhead(ips_ha_t *);static u32 ips_statupd_copperhead_memio(ips_ha_t *);static u32 ips_statupd_morpheus(ips_ha_t *);static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);static void ips_enable_int_copperhead(ips_ha_t *);static void ips_enable_int_copperhead_memio(ips_ha_t *);static void ips_enable_int_morpheus(ips_ha_t *);static void ips_intr_copperhead(ips_ha_t *);static void ips_intr_morpheus(ips_ha_t *);static void ips_next(ips_ha_t *, int);static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);static void ipsintr_done(ips_ha_t *, struct ips_scb *);static void ips_done(ips_ha_t *, ips_scb_t *);static void ips_free(ips_ha_t *);static void ips_init_scb(ips_ha_t *, ips_scb_t *);static void ips_freescb(ips_ha_t *, ips_scb_t *);static void ips_statinit(ips_ha_t *);static void ips_statinit_memio(ips_ha_t *);static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);static void ips_ffdc_reset(ips_ha_t *, int);static void ips_ffdc_time(ips_ha_t *, int);static ips_scb_t * ips_getscb(ips_ha_t *);static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -