fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / scsi / ips.c
index 6f7df0a..8b704f7 100644 (file)
 /* 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                        */
 /*****************************************************************************/
 
 /*
 
 #include <linux/blkdev.h>
 #include <linux/types.h>
+#include <linux/dma-mapping.h>
 
 #include <scsi/sg.h>
-
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
+
 #include "ips.h"
 
 #include <linux/module.h>
 
 #include <linux/stat.h>
-#include <linux/config.h>
 
 #include <linux/spinlock.h>
 #include <linux/init.h>
 
 #ifdef MODULE
 static char *ips = NULL;
-MODULE_PARM(ips, "s");
+module_param(ips, charp, 0);
 #endif
 
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "7.00"
-#define IPS_VERSION_LOW         ".15 "
+#define IPS_VERSION_HIGH        "7.12"
+#define IPS_VERSION_LOW         ".05 "
 
 #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
 #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
@@ -207,23 +214,20 @@ MODULE_PARM(ips, "s");
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
 #include <linux/blk.h>
 #include "sd.h"
-#define IPS_SG_ADDRESS(sg)       ((sg)->address)
 #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
 #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
 #ifndef __devexit_p
 #define __devexit_p(x) x
 #endif
 #else
-#define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
-                                     page_address((sg)->page)+(sg)->offset : 0)
 #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
 #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
 #endif
 
 #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
-                         SCSI_DATA_NONE == scb->scsi_cmd->sc_data_direction) ? \
+                         DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
                          PCI_DMA_BIDIRECTIONAL : \
-                         scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction))
+                         scb->scsi_cmd->sc_data_direction)
 
 #ifdef IPS_DEBUG
 #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
@@ -235,6 +239,120 @@ MODULE_PARM(ips, "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
  */
@@ -255,7 +373,7 @@ 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 Scsi_Host_Template ips_driver_template = {
+static struct scsi_host_template ips_driver_template = {
        .detect                 = ips_detect,
        .release                = ips_release,
        .info                   = ips_info,
@@ -278,10 +396,11 @@ static Scsi_Host_Template ips_driver_template = {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
        .use_new_eh_code        = 1,
 #endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)  &&  LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+    .highmem_io          = 1,   
+#endif
 };
 
-IPS_DEFINE_COMPAT_TABLE( Compatable ); /* Version Compatability Table      */
-
 
 /* This table describes all ServeRAID Adapters */
 static struct  pci_device_id  ips_pci_table[] = {
@@ -298,7 +417,7 @@ 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);
    
-struct pci_driver ips_pci_driver = {
+static struct pci_driver ips_pci_driver = {
        .name           = ips_hot_plug_name,
        .id_table       = ips_pci_table,
        .probe          = ips_insert_device,
@@ -395,123 +514,6 @@ static char ips_command_direction[] = {
        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 *));
-const char *ips_info(struct Scsi_Host *);
-irqreturn_t 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_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 inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
-static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *);
-static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *);
-static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
-static inline void ips_putq_copp_head(ips_copp_queue_t *,
-                                     ips_copp_wait_item_t *);
-static inline void ips_putq_copp_tail(ips_copp_queue_t *,
-                                     ips_copp_wait_item_t *);
-static inline ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
-static inline ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
-static inline Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
-static inline Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
-static inline ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
-                                                    ips_copp_wait_item_t *);
-static inline ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
-
-static int ips_is_passthru(Scsi_Cmnd *);
-static int ips_make_passthru(ips_ha_t *, 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(Scsi_Cmnd * scmd, void *data,
-                              unsigned int count);
-static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
-
-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_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
-static void ips_version_check(ips_ha_t * ha, int intr);
-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);
-/*--------------------------------------------------------------------------*/
-/* Exported Functions                                                       */
-/*--------------------------------------------------------------------------*/
 
 /****************************************************************************/
 /*                                                                          */
@@ -549,7 +551,7 @@ ips_setup(char *ips_str)
                 * We now have key/value pairs.
                 * Update the variables
                 */
-               for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) {
+               for (i = 0; i < ARRAY_SIZE(options); i++) {
                        if (strnicmp
                            (key, options[i].option_name,
                             strlen(options[i].option_name)) == 0) {
@@ -580,8 +582,8 @@ __setup("ips=", ips_setup);
 /* NOTE: this routine is called under the io_request_lock spinlock          */
 /*                                                                          */
 /****************************************************************************/
-int
-ips_detect(Scsi_Host_Template * SHT)
+static int
+ips_detect(struct scsi_host_template * SHT)
 {
        int i;
 
@@ -669,7 +671,7 @@ ips_setup_funclist(ips_ha_t * ha)
 /*   Remove a driver                                                        */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_release(struct Scsi_Host *sh)
 {
        ips_scb_t *scb;
@@ -806,18 +808,20 @@ ips_halt(struct notifier_block *nb, ulong event, void *buf)
 /*   Abort a command (using the new error code stuff)                       */
 /* Note: this routine is called under the io_request_lock                   */
 /****************************************************************************/
-int
-ips_eh_abort(Scsi_Cmnd * SC)
+int ips_eh_abort(struct scsi_cmnd *SC)
 {
        ips_ha_t *ha;
        ips_copp_wait_item_t *item;
        int ret;
+       unsigned long cpu_flags;
+       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)
@@ -826,12 +830,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
        if (!ha->active)
                return (FAILED);
 
-       if (SC->serial_number != SC->serial_number_at_timeout) {
-               /* HMM, looks like a bogus command */
-               DEBUG(1, "Abort called with bogus scsi command");
-
-               return (FAILED);
-       }
+       IPS_LOCK_SAVE(host->host_lock, cpu_flags);
 
        /* See if the command is on the copp queue */
        item = ha->copp_waitlist.head;
@@ -851,6 +850,8 @@ ips_eh_abort(Scsi_Cmnd * SC)
                /* command must have already been sent */
                ret = (FAILED);
        }
+
+       IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
        return ret;
 }
 
@@ -865,8 +866,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
 /* NOTE: this routine is called under the io_request_lock spinlock          */
 /*                                                                          */
 /****************************************************************************/
-int
-ips_eh_reset(Scsi_Cmnd * SC)
+static int __ips_eh_reset(struct scsi_cmnd *SC)
 {
        int ret;
        int i;
@@ -962,7 +962,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
        ret = (*ha->func.reset) (ha);
 
        if (!ret) {
-               Scsi_Cmnd *scsi_cmd;
+               struct scsi_cmnd *scsi_cmd;
 
                IPS_PRINTK(KERN_NOTICE, ha->pcidev,
                           "Controller reset failed - controller now offline.\n");
@@ -991,7 +991,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
        }
 
        if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
-               Scsi_Cmnd *scsi_cmd;
+               struct scsi_cmnd *scsi_cmd;
 
                IPS_PRINTK(KERN_NOTICE, ha->pcidev,
                           "Controller reset failed - controller now offline.\n");
@@ -1053,6 +1053,17 @@ ips_eh_reset(Scsi_Cmnd * SC)
 
 }
 
+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                                                  */
@@ -1065,8 +1076,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
 /*    Linux obtains io_request_lock before calling this function            */
 /*                                                                          */
 /****************************************************************************/
-int
-ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
+static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
 {
        ips_ha_t *ha;
        ips_passthru_t *pt;
@@ -1104,8 +1114,8 @@ ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
                  SC->device->channel, SC->device->id, SC->device->lun);
 
        /* Check for command to initiator IDs */
-       if ((SC->device->channel > 0)
-           && (SC->device->id == ha->ha_id[SC->device->channel])) {
+       if ((scmd_channel(SC) > 0)
+           && (scmd_id(SC) == ha->ha_id[scmd_channel(SC)])) {
                SC->result = DID_NO_CONNECT << 16;
                done(SC);
 
@@ -1128,7 +1138,7 @@ ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
                                return (0);
                        }
                        ha->ioctl_reset = 1;    /* This reset request is from an IOCTL */
-                       ips_eh_reset(SC);
+                       __ips_eh_reset(SC);
                        SC->result = DID_OK << 16;
                        SC->scsi_done(SC);
                        return (0);
@@ -1244,9 +1254,9 @@ ips_proc24_info(char *buffer, char **start, off_t offset, int length,
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
+ips_select_queue_depth(struct Scsi_Host *host, struct scsi_device * scsi_devs)
 {
-       Scsi_Device *device;
+       struct scsi_device *device;
        ips_ha_t *ha;
        int count = 0;
        int min;
@@ -1288,8 +1298,8 @@ ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
 /*   Set queue depths on devices once scan is complete                      */
 /*                                                                          */
 /****************************************************************************/
-int
-ips_slave_configure(Scsi_Device * SDptr)
+static int
+ips_slave_configure(struct scsi_device * SDptr)
 {
        ips_ha_t *ha;
        int min;
@@ -1301,6 +1311,9 @@ ips_slave_configure(Scsi_Device * SDptr)
                        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;
 }
 #endif
@@ -1314,8 +1327,8 @@ ips_slave_configure(Scsi_Device * SDptr)
 /*   Wrapper for the interrupt handler                                      */
 /*                                                                          */
 /****************************************************************************/
-irqreturn_t
-do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t
+do_ipsintr(int irq, void *dev_id)
 {
        ips_ha_t *ha;
        unsigned long cpu_flags;
@@ -1493,7 +1506,7 @@ ips_intr_morpheus(ips_ha_t * ha)
 /*   Return info about the driver                                           */
 /*                                                                          */
 /****************************************************************************/
-const char *
+static const char *
 ips_info(struct Scsi_Host *SH)
 {
        static char buffer[256];
@@ -1531,7 +1544,7 @@ ips_info(struct Scsi_Host *SH)
 /*   The passthru interface for the driver                                  */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
 ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
              int length, int func)
 {
@@ -1581,9 +1594,10 @@ ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
 /*   Determine if the specified SCSI command is really a passthru command   */
 /*                                                                          */
 /****************************************************************************/
-static int
-ips_is_passthru(Scsi_Cmnd * SC)
+static int ips_is_passthru(struct scsi_cmnd *SC)
 {
+       unsigned long flags;
+
        METHOD_TRACE("ips_is_passthru", 1);
 
        if (!SC)
@@ -1601,10 +1615,20 @@ ips_is_passthru(Scsi_Cmnd * SC)
                        return 1;
                else if (SC->use_sg) {
                        struct scatterlist *sg = SC->request_buffer;
-                       char *buffer = IPS_SG_ADDRESS(sg);
+                       char  *buffer; 
+
+                       /* kmap_atomic() ensures addressability of the user buffer.*/
+                       /* local_irq_save() protects the KM_IRQ0 address slot.     */
+                       local_irq_save(flags);
+                       buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; 
                        if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
-                           buffer[2] == 'P' && buffer[3] == 'P')
+                           buffer[2] == 'P' && buffer[3] == 'P') {
+                               kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+                               local_irq_restore(flags);
                                return 1;
+                       }
+                       kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+                       local_irq_restore(flags);
                }
        }
        return 0;
@@ -1652,7 +1676,7 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
+ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
 {
        ips_passthru_t *pt;
        int length = 0;
@@ -1885,7 +1909,7 @@ ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
 /*   Fill in a single scb sg_list element from an address                   */
 /*   return a -1 if a breakup occurred                                      */
 /****************************************************************************/
-static inline int
+static int
 ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
                       ips_scb_t * scb, int indx, unsigned int e_len)
 {
@@ -2701,9 +2725,9 @@ static void
 ips_next(ips_ha_t * ha, int intr)
 {
        ips_scb_t *scb;
-       Scsi_Cmnd *SC;
-       Scsi_Cmnd *p;
-       Scsi_Cmnd *q;
+       struct scsi_cmnd *SC;
+       struct scsi_cmnd *p;
+       struct scsi_cmnd *q;
        ips_copp_wait_item_t *item;
        int ret;
        unsigned long cpu_flags = 0;
@@ -2809,12 +2833,12 @@ ips_next(ips_ha_t * ha, int intr)
 
        p = ha->scb_waitlist.head;
        while ((p) && (scb = ips_getscb(ha))) {
-               if ((p->device->channel > 0)
+               if ((scmd_channel(p) > 0)
                    && (ha->
-                       dcdb_active[p->device->channel -
-                                   1] & (1 << p->device->id))) {
+                       dcdb_active[scmd_channel(p) -
+                                   1] & (1 << scmd_id(p)))) {
                        ips_freescb(ha, scb);
-                       p = (Scsi_Cmnd *) p->host_scribble;
+                       p = (struct scsi_cmnd *) p->host_scribble;
                        continue;
                }
 
@@ -2849,8 +2873,7 @@ ips_next(ips_ha_t * ha, int intr)
 
                        sg = SC->request_buffer;
                        scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
-                                                  scsi_to_pci_dma_dir(SC->
-                                                                      sc_data_direction));
+                                                  SC->sc_data_direction);
                        scb->flags |= IPS_SCB_MAP_SG;
                        for (i = 0; i < scb->sg_count; i++) {
                                if (ips_fill_scb_sg_single
@@ -2865,8 +2888,7 @@ ips_next(ips_ha_t * ha, int intr)
                                    pci_map_single(ha->pcidev,
                                                   SC->request_buffer,
                                                   SC->request_bufflen,
-                                                  scsi_to_pci_dma_dir(SC->
-                                                                      sc_data_direction));
+                                                  SC->sc_data_direction);
                                scb->flags |= IPS_SCB_MAP_SINGLE;
                                ips_fill_scb_sg_single(ha, scb->data_busaddr,
                                                       scb, 0,
@@ -2931,7 +2953,7 @@ ips_next(ips_ha_t * ha, int intr)
                        break;
                }               /* end case */
 
-               p = (Scsi_Cmnd *) p->host_scribble;
+               p = (struct scsi_cmnd *) p->host_scribble;
 
        }                       /* end while */
 
@@ -2950,7 +2972,7 @@ ips_next(ips_ha_t * ha, int intr)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline void
+static void
 ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
 {
        METHOD_TRACE("ips_putq_scb_head", 1);
@@ -2967,38 +2989,6 @@ ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
        queue->count++;
 }
 
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_putq_scb_tail                                          */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Add an item to the tail of the queue                                   */
-/*                                                                          */
-/* ASSUMED to be called from within the HA lock                             */
-/*                                                                          */
-/****************************************************************************/
-static inline void
-ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item)
-{
-       METHOD_TRACE("ips_putq_scb_tail", 1);
-
-       if (!item)
-               return;
-
-       item->q_next = NULL;
-
-       if (queue->tail)
-               queue->tail->q_next = item;
-
-       queue->tail = item;
-
-       if (!queue->head)
-               queue->head = item;
-
-       queue->count++;
-}
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_removeq_scb_head                                       */
@@ -3010,7 +3000,7 @@ ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline ips_scb_t *
+static ips_scb_t *
 ips_removeq_scb_head(ips_scb_queue_t * queue)
 {
        ips_scb_t *item;
@@ -3045,7 +3035,7 @@ ips_removeq_scb_head(ips_scb_queue_t * queue)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline ips_scb_t *
+static ips_scb_t *
 ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
 {
        ips_scb_t *p;
@@ -3080,34 +3070,6 @@ ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
        return (NULL);
 }
 
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_putq_wait_head                                         */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Add an item to the head of the queue                                   */
-/*                                                                          */
-/* ASSUMED to be called from within the HA lock                             */
-/*                                                                          */
-/****************************************************************************/
-static inline void
-ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item)
-{
-       METHOD_TRACE("ips_putq_wait_head", 1);
-
-       if (!item)
-               return;
-
-       item->host_scribble = (char *) queue->head;
-       queue->head = item;
-
-       if (!queue->tail)
-               queue->tail = item;
-
-       queue->count++;
-}
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_putq_wait_tail                                         */
@@ -3119,8 +3081,7 @@ ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline void
-ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item)
 {
        METHOD_TRACE("ips_putq_wait_tail", 1);
 
@@ -3151,10 +3112,9 @@ ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline Scsi_Cmnd *
-ips_removeq_wait_head(ips_wait_queue_t * queue)
+static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue)
 {
-       Scsi_Cmnd *item;
+       struct scsi_cmnd *item;
 
        METHOD_TRACE("ips_removeq_wait_head", 1);
 
@@ -3164,7 +3124,7 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
                return (NULL);
        }
 
-       queue->head = (Scsi_Cmnd *) item->host_scribble;
+       queue->head = (struct scsi_cmnd *) item->host_scribble;
        item->host_scribble = NULL;
 
        if (queue->tail == item)
@@ -3186,10 +3146,10 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline Scsi_Cmnd *
-ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue,
+                                         struct scsi_cmnd *item)
 {
-       Scsi_Cmnd *p;
+       struct scsi_cmnd *p;
 
        METHOD_TRACE("ips_removeq_wait", 1);
 
@@ -3202,8 +3162,8 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
 
        p = queue->head;
 
-       while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
-               p = (Scsi_Cmnd *) p->host_scribble;
+       while ((p) && (item != (struct scsi_cmnd *) p->host_scribble))
+               p = (struct scsi_cmnd *) p->host_scribble;
 
        if (p) {
                /* found a match */
@@ -3221,34 +3181,6 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
        return (NULL);
 }
 
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_putq_copp_head                                         */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Add an item to the head of the queue                                   */
-/*                                                                          */
-/* ASSUMED to be called from within the HA lock                             */
-/*                                                                          */
-/****************************************************************************/
-static inline void
-ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
-{
-       METHOD_TRACE("ips_putq_copp_head", 1);
-
-       if (!item)
-               return;
-
-       item->next = queue->head;
-       queue->head = item;
-
-       if (!queue->tail)
-               queue->tail = item;
-
-       queue->count++;
-}
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_putq_copp_tail                                         */
@@ -3260,7 +3192,7 @@ ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline void
+static void
 ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
 {
        METHOD_TRACE("ips_putq_copp_tail", 1);
@@ -3292,7 +3224,7 @@ ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline ips_copp_wait_item_t *
+static ips_copp_wait_item_t *
 ips_removeq_copp_head(ips_copp_queue_t * queue)
 {
        ips_copp_wait_item_t *item;
@@ -3327,7 +3259,7 @@ ips_removeq_copp_head(ips_copp_queue_t * queue)
 /* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
-static inline ips_copp_wait_item_t *
+static ips_copp_wait_item_t *
 ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
 {
        ips_copp_wait_item_t *p;
@@ -3556,6 +3488,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
        int device_error;
        uint32_t transfer_len;
        IPS_DCDB_TABLE_TAPE *tapeDCDB;
+       IPS_SCSI_INQ_DATA inquiryData;
 
        METHOD_TRACE("ips_map_status", 1);
 
@@ -3614,13 +3547,13 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
                                errcode = DID_OK;
 
                                /* Restrict access to physical DASD */
-                               if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-                                   ((((char *) scb->scsi_cmd->
-                                      buffer)[0] & 0x1f) == TYPE_DISK)) {
-                                       /* underflow -- no error               */
-                                       /* restrict access to physical DASD    */
-                                       errcode = DID_TIME_OUT;
-                                       break;
+                               if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+                                   ips_scmd_buf_read(scb->scsi_cmd, 
+                                      &inquiryData, sizeof (inquiryData));
+                                   if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
+                                       errcode = DID_TIME_OUT;
+                                       break;
+                                   }
                                }
                        } else
                                errcode = DID_ERROR;
@@ -3715,24 +3648,30 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
 /* Routine Name: ips_scmd_buf_write                                         */
 /*                                                                          */
 /* Routine Description:                                                     */
-/*  Write data to Scsi_Cmnd request_buffer at proper offsets                */
+/*  Write data to struct scsi_cmnd request_buffer at proper offsets        */
 /****************************************************************************/
 static void
-ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
-                  int count)
+ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
 {
        if (scmd->use_sg) {
                int i;
                unsigned int min_cnt, xfer_cnt;
                char *cdata = (char *) data;
+               unsigned char *buffer;
+               unsigned long flags;
                struct scatterlist *sg = scmd->request_buffer;
                for (i = 0, xfer_cnt = 0;
                     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
-                       if (!IPS_SG_ADDRESS(&sg[i]))
-                               return;
                        min_cnt = min(count - xfer_cnt, sg[i].length);
-                       memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt],
-                              min_cnt);
+
+                       /* kmap_atomic() ensures addressability of the data buffer.*/
+                       /* local_irq_save() protects the KM_IRQ0 address slot.     */
+                       local_irq_save(flags);
+                       buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+                       memcpy(buffer, &cdata[xfer_cnt], min_cnt);
+                       kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
+                       local_irq_restore(flags);
+
                        xfer_cnt += min_cnt;
                }
 
@@ -3747,24 +3686,30 @@ ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
 /* Routine Name: ips_scmd_buf_read                                          */
 /*                                                                          */
 /* Routine Description:                                                     */
-/*  Copy data from a Scsi_Cmnd to a new, linear buffer                      */
+/*  Copy data from a struct scsi_cmnd to a new, linear buffer              */
 /****************************************************************************/
 static void
-ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
-                 int count)
+ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
 {
        if (scmd->use_sg) {
                int i;
                unsigned int min_cnt, xfer_cnt;
                char *cdata = (char *) data;
+               unsigned char *buffer;
+               unsigned long flags;
                struct scatterlist *sg = scmd->request_buffer;
                for (i = 0, xfer_cnt = 0;
                     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
-                       if (!IPS_SG_ADDRESS(&sg[i]))
-                               return;
                        min_cnt = min(count - xfer_cnt, sg[i].length);
-                       memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]),
-                              min_cnt);
+
+                       /* kmap_atomic() ensures addressability of the data buffer.*/
+                       /* local_irq_save() protects the KM_IRQ0 address slot.     */
+                       local_irq_save(flags);
+                       buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+                       memcpy(&cdata[xfer_cnt], buffer, min_cnt);
+                       kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
+                       local_irq_restore(flags);
+
                        xfer_cnt += min_cnt;
                }
 
@@ -4178,6 +4123,7 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
        uint8_t basic_status;
        uint8_t ext_status;
        int errcode;
+       IPS_SCSI_INQ_DATA inquiryData;
 
        METHOD_TRACE("ips_chkstatus", 1);
 
@@ -4298,11 +4244,11 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
                        scb->scsi_cmd->result = errcode << 16;
                } else {        /* bus == 0 */
                        /* restrict access to physical drives */
-                       if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-                           ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) ==
-                            TYPE_DISK)) {
-
-                               scb->scsi_cmd->result = DID_TIME_OUT << 16;
+                       if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 
+                           ips_scmd_buf_read(scb->scsi_cmd, 
+                                  &inquiryData, sizeof (inquiryData));
+                           if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 
+                               scb->scsi_cmd->result = DID_TIME_OUT << 16;
                        }
                }               /* else */
        } else {                /* recovered error / success */
@@ -4404,7 +4350,7 @@ ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
 
        METHOD_TRACE("ips_rdcap", 1);
 
-       if (scb->scsi_cmd->bufflen < 8)
+       if (scb->scsi_cmd->request_bufflen < 8)
                return (0);
 
        cap.lba =
@@ -4560,10 +4506,8 @@ ips_free(ips_ha_t * ha)
                        ha->enq = NULL;
                }
 
-               if (ha->conf) {
-                       kfree(ha->conf);
-                       ha->conf = NULL;
-               }
+               kfree(ha->conf);
+               ha->conf = NULL;
 
                if (ha->adapt) {
                        pci_free_consistent(ha->pcidev,
@@ -4581,15 +4525,11 @@ ips_free(ips_ha_t * ha)
                        ha->logical_drive_info = NULL;
                }
 
-               if (ha->nvram) {
-                       kfree(ha->nvram);
-                       ha->nvram = NULL;
-               }
+               kfree(ha->nvram);
+               ha->nvram = NULL;
 
-               if (ha->subsys) {
-                       kfree(ha->subsys);
-                       ha->subsys = NULL;
-               }
+               kfree(ha->subsys);
+               ha->subsys = NULL;
 
                if (ha->ioctl_data) {
                        pci_free_consistent(ha->pcidev, ha->ioctl_len,
@@ -4876,6 +4816,9 @@ ips_isinit_morpheus(ips_ha_t * ha)
        uint32_t bits;
 
        METHOD_TRACE("ips_is_init_morpheus", 1);
+   
+       if (ips_isintr_morpheus(ha)) 
+           ips_flush_and_reset(ha);
 
        post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
        bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
@@ -4888,6 +4831,94 @@ ips_isinit_morpheus(ips_ha_t * ha)
                return (1);
 }
 
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_flush_and_reset                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Perform cleanup ( FLUSH and RESET ) when the adapter is in an unknown  */
+/*   state ( was trying to INIT and an interrupt was already pending ) ...  */
+/*                                                                          */
+/****************************************************************************/
+static void 
+ips_flush_and_reset(ips_ha_t *ha)
+{
+       ips_scb_t *scb;
+       int  ret;
+       int  time;
+       int  done;
+       dma_addr_t command_dma;
+
+       /* Create a usuable SCB */
+       scb = pci_alloc_consistent(ha->pcidev, sizeof(ips_scb_t), &command_dma);
+       if (scb) {
+           memset(scb, 0, sizeof(ips_scb_t));
+           ips_init_scb(ha, scb);
+           scb->scb_busaddr = command_dma;
+
+           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_MAX_CMDS;   /* Use an ID that would otherwise not exist */
+           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;
+
+           ret = ips_send_cmd(ha, scb);                      /* Send the Flush Command */
+
+           if (ret == IPS_SUCCESS) {
+               time = 60 * IPS_ONE_SEC;                      /* Max Wait time is 60 seconds */
+               done = 0;
+                   
+               while ((time > 0) && (!done)) {
+                  done = ips_poll_for_flush_complete(ha);         
+                  /* This may look evil, but it's only done during extremely rare start-up conditions ! */
+                  udelay(1000);
+                  time--;
+               }
+        }
+       }
+
+       /* Now RESET and INIT the adapter */
+       (*ha->func.reset) (ha);
+
+       pci_free_consistent(ha->pcidev, sizeof(ips_scb_t), scb, command_dma);
+       return;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_poll_for_flush_complete                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Poll for the Flush Command issued by ips_flush_and_reset() to complete */
+/*   All other responses are just taken off the queue and ignored           */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_poll_for_flush_complete(ips_ha_t * ha)
+{
+       IPS_STATUS cstatus;
+    
+       while (TRUE) {
+           cstatus.value = (*ha->func.statupd) (ha);
+
+           if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */
+                       break;
+            
+           /* Success is when we see the Flush Command ID */
+           if (cstatus.fields.command_id == IPS_MAX_CMDS ) 
+               return 1;
+        }      
+
+       return 0;
+}
+
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_enable_int_copperhead                                  */
@@ -5888,7 +5919,7 @@ ips_write_driver_status(ips_ha_t * ha, int intr)
        strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
        strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
 
-       ips_version_check(ha, intr);    /* Check BIOS/FW/Driver Versions */
+       ha->nvram->versioning = 0;      /* Indicate the Driver Does Not Support Versioning */
 
        /* now update the page */
        if (!ips_readwrite_page5(ha, TRUE, intr)) {
@@ -6393,7 +6424,7 @@ ips_erase_bios(ips_ha_t * ha)
                /* VPP failure */
                return (1);
 
-       /* check for succesful flash */
+       /* check for successful flash */
        if (status & 0x30)
                /* sequence error */
                return (1);
@@ -6505,7 +6536,7 @@ ips_erase_bios_memio(ips_ha_t * ha)
                /* VPP failure */
                return (1);
 
-       /* check for succesful flash */
+       /* check for successful flash */
        if (status & 0x30)
                /* sequence error */
                return (1);
@@ -6805,135 +6836,6 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
                return (0);
 }
 
-/*---------------------------------------------------------------------------*/
-/*   Routine Name: ips_version_check                                         */
-/*                                                                           */
-/*   Dependencies:                                                           */
-/*     Assumes that ips_read_adapter_status() is called first filling in     */
-/*     the data for SubSystem Parameters.                                    */
-/*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */
-/*     Data is available.                                                    */
-/*                                                                           */
-/*---------------------------------------------------------------------------*/
-static void
-ips_version_check(ips_ha_t * ha, int intr)
-{
-       IPS_VERSION_DATA *VersionInfo;
-       uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
-       uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
-       int MatchError;
-       int rc;
-       char BiosString[10];
-       char FirmwareString[10];
-
-       METHOD_TRACE("ips_version_check", 1);
-
-       VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;
-
-       memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
-       memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
-
-       /* Get the Compatible BIOS Version from NVRAM Page 5 */
-       memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,
-              IPS_COMPAT_ID_LENGTH);
-
-       rc = IPS_FAILURE;
-       if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {   /* If Versioning is Supported */
-               /* Get the Version Info with a Get Version Command */
-               memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
-               rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);
-               if (rc == IPS_SUCCESS)
-                       memcpy(FirmwareVersion, VersionInfo->compatibilityId,
-                              IPS_COMPAT_ID_LENGTH);
-       }
-
-       if (rc != IPS_SUCCESS) {        /* If Data Not Obtainable from a GetVersion Command */
-               /* Get the Firmware Version from Enquiry Data */
-               memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,
-                      IPS_COMPAT_ID_LENGTH);
-       }
-
-       /* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
-       /* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
-       /* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
-       /* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
-
-       MatchError = 0;
-
-       if (strncmp
-           (FirmwareVersion, Compatable[ha->nvram->adapter_type],
-            IPS_COMPAT_ID_LENGTH) != 0)
-               MatchError = 1;
-
-       if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
-               MatchError = 1;
-
-       ha->nvram->versioning = 1;      /* Indicate the Driver Supports Versioning */
-
-       if (MatchError) {
-               ha->nvram->version_mismatch = 1;
-               if (ips_cd_boot == 0) {
-                       strncpy(&BiosString[0], ha->nvram->bios_high, 4);
-                       strncpy(&BiosString[4], ha->nvram->bios_low, 4);
-                       BiosString[8] = 0;
-
-                       strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
-                       FirmwareString[8] = 0;
-
-                       IPS_PRINTK(KERN_WARNING, ha->pcidev,
-                                  "Warning ! ! ! ServeRAID Version Mismatch\n");
-                       IPS_PRINTK(KERN_WARNING, ha->pcidev,
-                                  "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
-                                  BiosString, FirmwareString, IPS_VERSION_HIGH,
-                                  IPS_VERSION_LOW);
-                       IPS_PRINTK(KERN_WARNING, ha->pcidev,
-                                  "These levels should match to avoid possible compatibility problems.\n");
-               }
-       } else {
-               ha->nvram->version_mismatch = 0;
-       }
-
-       return;
-}
-
-/*---------------------------------------------------------------------------*/
-/*   Routine Name: ips_get_version_info                                      */
-/*                                                                           */
-/*   Routine Description:                                                    */
-/*     Issue an internal GETVERSION Command                                  */
-/*                                                                           */
-/*   Return Value:                                                           */
-/*     0 if Successful, else non-zero                                        */
-/*---------------------------------------------------------------------------*/
-static int
-ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr)
-{
-       ips_scb_t *scb;
-       int rc;
-
-       METHOD_TRACE("ips_get_version_info", 1);
-
-       scb = &ha->scbs[ha->max_cmds - 1];
-
-       ips_init_scb(ha, scb);
-
-       scb->timeout = ips_cmd_timeout;
-       scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
-       scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
-       scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
-       scb->cmd.version_info.reserved = 0;
-       scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
-       scb->cmd.version_info.reserved2 = 0;
-       scb->data_len = sizeof (IPS_VERSION_DATA);
-       scb->data_busaddr = Buffer;
-       scb->cmd.version_info.buffer_addr = Buffer;
-       scb->flags = 0;
-
-       /* issue command */
-       rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
-       return (rc);
-}
-
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_abort_init                                             */
@@ -6946,8 +6848,8 @@ ips_abort_init(ips_ha_t * ha, int index)
 {
        ha->active = 0;
        ips_free(ha);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
+       ips_ha[index] = NULL;
+       ips_sh[index] = NULL;
        return -1;
 }
 
@@ -6996,7 +6898,6 @@ ips_order_controllers(void)
                        for (j = position; j < ips_num_controllers; j++) {
                                switch (ips_ha[j]->ad_type) {
                                case IPS_ADTYPE_SERVERAID6M:
-                               case IPS_ADTYPE_SERVERAID7k:
                                case IPS_ADTYPE_SERVERAID7M:
                                        if (nvram->adapter_order[i] == 'M') {
                                                ips_shift_controllers(position,
@@ -7017,6 +6918,7 @@ ips_order_controllers(void)
                                case IPS_ADTYPE_SERVERAID6I:
                                case IPS_ADTYPE_SERVERAID5I2:
                                case IPS_ADTYPE_SERVERAID5I1:
+                               case IPS_ADTYPE_SERVERAID7k:
                                        if (nvram->adapter_order[i] == 'S') {
                                                ips_shift_controllers(position,
                                                                      j);
@@ -7092,7 +6994,7 @@ ips_register_scsi(int index)
        memcpy(ha, oldha, sizeof (ips_ha_t));
        free_irq(oldha->irq, oldha);
        /* Install the interrupt handler with the new ha */
-       if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+       if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to install interrupt handler\n");
                scsi_host_put(sh);
@@ -7163,7 +7065,7 @@ ips_remove_device(struct pci_dev *pci_dev)
 static int __init
 ips_module_init(void)
 {
-       if (pci_module_init(&ips_pci_driver) < 0)
+       if (pci_register_driver(&ips_pci_driver) < 0)
                return -ENODEV;
        ips_driver_template.module = THIS_MODULE;
        ips_order_controllers();
@@ -7254,8 +7156,8 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
        int j;
        int index;
        dma_addr_t dma_address;
-       char *ioremap_ptr;
-       char *mem_ptr;
+       char __iomem *ioremap_ptr;
+       char __iomem *mem_ptr;
        uint32_t IsDead;
 
        METHOD_TRACE("ips_init_phase1", 1);
@@ -7369,10 +7271,10 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
         * are guaranteed to be < 4G.
         */
        if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
-           !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) {
+           !pci_set_dma_mask(ha->pcidev, DMA_64BIT_MASK)) {
                (ha)->flags |= IPS_HA_ENH_SG;
        } else {
-               if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) {
+               if (pci_set_dma_mask(ha->pcidev, DMA_32BIT_MASK) != 0) {
                        printk(KERN_WARNING "Unable to set DMA Mask\n");
                        return ips_abort_init(ha, index);
                }
@@ -7504,7 +7406,7 @@ ips_init_phase2(int index)
        }
 
        /* Install the interrupt handler */
-       if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+       if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
                IPS_PRINTK(KERN_WARNING, ha->pcidev,
                           "Unable to install interrupt handler\n");
                return ips_abort_init(ha, index);
@@ -7545,6 +7447,13 @@ ips_init_phase2(int index)
 MODULE_LICENSE("GPL");
 #endif
 
+MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
+
+#ifdef MODULE_VERSION
+MODULE_VERSION(IPS_VER_STRING);
+#endif
+
+
 /*
  * Overrides for Emacs so that we almost follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically