patch-2.4.5 linux/drivers/scsi/ips.c
Next file: linux/drivers/scsi/ips.h
Previous file: linux/drivers/scsi/ibmmca.c
Back to the patch index
Back to the overall index
- Lines: 2310
- Date:
Sat May 19 17:43:06 2001
- Orig file:
v2.4.4/linux/drivers/scsi/ips.c
- Orig date:
Fri Apr 27 13:59:18 2001
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c
@@ -86,6 +86,20 @@
/* Merge in changes through kernel 2.4.0test1ac21 */
/* 4.20.13 - Fix some failure cases / reset code */
/* - Hook into the reboot_notifier to flush the controller cache */
+/* 4.50.01 - Fix problem when there is a hole in logical drive numbering */
+/* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */
+/* - Add IPSSEND Flash Support */
+/* - Set Sense Data for Unknown SCSI Command */
+/* - Use Slot Number from NVRAM Page 5 */
+/* - Restore caller's DCDB Structure */
+/* 4.70.12 - Corrective actions for bad controller ( during initialization )*/
+/* 4.70.13 - Don't Send CDB's if we already know the device is not present */
+/* - Don't release HA Lock in ips_next() until SC taken off queue */
+/* - Unregister SCSI device in ips_release() */
+/* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */
+/* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */
+/* Code Clean-Up for 2.4.x kernel */
+/* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */
/* */
/*****************************************************************************/
@@ -110,10 +124,8 @@
* 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
*/
-
-
-#include <linux/module.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -122,7 +134,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
+#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -130,6 +142,8 @@
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/reboot.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
#include <linux/blk.h>
#include <linux/types.h>
@@ -143,6 +157,8 @@
#include "hosts.h"
#include "ips.h"
+#include <linux/module.h>
+
#include <linux/stat.h>
#include <linux/config.h>
@@ -166,8 +182,9 @@
/*
* DRIVER_VER
*/
-#define IPS_VERSION_HIGH "4.20"
-#define IPS_VERSION_LOW ".20 "
+#define IPS_VERSION_HIGH "4.72"
+#define IPS_VERSION_LOW ".00 "
+
#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
struct proc_dir_entry proc_scsi_ips = {
@@ -214,6 +231,10 @@
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 */
@@ -224,7 +245,7 @@
*/
static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
-#define MAX_ADAPTER_NAME 9
+#define MAX_ADAPTER_NAME 11
static char ips_adapter_name[][30] = {
"ServeRAID",
@@ -235,7 +256,9 @@
"ServeRAID 3L",
"ServeRAID 4H",
"ServeRAID 4M",
- "ServeRAID 4L"
+ "ServeRAID 4L",
+ "ServeRAID 4Mx",
+ "ServeRAID 4Lx"
};
static struct notifier_block ips_notifier = {
@@ -347,6 +370,12 @@
static u32 ips_statupd_copperhead(ips_ha_t *);
static u32 ips_statupd_copperhead_memio(ips_ha_t *);
static u32 ips_statupd_morpheus(ips_ha_t *);
+static void ips_flash_bios_section(void *);
+static void ips_flash_bios_segment(void *);
+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 *);
static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
static void ips_enable_int_copperhead(ips_ha_t *);
@@ -380,15 +409,15 @@
static inline ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *);
static inline ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t *);
static int ips_erase_bios(ips_ha_t *);
-static int ips_program_bios(ips_ha_t *, char *, int);
-static int ips_verify_bios(ips_ha_t *, char *, int);
+static int ips_program_bios(ips_ha_t *, char *, u32, u32);
+static int ips_verify_bios(ips_ha_t *, char *, u32, u32);
static int ips_erase_bios_memio(ips_ha_t *);
-static int ips_program_bios_memio(ips_ha_t *, char *, int);
-static int ips_verify_bios_memio(ips_ha_t *, char *, int);
+static int ips_program_bios_memio(ips_ha_t *, char *, u32, u32);
+static int ips_verify_bios_memio(ips_ha_t *, char *, u32, u32);
#ifndef NO_IPS_CMDLINE
static int ips_is_passthru(Scsi_Cmnd *);
-static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *);
+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 *);
@@ -432,6 +461,8 @@
{"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);
@@ -498,8 +529,10 @@
u8 func;
u8 irq;
u16 deviceID[2];
+ u16 subdevice_id;
int i;
int j;
+ u32 count;
char *ioremap_ptr;
char *mem_ptr;
struct pci_dev *dev[2];
@@ -522,6 +555,16 @@
#endif
#endif
+ /* If Booting from the ServeRAID Manager CD, Allocate a large Flash */
+ /* Buffer ( so we won't need to allocate one for each adapter ). */
+ if ( ips_cd_boot ) {
+ ips_FlashData = ( char * ) __get_free_pages( GFP_KERNEL, 7 );
+ if (ips_FlashData == NULL) {
+ /* The validity of this pointer is checked in ips_make_passthru() before it is used */
+ printk( KERN_WARNING "ERROR: Can't Allocate Large Buffer for Flashing\n" );
+ }
+ }
+
SHT->proc_info = ips_proc_info;
#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
SHT->proc_dir = &proc_scsi_ips;
@@ -530,53 +573,53 @@
#endif
#if defined(CONFIG_PCI)
-
+
/* initalize number of controllers */
ips_num_controllers = 0;
ips_next_controller = 0;
ips_released_controllers = 0;
-
+
if (!pci_present())
return (0);
- morpheus = pci_find_device(IPS_VENDORID, IPS_MORPHEUS_DEVICEID, morpheus);
- trombone = pci_find_device(IPS_VENDORID, IPS_COPPERHEAD_DEVICEID, trombone);
-
+ morpheus = pci_find_device(IPS_VENDORID, IPS_DEVICEID_MORPHEUS, morpheus);
+ trombone = pci_find_device(IPS_VENDORID, IPS_DEVICEID_COPPERHEAD, trombone);
+
/* determine which controller to probe first */
if (!morpheus) {
/* we only have trombone */
dev[0] = trombone;
dev[1] = NULL;
- deviceID[0] = IPS_COPPERHEAD_DEVICEID;
+ deviceID[0] = IPS_DEVICEID_COPPERHEAD;
} else if (!trombone) {
/* we only have morpheus */
dev[0] = morpheus;
dev[1] = NULL;
- deviceID[0] = IPS_MORPHEUS_DEVICEID;
+ deviceID[0] = IPS_DEVICEID_MORPHEUS;
} else {
/* we have both in the system */
if (trombone->bus < morpheus->bus) {
dev[0] = trombone;
dev[1] = morpheus;
- deviceID[0] = IPS_COPPERHEAD_DEVICEID;
- deviceID[1] = IPS_MORPHEUS_DEVICEID;
+ deviceID[0] = IPS_DEVICEID_COPPERHEAD;
+ deviceID[1] = IPS_DEVICEID_MORPHEUS;
} else if (trombone->bus > morpheus->bus) {
dev[0] = morpheus;
dev[1] = trombone;
- deviceID[0] = IPS_MORPHEUS_DEVICEID;
- deviceID[1] = IPS_COPPERHEAD_DEVICEID;
+ deviceID[0] = IPS_DEVICEID_MORPHEUS;
+ deviceID[1] = IPS_DEVICEID_COPPERHEAD;
} else {
/* further detection required */
if (trombone->devfn < morpheus->devfn) {
dev[0] = trombone;
dev[1] = morpheus;
- deviceID[0] = IPS_COPPERHEAD_DEVICEID;
- deviceID[1] = IPS_MORPHEUS_DEVICEID;
+ deviceID[0] = IPS_DEVICEID_COPPERHEAD;
+ deviceID[1] = IPS_DEVICEID_MORPHEUS;
} else {
dev[0] = morpheus;
dev[1] = trombone;
- deviceID[0] = IPS_MORPHEUS_DEVICEID;
- deviceID[1] = IPS_COPPERHEAD_DEVICEID;
+ deviceID[0] = IPS_DEVICEID_MORPHEUS;
+ deviceID[1] = IPS_DEVICEID_COPPERHEAD;
}
}
}
@@ -711,14 +754,14 @@
/* get planer status */
if (pci_read_config_word(dev[i], 0x04, &planer)) {
- printk(KERN_WARNING "(%s%d) can't get planer status.\n",
+ printk(KERN_WARNING "(%s%d) can't get planer status.\n",
ips_name, ips_next_controller);
ips_next_controller++;
continue;
}
-
+
/* check to see if an onboard planer controller is disabled */
if (!(planer & 0x000C)) {
@@ -743,6 +786,20 @@
continue;
}
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,15)
+ /* get the subdevice id */
+ if (pci_read_config_word(dev[i], 0x2e, &subdevice_id)) {
+ printk(KERN_WARNING "(%s%d) can't get subdevice id.\n",
+ ips_name, ips_next_controller);
+
+ ips_next_controller++;
+
+ continue;
+ }
+#else
+ subdevice_id = dev[i]->subsystem_device;
+#endif
+
/* found a controller */
sh = scsi_register(SHT, sizeof(ips_ha_t));
@@ -771,7 +828,7 @@
ips_num_controllers++;
ha->active = 1;
- ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC|GFP_DMA);
+ ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC);
if (!ha->enq) {
printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
@@ -779,26 +836,33 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
continue;
}
- ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC|GFP_DMA);
+ ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC);
if (!ha->adapt) {
printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\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;
ips_next_controller++;
ips_num_controllers--;
continue;
}
- ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC|GFP_DMA);
+ ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC);
if (!ha->conf) {
printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
@@ -806,13 +870,16 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
continue;
}
- ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC|GFP_DMA);
+ ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC);
if (!ha->nvram) {
printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
@@ -820,13 +887,16 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
continue;
}
- ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC|GFP_DMA);
+ ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC);
if (!ha->subsys) {
printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
@@ -834,13 +904,16 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
continue;
}
- ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC|GFP_DMA);
+ ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC);
if (!ha->dummy) {
printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n",
@@ -848,24 +921,29 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
continue;
}
- ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_ATOMIC|GFP_DMA);
- ha->ioctl_datasize = IPS_IOCTL_SIZE;
+ 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 "(%s%d) Unable to allocate ioctl data - skipping controller\n",
+ printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data\n",
ips_name, ips_next_controller);
- ha->active = 0;
- ips_free(ha);
- ips_next_controller++;
- ips_num_controllers--;
-
- continue;
+ ha->ioctl_data = NULL;
+ ha->ioctl_order = 0;
+ ha->ioctl_datasize = 0;
}
/* Store away needed values for later use */
@@ -879,7 +957,11 @@
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;
- scsi_set_pci_device(sh, dev[i]);
+/***** Implement the following if it gets into a future kernel
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,4)
+ sh->max_sectors = 128;
+#endif
+******/
#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,32)
sh->wish_block = FALSE;
@@ -895,7 +977,9 @@
ha->ioremap_ptr = ioremap_ptr;
ha->host_num = ips_next_controller;
ha->revision_id = revision_id;
+ ha->slot_num = PCI_SLOT(dev[i]->devfn);
ha->device_id = deviceID[i];
+ ha->subdevice_id = subdevice_id;
ha->pcidev = dev[i];
/*
@@ -962,6 +1046,9 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
@@ -976,6 +1063,9 @@
ha->active = 0;
ips_free(ha);
+ scsi_unregister(sh);
+ ips_ha[ips_next_controller] = 0;
+ ips_sh[ips_next_controller] = 0;
ips_next_controller++;
ips_num_controllers--;
@@ -985,7 +1075,7 @@
/*
* Allocate a temporary SCB for initialization
*/
- ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
+ ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC);
if (!ha->scbs) {
/* couldn't allocate a temp SCB */
printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
@@ -993,6 +1083,9 @@
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--;
@@ -1001,7 +1094,7 @@
}
memset(ha->scbs, 0, sizeof(ips_scb_t));
- ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA);
+ ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC);
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",
@@ -1009,6 +1102,9 @@
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--;
@@ -1027,6 +1123,13 @@
* Controller init
*/
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);
+ continue;
+ }
+
ha = ips_ha[i];
sh = ips_sh[i];
@@ -1165,6 +1268,8 @@
/* free IRQ */
free_irq(ha->irq, ha);
+ scsi_unregister(sh);
+
ips_released_controllers++;
if (ips_num_controllers == ips_released_controllers)
@@ -1376,7 +1481,7 @@
if (!ret) {
Scsi_Cmnd *scsi_cmd;
- printk(KERN_NOTICE
+ printk(KERN_NOTICE
"(%s%d) Controller reset failed - controller now offline.\n",
ips_name, ha->host_num);
@@ -1408,7 +1513,7 @@
if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
Scsi_Cmnd *scsi_cmd;
- printk(KERN_NOTICE
+ printk(KERN_NOTICE
"(%s%d) Controller reset failed - controller now offline.\n",
ips_name, ha->host_num);
@@ -1622,17 +1727,29 @@
kern_area = ha->ioctl_data;
datasize = *((u32 *) &SC->cmnd[8]);
- if (copy_to_user(user_area, kern_area, datasize) > 0) {
- DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
- ips_name, ha->host_num);
+ if (datasize) {
+ if (copy_to_user(user_area, kern_area, datasize) > 0) {
+ DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
+ ips_name, ha->host_num);
- SC->result = DID_ERROR << 16;
- SC->scsi_done(SC);
+ SC->result = DID_ERROR << 16;
+ SC->scsi_done(SC);
+ } else {
+ SC->scsi_done(SC);
+ }
} else {
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;
+ ips_FlashDataInUse = 0;
+ }
+
return (0);
}
@@ -1718,6 +1835,9 @@
device->queue_depth = ha->max_cmds / count - 1;
else
device->queue_depth = 2;
+
+ if (device->queue_depth < 2)
+ device->queue_depth = 2;
}
}
}
@@ -1979,10 +2099,11 @@
/* Find our host structure */
for (i = 0; i < ips_next_controller; i++) {
- if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
- ha = (ips_ha_t *) ips_sh[i]->hostdata;
-
- break;
+ if (ips_sh[i]) {
+ if (ips_sh[i]->host_no == hostno) {
+ ha = (ips_ha_t *) ips_sh[i]->hostdata;
+ break;
+ }
}
}
@@ -2051,7 +2172,8 @@
/* */
/****************************************************************************/
static int
-ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb) {
+ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb, int intr) {
+ IPS_NVRAM_P5 nvram;
ips_passthru_t *pt;
METHOD_TRACE("ips_make_passthru", 1);
@@ -2128,19 +2250,375 @@
return (IPS_FAILURE);
}
+ if ((pt->CoppCP.cmd.nvram.op_code == IPS_CMD_RW_NVRAM_PAGE) &&
+ (pt->CoppCP.cmd.nvram.page == 5) &&
+ (pt->CoppCP.cmd.nvram.write == 0)) {
+
+ if (pt->CmdBSize < sizeof(IPS_NVRAM_P5)) {
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ ips_get_bios_version(ha, IPS_INTR_IORL);
+ ips_create_nvrampage5(ha, &nvram);
+
+ /* Copy the result back */
+ memcpy(SC->request_buffer + sizeof(ips_passthru_t), &nvram, sizeof(IPS_NVRAM_P5));
+
+ SC->result = DID_OK << 16;
+ pt->BasicStatus = 0x00;
+ pt->ExtendedStatus = 0x00;
+
+ return (IPS_SUCCESS_IMM);
+ }
+
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;
+ u32 datasize;
+
if (SC->request_bufflen < (sizeof(ips_passthru_t))) {
/* wrong size */
DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
ips_name, ha->host_num);
+ SC->result = DID_ERROR << 16;
+
return (IPS_FAILURE);
}
+
+ /* 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 ( (ips_FlashData) &&
+ (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->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 = *((u32 *) &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 = *((u32 *) &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 (IPS_FAILURE);
+ }
+
+ pt->BasicStatus = 0x00;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_OK << 16;
+
+ return (IPS_SUCCESS_IMM);
+ }
+
+ /*
+ * IPSSEND flashing BIOS
+ */
+ if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
+ (pt->CoppCP.cmd.flashfw.type == 1) &&
+ (pt->CoppCP.cmd.flashfw.direction == 2) &&
+ (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
+ struct tq_struct task;
+ IPS_FLASH_DATA flash_data;
+ DECLARE_MUTEX_LOCKED(sem);
+
+ /* We only support one packet */
+ if (pt->CoppCP.cmd.flashfw.total_packets != 1) {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ /* 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 > pt->CoppCP.cmd.flashfw.count) {
+ pt->CmdBSize = pt->CoppCP.cmd.flashfw.count;
+ } else {
+ /* ERROR: Command/Buffer mismatch */
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ if ((!ha->func.programbios) ||
+ (!ha->func.erasebios) ||
+ (!ha->func.verifybios)) {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ /* must have a buffer */
+ if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ /* make sure buffer is big enough */
+ if (pt->CmdBSize > ha->ioctl_datasize) {
+ void *bigger_struct;
+ u32 count;
+ u32 order;
+
+ /* try to allocate a bigger struct */
+ for (count = PAGE_SIZE, order = 0;
+ count < pt->CmdBSize;
+ order++, count <<= 1);
+
+ bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
+ if (bigger_struct) {
+ /* free the old memory */
+ free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
+
+ /* use the new memory */
+ ha->ioctl_data = (char *) bigger_struct;
+ ha->ioctl_order = order;
+ ha->ioctl_datasize = count;
+ } else {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ spin_unlock(&ha->ips_lock);
+
+ return (IPS_FAILURE);
+ }
+ }
+
+ /* copy in the buffer */
+ if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
+ ips_name, ha->host_num);
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ flash_data.userbuffer = pt->CmdBuffer;
+ flash_data.usersize = pt->CmdBSize;
+ flash_data.kernbuffer = ha->ioctl_data;
+ flash_data.kernsize = ha->ioctl_datasize;
+ flash_data.offset = 0;
+ flash_data.SC = (void *) SC;
+ flash_data.pt = (void *) pt;
+ flash_data.ha = (void *) ha;
+ flash_data.sem = &sem;
+
+ task.sync = 0;
+ task.routine = ips_scheduled_flash_bios;
+ task.data = (void *) &flash_data;
+
+ /* Unlock the master lock */
+ spin_unlock_irq(&io_request_lock);
+
+ queue_task(&task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ /* Wait for the flash to complete */
+ down(&sem);
+
+ /* Obtain the master lock */
+ spin_lock_irq(&io_request_lock);
+
+ return (flash_data.retcode);
+ }
+
+ /*
+ * IPSSEND flashing BIOS in sectioned mode
+ */
+ if ((pt->CoppCP.cmd.flashbios.op_code == IPS_CMD_RW_BIOSFW) &&
+ (pt->CoppCP.cmd.flashbios.type == 1) &&
+ (pt->CoppCP.cmd.flashbios.direction == 4) &&
+ (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
+ struct tq_struct task;
+ IPS_FLASH_DATA flash_data;
+ DECLARE_MUTEX_LOCKED(sem);
+
+ /* 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 > pt->CoppCP.cmd.flashbios.count) {
+ pt->CmdBSize = pt->CoppCP.cmd.flashbios.count;
+ } else {
+ /* ERROR: Command/Buffer mismatch */
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ /* Update the Card BIOS */
+ if ((!ha->func.programbios) ||
+ (!ha->func.erasebios) ||
+ (!ha->func.verifybios)) {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ /* must have a buffer */
+ if ((!pt->CmdBSize) || (!pt->CmdBuffer)) {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ /* make sure buffer is big enough */
+ if (pt->CmdBSize > ha->ioctl_datasize) {
+ void *bigger_struct;
+ u32 count;
+ u32 order;
+
+ /* try to allocate a bigger struct */
+ for (count = PAGE_SIZE, order = 0;
+ count < pt->CmdBSize;
+ order++, count <<= 1);
+
+ bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
+ if (bigger_struct) {
+ /* free the old memory */
+ free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
+
+ /* use the new memory */
+ ha->ioctl_data = (char *) bigger_struct;
+ ha->ioctl_order = order;
+ ha->ioctl_datasize = count;
+ } else {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ spin_unlock(&ha->ips_lock);
+
+ return (IPS_FAILURE);
+ }
+ }
+
+ /* copy in the buffer */
+ if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
+ ips_name, ha->host_num);
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ flash_data.userbuffer = pt->CmdBuffer;
+ flash_data.usersize = pt->CmdBSize;
+ flash_data.kernbuffer = ha->ioctl_data;
+ flash_data.kernsize = ha->ioctl_datasize;
+ flash_data.offset = pt->CoppCP.cmd.flashbios.offset;
+ flash_data.SC = (void *) SC;
+ flash_data.pt = (void *) pt;
+ flash_data.ha = (void *) ha;
+ flash_data.sem = &sem;
+
+ task.sync = 0;
+ task.routine = ips_flash_bios_section;
+ task.data = (void *) &flash_data;
+
+ /* Unlock the master lock */
+ spin_unlock_irq(&io_request_lock);
+
+ queue_task(&task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ /* Wait for the flash to complete */
+ down(&sem);
+
+ /* Obtain the master lock */
+ spin_lock_irq(&io_request_lock);
+
+ return (flash_data.retcode);
+ }
+
+ if ((pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) &&
+ (pt->CoppCP.cmd.flashfw.type == 1) &&
+ (pt->CoppCP.cmd.flashfw.direction == 3) &&
+ (ha->device_id == IPS_DEVICEID_COPPERHEAD)) {
+ /* Erase the Card BIOS */
+ if (!ha->func.erasebios) {
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ if ((*ha->func.erasebios)(ha)) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+ ips_name, ha->host_num);
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+
+ return (IPS_FAILURE);
+ }
+
+ SC->result = DID_OK << 16;
+ pt->BasicStatus = 0x00;
+ pt->ExtendedStatus = 0x00;
+
+ return (IPS_SUCCESS_IMM);
+ }
+
if (ips_newusrcmd(ha, pt, scb))
return (IPS_SUCCESS);
else
@@ -2149,87 +2627,152 @@
break;
- case IPS_FLASHBIOS:
- /* we must use the new interface */
- if (SC->cmnd[0] != IPS_IOCTL_NEW_COMMAND)
- return (IPS_FAILURE);
+ } /* end switch */
- /* don't flash the BIOS on future cards */
- if ((ha->device_id != IPS_COPPERHEAD_DEVICEID) ||
- (ha->revision_id > IPS_REVID_TROMBONE64)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unsupported controller",
- ips_name, ha->host_num);
+ return (IPS_FAILURE);
+}
- return (IPS_FAILURE);
- }
+/****************************************************************************/
+/* */
+/* Routine Name: ips_scheduled_flash_bios */
+/* */
+/* Routine Description: */
+/* */
+/* Flash the BIOS on a Copperhead style controller */
+/* To be called from a task queue */
+/* */
+/****************************************************************************/
+static void
+ips_scheduled_flash_bios(void *data) {
+ ips_ha_t *ha;
+ Scsi_Cmnd *SC;
+ ips_passthru_t *pt;
+ IPS_FLASH_DATA *fd;
- /*
- * Check to make sure we have functions
- * to handle the request
- */
- if ((!ha->func.programbios) ||
- (!ha->func.erasebios) ||
- (!ha->func.verifybios))
- return (IPS_FAILURE);
+ fd = (IPS_FLASH_DATA *) data;
+ ha = (ips_ha_t *) fd->ha;
+ pt = (ips_passthru_t *) fd->pt;
+ SC = (Scsi_Cmnd *) fd->SC;
- /* copy in the size/buffer ptr from the scsi command */
- memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
- memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
+ /*
+ * Set initial return codes
+ */
+ SC->result = DID_OK << 16;
+ pt->BasicStatus = 0x00;
+ pt->ExtendedStatus = 0x00;
+ fd->retcode = IPS_SUCCESS_IMM;
- /* must have a buffer */
- if ((!pt->CmdBSize) || (!pt->CmdBuffer))
- return (IPS_FAILURE);
+ /*
+ * Fix the size/ptr to account for the
+ * flash header
+ */
+ fd->kernbuffer += 0xC0;
+ fd->kernsize -= 0xC0;
+ fd->userbuffer += 0xC0;
+ fd->usersize -= 0xC0;
- /* make sure buffer is big enough */
- if (pt->CmdBSize > ha->ioctl_datasize) {
- void *bigger_struct;
+ if ((*ha->func.erasebios)(ha)) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+ ips_name, ha->host_num);
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+ fd->retcode = IPS_FAILURE;
+ up(fd->sem);
- /* try to allocate a bigger struct */
- bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA);
- if (bigger_struct) {
- /* free the old memory */
- kfree(ha->ioctl_data);
+ return ;
+ }
- /* use the new memory */
- ha->ioctl_data = bigger_struct;
- ha->ioctl_datasize = pt->CmdBSize;
- } else
- return (IPS_FAILURE);
- }
+ ips_flash_bios_segment(data);
- /* copy in the buffer */
- if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
- ips_name, ha->host_num);
+ if (fd->retcode == IPS_FAILURE)
+ return ;
- return (IPS_FAILURE);
- }
+ if ((*ha->func.verifybios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
+ ips_name, ha->host_num);
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+ fd->retcode = IPS_FAILURE;
+ up(fd->sem);
- if ((*ha->func.erasebios)(ha)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
- ips_name, ha->host_num);
+ return ;
+ }
- return (IPS_FAILURE);
- }
+ /* Tell them we are done */
+ if (fd->retcode != IPS_FAILURE)
+ up(fd->sem);
+}
- if ((*ha->func.programbios)(ha, ha->ioctl_data, pt->CmdBSize)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
- ips_name, ha->host_num);
+/****************************************************************************/
+/* */
+/* Routine Name: ips_flash_bios_section */
+/* */
+/* Routine Description: */
+/* */
+/* wrapper for ips_flash_bios_segment that raises the semaphore */
+/* */
+/****************************************************************************/
+static void
+ips_flash_bios_section(void *data) {
+ ips_ha_t *ha;
+ Scsi_Cmnd *SC;
+ ips_passthru_t *pt;
+ IPS_FLASH_DATA *fd;
- return (IPS_FAILURE);
- }
+ fd = (IPS_FLASH_DATA *) data;
+ ha = (ips_ha_t *) fd->ha;
+ pt = (ips_passthru_t *) fd->pt;
+ SC = (Scsi_Cmnd *) fd->SC;
- if ((*ha->func.verifybios)(ha, ha->ioctl_data, pt->CmdBSize)) {
- DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
- ips_name, ha->host_num);
+ /*
+ * Set initial return codes
+ */
+ SC->result = DID_OK << 16;
+ pt->BasicStatus = 0x00;
+ pt->ExtendedStatus = 0x00;
+ fd->retcode = IPS_SUCCESS_IMM;
- return (IPS_FAILURE);
- }
+ ips_flash_bios_segment(data);
- return (IPS_SUCCESS_IMM);
- } /* end switch */
+ if (fd->retcode != IPS_FAILURE)
+ up(fd->sem);
+}
- return (IPS_FAILURE);
+/****************************************************************************/
+/* */
+/* Routine Name: ips_flash_bios_segment */
+/* */
+/* Routine Description: */
+/* */
+/* Flash a portion of the BIOS on a Copperhead style controller */
+/* To be called from a task queue */
+/* */
+/****************************************************************************/
+static void
+ips_flash_bios_segment(void *data) {
+ ips_ha_t *ha;
+ Scsi_Cmnd *SC;
+ ips_passthru_t *pt;
+ IPS_FLASH_DATA *fd;
+
+ fd = (IPS_FLASH_DATA *) data;
+ ha = (ips_ha_t *) fd->ha;
+ pt = (ips_passthru_t *) fd->pt;
+ SC = (Scsi_Cmnd *) fd->SC;
+
+ if ((*ha->func.programbios)(ha, fd->kernbuffer, fd->usersize, fd->offset)) {
+ DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
+ ips_name, ha->host_num);
+ pt->BasicStatus = 0x0B;
+ pt->ExtendedStatus = 0x00;
+ SC->result = DID_ERROR << 16;
+ fd->retcode = IPS_FAILURE;
+ up(fd->sem);
+
+ return ;
+ }
}
/****************************************************************************/
@@ -2363,16 +2906,23 @@
if (pt->CmdBSize) {
if (pt->CmdBSize > ha->ioctl_datasize) {
void *bigger_struct;
+ u32 count;
+ u32 order;
/* try to allocate a bigger struct */
- bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA);
+ for (count = PAGE_SIZE, order = 0;
+ count < pt->CmdBSize;
+ order++, count <<= 1);
+
+ bigger_struct = (void *) __get_free_pages(GFP_ATOMIC, order);
if (bigger_struct) {
/* free the old memory */
- kfree(ha->ioctl_data);
+ free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
/* use the new memory */
- ha->ioctl_data = bigger_struct;
- ha->ioctl_datasize = pt->CmdBSize;
+ ha->ioctl_data = (char *) bigger_struct;
+ ha->ioctl_order = order;
+ ha->ioctl_datasize = count;
} else
return (0);
@@ -2450,6 +3000,10 @@
pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer;
/* Copy data back to the user */
+ if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) { /* Copy DCDB Back to Caller's Area */
+ memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof(IPS_DCDB_TABLE));
+ }
+
if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_COMMAND) {
/* Copy data back to the user */
pt->BasicStatus = scb->basic_status;
@@ -2606,6 +3160,253 @@
/****************************************************************************/
/* */
+/* Routine Name: ips_identify_controller */
+/* */
+/* Routine Description: */
+/* */
+/* Identify this controller */
+/* */
+/****************************************************************************/
+static void
+ips_identify_controller(ips_ha_t *ha) {
+ METHOD_TRACE("ips_identify_controller", 1);
+
+ switch (ha->device_id) {
+ case IPS_DEVICEID_COPPERHEAD:
+ if (ha->revision_id <= IPS_REVID_SERVERAID) {
+ ha->ad_type = IPS_ADTYPE_SERVERAID;
+ } else if (ha->revision_id == IPS_REVID_SERVERAID2) {
+ ha->ad_type = IPS_ADTYPE_SERVERAID2;
+ } else if (ha->revision_id == IPS_REVID_NAVAJO) {
+ ha->ad_type = IPS_ADTYPE_NAVAJO;
+ } else if ((ha->revision_id == IPS_REVID_SERVERAID2) && (ha->slot_num == 0)) {
+ ha->ad_type = IPS_ADTYPE_KIOWA;
+ } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
+ (ha->revision_id <= IPS_REVID_CLARINETP3)) {
+ if (ha->enq->ucMaxPhysicalDevices == 15)
+ ha->ad_type = IPS_ADTYPE_SERVERAID3L;
+ else
+ ha->ad_type = IPS_ADTYPE_SERVERAID3;
+ } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
+ (ha->revision_id <= IPS_REVID_TROMBONE64)) {
+ ha->ad_type = IPS_ADTYPE_SERVERAID4H;
+ }
+ break;
+
+ case IPS_DEVICEID_MORPHEUS:
+ switch (ha->subdevice_id) {
+ case IPS_SUBDEVICEID_4L:
+ ha->ad_type = IPS_ADTYPE_SERVERAID4L;
+ break;
+
+ case IPS_SUBDEVICEID_4M:
+ ha->ad_type = IPS_ADTYPE_SERVERAID4M;
+ break;
+
+ case IPS_SUBDEVICEID_4MX:
+ ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
+ break;
+
+ case IPS_SUBDEVICEID_4LX:
+ ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
+ break;
+ }
+
+ break;
+ }
+}
+
+/****************************************************************************/
+/* */
+/* 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: */
+/* */
+/* Get the BIOS revision number */
+/* */
+/****************************************************************************/
+static void
+ips_get_bios_version(ips_ha_t *ha, int intr) {
+ ips_scb_t *scb;
+ int ret;
+ u8 major;
+ u8 minor;
+ u8 subminor;
+ u8 *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);
+
+ major = 0;
+ minor = 0;
+
+ strncpy(ha->bios_version, " ?", 8);
+
+ if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
+ if (IPS_USE_MEMIO(ha)) {
+ /* Memory Mapped I/O */
+
+ /* test 1st byte */
+ writel(0, ha->mem_ptr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+ return;
+
+ writel(1, ha->mem_ptr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+ return;
+
+ /* Get Major version */
+ writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ major = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+ /* Get Minor version */
+ writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ minor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+ /* Get Sub Minor version */
+ writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5);/* 5 us */
+
+ subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+
+ } else {
+ /* Programmed I/O */
+
+ /* test 1st byte */
+ outl(0, ha->io_addr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+ return ;
+
+ outl(1, ha->io_addr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+ return ;
+
+ /* Get Major version */
+ outl(0x1FF, ha->io_addr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ major = inb(ha->io_addr + IPS_REG_FLDP);
+
+ /* Get Minor version */
+ outl(0x1FE, ha->io_addr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ minor = inb(ha->io_addr + IPS_REG_FLDP);
+
+ /* Get SubMinor version */
+ outl(0x1FD, ha->io_addr + IPS_REG_FLAP);
+ if (ha->revision_id == IPS_REVID_TROMBONE64)
+ udelay(5); /* 5 us */
+
+ subminor = inb(ha->io_addr + IPS_REG_FLDP);
+
+ }
+ } else {
+ /* Morpheus Family - Send Command to the card */
+
+ buffer = kmalloc(0x1000, GFP_ATOMIC);
+ if (!buffer)
+ return;
+
+ memset(buffer, 0, 0x1000);
+
+ scb = &ha->scbs[ha->max_cmds-1];
+
+ ips_init_scb(ha, scb);
+
+ scb->timeout = ips_cmd_timeout;
+ scb->cdb[0] = IPS_CMD_RW_BIOSFW;
+
+ scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
+ scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+ scb->cmd.flashfw.type = 1;
+ scb->cmd.flashfw.direction = 0;
+ scb->cmd.flashfw.count = 0x800;
+ scb->cmd.flashfw.buffer_addr = VIRT_TO_BUS(buffer);
+ scb->cmd.flashfw.total_packets = 1;
+ scb->cmd.flashfw.packet_num = 0;
+
+ /* issue the command */
+ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
+ (ret == IPS_SUCCESS_IMM) ||
+ ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+ /* Error occurred */
+ kfree(buffer);
+
+ return;
+ }
+
+ if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
+ major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */
+ minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */
+ subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fe after the header (0xc0) */
+
+ } else {
+ return;
+ }
+
+ kfree(buffer);
+ }
+
+ ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
+ ha->bios_version[1] = '.';
+ ha->bios_version[2] = hexDigits[major & 0x0F];
+ ha->bios_version[3] = hexDigits[subminor];
+ ha->bios_version[4] = '.';
+ ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
+ ha->bios_version[6] = hexDigits[minor & 0x0F];
+ ha->bios_version[7] = 0;
+}
+
+/****************************************************************************/
+/* */
/* Routine Name: ips_hainit */
/* */
/* Routine Description: */
@@ -2651,6 +3452,9 @@
return (0);
}
+ /* Identify this controller */
+ ips_identify_controller(ha);
+
if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.\n",
ips_name, ha->host_num);
@@ -2799,30 +3603,47 @@
(scb = ips_getscb(ha))) {
IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
- IPS_HA_UNLOCK(cpu_flags);
item = ips_removeq_copp_head(&ha->copp_waitlist);
+ IPS_HA_UNLOCK(cpu_flags);
scb->scsi_cmd = item->scsi_cmd;
scb->sem = item->sem;
kfree(item);
- ret = ips_make_passthru(ha, scb->scsi_cmd, scb);
+ ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
switch (ret) {
case IPS_FAILURE:
if (scb->scsi_cmd) {
+ scb->scsi_cmd->result = DID_ERROR << 16;
+
/* raise the semaphore */
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
- up(scb->sem);
+ if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
+ u32 datasize;
- scb->scsi_cmd->result = DID_ERROR << 16;
+ datasize = 0;
+ memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
+ up(scb->sem);
+ } else {
+ scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+ }
}
+
ips_freescb(ha, scb);
break;
case IPS_SUCCESS_IMM:
if (scb->scsi_cmd) {
+ scb->scsi_cmd->result = DID_OK << 16;
+
/* raise the semaphore */
- if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND)
+ if (scb->scsi_cmd->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
+ u32 datasize;
+
+ datasize = 0;
+ memcpy(&scb->scsi_cmd->cmnd[8], &datasize, 4);
up(scb->sem);
+ } else {
+ scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+ }
}
ips_freescb(ha, scb);
@@ -2891,10 +3712,12 @@
continue;
}
- IPS_HA_UNLOCK(cpu_flags);
-
q = p;
SC = ips_removeq_wait(&ha->scb_waitlist, q);
+ if (SC == NULL) /* Should never happen, but good to check anyway */
+ continue;
+
+ IPS_HA_UNLOCK(cpu_flags); /* Unlock HA after command is taken off queue */
SC->result = DID_OK;
SC->host_scribble = NULL;
@@ -2932,27 +3755,37 @@
scb->data_busaddr = VIRT_TO_BUS(sg[0].address);
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 = VIRT_TO_BUS(sg[0].address);
+ 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 = VIRT_TO_BUS(sg[i].address);
+ scb->sg_list[i].length = sg[i].length;
+
+ if (scb->data_len + sg[i].length > ha->max_xfer) {
+ /*
+ * Data Breakup required
+ */
+ scb->breakup = i;
+ break;
+ }
- for (i = 0; i < SC->use_sg; i++) {
- scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
- scb->sg_list[i].length = sg[i].length;
-
- if (scb->data_len + sg[i].length > ha->max_xfer) {
- /*
- * Data Breakup required
- */
- scb->breakup = i;
- break;
+ scb->data_len += sg[i].length;
}
- scb->data_len += sg[i].length;
+ if (!scb->breakup)
+ scb->sg_len = SC->use_sg;
+ else
+ scb->sg_len = scb->breakup;
}
- if (!scb->breakup)
- scb->sg_len = SC->use_sg;
- else
- scb->sg_len = scb->breakup;
-
scb->dcdb.transfer_length = scb->data_len;
scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
}
@@ -3590,9 +4423,9 @@
* data and had to be broke up. If so, queue
* the rest of the data and continue.
*/
- if (scb->breakup) {
- /* we had a data breakup */
- u16 bk_save;
+ if (scb->breakup || scb->sg_break) {
+ /* We had a data breakup */
+ u8 bk_save;
bk_save = scb->breakup;
scb->breakup = 0;
@@ -3618,34 +4451,68 @@
scb->dcdb.transfer_length = scb->data_len;
scb->sg_len = 0;
} else {
- scb->data_len = 0;
-
- for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
- scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address);
- scb->sg_list[i - bk_save].length = sg[i].length;
-
- if (scb->data_len + sg[i].length > ha->max_xfer) {
- /*
- * Data Breakup required
- */
- scb->breakup = i;
- break;
+ /* We're here because there was MORE than one s/g unit. */
+ /* bk_save points to which sg unit to look at */
+ /* sg_break points to how far through this unit we are */
+ /* NOTE: We will not move from one sg to another here, */
+ /* just finish the one we are in. Not the most */
+ /* efficient, but it keeps it from getting too hacky */
+
+ /* IF sg_break is non-zero, then just work on this current sg piece, */
+ /* 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;
+ 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;;
+
+ if (sg[bk_save].length <= 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)
+ scb->breakup = 0;
+ 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 = 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;
+ /* 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 = VIRT_TO_BUS(sg[i].address);
+ scb->sg_list[i - bk_save].length = 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 */
+ }
+ }
+ }
- scb->data_len += sg[i].length;
- }
-
- if (!scb->breakup)
- scb->sg_len = scb->scsi_cmd->use_sg - bk_save;
- else
- scb->sg_len = scb->breakup - bk_save;
-
+ /* 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);
- }
- } else {
+ }
+ } else {
/* Non S/G Request */
- if (scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) {
+ 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));
@@ -3882,7 +4749,9 @@
static int
ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) {
int ret;
-
+ char *sp;
+ int device_error;
+
METHOD_TRACE("ips_send_cmd", 1);
ret = IPS_SUCCESS;
@@ -4068,7 +4937,20 @@
break;
default:
- scb->scsi_cmd->result = DID_ERROR << 16;
+ /* Set the Return Info to appear like the Command was */
+ /* attempted, a Check Condition occurred, and Sense */
+ /* Data indicating an Invalid CDB OpCode is returned. */
+ sp = (char *) scb->scsi_cmd->sense_buffer;
+ memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer));
+
+ sp[0] = 0x70; /* Error Code */
+ sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */
+ sp[7] = 0x0A; /* Additional Sense Length */
+ sp[12] = 0x20; /* ASC = Invalid OpCode */
+ sp[13] = 0x00; /* ASCQ */
+
+ device_error = 2; /* Indicate Check Condition */
+ scb->scsi_cmd->result = device_error | (DID_OK << 16);
break;
} /* end switch */
} /* end if */
@@ -4083,6 +4965,13 @@
else
scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
+ /* If we already know the Device is Not there, no need to attempt a Command */
+ /* This also protects an NT FailOver Controller from getting CDB's sent to it */
+ if ( ha->conf->dev[scb->bus-1][scb->target_id].ucState == 0 ) {
+ scb->scsi_cmd->result = DID_NO_CONNECT << 16;
+ return (IPS_SUCCESS_IMM);
+ }
+
ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
scb->cmd.dcdb.dcdb_address = VIRT_TO_BUS(&scb->dcdb);
@@ -4289,8 +5178,7 @@
return (0);
}
- if (scb->target_id < ha->adapt->logical_drive_info.no_of_log_drive &&
- ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE &&
+ if (ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE &&
ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_FREE &&
ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_CRS &&
ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_SYS)
@@ -4510,9 +5398,10 @@
}
if (ha->ioctl_data) {
- kfree(ha->ioctl_data);
+ free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
ha->ioctl_data = NULL;
ha->ioctl_datasize = 0;
+ ha->ioctl_order = 0;
}
if (ha->scbs) {
@@ -4552,9 +5441,10 @@
METHOD_TRACE("ips_allocatescbs", 1);
/* Allocate memory for the CCBs */
- ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
- if(ha->scbs == NULL)
- return 0;
+ ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC);
+ if (ha->scbs == NULL)
+ return 0;
+
memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
@@ -4562,7 +5452,7 @@
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|GFP_DMA);
+ scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC);
if (! scb_p->sg_list)
return (0);
@@ -4713,7 +5603,7 @@
/****************************************************************************/
static int
ips_isinit_copperhead_memio(ips_ha_t *ha) {
- u8 isr;
+ u8 isr=0;
u8 scpr;
METHOD_TRACE("ips_is_init_copperhead_memio", 1);
@@ -4903,7 +5793,7 @@
/****************************************************************************/
static int
ips_init_copperhead_memio(ips_ha_t *ha) {
- u8 Isr;
+ u8 Isr=0;
u8 Cbsp;
u8 PostByte[IPS_MAX_POST_BYTES];
u8 ConfigByte[IPS_MAX_CONFIG_BYTES];
@@ -5372,7 +6262,7 @@
TimeOut = 0;
while ((val = inw(ha->io_addr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
- UDELAY(1000);
+ udelay(1000);
if (++TimeOut >= IPS_SEM_TIMEOUT) {
if (!(val & IPS_BIT_START_STOP))
@@ -5435,7 +6325,7 @@
TimeOut = 0;
while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
- UDELAY(1000);
+ udelay(1000);
if (++TimeOut >= IPS_SEM_TIMEOUT) {
if (!(val & IPS_BIT_START_STOP))
@@ -5674,7 +6564,7 @@
*/
while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
- UDELAY(1000);
+ udelay(1000);
(*ha->func.intr)(ha);
@@ -5700,7 +6590,7 @@
spin_lock(&io_request_lock);
while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
- UDELAY(1000);
+ udelay(1000);
(*ha->func.intr)(ha);
@@ -5709,7 +6599,7 @@
spin_unlock(&io_request_lock);
}
- UDELAY(1000); /* 1 milisecond */
+ udelay(1000); /* 1 milisecond */
time--;
}
@@ -5752,9 +6642,6 @@
ha->nvram->bios_low[0], ha->nvram->bios_low[1],
ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
- /* save controller type */
- ha->ad_type = ha->nvram->adapter_type;
-
/* change values (as needed) */
ha->nvram->operating_system = IPS_OS_LINUX;
strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
@@ -5768,6 +6655,9 @@
return (0);
}
+ /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
+ ha->slot_num = ha->nvram->adapter_slot;
+
return (1);
}
@@ -6154,40 +7044,40 @@
static int
ips_erase_bios(ips_ha_t *ha) {
int timeout;
- u8 status;
+ u8 status=0;
METHOD_TRACE("ips_erase_bios", 1);
/* Clear the status register */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
outb(0x50, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* Erase Setup */
outb(0x20, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* Erase Confirm */
outb(0xD0, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* Erase Status */
outb(0x70, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 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(5); /* 5 us */
}
status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -6206,14 +7096,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(5); /* 5 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(5); /* 5 us */
}
status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -6242,12 +7132,12 @@
/* clear status */
outb(0x50, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* enable reads */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (0);
}
@@ -6270,33 +7160,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(5); /* 5 us */
writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* Erase Setup */
writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* Erase Confirm */
writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* Erase Status */
writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 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(5); /* 5 us */
}
status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -6315,14 +7205,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(5); /* 5 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(5); /* 5 us */
}
status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -6351,12 +7241,12 @@
/* clear status */
writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
/* enable reads */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (0);
}
@@ -6370,33 +7260,33 @@
/* */
/****************************************************************************/
static int
-ips_program_bios(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_program_bios(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
int i;
int timeout;
- u8 status;
+ u8 status=0;
METHOD_TRACE("ips_program_bios", 1);
for (i = 0; i < buffersize; i++) {
/* write a byte */
- outl(i, ha->io_addr + IPS_REG_FLAP);
+ outl(i + offset, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
outb(0x40, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 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(5); /* 5 us */
}
status = inb(ha->io_addr + IPS_REG_FLDP);
@@ -6412,11 +7302,11 @@
/* timeout error */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (1);
}
@@ -6426,11 +7316,11 @@
/* programming error */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (1);
}
@@ -6439,11 +7329,11 @@
/* Enable reading */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
outb(0xFF, ha->io_addr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (0);
}
@@ -6457,33 +7347,33 @@
/* */
/****************************************************************************/
static int
-ips_program_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_program_bios_memio(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
int i;
int timeout;
- u8 status;
+ u8 status=0;
METHOD_TRACE("ips_program_bios_memio", 1);
for (i = 0; i < buffersize; i++) {
/* write a byte */
- writel(i, 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(5); /* 5 us */
writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 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(5); /* 5 us */
}
status = readb(ha->mem_ptr + IPS_REG_FLDP);
@@ -6499,11 +7389,11 @@
/* timeout error */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (1);
}
@@ -6513,11 +7403,11 @@
/* programming error */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (1);
}
@@ -6526,11 +7416,11 @@
/* Enable reading */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
return (0);
}
@@ -6544,7 +7434,7 @@
/* */
/****************************************************************************/
static int
-ips_verify_bios(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_verify_bios(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
u8 checksum;
int i;
@@ -6553,23 +7443,23 @@
/* test 1st byte */
outl(0, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
return (1);
outl(1, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
return (1);
checksum = 0xff;
for (i = 2; i < buffersize; i++) {
- outl(i, ha->io_addr + IPS_REG_FLAP);
+ outl(i + offset, ha->io_addr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 us */
checksum = (u8) checksum + inb(ha->io_addr + IPS_REG_FLDP);
}
@@ -6591,7 +7481,7 @@
/* */
/****************************************************************************/
static int
-ips_verify_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) {
+ips_verify_bios_memio(ips_ha_t *ha, char *buffer, u32 buffersize, u32 offset) {
u8 checksum;
int i;
@@ -6600,23 +7490,23 @@
/* test 1st byte */
writel(0, ha->mem_ptr + IPS_REG_FLAP);
if (ha->revision_id == IPS_REVID_TROMBONE64)
- UDELAY(5); /* 5 us */
+ udelay(5); /* 5 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(5); /* 5 us */
if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
return (1);
checksum = 0xff;
for (i = 2; i < buffersize; i++) {
- writel(i, 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(5); /* 5 us */
checksum = (u8) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
}
@@ -6631,7 +7521,6 @@
static Scsi_Host_Template driver_template = IPS;
#include "scsi_module.c"
-
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)