patch-2.4.19 linux-2.4.19/drivers/scsi/ips.c
Next file: linux-2.4.19/drivers/scsi/ips.h
Previous file: linux-2.4.19/drivers/scsi/ide-scsi.c
Back to the patch index
Back to the overall index
- Lines: 3648
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/scsi/ips.c
- Orig date:
Mon Feb 25 11:38:04 2002
diff -urN linux-2.4.18/drivers/scsi/ips.c linux-2.4.19/drivers/scsi/ips.c
@@ -81,7 +81,7 @@
/* 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.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@caldera.de> */
/* 4.10.00 - Add support for ServeRAID 4M/4L */
/* 4.10.13 - Fix for dynamic unload and proc file system */
/* 4.20.03 - Rename version to coincide with new release schedules */
@@ -105,15 +105,22 @@
/* 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 */
+/* - 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 */
/*****************************************************************************/
/*
@@ -121,20 +128,15 @@
*
* IPS_DEBUG - Turn on debugging info
*
- *
* Parameters:
*
* debug:<number> - Set debug level to <number>
- * NOTE: only works when IPS_DEBUG compile directive
- * is used.
- *
+ * NOTE: only works when IPS_DEBUG compile directive is used.
* 1 - Normal debug messages
* 2 - Verbose debug messages
* 11 - Method trace (non interrupt)
* 12 - Method trace (includes interrupt)
*
- * noreset - Don't reset the controller
- * nocmdline - Turn off passthru support
* noi2o - Don't use I2O Queues (ServeRAID 4 only)
* nommap - Don't use memory mapped I/O
* ioctlsize - Initial size of the IOCTL buffer
@@ -162,9 +164,7 @@
#include <linux/blk.h>
#include <linux/types.h>
-#ifndef NO_IPS_CMDLINE
#include <scsi/sg.h>
-#endif
#include "sd.h"
#include "scsi.h"
@@ -176,14 +176,11 @@
#include <linux/stat.h>
#include <linux/config.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,18)
-#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+ #include <linux/spinlock.h>
+ #include <linux/init.h>
#else
-#include <asm/spinlock.h>
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
-#include <linux/init.h>
+ #include <asm/spinlock.h>
#endif
#include <linux/smp.h>
@@ -196,10 +193,10 @@
/*
* DRIVER_VER
*/
-#define IPS_VERSION_HIGH "4.80"
-#define IPS_VERSION_LOW ".26 "
+#define IPS_VERSION_HIGH "4.90"
+#define IPS_VERSION_LOW ".18 "
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
struct proc_dir_entry proc_scsi_ips = {
0,
3, "ips",
@@ -213,10 +210,29 @@
#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
#error "This driver only works with kernel 2.2.0 and later"
-#endif
-
-#if !defined(NO_IPS_CMDLINE) && ((SG_BIG_BUFF < 8192) || !defined(SG_BIG_BUFF))
- #error "To use the command-line interface you need to define SG_BIG_BUFF"
+#elif LINUX_VERSION_CODE <= LinuxVersionCode(2,3,18)
+ #define dma_addr_t uint32_t
+
+ static inline void *pci_alloc_consistent(struct pci_dev *dev,int size,
+ dma_addr_t *dmahandle) {
+ void * ptr = kmalloc(size, GFP_ATOMIC);
+ if(ptr){
+ *dmahandle = VIRT_TO_BUS(ptr);
+ }
+ return ptr;
+ }
+
+ #define pci_free_consistent(a,size,address,dmahandle) kfree(address)
+
+ #define pci_map_sg(a,b,n,z) (n)
+ #define pci_unmap_sg(a,b,c,d)
+ #define pci_map_single(a,b,c,d) (VIRT_TO_BUS(b))
+ #define pci_unmap_single(a,b,c,d)
+ #ifndef sg_dma_address
+ #define sg_dma_address(x) (VIRT_TO_BUS((x)->address))
+ #define sg_dma_len(x) ((x)->length)
+ #endif
+ #define pci_unregister_driver(x)
#endif
#ifdef IPS_DEBUG
@@ -233,8 +249,8 @@
* 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 struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */
+static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */
static unsigned int ips_next_controller = 0;
static unsigned int ips_num_controllers = 0;
static unsigned int ips_released_controllers = 0;
@@ -242,15 +258,34 @@
static int ips_reset_timeout = 60 * 5;
static int ips_force_memio = 1; /* Always use Memory Mapped I/O */
static int ips_force_i2o = 1; /* Always use I2O command delivery */
-static int ips_resetcontroller = 1; /* Reset the controller */
-static int ips_cmdline = 1; /* Support for passthru */
static int ips_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */
static int ips_cd_boot = 0; /* Booting from ServeRAID Manager CD */
static char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */
static int ips_FlashDataInUse = 0; /* CD Boot - Flash Data In Use Flag */
-#ifdef IPS_DEBUG
-static int ips_debug = 0; /* Debug mode */
+IPS_DEFINE_COMPAT_TABLE( Compatable ); /* Version Compatability Table */
+
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+ static struct pci_device_id ips_pci_table[] __devinitdata = {
+ { 0x1014, 0x002E, PCI_ANY_ID,PCI_ANY_ID, 0, 0, 0 },
+ { 0x1014, 0x01BD, PCI_ANY_ID,PCI_ANY_ID, 0, 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);
+
+ 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),
+ };
#endif
/*
@@ -271,7 +306,9 @@
"ServeRAID 4M",
"ServeRAID 4L",
"ServeRAID 4Mx",
- "ServeRAID 4Lx"
+ "ServeRAID 4Lx",
+ "ServeRAID 5I",
+ "ServeRAID 5I"
};
static struct notifier_block ips_notifier = {
@@ -356,6 +393,7 @@
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 *);
@@ -381,15 +419,18 @@
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 *, u_int32_t, u_int32_t);
-static int ips_verify_bios(ips_ha_t *, char *, u_int32_t, u_int32_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 *, u_int32_t, u_int32_t);
-static int ips_verify_bios_memio(ips_ha_t *, char *, u_int32_t, u_int32_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 void ips_flash_bios_section(void *);
static void ips_flash_bios_segment(void *);
+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_scheduled_flash_bios(void *);
-static void ips_create_nvrampage5(ips_ha_t *, IPS_NVRAM_P5 *);
static void ips_get_bios_version(ips_ha_t *, int);
static void ips_identify_controller(ips_ha_t *);
static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
@@ -410,10 +451,10 @@
static void ips_statinit_memio(ips_ha_t *);
static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
static void ips_ffdc_reset(ips_ha_t *, int);
-static void ips_ffdc_time(ips_ha_t *, int);
-static u_int32_t ips_statupd_copperhead(ips_ha_t *);
-static u_int32_t ips_statupd_copperhead_memio(ips_ha_t *);
-static u_int32_t ips_statupd_morpheus(ips_ha_t *);
+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 *);
@@ -428,18 +469,23 @@
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 *);
-#ifndef NO_IPS_CMDLINE
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 int ips_newusrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
-#endif
int ips_proc_info(char *, char **, off_t, int, 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, IPS_VERSION_DATA *Buffer, int intr );
+static void ips_version_check(ips_ha_t *ha, int intr);
+static int ips_init_phase2( int index );
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+static int ips_init_phase1( struct pci_dev *pci_dev, int *indexPtr );
+#endif
/*--------------------------------------------------------------------------*/
/* Exported Functions */
@@ -454,37 +500,25 @@
/* setup parameters to the driver */
/* */
/****************************************************************************/
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
static int
ips_setup(char *ips_str) {
#else
void
ips_setup(char *ips_str, int *dummy) {
#endif
- int i;
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
- char *p;
- char tokens[3] = {',', '.', 0};
-#endif
+ int i;
char *key;
char *value;
IPS_OPTION options[] = {
- {"noreset", &ips_resetcontroller, 0},
-#ifdef IPS_DEBUG
- {"debug", &ips_debug, 1},
-#endif
{"noi2o", &ips_force_i2o, 0},
{"nommap", &ips_force_memio, 0},
- {"nocmdline", &ips_cmdline, 0},
{"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
{"cdboot", &ips_cd_boot, 0},
};
-
- METHOD_TRACE("ips_setup", 1);
-
-/* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
+
+ /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
/* Search for value */
while ((key = strsep(&ips_str, ",."))) {
@@ -507,7 +541,15 @@
}
}
}
+
+ return (1);
+}
+
#else
+
+ char *p;
+ char tokens[3] = {',', '.', 0};
+
for (key = strtok(ips_str, tokens); key; key = strtok(NULL, tokens)) {
p = key;
@@ -536,17 +578,11 @@
}
}
}
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
- return (1);
-#endif
}
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
-__setup("ips=", ips_setup);
#endif
+
/****************************************************************************/
/* */
/* Routine Name: ips_detect */
@@ -562,36 +598,36 @@
ips_detect(Scsi_Host_Template *SHT) {
struct Scsi_Host *sh;
ips_ha_t *ha;
- u_int32_t io_addr;
- u_int32_t mem_addr;
- u_int32_t io_len;
- u_int32_t mem_len;
- u_int16_t planer;
- u_int8_t revision_id;
- u_int8_t bus;
- u_int8_t func;
- u_int8_t irq;
- u_int16_t deviceID[2];
- u_int16_t subdevice_id;
+ uint32_t io_addr;
+ uint32_t mem_addr;
+ uint32_t io_len;
+ uint32_t mem_len;
+ uint16_t planer;
+ uint8_t revision_id;
+ uint8_t bus;
+ uint8_t func;
+ uint8_t irq;
+ uint16_t deviceID[2];
+ uint16_t subdevice_id;
int i;
int j;
- u_int32_t count;
+ uint32_t count;
char *ioremap_ptr;
char *mem_ptr;
struct pci_dev *dev[2];
struct pci_dev *morpheus = NULL;
struct pci_dev *trombone = NULL;
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,14)
- u_int32_t currbar;
- u_int32_t maskbar;
- u_int8_t barnum;
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
+ uint32_t currbar;
+ uint32_t maskbar;
+ uint8_t barnum;
#endif
METHOD_TRACE("ips_detect", 1);
#ifdef MODULE
if (ips)
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
ips_setup(ips);
#else
ips_setup(ips, NULL);
@@ -609,7 +645,7 @@
}
SHT->proc_info = ips_proc_info;
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
SHT->proc_dir = &proc_scsi_ips;
#else
SHT->proc_name = "ips";
@@ -667,6 +703,18 @@
}
}
+/**********************************************************************************/
+/* For Kernel Versions 2.4 or greater, use new PCI ( Hot Pluggable ) architecture */
+/**********************************************************************************/
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+ spin_unlock_irq(&io_request_lock);
+ pci_module_init(&ips_pci_driver);
+ spin_lock_irq(&io_request_lock);
+ if (ips_num_controllers > 0)
+ register_reboot_notifier(&ips_notifier);
+ return (ips_num_controllers);
+#endif
+
/* Now scan the controllers */
for (i = 0; i < 2; i++) {
if (!dev[i])
@@ -704,17 +752,6 @@
mem_addr = pci_resource_start(dev[i], j);
mem_len = pci_resource_len(dev[i], j);
}
-#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,3,14)
- if (!dev[i]->resource[j].start)
- break;
-
- if ((dev[i]->resource[j].start & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
- io_addr = dev[i]->resource[j].start;
- io_len = dev[i]->resource[j].end - dev[i]->resource[j].start + 1;
- } else {
- mem_addr = dev[i]->resource[j].start;
- mem_len = dev[i]->resource[j].end - dev[i]->resource[j].start + 1;
- }
#else
if (!dev[i]->base_address[j])
break;
@@ -747,13 +784,13 @@
/* setup memory mapped area (if applicable) */
if (mem_addr) {
- u_int32_t base;
- u_int32_t offs;
+ uint32_t base;
+ uint32_t offs;
DEBUG_VAR(1, "(%s%d) detect, Memory region %x, size: %d",
ips_name, ips_next_controller, mem_addr, mem_len);
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
if (check_mem_region(mem_addr, mem_len)) {
/* Couldn't allocate io space */
printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
@@ -829,7 +866,7 @@
continue;
}
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,15)
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
/* get the subdevice id */
if (pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id)) {
printk(KERN_WARNING "(%s%d) can't get subdevice id.\n",
@@ -1003,9 +1040,9 @@
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
sh->max_sectors = 128;
-#endif
+#endif
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,32)
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
sh->wish_block = FALSE;
#endif
@@ -1078,6 +1115,7 @@
/*
* Initialize the card if it isn't already
*/
+
if (!(*ha->func.isinit)(ha)) {
if (!(*ha->func.init)(ha)) {
/*
@@ -1117,8 +1155,8 @@
/*
* Allocate a temporary SCB for initialization
*/
- ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_KERNEL);
- if (!ha->scbs) {
+ ha->max_cmds = 1;
+ if (!ips_allocatescbs(ha)) {
/* couldn't allocate a temp SCB */
printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
ips_name, ips_next_controller);
@@ -1135,27 +1173,6 @@
continue;
}
- memset(ha->scbs, 0, sizeof(ips_scb_t));
- ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_KERNEL);
- if (!ha->scbs->sg_list) {
- /* couldn't allocate a temp SCB S/G list */
- printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
- ips_name, ips_next_controller);
-
- ha->active = 0;
- ips_free(ha);
- scsi_unregister(sh);
- ips_ha[ips_next_controller] = 0;
- ips_sh[ips_next_controller] = 0;
- free_irq(ha->irq, ha);
- ips_next_controller++;
- ips_num_controllers--;
-
- continue;
- }
-
- ha->max_cmds = 1;
-
ips_next_controller++;
} while ((dev[i] = pci_find_device(IPS_VENDORID, deviceID[i], dev[i])));
}
@@ -1167,65 +1184,13 @@
for (i = 0; i < ips_next_controller; i++) {
if (ips_ha[i] == 0) {
- printk(KERN_WARNING "(%s%d) ignoring bad controller\n",
- ips_name, i);
+ printk(KERN_WARNING "(%s%d) ignoring bad controller\n", ips_name, i);
continue;
}
- ha = ips_ha[i];
- sh = ips_sh[i];
-
- if (!ha->active) {
- scsi_unregister(sh);
- ips_ha[i] = NULL;
- ips_sh[i] = NULL;
-
- continue;
- }
-
- if (!ips_hainit(ha)) {
- printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping\n",
- ips_name, i);
-
- ha->active = 0;
- ips_free(ha);
- free_irq(ha->irq, ha);
- scsi_unregister(sh);
- ips_ha[i] = NULL;
- ips_sh[i] = NULL;
+ if (ips_init_phase2(i) != SUCCESS)
ips_num_controllers--;
- continue;
- }
-
- /*
- * Free the temporary SCB
- */
- kfree(ha->scbs->sg_list);
- kfree(ha->scbs);
- ha->scbs = NULL;
-
- /* allocate CCBs */
- if (!ips_allocatescbs(ha)) {
- printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
- ips_name, i);
-
- ha->active = 0;
- ips_free(ha);
- free_irq(ha->irq, ha);
- scsi_unregister(sh);
- ips_ha[i] = NULL;
- ips_sh[i] = NULL;
- ips_num_controllers--;
-
- continue;
- }
-
- /* finish setting values */
- sh->max_id = ha->ntargets;
- sh->max_lun = ha->nlun;
- sh->max_channel = ha->nbus - 1;
- sh->can_queue = ha->max_cmds-1;
}
if (ips_num_controllers > 0)
@@ -1314,9 +1279,10 @@
ips_released_controllers++;
- if (ips_num_controllers == ips_released_controllers)
+ if (ips_num_controllers == ips_released_controllers){
unregister_reboot_notifier(&ips_notifier);
-
+ pci_unregister_driver(&ips_pci_driver);
+ }
return (FALSE);
}
@@ -1511,6 +1477,46 @@
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 a ServeRAID 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) {
+ printk(KERN_NOTICE "(%s%d) Reset Request - Flushed Cache\n", ips_name, ha->host_num);
+ clear_bit(IPS_IN_RESET, &ha->flags);
+ return (SUCCESS);
+ }
+ }
+
+ /* Either we can't communicate with the adapter or it's an IOCTL request */
+ /* from a ServeRAID 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
@@ -1633,6 +1639,10 @@
}
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+__setup("ips=", ips_setup);
+#endif
+
/****************************************************************************/
/* */
/* Routine Name: ips_queue */
@@ -1649,6 +1659,7 @@
ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) {
ips_ha_t *ha;
unsigned long cpu_flags;
+ ips_passthru_t *pt;
METHOD_TRACE("ips_queue", 1);
@@ -1660,7 +1671,6 @@
if (!ha->active)
return (DID_ERROR);
-#ifndef NO_IPS_CMDLINE
if (ips_is_passthru(SC)) {
IPS_QUEUE_LOCK(&ha->copp_waitlist);
if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
@@ -1673,7 +1683,6 @@
IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
}
} else {
-#endif
IPS_QUEUE_LOCK(&ha->scb_waitlist);
if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
@@ -1685,9 +1694,7 @@
IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
}
-#ifndef NO_IPS_CMDLINE
}
-#endif
SC->scsi_done = done;
@@ -1707,7 +1714,6 @@
return (0);
}
-#ifndef NO_IPS_CMDLINE
if (ips_is_passthru(SC)) {
ips_copp_wait_item_t *scratch;
@@ -1726,6 +1732,24 @@
}
}
+ /* A Reset IOCTL is only sent by the ServeRAID 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 *) SC->request_buffer;
+ 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);
@@ -1744,7 +1768,6 @@
ips_putq_copp_tail(&ha->copp_waitlist, scratch);
}
else
-#endif
ips_putq_wait_tail(&ha->scb_waitlist, SC);
IPS_HA_LOCK(cpu_flags);
@@ -1767,7 +1790,7 @@
if (ips_is_passthru(SC) && SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
char *user_area;
char *kern_area;
- u_int32_t datasize;
+ uint32_t datasize;
/* free io_request_lock */
spin_unlock_irq(&io_request_lock);
@@ -1775,13 +1798,10 @@
/* wait for the command to finish */
down(&ha->ioctl_sem);
- /* reobtain the lock */
- spin_lock_irq(&io_request_lock);
-
/* command finished -- copy back */
user_area = *((char **) &SC->cmnd[4]);
kern_area = ha->ioctl_data;
- datasize = *((u_int32_t *) &SC->cmnd[8]);
+ datasize = *((uint32_t *) &SC->cmnd[8]);
if (datasize) {
if (copy_to_user(user_area, kern_area, datasize) > 0) {
@@ -1791,17 +1811,18 @@
}
}
+ /* reobtain the lock */
+ spin_lock_irq(&io_request_lock);
SC->scsi_done(SC);
}
/* If We were using the CD Boot Flash Buffer, Restore the Old Values */
if ( ips_FlashData == ha->ioctl_data ) {
- ha->ioctl_data = ha->save_ioctl_data;
- ha->ioctl_order = ha->save_ioctl_order;
- ha->ioctl_datasize = ha->save_ioctl_datasize;
+ ha->ioctl_data = ha->flash_data;
+ ha->ioctl_order = ha->flash_order;
+ ha->ioctl_datasize = ha->flash_datasize;
ips_FlashDataInUse = 0;
}
-
return (0);
}
@@ -1917,7 +1938,9 @@
METHOD_TRACE("do_ipsintr", 2);
ha = (ips_ha_t *) dev_id;
-
+ if (!ha)
+ return;
+
spin_lock_irqsave(&io_request_lock, cpu_flags);
if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) {
@@ -1926,13 +1949,6 @@
return ;
}
- if (!ha) {
- clear_bit(IPS_IN_INTR, &ha->flags);
- spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-
- return;
- }
-
if (!ha->active) {
clear_bit(IPS_IN_INTR, &ha->flags);
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
@@ -2182,8 +2198,6 @@
/* Helper Functions */
/*--------------------------------------------------------------------------*/
-#ifndef NO_IPS_CMDLINE
-
/****************************************************************************/
/* */
/* Routine Name: ips_is_passthru */
@@ -2204,16 +2218,22 @@
(SC->channel == 0) &&
(SC->target == IPS_ADAPTER_ID) &&
(SC->lun == 0) &&
- (SC->request_bufflen) &&
- (!SC->use_sg) &&
- (((char *) SC->request_buffer)[0] == 'C') &&
- (((char *) SC->request_buffer)[1] == 'O') &&
- (((char *) SC->request_buffer)[2] == 'P') &&
- (((char *) SC->request_buffer)[3] == 'P')) {
- return (1);
- } else {
- return (0);
+ SC->request_buffer){
+ if((!SC->use_sg) && SC->request_bufflen &&
+ (((char *) SC->request_buffer)[0] == 'C') &&
+ (((char *) SC->request_buffer)[1] == 'O') &&
+ (((char *) SC->request_buffer)[2] == 'P') &&
+ (((char *) SC->request_buffer)[3] == 'P'))
+ return 1;
+ else if(SC->use_sg){
+ struct scatterlist *sg = SC->request_buffer;
+ char *buffer = sg[0].address;
+ if(buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+ buffer[2] == 'P' && buffer[3] == 'P')
+ return 1;
+ }
}
+ return 0;
}
/****************************************************************************/
@@ -2227,40 +2247,74 @@
/****************************************************************************/
static int
ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb, int intr) {
- IPS_NVRAM_P5 nvram;
ips_passthru_t *pt;
+ char *buffer;
+ int length = 0;
METHOD_TRACE("ips_make_passthru", 1);
- if (!SC->request_bufflen || !SC->request_buffer) {
+ if(!SC->use_sg){
+ buffer = SC->request_buffer;
+ length = SC->request_bufflen;
+ }else{
+ struct scatterlist *sg = SC->request_buffer;
+ int i;
+ for(i = 0; i < SC->use_sg; i++)
+ length += sg[i].length;
+
+ if (length < sizeof(ips_passthru_t)) {
+ /* wrong size */
+ DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
+ ips_name, ha->host_num);
+ return (IPS_FAILURE);
+ }else if(!ha->ioctl_data || length > (PAGE_SIZE << ha->ioctl_order)){
+ void *bigger_buf;
+ int count;
+ int order;
+ /* try to allocate a bigger buffer */
+ for (count = PAGE_SIZE, order = 0;
+ count < length;
+ order++, count <<= 1);
+ bigger_buf = (void *) __get_free_pages(GFP_ATOMIC, order);
+ if (bigger_buf) {
+ /* free the old memory */
+ free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
+ /* use the new memory */
+ ha->ioctl_data = (char *) bigger_buf;
+ ha->ioctl_order = order;
+ ha->ioctl_datasize = count;
+ } else {
+ pt = (ips_passthru_t*)sg[0].address;
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+ return (IPS_FAILURE);
+ }
+ }
+ ha->ioctl_datasize = length;
+ length = 0;
+ for(i = 0; i < SC->use_sg; i++){
+ memcpy(&ha->ioctl_data[length], sg[i].address, sg[i].length);
+ length += sg[i].length;
+ }
+ pt = (ips_passthru_t *)ha->ioctl_data;
+ buffer = ha->ioctl_data;
+ }
+ if (!length || !buffer) {
/* no data */
DEBUG_VAR(1, "(%s%d) No passthru structure",
ips_name, ha->host_num);
return (IPS_FAILURE);
}
-
- if (SC->request_bufflen < sizeof(ips_passthru_t)) {
+ if (length < sizeof(ips_passthru_t)) {
/* wrong size */
DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
ips_name, ha->host_num);
return (IPS_FAILURE);
}
-
- if ((((char *) SC->request_buffer)[0] != 'C') ||
- (((char *) SC->request_buffer)[1] != 'O') ||
- (((char *) SC->request_buffer)[2] != 'P') ||
- (((char *) SC->request_buffer)[3] != 'P')) {
- /* signature doesn't match */
- DEBUG_VAR(1, "(%s%d) Wrong signature on passthru structure.",
- ips_name, ha->host_num);
-
- return (IPS_FAILURE);
- }
-
- pt = (ips_passthru_t *) SC->request_buffer;
-
+ pt = (ips_passthru_t*) buffer;
/*
* Some notes about the passthru interface used
*
@@ -2280,14 +2334,14 @@
switch (pt->CoppCmd) {
case IPS_NUMCTRLS:
- memcpy(SC->request_buffer + sizeof(ips_passthru_t),
+ memcpy(buffer + sizeof(ips_passthru_t),
&ips_num_controllers, sizeof(int));
SC->result = DID_OK << 16;
return (IPS_SUCCESS_IMM);
case IPS_CTRLINFO:
- memcpy(SC->request_buffer + sizeof(ips_passthru_t),
+ memcpy(buffer + sizeof(ips_passthru_t),
ha, sizeof(ips_ha_t));
SC->result = DID_OK << 16;
@@ -2296,7 +2350,7 @@
case IPS_COPPUSRCMD:
case IPS_COPPIOCCMD:
if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
- if (SC->request_bufflen < (sizeof(ips_passthru_t) + pt->CmdBSize)) {
+ if (length < (sizeof(ips_passthru_t) + pt->CmdBSize)) {
/* wrong size */
DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
ips_name, ha->host_num);
@@ -2304,14 +2358,14 @@
return (IPS_FAILURE);
}
+ if(ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+ pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)
+ return ips_flash_copperhead(ha, pt, scb);
if (ips_usrcmd(ha, pt, scb))
return (IPS_SUCCESS);
else
return (IPS_FAILURE);
} else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
- char *user_area;
- char *kern_area;
- u_int32_t datasize;
if (SC->request_bufflen < (sizeof(ips_passthru_t))) {
/* wrong size */
@@ -2329,54 +2383,14 @@
(pt->CmdBSize == IPS_IMAGE_SIZE) &&
(ips_FlashDataInUse == 0) ) {
ips_FlashDataInUse = 1;
- ha->save_ioctl_data = ha->ioctl_data;
- ha->save_ioctl_order = ha->ioctl_order;
- ha->save_ioctl_datasize = ha->ioctl_datasize;
+ ha->flash_data = ha->ioctl_data;
+ ha->flash_order = ha->ioctl_order;
+ ha->flash_datasize = ha->ioctl_datasize;
ha->ioctl_data = ips_FlashData;
ha->ioctl_order = 7;
ha->ioctl_datasize = IPS_IMAGE_SIZE;
}
- if ((pt->CoppCP.cmd.nvram.op_code == IPS_CMD_RW_NVRAM_PAGE) &&
- (pt->CoppCP.cmd.nvram.page == 5) &&
- (pt->CoppCP.cmd.nvram.write == 0)) {
-
- datasize = *((u_int32_t *) &scb->scsi_cmd->cmnd[8]);
-
- if (datasize < sizeof(IPS_NVRAM_P5)) {
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
-
- return (IPS_FAILURE);
- }
-
- ips_get_bios_version(ha, IPS_INTR_IORL);
- ips_create_nvrampage5(ha, &nvram);
-
- user_area = *((char **) &scb->scsi_cmd->cmnd[4]);
- kern_area = (char *) &nvram;
- datasize = *((u_int32_t *) &scb->scsi_cmd->cmnd[8]);
-
- if (datasize > sizeof(IPS_NVRAM_P5))
- datasize = sizeof(IPS_NVRAM_P5);
-
- /* Copy out the buffer */
- if (copy_to_user((void *) user_area, (void *) kern_area, datasize) > 0) {
- pt->BasicStatus = 0x0B;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_ERROR << 16;
-
- return (EFAULT);
- }
-
- pt->BasicStatus = 0x00;
- pt->ExtendedStatus = 0x00;
- SC->result = DID_OK << 16;
-
- return (IPS_SUCCESS_IMM);
- }
-
/*
* IPSSEND flashing BIOS
*/
@@ -2433,8 +2447,8 @@
/* make sure buffer is big enough */
if (pt->CmdBSize > ha->ioctl_datasize) {
void *bigger_struct;
- u_int32_t count;
- u_int32_t order;
+ uint32_t count;
+ uint32_t order;
/* try to allocate a bigger struct */
for (count = PAGE_SIZE, order = 0;
@@ -2512,9 +2526,9 @@
struct tq_struct task;
IPS_FLASH_DATA flash_data;
- /* copy in the size/buffer ptr from the scsi command */
- memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
- memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
+ /* copy in the size/buffer ptr from the scsi command */
+ memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
+ memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
if (pt->CmdBSize > le32_to_cpu(pt->CoppCP.cmd.flashbios.count)) {
pt->CmdBSize = le32_to_cpu(pt->CoppCP.cmd.flashbios.count);
@@ -2544,14 +2558,14 @@
pt->ExtendedStatus = 0x00;
SC->result = DID_ERROR << 16;
- return (IPS_FAILURE);
+ return (IPS_FAILURE);
}
/* make sure buffer is big enough */
if (pt->CmdBSize > ha->ioctl_datasize) {
void *bigger_struct;
- u_int32_t count;
- u_int32_t order;
+ uint32_t count;
+ uint32_t order;
/* try to allocate a bigger struct */
for (count = PAGE_SIZE, order = 0;
@@ -2663,6 +2677,176 @@
}
/****************************************************************************/
+/* Routine Name: ips_flash_copperhead */
+/* Routine Description: */
+/* Flash the BIOS/FW on a Copperhead style controller */
+/****************************************************************************/
+static int
+ips_flash_copperhead(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb){
+ int datasize, count;
+
+ /* Trombone is the only copperhead that can do packet flash, but only
+ * for firmware. No one said it had to make sence. */
+ if(IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE){
+ if(ips_usrcmd(ha, pt, scb))
+ return IPS_SUCCESS;
+ else
+ return IPS_FAILURE;
+ }
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0;
+ scb->scsi_cmd->result = DID_OK <<16;
+ /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */
+ /* avoid allocating a huge buffer per adapter ( which can fail ). */
+ if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+ pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS){
+ pt->BasicStatus = 0;
+ return ips_flash_bios(ha, pt, scb);
+ }else if(pt->CoppCP.cmd.flashfw.packet_num == 0){
+ if(ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){
+ ha->flash_data = ips_FlashData;
+ ha->flash_order = 7;
+ ha->flash_datasize = 0;
+ }else if(!ha->flash_data){
+ datasize = pt->CoppCP.cmd.flashfw.total_packets *
+ pt->CoppCP.cmd.flashfw.count;
+ for (count = PAGE_SIZE, ha->flash_order = 0; count < datasize;
+ ha->flash_order++, count <<= 1);
+ ha->flash_data = (char *)__get_free_pages(GFP_ATOMIC, ha->flash_order);
+ ha->flash_datasize = 0;
+ }else
+ return IPS_FAILURE;
+ }else{
+ if(pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
+ (PAGE_SIZE << ha->flash_order)){
+ ips_free_flash_copperhead(ha);
+ printk(KERN_WARNING "failed size sanity check\n");
+ return IPS_FAILURE;
+ }
+ }
+ if(!ha->flash_data)
+ return IPS_FAILURE;
+ pt->BasicStatus = 0;
+ memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
+ pt->CoppCP.cmd.flashfw.count);
+ ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
+ if(pt->CoppCP.cmd.flashfw.packet_num ==
+ pt->CoppCP.cmd.flashfw.total_packets - 1){
+ if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
+ return ips_flash_bios(ha, pt, scb);
+ else if(pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
+ return ips_flash_firmware(ha, pt, scb);
+ }
+ return IPS_SUCCESS_IMM;
+}
+
+/****************************************************************************/
+/* Routine Name: ips_flash_bios */
+/* Routine Description: */
+/* flashes the bios of a copperhead adapter */
+/****************************************************************************/
+static int
+ips_flash_bios(ips_ha_t * ha, ips_passthru_t *pt, ips_scb_t *scb){
+
+ if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+ pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS){
+ if ((!ha->func.programbios) || (!ha->func.erasebios) ||
+ (!ha->func.verifybios))
+ goto error;
+ if((*ha->func.erasebios)(ha)){
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+ ips_name, ha->host_num);
+ goto error;
+ }else if ((*ha->func.programbios)(ha, ha->flash_data + IPS_BIOS_HEADER,
+ ha->flash_datasize - IPS_BIOS_HEADER, 0 )) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to flash",
+ ips_name, ha->host_num);
+ goto error;
+ }else if ((*ha->func.verifybios)(ha, ha->flash_data + IPS_BIOS_HEADER,
+ ha->flash_datasize - IPS_BIOS_HEADER, 0 )) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
+ ips_name, ha->host_num);
+ goto error;
+ }
+ ips_free_flash_copperhead(ha);
+ return IPS_SUCCESS_IMM;
+ }else if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+ pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS){
+ if(!ha->func.erasebios)
+ goto error;
+ if((*ha->func.erasebios)(ha)){
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+ ips_name, ha->host_num);
+ goto error;
+ }
+ return IPS_SUCCESS_IMM;
+ }
+error:
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ ips_free_flash_copperhead(ha);
+ return IPS_FAILURE;
+}
+
+/****************************************************************************/
+/* Routine Name: ips_flash_firmware */
+/* Routine Description: */
+/* flashes the firmware of a copperhead adapter */
+/****************************************************************************/
+static int
+ips_flash_firmware(ips_ha_t * ha, ips_passthru_t *pt, ips_scb_t *scb){
+ IPS_SG_LIST *sg_list;
+
+ if(pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
+ pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW ){
+ memset(&pt->CoppCP.cmd, 0, sizeof(IPS_HOST_COMMAND));
+ pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
+ pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
+ }else{
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ ips_free_flash_copperhead(ha);
+ return IPS_FAILURE;
+ }
+ /* Save the S/G list pointer so it doesn't get clobbered */
+ sg_list = scb->sg_list;
+ /* copy in the CP */
+ memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
+ /* FIX stuff that might be wrong */
+ scb->sg_list = sg_list;
+ scb->scb_busaddr = VIRT_TO_BUS(scb);
+ scb->bus = scb->scsi_cmd->channel;
+ scb->target_id = scb->scsi_cmd->target;
+ scb->lun = scb->scsi_cmd->lun;
+ scb->sg_len = 0;
+ scb->data_len = 0;
+ scb->flags = 0;
+ scb->op_code = 0;
+ scb->callback = ipsintr_done;
+ scb->timeout = ips_cmd_timeout;
+ scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+ scb->cmd.flashfw.buffer_addr = VIRT_TO_BUS(ha->flash_data);
+ if (pt->TimeOut)
+ scb->timeout = pt->TimeOut;
+ scb->scsi_cmd->result = DID_OK <<16;
+ return IPS_SUCCESS;
+}
+
+/****************************************************************************/
+/* Routine Name: ips_free_flash_copperhead */
+/* Routine Description: */
+/* release the memory resources used to hold the flash image */
+/****************************************************************************/
+static void
+ips_free_flash_copperhead(ips_ha_t *ha){
+ if(ha->flash_data == ips_FlashData)
+ test_and_clear_bit(0, &ips_FlashDataInUse);
+ else if(ha->flash_data)
+ free_pages((unsigned long)ha->flash_data, ha->flash_order);
+ ha->flash_data = NULL;
+}
+
+/****************************************************************************/
/* */
/* Routine Name: ips_scheduled_flash_bios */
/* */
@@ -2851,7 +3035,10 @@
return (0);
if (pt->CmdBSize) {
- scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + sizeof(ips_passthru_t));
+ if(!scb->scsi_cmd->use_sg)
+ scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + sizeof(ips_passthru_t));
+ else
+ scb->data_busaddr = VIRT_TO_BUS(ha->ioctl_data + sizeof(ips_passthru_t));
} else {
scb->data_busaddr = 0L;
}
@@ -2899,9 +3086,9 @@
IPS_SG_LIST *sg_list;
char *user_area;
char *kern_area;
- u_int32_t datasize;
+ uint32_t datasize;
- METHOD_TRACE("ips_usrcmd", 1);
+ METHOD_TRACE("ips_newusrcmd", 1);
if ((!scb) || (!pt) || (!ha))
return (0);
@@ -2936,8 +3123,8 @@
if (pt->CmdBSize) {
if (pt->CmdBSize > ha->ioctl_datasize) {
void *bigger_struct;
- u_int32_t count;
- u_int32_t order;
+ uint32_t count;
+ uint32_t order;
/* try to allocate a bigger struct */
for (count = PAGE_SIZE, order = 0;
@@ -2963,7 +3150,7 @@
/* Attempt to copy in the data */
user_area = *((char **) &scb->scsi_cmd->cmnd[4]);
kern_area = ha->ioctl_data;
- datasize = *((u_int32_t *) &scb->scsi_cmd->cmnd[8]);
+ datasize = *((uint32_t *) &scb->scsi_cmd->cmnd[8]);
if (copy_from_user(kern_area, user_area, datasize) > 0) {
DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy in user data",
@@ -3026,8 +3213,10 @@
return ;
}
-
- pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer;
+ if(!scb->scsi_cmd->use_sg)
+ pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer;
+ else
+ pt = (ips_passthru_t *) ha->ioctl_data;
/* Copy data back to the user */
if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) /* Copy DCDB Back to Caller's Area */
@@ -3035,13 +3224,24 @@
pt->BasicStatus = scb->basic_status;
pt->ExtendedStatus = scb->extended_status;
-
+ pt->AdapterType = ha->ad_type;
if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
up(&ha->ioctl_sem);
-
-}
-#endif
+ if(ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+ (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
+ scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
+ ips_free_flash_copperhead(ha);
+
+ if(scb->scsi_cmd->use_sg){
+ int i, length = 0;
+ struct scatterlist *sg = scb->scsi_cmd->request_buffer;
+ for(i = 0; i < scb->scsi_cmd->use_sg; i++){
+ memcpy(sg[i].address, &ha->ioctl_data[length], sg[i].length);
+ length += sg[i].length;
+ }
+ }
+}
/****************************************************************************/
/* */
@@ -3236,6 +3436,14 @@
case IPS_SUBDEVICEID_4LX:
ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
break;
+
+ case IPS_SUBDEVICEID_5I2:
+ ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
+ break;
+
+ case IPS_SUBDEVICEID_5I1:
+ ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
+ break;
}
break;
@@ -3244,31 +3452,6 @@
/****************************************************************************/
/* */
-/* Routine Name: ips_create_nvrampage5 */
-/* */
-/* Routine Description: */
-/* */
-/* Create a pseudo nvram page 5 */
-/* */
-/****************************************************************************/
-static void
-ips_create_nvrampage5(ips_ha_t *ha, IPS_NVRAM_P5 *nvram) {
- METHOD_TRACE("ips_create_nvrampage5", 1);
-
- memset(nvram, 0, sizeof(IPS_NVRAM_P5));
-
- nvram->signature = IPS_NVRAM_P5_SIG;
- nvram->adapter_slot = ha->slot_num;
- nvram->adapter_type = ha->ad_type;
- nvram->operating_system = IPS_OS_LINUX;
- strncpy((char *) nvram->driver_high, IPS_VERSION_HIGH, 4);
- strncpy((char *) nvram->driver_low, IPS_VERSION_LOW, 4);
- strncpy((char *) nvram->bios_high, ha->bios_version, 4);
- strncpy((char *) nvram->bios_low, ha->bios_version + 4, 4);
-}
-
-/****************************************************************************/
-/* */
/* Routine Name: ips_get_bios_version */
/* */
/* Routine Description: */
@@ -3280,10 +3463,10 @@
ips_get_bios_version(ips_ha_t *ha, int intr) {
ips_scb_t *scb;
int ret;
- u_int8_t major;
- u_int8_t minor;
- u_int8_t subminor;
- u_int8_t *buffer;
+ uint8_t major;
+ uint8_t minor;
+ uint8_t subminor;
+ uint8_t *buffer;
char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
METHOD_TRACE("ips_get_bios_version", 1);
@@ -3300,35 +3483,35 @@
/* test 1st byte */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
return;
- writel(cpu_to_le32(1), ha->mem_ptr + IPS_REG_FLAP);
+ writel(1, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
return;
/* Get Major version */
- writel(cpu_to_le32(0x1FF), ha->mem_ptr + IPS_REG_FLAP);
+ writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
major = readb(ha->mem_ptr + IPS_REG_FLDP);
/* Get Minor version */
- writel(cpu_to_le32(0x1FE), ha->mem_ptr + IPS_REG_FLAP);
+ writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
minor = readb(ha->mem_ptr + IPS_REG_FLDP);
/* Get SubMinor version */
- writel(cpu_to_le32(0x1FD), ha->mem_ptr + IPS_REG_FLAP);
+ writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
} else {
@@ -3337,14 +3520,14 @@
/* test 1st byte */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
return ;
outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
return ;
@@ -3352,21 +3535,21 @@
/* Get Major version */
outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
major = inb(ha->io_addr + IPS_REG_FLDP);
/* Get Minor version */
outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
minor = inb(ha->io_addr + IPS_REG_FLDP);
/* Get SubMinor version */
outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
subminor = inb(ha->io_addr + IPS_REG_FLDP);
@@ -3569,9 +3752,8 @@
Scsi_Cmnd *q;
ips_copp_wait_item_t *item;
int ret;
- int intr_status;
unsigned long cpu_flags;
- unsigned long cpu_flags2;
+ unsigned long cpu_flags2 = 0;
METHOD_TRACE("ips_next", 1);
@@ -3582,16 +3764,9 @@
* Block access to the queue function so
* this command won't time out
*/
- if (intr == IPS_INTR_ON) {
+ if (intr == IPS_INTR_ON)
spin_lock_irqsave(&io_request_lock, cpu_flags2);
- intr_status = IPS_INTR_IORL;
- } else {
- intr_status = intr;
-
- /* Quiet the compiler */
- cpu_flags2 = 0;
- }
-
+
if ((ha->subsys->param[3] & 0x300000) && ( ha->scb_activelist.count == 0 )) {
struct timeval tv;
@@ -3601,7 +3776,7 @@
if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
ha->last_ffdc = tv.tv_sec;
IPS_HA_UNLOCK(cpu_flags);
- ips_ffdc_time(ha, intr_status);
+ ips_ffdc_time(ha);
} else {
IPS_HA_UNLOCK(cpu_flags);
}
@@ -3610,7 +3785,6 @@
if (intr == IPS_INTR_ON)
spin_unlock_irqrestore(&io_request_lock, cpu_flags2);
-#ifndef NO_IPS_CMDLINE
/*
* Send passthru commands
* These have priority over normal I/O
@@ -3641,7 +3815,7 @@
/* raise the semaphore */
if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
- u_int32_t datasize;
+ uint32_t datasize;
datasize = 0;
memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
@@ -3659,7 +3833,7 @@
/* raise the semaphore */
if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
- u_int32_t datasize;
+ uint32_t datasize;
datasize = 0;
memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
@@ -3680,7 +3854,7 @@
IPS_QUEUE_LOCK(&ha->copp_waitlist);
ha->num_ioctl--;
continue;
- }
+ }
ret = ips_send_cmd(ha, scb);
@@ -3720,7 +3894,6 @@
IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
IPS_HA_UNLOCK(cpu_flags);
-#endif
/*
* Send "Normal" I/O commands
@@ -3767,33 +3940,33 @@
int i;
sg = SC->request_buffer;
-
- if (SC->use_sg == 1) {
- if (sg[0].length > ha->max_xfer) {
- scb->breakup = 1;
+ scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg, PCI_DMA_BIDIRECTIONAL);
+ scb->flags |= IPS_SCB_MAP_SG;
+ if (scb->sg_count == 1) {
+ if (sg_dma_len(sg) > ha->max_xfer) {
+ scb->breakup = 1;
scb->data_len = ha->max_xfer;
} else
- scb->data_len = sg[0].length;
+ scb->data_len = sg_dma_len(sg);
scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(sg[0].address);
+ scb->data_busaddr = sg_dma_address(sg);
scb->sg_len = 0;
} else {
/* Check for the first Element being bigger than MAX_XFER */
- if (sg[0].length > ha->max_xfer) {
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(sg[0].address));
+ if (sg_dma_len(&sg[0]) > ha->max_xfer) {
+ scb->sg_list[0].address = cpu_to_le32(sg_dma_address(&sg[0]));
scb->sg_list[0].length = ha->max_xfer;
scb->data_len = ha->max_xfer;
scb->breakup = 0;
scb->sg_break=1;
scb->sg_len = 1;
- }
- else {
- for (i = 0; i < SC->use_sg; i++) {
- scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i].length = cpu_to_le32(sg[i].length);
+ } else {
+ for (i = 0; i < scb->sg_count; i++) {
+ scb->sg_list[i].address = cpu_to_le32(sg_dma_address(&sg[i]));
+ scb->sg_list[i].length = cpu_to_le32(sg_dma_len(&sg[i]));
- if (scb->data_len + sg[i].length > ha->max_xfer) {
+ if (scb->data_len + sg_dma_len(&sg[i]) > ha->max_xfer) {
/*
* Data Breakup required
*/
@@ -3801,17 +3974,17 @@
break;
}
- scb->data_len += sg[i].length;
+ scb->data_len += sg_dma_len(&sg[i]);
}
if (!scb->breakup)
- scb->sg_len = SC->use_sg;
+ scb->sg_len = scb->sg_count;
else
scb->sg_len = scb->breakup;
}
scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
+ scb->data_busaddr = scb->sg_busaddr;
}
} else {
if (SC->request_bufflen) {
@@ -3826,7 +3999,9 @@
}
scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(SC->request_buffer);
+ scb->data_busaddr = pci_map_single(ha->pcidev, SC->request_buffer,
+ scb->data_len, PCI_DMA_BIDIRECTIONAL);
+ scb->flags |= IPS_SCB_MAP_SINGLE;
scb->sg_len = 0;
} else {
scb->data_busaddr = 0L;
@@ -4434,42 +4609,40 @@
if (!scb)
return ;
-#ifndef NO_IPS_CMDLINE
if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
ips_cleanup_passthru(ha, scb);
IPS_HA_LOCK(cpu_flags);
ha->num_ioctl--;
IPS_HA_UNLOCK(cpu_flags);
} else {
-#endif
/*
* Check to see if this command had too much
* data and had to be broke up. If so, queue
* the rest of the data and continue.
*/
- if (scb->breakup) {
+ if ((scb->breakup) || (scb->sg_break)) {
/* we had a data breakup */
- u_int8_t bk_save;
+ uint8_t bk_save;
bk_save = scb->breakup;
scb->breakup = 0;
- if (scb->scsi_cmd->use_sg) {
+ if (scb->sg_count) {
/* S/G request */
struct scatterlist *sg;
int i;
sg = scb->scsi_cmd->request_buffer;
- if (scb->scsi_cmd->use_sg == 1) {
- if (sg[0].length - (bk_save * ha->max_xfer) > ha->max_xfer) {
+ if (scb->sg_count == 1) {
+ if (sg_dma_len(sg) - (bk_save * ha->max_xfer) > ha->max_xfer) {
/* Further breakup required */
scb->data_len = ha->max_xfer;
- scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer));
+ scb->data_busaddr = sg_dma_address(sg) + (bk_save * ha->max_xfer);
scb->breakup = bk_save + 1;
} else {
- scb->data_len = sg[0].length - (bk_save * ha->max_xfer);
- scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer));
+ scb->data_len = sg_dma_len(sg) - (bk_save * ha->max_xfer);
+ scb->data_busaddr = sg_dma_address(sg) + (bk_save * ha->max_xfer);
}
scb->dcdb.transfer_length = scb->data_len;
@@ -4486,45 +4659,46 @@
/* pointed to by bk_save */
if (scb->sg_break) {
scb->sg_len = 1;
- scb->sg_list[0].address = VIRT_TO_BUS(sg[bk_save].address+ha->max_xfer*scb->sg_break);
- if (ha->max_xfer > sg[bk_save].length-ha->max_xfer * scb->sg_break)
- scb->sg_list[0].length = sg[bk_save].length-ha->max_xfer * scb->sg_break;
+ scb->sg_list[0].address = sg_dma_address(&sg[bk_save])
+ + ha->max_xfer*scb->sg_break;
+ if (ha->max_xfer > sg_dma_len(&sg[bk_save]) - ha->max_xfer * scb->sg_break)
+ scb->sg_list[0].length = sg_dma_len(&sg[bk_save]) - ha->max_xfer * scb->sg_break;
else
scb->sg_list[0].length = ha->max_xfer;
scb->sg_break++; /* MUST GO HERE for math below to work */
- scb->data_len = scb->sg_list[0].length;;
+ scb->data_len = scb->sg_list[0].length;;
- if (sg[bk_save].length <= ha->max_xfer * scb->sg_break ) {
+ if (sg_dma_len(&sg[bk_save]) <= ha->max_xfer * scb->sg_break ) {
scb->sg_break = 0; /* No more work in this unit */
- if (( bk_save + 1 ) >= scb->scsi_cmd->use_sg)
+ if (( bk_save + 1 ) >= scb->sg_count)
scb->breakup = 0;
- else
+ else
scb->breakup = bk_save + 1;
}
} else {
/* ( sg_break == 0 ), so this is our first look at a new sg piece */
- if (sg[bk_save].length > ha->max_xfer) {
- scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(sg[bk_save].address));
- scb->sg_list[0].length = ha->max_xfer;
- scb->breakup = bk_save;
- scb->sg_break = 1;
- scb->data_len = ha->max_xfer;
- scb->sg_len = 1;
- } else {
- /* OK, the next sg is a short one, so loop until full */
- scb->data_len = 0;
- scb->sg_len = 0;
- scb->sg_break = 0;
+ if (sg_dma_len(&sg[bk_save]) > ha->max_xfer) {
+ scb->sg_list[0].address = sg_dma_address(&sg[bk_save]);
+ scb->sg_list[0].length = ha->max_xfer;
+ scb->breakup = bk_save;
+ scb->sg_break = 1;
+ scb->data_len = ha->max_xfer;
+ scb->sg_len = 1;
+ } else {
+ /* OK, the next sg is a short one, so loop until full */
+ scb->data_len = 0;
+ scb->sg_len = 0;
+ scb->sg_break = 0;
/* We're only doing full units here */
- for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
- scb->sg_list[i - bk_save].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
- scb->sg_list[i - bk_save].length = cpu_to_le32(sg[i].length);
- if (scb->data_len + sg[i].length > ha->max_xfer) {
- scb->breakup = i; /* sneaky, if not more work, than breakup is 0 */
- break;
- }
- scb->data_len += sg[i].length;
- scb->sg_len++; /* only if we didn't get too big */
+ for (i = bk_save; i < scb->sg_count; i++) {
+ scb->sg_list[i - bk_save].address = sg_dma_address(&sg[i]);
+ scb->sg_list[i - bk_save].length = cpu_to_le32(sg_dma_len(&sg[i]));
+ if (scb->data_len + sg_dma_len(&sg[i]) > ha->max_xfer) {
+ scb->breakup = i; /* sneaky, if not more work, than breakup is 0 */
+ break;
+ }
+ scb->data_len += sg_dma_len(&sg[i]);
+ scb->sg_len++; /* only if we didn't get too big */
}
}
}
@@ -4532,20 +4706,22 @@
/* Also, we need to be sure we don't queue work ( breakup != 0 )
if no more sg units for next time */
scb->dcdb.transfer_length = scb->data_len;
- scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
+ scb->data_busaddr = scb->sg_busaddr;
}
- } else {
+ } else {
/* Non S/G Request */
+ pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
+ PCI_DMA_BIDIRECTIONAL);
if ((scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) > ha->max_xfer) {
/* Further breakup required */
scb->data_len = ha->max_xfer;
- scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer));
+ scb->data_busaddr = pci_map_single(ha->pcidev, scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer), scb->data_len, PCI_DMA_BIDIRECTIONAL);
scb->breakup = bk_save + 1;
} else {
scb->data_len = scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer);
- scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer));
- }
+ scb->data_busaddr = pci_map_single(ha->pcidev, scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer), scb->data_len, PCI_DMA_BIDIRECTIONAL);
+ }
scb->dcdb.transfer_length = scb->data_len;
scb->sg_len = 0;
@@ -4587,9 +4763,7 @@
return ;
}
-#ifndef NO_IPS_CMDLINE
} /* end if passthru */
-#endif
if (scb->bus) {
IPS_HA_LOCK(cpu_flags);
@@ -4742,6 +4916,8 @@
/* */
/* Send a command to the controller and wait for it to return */
/* */
+/* The FFDC Time Stamp use this function for the callback, but doesn't */
+/* actually need to wait. */
/****************************************************************************/
static int
ips_send_wait(ips_ha_t *ha, ips_scb_t *scb, int timeout, int intr) {
@@ -4749,15 +4925,18 @@
METHOD_TRACE("ips_send_wait", 1);
- ha->waitflag = TRUE;
- ha->cmd_in_progress = scb->cdb[0];
+ if (intr != IPS_FFDC) { /* Won't be Waiting if this is a Time Stamp */
+ ha->waitflag = TRUE;
+ ha->cmd_in_progress = scb->cdb[0];
+ }
ret = ips_send(ha, scb, ipsintr_blocking);
if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
return (ret);
- ret = ips_wait(ha, timeout, intr);
+ if (intr != IPS_FFDC) /* Don't Wait around if this is a Time Stamp */
+ ret = ips_wait(ha, timeout, intr);
return (ret);
}
@@ -4794,11 +4973,7 @@
return (1);
}
-#ifndef NO_IPS_CMDLINE
} else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
-#else
- } else if (scb->bus == 0) {
-#endif
/* command to logical bus -- interpret */
ret = IPS_SUCCESS_IMM;
@@ -5046,8 +5221,8 @@
ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) {
ips_scb_t *scb;
ips_stat_t *sp;
- u_int8_t basic_status;
- u_int8_t ext_status;
+ uint8_t basic_status;
+ uint8_t ext_status;
int errcode;
METHOD_TRACE("ips_chkstatus", 1);
@@ -5076,11 +5251,9 @@
scb->target_id,
scb->lun);
-#ifndef NO_IPS_CMDLINE
if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
/* passthru - just returns the raw result */
return ;
-#endif
errcode = DID_OK;
@@ -5270,7 +5443,7 @@
cap = (IPS_SCSI_CAPACITY *) scb->scsi_cmd->request_buffer;
cap->lba = cpu_to_be32(le32_to_cpu(ha->adapt->logical_drive_info.drive_info[scb->target_id].sector_count) - 1);
- cap->len = cpu_to_be32((u_int32_t) IPS_BLKSIZE);
+ cap->len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
return (1);
}
@@ -5286,9 +5459,9 @@
/****************************************************************************/
static int
ips_msense(ips_ha_t *ha, ips_scb_t *scb) {
- u_int16_t heads;
- u_int16_t sectors;
- u_int32_t cylinders;
+ uint16_t heads;
+ uint16_t sectors;
+ uint32_t cylinders;
IPS_SCSI_MODE_PAGE_DATA mdata;
METHOD_TRACE("ips_msense", 1);
@@ -5391,7 +5564,6 @@
/****************************************************************************/
static void
ips_free(ips_ha_t *ha) {
- int i;
METHOD_TRACE("ips_free", 1);
@@ -5432,16 +5604,7 @@
ha->ioctl_datasize = 0;
ha->ioctl_order = 0;
}
-
- if (ha->scbs) {
- for (i = 0; i < ha->max_cmds; i++) {
- if (ha->scbs[i].sg_list)
- kfree(ha->scbs[i].sg_list);
- }
-
- kfree(ha->scbs);
- ha->scbs = NULL;
- } /* end if */
+ ips_deallocatescbs(ha, ha->max_cmds);
/* free memory mapped (if applicable) */
if (ha->mem_ptr) {
@@ -5450,7 +5613,7 @@
ha->mem_ptr = NULL;
}
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
if (ha->mem_addr)
release_mem_region(ha->mem_addr, ha->mem_len);
#endif
@@ -5458,6 +5621,26 @@
}
}
+/****************************************************************************/
+/* */
+/* Routine Name: ips_deallocatescbs */
+/* */
+/* Routine Description: */
+/* */
+/* Free the command blocks */
+/* */
+/****************************************************************************/
+static int
+ips_deallocatescbs(ips_ha_t *ha, int cmds) {
+ if (ha->scbs) {
+ pci_free_consistent(ha->pcidev,sizeof(IPS_SG_LIST) * IPS_MAX_SG *
+ cmds, ha->scbs->sg_list, ha->scbs->sg_busaddr);
+ pci_free_consistent(ha->pcidev, sizeof(ips_scb_t) * cmds,
+ ha->scbs, ha->scbs->scb_busaddr);
+ ha->scbs = NULL;
+ } /* end if */
+return 1;
+}
/****************************************************************************/
/* */
@@ -5471,25 +5654,32 @@
static int
ips_allocatescbs(ips_ha_t *ha) {
ips_scb_t *scb_p;
+ IPS_SG_LIST* ips_sg;
int i;
-
+ dma_addr_t command_dma, sg_dma;
+
METHOD_TRACE("ips_allocatescbs", 1);
- /* Allocate memory for the CCBs */
- ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_KERNEL);
+ /* Allocate memory for the SCBs */
+ ha->scbs = pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof(ips_scb_t),
+ &command_dma);
if (ha->scbs == NULL)
return 0;
+ ips_sg = pci_alloc_consistent(ha->pcidev, sizeof(IPS_SG_LIST) * IPS_MAX_SG *
+ ha->max_cmds, &sg_dma);
+ if(ips_sg == NULL){
+ pci_free_consistent(ha->pcidev,ha->max_cmds * sizeof(ips_scb_t),ha->scbs, command_dma);
+ return 0;
+ }
memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
for (i = 0; i < ha->max_cmds; i++) {
scb_p = &ha->scbs[i];
-
- /* allocate S/G list */
- scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC);
-
- if (! scb_p->sg_list)
- return (0);
+ scb_p->scb_busaddr = command_dma + sizeof(ips_scb_t) * i;
+ /* set up S/G list */
+ scb_p->sg_list = ips_sg + i * IPS_MAX_SG;
+ scb_p->sg_busaddr = sg_dma + sizeof(IPS_SG_LIST) * IPS_MAX_SG * i;
/* add to the free list */
if (i < ha->max_cmds - 1) {
@@ -5514,14 +5704,15 @@
static void
ips_init_scb(ips_ha_t *ha, ips_scb_t *scb) {
IPS_SG_LIST *sg_list;
-
+ uint32_t cmd_busaddr, sg_busaddr;
METHOD_TRACE("ips_init_scb", 1);
if (scb == NULL)
return ;
sg_list = scb->sg_list;
-
+ cmd_busaddr = scb->scb_busaddr;
+ sg_busaddr = scb->sg_busaddr;
/* zero fill */
memset(scb, 0, sizeof(ips_scb_t));
memset(ha->dummy, 0, sizeof(IPS_IO_CMD));
@@ -5532,11 +5723,12 @@
ha->dummy->command_id = IPS_MAX_CMDS;
/* set bus address of scb */
- scb->scb_busaddr = VIRT_TO_BUS(scb);
+ scb->scb_busaddr = cmd_busaddr;
+ scb->sg_busaddr = sg_busaddr;
scb->sg_list = sg_list;
/* Neptune Fix */
- scb->cmd.basic_io.cccr = cpu_to_le32((u_int32_t) IPS_BIT_ILE);
+ scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
scb->cmd.basic_io.ccsar = cpu_to_le32(VIRT_TO_BUS(ha->dummy));
}
@@ -5591,6 +5783,10 @@
unsigned long cpu_flags;
METHOD_TRACE("ips_freescb", 1);
+ if(scb->flags & IPS_SCB_MAP_SG)
+ pci_unmap_sg(ha->pcidev,scb->scsi_cmd->request_buffer, scb->scsi_cmd->use_sg, PCI_DMA_BIDIRECTIONAL);
+ else if(scb->flags & IPS_SCB_MAP_SINGLE)
+ pci_unmap_single(ha->pcidev,scb->cmd.basic_io.sg_addr, scb->data_len, PCI_DMA_BIDIRECTIONAL);
/* check to make sure this is not our "special" scb */
if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
@@ -5607,13 +5803,13 @@
/* */
/* Routine Description: */
/* */
-/* Reset the controller */
+/* Is controller initialized ? */
/* */
/****************************************************************************/
static int
ips_isinit_copperhead(ips_ha_t *ha) {
- u_int8_t scpr;
- u_int8_t isr;
+ uint8_t scpr;
+ uint8_t isr;
METHOD_TRACE("ips_isinit_copperhead", 1);
@@ -5632,13 +5828,13 @@
/* */
/* Routine Description: */
/* */
-/* Reset the controller */
+/* Is controller initialized ? */
/* */
/****************************************************************************/
static int
ips_isinit_copperhead_memio(ips_ha_t *ha) {
- u_int8_t isr=0;
- u_int8_t scpr;
+ uint8_t isr=0;
+ uint8_t scpr;
METHOD_TRACE("ips_is_init_copperhead_memio", 1);
@@ -5657,18 +5853,18 @@
/* */
/* Routine Description: */
/* */
-/* Reset the controller */
+/* Is controller initialized ? */
/* */
/****************************************************************************/
static int
ips_isinit_morpheus(ips_ha_t *ha) {
- u_int32_t post;
- u_int32_t bits;
+ uint32_t post;
+ uint32_t bits;
METHOD_TRACE("ips_is_init_morpheus", 1);
- post = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I960_MSG0));
- bits = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I2O_HIR));
+ post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+ bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
if (post == 0)
return (0);
@@ -5718,13 +5914,13 @@
/****************************************************************************/
static void
ips_enable_int_morpheus(ips_ha_t *ha) {
- u_int32_t Oimr;
+ uint32_t Oimr;
METHOD_TRACE("ips_enable_int_morpheus", 1);
- Oimr = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I960_OIMR));
+ Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
Oimr &= ~0x08;
- writel(cpu_to_le32(Oimr), ha->mem_ptr + IPS_REG_I960_OIMR);
+ writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
}
/****************************************************************************/
@@ -5738,11 +5934,11 @@
/****************************************************************************/
static int
ips_init_copperhead(ips_ha_t *ha) {
- u_int8_t Isr;
- u_int8_t Cbsp;
- u_int8_t PostByte[IPS_MAX_POST_BYTES];
- u_int8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
- int i, j;
+ uint8_t Isr;
+ uint8_t Cbsp;
+ uint8_t PostByte[IPS_MAX_POST_BYTES];
+ uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
+ int i, j;
METHOD_TRACE("ips_init_copperhead", 1);
@@ -5752,8 +5948,9 @@
if (Isr & IPS_BIT_GHI)
break;
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
- }
+ }
if (j >= 45)
/* error occurred */
@@ -5776,7 +5973,8 @@
if (Isr & IPS_BIT_GHI)
break;
- MDELAY(IPS_ONE_SEC); /* 1 sec */
+ /* Delay for 1 Second */
+ MDELAY(IPS_ONE_SEC);
}
if (j >= 240)
@@ -5791,8 +5989,9 @@
Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
if ((Cbsp & IPS_BIT_OP) == 0)
- break;
+ break;
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
}
@@ -5827,11 +6026,11 @@
/****************************************************************************/
static int
ips_init_copperhead_memio(ips_ha_t *ha) {
- u_int8_t Isr=0;
- u_int8_t Cbsp;
- u_int8_t PostByte[IPS_MAX_POST_BYTES];
- u_int8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
- int i, j;
+ uint8_t Isr=0;
+ uint8_t Cbsp;
+ uint8_t PostByte[IPS_MAX_POST_BYTES];
+ uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
+ int i, j;
METHOD_TRACE("ips_init_copperhead_memio", 1);
@@ -5841,6 +6040,7 @@
if (Isr & IPS_BIT_GHI)
break;
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
}
@@ -5865,7 +6065,8 @@
if (Isr & IPS_BIT_GHI)
break;
- MDELAY(IPS_ONE_SEC); /* 100 msec */
+ /* Delay for 1 Second */
+ MDELAY(IPS_ONE_SEC);
}
if (j >= 240)
@@ -5882,6 +6083,7 @@
if ((Cbsp & IPS_BIT_OP) == 0)
break;
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
}
@@ -5890,7 +6092,7 @@
return (0);
/* setup CCCR */
- writel(cpu_to_le32(0x1010), ha->mem_ptr + IPS_REG_CCCR);
+ writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
/* Enable busmastering */
writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
@@ -5917,21 +6119,22 @@
/****************************************************************************/
static int
ips_init_morpheus(ips_ha_t *ha) {
- u_int32_t Post;
- u_int32_t Config;
- u_int32_t Isr;
- u_int32_t Oimr;
+ uint32_t Post;
+ uint32_t Config;
+ uint32_t Isr;
+ uint32_t Oimr;
int i;
METHOD_TRACE("ips_init_morpheus", 1);
/* Wait up to 45 secs for Post */
for (i = 0; i < 45; i++) {
- Isr = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I2O_HIR));
+ Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
if (Isr & IPS_BIT_I960_MSG0I)
break;
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
}
@@ -5943,11 +6146,11 @@
return (0);
}
- Post = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I960_MSG0));
+ Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
/* Clear the interrupt bit */
- Isr = (u_int32_t) IPS_BIT_I960_MSG0I;
- writel(cpu_to_le32(Isr), ha->mem_ptr + IPS_REG_I2O_HIR);
+ Isr = (uint32_t) IPS_BIT_I960_MSG0I;
+ writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
if (Post < (IPS_GOOD_POST_STATUS << 8)) {
printk(KERN_WARNING "(%s%d) reset controller fails (post status %x).\n",
@@ -5958,12 +6161,13 @@
/* Wait up to 240 secs for config bytes */
for (i = 0; i < 240; i++) {
- Isr = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I2O_HIR));
+ Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
if (Isr & IPS_BIT_I960_MSG1I)
break;
- MDELAY(IPS_ONE_SEC); /* 100 msec */
+ /* Delay for 1 Second */
+ MDELAY(IPS_ONE_SEC);
}
if (i >= 240) {
@@ -5974,16 +6178,16 @@
return (0);
}
- Config = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I960_MSG1));
+ Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
/* Clear interrupt bit */
- Isr = (u_int32_t) IPS_BIT_I960_MSG1I;
- writel(cpu_to_le32(Isr), ha->mem_ptr + IPS_REG_I2O_HIR);
+ Isr = (uint32_t) IPS_BIT_I960_MSG1I;
+ writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
/* Turn on the interrupts */
- Oimr = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I960_OIMR));
+ Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
Oimr &= ~0x8;
- writel(cpu_to_le32(Oimr), ha->mem_ptr + IPS_REG_I960_OIMR);
+ writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
/* if we get here then everything went OK */
return (1);
@@ -6016,10 +6220,15 @@
reset_counter++;
outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
+
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
+
outb(0, ha->io_addr + IPS_REG_SCPR);
- MDELAY(IPS_ONE_SEC);
+ /* Delay for 1 Second */
+ MDELAY(IPS_ONE_SEC);
+
if ((*ha->func.init)(ha))
break;
else if (reset_counter >= 2) {
@@ -6061,10 +6270,15 @@
reset_counter++;
writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
+
+ /* Delay for 1 Second */
MDELAY(IPS_ONE_SEC);
+
writeb(0, ha->mem_ptr + IPS_REG_SCPR);
- MDELAY(IPS_ONE_SEC);
+ /* Delay for 1 Second */
+ MDELAY(IPS_ONE_SEC);
+
if ((*ha->func.init)(ha))
break;
else if (reset_counter >= 2) {
@@ -6091,7 +6305,7 @@
static int
ips_reset_morpheus(ips_ha_t *ha) {
int reset_counter;
- u_int8_t junk;
+ uint8_t junk;
unsigned long cpu_flags;
METHOD_TRACE("ips_reset_morpheus", 1);
@@ -6106,11 +6320,11 @@
while (reset_counter < 2) {
reset_counter++;
- writel(cpu_to_le32(0x80000000), ha->mem_ptr + IPS_REG_I960_IDR);
+ writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
- /* Delay for 5 sec */
+ /* Delay for 5 Seconds */
MDELAY(5 * IPS_ONE_SEC);
-
+
/* Do a PCI config read to wait for adapter */
pci_read_config_byte(ha->pcidev, 4, &junk);
@@ -6139,7 +6353,7 @@
/****************************************************************************/
static void
ips_statinit(ips_ha_t *ha) {
- u_int32_t phys_status_start;
+ uint32_t phys_status_start;
METHOD_TRACE("ips_statinit", 1);
@@ -6168,7 +6382,7 @@
/****************************************************************************/
static void
ips_statinit_memio(ips_ha_t *ha) {
- u_int32_t phys_status_start;
+ uint32_t phys_status_start;
METHOD_TRACE("ips_statinit_memio", 1);
@@ -6177,10 +6391,10 @@
ha->adapt->p_status_tail = ha->adapt->status;
phys_status_start = VIRT_TO_BUS(ha->adapt->status);
- writel(cpu_to_le32(phys_status_start), ha->mem_ptr + IPS_REG_SQSR);
- writel(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), ha->mem_ptr + IPS_REG_SQER);
- writel(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), ha->mem_ptr + IPS_REG_SQHR);
- writel(cpu_to_le32(phys_status_start), ha->mem_ptr + IPS_REG_SQTR);
+ writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
+ writel(phys_status_start + IPS_STATUS_Q_SIZE, ha->mem_ptr + IPS_REG_SQER);
+ writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
+ writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
ha->adapt->hw_status_start = phys_status_start;
ha->adapt->hw_status_tail = phys_status_start;
@@ -6195,7 +6409,7 @@
/* Remove an element from the status queue */
/* */
/****************************************************************************/
-static u_int32_t
+static uint32_t
ips_statupd_copperhead(ips_ha_t *ha) {
METHOD_TRACE("ips_statupd_copperhead", 1);
@@ -6221,7 +6435,7 @@
/* Remove an element from the status queue */
/* */
/****************************************************************************/
-static u_int32_t
+static uint32_t
ips_statupd_copperhead_memio(ips_ha_t *ha) {
METHOD_TRACE("ips_statupd_copperhead_memio", 1);
@@ -6233,7 +6447,7 @@
ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
}
- writel(cpu_to_le32(ha->adapt->hw_status_tail), ha->mem_ptr + IPS_REG_SQTR);
+ writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
return (ha->adapt->p_status_tail->value);
}
@@ -6247,13 +6461,13 @@
/* Remove an element from the status queue */
/* */
/****************************************************************************/
-static u_int32_t
+static uint32_t
ips_statupd_morpheus(ips_ha_t *ha) {
- u_int32_t val;
+ uint32_t val;
METHOD_TRACE("ips_statupd_morpheus", 1);
- val = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ));
+ val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
return (val);
}
@@ -6269,8 +6483,8 @@
/****************************************************************************/
static int
ips_issue_copperhead(ips_ha_t *ha, ips_scb_t *scb) {
- u_int32_t TimeOut;
- u_int32_t val;
+ uint32_t TimeOut;
+ uint32_t val;
unsigned long cpu_flags;
METHOD_TRACE("ips_issue_copperhead", 1);
@@ -6332,8 +6546,8 @@
/****************************************************************************/
static int
ips_issue_copperhead_memio(ips_ha_t *ha, ips_scb_t *scb) {
- u_int32_t TimeOut;
- u_int32_t val;
+ uint32_t TimeOut;
+ uint32_t val;
unsigned long cpu_flags;
METHOD_TRACE("ips_issue_copperhead_memio", 1);
@@ -6358,7 +6572,7 @@
TimeOut = 0;
- while ((val = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
+ while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
udelay(1000);
if (++TimeOut >= IPS_SEM_TIMEOUT) {
@@ -6376,8 +6590,8 @@
} /* end if */
} /* end while */
- writel(cpu_to_le32(scb->scb_busaddr), ha->mem_ptr + IPS_REG_CCSAR);
- writel(cpu_to_le32(IPS_BIT_START_CMD), ha->mem_ptr + IPS_REG_CCCR);
+ writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
+ writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
IPS_HA_UNLOCK(cpu_flags);
@@ -6457,7 +6671,7 @@
IPS_HA_LOCK(cpu_flags);
- writel(cpu_to_le32(scb->scb_busaddr), ha->mem_ptr + IPS_REG_I2O_INMSGQ);
+ writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
IPS_HA_UNLOCK(cpu_flags);
@@ -6475,7 +6689,7 @@
/****************************************************************************/
static int
ips_isintr_copperhead(ips_ha_t *ha) {
- u_int8_t Isr;
+ uint8_t Isr;
METHOD_TRACE("ips_isintr_copperhead", 2);
@@ -6507,7 +6721,7 @@
/****************************************************************************/
static int
ips_isintr_copperhead_memio(ips_ha_t *ha) {
- u_int8_t Isr;
+ uint8_t Isr;
METHOD_TRACE("ips_isintr_memio", 2);
@@ -6539,11 +6753,11 @@
/****************************************************************************/
static int
ips_isintr_morpheus(ips_ha_t *ha) {
- u_int32_t Isr;
+ uint32_t Isr;
METHOD_TRACE("ips_isintr_morpheus", 2);
- Isr = le32_to_cpu(readl(ha->mem_ptr + IPS_REG_I2O_HIR));
+ Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
if (Isr & IPS_BIT_I2O_OPQI)
return (1);
@@ -6562,15 +6776,15 @@
/****************************************************************************/
static int
ips_wait(ips_ha_t *ha, int time, int intr) {
- int ret;
- u_int8_t done;
+ int ret;
+ int done;
METHOD_TRACE("ips_wait", 1);
ret = IPS_FAILURE;
done = FALSE;
- time *= IPS_ONE_SEC; /* convert seconds to milliseconds */
+ time *= IPS_ONE_SEC; /* convert seconds */
while ((time > 0) && (!done)) {
if (intr == IPS_INTR_ON) {
@@ -6603,37 +6817,10 @@
(*ha->func.intr)(ha);
clear_bit(IPS_IN_INTR, &ha->flags);
- } else if (intr == IPS_INTR_HAL) {
- if (ha->waitflag == FALSE) {
- /*
- * controller generated an interrupt to
- * acknowledge completion of the command
- * and ips_intr() has serviced the interrupt.
- */
- ret = IPS_SUCCESS;
- done = TRUE;
- break;
- }
+ }
- /*
- * NOTE: since we were not called with the iorequest lock
- * we must obtain it before we can call the interrupt handler.
- * We were called under the HA lock so we can assume that interrupts
- * are masked.
- */
- spin_lock(&io_request_lock);
-
- while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
- udelay(1000);
-
- (*ha->func.intr)(ha);
-
- clear_bit(IPS_IN_INTR, &ha->flags);
-
- spin_unlock(&io_request_lock);
- }
-
- udelay(1000); /* 1 milisecond */
+ /* This looks like a very evil loop, but it only does this during start-up */
+ udelay(1000);
time--;
}
@@ -6687,6 +6874,8 @@
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 */
+
/* now update the page */
if (!ips_readwrite_page5(ha, TRUE, intr)) {
printk(KERN_WARNING "(%s%d) unable to write NVRAM page 5.\n",
@@ -6827,6 +7016,10 @@
for (i = 0; i < 4; i++)
ha->conf->init_id[i] = 7;
+ /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
+ if ((scb->basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_CMPLT_WERROR)
+ return (1);
+
return (0);
}
@@ -6980,7 +7173,7 @@
/* */
/****************************************************************************/
static void
-ips_ffdc_time(ips_ha_t *ha, int intr) {
+ips_ffdc_time(ips_ha_t *ha) {
ips_scb_t *scb;
METHOD_TRACE("ips_ffdc_time", 1);
@@ -7003,7 +7196,7 @@
ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
/* issue command */
- ips_send_wait(ha, scb, ips_cmd_timeout, intr);
+ ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
}
/****************************************************************************/
@@ -7083,7 +7276,7 @@
static int
ips_erase_bios(ips_ha_t *ha) {
int timeout;
- u_int8_t status=0;
+ uint8_t status=0;
METHOD_TRACE("ips_erase_bios", 1);
@@ -7092,33 +7285,33 @@
/* Clear the status register */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
outb(0x50, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* Erase Setup */
outb(0x20, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* Erase Confirm */
outb(0xD0, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* Erase Status */
outb(0x70, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
timeout = 80000; /* 80 seconds */
while (timeout > 0) {
if (ha->revision_id == IPS_REVID_TROMBONE64) {
outl(0, ha->io_addr + IPS_REG_FLAP);
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
}
status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -7137,14 +7330,14 @@
/* try to suspend the erase */
outb(0xB0, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* wait for 10 seconds */
timeout = 10000;
while (timeout > 0) {
if (ha->revision_id == IPS_REVID_TROMBONE64) {
outl(0, ha->io_addr + IPS_REG_FLAP);
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
}
status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -7173,12 +7366,12 @@
/* clear status */
outb(0x50, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* enable reads */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (0);
}
@@ -7194,7 +7387,7 @@
static int
ips_erase_bios_memio(ips_ha_t *ha) {
int timeout;
- u_int8_t status;
+ uint8_t status;
METHOD_TRACE("ips_erase_bios_memio", 1);
@@ -7203,33 +7396,33 @@
/* Clear the status register */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* Erase Setup */
writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* Erase Confirm */
writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* Erase Status */
writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
timeout = 80000; /* 80 seconds */
while (timeout > 0) {
if (ha->revision_id == IPS_REVID_TROMBONE64) {
writel(0, ha->mem_ptr + IPS_REG_FLAP);
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
}
status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -7248,14 +7441,14 @@
/* try to suspend the erase */
writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* wait for 10 seconds */
timeout = 10000;
while (timeout > 0) {
if (ha->revision_id == IPS_REVID_TROMBONE64) {
writel(0, ha->mem_ptr + IPS_REG_FLAP);
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
}
status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -7284,12 +7477,12 @@
/* clear status */
writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* enable reads */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (0);
}
@@ -7303,10 +7496,10 @@
/* */
/****************************************************************************/
static int
-ips_program_bios(ips_ha_t *ha, char *buffer, u_int32_t buffersize, u_int32_t offset) {
+ips_program_bios(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
int i;
int timeout;
- u_int8_t status=0;
+ uint8_t status=0;
METHOD_TRACE("ips_program_bios", 1);
@@ -7316,22 +7509,22 @@
/* write a byte */
outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
outb(0x40, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* wait up to one second */
timeout = 1000;
while (timeout > 0) {
if (ha->revision_id == IPS_REVID_TROMBONE64) {
outl(0, ha->io_addr + IPS_REG_FLAP);
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
}
status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -7347,11 +7540,11 @@
/* timeout error */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (1);
}
@@ -7361,11 +7554,11 @@
/* programming error */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (1);
}
@@ -7374,11 +7567,11 @@
/* Enable reading */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (0);
}
@@ -7392,10 +7585,10 @@
/* */
/****************************************************************************/
static int
-ips_program_bios_memio(ips_ha_t *ha, char *buffer, u_int32_t buffersize, u_int32_t offset) {
+ips_program_bios_memio(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
int i;
int timeout;
- u_int8_t status=0;
+ uint8_t status=0;
METHOD_TRACE("ips_program_bios_memio", 1);
@@ -7403,24 +7596,24 @@
for (i = 0; i < buffersize; i++) {
/* write a byte */
- writel(cpu_to_le32(i + offset), ha->mem_ptr + IPS_REG_FLAP);
+ writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
/* wait up to one second */
timeout = 1000;
while (timeout > 0) {
if (ha->revision_id == IPS_REVID_TROMBONE64) {
writel(0, ha->mem_ptr + IPS_REG_FLAP);
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
}
status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -7436,11 +7629,11 @@
/* timeout error */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (1);
}
@@ -7450,11 +7643,11 @@
/* programming error */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (1);
}
@@ -7463,11 +7656,11 @@
/* Enable reading */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
return (0);
}
@@ -7481,8 +7674,8 @@
/* */
/****************************************************************************/
static int
-ips_verify_bios(ips_ha_t *ha, char *buffer, u_int32_t buffersize, u_int32_t offset) {
- u_int8_t checksum;
+ips_verify_bios(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
+ uint8_t checksum;
int i;
METHOD_TRACE("ips_verify_bios", 1);
@@ -7490,14 +7683,14 @@
/* test 1st byte */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
return (1);
outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
return (1);
@@ -7506,9 +7699,9 @@
outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
- checksum = (u_int8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
+ checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
}
if (checksum != 0)
@@ -7528,8 +7721,8 @@
/* */
/****************************************************************************/
static int
-ips_verify_bios_memio(ips_ha_t *ha, char *buffer, u_int32_t buffersize, u_int32_t offset) {
- u_int8_t checksum;
+ips_verify_bios_memio(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
+ uint8_t checksum;
int i;
METHOD_TRACE("ips_verify_bios_memio", 1);
@@ -7537,25 +7730,25 @@
/* test 1st byte */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
return (1);
writel(1, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
return (1);
checksum = 0xff;
for (i = 2; i < buffersize; i++) {
- writel(cpu_to_le32(i + offset), ha->mem_ptr + IPS_REG_FLAP);
+ writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- udelay(5); /* 5 us */
+ udelay(25); /* 25 us */
- checksum = (u_int8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
+ checksum = (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
}
if (checksum != 0)
@@ -7566,11 +7759,589 @@
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 availaible. */
+/* */
+/*---------------------------------------------------------------------------*/
+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;
+
+ METHOD_TRACE("ips_version_check", 1);
+
+ 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 */
+ rc = ips_get_version_info(ha, &VersionInfo, 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)
+ {
+ /* if (ips_cd_boot == 0) */
+ /* printk(KERN_WARNING "Warning: Adapter %d Firmware Compatible Version is %s, but should be %s\n", */
+ /* ha->host_num, FirmwareVersion, Compatable[ ha->nvram->adapter_type ]); */
+ MatchError = 1;
+ }
+
+ if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
+ {
+ /* if (ips_cd_boot == 0) */
+ /* printk(KERN_WARNING "Warning: Adapter %d BIOS Compatible Version is %s, but should be %s\n", */
+ /* ha->host_num, BiosVersion, IPS_COMPAT_BIOS); */
+ MatchError = 1;
+ }
+
+ ha->nvram->versioning = 1; /* Indicate the Driver Supports Versioning */
+
+ if (MatchError)
+ {
+ ha->nvram->version_mismatch = 1;
+ /* if (ips_cd_boot == 0) */
+ /* printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n"); */
+ }
+ else
+ {
+ ha->nvram->version_mismatch = 0;
+ }
+
+ return;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Routine Name: ips_get_version_info */
+/* */
+/* Routine Description: */
+/* Issue an internal GETVERSION ServeRAID Command */
+/* */
+/* Return Value: */
+/* 0 if Successful, else non-zero */
+/*---------------------------------------------------------------------------*/
+static int ips_get_version_info(ips_ha_t *ha, IPS_VERSION_DATA *Buffer, int intr ) {
+ ips_scb_t *scb;
+ int rc;
+
+ METHOD_TRACE("ips_get_version_info", 1);
+
+ memset(Buffer, 0, sizeof(IPS_VERSION_DATA));
+ 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.buffer_addr = cpu_to_le32(VIRT_TO_BUS(Buffer));
+ scb->cmd.version_info.reserved2 = 0;
+
+ /* issue command */
+ rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
+ return( rc );
+}
+
+
+
#if defined (MODULE) || (LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0))
static Scsi_Host_Template driver_template = IPS;
#include "scsi_module.c"
#endif
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+
+/*---------------------------------------------------------------------------*/
+/* Routine Name: ips_remove_device */
+/* */
+/* Routine Description: */
+/* Remove one Adapter ( Hot Plugging ) */
+/*---------------------------------------------------------------------------*/
+static void __devexit ips_remove_device(struct pci_dev *pci_dev)
+{
+ int i;
+ struct Scsi_Host *sh;
+ ips_ha_t *ha;
+
+ for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
+ ha = ips_ha[i];
+ if (ha) {
+ if ( (pci_dev->bus->number == ha->pcidev->bus->number) &&
+ (pci_dev->devfn == ha->pcidev->devfn)) {
+ sh = ips_sh[i];
+ ips_release(sh);
+ }
+ }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Routine Name: ips_insert_device */
+/* */
+/* Routine Description: */
+/* Add One Adapter ( Hot Plug ) */
+/* */
+/* Return Value: */
+/* 0 if Successful, else non-zero */
+/*---------------------------------------------------------------------------*/
+static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
+{
+ int index;
+ int rc;
+
+ METHOD_TRACE("ips_insert_device", 1);
+ if (pci_enable_device(pci_dev))
+ return -1;
+
+ rc = ips_init_phase1(pci_dev, &index);
+ if (rc == SUCCESS)
+ rc = ips_init_phase2(index);
+
+ if (rc == SUCCESS)
+ ips_num_controllers++;
+
+ ips_next_controller = ips_num_controllers;
+ return rc;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Routine Name: ips_init_phase1 */
+/* */
+/* Routine Description: */
+/* Adapter Initialization */
+/* */
+/* Return Value: */
+/* 0 if Successful, else non-zero */
+/*---------------------------------------------------------------------------*/
+static int ips_init_phase1( struct pci_dev *pci_dev, int *indexPtr )
+{
+ struct Scsi_Host *sh;
+ ips_ha_t *ha;
+ uint32_t io_addr;
+ uint32_t mem_addr;
+ uint32_t io_len;
+ uint32_t mem_len;
+ uint8_t revision_id;
+ uint8_t bus;
+ uint8_t func;
+ uint8_t irq;
+ uint16_t subdevice_id;
+ int j;
+ int index;
+ uint32_t count;
+ char *ioremap_ptr;
+ char *mem_ptr;
+
+ METHOD_TRACE("ips_init_phase1", 1);
+ index = IPS_MAX_ADAPTERS;
+ for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
+ if (ips_ha[j] ==0) {
+ index = j;
+ break;
+ }
+ }
+
+ if (index >= IPS_MAX_ADAPTERS)
+ return -1;
+
+ /* stuff that we get in dev */
+ irq = pci_dev->irq;
+ bus = pci_dev->bus->number;
+ func = pci_dev->devfn;
+
+ /* Init MEM/IO addresses to 0 */
+ mem_addr = 0;
+ io_addr = 0;
+ mem_len = 0;
+ io_len = 0;
+
+ for (j = 0; j < 2; j++) {
+ if (!pci_resource_start(pci_dev, j))
+ break;
+
+ if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
+ io_addr = pci_resource_start(pci_dev, j);
+ io_len = pci_resource_len(pci_dev, j);
+ } else {
+ mem_addr = pci_resource_start(pci_dev, j);
+ mem_len = pci_resource_len(pci_dev, j);
+ }
+ }
+
+ /* setup memory mapped area (if applicable) */
+ if (mem_addr) {
+ uint32_t base;
+ uint32_t offs;
+
+ if (check_mem_region(mem_addr, mem_len)) {
+ printk(KERN_WARNING "Couldn't allocate IO Memory space %x len %d.\n", mem_addr, mem_len);
+ return -1;
+ }
+
+ request_mem_region(mem_addr, mem_len, "ips");
+ base = mem_addr & PAGE_MASK;
+ offs = mem_addr - base;
+ ioremap_ptr = ioremap(base, PAGE_SIZE);
+ mem_ptr = ioremap_ptr + offs;
+ } else {
+ ioremap_ptr = NULL;
+ mem_ptr = NULL;
+ }
+
+ /* setup I/O mapped area (if applicable) */
+ if (io_addr) {
+ if (check_region(io_addr, io_len)) {
+ printk(KERN_WARNING "Couldn't allocate IO space %x len %d.\n", io_addr, io_len);
+ return -1;
+ }
+ request_region(io_addr, io_len, "ips");
+ }
+
+ /* get the revision ID */
+ if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
+ printk(KERN_WARNING "Can't get revision id.\n" );
+ return -1;
+ }
+
+ subdevice_id = pci_dev->subsystem_device;
+
+ /* found a controller */
+ sh = scsi_register(&driver_template, sizeof(ips_ha_t));
+ if (sh == NULL) {
+ printk(KERN_WARNING "Unable to register controller with SCSI subsystem\n" );
+ return -1;
+ }
+
+ ha = IPS_HA(sh);
+ memset(ha, 0, sizeof(ips_ha_t));
+
+ /* Initialize spin lock */
+ spin_lock_init(&ha->scb_lock);
+ spin_lock_init(&ha->copp_lock); spin_lock_init(&ha->ips_lock);
+ spin_lock_init(&ha->copp_waitlist.lock);
+ spin_lock_init(&ha->scb_waitlist.lock);
+ spin_lock_init(&ha->scb_activelist.lock);
+
+ ips_sh[index] = sh;
+ ips_ha[index] = ha;
+ ha->active = 1;
+
+ ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL);
+
+ if (!ha->enq) {
+ printk(KERN_WARNING "Unable to allocate host inquiry structure\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_KERNEL);
+
+ if (!ha->adapt) {
+ printk(KERN_WARNING "Unable to allocate host adapt structure\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL);
+
+ if (!ha->conf) {
+ printk(KERN_WARNING "Unable to allocate host conf structure\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
+
+ if (!ha->nvram) {
+ printk(KERN_WARNING "Unable to allocate host NVRAM structure\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
+
+ if (!ha->subsys) {
+ printk(KERN_WARNING "Unable to allocate host subsystem structure\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_KERNEL);
+
+ if (!ha->dummy) {
+ printk(KERN_WARNING "Unable to allocate host dummy structure\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ for (count = PAGE_SIZE, ha->ioctl_order = 0;
+ count < ips_ioctlsize;
+ ha->ioctl_order++, count <<= 1);
+
+ ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order);
+ ha->ioctl_datasize = count;
+
+ if (!ha->ioctl_data) {
+ printk(KERN_WARNING "Unable to allocate IOCTL data\n" );
+ ha->ioctl_data = NULL;
+ ha->ioctl_order = 0;
+ ha->ioctl_datasize = 0;
+ }
+
+ /* Store away needed values for later use */
+ sh->io_port = io_addr;
+ sh->n_io_port = io_addr ? 255 : 0;
+ sh->unique_id = (io_addr) ? io_addr : mem_addr;
+ sh->irq = irq;
+ sh->select_queue_depths = ips_select_queue_depth;
+ sh->sg_tablesize = sh->hostt->sg_tablesize;
+ sh->can_queue = sh->hostt->can_queue;
+ sh->cmd_per_lun = sh->hostt->cmd_per_lun;
+ sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
+ sh->use_clustering = sh->hostt->use_clustering;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+ sh->max_sectors = 128;
+#endif
+
+ /* Store info in HA structure */
+ ha->irq = irq;
+ ha->io_addr = io_addr;
+ ha->io_len = io_len;
+ ha->mem_addr = mem_addr;
+ ha->mem_len = mem_len;
+ ha->mem_ptr = mem_ptr;
+ ha->ioremap_ptr = ioremap_ptr;
+ ha->host_num = ( uint32_t) index;
+ ha->revision_id = revision_id;
+ ha->slot_num = PCI_SLOT(pci_dev->devfn);
+ ha->device_id = pci_dev->device;
+ ha->subdevice_id = subdevice_id;
+ ha->pcidev = pci_dev;
+
+ /*
+ * Setup Functions
+ */
+ if (IPS_IS_MORPHEUS(ha)) {
+ /* morpheus */
+ 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;
+ }
+
+ /*
+ * Initialize the card if it isn't already
+ */
+
+ if (!(*ha->func.isinit)(ha)) {
+ if (!(*ha->func.init)(ha)) {
+ /*
+ * Initialization failed
+ */
+ printk(KERN_WARNING "Unable to initialize controller\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+ }
+
+ /* Install the interrupt handler */
+ if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+ printk(KERN_WARNING "Unable to install interrupt handler\n" );
+ ha->active = 0;
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ /*
+ * Allocate a temporary SCB for initialization
+ */
+ ha->max_cmds = 1;
+ if (!ips_allocatescbs(ha)) {
+ printk(KERN_WARNING "Unable to allocate a CCB\n" );
+ ha->active = 0;
+ free_irq(ha->irq, ha);
+ ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[index] = 0;
+ ips_sh[index] = 0;
+ return -1;
+ }
+
+ *indexPtr = index;
+ return SUCCESS;
+}
+
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Routine Name: ips_init_phase2 */
+/* */
+/* Routine Description: */
+/* Adapter Initialization Phase 2 */
+/* */
+/* Return Value: */
+/* 0 if Successful, else non-zero */
+/*---------------------------------------------------------------------------*/
+static int ips_init_phase2( int index )
+{
+ struct Scsi_Host *sh;
+ ips_ha_t *ha;
+
+ ha = ips_ha[index];
+ sh = ips_sh[index];
+
+ METHOD_TRACE("ips_init_phase2", 1);
+ if (!ha->active) {
+ scsi_unregister(sh);
+ ips_ha[index] = NULL;
+ ips_sh[index] = NULL;
+ return -1;;
+ }
+
+ if (!ips_hainit(ha)) {
+ printk(KERN_WARNING "Unable to initialize controller\n" );
+ ha->active = 0;
+ ips_free(ha);
+ free_irq(ha->irq, ha);
+ scsi_unregister(sh);
+ ips_ha[index] = NULL;
+ ips_sh[index] = NULL;
+ return -1;
+ }
+ /* Free the temporary SCB */
+ ips_deallocatescbs(ha, 1);
+
+ /* allocate CCBs */
+ if (!ips_allocatescbs(ha)) {
+ printk(KERN_WARNING "Unable to allocate CCBs\n" );
+ ha->active = 0;
+ ips_free(ha);
+ free_irq(ha->irq, ha);
+ scsi_unregister(sh);
+ ips_ha[index] = NULL;
+ ips_sh[index] = NULL;
+ return -1;
+ }
+
+ /* finish setting values */
+ sh->max_id = ha->ntargets;
+ sh->max_lun = ha->nlun;
+ sh->max_channel = ha->nbus - 1;
+ sh->can_queue = ha->max_cmds-1;
+
+ return SUCCESS;
+}
+
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,9)
+MODULE_LICENSE("GPL");
+#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
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)