/drivers/scsi/ips.c
https://bitbucket.org/abioy/linux · C · 7245 lines · 4494 code · 1179 blank · 1572 comment · 970 complexity · 6d296e885505925d4a54f4a10c45cbc1 MD5 · raw file
Large files are truncated click here to view the full file
- /*****************************************************************************/
- /* ips.c -- driver for the Adaptec / IBM ServeRAID controller */
- /* */
- /* Written By: Keith Mitchell, IBM Corporation */
- /* Jack Hammer, Adaptec, Inc. */
- /* David Jeffery, Adaptec, Inc. */
- /* */
- /* Copyright (C) 2000 IBM Corporation */
- /* Copyright (C) 2002,2003 Adaptec, Inc. */
- /* */
- /* 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 about this driver should be mailed to: */
- /* ipslinux@adaptec.com */
- /* */
- /* For system support issues, contact your local IBM Customer support. */
- /* Directions to find IBM Customer Support for each country can be found at: */
- /* http://www.ibm.com/planetwide/ */
- /* */
- /*****************************************************************************/
- /*****************************************************************************/
- /* 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 firmware 3.60 */
- /* - Change version to 3.60 to coincide with 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 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@infradead.org> */
- /* 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 */
- /* 4.50.01 - Fix problem when there is a hole in logical drive numbering */
- /* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */
- /* - Add IPSSEND Flash Support */
- /* - Set Sense Data for Unknown SCSI Command */
- /* - Use Slot Number from NVRAM Page 5 */
- /* - Restore caller's DCDB Structure */
- /* 4.70.12 - Corrective actions for bad controller ( during initialization )*/
- /* 4.70.13 - Don't Send CDB's if we already know the device is not present */
- /* - Don't release HA Lock in ips_next() until SC taken off queue */
- /* - Unregister SCSI device in ips_release() */
- /* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */
- /* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */
- /* Code Clean-Up for 2.4.x kernel */
- /* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */
- /* 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) */
- /* - Don't Issue Internal FFDC Command if there are Active Commands */
- /* - Close Window for getting too many IOCTL's active */
- /* 4.80.00 - Make ia64 Safe */
- /* 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater */
- /* - Adjustments to Device Queue Depth */
- /* 4.80.14 - Take all semaphores off stack */
- /* - Clean Up New_IOCTL path */
- /* 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) */
- /* - 5 second delay needed after resetting an i960 adapter */
- /* 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) */
- /* 4.90.01 - Version Matching for FirmWare, BIOS, and Driver */
- /* 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development */
- /* 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) */
- /* 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K */
- /* 4.90.11 - Don't actually RESET unless it's physically required */
- /* - Remove unused compile options */
- /* 5.00.01 - Sarasota ( 5i ) adapters must always be scanned first */
- /* - Get rid on IOCTL_NEW_COMMAND code */
- /* - Add Extended DCDB Commands for Tape Support in 5I */
- /* 5.10.12 - use pci_dma interfaces, update for 2.5 kernel changes */
- /* 5.10.15 - remove unused code (sem, macros, etc.) */
- /* 5.30.00 - use __devexit_p() */
- /* 6.00.00 - Add 6x Adapters and Battery Flash */
- /* 6.10.00 - Remove 1G Addressing Limitations */
- /* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */
- /* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */
- /* 7.10.18 - Add highmem_io flag in SCSI Templete for 2.4 kernels */
- /* - Fix path/name for scsi_hosts.h include for 2.6 kernels */
- /* - Fix sort order of 7k */
- /* - Remove 3 unused "inline" functions */
- /* 7.12.xx - Use STATIC functions whereever possible */
- /* - Clean up deprecated MODULE_PARM calls */
- /* 7.12.05 - Remove Version Matching per IBM request */
- /*****************************************************************************/
- /*
- * 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)
- *
- * noi2o - Don't use I2O Queues (ServeRAID 4 only)
- * nommap - Don't use memory mapped I/O
- * ioctlsize - Initial size of the IOCTL buffer
- */
- #include <asm/io.h>
- #include <asm/byteorder.h>
- #include <asm/page.h>
- #include <linux/stddef.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/ioport.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/pci.h>
- #include <linux/proc_fs.h>
- #include <linux/reboot.h>
- #include <linux/interrupt.h>
- #include <linux/blkdev.h>
- #include <linux/types.h>
- #include <linux/dma-mapping.h>
- #include <scsi/sg.h>
- #include "scsi.h"
- #include <scsi/scsi_host.h>
- #include "ips.h"
- #include <linux/module.h>
- #include <linux/stat.h>
- #include <linux/spinlock.h>
- #include <linux/init.h>
- #include <linux/smp.h>
- #ifdef MODULE
- static char *ips = NULL;
- module_param(ips, charp, 0);
- #endif
- /*
- * DRIVER_VER
- */
- #define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING
- #define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " "
- #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
- #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
- #endif
- #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
- DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
- PCI_DMA_BIDIRECTIONAL : \
- scb->scsi_cmd->sc_data_direction)
- #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
- /*
- * Function prototypes
- */
- static int ips_detect(struct scsi_host_template *);
- static int ips_release(struct Scsi_Host *);
- static int ips_eh_abort(struct scsi_cmnd *);
- static int ips_eh_reset(struct scsi_cmnd *);
- static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
- static const char *ips_info(struct Scsi_Host *);
- static irqreturn_t do_ipsintr(int, void *);
- 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_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_deallocatescbs(ips_ha_t *, int);
- 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 int ips_erase_bios(ips_ha_t *);
- static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
- static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
- static int ips_erase_bios_memio(ips_ha_t *);
- static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
- static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
- static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
- static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
- static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
- static void ips_free_flash_copperhead(ips_ha_t * ha);
- static void ips_get_bios_version(ips_ha_t *, int);
- static void ips_identify_controller(ips_ha_t *);
- 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 int ips_intr_copperhead(ips_ha_t *);
- static int 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_setup_funclist(ips_ha_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 *);
- static uint32_t ips_statupd_copperhead(ips_ha_t *);
- static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
- static uint32_t ips_statupd_morpheus(ips_ha_t *);
- static ips_scb_t *ips_getscb(ips_ha_t *);
- static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
- static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *);
- static void ips_putq_copp_tail(ips_copp_queue_t *,
- ips_copp_wait_item_t *);
- static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
- static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
- static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
- static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *,
- struct scsi_cmnd *);
- static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
- ips_copp_wait_item_t *);
- static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
- static int ips_is_passthru(struct scsi_cmnd *);
- static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int);
- static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
- static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
- static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
- unsigned int count);
- static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data,
- unsigned int count);
- static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
- static int ips_host_info(ips_ha_t *, char *, off_t, int);
- static void copy_mem_info(IPS_INFOSTR *, char *, int);
- static int copy_info(IPS_INFOSTR *, char *, ...);
- static int ips_abort_init(ips_ha_t * ha, int index);
- static int ips_init_phase2(int index);
- static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
- static int ips_register_scsi(int index);
- static int ips_poll_for_flush_complete(ips_ha_t * ha);
- static void ips_flush_and_reset(ips_ha_t *ha);
- /*
- * 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;
- static unsigned int ips_num_controllers;
- static unsigned int ips_released_controllers;
- static int ips_hotplug;
- 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_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */
- static int ips_cd_boot; /* Booting from Manager CD */
- static char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */
- static dma_addr_t ips_flashbusaddr;
- static long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */
- static uint32_t MaxLiteCmds = 32; /* Max Active Cmds for a Lite Adapter */
- static struct scsi_host_template ips_driver_template = {
- .detect = ips_detect,
- .release = ips_release,
- .info = ips_info,
- .queuecommand = ips_queue,
- .eh_abort_handler = ips_eh_abort,
- .eh_host_reset_handler = ips_eh_reset,
- .proc_name = "ips",
- .proc_info = ips_proc_info,
- .slave_configure = ips_slave_configure,
- .bios_param = ips_biosparam,
- .this_id = -1,
- .sg_tablesize = IPS_MAX_SG,
- .cmd_per_lun = 3,
- .use_clustering = ENABLE_CLUSTERING,
- };
- /* This table describes all ServeRAID Adapters */
- static struct pci_device_id ips_pci_table[] = {
- { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
- };
- MODULE_DEVICE_TABLE( pci, ips_pci_table );
- static char ips_hot_plug_name[] = "ips";
- static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
- static void __devexit ips_remove_device(struct pci_dev *pci_dev);
- static struct pci_driver ips_pci_driver = {
- .name = ips_hot_plug_name,
- .id_table = ips_pci_table,
- .probe = ips_insert_device,
- .remove = __devexit_p(ips_remove_device),
- };
- /*
- * Necessary forward function protoypes
- */
- static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
- #define MAX_ADAPTER_NAME 15
- static char ips_adapter_name[][30] = {
- "ServeRAID",
- "ServeRAID II",
- "ServeRAID on motherboard",
- "ServeRAID on motherboard",
- "ServeRAID 3H",
- "ServeRAID 3L",
- "ServeRAID 4H",
- "ServeRAID 4M",
- "ServeRAID 4L",
- "ServeRAID 4Mx",
- "ServeRAID 4Lx",
- "ServeRAID 5i",
- "ServeRAID 5i",
- "ServeRAID 6M",
- "ServeRAID 6i",
- "ServeRAID 7t",
- "ServeRAID 7k",
- "ServeRAID 7M"
- };
- 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_NONE, 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
- };
- /****************************************************************************/
- /* */
- /* Routine Name: ips_setup */
- /* */
- /* Routine Description: */
- /* */
- /* setup parameters to the driver */
- /* */
- /****************************************************************************/
- static int
- ips_setup(char *ips_str)
- {
- int i;
- char *key;
- char *value;
- IPS_OPTION options[] = {
- {"noi2o", &ips_force_i2o, 0},
- {"nommap", &ips_force_memio, 0},
- {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
- {"cdboot", &ips_cd_boot, 0},
- {"maxcmds", &MaxLiteCmds, 32},
- };
- /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
- /* Search for value */
- while ((key = strsep(&ips_str, ",."))) {
- if (!*key)
- continue;
- value = strchr(key, ':');
- if (value)
- *value++ = '\0';
- /*
- * We now have key/value pairs.
- * Update the variables
- */
- for (i = 0; i < ARRAY_SIZE(options); i++) {
- if (strnicmp
- (key, options[i].option_name,
- strlen(options[i].option_name)) == 0) {
- if (value)
- *options[i].option_flag =
- simple_strtoul(value, NULL, 0);
- else
- *options[i].option_flag =
- options[i].option_value;
- break;
- }
- }
- }
- return (1);
- }
- __setup("ips=", ips_setup);
- /****************************************************************************/
- /* */
- /* Routine Name: ips_detect */
- /* */
- /* Routine Description: */
- /* */
- /* Detect and initialize the driver */
- /* */
- /* NOTE: this routine is called under the io_request_lock spinlock */
- /* */
- /****************************************************************************/
- static int
- ips_detect(struct scsi_host_template * SHT)
- {
- int i;
- METHOD_TRACE("ips_detect", 1);
- #ifdef MODULE
- if (ips)
- ips_setup(ips);
- #endif
- for (i = 0; i < ips_num_controllers; i++) {
- if (ips_register_scsi(i))
- ips_free(ips_ha[i]);
- ips_released_controllers++;
- }
- ips_hotplug = 1;
- return (ips_num_controllers);
- }
- /****************************************************************************/
- /* configure the function pointers to use the functions that will work */
- /* with the found version of the adapter */
- /****************************************************************************/
- static void
- ips_setup_funclist(ips_ha_t * ha)
- {
- /*
- * Setup Functions
- */
- if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
- /* morpheus / marco / sebring */
- ha->func.isintr = ips_isintr_morpheus;
- ha->func.isinit = ips_isinit_morpheus;
- ha->func.issue = ips_issue_i2o_memio;
- ha->func.init = ips_init_morpheus;
- ha->func.statupd = ips_statupd_morpheus;
- ha->func.reset = ips_reset_morpheus;
- ha->func.intr = ips_intr_morpheus;
- ha->func.enableint = ips_enable_int_morpheus;
- } else if (IPS_USE_MEMIO(ha)) {
- /* copperhead w/MEMIO */
- ha->func.isintr = ips_isintr_copperhead_memio;
- ha->func.isinit = ips_isinit_copperhead_memio;
- ha->func.init = ips_init_copperhead_memio;
- ha->func.statupd = ips_statupd_copperhead_memio;
- ha->func.statinit = ips_statinit_memio;
- ha->func.reset = ips_reset_copperhead_memio;
- ha->func.intr = ips_intr_copperhead;
- ha->func.erasebios = ips_erase_bios_memio;
- ha->func.programbios = ips_program_bios_memio;
- ha->func.verifybios = ips_verify_bios_memio;
- ha->func.enableint = ips_enable_int_copperhead_memio;
- if (IPS_USE_I2O_DELIVER(ha))
- ha->func.issue = ips_issue_i2o_memio;
- else
- ha->func.issue = ips_issue_copperhead_memio;
- } else {
- /* copperhead */
- ha->func.isintr = ips_isintr_copperhead;
- ha->func.isinit = ips_isinit_copperhead;
- ha->func.init = ips_init_copperhead;
- ha->func.statupd = ips_statupd_copperhead;
- ha->func.statinit = ips_statinit;
- ha->func.reset = ips_reset_copperhead;
- ha->func.intr = ips_intr_copperhead;
- ha->func.erasebios = ips_erase_bios;
- ha->func.programbios = ips_program_bios;
- ha->func.verifybios = ips_verify_bios;
- ha->func.enableint = ips_enable_int_copperhead;
- if (IPS_USE_I2O_DELIVER(ha))
- ha->func.issue = ips_issue_i2o;
- else
- ha->func.issue = ips_issue_copperhead;
- }
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_release */
- /* */
- /* Routine Description: */
- /* */
- /* Remove a driver */
- /* */
- /****************************************************************************/
- static int
- ips_release(struct Scsi_Host *sh)
- {
- ips_scb_t *scb;
- ips_ha_t *ha;
- int i;
- METHOD_TRACE("ips_release", 1);
- scsi_remove_host(sh);
- for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
- if (i == IPS_MAX_ADAPTERS) {
- printk(KERN_WARNING
- "(%s) release, invalid Scsi_Host pointer.\n", ips_name);
- BUG();
- return (FALSE);
- }
- ha = IPS_HA(sh);
- if (!ha)
- return (FALSE);
- /* flush the cache on the controller */
- scb = &ha->scbs[ha->max_cmds - 1];
- ips_init_scb(ha, scb);
- scb->timeout = ips_cmd_timeout;
- scb->cdb[0] = IPS_CMD_FLUSH;
- scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
- scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.flush_cache.state = IPS_NORM_STATE;
- scb->cmd.flush_cache.reserved = 0;
- scb->cmd.flush_cache.reserved2 = 0;
- scb->cmd.flush_cache.reserved3 = 0;
- scb->cmd.flush_cache.reserved4 = 0;
- IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
- /* send command */
- if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
- IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
- IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
- ips_sh[i] = NULL;
- ips_ha[i] = NULL;
- /* free extra memory */
- ips_free(ha);
- /* free IRQ */
- free_irq(ha->pcidev->irq, ha);
- scsi_host_put(sh);
- ips_released_controllers++;
- return (FALSE);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_halt */
- /* */
- /* Routine Description: */
- /* */
- /* Perform cleanup when the system reboots */
- /* */
- /****************************************************************************/
- static int
- ips_halt(struct notifier_block *nb, ulong event, void *buf)
- {
- ips_scb_t *scb;
- ips_ha_t *ha;
- int i;
- if ((event != SYS_RESTART) && (event != SYS_HALT) &&
- (event != SYS_POWER_OFF))
- return (NOTIFY_DONE);
- for (i = 0; i < ips_next_controller; i++) {
- ha = (ips_ha_t *) ips_ha[i];
- if (!ha)
- continue;
- if (!ha->active)
- continue;
- /* flush the cache on the controller */
- scb = &ha->scbs[ha->max_cmds - 1];
- ips_init_scb(ha, scb);
- scb->timeout = ips_cmd_timeout;
- scb->cdb[0] = IPS_CMD_FLUSH;
- scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
- scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.flush_cache.state = IPS_NORM_STATE;
- scb->cmd.flush_cache.reserved = 0;
- scb->cmd.flush_cache.reserved2 = 0;
- scb->cmd.flush_cache.reserved3 = 0;
- scb->cmd.flush_cache.reserved4 = 0;
- IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
- /* send command */
- if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==
- IPS_FAILURE)
- IPS_PRINTK(KERN_WARNING, ha->pcidev,
- "Incomplete Flush.\n");
- else
- IPS_PRINTK(KERN_WARNING, ha->pcidev,
- "Flushing Complete.\n");
- }
- return (NOTIFY_OK);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_eh_abort */
- /* */
- /* Routine Description: */
- /* */
- /* Abort a command (using the new error code stuff) */
- /* Note: this routine is called under the io_request_lock */
- /****************************************************************************/
- int ips_eh_abort(struct scsi_cmnd *SC)
- {
- ips_ha_t *ha;
- ips_copp_wait_item_t *item;
- int ret;
- struct Scsi_Host *host;
- METHOD_TRACE("ips_eh_abort", 1);
- if (!SC)
- return (FAILED);
- host = SC->device->host;
- ha = (ips_ha_t *) SC->device->host->hostdata;
- if (!ha)
- return (FAILED);
- if (!ha->active)
- return (FAILED);
- spin_lock(host->host_lock);
- /* See if the command is on the copp queue */
- item = ha->copp_waitlist.head;
- while ((item) && (item->scsi_cmd != SC))
- item = item->next;
- if (item) {
- /* Found it */
- ips_removeq_copp(&ha->copp_waitlist, item);
- ret = (SUCCESS);
- /* See if the command is on the wait queue */
- } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
- /* command not sent yet */
- ret = (SUCCESS);
- } else {
- /* command must have already been sent */
- ret = (FAILED);
- }
- spin_unlock(host->host_lock);
- return ret;
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_eh_reset */
- /* */
- /* Routine Description: */
- /* */
- /* Reset the controller (with new eh error code) */
- /* */
- /* NOTE: this routine is called under the io_request_lock spinlock */
- /* */
- /****************************************************************************/
- static int __ips_eh_reset(struct scsi_cmnd *SC)
- {
- int ret;
- int i;
- ips_ha_t *ha;
- ips_scb_t *scb;
- ips_copp_wait_item_t *item;
- METHOD_TRACE("ips_eh_reset", 1);
- #ifdef NO_IPS_RESET
- return (FAILED);
- #else
- if (!SC) {
- DEBUG(1, "Reset called with NULL scsi command");
- return (FAILED);
- }
- ha = (ips_ha_t *) SC->device->host->hostdata;
- if (!ha) {
- DEBUG(1, "Reset called with NULL ha struct");
- return (FAILED);
- }
- if (!ha->active)
- return (FAILED);
- /* See if the command is on the copp queue */
- item = ha->copp_waitlist.head;
- while ((item) && (item->scsi_cmd != SC))
- item = item->next;
- if (item) {
- /* Found it */
- ips_removeq_copp(&ha->copp_waitlist, item);
- return (SUCCESS);
- }
- /* See if the command is on the wait queue */
- if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
- /* command not sent yet */
- return (SUCCESS);
- }
- /* An explanation for the casual observer: */
- /* Part of the function of a RAID controller is automatic error */
- /* detection and recovery. As such, the only problem that physically */
- /* resetting an adapter will ever fix is when, for some reason, */
- /* the driver is not successfully communicating with the adapter. */
- /* Therefore, we will attempt to flush this adapter. If that succeeds, */
- /* then there's no real purpose in a physical reset. This will complete */
- /* much faster and avoids any problems that might be caused by a */
- /* physical reset ( such as having to fail all the outstanding I/O's ). */
- if (ha->ioctl_reset == 0) { /* IF Not an IOCTL Requested Reset */
- scb = &ha->scbs[ha->max_cmds - 1];
- ips_init_scb(ha, scb);
- scb->timeout = ips_cmd_timeout;
- scb->cdb[0] = IPS_CMD_FLUSH;
- scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
- scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
- scb->cmd.flush_cache.state = IPS_NORM_STATE;
- scb->cmd.flush_cache.reserved = 0;
- scb->cmd.flush_cache.reserved2 = 0;
- scb->cmd.flush_cache.reserved3 = 0;
- scb->cmd.flush_cache.reserved4 = 0;
- /* Attempt the flush command */
- ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
- if (ret == IPS_SUCCESS) {
- IPS_PRINTK(KERN_NOTICE, ha->pcidev,
- "Reset Request - Flushed Cache\n");
- return (SUCCESS);
- }
- }
- /* Either we can't communicate with the adapter or it's an IOCTL request */
- /* from a utility. A physical reset is needed at this point. */
- ha->ioctl_reset = 0; /* Reset the IOCTL Requested Reset Flag */
- /*
- * command must have already been sent
- * reset the controller
- */
- IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
- ret = (*ha->func.reset) (ha);
- if (!ret) {
- struct scsi_cmnd *scsi_cmd;
- IPS_PRINTK(KERN_NOTICE, ha->pcidev,
- "Controller reset failed - controller now offline.\n");
- /* Now fail all of the active commands */
- DEBUG_VAR(1, "(%s%d) Failing active commands",
- ips_name, ha->host_num);
- while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
- scb->scsi_cmd->result = DID_ERROR << 16;
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- ips_freescb(ha, scb);
- }
- /* Now fail all of the pending commands */
- DEBUG_VAR(1, "(%s%d) Failing pending commands",
- ips_name, ha->host_num);
- while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
- scsi_cmd->result = DID_ERROR;
- scsi_cmd->scsi_done(scsi_cmd);
- }
- ha->active = FALSE;
- return (FAILED);
- }
- if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
- struct scsi_cmnd *scsi_cmd;
- IPS_PRINTK(KERN_NOTICE, ha->pcidev,
- "Controller reset failed - controller now offline.\n");
- /* Now fail all of the active commands */
- DEBUG_VAR(1, "(%s%d) Failing active commands",
- ips_name, ha->host_num);
- while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
- scb->scsi_cmd->result = DID_ERROR << 16;
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- ips_freescb(ha, scb);
- }
- /* Now fail all of the pending commands */
- DEBUG_VAR(1, "(%s%d) Failing pending commands",
- ips_name, ha->host_num);
- while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
- scsi_cmd->result = DID_ERROR << 16;
- scsi_cmd->scsi_done(scsi_cmd);
- }
- ha->active = FALSE;
- return (FAILED);
- }
- /* FFDC */
- if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
- struct timeval tv;
- do_gettimeofday(&tv);
- ha->last_ffdc = tv.tv_sec;
- ha->reset_count++;
- ips_ffdc_reset(ha, IPS_INTR_IORL);
- }
- /* Now fail all of the active commands */
- DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
- while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
- scb->scsi_cmd->result = DID_RESET << 16;
- scb->scsi_cmd->scsi_done(scb->scsi_cmd);
- ips_freescb(ha, scb);
- }
- /* Reset DCDB active command bits */
- for (i = 1; i < ha->nbus; i++)
- ha->dcdb_active[i - 1] = 0;
- /* Reset the number of active IOCTLs */
- ha->num_ioctl = 0;
- ips_next(ha, IPS_INTR_IORL);
- return (SUCCESS);
- #endif /* NO_IPS_RESET */
- }
- static int ips_eh_reset(struct scsi_cmnd *SC)
- {
- int rc;
- spin_lock_irq(SC->device->host->host_lock);
- rc = __ips_eh_reset(SC);
- spin_unlock_irq(SC->device->host->host_lock);
- return rc;
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_queue */
- /* */
- /* Routine Description: */
- /* */
- /* Send a command to the controller */
- /* */
- /* NOTE: */
- /* Linux obtains io_request_lock before calling this function */
- /* */
- /****************************************************************************/
- static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
- {
- ips_ha_t *ha;
- ips_passthru_t *pt;
- METHOD_TRACE("ips_queue", 1);
- ha = (ips_ha_t *) SC->device->host->hostdata;
- if (!ha)
- return (1);
- if (!ha->active)
- return (DID_ERROR);
- if (ips_is_passthru(SC)) {
- if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
- SC->result = DID_BUS_BUSY << 16;
- done(SC);
- return (0);
- }
- } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
- SC->result = DID_BUS_BUSY << 16;
- done(SC);
- return (0);
- }
- SC->scsi_done = done;
- DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
- ips_name,
- ha->host_num,
- SC->cmnd[0],
- SC->device->channel, SC->device->id, SC->device->lun);
- /* Check for command to initiator IDs */
- if ((scmd_channel(SC) > 0)
- && (scmd_id(SC) == ha->ha_id[scmd_channel(SC)])) {
- SC->result = DID_NO_CONNECT << 16;
- done(SC);
- return (0);
- }
- if (ips_is_passthru(SC)) {
- ips_copp_wait_item_t *scratch;
- /* A Reset IOCTL is only sent by the boot CD in extreme cases. */
- /* There can never be any system activity ( network or disk ), but check */
- /* anyway just as a good practice. */
- pt = (ips_passthru_t *) scsi_sglist(SC);
- if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
- (pt->CoppCP.cmd.reset.adapter_flag == 1)) {
- if (ha->scb_activelist.count != 0) {
- SC->result = DID_BUS_BUSY << 16;
- done(SC);
- return (0);
- }
- ha->ioctl_reset = 1; /* This reset request is from an IOCTL */
- __ips_eh_reset(SC);
- SC->result = DID_OK << 16;
- SC->scsi_done(SC);
- return (0);
- }
- /* allocate space for the scribble */
- scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC);
- if (!scratch) {
- SC->result = DID_ERROR << 16;
- done(SC);
- return (0);
- }
- scratch->scsi_cmd = SC;
- scratch->next = NULL;
- ips_putq_copp_tail(&ha->copp_waitlist, scratch);
- } else {
- ips_putq_wait_tail(&ha->scb_waitlist, SC);
- }
- ips_next(ha, IPS_INTR_IORL);
- return (0);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_biosparam */
- /* */
- /* Routine Description: */
- /* */
- /* Set bios geometry for the controller */
- /* */
- /****************************************************************************/
- static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int geom[])
- {
- ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
- int heads;
- int sectors;
- int cylinders;
- METHOD_TRACE("ips_biosparam", 1);
- if (!ha)
- /* ?!?! host adater info invalid */
- return (0);
- if (!ha->active)
- return (0);
- if (!ips_read_adapter_status(ha, IPS_INTR_ON))
- /* ?!?! Enquiry command failed */
- return (0);
- if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
- heads = IPS_NORM_HEADS;
- sectors = IPS_NORM_SECTORS;
- } else {
- heads = IPS_COMP_HEADS;
- sectors = IPS_COMP_SECTORS;
- }
- cylinders = (unsigned long) capacity / (heads * sectors);
- DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
- heads, sectors, cylinders);
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
- return (0);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_slave_configure */
- /* */
- /* Routine Description: */
- /* */
- /* Set queue depths on devices once scan is complete */
- /* */
- /****************************************************************************/
- static int
- ips_slave_configure(struct scsi_device * SDptr)
- {
- ips_ha_t *ha;
- int min;
- ha = IPS_HA(SDptr->host);
- if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) {
- min = ha->max_cmds / 2;
- if (ha->enq->ucLogDriveCount <= 2)
- min = ha->max_cmds - 1;
- scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
- }
- SDptr->skip_ms_page_8 = 1;
- SDptr->skip_ms_page_3f = 1;
- return 0;
- }
- /****************************************************************************/
- /* */
- /* Routine Name: do_ipsintr */
- /* */
- /* Routine Description: */
- /* */
- /* Wrapper for the interrupt handler */
- /* */
- /****************************************************************************/
- static irqreturn_t
- do_ipsintr(int irq, void *dev_id)
- {
- ips_ha_t *ha;
- struct Scsi_Host *host;
- int irqstatus;
- METHOD_TRACE("do_ipsintr", 2);
- ha = (ips_ha_t *) dev_id;
- if (!ha)
- return IRQ_NONE;
- host = ips_sh[ha->host_num];
- /* interrupt during initialization */
- if (!host) {
- (*ha->func.intr) (ha);
- return IRQ_HANDLED;
- }
- spin_lock(host->host_lock);
- if (!ha->active) {
- spin_unlock(host->host_lock);
- return IRQ_HANDLED;
- }
- irqstatus = (*ha->func.intr) (ha);
- spin_unlock(host->host_lock);
- /* start the next command */
- ips_next(ha, IPS_INTR_ON);
- return IRQ_RETVAL(irqstatus);
- }
- /****************************************************************************/
- /* */
- /* Routine Name: ips_intr_copperhead */
- /* */
- /* Routine Description: */
- /* */
- /* Polling interrupt handler */
- /* */
- /* ASSUMES interrupts are disabled */
- /*…