1*1da177e4SLinus Torvalds /*****************************************************************************/ 2*1da177e4SLinus Torvalds /* ips.c -- driver for the Adaptec / IBM ServeRAID controller */ 3*1da177e4SLinus Torvalds /* */ 4*1da177e4SLinus Torvalds /* Written By: Keith Mitchell, IBM Corporation */ 5*1da177e4SLinus Torvalds /* Jack Hammer, Adaptec, Inc. */ 6*1da177e4SLinus Torvalds /* David Jeffery, Adaptec, Inc. */ 7*1da177e4SLinus Torvalds /* */ 8*1da177e4SLinus Torvalds /* Copyright (C) 2000 IBM Corporation */ 9*1da177e4SLinus Torvalds /* Copyright (C) 2002,2003 Adaptec, Inc. */ 10*1da177e4SLinus Torvalds /* */ 11*1da177e4SLinus Torvalds /* This program is free software; you can redistribute it and/or modify */ 12*1da177e4SLinus Torvalds /* it under the terms of the GNU General Public License as published by */ 13*1da177e4SLinus Torvalds /* the Free Software Foundation; either version 2 of the License, or */ 14*1da177e4SLinus Torvalds /* (at your option) any later version. */ 15*1da177e4SLinus Torvalds /* */ 16*1da177e4SLinus Torvalds /* This program is distributed in the hope that it will be useful, */ 17*1da177e4SLinus Torvalds /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 18*1da177e4SLinus Torvalds /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 19*1da177e4SLinus Torvalds /* GNU General Public License for more details. */ 20*1da177e4SLinus Torvalds /* */ 21*1da177e4SLinus Torvalds /* NO WARRANTY */ 22*1da177e4SLinus Torvalds /* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ 23*1da177e4SLinus Torvalds /* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ 24*1da177e4SLinus Torvalds /* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ 25*1da177e4SLinus Torvalds /* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ 26*1da177e4SLinus Torvalds /* solely responsible for determining the appropriateness of using and */ 27*1da177e4SLinus Torvalds /* distributing the Program and assumes all risks associated with its */ 28*1da177e4SLinus Torvalds /* exercise of rights under this Agreement, including but not limited to */ 29*1da177e4SLinus Torvalds /* the risks and costs of program errors, damage to or loss of data, */ 30*1da177e4SLinus Torvalds /* programs or equipment, and unavailability or interruption of operations. */ 31*1da177e4SLinus Torvalds /* */ 32*1da177e4SLinus Torvalds /* DISCLAIMER OF LIABILITY */ 33*1da177e4SLinus Torvalds /* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ 34*1da177e4SLinus Torvalds /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ 35*1da177e4SLinus Torvalds /* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ 36*1da177e4SLinus Torvalds /* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ 37*1da177e4SLinus Torvalds /* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ 38*1da177e4SLinus Torvalds /* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ 39*1da177e4SLinus Torvalds /* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ 40*1da177e4SLinus Torvalds /* */ 41*1da177e4SLinus Torvalds /* You should have received a copy of the GNU General Public License */ 42*1da177e4SLinus Torvalds /* along with this program; if not, write to the Free Software */ 43*1da177e4SLinus Torvalds /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 44*1da177e4SLinus Torvalds /* */ 45*1da177e4SLinus Torvalds /* Bugs/Comments/Suggestions about this driver should be mailed to: */ 46*1da177e4SLinus Torvalds /* ipslinux@adaptec.com */ 47*1da177e4SLinus Torvalds /* */ 48*1da177e4SLinus Torvalds /* For system support issues, contact your local IBM Customer support. */ 49*1da177e4SLinus Torvalds /* Directions to find IBM Customer Support for each country can be found at: */ 50*1da177e4SLinus Torvalds /* http://www.ibm.com/planetwide/ */ 51*1da177e4SLinus Torvalds /* */ 52*1da177e4SLinus Torvalds /*****************************************************************************/ 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds /*****************************************************************************/ 55*1da177e4SLinus Torvalds /* Change Log */ 56*1da177e4SLinus Torvalds /* */ 57*1da177e4SLinus Torvalds /* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size */ 58*1da177e4SLinus Torvalds /* 0.99.03 - Make interrupt routine handle all completed request on the */ 59*1da177e4SLinus Torvalds /* adapter not just the first one */ 60*1da177e4SLinus Torvalds /* - Make sure passthru commands get woken up if we run out of */ 61*1da177e4SLinus Torvalds /* SCBs */ 62*1da177e4SLinus Torvalds /* - Send all of the commands on the queue at once rather than */ 63*1da177e4SLinus Torvalds /* one at a time since the card will support it. */ 64*1da177e4SLinus Torvalds /* 0.99.04 - Fix race condition in the passthru mechanism -- this required */ 65*1da177e4SLinus Torvalds /* the interface to the utilities to change */ 66*1da177e4SLinus Torvalds /* - Fix error recovery code */ 67*1da177e4SLinus Torvalds /* 0.99.05 - Fix an oops when we get certain passthru commands */ 68*1da177e4SLinus Torvalds /* 1.00.00 - Initial Public Release */ 69*1da177e4SLinus Torvalds /* Functionally equivalent to 0.99.05 */ 70*1da177e4SLinus Torvalds /* 3.60.00 - Bump max commands to 128 for use with firmware 3.60 */ 71*1da177e4SLinus Torvalds /* - Change version to 3.60 to coincide with release numbering. */ 72*1da177e4SLinus Torvalds /* 3.60.01 - Remove bogus error check in passthru routine */ 73*1da177e4SLinus Torvalds /* 3.60.02 - Make DCDB direction based on lookup table */ 74*1da177e4SLinus Torvalds /* - Only allow one DCDB command to a SCSI ID at a time */ 75*1da177e4SLinus Torvalds /* 4.00.00 - Add support for ServeRAID 4 */ 76*1da177e4SLinus Torvalds /* 4.00.01 - Add support for First Failure Data Capture */ 77*1da177e4SLinus Torvalds /* 4.00.02 - Fix problem with PT DCDB with no buffer */ 78*1da177e4SLinus Torvalds /* 4.00.03 - Add alternative passthru interface */ 79*1da177e4SLinus Torvalds /* - Add ability to flash BIOS */ 80*1da177e4SLinus Torvalds /* 4.00.04 - Rename structures/constants to be prefixed with IPS_ */ 81*1da177e4SLinus Torvalds /* 4.00.05 - Remove wish_block from init routine */ 82*1da177e4SLinus Torvalds /* - Use linux/spinlock.h instead of asm/spinlock.h for kernels */ 83*1da177e4SLinus Torvalds /* 2.3.18 and later */ 84*1da177e4SLinus Torvalds /* - Sync with other changes from the 2.3 kernels */ 85*1da177e4SLinus Torvalds /* 4.00.06 - Fix timeout with initial FFDC command */ 86*1da177e4SLinus Torvalds /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */ 87*1da177e4SLinus Torvalds /* 4.10.00 - Add support for ServeRAID 4M/4L */ 88*1da177e4SLinus Torvalds /* 4.10.13 - Fix for dynamic unload and proc file system */ 89*1da177e4SLinus Torvalds /* 4.20.03 - Rename version to coincide with new release schedules */ 90*1da177e4SLinus Torvalds /* Performance fixes */ 91*1da177e4SLinus Torvalds /* Fix truncation of /proc files with cat */ 92*1da177e4SLinus Torvalds /* Merge in changes through kernel 2.4.0test1ac21 */ 93*1da177e4SLinus Torvalds /* 4.20.13 - Fix some failure cases / reset code */ 94*1da177e4SLinus Torvalds /* - Hook into the reboot_notifier to flush the controller cache */ 95*1da177e4SLinus Torvalds /* 4.50.01 - Fix problem when there is a hole in logical drive numbering */ 96*1da177e4SLinus Torvalds /* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */ 97*1da177e4SLinus Torvalds /* - Add IPSSEND Flash Support */ 98*1da177e4SLinus Torvalds /* - Set Sense Data for Unknown SCSI Command */ 99*1da177e4SLinus Torvalds /* - Use Slot Number from NVRAM Page 5 */ 100*1da177e4SLinus Torvalds /* - Restore caller's DCDB Structure */ 101*1da177e4SLinus Torvalds /* 4.70.12 - Corrective actions for bad controller ( during initialization )*/ 102*1da177e4SLinus Torvalds /* 4.70.13 - Don't Send CDB's if we already know the device is not present */ 103*1da177e4SLinus Torvalds /* - Don't release HA Lock in ips_next() until SC taken off queue */ 104*1da177e4SLinus Torvalds /* - Unregister SCSI device in ips_release() */ 105*1da177e4SLinus Torvalds /* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */ 106*1da177e4SLinus Torvalds /* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */ 107*1da177e4SLinus Torvalds /* Code Clean-Up for 2.4.x kernel */ 108*1da177e4SLinus Torvalds /* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */ 109*1da177e4SLinus Torvalds /* 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) */ 110*1da177e4SLinus Torvalds /* - Don't Issue Internal FFDC Command if there are Active Commands */ 111*1da177e4SLinus Torvalds /* - Close Window for getting too many IOCTL's active */ 112*1da177e4SLinus Torvalds /* 4.80.00 - Make ia64 Safe */ 113*1da177e4SLinus Torvalds /* 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater */ 114*1da177e4SLinus Torvalds /* - Adjustments to Device Queue Depth */ 115*1da177e4SLinus Torvalds /* 4.80.14 - Take all semaphores off stack */ 116*1da177e4SLinus Torvalds /* - Clean Up New_IOCTL path */ 117*1da177e4SLinus Torvalds /* 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) */ 118*1da177e4SLinus Torvalds /* - 5 second delay needed after resetting an i960 adapter */ 119*1da177e4SLinus Torvalds /* 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) */ 120*1da177e4SLinus Torvalds /* 4.90.01 - Version Matching for FirmWare, BIOS, and Driver */ 121*1da177e4SLinus Torvalds /* 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development */ 122*1da177e4SLinus Torvalds /* 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) */ 123*1da177e4SLinus Torvalds /* 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K */ 124*1da177e4SLinus Torvalds /* 4.90.11 - Don't actually RESET unless it's physically required */ 125*1da177e4SLinus Torvalds /* - Remove unused compile options */ 126*1da177e4SLinus Torvalds /* 5.00.01 - Sarasota ( 5i ) adapters must always be scanned first */ 127*1da177e4SLinus Torvalds /* - Get rid on IOCTL_NEW_COMMAND code */ 128*1da177e4SLinus Torvalds /* - Add Extended DCDB Commands for Tape Support in 5I */ 129*1da177e4SLinus Torvalds /* 5.10.12 - use pci_dma interfaces, update for 2.5 kernel changes */ 130*1da177e4SLinus Torvalds /* 5.10.15 - remove unused code (sem, macros, etc.) */ 131*1da177e4SLinus Torvalds /* 5.30.00 - use __devexit_p() */ 132*1da177e4SLinus Torvalds /* 6.00.00 - Add 6x Adapters and Battery Flash */ 133*1da177e4SLinus Torvalds /* 6.10.00 - Remove 1G Addressing Limitations */ 134*1da177e4SLinus Torvalds /* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */ 135*1da177e4SLinus Torvalds /* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */ 136*1da177e4SLinus Torvalds /* 7.10.xx - Add highmem_io flag in SCSI Templete for 2.4 kernels */ 137*1da177e4SLinus Torvalds /* - Fix path/name for scsi_hosts.h include for 2.6 kernels */ 138*1da177e4SLinus Torvalds /* - Fix sort order of 7k */ 139*1da177e4SLinus Torvalds /* - Remove 3 unused "inline" functions */ 140*1da177e4SLinus Torvalds /*****************************************************************************/ 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds /* 143*1da177e4SLinus Torvalds * Conditional Compilation directives for this driver: 144*1da177e4SLinus Torvalds * 145*1da177e4SLinus Torvalds * IPS_DEBUG - Turn on debugging info 146*1da177e4SLinus Torvalds * 147*1da177e4SLinus Torvalds * Parameters: 148*1da177e4SLinus Torvalds * 149*1da177e4SLinus Torvalds * debug:<number> - Set debug level to <number> 150*1da177e4SLinus Torvalds * NOTE: only works when IPS_DEBUG compile directive is used. 151*1da177e4SLinus Torvalds * 1 - Normal debug messages 152*1da177e4SLinus Torvalds * 2 - Verbose debug messages 153*1da177e4SLinus Torvalds * 11 - Method trace (non interrupt) 154*1da177e4SLinus Torvalds * 12 - Method trace (includes interrupt) 155*1da177e4SLinus Torvalds * 156*1da177e4SLinus Torvalds * noi2o - Don't use I2O Queues (ServeRAID 4 only) 157*1da177e4SLinus Torvalds * nommap - Don't use memory mapped I/O 158*1da177e4SLinus Torvalds * ioctlsize - Initial size of the IOCTL buffer 159*1da177e4SLinus Torvalds */ 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds #include <asm/io.h> 162*1da177e4SLinus Torvalds #include <asm/byteorder.h> 163*1da177e4SLinus Torvalds #include <asm/page.h> 164*1da177e4SLinus Torvalds #include <linux/stddef.h> 165*1da177e4SLinus Torvalds #include <linux/version.h> 166*1da177e4SLinus Torvalds #include <linux/string.h> 167*1da177e4SLinus Torvalds #include <linux/errno.h> 168*1da177e4SLinus Torvalds #include <linux/kernel.h> 169*1da177e4SLinus Torvalds #include <linux/ioport.h> 170*1da177e4SLinus Torvalds #include <linux/slab.h> 171*1da177e4SLinus Torvalds #include <linux/delay.h> 172*1da177e4SLinus Torvalds #include <linux/pci.h> 173*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 174*1da177e4SLinus Torvalds #include <linux/reboot.h> 175*1da177e4SLinus Torvalds #include <linux/interrupt.h> 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds #include <linux/blkdev.h> 178*1da177e4SLinus Torvalds #include <linux/types.h> 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds #include <scsi/sg.h> 181*1da177e4SLinus Torvalds 182*1da177e4SLinus Torvalds #include "scsi.h" 183*1da177e4SLinus Torvalds 184*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) 185*1da177e4SLinus Torvalds #include "hosts.h" 186*1da177e4SLinus Torvalds #else 187*1da177e4SLinus Torvalds #include <scsi/scsi_host.h> 188*1da177e4SLinus Torvalds #endif 189*1da177e4SLinus Torvalds 190*1da177e4SLinus Torvalds #include "ips.h" 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds #include <linux/module.h> 193*1da177e4SLinus Torvalds 194*1da177e4SLinus Torvalds #include <linux/stat.h> 195*1da177e4SLinus Torvalds #include <linux/config.h> 196*1da177e4SLinus Torvalds 197*1da177e4SLinus Torvalds #include <linux/spinlock.h> 198*1da177e4SLinus Torvalds #include <linux/init.h> 199*1da177e4SLinus Torvalds 200*1da177e4SLinus Torvalds #include <linux/smp.h> 201*1da177e4SLinus Torvalds 202*1da177e4SLinus Torvalds #ifdef MODULE 203*1da177e4SLinus Torvalds static char *ips = NULL; 204*1da177e4SLinus Torvalds module_param(ips, charp, 0); 205*1da177e4SLinus Torvalds #endif 206*1da177e4SLinus Torvalds 207*1da177e4SLinus Torvalds /* 208*1da177e4SLinus Torvalds * DRIVER_VER 209*1da177e4SLinus Torvalds */ 210*1da177e4SLinus Torvalds #define IPS_VERSION_HIGH "7.10" 211*1da177e4SLinus Torvalds #define IPS_VERSION_LOW ".18 " 212*1da177e4SLinus Torvalds 213*1da177e4SLinus Torvalds #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) 214*1da177e4SLinus Torvalds #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" 215*1da177e4SLinus Torvalds #endif 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) 218*1da177e4SLinus Torvalds #include <linux/blk.h> 219*1da177e4SLinus Torvalds #include "sd.h" 220*1da177e4SLinus Torvalds #define IPS_SG_ADDRESS(sg) ((sg)->address) 221*1da177e4SLinus Torvalds #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags) 222*1da177e4SLinus Torvalds #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags) 223*1da177e4SLinus Torvalds #ifndef __devexit_p 224*1da177e4SLinus Torvalds #define __devexit_p(x) x 225*1da177e4SLinus Torvalds #endif 226*1da177e4SLinus Torvalds #else 227*1da177e4SLinus Torvalds #define IPS_SG_ADDRESS(sg) (page_address((sg)->page) ? \ 228*1da177e4SLinus Torvalds page_address((sg)->page)+(sg)->offset : NULL) 229*1da177e4SLinus Torvalds #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0) 230*1da177e4SLinus Torvalds #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0) 231*1da177e4SLinus Torvalds #endif 232*1da177e4SLinus Torvalds 233*1da177e4SLinus Torvalds #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \ 234*1da177e4SLinus Torvalds SCSI_DATA_NONE == scb->scsi_cmd->sc_data_direction) ? \ 235*1da177e4SLinus Torvalds PCI_DMA_BIDIRECTIONAL : \ 236*1da177e4SLinus Torvalds scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction)) 237*1da177e4SLinus Torvalds 238*1da177e4SLinus Torvalds #ifdef IPS_DEBUG 239*1da177e4SLinus Torvalds #define METHOD_TRACE(s, i) if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); 240*1da177e4SLinus Torvalds #define DEBUG(i, s) if (ips_debug >= i) printk(KERN_NOTICE s "\n"); 241*1da177e4SLinus Torvalds #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v); 242*1da177e4SLinus Torvalds #else 243*1da177e4SLinus Torvalds #define METHOD_TRACE(s, i) 244*1da177e4SLinus Torvalds #define DEBUG(i, s) 245*1da177e4SLinus Torvalds #define DEBUG_VAR(i, s, v...) 246*1da177e4SLinus Torvalds #endif 247*1da177e4SLinus Torvalds 248*1da177e4SLinus Torvalds /* 249*1da177e4SLinus Torvalds * Function prototypes 250*1da177e4SLinus Torvalds */ 251*1da177e4SLinus Torvalds static int ips_detect(Scsi_Host_Template *); 252*1da177e4SLinus Torvalds static int ips_release(struct Scsi_Host *); 253*1da177e4SLinus Torvalds static int ips_eh_abort(Scsi_Cmnd *); 254*1da177e4SLinus Torvalds static int ips_eh_reset(Scsi_Cmnd *); 255*1da177e4SLinus Torvalds static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); 256*1da177e4SLinus Torvalds static const char *ips_info(struct Scsi_Host *); 257*1da177e4SLinus Torvalds static irqreturn_t do_ipsintr(int, void *, struct pt_regs *); 258*1da177e4SLinus Torvalds static int ips_hainit(ips_ha_t *); 259*1da177e4SLinus Torvalds static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); 260*1da177e4SLinus Torvalds static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); 261*1da177e4SLinus Torvalds static int ips_send_cmd(ips_ha_t *, ips_scb_t *); 262*1da177e4SLinus Torvalds static int ips_online(ips_ha_t *, ips_scb_t *); 263*1da177e4SLinus Torvalds static int ips_inquiry(ips_ha_t *, ips_scb_t *); 264*1da177e4SLinus Torvalds static int ips_rdcap(ips_ha_t *, ips_scb_t *); 265*1da177e4SLinus Torvalds static int ips_msense(ips_ha_t *, ips_scb_t *); 266*1da177e4SLinus Torvalds static int ips_reqsen(ips_ha_t *, ips_scb_t *); 267*1da177e4SLinus Torvalds static int ips_deallocatescbs(ips_ha_t *, int); 268*1da177e4SLinus Torvalds static int ips_allocatescbs(ips_ha_t *); 269*1da177e4SLinus Torvalds static int ips_reset_copperhead(ips_ha_t *); 270*1da177e4SLinus Torvalds static int ips_reset_copperhead_memio(ips_ha_t *); 271*1da177e4SLinus Torvalds static int ips_reset_morpheus(ips_ha_t *); 272*1da177e4SLinus Torvalds static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); 273*1da177e4SLinus Torvalds static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); 274*1da177e4SLinus Torvalds static int ips_issue_i2o(ips_ha_t *, ips_scb_t *); 275*1da177e4SLinus Torvalds static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); 276*1da177e4SLinus Torvalds static int ips_isintr_copperhead(ips_ha_t *); 277*1da177e4SLinus Torvalds static int ips_isintr_copperhead_memio(ips_ha_t *); 278*1da177e4SLinus Torvalds static int ips_isintr_morpheus(ips_ha_t *); 279*1da177e4SLinus Torvalds static int ips_wait(ips_ha_t *, int, int); 280*1da177e4SLinus Torvalds static int ips_write_driver_status(ips_ha_t *, int); 281*1da177e4SLinus Torvalds static int ips_read_adapter_status(ips_ha_t *, int); 282*1da177e4SLinus Torvalds static int ips_read_subsystem_parameters(ips_ha_t *, int); 283*1da177e4SLinus Torvalds static int ips_read_config(ips_ha_t *, int); 284*1da177e4SLinus Torvalds static int ips_clear_adapter(ips_ha_t *, int); 285*1da177e4SLinus Torvalds static int ips_readwrite_page5(ips_ha_t *, int, int); 286*1da177e4SLinus Torvalds static int ips_init_copperhead(ips_ha_t *); 287*1da177e4SLinus Torvalds static int ips_init_copperhead_memio(ips_ha_t *); 288*1da177e4SLinus Torvalds static int ips_init_morpheus(ips_ha_t *); 289*1da177e4SLinus Torvalds static int ips_isinit_copperhead(ips_ha_t *); 290*1da177e4SLinus Torvalds static int ips_isinit_copperhead_memio(ips_ha_t *); 291*1da177e4SLinus Torvalds static int ips_isinit_morpheus(ips_ha_t *); 292*1da177e4SLinus Torvalds static int ips_erase_bios(ips_ha_t *); 293*1da177e4SLinus Torvalds static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t); 294*1da177e4SLinus Torvalds static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t); 295*1da177e4SLinus Torvalds static int ips_erase_bios_memio(ips_ha_t *); 296*1da177e4SLinus Torvalds static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); 297*1da177e4SLinus Torvalds static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); 298*1da177e4SLinus Torvalds static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 299*1da177e4SLinus Torvalds static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 300*1da177e4SLinus Torvalds static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 301*1da177e4SLinus Torvalds static void ips_free_flash_copperhead(ips_ha_t * ha); 302*1da177e4SLinus Torvalds static void ips_get_bios_version(ips_ha_t *, int); 303*1da177e4SLinus Torvalds static void ips_identify_controller(ips_ha_t *); 304*1da177e4SLinus Torvalds static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); 305*1da177e4SLinus Torvalds static void ips_enable_int_copperhead(ips_ha_t *); 306*1da177e4SLinus Torvalds static void ips_enable_int_copperhead_memio(ips_ha_t *); 307*1da177e4SLinus Torvalds static void ips_enable_int_morpheus(ips_ha_t *); 308*1da177e4SLinus Torvalds static int ips_intr_copperhead(ips_ha_t *); 309*1da177e4SLinus Torvalds static int ips_intr_morpheus(ips_ha_t *); 310*1da177e4SLinus Torvalds static void ips_next(ips_ha_t *, int); 311*1da177e4SLinus Torvalds static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); 312*1da177e4SLinus Torvalds static void ipsintr_done(ips_ha_t *, struct ips_scb *); 313*1da177e4SLinus Torvalds static void ips_done(ips_ha_t *, ips_scb_t *); 314*1da177e4SLinus Torvalds static void ips_free(ips_ha_t *); 315*1da177e4SLinus Torvalds static void ips_init_scb(ips_ha_t *, ips_scb_t *); 316*1da177e4SLinus Torvalds static void ips_freescb(ips_ha_t *, ips_scb_t *); 317*1da177e4SLinus Torvalds static void ips_setup_funclist(ips_ha_t *); 318*1da177e4SLinus Torvalds static void ips_statinit(ips_ha_t *); 319*1da177e4SLinus Torvalds static void ips_statinit_memio(ips_ha_t *); 320*1da177e4SLinus Torvalds static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t); 321*1da177e4SLinus Torvalds static void ips_ffdc_reset(ips_ha_t *, int); 322*1da177e4SLinus Torvalds static void ips_ffdc_time(ips_ha_t *); 323*1da177e4SLinus Torvalds static uint32_t ips_statupd_copperhead(ips_ha_t *); 324*1da177e4SLinus Torvalds static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); 325*1da177e4SLinus Torvalds static uint32_t ips_statupd_morpheus(ips_ha_t *); 326*1da177e4SLinus Torvalds static ips_scb_t *ips_getscb(ips_ha_t *); 327*1da177e4SLinus Torvalds static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); 328*1da177e4SLinus Torvalds static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); 329*1da177e4SLinus Torvalds static void ips_putq_copp_tail(ips_copp_queue_t *, 330*1da177e4SLinus Torvalds ips_copp_wait_item_t *); 331*1da177e4SLinus Torvalds static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); 332*1da177e4SLinus Torvalds static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); 333*1da177e4SLinus Torvalds static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); 334*1da177e4SLinus Torvalds static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); 335*1da177e4SLinus Torvalds static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, 336*1da177e4SLinus Torvalds ips_copp_wait_item_t *); 337*1da177e4SLinus Torvalds static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); 338*1da177e4SLinus Torvalds 339*1da177e4SLinus Torvalds static int ips_is_passthru(Scsi_Cmnd *); 340*1da177e4SLinus Torvalds static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); 341*1da177e4SLinus Torvalds static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 342*1da177e4SLinus Torvalds static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); 343*1da177e4SLinus Torvalds static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, 344*1da177e4SLinus Torvalds unsigned int count); 345*1da177e4SLinus Torvalds static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count); 346*1da177e4SLinus Torvalds 347*1da177e4SLinus Torvalds static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); 348*1da177e4SLinus Torvalds static int ips_host_info(ips_ha_t *, char *, off_t, int); 349*1da177e4SLinus Torvalds static void copy_mem_info(IPS_INFOSTR *, char *, int); 350*1da177e4SLinus Torvalds static int copy_info(IPS_INFOSTR *, char *, ...); 351*1da177e4SLinus Torvalds static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr); 352*1da177e4SLinus Torvalds static void ips_version_check(ips_ha_t * ha, int intr); 353*1da177e4SLinus Torvalds static int ips_abort_init(ips_ha_t * ha, int index); 354*1da177e4SLinus Torvalds static int ips_init_phase2(int index); 355*1da177e4SLinus Torvalds 356*1da177e4SLinus Torvalds static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr); 357*1da177e4SLinus Torvalds static int ips_register_scsi(int index); 358*1da177e4SLinus Torvalds 359*1da177e4SLinus Torvalds /* 360*1da177e4SLinus Torvalds * global variables 361*1da177e4SLinus Torvalds */ 362*1da177e4SLinus Torvalds static const char ips_name[] = "ips"; 363*1da177e4SLinus Torvalds static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */ 364*1da177e4SLinus Torvalds static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */ 365*1da177e4SLinus Torvalds static unsigned int ips_next_controller; 366*1da177e4SLinus Torvalds static unsigned int ips_num_controllers; 367*1da177e4SLinus Torvalds static unsigned int ips_released_controllers; 368*1da177e4SLinus Torvalds static int ips_hotplug; 369*1da177e4SLinus Torvalds static int ips_cmd_timeout = 60; 370*1da177e4SLinus Torvalds static int ips_reset_timeout = 60 * 5; 371*1da177e4SLinus Torvalds static int ips_force_memio = 1; /* Always use Memory Mapped I/O */ 372*1da177e4SLinus Torvalds static int ips_force_i2o = 1; /* Always use I2O command delivery */ 373*1da177e4SLinus Torvalds static int ips_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */ 374*1da177e4SLinus Torvalds static int ips_cd_boot; /* Booting from Manager CD */ 375*1da177e4SLinus Torvalds static char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */ 376*1da177e4SLinus Torvalds static dma_addr_t ips_flashbusaddr; 377*1da177e4SLinus Torvalds static long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */ 378*1da177e4SLinus Torvalds static uint32_t MaxLiteCmds = 32; /* Max Active Cmds for a Lite Adapter */ 379*1da177e4SLinus Torvalds static Scsi_Host_Template ips_driver_template = { 380*1da177e4SLinus Torvalds .detect = ips_detect, 381*1da177e4SLinus Torvalds .release = ips_release, 382*1da177e4SLinus Torvalds .info = ips_info, 383*1da177e4SLinus Torvalds .queuecommand = ips_queue, 384*1da177e4SLinus Torvalds .eh_abort_handler = ips_eh_abort, 385*1da177e4SLinus Torvalds .eh_host_reset_handler = ips_eh_reset, 386*1da177e4SLinus Torvalds .proc_name = "ips", 387*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) 388*1da177e4SLinus Torvalds .proc_info = ips_proc_info, 389*1da177e4SLinus Torvalds .slave_configure = ips_slave_configure, 390*1da177e4SLinus Torvalds #else 391*1da177e4SLinus Torvalds .proc_info = ips_proc24_info, 392*1da177e4SLinus Torvalds .select_queue_depths = ips_select_queue_depth, 393*1da177e4SLinus Torvalds #endif 394*1da177e4SLinus Torvalds .bios_param = ips_biosparam, 395*1da177e4SLinus Torvalds .this_id = -1, 396*1da177e4SLinus Torvalds .sg_tablesize = IPS_MAX_SG, 397*1da177e4SLinus Torvalds .cmd_per_lun = 3, 398*1da177e4SLinus Torvalds .use_clustering = ENABLE_CLUSTERING, 399*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 400*1da177e4SLinus Torvalds .use_new_eh_code = 1, 401*1da177e4SLinus Torvalds #endif 402*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 403*1da177e4SLinus Torvalds .highmem_io = 1, 404*1da177e4SLinus Torvalds #endif 405*1da177e4SLinus Torvalds }; 406*1da177e4SLinus Torvalds 407*1da177e4SLinus Torvalds static IPS_DEFINE_COMPAT_TABLE( Compatable ); /* Version Compatability Table */ 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds 410*1da177e4SLinus Torvalds /* This table describes all ServeRAID Adapters */ 411*1da177e4SLinus Torvalds static struct pci_device_id ips_pci_table[] = { 412*1da177e4SLinus Torvalds { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, 413*1da177e4SLinus Torvalds { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, 414*1da177e4SLinus Torvalds { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, 415*1da177e4SLinus Torvalds { 0, } 416*1da177e4SLinus Torvalds }; 417*1da177e4SLinus Torvalds 418*1da177e4SLinus Torvalds MODULE_DEVICE_TABLE( pci, ips_pci_table ); 419*1da177e4SLinus Torvalds 420*1da177e4SLinus Torvalds static char ips_hot_plug_name[] = "ips"; 421*1da177e4SLinus Torvalds 422*1da177e4SLinus Torvalds static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); 423*1da177e4SLinus Torvalds static void __devexit ips_remove_device(struct pci_dev *pci_dev); 424*1da177e4SLinus Torvalds 425*1da177e4SLinus Torvalds static struct pci_driver ips_pci_driver = { 426*1da177e4SLinus Torvalds .name = ips_hot_plug_name, 427*1da177e4SLinus Torvalds .id_table = ips_pci_table, 428*1da177e4SLinus Torvalds .probe = ips_insert_device, 429*1da177e4SLinus Torvalds .remove = __devexit_p(ips_remove_device), 430*1da177e4SLinus Torvalds }; 431*1da177e4SLinus Torvalds 432*1da177e4SLinus Torvalds 433*1da177e4SLinus Torvalds /* 434*1da177e4SLinus Torvalds * Necessary forward function protoypes 435*1da177e4SLinus Torvalds */ 436*1da177e4SLinus Torvalds static int ips_halt(struct notifier_block *nb, ulong event, void *buf); 437*1da177e4SLinus Torvalds 438*1da177e4SLinus Torvalds #define MAX_ADAPTER_NAME 15 439*1da177e4SLinus Torvalds 440*1da177e4SLinus Torvalds static char ips_adapter_name[][30] = { 441*1da177e4SLinus Torvalds "ServeRAID", 442*1da177e4SLinus Torvalds "ServeRAID II", 443*1da177e4SLinus Torvalds "ServeRAID on motherboard", 444*1da177e4SLinus Torvalds "ServeRAID on motherboard", 445*1da177e4SLinus Torvalds "ServeRAID 3H", 446*1da177e4SLinus Torvalds "ServeRAID 3L", 447*1da177e4SLinus Torvalds "ServeRAID 4H", 448*1da177e4SLinus Torvalds "ServeRAID 4M", 449*1da177e4SLinus Torvalds "ServeRAID 4L", 450*1da177e4SLinus Torvalds "ServeRAID 4Mx", 451*1da177e4SLinus Torvalds "ServeRAID 4Lx", 452*1da177e4SLinus Torvalds "ServeRAID 5i", 453*1da177e4SLinus Torvalds "ServeRAID 5i", 454*1da177e4SLinus Torvalds "ServeRAID 6M", 455*1da177e4SLinus Torvalds "ServeRAID 6i", 456*1da177e4SLinus Torvalds "ServeRAID 7t", 457*1da177e4SLinus Torvalds "ServeRAID 7k", 458*1da177e4SLinus Torvalds "ServeRAID 7M" 459*1da177e4SLinus Torvalds }; 460*1da177e4SLinus Torvalds 461*1da177e4SLinus Torvalds static struct notifier_block ips_notifier = { 462*1da177e4SLinus Torvalds ips_halt, NULL, 0 463*1da177e4SLinus Torvalds }; 464*1da177e4SLinus Torvalds 465*1da177e4SLinus Torvalds /* 466*1da177e4SLinus Torvalds * Direction table 467*1da177e4SLinus Torvalds */ 468*1da177e4SLinus Torvalds static char ips_command_direction[] = { 469*1da177e4SLinus Torvalds IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, 470*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, 471*1da177e4SLinus Torvalds IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 472*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, 473*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT, 474*1da177e4SLinus Torvalds IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, 475*1da177e4SLinus Torvalds IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN, 476*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, 477*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK, 478*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, 479*1da177e4SLinus Torvalds IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, 480*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, 481*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, 482*1da177e4SLinus Torvalds IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE, 483*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, 484*1da177e4SLinus Torvalds IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, 485*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 486*1da177e4SLinus Torvalds IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 487*1da177e4SLinus Torvalds IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 488*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 489*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 490*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 491*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 492*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 493*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 494*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 495*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 496*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 497*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 498*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 499*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 500*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 501*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 502*1da177e4SLinus Torvalds IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE, 503*1da177e4SLinus Torvalds IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT, 504*1da177e4SLinus Torvalds IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE, 505*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, 506*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 507*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 508*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 509*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 510*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 511*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 512*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 513*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 514*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 515*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT, 516*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 517*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 518*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 519*1da177e4SLinus Torvalds IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK 520*1da177e4SLinus Torvalds }; 521*1da177e4SLinus Torvalds 522*1da177e4SLinus Torvalds 523*1da177e4SLinus Torvalds /****************************************************************************/ 524*1da177e4SLinus Torvalds /* */ 525*1da177e4SLinus Torvalds /* Routine Name: ips_setup */ 526*1da177e4SLinus Torvalds /* */ 527*1da177e4SLinus Torvalds /* Routine Description: */ 528*1da177e4SLinus Torvalds /* */ 529*1da177e4SLinus Torvalds /* setup parameters to the driver */ 530*1da177e4SLinus Torvalds /* */ 531*1da177e4SLinus Torvalds /****************************************************************************/ 532*1da177e4SLinus Torvalds static int 533*1da177e4SLinus Torvalds ips_setup(char *ips_str) 534*1da177e4SLinus Torvalds { 535*1da177e4SLinus Torvalds 536*1da177e4SLinus Torvalds int i; 537*1da177e4SLinus Torvalds char *key; 538*1da177e4SLinus Torvalds char *value; 539*1da177e4SLinus Torvalds IPS_OPTION options[] = { 540*1da177e4SLinus Torvalds {"noi2o", &ips_force_i2o, 0}, 541*1da177e4SLinus Torvalds {"nommap", &ips_force_memio, 0}, 542*1da177e4SLinus Torvalds {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, 543*1da177e4SLinus Torvalds {"cdboot", &ips_cd_boot, 0}, 544*1da177e4SLinus Torvalds {"maxcmds", &MaxLiteCmds, 32}, 545*1da177e4SLinus Torvalds }; 546*1da177e4SLinus Torvalds 547*1da177e4SLinus Torvalds /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */ 548*1da177e4SLinus Torvalds /* Search for value */ 549*1da177e4SLinus Torvalds while ((key = strsep(&ips_str, ",."))) { 550*1da177e4SLinus Torvalds if (!*key) 551*1da177e4SLinus Torvalds continue; 552*1da177e4SLinus Torvalds value = strchr(key, ':'); 553*1da177e4SLinus Torvalds if (value) 554*1da177e4SLinus Torvalds *value++ = '\0'; 555*1da177e4SLinus Torvalds /* 556*1da177e4SLinus Torvalds * We now have key/value pairs. 557*1da177e4SLinus Torvalds * Update the variables 558*1da177e4SLinus Torvalds */ 559*1da177e4SLinus Torvalds for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) { 560*1da177e4SLinus Torvalds if (strnicmp 561*1da177e4SLinus Torvalds (key, options[i].option_name, 562*1da177e4SLinus Torvalds strlen(options[i].option_name)) == 0) { 563*1da177e4SLinus Torvalds if (value) 564*1da177e4SLinus Torvalds *options[i].option_flag = 565*1da177e4SLinus Torvalds simple_strtoul(value, NULL, 0); 566*1da177e4SLinus Torvalds else 567*1da177e4SLinus Torvalds *options[i].option_flag = 568*1da177e4SLinus Torvalds options[i].option_value; 569*1da177e4SLinus Torvalds break; 570*1da177e4SLinus Torvalds } 571*1da177e4SLinus Torvalds } 572*1da177e4SLinus Torvalds } 573*1da177e4SLinus Torvalds 574*1da177e4SLinus Torvalds return (1); 575*1da177e4SLinus Torvalds } 576*1da177e4SLinus Torvalds 577*1da177e4SLinus Torvalds __setup("ips=", ips_setup); 578*1da177e4SLinus Torvalds 579*1da177e4SLinus Torvalds /****************************************************************************/ 580*1da177e4SLinus Torvalds /* */ 581*1da177e4SLinus Torvalds /* Routine Name: ips_detect */ 582*1da177e4SLinus Torvalds /* */ 583*1da177e4SLinus Torvalds /* Routine Description: */ 584*1da177e4SLinus Torvalds /* */ 585*1da177e4SLinus Torvalds /* Detect and initialize the driver */ 586*1da177e4SLinus Torvalds /* */ 587*1da177e4SLinus Torvalds /* NOTE: this routine is called under the io_request_lock spinlock */ 588*1da177e4SLinus Torvalds /* */ 589*1da177e4SLinus Torvalds /****************************************************************************/ 590*1da177e4SLinus Torvalds static int 591*1da177e4SLinus Torvalds ips_detect(Scsi_Host_Template * SHT) 592*1da177e4SLinus Torvalds { 593*1da177e4SLinus Torvalds int i; 594*1da177e4SLinus Torvalds 595*1da177e4SLinus Torvalds METHOD_TRACE("ips_detect", 1); 596*1da177e4SLinus Torvalds 597*1da177e4SLinus Torvalds #ifdef MODULE 598*1da177e4SLinus Torvalds if (ips) 599*1da177e4SLinus Torvalds ips_setup(ips); 600*1da177e4SLinus Torvalds #endif 601*1da177e4SLinus Torvalds 602*1da177e4SLinus Torvalds for (i = 0; i < ips_num_controllers; i++) { 603*1da177e4SLinus Torvalds if (ips_register_scsi(i)) 604*1da177e4SLinus Torvalds ips_free(ips_ha[i]); 605*1da177e4SLinus Torvalds ips_released_controllers++; 606*1da177e4SLinus Torvalds } 607*1da177e4SLinus Torvalds ips_hotplug = 1; 608*1da177e4SLinus Torvalds return (ips_num_controllers); 609*1da177e4SLinus Torvalds } 610*1da177e4SLinus Torvalds 611*1da177e4SLinus Torvalds /****************************************************************************/ 612*1da177e4SLinus Torvalds /* configure the function pointers to use the functions that will work */ 613*1da177e4SLinus Torvalds /* with the found version of the adapter */ 614*1da177e4SLinus Torvalds /****************************************************************************/ 615*1da177e4SLinus Torvalds static void 616*1da177e4SLinus Torvalds ips_setup_funclist(ips_ha_t * ha) 617*1da177e4SLinus Torvalds { 618*1da177e4SLinus Torvalds 619*1da177e4SLinus Torvalds /* 620*1da177e4SLinus Torvalds * Setup Functions 621*1da177e4SLinus Torvalds */ 622*1da177e4SLinus Torvalds if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) { 623*1da177e4SLinus Torvalds /* morpheus / marco / sebring */ 624*1da177e4SLinus Torvalds ha->func.isintr = ips_isintr_morpheus; 625*1da177e4SLinus Torvalds ha->func.isinit = ips_isinit_morpheus; 626*1da177e4SLinus Torvalds ha->func.issue = ips_issue_i2o_memio; 627*1da177e4SLinus Torvalds ha->func.init = ips_init_morpheus; 628*1da177e4SLinus Torvalds ha->func.statupd = ips_statupd_morpheus; 629*1da177e4SLinus Torvalds ha->func.reset = ips_reset_morpheus; 630*1da177e4SLinus Torvalds ha->func.intr = ips_intr_morpheus; 631*1da177e4SLinus Torvalds ha->func.enableint = ips_enable_int_morpheus; 632*1da177e4SLinus Torvalds } else if (IPS_USE_MEMIO(ha)) { 633*1da177e4SLinus Torvalds /* copperhead w/MEMIO */ 634*1da177e4SLinus Torvalds ha->func.isintr = ips_isintr_copperhead_memio; 635*1da177e4SLinus Torvalds ha->func.isinit = ips_isinit_copperhead_memio; 636*1da177e4SLinus Torvalds ha->func.init = ips_init_copperhead_memio; 637*1da177e4SLinus Torvalds ha->func.statupd = ips_statupd_copperhead_memio; 638*1da177e4SLinus Torvalds ha->func.statinit = ips_statinit_memio; 639*1da177e4SLinus Torvalds ha->func.reset = ips_reset_copperhead_memio; 640*1da177e4SLinus Torvalds ha->func.intr = ips_intr_copperhead; 641*1da177e4SLinus Torvalds ha->func.erasebios = ips_erase_bios_memio; 642*1da177e4SLinus Torvalds ha->func.programbios = ips_program_bios_memio; 643*1da177e4SLinus Torvalds ha->func.verifybios = ips_verify_bios_memio; 644*1da177e4SLinus Torvalds ha->func.enableint = ips_enable_int_copperhead_memio; 645*1da177e4SLinus Torvalds if (IPS_USE_I2O_DELIVER(ha)) 646*1da177e4SLinus Torvalds ha->func.issue = ips_issue_i2o_memio; 647*1da177e4SLinus Torvalds else 648*1da177e4SLinus Torvalds ha->func.issue = ips_issue_copperhead_memio; 649*1da177e4SLinus Torvalds } else { 650*1da177e4SLinus Torvalds /* copperhead */ 651*1da177e4SLinus Torvalds ha->func.isintr = ips_isintr_copperhead; 652*1da177e4SLinus Torvalds ha->func.isinit = ips_isinit_copperhead; 653*1da177e4SLinus Torvalds ha->func.init = ips_init_copperhead; 654*1da177e4SLinus Torvalds ha->func.statupd = ips_statupd_copperhead; 655*1da177e4SLinus Torvalds ha->func.statinit = ips_statinit; 656*1da177e4SLinus Torvalds ha->func.reset = ips_reset_copperhead; 657*1da177e4SLinus Torvalds ha->func.intr = ips_intr_copperhead; 658*1da177e4SLinus Torvalds ha->func.erasebios = ips_erase_bios; 659*1da177e4SLinus Torvalds ha->func.programbios = ips_program_bios; 660*1da177e4SLinus Torvalds ha->func.verifybios = ips_verify_bios; 661*1da177e4SLinus Torvalds ha->func.enableint = ips_enable_int_copperhead; 662*1da177e4SLinus Torvalds 663*1da177e4SLinus Torvalds if (IPS_USE_I2O_DELIVER(ha)) 664*1da177e4SLinus Torvalds ha->func.issue = ips_issue_i2o; 665*1da177e4SLinus Torvalds else 666*1da177e4SLinus Torvalds ha->func.issue = ips_issue_copperhead; 667*1da177e4SLinus Torvalds } 668*1da177e4SLinus Torvalds } 669*1da177e4SLinus Torvalds 670*1da177e4SLinus Torvalds /****************************************************************************/ 671*1da177e4SLinus Torvalds /* */ 672*1da177e4SLinus Torvalds /* Routine Name: ips_release */ 673*1da177e4SLinus Torvalds /* */ 674*1da177e4SLinus Torvalds /* Routine Description: */ 675*1da177e4SLinus Torvalds /* */ 676*1da177e4SLinus Torvalds /* Remove a driver */ 677*1da177e4SLinus Torvalds /* */ 678*1da177e4SLinus Torvalds /****************************************************************************/ 679*1da177e4SLinus Torvalds static int 680*1da177e4SLinus Torvalds ips_release(struct Scsi_Host *sh) 681*1da177e4SLinus Torvalds { 682*1da177e4SLinus Torvalds ips_scb_t *scb; 683*1da177e4SLinus Torvalds ips_ha_t *ha; 684*1da177e4SLinus Torvalds int i; 685*1da177e4SLinus Torvalds 686*1da177e4SLinus Torvalds METHOD_TRACE("ips_release", 1); 687*1da177e4SLinus Torvalds 688*1da177e4SLinus Torvalds for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ; 689*1da177e4SLinus Torvalds 690*1da177e4SLinus Torvalds if (i == IPS_MAX_ADAPTERS) { 691*1da177e4SLinus Torvalds printk(KERN_WARNING 692*1da177e4SLinus Torvalds "(%s) release, invalid Scsi_Host pointer.\n", ips_name); 693*1da177e4SLinus Torvalds BUG(); 694*1da177e4SLinus Torvalds return (FALSE); 695*1da177e4SLinus Torvalds } 696*1da177e4SLinus Torvalds 697*1da177e4SLinus Torvalds ha = IPS_HA(sh); 698*1da177e4SLinus Torvalds 699*1da177e4SLinus Torvalds if (!ha) 700*1da177e4SLinus Torvalds return (FALSE); 701*1da177e4SLinus Torvalds 702*1da177e4SLinus Torvalds /* flush the cache on the controller */ 703*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 704*1da177e4SLinus Torvalds 705*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 706*1da177e4SLinus Torvalds 707*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 708*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_FLUSH; 709*1da177e4SLinus Torvalds 710*1da177e4SLinus Torvalds scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 711*1da177e4SLinus Torvalds scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); 712*1da177e4SLinus Torvalds scb->cmd.flush_cache.state = IPS_NORM_STATE; 713*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved = 0; 714*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved2 = 0; 715*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved3 = 0; 716*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved4 = 0; 717*1da177e4SLinus Torvalds 718*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); 719*1da177e4SLinus Torvalds 720*1da177e4SLinus Torvalds /* send command */ 721*1da177e4SLinus Torvalds if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) 722*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n"); 723*1da177e4SLinus Torvalds 724*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); 725*1da177e4SLinus Torvalds 726*1da177e4SLinus Torvalds ips_sh[i] = NULL; 727*1da177e4SLinus Torvalds ips_ha[i] = NULL; 728*1da177e4SLinus Torvalds 729*1da177e4SLinus Torvalds /* free extra memory */ 730*1da177e4SLinus Torvalds ips_free(ha); 731*1da177e4SLinus Torvalds 732*1da177e4SLinus Torvalds /* Free I/O Region */ 733*1da177e4SLinus Torvalds if (ha->io_addr) 734*1da177e4SLinus Torvalds release_region(ha->io_addr, ha->io_len); 735*1da177e4SLinus Torvalds 736*1da177e4SLinus Torvalds /* free IRQ */ 737*1da177e4SLinus Torvalds free_irq(ha->irq, ha); 738*1da177e4SLinus Torvalds 739*1da177e4SLinus Torvalds IPS_REMOVE_HOST(sh); 740*1da177e4SLinus Torvalds scsi_host_put(sh); 741*1da177e4SLinus Torvalds 742*1da177e4SLinus Torvalds ips_released_controllers++; 743*1da177e4SLinus Torvalds 744*1da177e4SLinus Torvalds return (FALSE); 745*1da177e4SLinus Torvalds } 746*1da177e4SLinus Torvalds 747*1da177e4SLinus Torvalds /****************************************************************************/ 748*1da177e4SLinus Torvalds /* */ 749*1da177e4SLinus Torvalds /* Routine Name: ips_halt */ 750*1da177e4SLinus Torvalds /* */ 751*1da177e4SLinus Torvalds /* Routine Description: */ 752*1da177e4SLinus Torvalds /* */ 753*1da177e4SLinus Torvalds /* Perform cleanup when the system reboots */ 754*1da177e4SLinus Torvalds /* */ 755*1da177e4SLinus Torvalds /****************************************************************************/ 756*1da177e4SLinus Torvalds static int 757*1da177e4SLinus Torvalds ips_halt(struct notifier_block *nb, ulong event, void *buf) 758*1da177e4SLinus Torvalds { 759*1da177e4SLinus Torvalds ips_scb_t *scb; 760*1da177e4SLinus Torvalds ips_ha_t *ha; 761*1da177e4SLinus Torvalds int i; 762*1da177e4SLinus Torvalds 763*1da177e4SLinus Torvalds if ((event != SYS_RESTART) && (event != SYS_HALT) && 764*1da177e4SLinus Torvalds (event != SYS_POWER_OFF)) 765*1da177e4SLinus Torvalds return (NOTIFY_DONE); 766*1da177e4SLinus Torvalds 767*1da177e4SLinus Torvalds for (i = 0; i < ips_next_controller; i++) { 768*1da177e4SLinus Torvalds ha = (ips_ha_t *) ips_ha[i]; 769*1da177e4SLinus Torvalds 770*1da177e4SLinus Torvalds if (!ha) 771*1da177e4SLinus Torvalds continue; 772*1da177e4SLinus Torvalds 773*1da177e4SLinus Torvalds if (!ha->active) 774*1da177e4SLinus Torvalds continue; 775*1da177e4SLinus Torvalds 776*1da177e4SLinus Torvalds /* flush the cache on the controller */ 777*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 778*1da177e4SLinus Torvalds 779*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 780*1da177e4SLinus Torvalds 781*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 782*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_FLUSH; 783*1da177e4SLinus Torvalds 784*1da177e4SLinus Torvalds scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 785*1da177e4SLinus Torvalds scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); 786*1da177e4SLinus Torvalds scb->cmd.flush_cache.state = IPS_NORM_STATE; 787*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved = 0; 788*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved2 = 0; 789*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved3 = 0; 790*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved4 = 0; 791*1da177e4SLinus Torvalds 792*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); 793*1da177e4SLinus Torvalds 794*1da177e4SLinus Torvalds /* send command */ 795*1da177e4SLinus Torvalds if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == 796*1da177e4SLinus Torvalds IPS_FAILURE) 797*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 798*1da177e4SLinus Torvalds "Incomplete Flush.\n"); 799*1da177e4SLinus Torvalds else 800*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 801*1da177e4SLinus Torvalds "Flushing Complete.\n"); 802*1da177e4SLinus Torvalds } 803*1da177e4SLinus Torvalds 804*1da177e4SLinus Torvalds return (NOTIFY_OK); 805*1da177e4SLinus Torvalds } 806*1da177e4SLinus Torvalds 807*1da177e4SLinus Torvalds /****************************************************************************/ 808*1da177e4SLinus Torvalds /* */ 809*1da177e4SLinus Torvalds /* Routine Name: ips_eh_abort */ 810*1da177e4SLinus Torvalds /* */ 811*1da177e4SLinus Torvalds /* Routine Description: */ 812*1da177e4SLinus Torvalds /* */ 813*1da177e4SLinus Torvalds /* Abort a command (using the new error code stuff) */ 814*1da177e4SLinus Torvalds /* Note: this routine is called under the io_request_lock */ 815*1da177e4SLinus Torvalds /****************************************************************************/ 816*1da177e4SLinus Torvalds int 817*1da177e4SLinus Torvalds ips_eh_abort(Scsi_Cmnd * SC) 818*1da177e4SLinus Torvalds { 819*1da177e4SLinus Torvalds ips_ha_t *ha; 820*1da177e4SLinus Torvalds ips_copp_wait_item_t *item; 821*1da177e4SLinus Torvalds int ret; 822*1da177e4SLinus Torvalds 823*1da177e4SLinus Torvalds METHOD_TRACE("ips_eh_abort", 1); 824*1da177e4SLinus Torvalds 825*1da177e4SLinus Torvalds if (!SC) 826*1da177e4SLinus Torvalds return (FAILED); 827*1da177e4SLinus Torvalds 828*1da177e4SLinus Torvalds ha = (ips_ha_t *) SC->device->host->hostdata; 829*1da177e4SLinus Torvalds 830*1da177e4SLinus Torvalds if (!ha) 831*1da177e4SLinus Torvalds return (FAILED); 832*1da177e4SLinus Torvalds 833*1da177e4SLinus Torvalds if (!ha->active) 834*1da177e4SLinus Torvalds return (FAILED); 835*1da177e4SLinus Torvalds 836*1da177e4SLinus Torvalds if (SC->serial_number != SC->serial_number_at_timeout) { 837*1da177e4SLinus Torvalds /* HMM, looks like a bogus command */ 838*1da177e4SLinus Torvalds DEBUG(1, "Abort called with bogus scsi command"); 839*1da177e4SLinus Torvalds 840*1da177e4SLinus Torvalds return (FAILED); 841*1da177e4SLinus Torvalds } 842*1da177e4SLinus Torvalds 843*1da177e4SLinus Torvalds /* See if the command is on the copp queue */ 844*1da177e4SLinus Torvalds item = ha->copp_waitlist.head; 845*1da177e4SLinus Torvalds while ((item) && (item->scsi_cmd != SC)) 846*1da177e4SLinus Torvalds item = item->next; 847*1da177e4SLinus Torvalds 848*1da177e4SLinus Torvalds if (item) { 849*1da177e4SLinus Torvalds /* Found it */ 850*1da177e4SLinus Torvalds ips_removeq_copp(&ha->copp_waitlist, item); 851*1da177e4SLinus Torvalds ret = (SUCCESS); 852*1da177e4SLinus Torvalds 853*1da177e4SLinus Torvalds /* See if the command is on the wait queue */ 854*1da177e4SLinus Torvalds } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) { 855*1da177e4SLinus Torvalds /* command not sent yet */ 856*1da177e4SLinus Torvalds ret = (SUCCESS); 857*1da177e4SLinus Torvalds } else { 858*1da177e4SLinus Torvalds /* command must have already been sent */ 859*1da177e4SLinus Torvalds ret = (FAILED); 860*1da177e4SLinus Torvalds } 861*1da177e4SLinus Torvalds return ret; 862*1da177e4SLinus Torvalds } 863*1da177e4SLinus Torvalds 864*1da177e4SLinus Torvalds /****************************************************************************/ 865*1da177e4SLinus Torvalds /* */ 866*1da177e4SLinus Torvalds /* Routine Name: ips_eh_reset */ 867*1da177e4SLinus Torvalds /* */ 868*1da177e4SLinus Torvalds /* Routine Description: */ 869*1da177e4SLinus Torvalds /* */ 870*1da177e4SLinus Torvalds /* Reset the controller (with new eh error code) */ 871*1da177e4SLinus Torvalds /* */ 872*1da177e4SLinus Torvalds /* NOTE: this routine is called under the io_request_lock spinlock */ 873*1da177e4SLinus Torvalds /* */ 874*1da177e4SLinus Torvalds /****************************************************************************/ 875*1da177e4SLinus Torvalds static int 876*1da177e4SLinus Torvalds ips_eh_reset(Scsi_Cmnd * SC) 877*1da177e4SLinus Torvalds { 878*1da177e4SLinus Torvalds int ret; 879*1da177e4SLinus Torvalds int i; 880*1da177e4SLinus Torvalds ips_ha_t *ha; 881*1da177e4SLinus Torvalds ips_scb_t *scb; 882*1da177e4SLinus Torvalds ips_copp_wait_item_t *item; 883*1da177e4SLinus Torvalds 884*1da177e4SLinus Torvalds METHOD_TRACE("ips_eh_reset", 1); 885*1da177e4SLinus Torvalds 886*1da177e4SLinus Torvalds #ifdef NO_IPS_RESET 887*1da177e4SLinus Torvalds return (FAILED); 888*1da177e4SLinus Torvalds #else 889*1da177e4SLinus Torvalds 890*1da177e4SLinus Torvalds if (!SC) { 891*1da177e4SLinus Torvalds DEBUG(1, "Reset called with NULL scsi command"); 892*1da177e4SLinus Torvalds 893*1da177e4SLinus Torvalds return (FAILED); 894*1da177e4SLinus Torvalds } 895*1da177e4SLinus Torvalds 896*1da177e4SLinus Torvalds ha = (ips_ha_t *) SC->device->host->hostdata; 897*1da177e4SLinus Torvalds 898*1da177e4SLinus Torvalds if (!ha) { 899*1da177e4SLinus Torvalds DEBUG(1, "Reset called with NULL ha struct"); 900*1da177e4SLinus Torvalds 901*1da177e4SLinus Torvalds return (FAILED); 902*1da177e4SLinus Torvalds } 903*1da177e4SLinus Torvalds 904*1da177e4SLinus Torvalds if (!ha->active) 905*1da177e4SLinus Torvalds return (FAILED); 906*1da177e4SLinus Torvalds 907*1da177e4SLinus Torvalds /* See if the command is on the copp queue */ 908*1da177e4SLinus Torvalds item = ha->copp_waitlist.head; 909*1da177e4SLinus Torvalds while ((item) && (item->scsi_cmd != SC)) 910*1da177e4SLinus Torvalds item = item->next; 911*1da177e4SLinus Torvalds 912*1da177e4SLinus Torvalds if (item) { 913*1da177e4SLinus Torvalds /* Found it */ 914*1da177e4SLinus Torvalds ips_removeq_copp(&ha->copp_waitlist, item); 915*1da177e4SLinus Torvalds return (SUCCESS); 916*1da177e4SLinus Torvalds } 917*1da177e4SLinus Torvalds 918*1da177e4SLinus Torvalds /* See if the command is on the wait queue */ 919*1da177e4SLinus Torvalds if (ips_removeq_wait(&ha->scb_waitlist, SC)) { 920*1da177e4SLinus Torvalds /* command not sent yet */ 921*1da177e4SLinus Torvalds return (SUCCESS); 922*1da177e4SLinus Torvalds } 923*1da177e4SLinus Torvalds 924*1da177e4SLinus Torvalds /* An explanation for the casual observer: */ 925*1da177e4SLinus Torvalds /* Part of the function of a RAID controller is automatic error */ 926*1da177e4SLinus Torvalds /* detection and recovery. As such, the only problem that physically */ 927*1da177e4SLinus Torvalds /* resetting an adapter will ever fix is when, for some reason, */ 928*1da177e4SLinus Torvalds /* the driver is not successfully communicating with the adapter. */ 929*1da177e4SLinus Torvalds /* Therefore, we will attempt to flush this adapter. If that succeeds, */ 930*1da177e4SLinus Torvalds /* then there's no real purpose in a physical reset. This will complete */ 931*1da177e4SLinus Torvalds /* much faster and avoids any problems that might be caused by a */ 932*1da177e4SLinus Torvalds /* physical reset ( such as having to fail all the outstanding I/O's ). */ 933*1da177e4SLinus Torvalds 934*1da177e4SLinus Torvalds if (ha->ioctl_reset == 0) { /* IF Not an IOCTL Requested Reset */ 935*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 936*1da177e4SLinus Torvalds 937*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 938*1da177e4SLinus Torvalds 939*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 940*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_FLUSH; 941*1da177e4SLinus Torvalds 942*1da177e4SLinus Torvalds scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 943*1da177e4SLinus Torvalds scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); 944*1da177e4SLinus Torvalds scb->cmd.flush_cache.state = IPS_NORM_STATE; 945*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved = 0; 946*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved2 = 0; 947*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved3 = 0; 948*1da177e4SLinus Torvalds scb->cmd.flush_cache.reserved4 = 0; 949*1da177e4SLinus Torvalds 950*1da177e4SLinus Torvalds /* Attempt the flush command */ 951*1da177e4SLinus Torvalds ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL); 952*1da177e4SLinus Torvalds if (ret == IPS_SUCCESS) { 953*1da177e4SLinus Torvalds IPS_PRINTK(KERN_NOTICE, ha->pcidev, 954*1da177e4SLinus Torvalds "Reset Request - Flushed Cache\n"); 955*1da177e4SLinus Torvalds return (SUCCESS); 956*1da177e4SLinus Torvalds } 957*1da177e4SLinus Torvalds } 958*1da177e4SLinus Torvalds 959*1da177e4SLinus Torvalds /* Either we can't communicate with the adapter or it's an IOCTL request */ 960*1da177e4SLinus Torvalds /* from a utility. A physical reset is needed at this point. */ 961*1da177e4SLinus Torvalds 962*1da177e4SLinus Torvalds ha->ioctl_reset = 0; /* Reset the IOCTL Requested Reset Flag */ 963*1da177e4SLinus Torvalds 964*1da177e4SLinus Torvalds /* 965*1da177e4SLinus Torvalds * command must have already been sent 966*1da177e4SLinus Torvalds * reset the controller 967*1da177e4SLinus Torvalds */ 968*1da177e4SLinus Torvalds IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n"); 969*1da177e4SLinus Torvalds ret = (*ha->func.reset) (ha); 970*1da177e4SLinus Torvalds 971*1da177e4SLinus Torvalds if (!ret) { 972*1da177e4SLinus Torvalds Scsi_Cmnd *scsi_cmd; 973*1da177e4SLinus Torvalds 974*1da177e4SLinus Torvalds IPS_PRINTK(KERN_NOTICE, ha->pcidev, 975*1da177e4SLinus Torvalds "Controller reset failed - controller now offline.\n"); 976*1da177e4SLinus Torvalds 977*1da177e4SLinus Torvalds /* Now fail all of the active commands */ 978*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Failing active commands", 979*1da177e4SLinus Torvalds ips_name, ha->host_num); 980*1da177e4SLinus Torvalds 981*1da177e4SLinus Torvalds while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { 982*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 983*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 984*1da177e4SLinus Torvalds ips_freescb(ha, scb); 985*1da177e4SLinus Torvalds } 986*1da177e4SLinus Torvalds 987*1da177e4SLinus Torvalds /* Now fail all of the pending commands */ 988*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Failing pending commands", 989*1da177e4SLinus Torvalds ips_name, ha->host_num); 990*1da177e4SLinus Torvalds 991*1da177e4SLinus Torvalds while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { 992*1da177e4SLinus Torvalds scsi_cmd->result = DID_ERROR; 993*1da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 994*1da177e4SLinus Torvalds } 995*1da177e4SLinus Torvalds 996*1da177e4SLinus Torvalds ha->active = FALSE; 997*1da177e4SLinus Torvalds return (FAILED); 998*1da177e4SLinus Torvalds } 999*1da177e4SLinus Torvalds 1000*1da177e4SLinus Torvalds if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { 1001*1da177e4SLinus Torvalds Scsi_Cmnd *scsi_cmd; 1002*1da177e4SLinus Torvalds 1003*1da177e4SLinus Torvalds IPS_PRINTK(KERN_NOTICE, ha->pcidev, 1004*1da177e4SLinus Torvalds "Controller reset failed - controller now offline.\n"); 1005*1da177e4SLinus Torvalds 1006*1da177e4SLinus Torvalds /* Now fail all of the active commands */ 1007*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Failing active commands", 1008*1da177e4SLinus Torvalds ips_name, ha->host_num); 1009*1da177e4SLinus Torvalds 1010*1da177e4SLinus Torvalds while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { 1011*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 1012*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 1013*1da177e4SLinus Torvalds ips_freescb(ha, scb); 1014*1da177e4SLinus Torvalds } 1015*1da177e4SLinus Torvalds 1016*1da177e4SLinus Torvalds /* Now fail all of the pending commands */ 1017*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Failing pending commands", 1018*1da177e4SLinus Torvalds ips_name, ha->host_num); 1019*1da177e4SLinus Torvalds 1020*1da177e4SLinus Torvalds while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { 1021*1da177e4SLinus Torvalds scsi_cmd->result = DID_ERROR << 16; 1022*1da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 1023*1da177e4SLinus Torvalds } 1024*1da177e4SLinus Torvalds 1025*1da177e4SLinus Torvalds ha->active = FALSE; 1026*1da177e4SLinus Torvalds return (FAILED); 1027*1da177e4SLinus Torvalds } 1028*1da177e4SLinus Torvalds 1029*1da177e4SLinus Torvalds /* FFDC */ 1030*1da177e4SLinus Torvalds if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) { 1031*1da177e4SLinus Torvalds struct timeval tv; 1032*1da177e4SLinus Torvalds 1033*1da177e4SLinus Torvalds do_gettimeofday(&tv); 1034*1da177e4SLinus Torvalds ha->last_ffdc = tv.tv_sec; 1035*1da177e4SLinus Torvalds ha->reset_count++; 1036*1da177e4SLinus Torvalds ips_ffdc_reset(ha, IPS_INTR_IORL); 1037*1da177e4SLinus Torvalds } 1038*1da177e4SLinus Torvalds 1039*1da177e4SLinus Torvalds /* Now fail all of the active commands */ 1040*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); 1041*1da177e4SLinus Torvalds 1042*1da177e4SLinus Torvalds while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { 1043*1da177e4SLinus Torvalds scb->scsi_cmd->result = 1044*1da177e4SLinus Torvalds (DID_RESET << 16) | (SUGGEST_RETRY << 24); 1045*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 1046*1da177e4SLinus Torvalds ips_freescb(ha, scb); 1047*1da177e4SLinus Torvalds } 1048*1da177e4SLinus Torvalds 1049*1da177e4SLinus Torvalds /* Reset DCDB active command bits */ 1050*1da177e4SLinus Torvalds for (i = 1; i < ha->nbus; i++) 1051*1da177e4SLinus Torvalds ha->dcdb_active[i - 1] = 0; 1052*1da177e4SLinus Torvalds 1053*1da177e4SLinus Torvalds /* Reset the number of active IOCTLs */ 1054*1da177e4SLinus Torvalds ha->num_ioctl = 0; 1055*1da177e4SLinus Torvalds 1056*1da177e4SLinus Torvalds ips_next(ha, IPS_INTR_IORL); 1057*1da177e4SLinus Torvalds 1058*1da177e4SLinus Torvalds return (SUCCESS); 1059*1da177e4SLinus Torvalds #endif /* NO_IPS_RESET */ 1060*1da177e4SLinus Torvalds 1061*1da177e4SLinus Torvalds } 1062*1da177e4SLinus Torvalds 1063*1da177e4SLinus Torvalds /****************************************************************************/ 1064*1da177e4SLinus Torvalds /* */ 1065*1da177e4SLinus Torvalds /* Routine Name: ips_queue */ 1066*1da177e4SLinus Torvalds /* */ 1067*1da177e4SLinus Torvalds /* Routine Description: */ 1068*1da177e4SLinus Torvalds /* */ 1069*1da177e4SLinus Torvalds /* Send a command to the controller */ 1070*1da177e4SLinus Torvalds /* */ 1071*1da177e4SLinus Torvalds /* NOTE: */ 1072*1da177e4SLinus Torvalds /* Linux obtains io_request_lock before calling this function */ 1073*1da177e4SLinus Torvalds /* */ 1074*1da177e4SLinus Torvalds /****************************************************************************/ 1075*1da177e4SLinus Torvalds static int 1076*1da177e4SLinus Torvalds ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *)) 1077*1da177e4SLinus Torvalds { 1078*1da177e4SLinus Torvalds ips_ha_t *ha; 1079*1da177e4SLinus Torvalds ips_passthru_t *pt; 1080*1da177e4SLinus Torvalds 1081*1da177e4SLinus Torvalds METHOD_TRACE("ips_queue", 1); 1082*1da177e4SLinus Torvalds 1083*1da177e4SLinus Torvalds ha = (ips_ha_t *) SC->device->host->hostdata; 1084*1da177e4SLinus Torvalds 1085*1da177e4SLinus Torvalds if (!ha) 1086*1da177e4SLinus Torvalds return (1); 1087*1da177e4SLinus Torvalds 1088*1da177e4SLinus Torvalds if (!ha->active) 1089*1da177e4SLinus Torvalds return (DID_ERROR); 1090*1da177e4SLinus Torvalds 1091*1da177e4SLinus Torvalds if (ips_is_passthru(SC)) { 1092*1da177e4SLinus Torvalds if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) { 1093*1da177e4SLinus Torvalds SC->result = DID_BUS_BUSY << 16; 1094*1da177e4SLinus Torvalds done(SC); 1095*1da177e4SLinus Torvalds 1096*1da177e4SLinus Torvalds return (0); 1097*1da177e4SLinus Torvalds } 1098*1da177e4SLinus Torvalds } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) { 1099*1da177e4SLinus Torvalds SC->result = DID_BUS_BUSY << 16; 1100*1da177e4SLinus Torvalds done(SC); 1101*1da177e4SLinus Torvalds 1102*1da177e4SLinus Torvalds return (0); 1103*1da177e4SLinus Torvalds } 1104*1da177e4SLinus Torvalds 1105*1da177e4SLinus Torvalds SC->scsi_done = done; 1106*1da177e4SLinus Torvalds 1107*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)", 1108*1da177e4SLinus Torvalds ips_name, 1109*1da177e4SLinus Torvalds ha->host_num, 1110*1da177e4SLinus Torvalds SC->cmnd[0], 1111*1da177e4SLinus Torvalds SC->device->channel, SC->device->id, SC->device->lun); 1112*1da177e4SLinus Torvalds 1113*1da177e4SLinus Torvalds /* Check for command to initiator IDs */ 1114*1da177e4SLinus Torvalds if ((SC->device->channel > 0) 1115*1da177e4SLinus Torvalds && (SC->device->id == ha->ha_id[SC->device->channel])) { 1116*1da177e4SLinus Torvalds SC->result = DID_NO_CONNECT << 16; 1117*1da177e4SLinus Torvalds done(SC); 1118*1da177e4SLinus Torvalds 1119*1da177e4SLinus Torvalds return (0); 1120*1da177e4SLinus Torvalds } 1121*1da177e4SLinus Torvalds 1122*1da177e4SLinus Torvalds if (ips_is_passthru(SC)) { 1123*1da177e4SLinus Torvalds 1124*1da177e4SLinus Torvalds ips_copp_wait_item_t *scratch; 1125*1da177e4SLinus Torvalds 1126*1da177e4SLinus Torvalds /* A Reset IOCTL is only sent by the boot CD in extreme cases. */ 1127*1da177e4SLinus Torvalds /* There can never be any system activity ( network or disk ), but check */ 1128*1da177e4SLinus Torvalds /* anyway just as a good practice. */ 1129*1da177e4SLinus Torvalds pt = (ips_passthru_t *) SC->request_buffer; 1130*1da177e4SLinus Torvalds if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) && 1131*1da177e4SLinus Torvalds (pt->CoppCP.cmd.reset.adapter_flag == 1)) { 1132*1da177e4SLinus Torvalds if (ha->scb_activelist.count != 0) { 1133*1da177e4SLinus Torvalds SC->result = DID_BUS_BUSY << 16; 1134*1da177e4SLinus Torvalds done(SC); 1135*1da177e4SLinus Torvalds return (0); 1136*1da177e4SLinus Torvalds } 1137*1da177e4SLinus Torvalds ha->ioctl_reset = 1; /* This reset request is from an IOCTL */ 1138*1da177e4SLinus Torvalds ips_eh_reset(SC); 1139*1da177e4SLinus Torvalds SC->result = DID_OK << 16; 1140*1da177e4SLinus Torvalds SC->scsi_done(SC); 1141*1da177e4SLinus Torvalds return (0); 1142*1da177e4SLinus Torvalds } 1143*1da177e4SLinus Torvalds 1144*1da177e4SLinus Torvalds /* allocate space for the scribble */ 1145*1da177e4SLinus Torvalds scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC); 1146*1da177e4SLinus Torvalds 1147*1da177e4SLinus Torvalds if (!scratch) { 1148*1da177e4SLinus Torvalds SC->result = DID_ERROR << 16; 1149*1da177e4SLinus Torvalds done(SC); 1150*1da177e4SLinus Torvalds 1151*1da177e4SLinus Torvalds return (0); 1152*1da177e4SLinus Torvalds } 1153*1da177e4SLinus Torvalds 1154*1da177e4SLinus Torvalds scratch->scsi_cmd = SC; 1155*1da177e4SLinus Torvalds scratch->next = NULL; 1156*1da177e4SLinus Torvalds 1157*1da177e4SLinus Torvalds ips_putq_copp_tail(&ha->copp_waitlist, scratch); 1158*1da177e4SLinus Torvalds } else { 1159*1da177e4SLinus Torvalds ips_putq_wait_tail(&ha->scb_waitlist, SC); 1160*1da177e4SLinus Torvalds } 1161*1da177e4SLinus Torvalds 1162*1da177e4SLinus Torvalds ips_next(ha, IPS_INTR_IORL); 1163*1da177e4SLinus Torvalds 1164*1da177e4SLinus Torvalds return (0); 1165*1da177e4SLinus Torvalds } 1166*1da177e4SLinus Torvalds 1167*1da177e4SLinus Torvalds /****************************************************************************/ 1168*1da177e4SLinus Torvalds /* */ 1169*1da177e4SLinus Torvalds /* Routine Name: ips_biosparam */ 1170*1da177e4SLinus Torvalds /* */ 1171*1da177e4SLinus Torvalds /* Routine Description: */ 1172*1da177e4SLinus Torvalds /* */ 1173*1da177e4SLinus Torvalds /* Set bios geometry for the controller */ 1174*1da177e4SLinus Torvalds /* */ 1175*1da177e4SLinus Torvalds /****************************************************************************/ 1176*1da177e4SLinus Torvalds static int 1177*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 1178*1da177e4SLinus Torvalds ips_biosparam(Disk * disk, kdev_t dev, int geom[]) 1179*1da177e4SLinus Torvalds { 1180*1da177e4SLinus Torvalds ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata; 1181*1da177e4SLinus Torvalds unsigned long capacity = disk->capacity; 1182*1da177e4SLinus Torvalds #else 1183*1da177e4SLinus Torvalds ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, 1184*1da177e4SLinus Torvalds sector_t capacity, int geom[]) 1185*1da177e4SLinus Torvalds { 1186*1da177e4SLinus Torvalds ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; 1187*1da177e4SLinus Torvalds #endif 1188*1da177e4SLinus Torvalds int heads; 1189*1da177e4SLinus Torvalds int sectors; 1190*1da177e4SLinus Torvalds int cylinders; 1191*1da177e4SLinus Torvalds 1192*1da177e4SLinus Torvalds METHOD_TRACE("ips_biosparam", 1); 1193*1da177e4SLinus Torvalds 1194*1da177e4SLinus Torvalds if (!ha) 1195*1da177e4SLinus Torvalds /* ?!?! host adater info invalid */ 1196*1da177e4SLinus Torvalds return (0); 1197*1da177e4SLinus Torvalds 1198*1da177e4SLinus Torvalds if (!ha->active) 1199*1da177e4SLinus Torvalds return (0); 1200*1da177e4SLinus Torvalds 1201*1da177e4SLinus Torvalds if (!ips_read_adapter_status(ha, IPS_INTR_ON)) 1202*1da177e4SLinus Torvalds /* ?!?! Enquiry command failed */ 1203*1da177e4SLinus Torvalds return (0); 1204*1da177e4SLinus Torvalds 1205*1da177e4SLinus Torvalds if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) { 1206*1da177e4SLinus Torvalds heads = IPS_NORM_HEADS; 1207*1da177e4SLinus Torvalds sectors = IPS_NORM_SECTORS; 1208*1da177e4SLinus Torvalds } else { 1209*1da177e4SLinus Torvalds heads = IPS_COMP_HEADS; 1210*1da177e4SLinus Torvalds sectors = IPS_COMP_SECTORS; 1211*1da177e4SLinus Torvalds } 1212*1da177e4SLinus Torvalds 1213*1da177e4SLinus Torvalds cylinders = (unsigned long) capacity / (heads * sectors); 1214*1da177e4SLinus Torvalds 1215*1da177e4SLinus Torvalds DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d", 1216*1da177e4SLinus Torvalds heads, sectors, cylinders); 1217*1da177e4SLinus Torvalds 1218*1da177e4SLinus Torvalds geom[0] = heads; 1219*1da177e4SLinus Torvalds geom[1] = sectors; 1220*1da177e4SLinus Torvalds geom[2] = cylinders; 1221*1da177e4SLinus Torvalds 1222*1da177e4SLinus Torvalds return (0); 1223*1da177e4SLinus Torvalds } 1224*1da177e4SLinus Torvalds 1225*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) 1226*1da177e4SLinus Torvalds 1227*1da177e4SLinus Torvalds /* ips_proc24_info is a wrapper around ips_proc_info * 1228*1da177e4SLinus Torvalds * for compatibility with the 2.4 scsi parameters */ 1229*1da177e4SLinus Torvalds static int 1230*1da177e4SLinus Torvalds ips_proc24_info(char *buffer, char **start, off_t offset, int length, 1231*1da177e4SLinus Torvalds int hostno, int func) 1232*1da177e4SLinus Torvalds { 1233*1da177e4SLinus Torvalds int i; 1234*1da177e4SLinus Torvalds 1235*1da177e4SLinus Torvalds for (i = 0; i < ips_next_controller; i++) { 1236*1da177e4SLinus Torvalds if (ips_sh[i] && ips_sh[i]->host_no == hostno) { 1237*1da177e4SLinus Torvalds return ips_proc_info(ips_sh[i], buffer, start, 1238*1da177e4SLinus Torvalds offset, length, func); 1239*1da177e4SLinus Torvalds } 1240*1da177e4SLinus Torvalds } 1241*1da177e4SLinus Torvalds return -EINVAL; 1242*1da177e4SLinus Torvalds } 1243*1da177e4SLinus Torvalds 1244*1da177e4SLinus Torvalds /****************************************************************************/ 1245*1da177e4SLinus Torvalds /* */ 1246*1da177e4SLinus Torvalds /* Routine Name: ips_select_queue_depth */ 1247*1da177e4SLinus Torvalds /* */ 1248*1da177e4SLinus Torvalds /* Routine Description: */ 1249*1da177e4SLinus Torvalds /* */ 1250*1da177e4SLinus Torvalds /* Select queue depths for the devices on the contoller */ 1251*1da177e4SLinus Torvalds /* */ 1252*1da177e4SLinus Torvalds /****************************************************************************/ 1253*1da177e4SLinus Torvalds static void 1254*1da177e4SLinus Torvalds ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs) 1255*1da177e4SLinus Torvalds { 1256*1da177e4SLinus Torvalds Scsi_Device *device; 1257*1da177e4SLinus Torvalds ips_ha_t *ha; 1258*1da177e4SLinus Torvalds int count = 0; 1259*1da177e4SLinus Torvalds int min; 1260*1da177e4SLinus Torvalds 1261*1da177e4SLinus Torvalds ha = IPS_HA(host); 1262*1da177e4SLinus Torvalds min = ha->max_cmds / 4; 1263*1da177e4SLinus Torvalds 1264*1da177e4SLinus Torvalds for (device = scsi_devs; device; device = device->next) { 1265*1da177e4SLinus Torvalds if (device->host == host) { 1266*1da177e4SLinus Torvalds if ((device->channel == 0) && (device->type == 0)) 1267*1da177e4SLinus Torvalds count++; 1268*1da177e4SLinus Torvalds } 1269*1da177e4SLinus Torvalds } 1270*1da177e4SLinus Torvalds 1271*1da177e4SLinus Torvalds for (device = scsi_devs; device; device = device->next) { 1272*1da177e4SLinus Torvalds if (device->host == host) { 1273*1da177e4SLinus Torvalds if ((device->channel == 0) && (device->type == 0)) { 1274*1da177e4SLinus Torvalds device->queue_depth = 1275*1da177e4SLinus Torvalds (ha->max_cmds - 1) / count; 1276*1da177e4SLinus Torvalds if (device->queue_depth < min) 1277*1da177e4SLinus Torvalds device->queue_depth = min; 1278*1da177e4SLinus Torvalds } else { 1279*1da177e4SLinus Torvalds device->queue_depth = 2; 1280*1da177e4SLinus Torvalds } 1281*1da177e4SLinus Torvalds 1282*1da177e4SLinus Torvalds if (device->queue_depth < 2) 1283*1da177e4SLinus Torvalds device->queue_depth = 2; 1284*1da177e4SLinus Torvalds } 1285*1da177e4SLinus Torvalds } 1286*1da177e4SLinus Torvalds } 1287*1da177e4SLinus Torvalds 1288*1da177e4SLinus Torvalds #else 1289*1da177e4SLinus Torvalds /****************************************************************************/ 1290*1da177e4SLinus Torvalds /* */ 1291*1da177e4SLinus Torvalds /* Routine Name: ips_slave_configure */ 1292*1da177e4SLinus Torvalds /* */ 1293*1da177e4SLinus Torvalds /* Routine Description: */ 1294*1da177e4SLinus Torvalds /* */ 1295*1da177e4SLinus Torvalds /* Set queue depths on devices once scan is complete */ 1296*1da177e4SLinus Torvalds /* */ 1297*1da177e4SLinus Torvalds /****************************************************************************/ 1298*1da177e4SLinus Torvalds static int 1299*1da177e4SLinus Torvalds ips_slave_configure(Scsi_Device * SDptr) 1300*1da177e4SLinus Torvalds { 1301*1da177e4SLinus Torvalds ips_ha_t *ha; 1302*1da177e4SLinus Torvalds int min; 1303*1da177e4SLinus Torvalds 1304*1da177e4SLinus Torvalds ha = IPS_HA(SDptr->host); 1305*1da177e4SLinus Torvalds if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) { 1306*1da177e4SLinus Torvalds min = ha->max_cmds / 2; 1307*1da177e4SLinus Torvalds if (ha->enq->ucLogDriveCount <= 2) 1308*1da177e4SLinus Torvalds min = ha->max_cmds - 1; 1309*1da177e4SLinus Torvalds scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); 1310*1da177e4SLinus Torvalds } 1311*1da177e4SLinus Torvalds return 0; 1312*1da177e4SLinus Torvalds } 1313*1da177e4SLinus Torvalds #endif 1314*1da177e4SLinus Torvalds 1315*1da177e4SLinus Torvalds /****************************************************************************/ 1316*1da177e4SLinus Torvalds /* */ 1317*1da177e4SLinus Torvalds /* Routine Name: do_ipsintr */ 1318*1da177e4SLinus Torvalds /* */ 1319*1da177e4SLinus Torvalds /* Routine Description: */ 1320*1da177e4SLinus Torvalds /* */ 1321*1da177e4SLinus Torvalds /* Wrapper for the interrupt handler */ 1322*1da177e4SLinus Torvalds /* */ 1323*1da177e4SLinus Torvalds /****************************************************************************/ 1324*1da177e4SLinus Torvalds static irqreturn_t 1325*1da177e4SLinus Torvalds do_ipsintr(int irq, void *dev_id, struct pt_regs * regs) 1326*1da177e4SLinus Torvalds { 1327*1da177e4SLinus Torvalds ips_ha_t *ha; 1328*1da177e4SLinus Torvalds unsigned long cpu_flags; 1329*1da177e4SLinus Torvalds struct Scsi_Host *host; 1330*1da177e4SLinus Torvalds int irqstatus; 1331*1da177e4SLinus Torvalds 1332*1da177e4SLinus Torvalds METHOD_TRACE("do_ipsintr", 2); 1333*1da177e4SLinus Torvalds 1334*1da177e4SLinus Torvalds ha = (ips_ha_t *) dev_id; 1335*1da177e4SLinus Torvalds if (!ha) 1336*1da177e4SLinus Torvalds return IRQ_NONE; 1337*1da177e4SLinus Torvalds host = ips_sh[ha->host_num]; 1338*1da177e4SLinus Torvalds /* interrupt during initialization */ 1339*1da177e4SLinus Torvalds if (!host) { 1340*1da177e4SLinus Torvalds (*ha->func.intr) (ha); 1341*1da177e4SLinus Torvalds return IRQ_HANDLED; 1342*1da177e4SLinus Torvalds } 1343*1da177e4SLinus Torvalds 1344*1da177e4SLinus Torvalds IPS_LOCK_SAVE(host->host_lock, cpu_flags); 1345*1da177e4SLinus Torvalds 1346*1da177e4SLinus Torvalds if (!ha->active) { 1347*1da177e4SLinus Torvalds IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); 1348*1da177e4SLinus Torvalds return IRQ_HANDLED; 1349*1da177e4SLinus Torvalds } 1350*1da177e4SLinus Torvalds 1351*1da177e4SLinus Torvalds irqstatus = (*ha->func.intr) (ha); 1352*1da177e4SLinus Torvalds 1353*1da177e4SLinus Torvalds IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); 1354*1da177e4SLinus Torvalds 1355*1da177e4SLinus Torvalds /* start the next command */ 1356*1da177e4SLinus Torvalds ips_next(ha, IPS_INTR_ON); 1357*1da177e4SLinus Torvalds return IRQ_RETVAL(irqstatus); 1358*1da177e4SLinus Torvalds } 1359*1da177e4SLinus Torvalds 1360*1da177e4SLinus Torvalds /****************************************************************************/ 1361*1da177e4SLinus Torvalds /* */ 1362*1da177e4SLinus Torvalds /* Routine Name: ips_intr_copperhead */ 1363*1da177e4SLinus Torvalds /* */ 1364*1da177e4SLinus Torvalds /* Routine Description: */ 1365*1da177e4SLinus Torvalds /* */ 1366*1da177e4SLinus Torvalds /* Polling interrupt handler */ 1367*1da177e4SLinus Torvalds /* */ 1368*1da177e4SLinus Torvalds /* ASSUMES interrupts are disabled */ 1369*1da177e4SLinus Torvalds /* */ 1370*1da177e4SLinus Torvalds /****************************************************************************/ 1371*1da177e4SLinus Torvalds int 1372*1da177e4SLinus Torvalds ips_intr_copperhead(ips_ha_t * ha) 1373*1da177e4SLinus Torvalds { 1374*1da177e4SLinus Torvalds ips_stat_t *sp; 1375*1da177e4SLinus Torvalds ips_scb_t *scb; 1376*1da177e4SLinus Torvalds IPS_STATUS cstatus; 1377*1da177e4SLinus Torvalds int intrstatus; 1378*1da177e4SLinus Torvalds 1379*1da177e4SLinus Torvalds METHOD_TRACE("ips_intr", 2); 1380*1da177e4SLinus Torvalds 1381*1da177e4SLinus Torvalds if (!ha) 1382*1da177e4SLinus Torvalds return 0; 1383*1da177e4SLinus Torvalds 1384*1da177e4SLinus Torvalds if (!ha->active) 1385*1da177e4SLinus Torvalds return 0; 1386*1da177e4SLinus Torvalds 1387*1da177e4SLinus Torvalds intrstatus = (*ha->func.isintr) (ha); 1388*1da177e4SLinus Torvalds 1389*1da177e4SLinus Torvalds if (!intrstatus) { 1390*1da177e4SLinus Torvalds /* 1391*1da177e4SLinus Torvalds * Unexpected/Shared interrupt 1392*1da177e4SLinus Torvalds */ 1393*1da177e4SLinus Torvalds 1394*1da177e4SLinus Torvalds return 0; 1395*1da177e4SLinus Torvalds } 1396*1da177e4SLinus Torvalds 1397*1da177e4SLinus Torvalds while (TRUE) { 1398*1da177e4SLinus Torvalds sp = &ha->sp; 1399*1da177e4SLinus Torvalds 1400*1da177e4SLinus Torvalds intrstatus = (*ha->func.isintr) (ha); 1401*1da177e4SLinus Torvalds 1402*1da177e4SLinus Torvalds if (!intrstatus) 1403*1da177e4SLinus Torvalds break; 1404*1da177e4SLinus Torvalds else 1405*1da177e4SLinus Torvalds cstatus.value = (*ha->func.statupd) (ha); 1406*1da177e4SLinus Torvalds 1407*1da177e4SLinus Torvalds if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { 1408*1da177e4SLinus Torvalds /* Spurious Interupt ? */ 1409*1da177e4SLinus Torvalds continue; 1410*1da177e4SLinus Torvalds } 1411*1da177e4SLinus Torvalds 1412*1da177e4SLinus Torvalds ips_chkstatus(ha, &cstatus); 1413*1da177e4SLinus Torvalds scb = (ips_scb_t *) sp->scb_addr; 1414*1da177e4SLinus Torvalds 1415*1da177e4SLinus Torvalds /* 1416*1da177e4SLinus Torvalds * use the callback function to finish things up 1417*1da177e4SLinus Torvalds * NOTE: interrupts are OFF for this 1418*1da177e4SLinus Torvalds */ 1419*1da177e4SLinus Torvalds (*scb->callback) (ha, scb); 1420*1da177e4SLinus Torvalds } /* end while */ 1421*1da177e4SLinus Torvalds return 1; 1422*1da177e4SLinus Torvalds } 1423*1da177e4SLinus Torvalds 1424*1da177e4SLinus Torvalds /****************************************************************************/ 1425*1da177e4SLinus Torvalds /* */ 1426*1da177e4SLinus Torvalds /* Routine Name: ips_intr_morpheus */ 1427*1da177e4SLinus Torvalds /* */ 1428*1da177e4SLinus Torvalds /* Routine Description: */ 1429*1da177e4SLinus Torvalds /* */ 1430*1da177e4SLinus Torvalds /* Polling interrupt handler */ 1431*1da177e4SLinus Torvalds /* */ 1432*1da177e4SLinus Torvalds /* ASSUMES interrupts are disabled */ 1433*1da177e4SLinus Torvalds /* */ 1434*1da177e4SLinus Torvalds /****************************************************************************/ 1435*1da177e4SLinus Torvalds int 1436*1da177e4SLinus Torvalds ips_intr_morpheus(ips_ha_t * ha) 1437*1da177e4SLinus Torvalds { 1438*1da177e4SLinus Torvalds ips_stat_t *sp; 1439*1da177e4SLinus Torvalds ips_scb_t *scb; 1440*1da177e4SLinus Torvalds IPS_STATUS cstatus; 1441*1da177e4SLinus Torvalds int intrstatus; 1442*1da177e4SLinus Torvalds 1443*1da177e4SLinus Torvalds METHOD_TRACE("ips_intr_morpheus", 2); 1444*1da177e4SLinus Torvalds 1445*1da177e4SLinus Torvalds if (!ha) 1446*1da177e4SLinus Torvalds return 0; 1447*1da177e4SLinus Torvalds 1448*1da177e4SLinus Torvalds if (!ha->active) 1449*1da177e4SLinus Torvalds return 0; 1450*1da177e4SLinus Torvalds 1451*1da177e4SLinus Torvalds intrstatus = (*ha->func.isintr) (ha); 1452*1da177e4SLinus Torvalds 1453*1da177e4SLinus Torvalds if (!intrstatus) { 1454*1da177e4SLinus Torvalds /* 1455*1da177e4SLinus Torvalds * Unexpected/Shared interrupt 1456*1da177e4SLinus Torvalds */ 1457*1da177e4SLinus Torvalds 1458*1da177e4SLinus Torvalds return 0; 1459*1da177e4SLinus Torvalds } 1460*1da177e4SLinus Torvalds 1461*1da177e4SLinus Torvalds while (TRUE) { 1462*1da177e4SLinus Torvalds sp = &ha->sp; 1463*1da177e4SLinus Torvalds 1464*1da177e4SLinus Torvalds intrstatus = (*ha->func.isintr) (ha); 1465*1da177e4SLinus Torvalds 1466*1da177e4SLinus Torvalds if (!intrstatus) 1467*1da177e4SLinus Torvalds break; 1468*1da177e4SLinus Torvalds else 1469*1da177e4SLinus Torvalds cstatus.value = (*ha->func.statupd) (ha); 1470*1da177e4SLinus Torvalds 1471*1da177e4SLinus Torvalds if (cstatus.value == 0xffffffff) 1472*1da177e4SLinus Torvalds /* No more to process */ 1473*1da177e4SLinus Torvalds break; 1474*1da177e4SLinus Torvalds 1475*1da177e4SLinus Torvalds if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { 1476*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 1477*1da177e4SLinus Torvalds "Spurious interrupt; no ccb.\n"); 1478*1da177e4SLinus Torvalds 1479*1da177e4SLinus Torvalds continue; 1480*1da177e4SLinus Torvalds } 1481*1da177e4SLinus Torvalds 1482*1da177e4SLinus Torvalds ips_chkstatus(ha, &cstatus); 1483*1da177e4SLinus Torvalds scb = (ips_scb_t *) sp->scb_addr; 1484*1da177e4SLinus Torvalds 1485*1da177e4SLinus Torvalds /* 1486*1da177e4SLinus Torvalds * use the callback function to finish things up 1487*1da177e4SLinus Torvalds * NOTE: interrupts are OFF for this 1488*1da177e4SLinus Torvalds */ 1489*1da177e4SLinus Torvalds (*scb->callback) (ha, scb); 1490*1da177e4SLinus Torvalds } /* end while */ 1491*1da177e4SLinus Torvalds return 1; 1492*1da177e4SLinus Torvalds } 1493*1da177e4SLinus Torvalds 1494*1da177e4SLinus Torvalds /****************************************************************************/ 1495*1da177e4SLinus Torvalds /* */ 1496*1da177e4SLinus Torvalds /* Routine Name: ips_info */ 1497*1da177e4SLinus Torvalds /* */ 1498*1da177e4SLinus Torvalds /* Routine Description: */ 1499*1da177e4SLinus Torvalds /* */ 1500*1da177e4SLinus Torvalds /* Return info about the driver */ 1501*1da177e4SLinus Torvalds /* */ 1502*1da177e4SLinus Torvalds /****************************************************************************/ 1503*1da177e4SLinus Torvalds static const char * 1504*1da177e4SLinus Torvalds ips_info(struct Scsi_Host *SH) 1505*1da177e4SLinus Torvalds { 1506*1da177e4SLinus Torvalds static char buffer[256]; 1507*1da177e4SLinus Torvalds char *bp; 1508*1da177e4SLinus Torvalds ips_ha_t *ha; 1509*1da177e4SLinus Torvalds 1510*1da177e4SLinus Torvalds METHOD_TRACE("ips_info", 1); 1511*1da177e4SLinus Torvalds 1512*1da177e4SLinus Torvalds ha = IPS_HA(SH); 1513*1da177e4SLinus Torvalds 1514*1da177e4SLinus Torvalds if (!ha) 1515*1da177e4SLinus Torvalds return (NULL); 1516*1da177e4SLinus Torvalds 1517*1da177e4SLinus Torvalds bp = &buffer[0]; 1518*1da177e4SLinus Torvalds memset(bp, 0, sizeof (buffer)); 1519*1da177e4SLinus Torvalds 1520*1da177e4SLinus Torvalds sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ", 1521*1da177e4SLinus Torvalds IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT); 1522*1da177e4SLinus Torvalds 1523*1da177e4SLinus Torvalds if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) { 1524*1da177e4SLinus Torvalds strcat(bp, " <"); 1525*1da177e4SLinus Torvalds strcat(bp, ips_adapter_name[ha->ad_type - 1]); 1526*1da177e4SLinus Torvalds strcat(bp, ">"); 1527*1da177e4SLinus Torvalds } 1528*1da177e4SLinus Torvalds 1529*1da177e4SLinus Torvalds return (bp); 1530*1da177e4SLinus Torvalds } 1531*1da177e4SLinus Torvalds 1532*1da177e4SLinus Torvalds /****************************************************************************/ 1533*1da177e4SLinus Torvalds /* */ 1534*1da177e4SLinus Torvalds /* Routine Name: ips_proc_info */ 1535*1da177e4SLinus Torvalds /* */ 1536*1da177e4SLinus Torvalds /* Routine Description: */ 1537*1da177e4SLinus Torvalds /* */ 1538*1da177e4SLinus Torvalds /* The passthru interface for the driver */ 1539*1da177e4SLinus Torvalds /* */ 1540*1da177e4SLinus Torvalds /****************************************************************************/ 1541*1da177e4SLinus Torvalds static int 1542*1da177e4SLinus Torvalds ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 1543*1da177e4SLinus Torvalds int length, int func) 1544*1da177e4SLinus Torvalds { 1545*1da177e4SLinus Torvalds int i; 1546*1da177e4SLinus Torvalds int ret; 1547*1da177e4SLinus Torvalds ips_ha_t *ha = NULL; 1548*1da177e4SLinus Torvalds 1549*1da177e4SLinus Torvalds METHOD_TRACE("ips_proc_info", 1); 1550*1da177e4SLinus Torvalds 1551*1da177e4SLinus Torvalds /* Find our host structure */ 1552*1da177e4SLinus Torvalds for (i = 0; i < ips_next_controller; i++) { 1553*1da177e4SLinus Torvalds if (ips_sh[i]) { 1554*1da177e4SLinus Torvalds if (ips_sh[i] == host) { 1555*1da177e4SLinus Torvalds ha = (ips_ha_t *) ips_sh[i]->hostdata; 1556*1da177e4SLinus Torvalds break; 1557*1da177e4SLinus Torvalds } 1558*1da177e4SLinus Torvalds } 1559*1da177e4SLinus Torvalds } 1560*1da177e4SLinus Torvalds 1561*1da177e4SLinus Torvalds if (!ha) 1562*1da177e4SLinus Torvalds return (-EINVAL); 1563*1da177e4SLinus Torvalds 1564*1da177e4SLinus Torvalds if (func) { 1565*1da177e4SLinus Torvalds /* write */ 1566*1da177e4SLinus Torvalds return (0); 1567*1da177e4SLinus Torvalds } else { 1568*1da177e4SLinus Torvalds /* read */ 1569*1da177e4SLinus Torvalds if (start) 1570*1da177e4SLinus Torvalds *start = buffer; 1571*1da177e4SLinus Torvalds 1572*1da177e4SLinus Torvalds ret = ips_host_info(ha, buffer, offset, length); 1573*1da177e4SLinus Torvalds 1574*1da177e4SLinus Torvalds return (ret); 1575*1da177e4SLinus Torvalds } 1576*1da177e4SLinus Torvalds } 1577*1da177e4SLinus Torvalds 1578*1da177e4SLinus Torvalds /*--------------------------------------------------------------------------*/ 1579*1da177e4SLinus Torvalds /* Helper Functions */ 1580*1da177e4SLinus Torvalds /*--------------------------------------------------------------------------*/ 1581*1da177e4SLinus Torvalds 1582*1da177e4SLinus Torvalds /****************************************************************************/ 1583*1da177e4SLinus Torvalds /* */ 1584*1da177e4SLinus Torvalds /* Routine Name: ips_is_passthru */ 1585*1da177e4SLinus Torvalds /* */ 1586*1da177e4SLinus Torvalds /* Routine Description: */ 1587*1da177e4SLinus Torvalds /* */ 1588*1da177e4SLinus Torvalds /* Determine if the specified SCSI command is really a passthru command */ 1589*1da177e4SLinus Torvalds /* */ 1590*1da177e4SLinus Torvalds /****************************************************************************/ 1591*1da177e4SLinus Torvalds static int 1592*1da177e4SLinus Torvalds ips_is_passthru(Scsi_Cmnd * SC) 1593*1da177e4SLinus Torvalds { 1594*1da177e4SLinus Torvalds METHOD_TRACE("ips_is_passthru", 1); 1595*1da177e4SLinus Torvalds 1596*1da177e4SLinus Torvalds if (!SC) 1597*1da177e4SLinus Torvalds return (0); 1598*1da177e4SLinus Torvalds 1599*1da177e4SLinus Torvalds if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) && 1600*1da177e4SLinus Torvalds (SC->device->channel == 0) && 1601*1da177e4SLinus Torvalds (SC->device->id == IPS_ADAPTER_ID) && 1602*1da177e4SLinus Torvalds (SC->device->lun == 0) && SC->request_buffer) { 1603*1da177e4SLinus Torvalds if ((!SC->use_sg) && SC->request_bufflen && 1604*1da177e4SLinus Torvalds (((char *) SC->request_buffer)[0] == 'C') && 1605*1da177e4SLinus Torvalds (((char *) SC->request_buffer)[1] == 'O') && 1606*1da177e4SLinus Torvalds (((char *) SC->request_buffer)[2] == 'P') && 1607*1da177e4SLinus Torvalds (((char *) SC->request_buffer)[3] == 'P')) 1608*1da177e4SLinus Torvalds return 1; 1609*1da177e4SLinus Torvalds else if (SC->use_sg) { 1610*1da177e4SLinus Torvalds struct scatterlist *sg = SC->request_buffer; 1611*1da177e4SLinus Torvalds char *buffer = IPS_SG_ADDRESS(sg); 1612*1da177e4SLinus Torvalds if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && 1613*1da177e4SLinus Torvalds buffer[2] == 'P' && buffer[3] == 'P') 1614*1da177e4SLinus Torvalds return 1; 1615*1da177e4SLinus Torvalds } 1616*1da177e4SLinus Torvalds } 1617*1da177e4SLinus Torvalds return 0; 1618*1da177e4SLinus Torvalds } 1619*1da177e4SLinus Torvalds 1620*1da177e4SLinus Torvalds /****************************************************************************/ 1621*1da177e4SLinus Torvalds /* */ 1622*1da177e4SLinus Torvalds /* Routine Name: ips_alloc_passthru_buffer */ 1623*1da177e4SLinus Torvalds /* */ 1624*1da177e4SLinus Torvalds /* Routine Description: */ 1625*1da177e4SLinus Torvalds /* allocate a buffer large enough for the ioctl data if the ioctl buffer */ 1626*1da177e4SLinus Torvalds /* is too small or doesn't exist */ 1627*1da177e4SLinus Torvalds /****************************************************************************/ 1628*1da177e4SLinus Torvalds static int 1629*1da177e4SLinus Torvalds ips_alloc_passthru_buffer(ips_ha_t * ha, int length) 1630*1da177e4SLinus Torvalds { 1631*1da177e4SLinus Torvalds void *bigger_buf; 1632*1da177e4SLinus Torvalds dma_addr_t dma_busaddr; 1633*1da177e4SLinus Torvalds 1634*1da177e4SLinus Torvalds if (ha->ioctl_data && length <= ha->ioctl_len) 1635*1da177e4SLinus Torvalds return 0; 1636*1da177e4SLinus Torvalds /* there is no buffer or it's not big enough, allocate a new one */ 1637*1da177e4SLinus Torvalds bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr); 1638*1da177e4SLinus Torvalds if (bigger_buf) { 1639*1da177e4SLinus Torvalds /* free the old memory */ 1640*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data, 1641*1da177e4SLinus Torvalds ha->ioctl_busaddr); 1642*1da177e4SLinus Torvalds /* use the new memory */ 1643*1da177e4SLinus Torvalds ha->ioctl_data = (char *) bigger_buf; 1644*1da177e4SLinus Torvalds ha->ioctl_len = length; 1645*1da177e4SLinus Torvalds ha->ioctl_busaddr = dma_busaddr; 1646*1da177e4SLinus Torvalds } else { 1647*1da177e4SLinus Torvalds return -1; 1648*1da177e4SLinus Torvalds } 1649*1da177e4SLinus Torvalds return 0; 1650*1da177e4SLinus Torvalds } 1651*1da177e4SLinus Torvalds 1652*1da177e4SLinus Torvalds /****************************************************************************/ 1653*1da177e4SLinus Torvalds /* */ 1654*1da177e4SLinus Torvalds /* Routine Name: ips_make_passthru */ 1655*1da177e4SLinus Torvalds /* */ 1656*1da177e4SLinus Torvalds /* Routine Description: */ 1657*1da177e4SLinus Torvalds /* */ 1658*1da177e4SLinus Torvalds /* Make a passthru command out of the info in the Scsi block */ 1659*1da177e4SLinus Torvalds /* */ 1660*1da177e4SLinus Torvalds /****************************************************************************/ 1661*1da177e4SLinus Torvalds static int 1662*1da177e4SLinus Torvalds ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr) 1663*1da177e4SLinus Torvalds { 1664*1da177e4SLinus Torvalds ips_passthru_t *pt; 1665*1da177e4SLinus Torvalds int length = 0; 1666*1da177e4SLinus Torvalds int ret; 1667*1da177e4SLinus Torvalds 1668*1da177e4SLinus Torvalds METHOD_TRACE("ips_make_passthru", 1); 1669*1da177e4SLinus Torvalds 1670*1da177e4SLinus Torvalds if (!SC->use_sg) { 1671*1da177e4SLinus Torvalds length = SC->request_bufflen; 1672*1da177e4SLinus Torvalds } else { 1673*1da177e4SLinus Torvalds struct scatterlist *sg = SC->request_buffer; 1674*1da177e4SLinus Torvalds int i; 1675*1da177e4SLinus Torvalds for (i = 0; i < SC->use_sg; i++) 1676*1da177e4SLinus Torvalds length += sg[i].length; 1677*1da177e4SLinus Torvalds } 1678*1da177e4SLinus Torvalds if (length < sizeof (ips_passthru_t)) { 1679*1da177e4SLinus Torvalds /* wrong size */ 1680*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", 1681*1da177e4SLinus Torvalds ips_name, ha->host_num); 1682*1da177e4SLinus Torvalds return (IPS_FAILURE); 1683*1da177e4SLinus Torvalds } 1684*1da177e4SLinus Torvalds if (ips_alloc_passthru_buffer(ha, length)) { 1685*1da177e4SLinus Torvalds /* allocation failure! If ha->ioctl_data exists, use it to return 1686*1da177e4SLinus Torvalds some error codes. Return a failed command to the scsi layer. */ 1687*1da177e4SLinus Torvalds if (ha->ioctl_data) { 1688*1da177e4SLinus Torvalds pt = (ips_passthru_t *) ha->ioctl_data; 1689*1da177e4SLinus Torvalds ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t)); 1690*1da177e4SLinus Torvalds pt->BasicStatus = 0x0B; 1691*1da177e4SLinus Torvalds pt->ExtendedStatus = 0x00; 1692*1da177e4SLinus Torvalds ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t)); 1693*1da177e4SLinus Torvalds } 1694*1da177e4SLinus Torvalds return IPS_FAILURE; 1695*1da177e4SLinus Torvalds } 1696*1da177e4SLinus Torvalds ha->ioctl_datasize = length; 1697*1da177e4SLinus Torvalds 1698*1da177e4SLinus Torvalds ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize); 1699*1da177e4SLinus Torvalds pt = (ips_passthru_t *) ha->ioctl_data; 1700*1da177e4SLinus Torvalds 1701*1da177e4SLinus Torvalds /* 1702*1da177e4SLinus Torvalds * Some notes about the passthru interface used 1703*1da177e4SLinus Torvalds * 1704*1da177e4SLinus Torvalds * IF the scsi op_code == 0x0d then we assume 1705*1da177e4SLinus Torvalds * that the data came along with/goes with the 1706*1da177e4SLinus Torvalds * packet we received from the sg driver. In this 1707*1da177e4SLinus Torvalds * case the CmdBSize field of the pt structure is 1708*1da177e4SLinus Torvalds * used for the size of the buffer. 1709*1da177e4SLinus Torvalds */ 1710*1da177e4SLinus Torvalds 1711*1da177e4SLinus Torvalds switch (pt->CoppCmd) { 1712*1da177e4SLinus Torvalds case IPS_NUMCTRLS: 1713*1da177e4SLinus Torvalds memcpy(ha->ioctl_data + sizeof (ips_passthru_t), 1714*1da177e4SLinus Torvalds &ips_num_controllers, sizeof (int)); 1715*1da177e4SLinus Torvalds ips_scmd_buf_write(SC, ha->ioctl_data, 1716*1da177e4SLinus Torvalds sizeof (ips_passthru_t) + sizeof (int)); 1717*1da177e4SLinus Torvalds SC->result = DID_OK << 16; 1718*1da177e4SLinus Torvalds 1719*1da177e4SLinus Torvalds return (IPS_SUCCESS_IMM); 1720*1da177e4SLinus Torvalds 1721*1da177e4SLinus Torvalds case IPS_COPPUSRCMD: 1722*1da177e4SLinus Torvalds case IPS_COPPIOCCMD: 1723*1da177e4SLinus Torvalds if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { 1724*1da177e4SLinus Torvalds if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) { 1725*1da177e4SLinus Torvalds /* wrong size */ 1726*1da177e4SLinus Torvalds DEBUG_VAR(1, 1727*1da177e4SLinus Torvalds "(%s%d) Passthru structure wrong size", 1728*1da177e4SLinus Torvalds ips_name, ha->host_num); 1729*1da177e4SLinus Torvalds 1730*1da177e4SLinus Torvalds return (IPS_FAILURE); 1731*1da177e4SLinus Torvalds } 1732*1da177e4SLinus Torvalds 1733*1da177e4SLinus Torvalds if (ha->device_id == IPS_DEVICEID_COPPERHEAD && 1734*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.op_code == 1735*1da177e4SLinus Torvalds IPS_CMD_RW_BIOSFW) { 1736*1da177e4SLinus Torvalds ret = ips_flash_copperhead(ha, pt, scb); 1737*1da177e4SLinus Torvalds ips_scmd_buf_write(SC, ha->ioctl_data, 1738*1da177e4SLinus Torvalds sizeof (ips_passthru_t)); 1739*1da177e4SLinus Torvalds return ret; 1740*1da177e4SLinus Torvalds } 1741*1da177e4SLinus Torvalds if (ips_usrcmd(ha, pt, scb)) 1742*1da177e4SLinus Torvalds return (IPS_SUCCESS); 1743*1da177e4SLinus Torvalds else 1744*1da177e4SLinus Torvalds return (IPS_FAILURE); 1745*1da177e4SLinus Torvalds } 1746*1da177e4SLinus Torvalds 1747*1da177e4SLinus Torvalds break; 1748*1da177e4SLinus Torvalds 1749*1da177e4SLinus Torvalds } /* end switch */ 1750*1da177e4SLinus Torvalds 1751*1da177e4SLinus Torvalds return (IPS_FAILURE); 1752*1da177e4SLinus Torvalds } 1753*1da177e4SLinus Torvalds 1754*1da177e4SLinus Torvalds /****************************************************************************/ 1755*1da177e4SLinus Torvalds /* Routine Name: ips_flash_copperhead */ 1756*1da177e4SLinus Torvalds /* Routine Description: */ 1757*1da177e4SLinus Torvalds /* Flash the BIOS/FW on a Copperhead style controller */ 1758*1da177e4SLinus Torvalds /****************************************************************************/ 1759*1da177e4SLinus Torvalds static int 1760*1da177e4SLinus Torvalds ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 1761*1da177e4SLinus Torvalds { 1762*1da177e4SLinus Torvalds int datasize; 1763*1da177e4SLinus Torvalds 1764*1da177e4SLinus Torvalds /* Trombone is the only copperhead that can do packet flash, but only 1765*1da177e4SLinus Torvalds * for firmware. No one said it had to make sence. */ 1766*1da177e4SLinus Torvalds if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { 1767*1da177e4SLinus Torvalds if (ips_usrcmd(ha, pt, scb)) 1768*1da177e4SLinus Torvalds return IPS_SUCCESS; 1769*1da177e4SLinus Torvalds else 1770*1da177e4SLinus Torvalds return IPS_FAILURE; 1771*1da177e4SLinus Torvalds } 1772*1da177e4SLinus Torvalds pt->BasicStatus = 0x0B; 1773*1da177e4SLinus Torvalds pt->ExtendedStatus = 0; 1774*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 1775*1da177e4SLinus Torvalds /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */ 1776*1da177e4SLinus Torvalds /* avoid allocating a huge buffer per adapter ( which can fail ). */ 1777*1da177e4SLinus Torvalds if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && 1778*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { 1779*1da177e4SLinus Torvalds pt->BasicStatus = 0; 1780*1da177e4SLinus Torvalds return ips_flash_bios(ha, pt, scb); 1781*1da177e4SLinus Torvalds } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) { 1782*1da177e4SLinus Torvalds if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){ 1783*1da177e4SLinus Torvalds ha->flash_data = ips_FlashData; 1784*1da177e4SLinus Torvalds ha->flash_busaddr = ips_flashbusaddr; 1785*1da177e4SLinus Torvalds ha->flash_len = PAGE_SIZE << 7; 1786*1da177e4SLinus Torvalds ha->flash_datasize = 0; 1787*1da177e4SLinus Torvalds } else if (!ha->flash_data) { 1788*1da177e4SLinus Torvalds datasize = pt->CoppCP.cmd.flashfw.total_packets * 1789*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.count; 1790*1da177e4SLinus Torvalds ha->flash_data = pci_alloc_consistent(ha->pcidev, 1791*1da177e4SLinus Torvalds datasize, 1792*1da177e4SLinus Torvalds &ha->flash_busaddr); 1793*1da177e4SLinus Torvalds if (!ha->flash_data){ 1794*1da177e4SLinus Torvalds printk(KERN_WARNING "Unable to allocate a flash buffer\n"); 1795*1da177e4SLinus Torvalds return IPS_FAILURE; 1796*1da177e4SLinus Torvalds } 1797*1da177e4SLinus Torvalds ha->flash_datasize = 0; 1798*1da177e4SLinus Torvalds ha->flash_len = datasize; 1799*1da177e4SLinus Torvalds } else 1800*1da177e4SLinus Torvalds return IPS_FAILURE; 1801*1da177e4SLinus Torvalds } else { 1802*1da177e4SLinus Torvalds if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize > 1803*1da177e4SLinus Torvalds ha->flash_len) { 1804*1da177e4SLinus Torvalds ips_free_flash_copperhead(ha); 1805*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 1806*1da177e4SLinus Torvalds "failed size sanity check\n"); 1807*1da177e4SLinus Torvalds return IPS_FAILURE; 1808*1da177e4SLinus Torvalds } 1809*1da177e4SLinus Torvalds } 1810*1da177e4SLinus Torvalds if (!ha->flash_data) 1811*1da177e4SLinus Torvalds return IPS_FAILURE; 1812*1da177e4SLinus Torvalds pt->BasicStatus = 0; 1813*1da177e4SLinus Torvalds memcpy(&ha->flash_data[ha->flash_datasize], pt + 1, 1814*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.count); 1815*1da177e4SLinus Torvalds ha->flash_datasize += pt->CoppCP.cmd.flashfw.count; 1816*1da177e4SLinus Torvalds if (pt->CoppCP.cmd.flashfw.packet_num == 1817*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.total_packets - 1) { 1818*1da177e4SLinus Torvalds if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE) 1819*1da177e4SLinus Torvalds return ips_flash_bios(ha, pt, scb); 1820*1da177e4SLinus Torvalds else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) 1821*1da177e4SLinus Torvalds return ips_flash_firmware(ha, pt, scb); 1822*1da177e4SLinus Torvalds } 1823*1da177e4SLinus Torvalds return IPS_SUCCESS_IMM; 1824*1da177e4SLinus Torvalds } 1825*1da177e4SLinus Torvalds 1826*1da177e4SLinus Torvalds /****************************************************************************/ 1827*1da177e4SLinus Torvalds /* Routine Name: ips_flash_bios */ 1828*1da177e4SLinus Torvalds /* Routine Description: */ 1829*1da177e4SLinus Torvalds /* flashes the bios of a copperhead adapter */ 1830*1da177e4SLinus Torvalds /****************************************************************************/ 1831*1da177e4SLinus Torvalds static int 1832*1da177e4SLinus Torvalds ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 1833*1da177e4SLinus Torvalds { 1834*1da177e4SLinus Torvalds 1835*1da177e4SLinus Torvalds if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && 1836*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) { 1837*1da177e4SLinus Torvalds if ((!ha->func.programbios) || (!ha->func.erasebios) || 1838*1da177e4SLinus Torvalds (!ha->func.verifybios)) 1839*1da177e4SLinus Torvalds goto error; 1840*1da177e4SLinus Torvalds if ((*ha->func.erasebios) (ha)) { 1841*1da177e4SLinus Torvalds DEBUG_VAR(1, 1842*1da177e4SLinus Torvalds "(%s%d) flash bios failed - unable to erase flash", 1843*1da177e4SLinus Torvalds ips_name, ha->host_num); 1844*1da177e4SLinus Torvalds goto error; 1845*1da177e4SLinus Torvalds } else 1846*1da177e4SLinus Torvalds if ((*ha->func.programbios) (ha, 1847*1da177e4SLinus Torvalds ha->flash_data + 1848*1da177e4SLinus Torvalds IPS_BIOS_HEADER, 1849*1da177e4SLinus Torvalds ha->flash_datasize - 1850*1da177e4SLinus Torvalds IPS_BIOS_HEADER, 0)) { 1851*1da177e4SLinus Torvalds DEBUG_VAR(1, 1852*1da177e4SLinus Torvalds "(%s%d) flash bios failed - unable to flash", 1853*1da177e4SLinus Torvalds ips_name, ha->host_num); 1854*1da177e4SLinus Torvalds goto error; 1855*1da177e4SLinus Torvalds } else 1856*1da177e4SLinus Torvalds if ((*ha->func.verifybios) (ha, 1857*1da177e4SLinus Torvalds ha->flash_data + 1858*1da177e4SLinus Torvalds IPS_BIOS_HEADER, 1859*1da177e4SLinus Torvalds ha->flash_datasize - 1860*1da177e4SLinus Torvalds IPS_BIOS_HEADER, 0)) { 1861*1da177e4SLinus Torvalds DEBUG_VAR(1, 1862*1da177e4SLinus Torvalds "(%s%d) flash bios failed - unable to verify flash", 1863*1da177e4SLinus Torvalds ips_name, ha->host_num); 1864*1da177e4SLinus Torvalds goto error; 1865*1da177e4SLinus Torvalds } 1866*1da177e4SLinus Torvalds ips_free_flash_copperhead(ha); 1867*1da177e4SLinus Torvalds return IPS_SUCCESS_IMM; 1868*1da177e4SLinus Torvalds } else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && 1869*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { 1870*1da177e4SLinus Torvalds if (!ha->func.erasebios) 1871*1da177e4SLinus Torvalds goto error; 1872*1da177e4SLinus Torvalds if ((*ha->func.erasebios) (ha)) { 1873*1da177e4SLinus Torvalds DEBUG_VAR(1, 1874*1da177e4SLinus Torvalds "(%s%d) flash bios failed - unable to erase flash", 1875*1da177e4SLinus Torvalds ips_name, ha->host_num); 1876*1da177e4SLinus Torvalds goto error; 1877*1da177e4SLinus Torvalds } 1878*1da177e4SLinus Torvalds return IPS_SUCCESS_IMM; 1879*1da177e4SLinus Torvalds } 1880*1da177e4SLinus Torvalds error: 1881*1da177e4SLinus Torvalds pt->BasicStatus = 0x0B; 1882*1da177e4SLinus Torvalds pt->ExtendedStatus = 0x00; 1883*1da177e4SLinus Torvalds ips_free_flash_copperhead(ha); 1884*1da177e4SLinus Torvalds return IPS_FAILURE; 1885*1da177e4SLinus Torvalds } 1886*1da177e4SLinus Torvalds 1887*1da177e4SLinus Torvalds /****************************************************************************/ 1888*1da177e4SLinus Torvalds /* */ 1889*1da177e4SLinus Torvalds /* Routine Name: ips_fill_scb_sg_single */ 1890*1da177e4SLinus Torvalds /* */ 1891*1da177e4SLinus Torvalds /* Routine Description: */ 1892*1da177e4SLinus Torvalds /* Fill in a single scb sg_list element from an address */ 1893*1da177e4SLinus Torvalds /* return a -1 if a breakup occurred */ 1894*1da177e4SLinus Torvalds /****************************************************************************/ 1895*1da177e4SLinus Torvalds static int 1896*1da177e4SLinus Torvalds ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, 1897*1da177e4SLinus Torvalds ips_scb_t * scb, int indx, unsigned int e_len) 1898*1da177e4SLinus Torvalds { 1899*1da177e4SLinus Torvalds 1900*1da177e4SLinus Torvalds int ret_val = 0; 1901*1da177e4SLinus Torvalds 1902*1da177e4SLinus Torvalds if ((scb->data_len + e_len) > ha->max_xfer) { 1903*1da177e4SLinus Torvalds e_len = ha->max_xfer - scb->data_len; 1904*1da177e4SLinus Torvalds scb->breakup = indx; 1905*1da177e4SLinus Torvalds ++scb->sg_break; 1906*1da177e4SLinus Torvalds ret_val = -1; 1907*1da177e4SLinus Torvalds } else { 1908*1da177e4SLinus Torvalds scb->breakup = 0; 1909*1da177e4SLinus Torvalds scb->sg_break = 0; 1910*1da177e4SLinus Torvalds } 1911*1da177e4SLinus Torvalds if (IPS_USE_ENH_SGLIST(ha)) { 1912*1da177e4SLinus Torvalds scb->sg_list.enh_list[indx].address_lo = 1913*1da177e4SLinus Torvalds cpu_to_le32(pci_dma_lo32(busaddr)); 1914*1da177e4SLinus Torvalds scb->sg_list.enh_list[indx].address_hi = 1915*1da177e4SLinus Torvalds cpu_to_le32(pci_dma_hi32(busaddr)); 1916*1da177e4SLinus Torvalds scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len); 1917*1da177e4SLinus Torvalds } else { 1918*1da177e4SLinus Torvalds scb->sg_list.std_list[indx].address = 1919*1da177e4SLinus Torvalds cpu_to_le32(pci_dma_lo32(busaddr)); 1920*1da177e4SLinus Torvalds scb->sg_list.std_list[indx].length = cpu_to_le32(e_len); 1921*1da177e4SLinus Torvalds } 1922*1da177e4SLinus Torvalds 1923*1da177e4SLinus Torvalds ++scb->sg_len; 1924*1da177e4SLinus Torvalds scb->data_len += e_len; 1925*1da177e4SLinus Torvalds return ret_val; 1926*1da177e4SLinus Torvalds } 1927*1da177e4SLinus Torvalds 1928*1da177e4SLinus Torvalds /****************************************************************************/ 1929*1da177e4SLinus Torvalds /* Routine Name: ips_flash_firmware */ 1930*1da177e4SLinus Torvalds /* Routine Description: */ 1931*1da177e4SLinus Torvalds /* flashes the firmware of a copperhead adapter */ 1932*1da177e4SLinus Torvalds /****************************************************************************/ 1933*1da177e4SLinus Torvalds static int 1934*1da177e4SLinus Torvalds ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 1935*1da177e4SLinus Torvalds { 1936*1da177e4SLinus Torvalds IPS_SG_LIST sg_list; 1937*1da177e4SLinus Torvalds uint32_t cmd_busaddr; 1938*1da177e4SLinus Torvalds 1939*1da177e4SLinus Torvalds if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE && 1940*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) { 1941*1da177e4SLinus Torvalds memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND)); 1942*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD; 1943*1da177e4SLinus Torvalds pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize); 1944*1da177e4SLinus Torvalds } else { 1945*1da177e4SLinus Torvalds pt->BasicStatus = 0x0B; 1946*1da177e4SLinus Torvalds pt->ExtendedStatus = 0x00; 1947*1da177e4SLinus Torvalds ips_free_flash_copperhead(ha); 1948*1da177e4SLinus Torvalds return IPS_FAILURE; 1949*1da177e4SLinus Torvalds } 1950*1da177e4SLinus Torvalds /* Save the S/G list pointer so it doesn't get clobbered */ 1951*1da177e4SLinus Torvalds sg_list.list = scb->sg_list.list; 1952*1da177e4SLinus Torvalds cmd_busaddr = scb->scb_busaddr; 1953*1da177e4SLinus Torvalds /* copy in the CP */ 1954*1da177e4SLinus Torvalds memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); 1955*1da177e4SLinus Torvalds /* FIX stuff that might be wrong */ 1956*1da177e4SLinus Torvalds scb->sg_list.list = sg_list.list; 1957*1da177e4SLinus Torvalds scb->scb_busaddr = cmd_busaddr; 1958*1da177e4SLinus Torvalds scb->bus = scb->scsi_cmd->device->channel; 1959*1da177e4SLinus Torvalds scb->target_id = scb->scsi_cmd->device->id; 1960*1da177e4SLinus Torvalds scb->lun = scb->scsi_cmd->device->lun; 1961*1da177e4SLinus Torvalds scb->sg_len = 0; 1962*1da177e4SLinus Torvalds scb->data_len = 0; 1963*1da177e4SLinus Torvalds scb->flags = 0; 1964*1da177e4SLinus Torvalds scb->op_code = 0; 1965*1da177e4SLinus Torvalds scb->callback = ipsintr_done; 1966*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 1967*1da177e4SLinus Torvalds 1968*1da177e4SLinus Torvalds scb->data_len = ha->flash_datasize; 1969*1da177e4SLinus Torvalds scb->data_busaddr = 1970*1da177e4SLinus Torvalds pci_map_single(ha->pcidev, ha->flash_data, scb->data_len, 1971*1da177e4SLinus Torvalds IPS_DMA_DIR(scb)); 1972*1da177e4SLinus Torvalds scb->flags |= IPS_SCB_MAP_SINGLE; 1973*1da177e4SLinus Torvalds scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); 1974*1da177e4SLinus Torvalds scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr); 1975*1da177e4SLinus Torvalds if (pt->TimeOut) 1976*1da177e4SLinus Torvalds scb->timeout = pt->TimeOut; 1977*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 1978*1da177e4SLinus Torvalds return IPS_SUCCESS; 1979*1da177e4SLinus Torvalds } 1980*1da177e4SLinus Torvalds 1981*1da177e4SLinus Torvalds /****************************************************************************/ 1982*1da177e4SLinus Torvalds /* Routine Name: ips_free_flash_copperhead */ 1983*1da177e4SLinus Torvalds /* Routine Description: */ 1984*1da177e4SLinus Torvalds /* release the memory resources used to hold the flash image */ 1985*1da177e4SLinus Torvalds /****************************************************************************/ 1986*1da177e4SLinus Torvalds static void 1987*1da177e4SLinus Torvalds ips_free_flash_copperhead(ips_ha_t * ha) 1988*1da177e4SLinus Torvalds { 1989*1da177e4SLinus Torvalds if (ha->flash_data == ips_FlashData) 1990*1da177e4SLinus Torvalds test_and_clear_bit(0, &ips_FlashDataInUse); 1991*1da177e4SLinus Torvalds else if (ha->flash_data) 1992*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data, 1993*1da177e4SLinus Torvalds ha->flash_busaddr); 1994*1da177e4SLinus Torvalds ha->flash_data = NULL; 1995*1da177e4SLinus Torvalds } 1996*1da177e4SLinus Torvalds 1997*1da177e4SLinus Torvalds /****************************************************************************/ 1998*1da177e4SLinus Torvalds /* */ 1999*1da177e4SLinus Torvalds /* Routine Name: ips_usrcmd */ 2000*1da177e4SLinus Torvalds /* */ 2001*1da177e4SLinus Torvalds /* Routine Description: */ 2002*1da177e4SLinus Torvalds /* */ 2003*1da177e4SLinus Torvalds /* Process a user command and make it ready to send */ 2004*1da177e4SLinus Torvalds /* */ 2005*1da177e4SLinus Torvalds /****************************************************************************/ 2006*1da177e4SLinus Torvalds static int 2007*1da177e4SLinus Torvalds ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 2008*1da177e4SLinus Torvalds { 2009*1da177e4SLinus Torvalds IPS_SG_LIST sg_list; 2010*1da177e4SLinus Torvalds uint32_t cmd_busaddr; 2011*1da177e4SLinus Torvalds 2012*1da177e4SLinus Torvalds METHOD_TRACE("ips_usrcmd", 1); 2013*1da177e4SLinus Torvalds 2014*1da177e4SLinus Torvalds if ((!scb) || (!pt) || (!ha)) 2015*1da177e4SLinus Torvalds return (0); 2016*1da177e4SLinus Torvalds 2017*1da177e4SLinus Torvalds /* Save the S/G list pointer so it doesn't get clobbered */ 2018*1da177e4SLinus Torvalds sg_list.list = scb->sg_list.list; 2019*1da177e4SLinus Torvalds cmd_busaddr = scb->scb_busaddr; 2020*1da177e4SLinus Torvalds /* copy in the CP */ 2021*1da177e4SLinus Torvalds memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); 2022*1da177e4SLinus Torvalds memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE)); 2023*1da177e4SLinus Torvalds 2024*1da177e4SLinus Torvalds /* FIX stuff that might be wrong */ 2025*1da177e4SLinus Torvalds scb->sg_list.list = sg_list.list; 2026*1da177e4SLinus Torvalds scb->scb_busaddr = cmd_busaddr; 2027*1da177e4SLinus Torvalds scb->bus = scb->scsi_cmd->device->channel; 2028*1da177e4SLinus Torvalds scb->target_id = scb->scsi_cmd->device->id; 2029*1da177e4SLinus Torvalds scb->lun = scb->scsi_cmd->device->lun; 2030*1da177e4SLinus Torvalds scb->sg_len = 0; 2031*1da177e4SLinus Torvalds scb->data_len = 0; 2032*1da177e4SLinus Torvalds scb->flags = 0; 2033*1da177e4SLinus Torvalds scb->op_code = 0; 2034*1da177e4SLinus Torvalds scb->callback = ipsintr_done; 2035*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 2036*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 2037*1da177e4SLinus Torvalds 2038*1da177e4SLinus Torvalds /* we don't support DCDB/READ/WRITE Scatter Gather */ 2039*1da177e4SLinus Torvalds if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) || 2040*1da177e4SLinus Torvalds (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) || 2041*1da177e4SLinus Torvalds (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG)) 2042*1da177e4SLinus Torvalds return (0); 2043*1da177e4SLinus Torvalds 2044*1da177e4SLinus Torvalds if (pt->CmdBSize) { 2045*1da177e4SLinus Torvalds scb->data_len = pt->CmdBSize; 2046*1da177e4SLinus Torvalds scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t); 2047*1da177e4SLinus Torvalds } else { 2048*1da177e4SLinus Torvalds scb->data_busaddr = 0L; 2049*1da177e4SLinus Torvalds } 2050*1da177e4SLinus Torvalds 2051*1da177e4SLinus Torvalds if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) 2052*1da177e4SLinus Torvalds scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + 2053*1da177e4SLinus Torvalds (unsigned long) &scb-> 2054*1da177e4SLinus Torvalds dcdb - 2055*1da177e4SLinus Torvalds (unsigned long) scb); 2056*1da177e4SLinus Torvalds 2057*1da177e4SLinus Torvalds if (pt->CmdBSize) { 2058*1da177e4SLinus Torvalds if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) 2059*1da177e4SLinus Torvalds scb->dcdb.buffer_pointer = 2060*1da177e4SLinus Torvalds cpu_to_le32(scb->data_busaddr); 2061*1da177e4SLinus Torvalds else 2062*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = 2063*1da177e4SLinus Torvalds cpu_to_le32(scb->data_busaddr); 2064*1da177e4SLinus Torvalds } 2065*1da177e4SLinus Torvalds 2066*1da177e4SLinus Torvalds /* set timeouts */ 2067*1da177e4SLinus Torvalds if (pt->TimeOut) { 2068*1da177e4SLinus Torvalds scb->timeout = pt->TimeOut; 2069*1da177e4SLinus Torvalds 2070*1da177e4SLinus Torvalds if (pt->TimeOut <= 10) 2071*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; 2072*1da177e4SLinus Torvalds else if (pt->TimeOut <= 60) 2073*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; 2074*1da177e4SLinus Torvalds else 2075*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; 2076*1da177e4SLinus Torvalds } 2077*1da177e4SLinus Torvalds 2078*1da177e4SLinus Torvalds /* assume success */ 2079*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 2080*1da177e4SLinus Torvalds 2081*1da177e4SLinus Torvalds /* success */ 2082*1da177e4SLinus Torvalds return (1); 2083*1da177e4SLinus Torvalds } 2084*1da177e4SLinus Torvalds 2085*1da177e4SLinus Torvalds /****************************************************************************/ 2086*1da177e4SLinus Torvalds /* */ 2087*1da177e4SLinus Torvalds /* Routine Name: ips_cleanup_passthru */ 2088*1da177e4SLinus Torvalds /* */ 2089*1da177e4SLinus Torvalds /* Routine Description: */ 2090*1da177e4SLinus Torvalds /* */ 2091*1da177e4SLinus Torvalds /* Cleanup after a passthru command */ 2092*1da177e4SLinus Torvalds /* */ 2093*1da177e4SLinus Torvalds /****************************************************************************/ 2094*1da177e4SLinus Torvalds static void 2095*1da177e4SLinus Torvalds ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) 2096*1da177e4SLinus Torvalds { 2097*1da177e4SLinus Torvalds ips_passthru_t *pt; 2098*1da177e4SLinus Torvalds 2099*1da177e4SLinus Torvalds METHOD_TRACE("ips_cleanup_passthru", 1); 2100*1da177e4SLinus Torvalds 2101*1da177e4SLinus Torvalds if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) { 2102*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru", 2103*1da177e4SLinus Torvalds ips_name, ha->host_num); 2104*1da177e4SLinus Torvalds 2105*1da177e4SLinus Torvalds return; 2106*1da177e4SLinus Torvalds } 2107*1da177e4SLinus Torvalds pt = (ips_passthru_t *) ha->ioctl_data; 2108*1da177e4SLinus Torvalds 2109*1da177e4SLinus Torvalds /* Copy data back to the user */ 2110*1da177e4SLinus Torvalds if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) /* Copy DCDB Back to Caller's Area */ 2111*1da177e4SLinus Torvalds memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE)); 2112*1da177e4SLinus Torvalds 2113*1da177e4SLinus Torvalds pt->BasicStatus = scb->basic_status; 2114*1da177e4SLinus Torvalds pt->ExtendedStatus = scb->extended_status; 2115*1da177e4SLinus Torvalds pt->AdapterType = ha->ad_type; 2116*1da177e4SLinus Torvalds 2117*1da177e4SLinus Torvalds if (ha->device_id == IPS_DEVICEID_COPPERHEAD && 2118*1da177e4SLinus Torvalds (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || 2119*1da177e4SLinus Torvalds scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)) 2120*1da177e4SLinus Torvalds ips_free_flash_copperhead(ha); 2121*1da177e4SLinus Torvalds 2122*1da177e4SLinus Torvalds ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize); 2123*1da177e4SLinus Torvalds } 2124*1da177e4SLinus Torvalds 2125*1da177e4SLinus Torvalds /****************************************************************************/ 2126*1da177e4SLinus Torvalds /* */ 2127*1da177e4SLinus Torvalds /* Routine Name: ips_host_info */ 2128*1da177e4SLinus Torvalds /* */ 2129*1da177e4SLinus Torvalds /* Routine Description: */ 2130*1da177e4SLinus Torvalds /* */ 2131*1da177e4SLinus Torvalds /* The passthru interface for the driver */ 2132*1da177e4SLinus Torvalds /* */ 2133*1da177e4SLinus Torvalds /****************************************************************************/ 2134*1da177e4SLinus Torvalds static int 2135*1da177e4SLinus Torvalds ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len) 2136*1da177e4SLinus Torvalds { 2137*1da177e4SLinus Torvalds IPS_INFOSTR info; 2138*1da177e4SLinus Torvalds 2139*1da177e4SLinus Torvalds METHOD_TRACE("ips_host_info", 1); 2140*1da177e4SLinus Torvalds 2141*1da177e4SLinus Torvalds info.buffer = ptr; 2142*1da177e4SLinus Torvalds info.length = len; 2143*1da177e4SLinus Torvalds info.offset = offset; 2144*1da177e4SLinus Torvalds info.pos = 0; 2145*1da177e4SLinus Torvalds info.localpos = 0; 2146*1da177e4SLinus Torvalds 2147*1da177e4SLinus Torvalds copy_info(&info, "\nIBM ServeRAID General Information:\n\n"); 2148*1da177e4SLinus Torvalds 2149*1da177e4SLinus Torvalds if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) && 2150*1da177e4SLinus Torvalds (le16_to_cpu(ha->nvram->adapter_type) != 0)) 2151*1da177e4SLinus Torvalds copy_info(&info, "\tController Type : %s\n", 2152*1da177e4SLinus Torvalds ips_adapter_name[ha->ad_type - 1]); 2153*1da177e4SLinus Torvalds else 2154*1da177e4SLinus Torvalds copy_info(&info, 2155*1da177e4SLinus Torvalds "\tController Type : Unknown\n"); 2156*1da177e4SLinus Torvalds 2157*1da177e4SLinus Torvalds if (ha->io_addr) 2158*1da177e4SLinus Torvalds copy_info(&info, 2159*1da177e4SLinus Torvalds "\tIO region : 0x%lx (%d bytes)\n", 2160*1da177e4SLinus Torvalds ha->io_addr, ha->io_len); 2161*1da177e4SLinus Torvalds 2162*1da177e4SLinus Torvalds if (ha->mem_addr) { 2163*1da177e4SLinus Torvalds copy_info(&info, 2164*1da177e4SLinus Torvalds "\tMemory region : 0x%lx (%d bytes)\n", 2165*1da177e4SLinus Torvalds ha->mem_addr, ha->mem_len); 2166*1da177e4SLinus Torvalds copy_info(&info, 2167*1da177e4SLinus Torvalds "\tShared memory address : 0x%lx\n", 2168*1da177e4SLinus Torvalds ha->mem_ptr); 2169*1da177e4SLinus Torvalds } 2170*1da177e4SLinus Torvalds 2171*1da177e4SLinus Torvalds copy_info(&info, "\tIRQ number : %d\n", ha->irq); 2172*1da177e4SLinus Torvalds 2173*1da177e4SLinus Torvalds /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */ 2174*1da177e4SLinus Torvalds /* That keeps everything happy for "text" operations on the proc file. */ 2175*1da177e4SLinus Torvalds 2176*1da177e4SLinus Torvalds if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) { 2177*1da177e4SLinus Torvalds if (ha->nvram->bios_low[3] == 0) { 2178*1da177e4SLinus Torvalds copy_info(&info, 2179*1da177e4SLinus Torvalds "\tBIOS Version : %c%c%c%c%c%c%c\n", 2180*1da177e4SLinus Torvalds ha->nvram->bios_high[0], ha->nvram->bios_high[1], 2181*1da177e4SLinus Torvalds ha->nvram->bios_high[2], ha->nvram->bios_high[3], 2182*1da177e4SLinus Torvalds ha->nvram->bios_low[0], ha->nvram->bios_low[1], 2183*1da177e4SLinus Torvalds ha->nvram->bios_low[2]); 2184*1da177e4SLinus Torvalds 2185*1da177e4SLinus Torvalds } else { 2186*1da177e4SLinus Torvalds copy_info(&info, 2187*1da177e4SLinus Torvalds "\tBIOS Version : %c%c%c%c%c%c%c%c\n", 2188*1da177e4SLinus Torvalds ha->nvram->bios_high[0], ha->nvram->bios_high[1], 2189*1da177e4SLinus Torvalds ha->nvram->bios_high[2], ha->nvram->bios_high[3], 2190*1da177e4SLinus Torvalds ha->nvram->bios_low[0], ha->nvram->bios_low[1], 2191*1da177e4SLinus Torvalds ha->nvram->bios_low[2], ha->nvram->bios_low[3]); 2192*1da177e4SLinus Torvalds } 2193*1da177e4SLinus Torvalds 2194*1da177e4SLinus Torvalds } 2195*1da177e4SLinus Torvalds 2196*1da177e4SLinus Torvalds if (ha->enq->CodeBlkVersion[7] == 0) { 2197*1da177e4SLinus Torvalds copy_info(&info, 2198*1da177e4SLinus Torvalds "\tFirmware Version : %c%c%c%c%c%c%c\n", 2199*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], 2200*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], 2201*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], 2202*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[6]); 2203*1da177e4SLinus Torvalds } else { 2204*1da177e4SLinus Torvalds copy_info(&info, 2205*1da177e4SLinus Torvalds "\tFirmware Version : %c%c%c%c%c%c%c%c\n", 2206*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], 2207*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], 2208*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], 2209*1da177e4SLinus Torvalds ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]); 2210*1da177e4SLinus Torvalds } 2211*1da177e4SLinus Torvalds 2212*1da177e4SLinus Torvalds if (ha->enq->BootBlkVersion[7] == 0) { 2213*1da177e4SLinus Torvalds copy_info(&info, 2214*1da177e4SLinus Torvalds "\tBoot Block Version : %c%c%c%c%c%c%c\n", 2215*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], 2216*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], 2217*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], 2218*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[6]); 2219*1da177e4SLinus Torvalds } else { 2220*1da177e4SLinus Torvalds copy_info(&info, 2221*1da177e4SLinus Torvalds "\tBoot Block Version : %c%c%c%c%c%c%c%c\n", 2222*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], 2223*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], 2224*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], 2225*1da177e4SLinus Torvalds ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]); 2226*1da177e4SLinus Torvalds } 2227*1da177e4SLinus Torvalds 2228*1da177e4SLinus Torvalds copy_info(&info, "\tDriver Version : %s%s\n", 2229*1da177e4SLinus Torvalds IPS_VERSION_HIGH, IPS_VERSION_LOW); 2230*1da177e4SLinus Torvalds 2231*1da177e4SLinus Torvalds copy_info(&info, "\tDriver Build : %d\n", 2232*1da177e4SLinus Torvalds IPS_BUILD_IDENT); 2233*1da177e4SLinus Torvalds 2234*1da177e4SLinus Torvalds copy_info(&info, "\tMax Physical Devices : %d\n", 2235*1da177e4SLinus Torvalds ha->enq->ucMaxPhysicalDevices); 2236*1da177e4SLinus Torvalds copy_info(&info, "\tMax Active Commands : %d\n", 2237*1da177e4SLinus Torvalds ha->max_cmds); 2238*1da177e4SLinus Torvalds copy_info(&info, "\tCurrent Queued Commands : %d\n", 2239*1da177e4SLinus Torvalds ha->scb_waitlist.count); 2240*1da177e4SLinus Torvalds copy_info(&info, "\tCurrent Active Commands : %d\n", 2241*1da177e4SLinus Torvalds ha->scb_activelist.count - ha->num_ioctl); 2242*1da177e4SLinus Torvalds copy_info(&info, "\tCurrent Queued PT Commands : %d\n", 2243*1da177e4SLinus Torvalds ha->copp_waitlist.count); 2244*1da177e4SLinus Torvalds copy_info(&info, "\tCurrent Active PT Commands : %d\n", 2245*1da177e4SLinus Torvalds ha->num_ioctl); 2246*1da177e4SLinus Torvalds 2247*1da177e4SLinus Torvalds copy_info(&info, "\n"); 2248*1da177e4SLinus Torvalds 2249*1da177e4SLinus Torvalds return (info.localpos); 2250*1da177e4SLinus Torvalds } 2251*1da177e4SLinus Torvalds 2252*1da177e4SLinus Torvalds /****************************************************************************/ 2253*1da177e4SLinus Torvalds /* */ 2254*1da177e4SLinus Torvalds /* Routine Name: copy_mem_info */ 2255*1da177e4SLinus Torvalds /* */ 2256*1da177e4SLinus Torvalds /* Routine Description: */ 2257*1da177e4SLinus Torvalds /* */ 2258*1da177e4SLinus Torvalds /* Copy data into an IPS_INFOSTR structure */ 2259*1da177e4SLinus Torvalds /* */ 2260*1da177e4SLinus Torvalds /****************************************************************************/ 2261*1da177e4SLinus Torvalds static void 2262*1da177e4SLinus Torvalds copy_mem_info(IPS_INFOSTR * info, char *data, int len) 2263*1da177e4SLinus Torvalds { 2264*1da177e4SLinus Torvalds METHOD_TRACE("copy_mem_info", 1); 2265*1da177e4SLinus Torvalds 2266*1da177e4SLinus Torvalds if (info->pos + len < info->offset) { 2267*1da177e4SLinus Torvalds info->pos += len; 2268*1da177e4SLinus Torvalds return; 2269*1da177e4SLinus Torvalds } 2270*1da177e4SLinus Torvalds 2271*1da177e4SLinus Torvalds if (info->pos < info->offset) { 2272*1da177e4SLinus Torvalds data += (info->offset - info->pos); 2273*1da177e4SLinus Torvalds len -= (info->offset - info->pos); 2274*1da177e4SLinus Torvalds info->pos += (info->offset - info->pos); 2275*1da177e4SLinus Torvalds } 2276*1da177e4SLinus Torvalds 2277*1da177e4SLinus Torvalds if (info->localpos + len > info->length) 2278*1da177e4SLinus Torvalds len = info->length - info->localpos; 2279*1da177e4SLinus Torvalds 2280*1da177e4SLinus Torvalds if (len > 0) { 2281*1da177e4SLinus Torvalds memcpy(info->buffer + info->localpos, data, len); 2282*1da177e4SLinus Torvalds info->pos += len; 2283*1da177e4SLinus Torvalds info->localpos += len; 2284*1da177e4SLinus Torvalds } 2285*1da177e4SLinus Torvalds } 2286*1da177e4SLinus Torvalds 2287*1da177e4SLinus Torvalds /****************************************************************************/ 2288*1da177e4SLinus Torvalds /* */ 2289*1da177e4SLinus Torvalds /* Routine Name: copy_info */ 2290*1da177e4SLinus Torvalds /* */ 2291*1da177e4SLinus Torvalds /* Routine Description: */ 2292*1da177e4SLinus Torvalds /* */ 2293*1da177e4SLinus Torvalds /* printf style wrapper for an info structure */ 2294*1da177e4SLinus Torvalds /* */ 2295*1da177e4SLinus Torvalds /****************************************************************************/ 2296*1da177e4SLinus Torvalds static int 2297*1da177e4SLinus Torvalds copy_info(IPS_INFOSTR * info, char *fmt, ...) 2298*1da177e4SLinus Torvalds { 2299*1da177e4SLinus Torvalds va_list args; 2300*1da177e4SLinus Torvalds char buf[128]; 2301*1da177e4SLinus Torvalds int len; 2302*1da177e4SLinus Torvalds 2303*1da177e4SLinus Torvalds METHOD_TRACE("copy_info", 1); 2304*1da177e4SLinus Torvalds 2305*1da177e4SLinus Torvalds va_start(args, fmt); 2306*1da177e4SLinus Torvalds len = vsprintf(buf, fmt, args); 2307*1da177e4SLinus Torvalds va_end(args); 2308*1da177e4SLinus Torvalds 2309*1da177e4SLinus Torvalds copy_mem_info(info, buf, len); 2310*1da177e4SLinus Torvalds 2311*1da177e4SLinus Torvalds return (len); 2312*1da177e4SLinus Torvalds } 2313*1da177e4SLinus Torvalds 2314*1da177e4SLinus Torvalds /****************************************************************************/ 2315*1da177e4SLinus Torvalds /* */ 2316*1da177e4SLinus Torvalds /* Routine Name: ips_identify_controller */ 2317*1da177e4SLinus Torvalds /* */ 2318*1da177e4SLinus Torvalds /* Routine Description: */ 2319*1da177e4SLinus Torvalds /* */ 2320*1da177e4SLinus Torvalds /* Identify this controller */ 2321*1da177e4SLinus Torvalds /* */ 2322*1da177e4SLinus Torvalds /****************************************************************************/ 2323*1da177e4SLinus Torvalds static void 2324*1da177e4SLinus Torvalds ips_identify_controller(ips_ha_t * ha) 2325*1da177e4SLinus Torvalds { 2326*1da177e4SLinus Torvalds METHOD_TRACE("ips_identify_controller", 1); 2327*1da177e4SLinus Torvalds 2328*1da177e4SLinus Torvalds switch (ha->device_id) { 2329*1da177e4SLinus Torvalds case IPS_DEVICEID_COPPERHEAD: 2330*1da177e4SLinus Torvalds if (ha->revision_id <= IPS_REVID_SERVERAID) { 2331*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID; 2332*1da177e4SLinus Torvalds } else if (ha->revision_id == IPS_REVID_SERVERAID2) { 2333*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID2; 2334*1da177e4SLinus Torvalds } else if (ha->revision_id == IPS_REVID_NAVAJO) { 2335*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_NAVAJO; 2336*1da177e4SLinus Torvalds } else if ((ha->revision_id == IPS_REVID_SERVERAID2) 2337*1da177e4SLinus Torvalds && (ha->slot_num == 0)) { 2338*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_KIOWA; 2339*1da177e4SLinus Torvalds } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) && 2340*1da177e4SLinus Torvalds (ha->revision_id <= IPS_REVID_CLARINETP3)) { 2341*1da177e4SLinus Torvalds if (ha->enq->ucMaxPhysicalDevices == 15) 2342*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID3L; 2343*1da177e4SLinus Torvalds else 2344*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID3; 2345*1da177e4SLinus Torvalds } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) && 2346*1da177e4SLinus Torvalds (ha->revision_id <= IPS_REVID_TROMBONE64)) { 2347*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID4H; 2348*1da177e4SLinus Torvalds } 2349*1da177e4SLinus Torvalds break; 2350*1da177e4SLinus Torvalds 2351*1da177e4SLinus Torvalds case IPS_DEVICEID_MORPHEUS: 2352*1da177e4SLinus Torvalds switch (ha->subdevice_id) { 2353*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_4L: 2354*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID4L; 2355*1da177e4SLinus Torvalds break; 2356*1da177e4SLinus Torvalds 2357*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_4M: 2358*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID4M; 2359*1da177e4SLinus Torvalds break; 2360*1da177e4SLinus Torvalds 2361*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_4MX: 2362*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID4MX; 2363*1da177e4SLinus Torvalds break; 2364*1da177e4SLinus Torvalds 2365*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_4LX: 2366*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID4LX; 2367*1da177e4SLinus Torvalds break; 2368*1da177e4SLinus Torvalds 2369*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_5I2: 2370*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID5I2; 2371*1da177e4SLinus Torvalds break; 2372*1da177e4SLinus Torvalds 2373*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_5I1: 2374*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID5I1; 2375*1da177e4SLinus Torvalds break; 2376*1da177e4SLinus Torvalds } 2377*1da177e4SLinus Torvalds 2378*1da177e4SLinus Torvalds break; 2379*1da177e4SLinus Torvalds 2380*1da177e4SLinus Torvalds case IPS_DEVICEID_MARCO: 2381*1da177e4SLinus Torvalds switch (ha->subdevice_id) { 2382*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_6M: 2383*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID6M; 2384*1da177e4SLinus Torvalds break; 2385*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_6I: 2386*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID6I; 2387*1da177e4SLinus Torvalds break; 2388*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_7k: 2389*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID7k; 2390*1da177e4SLinus Torvalds break; 2391*1da177e4SLinus Torvalds case IPS_SUBDEVICEID_7M: 2392*1da177e4SLinus Torvalds ha->ad_type = IPS_ADTYPE_SERVERAID7M; 2393*1da177e4SLinus Torvalds break; 2394*1da177e4SLinus Torvalds } 2395*1da177e4SLinus Torvalds break; 2396*1da177e4SLinus Torvalds } 2397*1da177e4SLinus Torvalds } 2398*1da177e4SLinus Torvalds 2399*1da177e4SLinus Torvalds /****************************************************************************/ 2400*1da177e4SLinus Torvalds /* */ 2401*1da177e4SLinus Torvalds /* Routine Name: ips_get_bios_version */ 2402*1da177e4SLinus Torvalds /* */ 2403*1da177e4SLinus Torvalds /* Routine Description: */ 2404*1da177e4SLinus Torvalds /* */ 2405*1da177e4SLinus Torvalds /* Get the BIOS revision number */ 2406*1da177e4SLinus Torvalds /* */ 2407*1da177e4SLinus Torvalds /****************************************************************************/ 2408*1da177e4SLinus Torvalds static void 2409*1da177e4SLinus Torvalds ips_get_bios_version(ips_ha_t * ha, int intr) 2410*1da177e4SLinus Torvalds { 2411*1da177e4SLinus Torvalds ips_scb_t *scb; 2412*1da177e4SLinus Torvalds int ret; 2413*1da177e4SLinus Torvalds uint8_t major; 2414*1da177e4SLinus Torvalds uint8_t minor; 2415*1da177e4SLinus Torvalds uint8_t subminor; 2416*1da177e4SLinus Torvalds uint8_t *buffer; 2417*1da177e4SLinus Torvalds char hexDigits[] = 2418*1da177e4SLinus Torvalds { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 2419*1da177e4SLinus Torvalds 'D', 'E', 'F' }; 2420*1da177e4SLinus Torvalds 2421*1da177e4SLinus Torvalds METHOD_TRACE("ips_get_bios_version", 1); 2422*1da177e4SLinus Torvalds 2423*1da177e4SLinus Torvalds major = 0; 2424*1da177e4SLinus Torvalds minor = 0; 2425*1da177e4SLinus Torvalds 2426*1da177e4SLinus Torvalds strncpy(ha->bios_version, " ?", 8); 2427*1da177e4SLinus Torvalds 2428*1da177e4SLinus Torvalds if (ha->device_id == IPS_DEVICEID_COPPERHEAD) { 2429*1da177e4SLinus Torvalds if (IPS_USE_MEMIO(ha)) { 2430*1da177e4SLinus Torvalds /* Memory Mapped I/O */ 2431*1da177e4SLinus Torvalds 2432*1da177e4SLinus Torvalds /* test 1st byte */ 2433*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 2434*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2435*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2436*1da177e4SLinus Torvalds 2437*1da177e4SLinus Torvalds if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) 2438*1da177e4SLinus Torvalds return; 2439*1da177e4SLinus Torvalds 2440*1da177e4SLinus Torvalds writel(1, ha->mem_ptr + IPS_REG_FLAP); 2441*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2442*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2443*1da177e4SLinus Torvalds 2444*1da177e4SLinus Torvalds if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) 2445*1da177e4SLinus Torvalds return; 2446*1da177e4SLinus Torvalds 2447*1da177e4SLinus Torvalds /* Get Major version */ 2448*1da177e4SLinus Torvalds writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); 2449*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2450*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2451*1da177e4SLinus Torvalds 2452*1da177e4SLinus Torvalds major = readb(ha->mem_ptr + IPS_REG_FLDP); 2453*1da177e4SLinus Torvalds 2454*1da177e4SLinus Torvalds /* Get Minor version */ 2455*1da177e4SLinus Torvalds writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); 2456*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2457*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2458*1da177e4SLinus Torvalds minor = readb(ha->mem_ptr + IPS_REG_FLDP); 2459*1da177e4SLinus Torvalds 2460*1da177e4SLinus Torvalds /* Get SubMinor version */ 2461*1da177e4SLinus Torvalds writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); 2462*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2463*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2464*1da177e4SLinus Torvalds subminor = readb(ha->mem_ptr + IPS_REG_FLDP); 2465*1da177e4SLinus Torvalds 2466*1da177e4SLinus Torvalds } else { 2467*1da177e4SLinus Torvalds /* Programmed I/O */ 2468*1da177e4SLinus Torvalds 2469*1da177e4SLinus Torvalds /* test 1st byte */ 2470*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 2471*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2472*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2473*1da177e4SLinus Torvalds 2474*1da177e4SLinus Torvalds if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) 2475*1da177e4SLinus Torvalds return; 2476*1da177e4SLinus Torvalds 2477*1da177e4SLinus Torvalds outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); 2478*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2479*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2480*1da177e4SLinus Torvalds 2481*1da177e4SLinus Torvalds if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) 2482*1da177e4SLinus Torvalds return; 2483*1da177e4SLinus Torvalds 2484*1da177e4SLinus Torvalds /* Get Major version */ 2485*1da177e4SLinus Torvalds outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP); 2486*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2487*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2488*1da177e4SLinus Torvalds 2489*1da177e4SLinus Torvalds major = inb(ha->io_addr + IPS_REG_FLDP); 2490*1da177e4SLinus Torvalds 2491*1da177e4SLinus Torvalds /* Get Minor version */ 2492*1da177e4SLinus Torvalds outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP); 2493*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2494*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2495*1da177e4SLinus Torvalds 2496*1da177e4SLinus Torvalds minor = inb(ha->io_addr + IPS_REG_FLDP); 2497*1da177e4SLinus Torvalds 2498*1da177e4SLinus Torvalds /* Get SubMinor version */ 2499*1da177e4SLinus Torvalds outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP); 2500*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 2501*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 2502*1da177e4SLinus Torvalds 2503*1da177e4SLinus Torvalds subminor = inb(ha->io_addr + IPS_REG_FLDP); 2504*1da177e4SLinus Torvalds 2505*1da177e4SLinus Torvalds } 2506*1da177e4SLinus Torvalds } else { 2507*1da177e4SLinus Torvalds /* Morpheus Family - Send Command to the card */ 2508*1da177e4SLinus Torvalds 2509*1da177e4SLinus Torvalds buffer = ha->ioctl_data; 2510*1da177e4SLinus Torvalds 2511*1da177e4SLinus Torvalds memset(buffer, 0, 0x1000); 2512*1da177e4SLinus Torvalds 2513*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 2514*1da177e4SLinus Torvalds 2515*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 2516*1da177e4SLinus Torvalds 2517*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 2518*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_RW_BIOSFW; 2519*1da177e4SLinus Torvalds 2520*1da177e4SLinus Torvalds scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW; 2521*1da177e4SLinus Torvalds scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); 2522*1da177e4SLinus Torvalds scb->cmd.flashfw.type = 1; 2523*1da177e4SLinus Torvalds scb->cmd.flashfw.direction = 0; 2524*1da177e4SLinus Torvalds scb->cmd.flashfw.count = cpu_to_le32(0x800); 2525*1da177e4SLinus Torvalds scb->cmd.flashfw.total_packets = 1; 2526*1da177e4SLinus Torvalds scb->cmd.flashfw.packet_num = 0; 2527*1da177e4SLinus Torvalds scb->data_len = 0x1000; 2528*1da177e4SLinus Torvalds scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr; 2529*1da177e4SLinus Torvalds 2530*1da177e4SLinus Torvalds /* issue the command */ 2531*1da177e4SLinus Torvalds if (((ret = 2532*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, 2533*1da177e4SLinus Torvalds intr)) == IPS_FAILURE) 2534*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 2535*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { 2536*1da177e4SLinus Torvalds /* Error occurred */ 2537*1da177e4SLinus Torvalds 2538*1da177e4SLinus Torvalds return; 2539*1da177e4SLinus Torvalds } 2540*1da177e4SLinus Torvalds 2541*1da177e4SLinus Torvalds if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) { 2542*1da177e4SLinus Torvalds major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */ 2543*1da177e4SLinus Torvalds minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */ 2544*1da177e4SLinus Torvalds subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fd after the header (0xc0) */ 2545*1da177e4SLinus Torvalds } else { 2546*1da177e4SLinus Torvalds return; 2547*1da177e4SLinus Torvalds } 2548*1da177e4SLinus Torvalds } 2549*1da177e4SLinus Torvalds 2550*1da177e4SLinus Torvalds ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4]; 2551*1da177e4SLinus Torvalds ha->bios_version[1] = '.'; 2552*1da177e4SLinus Torvalds ha->bios_version[2] = hexDigits[major & 0x0F]; 2553*1da177e4SLinus Torvalds ha->bios_version[3] = hexDigits[subminor]; 2554*1da177e4SLinus Torvalds ha->bios_version[4] = '.'; 2555*1da177e4SLinus Torvalds ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4]; 2556*1da177e4SLinus Torvalds ha->bios_version[6] = hexDigits[minor & 0x0F]; 2557*1da177e4SLinus Torvalds ha->bios_version[7] = 0; 2558*1da177e4SLinus Torvalds } 2559*1da177e4SLinus Torvalds 2560*1da177e4SLinus Torvalds /****************************************************************************/ 2561*1da177e4SLinus Torvalds /* */ 2562*1da177e4SLinus Torvalds /* Routine Name: ips_hainit */ 2563*1da177e4SLinus Torvalds /* */ 2564*1da177e4SLinus Torvalds /* Routine Description: */ 2565*1da177e4SLinus Torvalds /* */ 2566*1da177e4SLinus Torvalds /* Initialize the controller */ 2567*1da177e4SLinus Torvalds /* */ 2568*1da177e4SLinus Torvalds /* NOTE: Assumes to be called from with a lock */ 2569*1da177e4SLinus Torvalds /* */ 2570*1da177e4SLinus Torvalds /****************************************************************************/ 2571*1da177e4SLinus Torvalds static int 2572*1da177e4SLinus Torvalds ips_hainit(ips_ha_t * ha) 2573*1da177e4SLinus Torvalds { 2574*1da177e4SLinus Torvalds int i; 2575*1da177e4SLinus Torvalds struct timeval tv; 2576*1da177e4SLinus Torvalds 2577*1da177e4SLinus Torvalds METHOD_TRACE("ips_hainit", 1); 2578*1da177e4SLinus Torvalds 2579*1da177e4SLinus Torvalds if (!ha) 2580*1da177e4SLinus Torvalds return (0); 2581*1da177e4SLinus Torvalds 2582*1da177e4SLinus Torvalds if (ha->func.statinit) 2583*1da177e4SLinus Torvalds (*ha->func.statinit) (ha); 2584*1da177e4SLinus Torvalds 2585*1da177e4SLinus Torvalds if (ha->func.enableint) 2586*1da177e4SLinus Torvalds (*ha->func.enableint) (ha); 2587*1da177e4SLinus Torvalds 2588*1da177e4SLinus Torvalds /* Send FFDC */ 2589*1da177e4SLinus Torvalds ha->reset_count = 1; 2590*1da177e4SLinus Torvalds do_gettimeofday(&tv); 2591*1da177e4SLinus Torvalds ha->last_ffdc = tv.tv_sec; 2592*1da177e4SLinus Torvalds ips_ffdc_reset(ha, IPS_INTR_IORL); 2593*1da177e4SLinus Torvalds 2594*1da177e4SLinus Torvalds if (!ips_read_config(ha, IPS_INTR_IORL)) { 2595*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 2596*1da177e4SLinus Torvalds "unable to read config from controller.\n"); 2597*1da177e4SLinus Torvalds 2598*1da177e4SLinus Torvalds return (0); 2599*1da177e4SLinus Torvalds } 2600*1da177e4SLinus Torvalds /* end if */ 2601*1da177e4SLinus Torvalds if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) { 2602*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 2603*1da177e4SLinus Torvalds "unable to read controller status.\n"); 2604*1da177e4SLinus Torvalds 2605*1da177e4SLinus Torvalds return (0); 2606*1da177e4SLinus Torvalds } 2607*1da177e4SLinus Torvalds 2608*1da177e4SLinus Torvalds /* Identify this controller */ 2609*1da177e4SLinus Torvalds ips_identify_controller(ha); 2610*1da177e4SLinus Torvalds 2611*1da177e4SLinus Torvalds if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) { 2612*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 2613*1da177e4SLinus Torvalds "unable to read subsystem parameters.\n"); 2614*1da177e4SLinus Torvalds 2615*1da177e4SLinus Torvalds return (0); 2616*1da177e4SLinus Torvalds } 2617*1da177e4SLinus Torvalds 2618*1da177e4SLinus Torvalds /* write nvram user page 5 */ 2619*1da177e4SLinus Torvalds if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { 2620*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 2621*1da177e4SLinus Torvalds "unable to write driver info to controller.\n"); 2622*1da177e4SLinus Torvalds 2623*1da177e4SLinus Torvalds return (0); 2624*1da177e4SLinus Torvalds } 2625*1da177e4SLinus Torvalds 2626*1da177e4SLinus Torvalds /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */ 2627*1da177e4SLinus Torvalds if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1)) 2628*1da177e4SLinus Torvalds ips_clear_adapter(ha, IPS_INTR_IORL); 2629*1da177e4SLinus Torvalds 2630*1da177e4SLinus Torvalds /* set limits on SID, LUN, BUS */ 2631*1da177e4SLinus Torvalds ha->ntargets = IPS_MAX_TARGETS + 1; 2632*1da177e4SLinus Torvalds ha->nlun = 1; 2633*1da177e4SLinus Torvalds ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1; 2634*1da177e4SLinus Torvalds 2635*1da177e4SLinus Torvalds switch (ha->conf->logical_drive[0].ucStripeSize) { 2636*1da177e4SLinus Torvalds case 4: 2637*1da177e4SLinus Torvalds ha->max_xfer = 0x10000; 2638*1da177e4SLinus Torvalds break; 2639*1da177e4SLinus Torvalds 2640*1da177e4SLinus Torvalds case 5: 2641*1da177e4SLinus Torvalds ha->max_xfer = 0x20000; 2642*1da177e4SLinus Torvalds break; 2643*1da177e4SLinus Torvalds 2644*1da177e4SLinus Torvalds case 6: 2645*1da177e4SLinus Torvalds ha->max_xfer = 0x40000; 2646*1da177e4SLinus Torvalds break; 2647*1da177e4SLinus Torvalds 2648*1da177e4SLinus Torvalds case 7: 2649*1da177e4SLinus Torvalds default: 2650*1da177e4SLinus Torvalds ha->max_xfer = 0x80000; 2651*1da177e4SLinus Torvalds break; 2652*1da177e4SLinus Torvalds } 2653*1da177e4SLinus Torvalds 2654*1da177e4SLinus Torvalds /* setup max concurrent commands */ 2655*1da177e4SLinus Torvalds if (le32_to_cpu(ha->subsys->param[4]) & 0x1) { 2656*1da177e4SLinus Torvalds /* Use the new method */ 2657*1da177e4SLinus Torvalds ha->max_cmds = ha->enq->ucConcurrentCmdCount; 2658*1da177e4SLinus Torvalds } else { 2659*1da177e4SLinus Torvalds /* use the old method */ 2660*1da177e4SLinus Torvalds switch (ha->conf->logical_drive[0].ucStripeSize) { 2661*1da177e4SLinus Torvalds case 4: 2662*1da177e4SLinus Torvalds ha->max_cmds = 32; 2663*1da177e4SLinus Torvalds break; 2664*1da177e4SLinus Torvalds 2665*1da177e4SLinus Torvalds case 5: 2666*1da177e4SLinus Torvalds ha->max_cmds = 16; 2667*1da177e4SLinus Torvalds break; 2668*1da177e4SLinus Torvalds 2669*1da177e4SLinus Torvalds case 6: 2670*1da177e4SLinus Torvalds ha->max_cmds = 8; 2671*1da177e4SLinus Torvalds break; 2672*1da177e4SLinus Torvalds 2673*1da177e4SLinus Torvalds case 7: 2674*1da177e4SLinus Torvalds default: 2675*1da177e4SLinus Torvalds ha->max_cmds = 4; 2676*1da177e4SLinus Torvalds break; 2677*1da177e4SLinus Torvalds } 2678*1da177e4SLinus Torvalds } 2679*1da177e4SLinus Torvalds 2680*1da177e4SLinus Torvalds /* Limit the Active Commands on a Lite Adapter */ 2681*1da177e4SLinus Torvalds if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) || 2682*1da177e4SLinus Torvalds (ha->ad_type == IPS_ADTYPE_SERVERAID4L) || 2683*1da177e4SLinus Torvalds (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) { 2684*1da177e4SLinus Torvalds if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) 2685*1da177e4SLinus Torvalds ha->max_cmds = MaxLiteCmds; 2686*1da177e4SLinus Torvalds } 2687*1da177e4SLinus Torvalds 2688*1da177e4SLinus Torvalds /* set controller IDs */ 2689*1da177e4SLinus Torvalds ha->ha_id[0] = IPS_ADAPTER_ID; 2690*1da177e4SLinus Torvalds for (i = 1; i < ha->nbus; i++) { 2691*1da177e4SLinus Torvalds ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f; 2692*1da177e4SLinus Torvalds ha->dcdb_active[i - 1] = 0; 2693*1da177e4SLinus Torvalds } 2694*1da177e4SLinus Torvalds 2695*1da177e4SLinus Torvalds return (1); 2696*1da177e4SLinus Torvalds } 2697*1da177e4SLinus Torvalds 2698*1da177e4SLinus Torvalds /****************************************************************************/ 2699*1da177e4SLinus Torvalds /* */ 2700*1da177e4SLinus Torvalds /* Routine Name: ips_next */ 2701*1da177e4SLinus Torvalds /* */ 2702*1da177e4SLinus Torvalds /* Routine Description: */ 2703*1da177e4SLinus Torvalds /* */ 2704*1da177e4SLinus Torvalds /* Take the next command off the queue and send it to the controller */ 2705*1da177e4SLinus Torvalds /* */ 2706*1da177e4SLinus Torvalds /****************************************************************************/ 2707*1da177e4SLinus Torvalds static void 2708*1da177e4SLinus Torvalds ips_next(ips_ha_t * ha, int intr) 2709*1da177e4SLinus Torvalds { 2710*1da177e4SLinus Torvalds ips_scb_t *scb; 2711*1da177e4SLinus Torvalds Scsi_Cmnd *SC; 2712*1da177e4SLinus Torvalds Scsi_Cmnd *p; 2713*1da177e4SLinus Torvalds Scsi_Cmnd *q; 2714*1da177e4SLinus Torvalds ips_copp_wait_item_t *item; 2715*1da177e4SLinus Torvalds int ret; 2716*1da177e4SLinus Torvalds unsigned long cpu_flags = 0; 2717*1da177e4SLinus Torvalds struct Scsi_Host *host; 2718*1da177e4SLinus Torvalds METHOD_TRACE("ips_next", 1); 2719*1da177e4SLinus Torvalds 2720*1da177e4SLinus Torvalds if (!ha) 2721*1da177e4SLinus Torvalds return; 2722*1da177e4SLinus Torvalds host = ips_sh[ha->host_num]; 2723*1da177e4SLinus Torvalds /* 2724*1da177e4SLinus Torvalds * Block access to the queue function so 2725*1da177e4SLinus Torvalds * this command won't time out 2726*1da177e4SLinus Torvalds */ 2727*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) 2728*1da177e4SLinus Torvalds IPS_LOCK_SAVE(host->host_lock, cpu_flags); 2729*1da177e4SLinus Torvalds 2730*1da177e4SLinus Torvalds if ((ha->subsys->param[3] & 0x300000) 2731*1da177e4SLinus Torvalds && (ha->scb_activelist.count == 0)) { 2732*1da177e4SLinus Torvalds struct timeval tv; 2733*1da177e4SLinus Torvalds 2734*1da177e4SLinus Torvalds do_gettimeofday(&tv); 2735*1da177e4SLinus Torvalds 2736*1da177e4SLinus Torvalds if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) { 2737*1da177e4SLinus Torvalds ha->last_ffdc = tv.tv_sec; 2738*1da177e4SLinus Torvalds ips_ffdc_time(ha); 2739*1da177e4SLinus Torvalds } 2740*1da177e4SLinus Torvalds } 2741*1da177e4SLinus Torvalds 2742*1da177e4SLinus Torvalds /* 2743*1da177e4SLinus Torvalds * Send passthru commands 2744*1da177e4SLinus Torvalds * These have priority over normal I/O 2745*1da177e4SLinus Torvalds * but shouldn't affect performance too much 2746*1da177e4SLinus Torvalds * since we limit the number that can be active 2747*1da177e4SLinus Torvalds * on the card at any one time 2748*1da177e4SLinus Torvalds */ 2749*1da177e4SLinus Torvalds while ((ha->num_ioctl < IPS_MAX_IOCTL) && 2750*1da177e4SLinus Torvalds (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) { 2751*1da177e4SLinus Torvalds 2752*1da177e4SLinus Torvalds item = ips_removeq_copp_head(&ha->copp_waitlist); 2753*1da177e4SLinus Torvalds ha->num_ioctl++; 2754*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) 2755*1da177e4SLinus Torvalds IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); 2756*1da177e4SLinus Torvalds scb->scsi_cmd = item->scsi_cmd; 2757*1da177e4SLinus Torvalds kfree(item); 2758*1da177e4SLinus Torvalds 2759*1da177e4SLinus Torvalds ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr); 2760*1da177e4SLinus Torvalds 2761*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) 2762*1da177e4SLinus Torvalds IPS_LOCK_SAVE(host->host_lock, cpu_flags); 2763*1da177e4SLinus Torvalds switch (ret) { 2764*1da177e4SLinus Torvalds case IPS_FAILURE: 2765*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 2766*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 2767*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 2768*1da177e4SLinus Torvalds } 2769*1da177e4SLinus Torvalds 2770*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2771*1da177e4SLinus Torvalds break; 2772*1da177e4SLinus Torvalds case IPS_SUCCESS_IMM: 2773*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 2774*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 2775*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 2776*1da177e4SLinus Torvalds } 2777*1da177e4SLinus Torvalds 2778*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2779*1da177e4SLinus Torvalds break; 2780*1da177e4SLinus Torvalds default: 2781*1da177e4SLinus Torvalds break; 2782*1da177e4SLinus Torvalds } /* end case */ 2783*1da177e4SLinus Torvalds 2784*1da177e4SLinus Torvalds if (ret != IPS_SUCCESS) { 2785*1da177e4SLinus Torvalds ha->num_ioctl--; 2786*1da177e4SLinus Torvalds continue; 2787*1da177e4SLinus Torvalds } 2788*1da177e4SLinus Torvalds 2789*1da177e4SLinus Torvalds ret = ips_send_cmd(ha, scb); 2790*1da177e4SLinus Torvalds 2791*1da177e4SLinus Torvalds if (ret == IPS_SUCCESS) 2792*1da177e4SLinus Torvalds ips_putq_scb_head(&ha->scb_activelist, scb); 2793*1da177e4SLinus Torvalds else 2794*1da177e4SLinus Torvalds ha->num_ioctl--; 2795*1da177e4SLinus Torvalds 2796*1da177e4SLinus Torvalds switch (ret) { 2797*1da177e4SLinus Torvalds case IPS_FAILURE: 2798*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 2799*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 2800*1da177e4SLinus Torvalds } 2801*1da177e4SLinus Torvalds 2802*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2803*1da177e4SLinus Torvalds break; 2804*1da177e4SLinus Torvalds case IPS_SUCCESS_IMM: 2805*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2806*1da177e4SLinus Torvalds break; 2807*1da177e4SLinus Torvalds default: 2808*1da177e4SLinus Torvalds break; 2809*1da177e4SLinus Torvalds } /* end case */ 2810*1da177e4SLinus Torvalds 2811*1da177e4SLinus Torvalds } 2812*1da177e4SLinus Torvalds 2813*1da177e4SLinus Torvalds /* 2814*1da177e4SLinus Torvalds * Send "Normal" I/O commands 2815*1da177e4SLinus Torvalds */ 2816*1da177e4SLinus Torvalds 2817*1da177e4SLinus Torvalds p = ha->scb_waitlist.head; 2818*1da177e4SLinus Torvalds while ((p) && (scb = ips_getscb(ha))) { 2819*1da177e4SLinus Torvalds if ((p->device->channel > 0) 2820*1da177e4SLinus Torvalds && (ha-> 2821*1da177e4SLinus Torvalds dcdb_active[p->device->channel - 2822*1da177e4SLinus Torvalds 1] & (1 << p->device->id))) { 2823*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2824*1da177e4SLinus Torvalds p = (Scsi_Cmnd *) p->host_scribble; 2825*1da177e4SLinus Torvalds continue; 2826*1da177e4SLinus Torvalds } 2827*1da177e4SLinus Torvalds 2828*1da177e4SLinus Torvalds q = p; 2829*1da177e4SLinus Torvalds SC = ips_removeq_wait(&ha->scb_waitlist, q); 2830*1da177e4SLinus Torvalds 2831*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) 2832*1da177e4SLinus Torvalds IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); /* Unlock HA after command is taken off queue */ 2833*1da177e4SLinus Torvalds 2834*1da177e4SLinus Torvalds SC->result = DID_OK; 2835*1da177e4SLinus Torvalds SC->host_scribble = NULL; 2836*1da177e4SLinus Torvalds 2837*1da177e4SLinus Torvalds memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer)); 2838*1da177e4SLinus Torvalds 2839*1da177e4SLinus Torvalds scb->target_id = SC->device->id; 2840*1da177e4SLinus Torvalds scb->lun = SC->device->lun; 2841*1da177e4SLinus Torvalds scb->bus = SC->device->channel; 2842*1da177e4SLinus Torvalds scb->scsi_cmd = SC; 2843*1da177e4SLinus Torvalds scb->breakup = 0; 2844*1da177e4SLinus Torvalds scb->data_len = 0; 2845*1da177e4SLinus Torvalds scb->callback = ipsintr_done; 2846*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 2847*1da177e4SLinus Torvalds memset(&scb->cmd, 0, 16); 2848*1da177e4SLinus Torvalds 2849*1da177e4SLinus Torvalds /* copy in the CDB */ 2850*1da177e4SLinus Torvalds memcpy(scb->cdb, SC->cmnd, SC->cmd_len); 2851*1da177e4SLinus Torvalds 2852*1da177e4SLinus Torvalds /* Now handle the data buffer */ 2853*1da177e4SLinus Torvalds if (SC->use_sg) { 2854*1da177e4SLinus Torvalds struct scatterlist *sg; 2855*1da177e4SLinus Torvalds int i; 2856*1da177e4SLinus Torvalds 2857*1da177e4SLinus Torvalds sg = SC->request_buffer; 2858*1da177e4SLinus Torvalds scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg, 2859*1da177e4SLinus Torvalds scsi_to_pci_dma_dir(SC-> 2860*1da177e4SLinus Torvalds sc_data_direction)); 2861*1da177e4SLinus Torvalds scb->flags |= IPS_SCB_MAP_SG; 2862*1da177e4SLinus Torvalds for (i = 0; i < scb->sg_count; i++) { 2863*1da177e4SLinus Torvalds if (ips_fill_scb_sg_single 2864*1da177e4SLinus Torvalds (ha, sg_dma_address(&sg[i]), scb, i, 2865*1da177e4SLinus Torvalds sg_dma_len(&sg[i])) < 0) 2866*1da177e4SLinus Torvalds break; 2867*1da177e4SLinus Torvalds } 2868*1da177e4SLinus Torvalds scb->dcdb.transfer_length = scb->data_len; 2869*1da177e4SLinus Torvalds } else { 2870*1da177e4SLinus Torvalds if (SC->request_bufflen) { 2871*1da177e4SLinus Torvalds scb->data_busaddr = 2872*1da177e4SLinus Torvalds pci_map_single(ha->pcidev, 2873*1da177e4SLinus Torvalds SC->request_buffer, 2874*1da177e4SLinus Torvalds SC->request_bufflen, 2875*1da177e4SLinus Torvalds scsi_to_pci_dma_dir(SC-> 2876*1da177e4SLinus Torvalds sc_data_direction)); 2877*1da177e4SLinus Torvalds scb->flags |= IPS_SCB_MAP_SINGLE; 2878*1da177e4SLinus Torvalds ips_fill_scb_sg_single(ha, scb->data_busaddr, 2879*1da177e4SLinus Torvalds scb, 0, 2880*1da177e4SLinus Torvalds SC->request_bufflen); 2881*1da177e4SLinus Torvalds scb->dcdb.transfer_length = scb->data_len; 2882*1da177e4SLinus Torvalds } else { 2883*1da177e4SLinus Torvalds scb->data_busaddr = 0L; 2884*1da177e4SLinus Torvalds scb->sg_len = 0; 2885*1da177e4SLinus Torvalds scb->data_len = 0; 2886*1da177e4SLinus Torvalds scb->dcdb.transfer_length = 0; 2887*1da177e4SLinus Torvalds } 2888*1da177e4SLinus Torvalds 2889*1da177e4SLinus Torvalds } 2890*1da177e4SLinus Torvalds 2891*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute = 2892*1da177e4SLinus Torvalds ips_command_direction[scb->scsi_cmd->cmnd[0]]; 2893*1da177e4SLinus Torvalds 2894*1da177e4SLinus Torvalds /* Allow a WRITE BUFFER Command to Have no Data */ 2895*1da177e4SLinus Torvalds /* This is Used by Tape Flash Utilites */ 2896*1da177e4SLinus Torvalds if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) 2897*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute = 0; 2898*1da177e4SLinus Torvalds 2899*1da177e4SLinus Torvalds if (!(scb->dcdb.cmd_attribute & 0x3)) 2900*1da177e4SLinus Torvalds scb->dcdb.transfer_length = 0; 2901*1da177e4SLinus Torvalds 2902*1da177e4SLinus Torvalds if (scb->data_len >= IPS_MAX_XFER) { 2903*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; 2904*1da177e4SLinus Torvalds scb->dcdb.transfer_length = 0; 2905*1da177e4SLinus Torvalds } 2906*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) 2907*1da177e4SLinus Torvalds IPS_LOCK_SAVE(host->host_lock, cpu_flags); 2908*1da177e4SLinus Torvalds 2909*1da177e4SLinus Torvalds ret = ips_send_cmd(ha, scb); 2910*1da177e4SLinus Torvalds 2911*1da177e4SLinus Torvalds switch (ret) { 2912*1da177e4SLinus Torvalds case IPS_SUCCESS: 2913*1da177e4SLinus Torvalds ips_putq_scb_head(&ha->scb_activelist, scb); 2914*1da177e4SLinus Torvalds break; 2915*1da177e4SLinus Torvalds case IPS_FAILURE: 2916*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 2917*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 2918*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 2919*1da177e4SLinus Torvalds } 2920*1da177e4SLinus Torvalds 2921*1da177e4SLinus Torvalds if (scb->bus) 2922*1da177e4SLinus Torvalds ha->dcdb_active[scb->bus - 1] &= 2923*1da177e4SLinus Torvalds ~(1 << scb->target_id); 2924*1da177e4SLinus Torvalds 2925*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2926*1da177e4SLinus Torvalds break; 2927*1da177e4SLinus Torvalds case IPS_SUCCESS_IMM: 2928*1da177e4SLinus Torvalds if (scb->scsi_cmd) 2929*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 2930*1da177e4SLinus Torvalds 2931*1da177e4SLinus Torvalds if (scb->bus) 2932*1da177e4SLinus Torvalds ha->dcdb_active[scb->bus - 1] &= 2933*1da177e4SLinus Torvalds ~(1 << scb->target_id); 2934*1da177e4SLinus Torvalds 2935*1da177e4SLinus Torvalds ips_freescb(ha, scb); 2936*1da177e4SLinus Torvalds break; 2937*1da177e4SLinus Torvalds default: 2938*1da177e4SLinus Torvalds break; 2939*1da177e4SLinus Torvalds } /* end case */ 2940*1da177e4SLinus Torvalds 2941*1da177e4SLinus Torvalds p = (Scsi_Cmnd *) p->host_scribble; 2942*1da177e4SLinus Torvalds 2943*1da177e4SLinus Torvalds } /* end while */ 2944*1da177e4SLinus Torvalds 2945*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) 2946*1da177e4SLinus Torvalds IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); 2947*1da177e4SLinus Torvalds } 2948*1da177e4SLinus Torvalds 2949*1da177e4SLinus Torvalds /****************************************************************************/ 2950*1da177e4SLinus Torvalds /* */ 2951*1da177e4SLinus Torvalds /* Routine Name: ips_putq_scb_head */ 2952*1da177e4SLinus Torvalds /* */ 2953*1da177e4SLinus Torvalds /* Routine Description: */ 2954*1da177e4SLinus Torvalds /* */ 2955*1da177e4SLinus Torvalds /* Add an item to the head of the queue */ 2956*1da177e4SLinus Torvalds /* */ 2957*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 2958*1da177e4SLinus Torvalds /* */ 2959*1da177e4SLinus Torvalds /****************************************************************************/ 2960*1da177e4SLinus Torvalds static void 2961*1da177e4SLinus Torvalds ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) 2962*1da177e4SLinus Torvalds { 2963*1da177e4SLinus Torvalds METHOD_TRACE("ips_putq_scb_head", 1); 2964*1da177e4SLinus Torvalds 2965*1da177e4SLinus Torvalds if (!item) 2966*1da177e4SLinus Torvalds return; 2967*1da177e4SLinus Torvalds 2968*1da177e4SLinus Torvalds item->q_next = queue->head; 2969*1da177e4SLinus Torvalds queue->head = item; 2970*1da177e4SLinus Torvalds 2971*1da177e4SLinus Torvalds if (!queue->tail) 2972*1da177e4SLinus Torvalds queue->tail = item; 2973*1da177e4SLinus Torvalds 2974*1da177e4SLinus Torvalds queue->count++; 2975*1da177e4SLinus Torvalds } 2976*1da177e4SLinus Torvalds 2977*1da177e4SLinus Torvalds /****************************************************************************/ 2978*1da177e4SLinus Torvalds /* */ 2979*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_scb_head */ 2980*1da177e4SLinus Torvalds /* */ 2981*1da177e4SLinus Torvalds /* Routine Description: */ 2982*1da177e4SLinus Torvalds /* */ 2983*1da177e4SLinus Torvalds /* Remove the head of the queue */ 2984*1da177e4SLinus Torvalds /* */ 2985*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 2986*1da177e4SLinus Torvalds /* */ 2987*1da177e4SLinus Torvalds /****************************************************************************/ 2988*1da177e4SLinus Torvalds static ips_scb_t * 2989*1da177e4SLinus Torvalds ips_removeq_scb_head(ips_scb_queue_t * queue) 2990*1da177e4SLinus Torvalds { 2991*1da177e4SLinus Torvalds ips_scb_t *item; 2992*1da177e4SLinus Torvalds 2993*1da177e4SLinus Torvalds METHOD_TRACE("ips_removeq_scb_head", 1); 2994*1da177e4SLinus Torvalds 2995*1da177e4SLinus Torvalds item = queue->head; 2996*1da177e4SLinus Torvalds 2997*1da177e4SLinus Torvalds if (!item) { 2998*1da177e4SLinus Torvalds return (NULL); 2999*1da177e4SLinus Torvalds } 3000*1da177e4SLinus Torvalds 3001*1da177e4SLinus Torvalds queue->head = item->q_next; 3002*1da177e4SLinus Torvalds item->q_next = NULL; 3003*1da177e4SLinus Torvalds 3004*1da177e4SLinus Torvalds if (queue->tail == item) 3005*1da177e4SLinus Torvalds queue->tail = NULL; 3006*1da177e4SLinus Torvalds 3007*1da177e4SLinus Torvalds queue->count--; 3008*1da177e4SLinus Torvalds 3009*1da177e4SLinus Torvalds return (item); 3010*1da177e4SLinus Torvalds } 3011*1da177e4SLinus Torvalds 3012*1da177e4SLinus Torvalds /****************************************************************************/ 3013*1da177e4SLinus Torvalds /* */ 3014*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_scb */ 3015*1da177e4SLinus Torvalds /* */ 3016*1da177e4SLinus Torvalds /* Routine Description: */ 3017*1da177e4SLinus Torvalds /* */ 3018*1da177e4SLinus Torvalds /* Remove an item from a queue */ 3019*1da177e4SLinus Torvalds /* */ 3020*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3021*1da177e4SLinus Torvalds /* */ 3022*1da177e4SLinus Torvalds /****************************************************************************/ 3023*1da177e4SLinus Torvalds static ips_scb_t * 3024*1da177e4SLinus Torvalds ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) 3025*1da177e4SLinus Torvalds { 3026*1da177e4SLinus Torvalds ips_scb_t *p; 3027*1da177e4SLinus Torvalds 3028*1da177e4SLinus Torvalds METHOD_TRACE("ips_removeq_scb", 1); 3029*1da177e4SLinus Torvalds 3030*1da177e4SLinus Torvalds if (!item) 3031*1da177e4SLinus Torvalds return (NULL); 3032*1da177e4SLinus Torvalds 3033*1da177e4SLinus Torvalds if (item == queue->head) { 3034*1da177e4SLinus Torvalds return (ips_removeq_scb_head(queue)); 3035*1da177e4SLinus Torvalds } 3036*1da177e4SLinus Torvalds 3037*1da177e4SLinus Torvalds p = queue->head; 3038*1da177e4SLinus Torvalds 3039*1da177e4SLinus Torvalds while ((p) && (item != p->q_next)) 3040*1da177e4SLinus Torvalds p = p->q_next; 3041*1da177e4SLinus Torvalds 3042*1da177e4SLinus Torvalds if (p) { 3043*1da177e4SLinus Torvalds /* found a match */ 3044*1da177e4SLinus Torvalds p->q_next = item->q_next; 3045*1da177e4SLinus Torvalds 3046*1da177e4SLinus Torvalds if (!item->q_next) 3047*1da177e4SLinus Torvalds queue->tail = p; 3048*1da177e4SLinus Torvalds 3049*1da177e4SLinus Torvalds item->q_next = NULL; 3050*1da177e4SLinus Torvalds queue->count--; 3051*1da177e4SLinus Torvalds 3052*1da177e4SLinus Torvalds return (item); 3053*1da177e4SLinus Torvalds } 3054*1da177e4SLinus Torvalds 3055*1da177e4SLinus Torvalds return (NULL); 3056*1da177e4SLinus Torvalds } 3057*1da177e4SLinus Torvalds 3058*1da177e4SLinus Torvalds /****************************************************************************/ 3059*1da177e4SLinus Torvalds /* */ 3060*1da177e4SLinus Torvalds /* Routine Name: ips_putq_wait_tail */ 3061*1da177e4SLinus Torvalds /* */ 3062*1da177e4SLinus Torvalds /* Routine Description: */ 3063*1da177e4SLinus Torvalds /* */ 3064*1da177e4SLinus Torvalds /* Add an item to the tail of the queue */ 3065*1da177e4SLinus Torvalds /* */ 3066*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3067*1da177e4SLinus Torvalds /* */ 3068*1da177e4SLinus Torvalds /****************************************************************************/ 3069*1da177e4SLinus Torvalds static void 3070*1da177e4SLinus Torvalds ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) 3071*1da177e4SLinus Torvalds { 3072*1da177e4SLinus Torvalds METHOD_TRACE("ips_putq_wait_tail", 1); 3073*1da177e4SLinus Torvalds 3074*1da177e4SLinus Torvalds if (!item) 3075*1da177e4SLinus Torvalds return; 3076*1da177e4SLinus Torvalds 3077*1da177e4SLinus Torvalds item->host_scribble = NULL; 3078*1da177e4SLinus Torvalds 3079*1da177e4SLinus Torvalds if (queue->tail) 3080*1da177e4SLinus Torvalds queue->tail->host_scribble = (char *) item; 3081*1da177e4SLinus Torvalds 3082*1da177e4SLinus Torvalds queue->tail = item; 3083*1da177e4SLinus Torvalds 3084*1da177e4SLinus Torvalds if (!queue->head) 3085*1da177e4SLinus Torvalds queue->head = item; 3086*1da177e4SLinus Torvalds 3087*1da177e4SLinus Torvalds queue->count++; 3088*1da177e4SLinus Torvalds } 3089*1da177e4SLinus Torvalds 3090*1da177e4SLinus Torvalds /****************************************************************************/ 3091*1da177e4SLinus Torvalds /* */ 3092*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_wait_head */ 3093*1da177e4SLinus Torvalds /* */ 3094*1da177e4SLinus Torvalds /* Routine Description: */ 3095*1da177e4SLinus Torvalds /* */ 3096*1da177e4SLinus Torvalds /* Remove the head of the queue */ 3097*1da177e4SLinus Torvalds /* */ 3098*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3099*1da177e4SLinus Torvalds /* */ 3100*1da177e4SLinus Torvalds /****************************************************************************/ 3101*1da177e4SLinus Torvalds static Scsi_Cmnd * 3102*1da177e4SLinus Torvalds ips_removeq_wait_head(ips_wait_queue_t * queue) 3103*1da177e4SLinus Torvalds { 3104*1da177e4SLinus Torvalds Scsi_Cmnd *item; 3105*1da177e4SLinus Torvalds 3106*1da177e4SLinus Torvalds METHOD_TRACE("ips_removeq_wait_head", 1); 3107*1da177e4SLinus Torvalds 3108*1da177e4SLinus Torvalds item = queue->head; 3109*1da177e4SLinus Torvalds 3110*1da177e4SLinus Torvalds if (!item) { 3111*1da177e4SLinus Torvalds return (NULL); 3112*1da177e4SLinus Torvalds } 3113*1da177e4SLinus Torvalds 3114*1da177e4SLinus Torvalds queue->head = (Scsi_Cmnd *) item->host_scribble; 3115*1da177e4SLinus Torvalds item->host_scribble = NULL; 3116*1da177e4SLinus Torvalds 3117*1da177e4SLinus Torvalds if (queue->tail == item) 3118*1da177e4SLinus Torvalds queue->tail = NULL; 3119*1da177e4SLinus Torvalds 3120*1da177e4SLinus Torvalds queue->count--; 3121*1da177e4SLinus Torvalds 3122*1da177e4SLinus Torvalds return (item); 3123*1da177e4SLinus Torvalds } 3124*1da177e4SLinus Torvalds 3125*1da177e4SLinus Torvalds /****************************************************************************/ 3126*1da177e4SLinus Torvalds /* */ 3127*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_wait */ 3128*1da177e4SLinus Torvalds /* */ 3129*1da177e4SLinus Torvalds /* Routine Description: */ 3130*1da177e4SLinus Torvalds /* */ 3131*1da177e4SLinus Torvalds /* Remove an item from a queue */ 3132*1da177e4SLinus Torvalds /* */ 3133*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3134*1da177e4SLinus Torvalds /* */ 3135*1da177e4SLinus Torvalds /****************************************************************************/ 3136*1da177e4SLinus Torvalds static Scsi_Cmnd * 3137*1da177e4SLinus Torvalds ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) 3138*1da177e4SLinus Torvalds { 3139*1da177e4SLinus Torvalds Scsi_Cmnd *p; 3140*1da177e4SLinus Torvalds 3141*1da177e4SLinus Torvalds METHOD_TRACE("ips_removeq_wait", 1); 3142*1da177e4SLinus Torvalds 3143*1da177e4SLinus Torvalds if (!item) 3144*1da177e4SLinus Torvalds return (NULL); 3145*1da177e4SLinus Torvalds 3146*1da177e4SLinus Torvalds if (item == queue->head) { 3147*1da177e4SLinus Torvalds return (ips_removeq_wait_head(queue)); 3148*1da177e4SLinus Torvalds } 3149*1da177e4SLinus Torvalds 3150*1da177e4SLinus Torvalds p = queue->head; 3151*1da177e4SLinus Torvalds 3152*1da177e4SLinus Torvalds while ((p) && (item != (Scsi_Cmnd *) p->host_scribble)) 3153*1da177e4SLinus Torvalds p = (Scsi_Cmnd *) p->host_scribble; 3154*1da177e4SLinus Torvalds 3155*1da177e4SLinus Torvalds if (p) { 3156*1da177e4SLinus Torvalds /* found a match */ 3157*1da177e4SLinus Torvalds p->host_scribble = item->host_scribble; 3158*1da177e4SLinus Torvalds 3159*1da177e4SLinus Torvalds if (!item->host_scribble) 3160*1da177e4SLinus Torvalds queue->tail = p; 3161*1da177e4SLinus Torvalds 3162*1da177e4SLinus Torvalds item->host_scribble = NULL; 3163*1da177e4SLinus Torvalds queue->count--; 3164*1da177e4SLinus Torvalds 3165*1da177e4SLinus Torvalds return (item); 3166*1da177e4SLinus Torvalds } 3167*1da177e4SLinus Torvalds 3168*1da177e4SLinus Torvalds return (NULL); 3169*1da177e4SLinus Torvalds } 3170*1da177e4SLinus Torvalds 3171*1da177e4SLinus Torvalds /****************************************************************************/ 3172*1da177e4SLinus Torvalds /* */ 3173*1da177e4SLinus Torvalds /* Routine Name: ips_putq_copp_tail */ 3174*1da177e4SLinus Torvalds /* */ 3175*1da177e4SLinus Torvalds /* Routine Description: */ 3176*1da177e4SLinus Torvalds /* */ 3177*1da177e4SLinus Torvalds /* Add an item to the tail of the queue */ 3178*1da177e4SLinus Torvalds /* */ 3179*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3180*1da177e4SLinus Torvalds /* */ 3181*1da177e4SLinus Torvalds /****************************************************************************/ 3182*1da177e4SLinus Torvalds static void 3183*1da177e4SLinus Torvalds ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) 3184*1da177e4SLinus Torvalds { 3185*1da177e4SLinus Torvalds METHOD_TRACE("ips_putq_copp_tail", 1); 3186*1da177e4SLinus Torvalds 3187*1da177e4SLinus Torvalds if (!item) 3188*1da177e4SLinus Torvalds return; 3189*1da177e4SLinus Torvalds 3190*1da177e4SLinus Torvalds item->next = NULL; 3191*1da177e4SLinus Torvalds 3192*1da177e4SLinus Torvalds if (queue->tail) 3193*1da177e4SLinus Torvalds queue->tail->next = item; 3194*1da177e4SLinus Torvalds 3195*1da177e4SLinus Torvalds queue->tail = item; 3196*1da177e4SLinus Torvalds 3197*1da177e4SLinus Torvalds if (!queue->head) 3198*1da177e4SLinus Torvalds queue->head = item; 3199*1da177e4SLinus Torvalds 3200*1da177e4SLinus Torvalds queue->count++; 3201*1da177e4SLinus Torvalds } 3202*1da177e4SLinus Torvalds 3203*1da177e4SLinus Torvalds /****************************************************************************/ 3204*1da177e4SLinus Torvalds /* */ 3205*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_copp_head */ 3206*1da177e4SLinus Torvalds /* */ 3207*1da177e4SLinus Torvalds /* Routine Description: */ 3208*1da177e4SLinus Torvalds /* */ 3209*1da177e4SLinus Torvalds /* Remove the head of the queue */ 3210*1da177e4SLinus Torvalds /* */ 3211*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3212*1da177e4SLinus Torvalds /* */ 3213*1da177e4SLinus Torvalds /****************************************************************************/ 3214*1da177e4SLinus Torvalds static ips_copp_wait_item_t * 3215*1da177e4SLinus Torvalds ips_removeq_copp_head(ips_copp_queue_t * queue) 3216*1da177e4SLinus Torvalds { 3217*1da177e4SLinus Torvalds ips_copp_wait_item_t *item; 3218*1da177e4SLinus Torvalds 3219*1da177e4SLinus Torvalds METHOD_TRACE("ips_removeq_copp_head", 1); 3220*1da177e4SLinus Torvalds 3221*1da177e4SLinus Torvalds item = queue->head; 3222*1da177e4SLinus Torvalds 3223*1da177e4SLinus Torvalds if (!item) { 3224*1da177e4SLinus Torvalds return (NULL); 3225*1da177e4SLinus Torvalds } 3226*1da177e4SLinus Torvalds 3227*1da177e4SLinus Torvalds queue->head = item->next; 3228*1da177e4SLinus Torvalds item->next = NULL; 3229*1da177e4SLinus Torvalds 3230*1da177e4SLinus Torvalds if (queue->tail == item) 3231*1da177e4SLinus Torvalds queue->tail = NULL; 3232*1da177e4SLinus Torvalds 3233*1da177e4SLinus Torvalds queue->count--; 3234*1da177e4SLinus Torvalds 3235*1da177e4SLinus Torvalds return (item); 3236*1da177e4SLinus Torvalds } 3237*1da177e4SLinus Torvalds 3238*1da177e4SLinus Torvalds /****************************************************************************/ 3239*1da177e4SLinus Torvalds /* */ 3240*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_copp */ 3241*1da177e4SLinus Torvalds /* */ 3242*1da177e4SLinus Torvalds /* Routine Description: */ 3243*1da177e4SLinus Torvalds /* */ 3244*1da177e4SLinus Torvalds /* Remove an item from a queue */ 3245*1da177e4SLinus Torvalds /* */ 3246*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock */ 3247*1da177e4SLinus Torvalds /* */ 3248*1da177e4SLinus Torvalds /****************************************************************************/ 3249*1da177e4SLinus Torvalds static ips_copp_wait_item_t * 3250*1da177e4SLinus Torvalds ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) 3251*1da177e4SLinus Torvalds { 3252*1da177e4SLinus Torvalds ips_copp_wait_item_t *p; 3253*1da177e4SLinus Torvalds 3254*1da177e4SLinus Torvalds METHOD_TRACE("ips_removeq_copp", 1); 3255*1da177e4SLinus Torvalds 3256*1da177e4SLinus Torvalds if (!item) 3257*1da177e4SLinus Torvalds return (NULL); 3258*1da177e4SLinus Torvalds 3259*1da177e4SLinus Torvalds if (item == queue->head) { 3260*1da177e4SLinus Torvalds return (ips_removeq_copp_head(queue)); 3261*1da177e4SLinus Torvalds } 3262*1da177e4SLinus Torvalds 3263*1da177e4SLinus Torvalds p = queue->head; 3264*1da177e4SLinus Torvalds 3265*1da177e4SLinus Torvalds while ((p) && (item != p->next)) 3266*1da177e4SLinus Torvalds p = p->next; 3267*1da177e4SLinus Torvalds 3268*1da177e4SLinus Torvalds if (p) { 3269*1da177e4SLinus Torvalds /* found a match */ 3270*1da177e4SLinus Torvalds p->next = item->next; 3271*1da177e4SLinus Torvalds 3272*1da177e4SLinus Torvalds if (!item->next) 3273*1da177e4SLinus Torvalds queue->tail = p; 3274*1da177e4SLinus Torvalds 3275*1da177e4SLinus Torvalds item->next = NULL; 3276*1da177e4SLinus Torvalds queue->count--; 3277*1da177e4SLinus Torvalds 3278*1da177e4SLinus Torvalds return (item); 3279*1da177e4SLinus Torvalds } 3280*1da177e4SLinus Torvalds 3281*1da177e4SLinus Torvalds return (NULL); 3282*1da177e4SLinus Torvalds } 3283*1da177e4SLinus Torvalds 3284*1da177e4SLinus Torvalds /****************************************************************************/ 3285*1da177e4SLinus Torvalds /* */ 3286*1da177e4SLinus Torvalds /* Routine Name: ipsintr_blocking */ 3287*1da177e4SLinus Torvalds /* */ 3288*1da177e4SLinus Torvalds /* Routine Description: */ 3289*1da177e4SLinus Torvalds /* */ 3290*1da177e4SLinus Torvalds /* Finalize an interrupt for internal commands */ 3291*1da177e4SLinus Torvalds /* */ 3292*1da177e4SLinus Torvalds /****************************************************************************/ 3293*1da177e4SLinus Torvalds static void 3294*1da177e4SLinus Torvalds ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb) 3295*1da177e4SLinus Torvalds { 3296*1da177e4SLinus Torvalds METHOD_TRACE("ipsintr_blocking", 2); 3297*1da177e4SLinus Torvalds 3298*1da177e4SLinus Torvalds ips_freescb(ha, scb); 3299*1da177e4SLinus Torvalds if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) { 3300*1da177e4SLinus Torvalds ha->waitflag = FALSE; 3301*1da177e4SLinus Torvalds 3302*1da177e4SLinus Torvalds return; 3303*1da177e4SLinus Torvalds } 3304*1da177e4SLinus Torvalds } 3305*1da177e4SLinus Torvalds 3306*1da177e4SLinus Torvalds /****************************************************************************/ 3307*1da177e4SLinus Torvalds /* */ 3308*1da177e4SLinus Torvalds /* Routine Name: ipsintr_done */ 3309*1da177e4SLinus Torvalds /* */ 3310*1da177e4SLinus Torvalds /* Routine Description: */ 3311*1da177e4SLinus Torvalds /* */ 3312*1da177e4SLinus Torvalds /* Finalize an interrupt for non-internal commands */ 3313*1da177e4SLinus Torvalds /* */ 3314*1da177e4SLinus Torvalds /****************************************************************************/ 3315*1da177e4SLinus Torvalds static void 3316*1da177e4SLinus Torvalds ipsintr_done(ips_ha_t * ha, ips_scb_t * scb) 3317*1da177e4SLinus Torvalds { 3318*1da177e4SLinus Torvalds METHOD_TRACE("ipsintr_done", 2); 3319*1da177e4SLinus Torvalds 3320*1da177e4SLinus Torvalds if (!scb) { 3321*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 3322*1da177e4SLinus Torvalds "Spurious interrupt; scb NULL.\n"); 3323*1da177e4SLinus Torvalds 3324*1da177e4SLinus Torvalds return; 3325*1da177e4SLinus Torvalds } 3326*1da177e4SLinus Torvalds 3327*1da177e4SLinus Torvalds if (scb->scsi_cmd == NULL) { 3328*1da177e4SLinus Torvalds /* unexpected interrupt */ 3329*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 3330*1da177e4SLinus Torvalds "Spurious interrupt; scsi_cmd not set.\n"); 3331*1da177e4SLinus Torvalds 3332*1da177e4SLinus Torvalds return; 3333*1da177e4SLinus Torvalds } 3334*1da177e4SLinus Torvalds 3335*1da177e4SLinus Torvalds ips_done(ha, scb); 3336*1da177e4SLinus Torvalds } 3337*1da177e4SLinus Torvalds 3338*1da177e4SLinus Torvalds /****************************************************************************/ 3339*1da177e4SLinus Torvalds /* */ 3340*1da177e4SLinus Torvalds /* Routine Name: ips_done */ 3341*1da177e4SLinus Torvalds /* */ 3342*1da177e4SLinus Torvalds /* Routine Description: */ 3343*1da177e4SLinus Torvalds /* */ 3344*1da177e4SLinus Torvalds /* Do housekeeping on completed commands */ 3345*1da177e4SLinus Torvalds /* ASSUMED to be called form within the request lock */ 3346*1da177e4SLinus Torvalds /****************************************************************************/ 3347*1da177e4SLinus Torvalds static void 3348*1da177e4SLinus Torvalds ips_done(ips_ha_t * ha, ips_scb_t * scb) 3349*1da177e4SLinus Torvalds { 3350*1da177e4SLinus Torvalds int ret; 3351*1da177e4SLinus Torvalds 3352*1da177e4SLinus Torvalds METHOD_TRACE("ips_done", 1); 3353*1da177e4SLinus Torvalds 3354*1da177e4SLinus Torvalds if (!scb) 3355*1da177e4SLinus Torvalds return; 3356*1da177e4SLinus Torvalds 3357*1da177e4SLinus Torvalds if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) { 3358*1da177e4SLinus Torvalds ips_cleanup_passthru(ha, scb); 3359*1da177e4SLinus Torvalds ha->num_ioctl--; 3360*1da177e4SLinus Torvalds } else { 3361*1da177e4SLinus Torvalds /* 3362*1da177e4SLinus Torvalds * Check to see if this command had too much 3363*1da177e4SLinus Torvalds * data and had to be broke up. If so, queue 3364*1da177e4SLinus Torvalds * the rest of the data and continue. 3365*1da177e4SLinus Torvalds */ 3366*1da177e4SLinus Torvalds if ((scb->breakup) || (scb->sg_break)) { 3367*1da177e4SLinus Torvalds /* we had a data breakup */ 3368*1da177e4SLinus Torvalds scb->data_len = 0; 3369*1da177e4SLinus Torvalds 3370*1da177e4SLinus Torvalds if (scb->sg_count) { 3371*1da177e4SLinus Torvalds /* S/G request */ 3372*1da177e4SLinus Torvalds struct scatterlist *sg; 3373*1da177e4SLinus Torvalds int ips_sg_index = 0; 3374*1da177e4SLinus Torvalds int sg_dma_index; 3375*1da177e4SLinus Torvalds 3376*1da177e4SLinus Torvalds sg = scb->scsi_cmd->request_buffer; 3377*1da177e4SLinus Torvalds 3378*1da177e4SLinus Torvalds /* Spin forward to last dma chunk */ 3379*1da177e4SLinus Torvalds sg_dma_index = scb->breakup; 3380*1da177e4SLinus Torvalds 3381*1da177e4SLinus Torvalds /* Take care of possible partial on last chunk */ 3382*1da177e4SLinus Torvalds ips_fill_scb_sg_single(ha, 3383*1da177e4SLinus Torvalds sg_dma_address(&sg 3384*1da177e4SLinus Torvalds [sg_dma_index]), 3385*1da177e4SLinus Torvalds scb, ips_sg_index++, 3386*1da177e4SLinus Torvalds sg_dma_len(&sg 3387*1da177e4SLinus Torvalds [sg_dma_index])); 3388*1da177e4SLinus Torvalds 3389*1da177e4SLinus Torvalds for (; sg_dma_index < scb->sg_count; 3390*1da177e4SLinus Torvalds sg_dma_index++) { 3391*1da177e4SLinus Torvalds if (ips_fill_scb_sg_single 3392*1da177e4SLinus Torvalds (ha, 3393*1da177e4SLinus Torvalds sg_dma_address(&sg[sg_dma_index]), 3394*1da177e4SLinus Torvalds scb, ips_sg_index++, 3395*1da177e4SLinus Torvalds sg_dma_len(&sg[sg_dma_index])) < 0) 3396*1da177e4SLinus Torvalds break; 3397*1da177e4SLinus Torvalds 3398*1da177e4SLinus Torvalds } 3399*1da177e4SLinus Torvalds 3400*1da177e4SLinus Torvalds } else { 3401*1da177e4SLinus Torvalds /* Non S/G Request */ 3402*1da177e4SLinus Torvalds (void) ips_fill_scb_sg_single(ha, 3403*1da177e4SLinus Torvalds scb-> 3404*1da177e4SLinus Torvalds data_busaddr + 3405*1da177e4SLinus Torvalds (scb->sg_break * 3406*1da177e4SLinus Torvalds ha->max_xfer), 3407*1da177e4SLinus Torvalds scb, 0, 3408*1da177e4SLinus Torvalds scb->scsi_cmd-> 3409*1da177e4SLinus Torvalds request_bufflen - 3410*1da177e4SLinus Torvalds (scb->sg_break * 3411*1da177e4SLinus Torvalds ha->max_xfer)); 3412*1da177e4SLinus Torvalds } 3413*1da177e4SLinus Torvalds 3414*1da177e4SLinus Torvalds scb->dcdb.transfer_length = scb->data_len; 3415*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= 3416*1da177e4SLinus Torvalds ips_command_direction[scb->scsi_cmd->cmnd[0]]; 3417*1da177e4SLinus Torvalds 3418*1da177e4SLinus Torvalds if (!(scb->dcdb.cmd_attribute & 0x3)) 3419*1da177e4SLinus Torvalds scb->dcdb.transfer_length = 0; 3420*1da177e4SLinus Torvalds 3421*1da177e4SLinus Torvalds if (scb->data_len >= IPS_MAX_XFER) { 3422*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; 3423*1da177e4SLinus Torvalds scb->dcdb.transfer_length = 0; 3424*1da177e4SLinus Torvalds } 3425*1da177e4SLinus Torvalds 3426*1da177e4SLinus Torvalds ret = ips_send_cmd(ha, scb); 3427*1da177e4SLinus Torvalds 3428*1da177e4SLinus Torvalds switch (ret) { 3429*1da177e4SLinus Torvalds case IPS_FAILURE: 3430*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 3431*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 3432*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 3433*1da177e4SLinus Torvalds } 3434*1da177e4SLinus Torvalds 3435*1da177e4SLinus Torvalds ips_freescb(ha, scb); 3436*1da177e4SLinus Torvalds break; 3437*1da177e4SLinus Torvalds case IPS_SUCCESS_IMM: 3438*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 3439*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 3440*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 3441*1da177e4SLinus Torvalds } 3442*1da177e4SLinus Torvalds 3443*1da177e4SLinus Torvalds ips_freescb(ha, scb); 3444*1da177e4SLinus Torvalds break; 3445*1da177e4SLinus Torvalds default: 3446*1da177e4SLinus Torvalds break; 3447*1da177e4SLinus Torvalds } /* end case */ 3448*1da177e4SLinus Torvalds 3449*1da177e4SLinus Torvalds return; 3450*1da177e4SLinus Torvalds } 3451*1da177e4SLinus Torvalds } /* end if passthru */ 3452*1da177e4SLinus Torvalds 3453*1da177e4SLinus Torvalds if (scb->bus) { 3454*1da177e4SLinus Torvalds ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id); 3455*1da177e4SLinus Torvalds } 3456*1da177e4SLinus Torvalds 3457*1da177e4SLinus Torvalds scb->scsi_cmd->scsi_done(scb->scsi_cmd); 3458*1da177e4SLinus Torvalds 3459*1da177e4SLinus Torvalds ips_freescb(ha, scb); 3460*1da177e4SLinus Torvalds } 3461*1da177e4SLinus Torvalds 3462*1da177e4SLinus Torvalds /****************************************************************************/ 3463*1da177e4SLinus Torvalds /* */ 3464*1da177e4SLinus Torvalds /* Routine Name: ips_map_status */ 3465*1da177e4SLinus Torvalds /* */ 3466*1da177e4SLinus Torvalds /* Routine Description: */ 3467*1da177e4SLinus Torvalds /* */ 3468*1da177e4SLinus Torvalds /* Map Controller Error codes to Linux Error Codes */ 3469*1da177e4SLinus Torvalds /* */ 3470*1da177e4SLinus Torvalds /****************************************************************************/ 3471*1da177e4SLinus Torvalds static int 3472*1da177e4SLinus Torvalds ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) 3473*1da177e4SLinus Torvalds { 3474*1da177e4SLinus Torvalds int errcode; 3475*1da177e4SLinus Torvalds int device_error; 3476*1da177e4SLinus Torvalds uint32_t transfer_len; 3477*1da177e4SLinus Torvalds IPS_DCDB_TABLE_TAPE *tapeDCDB; 3478*1da177e4SLinus Torvalds 3479*1da177e4SLinus Torvalds METHOD_TRACE("ips_map_status", 1); 3480*1da177e4SLinus Torvalds 3481*1da177e4SLinus Torvalds if (scb->bus) { 3482*1da177e4SLinus Torvalds DEBUG_VAR(2, 3483*1da177e4SLinus Torvalds "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x", 3484*1da177e4SLinus Torvalds ips_name, ha->host_num, 3485*1da177e4SLinus Torvalds scb->scsi_cmd->device->channel, 3486*1da177e4SLinus Torvalds scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun, 3487*1da177e4SLinus Torvalds scb->basic_status, scb->extended_status, 3488*1da177e4SLinus Torvalds scb->extended_status == 3489*1da177e4SLinus Torvalds IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0, 3490*1da177e4SLinus Torvalds scb->extended_status == 3491*1da177e4SLinus Torvalds IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0, 3492*1da177e4SLinus Torvalds scb->extended_status == 3493*1da177e4SLinus Torvalds IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0); 3494*1da177e4SLinus Torvalds } 3495*1da177e4SLinus Torvalds 3496*1da177e4SLinus Torvalds /* default driver error */ 3497*1da177e4SLinus Torvalds errcode = DID_ERROR; 3498*1da177e4SLinus Torvalds device_error = 0; 3499*1da177e4SLinus Torvalds 3500*1da177e4SLinus Torvalds switch (scb->basic_status & IPS_GSC_STATUS_MASK) { 3501*1da177e4SLinus Torvalds case IPS_CMD_TIMEOUT: 3502*1da177e4SLinus Torvalds errcode = DID_TIME_OUT; 3503*1da177e4SLinus Torvalds break; 3504*1da177e4SLinus Torvalds 3505*1da177e4SLinus Torvalds case IPS_INVAL_OPCO: 3506*1da177e4SLinus Torvalds case IPS_INVAL_CMD_BLK: 3507*1da177e4SLinus Torvalds case IPS_INVAL_PARM_BLK: 3508*1da177e4SLinus Torvalds case IPS_LD_ERROR: 3509*1da177e4SLinus Torvalds case IPS_CMD_CMPLT_WERROR: 3510*1da177e4SLinus Torvalds break; 3511*1da177e4SLinus Torvalds 3512*1da177e4SLinus Torvalds case IPS_PHYS_DRV_ERROR: 3513*1da177e4SLinus Torvalds switch (scb->extended_status) { 3514*1da177e4SLinus Torvalds case IPS_ERR_SEL_TO: 3515*1da177e4SLinus Torvalds if (scb->bus) 3516*1da177e4SLinus Torvalds errcode = DID_NO_CONNECT; 3517*1da177e4SLinus Torvalds 3518*1da177e4SLinus Torvalds break; 3519*1da177e4SLinus Torvalds 3520*1da177e4SLinus Torvalds case IPS_ERR_OU_RUN: 3521*1da177e4SLinus Torvalds if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) || 3522*1da177e4SLinus Torvalds (scb->cmd.dcdb.op_code == 3523*1da177e4SLinus Torvalds IPS_CMD_EXTENDED_DCDB_SG)) { 3524*1da177e4SLinus Torvalds tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; 3525*1da177e4SLinus Torvalds transfer_len = tapeDCDB->transfer_length; 3526*1da177e4SLinus Torvalds } else { 3527*1da177e4SLinus Torvalds transfer_len = 3528*1da177e4SLinus Torvalds (uint32_t) scb->dcdb.transfer_length; 3529*1da177e4SLinus Torvalds } 3530*1da177e4SLinus Torvalds 3531*1da177e4SLinus Torvalds if ((scb->bus) && (transfer_len < scb->data_len)) { 3532*1da177e4SLinus Torvalds /* Underrun - set default to no error */ 3533*1da177e4SLinus Torvalds errcode = DID_OK; 3534*1da177e4SLinus Torvalds 3535*1da177e4SLinus Torvalds /* Restrict access to physical DASD */ 3536*1da177e4SLinus Torvalds if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && 3537*1da177e4SLinus Torvalds ((((char *) scb->scsi_cmd-> 3538*1da177e4SLinus Torvalds buffer)[0] & 0x1f) == TYPE_DISK)) { 3539*1da177e4SLinus Torvalds /* underflow -- no error */ 3540*1da177e4SLinus Torvalds /* restrict access to physical DASD */ 3541*1da177e4SLinus Torvalds errcode = DID_TIME_OUT; 3542*1da177e4SLinus Torvalds break; 3543*1da177e4SLinus Torvalds } 3544*1da177e4SLinus Torvalds } else 3545*1da177e4SLinus Torvalds errcode = DID_ERROR; 3546*1da177e4SLinus Torvalds 3547*1da177e4SLinus Torvalds break; 3548*1da177e4SLinus Torvalds 3549*1da177e4SLinus Torvalds case IPS_ERR_RECOVERY: 3550*1da177e4SLinus Torvalds /* don't fail recovered errors */ 3551*1da177e4SLinus Torvalds if (scb->bus) 3552*1da177e4SLinus Torvalds errcode = DID_OK; 3553*1da177e4SLinus Torvalds 3554*1da177e4SLinus Torvalds break; 3555*1da177e4SLinus Torvalds 3556*1da177e4SLinus Torvalds case IPS_ERR_HOST_RESET: 3557*1da177e4SLinus Torvalds case IPS_ERR_DEV_RESET: 3558*1da177e4SLinus Torvalds errcode = DID_RESET; 3559*1da177e4SLinus Torvalds break; 3560*1da177e4SLinus Torvalds 3561*1da177e4SLinus Torvalds case IPS_ERR_CKCOND: 3562*1da177e4SLinus Torvalds if (scb->bus) { 3563*1da177e4SLinus Torvalds if ((scb->cmd.dcdb.op_code == 3564*1da177e4SLinus Torvalds IPS_CMD_EXTENDED_DCDB) 3565*1da177e4SLinus Torvalds || (scb->cmd.dcdb.op_code == 3566*1da177e4SLinus Torvalds IPS_CMD_EXTENDED_DCDB_SG)) { 3567*1da177e4SLinus Torvalds tapeDCDB = 3568*1da177e4SLinus Torvalds (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; 3569*1da177e4SLinus Torvalds memcpy(scb->scsi_cmd->sense_buffer, 3570*1da177e4SLinus Torvalds tapeDCDB->sense_info, 3571*1da177e4SLinus Torvalds sizeof (scb->scsi_cmd-> 3572*1da177e4SLinus Torvalds sense_buffer)); 3573*1da177e4SLinus Torvalds } else { 3574*1da177e4SLinus Torvalds memcpy(scb->scsi_cmd->sense_buffer, 3575*1da177e4SLinus Torvalds scb->dcdb.sense_info, 3576*1da177e4SLinus Torvalds sizeof (scb->scsi_cmd-> 3577*1da177e4SLinus Torvalds sense_buffer)); 3578*1da177e4SLinus Torvalds } 3579*1da177e4SLinus Torvalds device_error = 2; /* check condition */ 3580*1da177e4SLinus Torvalds } 3581*1da177e4SLinus Torvalds 3582*1da177e4SLinus Torvalds errcode = DID_OK; 3583*1da177e4SLinus Torvalds 3584*1da177e4SLinus Torvalds break; 3585*1da177e4SLinus Torvalds 3586*1da177e4SLinus Torvalds default: 3587*1da177e4SLinus Torvalds errcode = DID_ERROR; 3588*1da177e4SLinus Torvalds break; 3589*1da177e4SLinus Torvalds 3590*1da177e4SLinus Torvalds } /* end switch */ 3591*1da177e4SLinus Torvalds } /* end switch */ 3592*1da177e4SLinus Torvalds 3593*1da177e4SLinus Torvalds scb->scsi_cmd->result = device_error | (errcode << 16); 3594*1da177e4SLinus Torvalds 3595*1da177e4SLinus Torvalds return (1); 3596*1da177e4SLinus Torvalds } 3597*1da177e4SLinus Torvalds 3598*1da177e4SLinus Torvalds /****************************************************************************/ 3599*1da177e4SLinus Torvalds /* */ 3600*1da177e4SLinus Torvalds /* Routine Name: ips_send_wait */ 3601*1da177e4SLinus Torvalds /* */ 3602*1da177e4SLinus Torvalds /* Routine Description: */ 3603*1da177e4SLinus Torvalds /* */ 3604*1da177e4SLinus Torvalds /* Send a command to the controller and wait for it to return */ 3605*1da177e4SLinus Torvalds /* */ 3606*1da177e4SLinus Torvalds /* The FFDC Time Stamp use this function for the callback, but doesn't */ 3607*1da177e4SLinus Torvalds /* actually need to wait. */ 3608*1da177e4SLinus Torvalds /****************************************************************************/ 3609*1da177e4SLinus Torvalds static int 3610*1da177e4SLinus Torvalds ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) 3611*1da177e4SLinus Torvalds { 3612*1da177e4SLinus Torvalds int ret; 3613*1da177e4SLinus Torvalds 3614*1da177e4SLinus Torvalds METHOD_TRACE("ips_send_wait", 1); 3615*1da177e4SLinus Torvalds 3616*1da177e4SLinus Torvalds if (intr != IPS_FFDC) { /* Won't be Waiting if this is a Time Stamp */ 3617*1da177e4SLinus Torvalds ha->waitflag = TRUE; 3618*1da177e4SLinus Torvalds ha->cmd_in_progress = scb->cdb[0]; 3619*1da177e4SLinus Torvalds } 3620*1da177e4SLinus Torvalds scb->callback = ipsintr_blocking; 3621*1da177e4SLinus Torvalds ret = ips_send_cmd(ha, scb); 3622*1da177e4SLinus Torvalds 3623*1da177e4SLinus Torvalds if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) 3624*1da177e4SLinus Torvalds return (ret); 3625*1da177e4SLinus Torvalds 3626*1da177e4SLinus Torvalds if (intr != IPS_FFDC) /* Don't Wait around if this is a Time Stamp */ 3627*1da177e4SLinus Torvalds ret = ips_wait(ha, timeout, intr); 3628*1da177e4SLinus Torvalds 3629*1da177e4SLinus Torvalds return (ret); 3630*1da177e4SLinus Torvalds } 3631*1da177e4SLinus Torvalds 3632*1da177e4SLinus Torvalds /****************************************************************************/ 3633*1da177e4SLinus Torvalds /* */ 3634*1da177e4SLinus Torvalds /* Routine Name: ips_scmd_buf_write */ 3635*1da177e4SLinus Torvalds /* */ 3636*1da177e4SLinus Torvalds /* Routine Description: */ 3637*1da177e4SLinus Torvalds /* Write data to Scsi_Cmnd request_buffer at proper offsets */ 3638*1da177e4SLinus Torvalds /****************************************************************************/ 3639*1da177e4SLinus Torvalds static void 3640*1da177e4SLinus Torvalds ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned 3641*1da177e4SLinus Torvalds int count) 3642*1da177e4SLinus Torvalds { 3643*1da177e4SLinus Torvalds if (scmd->use_sg) { 3644*1da177e4SLinus Torvalds int i; 3645*1da177e4SLinus Torvalds unsigned int min_cnt, xfer_cnt; 3646*1da177e4SLinus Torvalds char *cdata = (char *) data; 3647*1da177e4SLinus Torvalds struct scatterlist *sg = scmd->request_buffer; 3648*1da177e4SLinus Torvalds for (i = 0, xfer_cnt = 0; 3649*1da177e4SLinus Torvalds (i < scmd->use_sg) && (xfer_cnt < count); i++) { 3650*1da177e4SLinus Torvalds if (!IPS_SG_ADDRESS(&sg[i])) 3651*1da177e4SLinus Torvalds return; 3652*1da177e4SLinus Torvalds min_cnt = min(count - xfer_cnt, sg[i].length); 3653*1da177e4SLinus Torvalds memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt], 3654*1da177e4SLinus Torvalds min_cnt); 3655*1da177e4SLinus Torvalds xfer_cnt += min_cnt; 3656*1da177e4SLinus Torvalds } 3657*1da177e4SLinus Torvalds 3658*1da177e4SLinus Torvalds } else { 3659*1da177e4SLinus Torvalds unsigned int min_cnt = min(count, scmd->request_bufflen); 3660*1da177e4SLinus Torvalds memcpy(scmd->request_buffer, data, min_cnt); 3661*1da177e4SLinus Torvalds } 3662*1da177e4SLinus Torvalds } 3663*1da177e4SLinus Torvalds 3664*1da177e4SLinus Torvalds /****************************************************************************/ 3665*1da177e4SLinus Torvalds /* */ 3666*1da177e4SLinus Torvalds /* Routine Name: ips_scmd_buf_read */ 3667*1da177e4SLinus Torvalds /* */ 3668*1da177e4SLinus Torvalds /* Routine Description: */ 3669*1da177e4SLinus Torvalds /* Copy data from a Scsi_Cmnd to a new, linear buffer */ 3670*1da177e4SLinus Torvalds /****************************************************************************/ 3671*1da177e4SLinus Torvalds static void 3672*1da177e4SLinus Torvalds ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned 3673*1da177e4SLinus Torvalds int count) 3674*1da177e4SLinus Torvalds { 3675*1da177e4SLinus Torvalds if (scmd->use_sg) { 3676*1da177e4SLinus Torvalds int i; 3677*1da177e4SLinus Torvalds unsigned int min_cnt, xfer_cnt; 3678*1da177e4SLinus Torvalds char *cdata = (char *) data; 3679*1da177e4SLinus Torvalds struct scatterlist *sg = scmd->request_buffer; 3680*1da177e4SLinus Torvalds for (i = 0, xfer_cnt = 0; 3681*1da177e4SLinus Torvalds (i < scmd->use_sg) && (xfer_cnt < count); i++) { 3682*1da177e4SLinus Torvalds if (!IPS_SG_ADDRESS(&sg[i])) 3683*1da177e4SLinus Torvalds return; 3684*1da177e4SLinus Torvalds min_cnt = min(count - xfer_cnt, sg[i].length); 3685*1da177e4SLinus Torvalds memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]), 3686*1da177e4SLinus Torvalds min_cnt); 3687*1da177e4SLinus Torvalds xfer_cnt += min_cnt; 3688*1da177e4SLinus Torvalds } 3689*1da177e4SLinus Torvalds 3690*1da177e4SLinus Torvalds } else { 3691*1da177e4SLinus Torvalds unsigned int min_cnt = min(count, scmd->request_bufflen); 3692*1da177e4SLinus Torvalds memcpy(data, scmd->request_buffer, min_cnt); 3693*1da177e4SLinus Torvalds } 3694*1da177e4SLinus Torvalds } 3695*1da177e4SLinus Torvalds 3696*1da177e4SLinus Torvalds /****************************************************************************/ 3697*1da177e4SLinus Torvalds /* */ 3698*1da177e4SLinus Torvalds /* Routine Name: ips_send_cmd */ 3699*1da177e4SLinus Torvalds /* */ 3700*1da177e4SLinus Torvalds /* Routine Description: */ 3701*1da177e4SLinus Torvalds /* */ 3702*1da177e4SLinus Torvalds /* Map SCSI commands to ServeRAID commands for logical drives */ 3703*1da177e4SLinus Torvalds /* */ 3704*1da177e4SLinus Torvalds /****************************************************************************/ 3705*1da177e4SLinus Torvalds static int 3706*1da177e4SLinus Torvalds ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) 3707*1da177e4SLinus Torvalds { 3708*1da177e4SLinus Torvalds int ret; 3709*1da177e4SLinus Torvalds char *sp; 3710*1da177e4SLinus Torvalds int device_error; 3711*1da177e4SLinus Torvalds IPS_DCDB_TABLE_TAPE *tapeDCDB; 3712*1da177e4SLinus Torvalds int TimeOut; 3713*1da177e4SLinus Torvalds 3714*1da177e4SLinus Torvalds METHOD_TRACE("ips_send_cmd", 1); 3715*1da177e4SLinus Torvalds 3716*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 3717*1da177e4SLinus Torvalds 3718*1da177e4SLinus Torvalds if (!scb->scsi_cmd) { 3719*1da177e4SLinus Torvalds /* internal command */ 3720*1da177e4SLinus Torvalds 3721*1da177e4SLinus Torvalds if (scb->bus > 0) { 3722*1da177e4SLinus Torvalds /* Controller commands can't be issued */ 3723*1da177e4SLinus Torvalds /* to real devices -- fail them */ 3724*1da177e4SLinus Torvalds if ((ha->waitflag == TRUE) && 3725*1da177e4SLinus Torvalds (ha->cmd_in_progress == scb->cdb[0])) { 3726*1da177e4SLinus Torvalds ha->waitflag = FALSE; 3727*1da177e4SLinus Torvalds } 3728*1da177e4SLinus Torvalds 3729*1da177e4SLinus Torvalds return (1); 3730*1da177e4SLinus Torvalds } 3731*1da177e4SLinus Torvalds } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) { 3732*1da177e4SLinus Torvalds /* command to logical bus -- interpret */ 3733*1da177e4SLinus Torvalds ret = IPS_SUCCESS_IMM; 3734*1da177e4SLinus Torvalds 3735*1da177e4SLinus Torvalds switch (scb->scsi_cmd->cmnd[0]) { 3736*1da177e4SLinus Torvalds case ALLOW_MEDIUM_REMOVAL: 3737*1da177e4SLinus Torvalds case REZERO_UNIT: 3738*1da177e4SLinus Torvalds case ERASE: 3739*1da177e4SLinus Torvalds case WRITE_FILEMARKS: 3740*1da177e4SLinus Torvalds case SPACE: 3741*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_ERROR << 16; 3742*1da177e4SLinus Torvalds break; 3743*1da177e4SLinus Torvalds 3744*1da177e4SLinus Torvalds case START_STOP: 3745*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3746*1da177e4SLinus Torvalds 3747*1da177e4SLinus Torvalds case TEST_UNIT_READY: 3748*1da177e4SLinus Torvalds case INQUIRY: 3749*1da177e4SLinus Torvalds if (scb->target_id == IPS_ADAPTER_ID) { 3750*1da177e4SLinus Torvalds /* 3751*1da177e4SLinus Torvalds * Either we have a TUR 3752*1da177e4SLinus Torvalds * or we have a SCSI inquiry 3753*1da177e4SLinus Torvalds */ 3754*1da177e4SLinus Torvalds if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY) 3755*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3756*1da177e4SLinus Torvalds 3757*1da177e4SLinus Torvalds if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 3758*1da177e4SLinus Torvalds IPS_SCSI_INQ_DATA inquiry; 3759*1da177e4SLinus Torvalds 3760*1da177e4SLinus Torvalds memset(&inquiry, 0, 3761*1da177e4SLinus Torvalds sizeof (IPS_SCSI_INQ_DATA)); 3762*1da177e4SLinus Torvalds 3763*1da177e4SLinus Torvalds inquiry.DeviceType = 3764*1da177e4SLinus Torvalds IPS_SCSI_INQ_TYPE_PROCESSOR; 3765*1da177e4SLinus Torvalds inquiry.DeviceTypeQualifier = 3766*1da177e4SLinus Torvalds IPS_SCSI_INQ_LU_CONNECTED; 3767*1da177e4SLinus Torvalds inquiry.Version = IPS_SCSI_INQ_REV2; 3768*1da177e4SLinus Torvalds inquiry.ResponseDataFormat = 3769*1da177e4SLinus Torvalds IPS_SCSI_INQ_RD_REV2; 3770*1da177e4SLinus Torvalds inquiry.AdditionalLength = 31; 3771*1da177e4SLinus Torvalds inquiry.Flags[0] = 3772*1da177e4SLinus Torvalds IPS_SCSI_INQ_Address16; 3773*1da177e4SLinus Torvalds inquiry.Flags[1] = 3774*1da177e4SLinus Torvalds IPS_SCSI_INQ_WBus16 | 3775*1da177e4SLinus Torvalds IPS_SCSI_INQ_Sync; 3776*1da177e4SLinus Torvalds strncpy(inquiry.VendorId, "IBM ", 3777*1da177e4SLinus Torvalds 8); 3778*1da177e4SLinus Torvalds strncpy(inquiry.ProductId, 3779*1da177e4SLinus Torvalds "SERVERAID ", 16); 3780*1da177e4SLinus Torvalds strncpy(inquiry.ProductRevisionLevel, 3781*1da177e4SLinus Torvalds "1.00", 4); 3782*1da177e4SLinus Torvalds 3783*1da177e4SLinus Torvalds ips_scmd_buf_write(scb->scsi_cmd, 3784*1da177e4SLinus Torvalds &inquiry, 3785*1da177e4SLinus Torvalds sizeof (inquiry)); 3786*1da177e4SLinus Torvalds 3787*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3788*1da177e4SLinus Torvalds } 3789*1da177e4SLinus Torvalds } else { 3790*1da177e4SLinus Torvalds scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; 3791*1da177e4SLinus Torvalds scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); 3792*1da177e4SLinus Torvalds scb->cmd.logical_info.reserved = 0; 3793*1da177e4SLinus Torvalds scb->cmd.logical_info.reserved2 = 0; 3794*1da177e4SLinus Torvalds scb->data_len = sizeof (IPS_LD_INFO); 3795*1da177e4SLinus Torvalds scb->data_busaddr = ha->logical_drive_info_dma_addr; 3796*1da177e4SLinus Torvalds scb->flags = 0; 3797*1da177e4SLinus Torvalds scb->cmd.logical_info.buffer_addr = scb->data_busaddr; 3798*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 3799*1da177e4SLinus Torvalds } 3800*1da177e4SLinus Torvalds 3801*1da177e4SLinus Torvalds break; 3802*1da177e4SLinus Torvalds 3803*1da177e4SLinus Torvalds case REQUEST_SENSE: 3804*1da177e4SLinus Torvalds ips_reqsen(ha, scb); 3805*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3806*1da177e4SLinus Torvalds break; 3807*1da177e4SLinus Torvalds 3808*1da177e4SLinus Torvalds case READ_6: 3809*1da177e4SLinus Torvalds case WRITE_6: 3810*1da177e4SLinus Torvalds if (!scb->sg_len) { 3811*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = 3812*1da177e4SLinus Torvalds (scb->scsi_cmd->cmnd[0] == 3813*1da177e4SLinus Torvalds READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE; 3814*1da177e4SLinus Torvalds scb->cmd.basic_io.enhanced_sg = 0; 3815*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = 3816*1da177e4SLinus Torvalds cpu_to_le32(scb->data_busaddr); 3817*1da177e4SLinus Torvalds } else { 3818*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = 3819*1da177e4SLinus Torvalds (scb->scsi_cmd->cmnd[0] == 3820*1da177e4SLinus Torvalds READ_6) ? IPS_CMD_READ_SG : 3821*1da177e4SLinus Torvalds IPS_CMD_WRITE_SG; 3822*1da177e4SLinus Torvalds scb->cmd.basic_io.enhanced_sg = 3823*1da177e4SLinus Torvalds IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 3824*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = 3825*1da177e4SLinus Torvalds cpu_to_le32(scb->sg_busaddr); 3826*1da177e4SLinus Torvalds } 3827*1da177e4SLinus Torvalds 3828*1da177e4SLinus Torvalds scb->cmd.basic_io.segment_4G = 0; 3829*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 3830*1da177e4SLinus Torvalds scb->cmd.basic_io.log_drv = scb->target_id; 3831*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_count = scb->sg_len; 3832*1da177e4SLinus Torvalds 3833*1da177e4SLinus Torvalds if (scb->cmd.basic_io.lba) 3834*1da177e4SLinus Torvalds scb->cmd.basic_io.lba = 3835*1da177e4SLinus Torvalds cpu_to_le32(le32_to_cpu 3836*1da177e4SLinus Torvalds (scb->cmd.basic_io.lba) + 3837*1da177e4SLinus Torvalds le16_to_cpu(scb->cmd.basic_io. 3838*1da177e4SLinus Torvalds sector_count)); 3839*1da177e4SLinus Torvalds else 3840*1da177e4SLinus Torvalds scb->cmd.basic_io.lba = 3841*1da177e4SLinus Torvalds (((scb->scsi_cmd-> 3842*1da177e4SLinus Torvalds cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd-> 3843*1da177e4SLinus Torvalds cmnd[2] << 8) | 3844*1da177e4SLinus Torvalds (scb->scsi_cmd->cmnd[3])); 3845*1da177e4SLinus Torvalds 3846*1da177e4SLinus Torvalds scb->cmd.basic_io.sector_count = 3847*1da177e4SLinus Torvalds cpu_to_le16(scb->data_len / IPS_BLKSIZE); 3848*1da177e4SLinus Torvalds 3849*1da177e4SLinus Torvalds if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0) 3850*1da177e4SLinus Torvalds scb->cmd.basic_io.sector_count = 3851*1da177e4SLinus Torvalds cpu_to_le16(256); 3852*1da177e4SLinus Torvalds 3853*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 3854*1da177e4SLinus Torvalds break; 3855*1da177e4SLinus Torvalds 3856*1da177e4SLinus Torvalds case READ_10: 3857*1da177e4SLinus Torvalds case WRITE_10: 3858*1da177e4SLinus Torvalds if (!scb->sg_len) { 3859*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = 3860*1da177e4SLinus Torvalds (scb->scsi_cmd->cmnd[0] == 3861*1da177e4SLinus Torvalds READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE; 3862*1da177e4SLinus Torvalds scb->cmd.basic_io.enhanced_sg = 0; 3863*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = 3864*1da177e4SLinus Torvalds cpu_to_le32(scb->data_busaddr); 3865*1da177e4SLinus Torvalds } else { 3866*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = 3867*1da177e4SLinus Torvalds (scb->scsi_cmd->cmnd[0] == 3868*1da177e4SLinus Torvalds READ_10) ? IPS_CMD_READ_SG : 3869*1da177e4SLinus Torvalds IPS_CMD_WRITE_SG; 3870*1da177e4SLinus Torvalds scb->cmd.basic_io.enhanced_sg = 3871*1da177e4SLinus Torvalds IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 3872*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = 3873*1da177e4SLinus Torvalds cpu_to_le32(scb->sg_busaddr); 3874*1da177e4SLinus Torvalds } 3875*1da177e4SLinus Torvalds 3876*1da177e4SLinus Torvalds scb->cmd.basic_io.segment_4G = 0; 3877*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 3878*1da177e4SLinus Torvalds scb->cmd.basic_io.log_drv = scb->target_id; 3879*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_count = scb->sg_len; 3880*1da177e4SLinus Torvalds 3881*1da177e4SLinus Torvalds if (scb->cmd.basic_io.lba) 3882*1da177e4SLinus Torvalds scb->cmd.basic_io.lba = 3883*1da177e4SLinus Torvalds cpu_to_le32(le32_to_cpu 3884*1da177e4SLinus Torvalds (scb->cmd.basic_io.lba) + 3885*1da177e4SLinus Torvalds le16_to_cpu(scb->cmd.basic_io. 3886*1da177e4SLinus Torvalds sector_count)); 3887*1da177e4SLinus Torvalds else 3888*1da177e4SLinus Torvalds scb->cmd.basic_io.lba = 3889*1da177e4SLinus Torvalds ((scb->scsi_cmd->cmnd[2] << 24) | (scb-> 3890*1da177e4SLinus Torvalds scsi_cmd-> 3891*1da177e4SLinus Torvalds cmnd[3] 3892*1da177e4SLinus Torvalds << 16) | 3893*1da177e4SLinus Torvalds (scb->scsi_cmd->cmnd[4] << 8) | scb-> 3894*1da177e4SLinus Torvalds scsi_cmd->cmnd[5]); 3895*1da177e4SLinus Torvalds 3896*1da177e4SLinus Torvalds scb->cmd.basic_io.sector_count = 3897*1da177e4SLinus Torvalds cpu_to_le16(scb->data_len / IPS_BLKSIZE); 3898*1da177e4SLinus Torvalds 3899*1da177e4SLinus Torvalds if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) { 3900*1da177e4SLinus Torvalds /* 3901*1da177e4SLinus Torvalds * This is a null condition 3902*1da177e4SLinus Torvalds * we don't have to do anything 3903*1da177e4SLinus Torvalds * so just return 3904*1da177e4SLinus Torvalds */ 3905*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3906*1da177e4SLinus Torvalds } else 3907*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 3908*1da177e4SLinus Torvalds 3909*1da177e4SLinus Torvalds break; 3910*1da177e4SLinus Torvalds 3911*1da177e4SLinus Torvalds case RESERVE: 3912*1da177e4SLinus Torvalds case RELEASE: 3913*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3914*1da177e4SLinus Torvalds break; 3915*1da177e4SLinus Torvalds 3916*1da177e4SLinus Torvalds case MODE_SENSE: 3917*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; 3918*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 3919*1da177e4SLinus Torvalds scb->cmd.basic_io.segment_4G = 0; 3920*1da177e4SLinus Torvalds scb->cmd.basic_io.enhanced_sg = 0; 3921*1da177e4SLinus Torvalds scb->data_len = sizeof (*ha->enq); 3922*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = ha->enq_busaddr; 3923*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 3924*1da177e4SLinus Torvalds break; 3925*1da177e4SLinus Torvalds 3926*1da177e4SLinus Torvalds case READ_CAPACITY: 3927*1da177e4SLinus Torvalds scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; 3928*1da177e4SLinus Torvalds scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); 3929*1da177e4SLinus Torvalds scb->cmd.logical_info.reserved = 0; 3930*1da177e4SLinus Torvalds scb->cmd.logical_info.reserved2 = 0; 3931*1da177e4SLinus Torvalds scb->cmd.logical_info.reserved3 = 0; 3932*1da177e4SLinus Torvalds scb->data_len = sizeof (IPS_LD_INFO); 3933*1da177e4SLinus Torvalds scb->data_busaddr = ha->logical_drive_info_dma_addr; 3934*1da177e4SLinus Torvalds scb->flags = 0; 3935*1da177e4SLinus Torvalds scb->cmd.logical_info.buffer_addr = scb->data_busaddr; 3936*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 3937*1da177e4SLinus Torvalds break; 3938*1da177e4SLinus Torvalds 3939*1da177e4SLinus Torvalds case SEND_DIAGNOSTIC: 3940*1da177e4SLinus Torvalds case REASSIGN_BLOCKS: 3941*1da177e4SLinus Torvalds case FORMAT_UNIT: 3942*1da177e4SLinus Torvalds case SEEK_10: 3943*1da177e4SLinus Torvalds case VERIFY: 3944*1da177e4SLinus Torvalds case READ_DEFECT_DATA: 3945*1da177e4SLinus Torvalds case READ_BUFFER: 3946*1da177e4SLinus Torvalds case WRITE_BUFFER: 3947*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_OK << 16; 3948*1da177e4SLinus Torvalds break; 3949*1da177e4SLinus Torvalds 3950*1da177e4SLinus Torvalds default: 3951*1da177e4SLinus Torvalds /* Set the Return Info to appear like the Command was */ 3952*1da177e4SLinus Torvalds /* attempted, a Check Condition occurred, and Sense */ 3953*1da177e4SLinus Torvalds /* Data indicating an Invalid CDB OpCode is returned. */ 3954*1da177e4SLinus Torvalds sp = (char *) scb->scsi_cmd->sense_buffer; 3955*1da177e4SLinus Torvalds memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer)); 3956*1da177e4SLinus Torvalds 3957*1da177e4SLinus Torvalds sp[0] = 0x70; /* Error Code */ 3958*1da177e4SLinus Torvalds sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */ 3959*1da177e4SLinus Torvalds sp[7] = 0x0A; /* Additional Sense Length */ 3960*1da177e4SLinus Torvalds sp[12] = 0x20; /* ASC = Invalid OpCode */ 3961*1da177e4SLinus Torvalds sp[13] = 0x00; /* ASCQ */ 3962*1da177e4SLinus Torvalds 3963*1da177e4SLinus Torvalds device_error = 2; /* Indicate Check Condition */ 3964*1da177e4SLinus Torvalds scb->scsi_cmd->result = device_error | (DID_OK << 16); 3965*1da177e4SLinus Torvalds break; 3966*1da177e4SLinus Torvalds } /* end switch */ 3967*1da177e4SLinus Torvalds } 3968*1da177e4SLinus Torvalds /* end if */ 3969*1da177e4SLinus Torvalds if (ret == IPS_SUCCESS_IMM) 3970*1da177e4SLinus Torvalds return (ret); 3971*1da177e4SLinus Torvalds 3972*1da177e4SLinus Torvalds /* setup DCDB */ 3973*1da177e4SLinus Torvalds if (scb->bus > 0) { 3974*1da177e4SLinus Torvalds 3975*1da177e4SLinus Torvalds /* If we already know the Device is Not there, no need to attempt a Command */ 3976*1da177e4SLinus Torvalds /* This also protects an NT FailOver Controller from getting CDB's sent to it */ 3977*1da177e4SLinus Torvalds if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) { 3978*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_NO_CONNECT << 16; 3979*1da177e4SLinus Torvalds return (IPS_SUCCESS_IMM); 3980*1da177e4SLinus Torvalds } 3981*1da177e4SLinus Torvalds 3982*1da177e4SLinus Torvalds ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id); 3983*1da177e4SLinus Torvalds scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); 3984*1da177e4SLinus Torvalds scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + 3985*1da177e4SLinus Torvalds (unsigned long) &scb-> 3986*1da177e4SLinus Torvalds dcdb - 3987*1da177e4SLinus Torvalds (unsigned long) scb); 3988*1da177e4SLinus Torvalds scb->cmd.dcdb.reserved = 0; 3989*1da177e4SLinus Torvalds scb->cmd.dcdb.reserved2 = 0; 3990*1da177e4SLinus Torvalds scb->cmd.dcdb.reserved3 = 0; 3991*1da177e4SLinus Torvalds scb->cmd.dcdb.segment_4G = 0; 3992*1da177e4SLinus Torvalds scb->cmd.dcdb.enhanced_sg = 0; 3993*1da177e4SLinus Torvalds 3994*1da177e4SLinus Torvalds TimeOut = scb->scsi_cmd->timeout_per_command; 3995*1da177e4SLinus Torvalds 3996*1da177e4SLinus Torvalds if (ha->subsys->param[4] & 0x00100000) { /* If NEW Tape DCDB is Supported */ 3997*1da177e4SLinus Torvalds if (!scb->sg_len) { 3998*1da177e4SLinus Torvalds scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB; 3999*1da177e4SLinus Torvalds } else { 4000*1da177e4SLinus Torvalds scb->cmd.dcdb.op_code = 4001*1da177e4SLinus Torvalds IPS_CMD_EXTENDED_DCDB_SG; 4002*1da177e4SLinus Torvalds scb->cmd.dcdb.enhanced_sg = 4003*1da177e4SLinus Torvalds IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 4004*1da177e4SLinus Torvalds } 4005*1da177e4SLinus Torvalds 4006*1da177e4SLinus Torvalds tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; /* Use Same Data Area as Old DCDB Struct */ 4007*1da177e4SLinus Torvalds tapeDCDB->device_address = 4008*1da177e4SLinus Torvalds ((scb->bus - 1) << 4) | scb->target_id; 4009*1da177e4SLinus Torvalds tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED; 4010*1da177e4SLinus Torvalds tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K; /* Always Turn OFF 64K Size Flag */ 4011*1da177e4SLinus Torvalds 4012*1da177e4SLinus Torvalds if (TimeOut) { 4013*1da177e4SLinus Torvalds if (TimeOut < (10 * HZ)) 4014*1da177e4SLinus Torvalds tapeDCDB->cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */ 4015*1da177e4SLinus Torvalds else if (TimeOut < (60 * HZ)) 4016*1da177e4SLinus Torvalds tapeDCDB->cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */ 4017*1da177e4SLinus Torvalds else if (TimeOut < (1200 * HZ)) 4018*1da177e4SLinus Torvalds tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */ 4019*1da177e4SLinus Torvalds } 4020*1da177e4SLinus Torvalds 4021*1da177e4SLinus Torvalds tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len; 4022*1da177e4SLinus Torvalds tapeDCDB->reserved_for_LUN = 0; 4023*1da177e4SLinus Torvalds tapeDCDB->transfer_length = scb->data_len; 4024*1da177e4SLinus Torvalds if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG) 4025*1da177e4SLinus Torvalds tapeDCDB->buffer_pointer = 4026*1da177e4SLinus Torvalds cpu_to_le32(scb->sg_busaddr); 4027*1da177e4SLinus Torvalds else 4028*1da177e4SLinus Torvalds tapeDCDB->buffer_pointer = 4029*1da177e4SLinus Torvalds cpu_to_le32(scb->data_busaddr); 4030*1da177e4SLinus Torvalds tapeDCDB->sg_count = scb->sg_len; 4031*1da177e4SLinus Torvalds tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info); 4032*1da177e4SLinus Torvalds tapeDCDB->scsi_status = 0; 4033*1da177e4SLinus Torvalds tapeDCDB->reserved = 0; 4034*1da177e4SLinus Torvalds memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, 4035*1da177e4SLinus Torvalds scb->scsi_cmd->cmd_len); 4036*1da177e4SLinus Torvalds } else { 4037*1da177e4SLinus Torvalds if (!scb->sg_len) { 4038*1da177e4SLinus Torvalds scb->cmd.dcdb.op_code = IPS_CMD_DCDB; 4039*1da177e4SLinus Torvalds } else { 4040*1da177e4SLinus Torvalds scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG; 4041*1da177e4SLinus Torvalds scb->cmd.dcdb.enhanced_sg = 4042*1da177e4SLinus Torvalds IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 4043*1da177e4SLinus Torvalds } 4044*1da177e4SLinus Torvalds 4045*1da177e4SLinus Torvalds scb->dcdb.device_address = 4046*1da177e4SLinus Torvalds ((scb->bus - 1) << 4) | scb->target_id; 4047*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED; 4048*1da177e4SLinus Torvalds 4049*1da177e4SLinus Torvalds if (TimeOut) { 4050*1da177e4SLinus Torvalds if (TimeOut < (10 * HZ)) 4051*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */ 4052*1da177e4SLinus Torvalds else if (TimeOut < (60 * HZ)) 4053*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */ 4054*1da177e4SLinus Torvalds else if (TimeOut < (1200 * HZ)) 4055*1da177e4SLinus Torvalds scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */ 4056*1da177e4SLinus Torvalds } 4057*1da177e4SLinus Torvalds 4058*1da177e4SLinus Torvalds scb->dcdb.transfer_length = scb->data_len; 4059*1da177e4SLinus Torvalds if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K) 4060*1da177e4SLinus Torvalds scb->dcdb.transfer_length = 0; 4061*1da177e4SLinus Torvalds if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG) 4062*1da177e4SLinus Torvalds scb->dcdb.buffer_pointer = 4063*1da177e4SLinus Torvalds cpu_to_le32(scb->sg_busaddr); 4064*1da177e4SLinus Torvalds else 4065*1da177e4SLinus Torvalds scb->dcdb.buffer_pointer = 4066*1da177e4SLinus Torvalds cpu_to_le32(scb->data_busaddr); 4067*1da177e4SLinus Torvalds scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len; 4068*1da177e4SLinus Torvalds scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info); 4069*1da177e4SLinus Torvalds scb->dcdb.sg_count = scb->sg_len; 4070*1da177e4SLinus Torvalds scb->dcdb.reserved = 0; 4071*1da177e4SLinus Torvalds memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, 4072*1da177e4SLinus Torvalds scb->scsi_cmd->cmd_len); 4073*1da177e4SLinus Torvalds scb->dcdb.scsi_status = 0; 4074*1da177e4SLinus Torvalds scb->dcdb.reserved2[0] = 0; 4075*1da177e4SLinus Torvalds scb->dcdb.reserved2[1] = 0; 4076*1da177e4SLinus Torvalds scb->dcdb.reserved2[2] = 0; 4077*1da177e4SLinus Torvalds } 4078*1da177e4SLinus Torvalds } 4079*1da177e4SLinus Torvalds 4080*1da177e4SLinus Torvalds return ((*ha->func.issue) (ha, scb)); 4081*1da177e4SLinus Torvalds } 4082*1da177e4SLinus Torvalds 4083*1da177e4SLinus Torvalds /****************************************************************************/ 4084*1da177e4SLinus Torvalds /* */ 4085*1da177e4SLinus Torvalds /* Routine Name: ips_chk_status */ 4086*1da177e4SLinus Torvalds /* */ 4087*1da177e4SLinus Torvalds /* Routine Description: */ 4088*1da177e4SLinus Torvalds /* */ 4089*1da177e4SLinus Torvalds /* Check the status of commands to logical drives */ 4090*1da177e4SLinus Torvalds /* Assumed to be called with the HA lock */ 4091*1da177e4SLinus Torvalds /****************************************************************************/ 4092*1da177e4SLinus Torvalds static void 4093*1da177e4SLinus Torvalds ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) 4094*1da177e4SLinus Torvalds { 4095*1da177e4SLinus Torvalds ips_scb_t *scb; 4096*1da177e4SLinus Torvalds ips_stat_t *sp; 4097*1da177e4SLinus Torvalds uint8_t basic_status; 4098*1da177e4SLinus Torvalds uint8_t ext_status; 4099*1da177e4SLinus Torvalds int errcode; 4100*1da177e4SLinus Torvalds 4101*1da177e4SLinus Torvalds METHOD_TRACE("ips_chkstatus", 1); 4102*1da177e4SLinus Torvalds 4103*1da177e4SLinus Torvalds scb = &ha->scbs[pstatus->fields.command_id]; 4104*1da177e4SLinus Torvalds scb->basic_status = basic_status = 4105*1da177e4SLinus Torvalds pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK; 4106*1da177e4SLinus Torvalds scb->extended_status = ext_status = pstatus->fields.extended_status; 4107*1da177e4SLinus Torvalds 4108*1da177e4SLinus Torvalds sp = &ha->sp; 4109*1da177e4SLinus Torvalds sp->residue_len = 0; 4110*1da177e4SLinus Torvalds sp->scb_addr = (void *) scb; 4111*1da177e4SLinus Torvalds 4112*1da177e4SLinus Torvalds /* Remove the item from the active queue */ 4113*1da177e4SLinus Torvalds ips_removeq_scb(&ha->scb_activelist, scb); 4114*1da177e4SLinus Torvalds 4115*1da177e4SLinus Torvalds if (!scb->scsi_cmd) 4116*1da177e4SLinus Torvalds /* internal commands are handled in do_ipsintr */ 4117*1da177e4SLinus Torvalds return; 4118*1da177e4SLinus Torvalds 4119*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)", 4120*1da177e4SLinus Torvalds ips_name, 4121*1da177e4SLinus Torvalds ha->host_num, 4122*1da177e4SLinus Torvalds scb->cdb[0], 4123*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id, 4124*1da177e4SLinus Torvalds scb->bus, scb->target_id, scb->lun); 4125*1da177e4SLinus Torvalds 4126*1da177e4SLinus Torvalds if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) 4127*1da177e4SLinus Torvalds /* passthru - just returns the raw result */ 4128*1da177e4SLinus Torvalds return; 4129*1da177e4SLinus Torvalds 4130*1da177e4SLinus Torvalds errcode = DID_OK; 4131*1da177e4SLinus Torvalds 4132*1da177e4SLinus Torvalds if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) || 4133*1da177e4SLinus Torvalds ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) { 4134*1da177e4SLinus Torvalds 4135*1da177e4SLinus Torvalds if (scb->bus == 0) { 4136*1da177e4SLinus Torvalds if ((basic_status & IPS_GSC_STATUS_MASK) == 4137*1da177e4SLinus Torvalds IPS_CMD_RECOVERED_ERROR) { 4138*1da177e4SLinus Torvalds DEBUG_VAR(1, 4139*1da177e4SLinus Torvalds "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", 4140*1da177e4SLinus Torvalds ips_name, ha->host_num, 4141*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code, 4142*1da177e4SLinus Torvalds basic_status, ext_status); 4143*1da177e4SLinus Torvalds } 4144*1da177e4SLinus Torvalds 4145*1da177e4SLinus Torvalds switch (scb->scsi_cmd->cmnd[0]) { 4146*1da177e4SLinus Torvalds case ALLOW_MEDIUM_REMOVAL: 4147*1da177e4SLinus Torvalds case REZERO_UNIT: 4148*1da177e4SLinus Torvalds case ERASE: 4149*1da177e4SLinus Torvalds case WRITE_FILEMARKS: 4150*1da177e4SLinus Torvalds case SPACE: 4151*1da177e4SLinus Torvalds errcode = DID_ERROR; 4152*1da177e4SLinus Torvalds break; 4153*1da177e4SLinus Torvalds 4154*1da177e4SLinus Torvalds case START_STOP: 4155*1da177e4SLinus Torvalds break; 4156*1da177e4SLinus Torvalds 4157*1da177e4SLinus Torvalds case TEST_UNIT_READY: 4158*1da177e4SLinus Torvalds if (!ips_online(ha, scb)) { 4159*1da177e4SLinus Torvalds errcode = DID_TIME_OUT; 4160*1da177e4SLinus Torvalds } 4161*1da177e4SLinus Torvalds break; 4162*1da177e4SLinus Torvalds 4163*1da177e4SLinus Torvalds case INQUIRY: 4164*1da177e4SLinus Torvalds if (ips_online(ha, scb)) { 4165*1da177e4SLinus Torvalds ips_inquiry(ha, scb); 4166*1da177e4SLinus Torvalds } else { 4167*1da177e4SLinus Torvalds errcode = DID_TIME_OUT; 4168*1da177e4SLinus Torvalds } 4169*1da177e4SLinus Torvalds break; 4170*1da177e4SLinus Torvalds 4171*1da177e4SLinus Torvalds case REQUEST_SENSE: 4172*1da177e4SLinus Torvalds ips_reqsen(ha, scb); 4173*1da177e4SLinus Torvalds break; 4174*1da177e4SLinus Torvalds 4175*1da177e4SLinus Torvalds case READ_6: 4176*1da177e4SLinus Torvalds case WRITE_6: 4177*1da177e4SLinus Torvalds case READ_10: 4178*1da177e4SLinus Torvalds case WRITE_10: 4179*1da177e4SLinus Torvalds case RESERVE: 4180*1da177e4SLinus Torvalds case RELEASE: 4181*1da177e4SLinus Torvalds break; 4182*1da177e4SLinus Torvalds 4183*1da177e4SLinus Torvalds case MODE_SENSE: 4184*1da177e4SLinus Torvalds if (!ips_online(ha, scb) 4185*1da177e4SLinus Torvalds || !ips_msense(ha, scb)) { 4186*1da177e4SLinus Torvalds errcode = DID_ERROR; 4187*1da177e4SLinus Torvalds } 4188*1da177e4SLinus Torvalds break; 4189*1da177e4SLinus Torvalds 4190*1da177e4SLinus Torvalds case READ_CAPACITY: 4191*1da177e4SLinus Torvalds if (ips_online(ha, scb)) 4192*1da177e4SLinus Torvalds ips_rdcap(ha, scb); 4193*1da177e4SLinus Torvalds else { 4194*1da177e4SLinus Torvalds errcode = DID_TIME_OUT; 4195*1da177e4SLinus Torvalds } 4196*1da177e4SLinus Torvalds break; 4197*1da177e4SLinus Torvalds 4198*1da177e4SLinus Torvalds case SEND_DIAGNOSTIC: 4199*1da177e4SLinus Torvalds case REASSIGN_BLOCKS: 4200*1da177e4SLinus Torvalds break; 4201*1da177e4SLinus Torvalds 4202*1da177e4SLinus Torvalds case FORMAT_UNIT: 4203*1da177e4SLinus Torvalds errcode = DID_ERROR; 4204*1da177e4SLinus Torvalds break; 4205*1da177e4SLinus Torvalds 4206*1da177e4SLinus Torvalds case SEEK_10: 4207*1da177e4SLinus Torvalds case VERIFY: 4208*1da177e4SLinus Torvalds case READ_DEFECT_DATA: 4209*1da177e4SLinus Torvalds case READ_BUFFER: 4210*1da177e4SLinus Torvalds case WRITE_BUFFER: 4211*1da177e4SLinus Torvalds break; 4212*1da177e4SLinus Torvalds 4213*1da177e4SLinus Torvalds default: 4214*1da177e4SLinus Torvalds errcode = DID_ERROR; 4215*1da177e4SLinus Torvalds } /* end switch */ 4216*1da177e4SLinus Torvalds 4217*1da177e4SLinus Torvalds scb->scsi_cmd->result = errcode << 16; 4218*1da177e4SLinus Torvalds } else { /* bus == 0 */ 4219*1da177e4SLinus Torvalds /* restrict access to physical drives */ 4220*1da177e4SLinus Torvalds if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && 4221*1da177e4SLinus Torvalds ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == 4222*1da177e4SLinus Torvalds TYPE_DISK)) { 4223*1da177e4SLinus Torvalds 4224*1da177e4SLinus Torvalds scb->scsi_cmd->result = DID_TIME_OUT << 16; 4225*1da177e4SLinus Torvalds } 4226*1da177e4SLinus Torvalds } /* else */ 4227*1da177e4SLinus Torvalds } else { /* recovered error / success */ 4228*1da177e4SLinus Torvalds if (scb->bus == 0) { 4229*1da177e4SLinus Torvalds DEBUG_VAR(1, 4230*1da177e4SLinus Torvalds "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", 4231*1da177e4SLinus Torvalds ips_name, ha->host_num, 4232*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code, basic_status, 4233*1da177e4SLinus Torvalds ext_status); 4234*1da177e4SLinus Torvalds } 4235*1da177e4SLinus Torvalds 4236*1da177e4SLinus Torvalds ips_map_status(ha, scb, sp); 4237*1da177e4SLinus Torvalds } /* else */ 4238*1da177e4SLinus Torvalds } 4239*1da177e4SLinus Torvalds 4240*1da177e4SLinus Torvalds /****************************************************************************/ 4241*1da177e4SLinus Torvalds /* */ 4242*1da177e4SLinus Torvalds /* Routine Name: ips_online */ 4243*1da177e4SLinus Torvalds /* */ 4244*1da177e4SLinus Torvalds /* Routine Description: */ 4245*1da177e4SLinus Torvalds /* */ 4246*1da177e4SLinus Torvalds /* Determine if a logical drive is online */ 4247*1da177e4SLinus Torvalds /* */ 4248*1da177e4SLinus Torvalds /****************************************************************************/ 4249*1da177e4SLinus Torvalds static int 4250*1da177e4SLinus Torvalds ips_online(ips_ha_t * ha, ips_scb_t * scb) 4251*1da177e4SLinus Torvalds { 4252*1da177e4SLinus Torvalds METHOD_TRACE("ips_online", 1); 4253*1da177e4SLinus Torvalds 4254*1da177e4SLinus Torvalds if (scb->target_id >= IPS_MAX_LD) 4255*1da177e4SLinus Torvalds return (0); 4256*1da177e4SLinus Torvalds 4257*1da177e4SLinus Torvalds if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) { 4258*1da177e4SLinus Torvalds memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO)); 4259*1da177e4SLinus Torvalds return (0); 4260*1da177e4SLinus Torvalds } 4261*1da177e4SLinus Torvalds 4262*1da177e4SLinus Torvalds if (ha->logical_drive_info->drive_info[scb->target_id].state != 4263*1da177e4SLinus Torvalds IPS_LD_OFFLINE 4264*1da177e4SLinus Torvalds && ha->logical_drive_info->drive_info[scb->target_id].state != 4265*1da177e4SLinus Torvalds IPS_LD_FREE 4266*1da177e4SLinus Torvalds && ha->logical_drive_info->drive_info[scb->target_id].state != 4267*1da177e4SLinus Torvalds IPS_LD_CRS 4268*1da177e4SLinus Torvalds && ha->logical_drive_info->drive_info[scb->target_id].state != 4269*1da177e4SLinus Torvalds IPS_LD_SYS) 4270*1da177e4SLinus Torvalds return (1); 4271*1da177e4SLinus Torvalds else 4272*1da177e4SLinus Torvalds return (0); 4273*1da177e4SLinus Torvalds } 4274*1da177e4SLinus Torvalds 4275*1da177e4SLinus Torvalds /****************************************************************************/ 4276*1da177e4SLinus Torvalds /* */ 4277*1da177e4SLinus Torvalds /* Routine Name: ips_inquiry */ 4278*1da177e4SLinus Torvalds /* */ 4279*1da177e4SLinus Torvalds /* Routine Description: */ 4280*1da177e4SLinus Torvalds /* */ 4281*1da177e4SLinus Torvalds /* Simulate an inquiry command to a logical drive */ 4282*1da177e4SLinus Torvalds /* */ 4283*1da177e4SLinus Torvalds /****************************************************************************/ 4284*1da177e4SLinus Torvalds static int 4285*1da177e4SLinus Torvalds ips_inquiry(ips_ha_t * ha, ips_scb_t * scb) 4286*1da177e4SLinus Torvalds { 4287*1da177e4SLinus Torvalds IPS_SCSI_INQ_DATA inquiry; 4288*1da177e4SLinus Torvalds 4289*1da177e4SLinus Torvalds METHOD_TRACE("ips_inquiry", 1); 4290*1da177e4SLinus Torvalds 4291*1da177e4SLinus Torvalds memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA)); 4292*1da177e4SLinus Torvalds 4293*1da177e4SLinus Torvalds inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD; 4294*1da177e4SLinus Torvalds inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED; 4295*1da177e4SLinus Torvalds inquiry.Version = IPS_SCSI_INQ_REV2; 4296*1da177e4SLinus Torvalds inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2; 4297*1da177e4SLinus Torvalds inquiry.AdditionalLength = 31; 4298*1da177e4SLinus Torvalds inquiry.Flags[0] = IPS_SCSI_INQ_Address16; 4299*1da177e4SLinus Torvalds inquiry.Flags[1] = 4300*1da177e4SLinus Torvalds IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue; 4301*1da177e4SLinus Torvalds strncpy(inquiry.VendorId, "IBM ", 8); 4302*1da177e4SLinus Torvalds strncpy(inquiry.ProductId, "SERVERAID ", 16); 4303*1da177e4SLinus Torvalds strncpy(inquiry.ProductRevisionLevel, "1.00", 4); 4304*1da177e4SLinus Torvalds 4305*1da177e4SLinus Torvalds ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry)); 4306*1da177e4SLinus Torvalds 4307*1da177e4SLinus Torvalds return (1); 4308*1da177e4SLinus Torvalds } 4309*1da177e4SLinus Torvalds 4310*1da177e4SLinus Torvalds /****************************************************************************/ 4311*1da177e4SLinus Torvalds /* */ 4312*1da177e4SLinus Torvalds /* Routine Name: ips_rdcap */ 4313*1da177e4SLinus Torvalds /* */ 4314*1da177e4SLinus Torvalds /* Routine Description: */ 4315*1da177e4SLinus Torvalds /* */ 4316*1da177e4SLinus Torvalds /* Simulate a read capacity command to a logical drive */ 4317*1da177e4SLinus Torvalds /* */ 4318*1da177e4SLinus Torvalds /****************************************************************************/ 4319*1da177e4SLinus Torvalds static int 4320*1da177e4SLinus Torvalds ips_rdcap(ips_ha_t * ha, ips_scb_t * scb) 4321*1da177e4SLinus Torvalds { 4322*1da177e4SLinus Torvalds IPS_SCSI_CAPACITY cap; 4323*1da177e4SLinus Torvalds 4324*1da177e4SLinus Torvalds METHOD_TRACE("ips_rdcap", 1); 4325*1da177e4SLinus Torvalds 4326*1da177e4SLinus Torvalds if (scb->scsi_cmd->bufflen < 8) 4327*1da177e4SLinus Torvalds return (0); 4328*1da177e4SLinus Torvalds 4329*1da177e4SLinus Torvalds cap.lba = 4330*1da177e4SLinus Torvalds cpu_to_be32(le32_to_cpu 4331*1da177e4SLinus Torvalds (ha->logical_drive_info-> 4332*1da177e4SLinus Torvalds drive_info[scb->target_id].sector_count) - 1); 4333*1da177e4SLinus Torvalds cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE); 4334*1da177e4SLinus Torvalds 4335*1da177e4SLinus Torvalds ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap)); 4336*1da177e4SLinus Torvalds 4337*1da177e4SLinus Torvalds return (1); 4338*1da177e4SLinus Torvalds } 4339*1da177e4SLinus Torvalds 4340*1da177e4SLinus Torvalds /****************************************************************************/ 4341*1da177e4SLinus Torvalds /* */ 4342*1da177e4SLinus Torvalds /* Routine Name: ips_msense */ 4343*1da177e4SLinus Torvalds /* */ 4344*1da177e4SLinus Torvalds /* Routine Description: */ 4345*1da177e4SLinus Torvalds /* */ 4346*1da177e4SLinus Torvalds /* Simulate a mode sense command to a logical drive */ 4347*1da177e4SLinus Torvalds /* */ 4348*1da177e4SLinus Torvalds /****************************************************************************/ 4349*1da177e4SLinus Torvalds static int 4350*1da177e4SLinus Torvalds ips_msense(ips_ha_t * ha, ips_scb_t * scb) 4351*1da177e4SLinus Torvalds { 4352*1da177e4SLinus Torvalds uint16_t heads; 4353*1da177e4SLinus Torvalds uint16_t sectors; 4354*1da177e4SLinus Torvalds uint32_t cylinders; 4355*1da177e4SLinus Torvalds IPS_SCSI_MODE_PAGE_DATA mdata; 4356*1da177e4SLinus Torvalds 4357*1da177e4SLinus Torvalds METHOD_TRACE("ips_msense", 1); 4358*1da177e4SLinus Torvalds 4359*1da177e4SLinus Torvalds if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 && 4360*1da177e4SLinus Torvalds (ha->enq->ucMiscFlag & 0x8) == 0) { 4361*1da177e4SLinus Torvalds heads = IPS_NORM_HEADS; 4362*1da177e4SLinus Torvalds sectors = IPS_NORM_SECTORS; 4363*1da177e4SLinus Torvalds } else { 4364*1da177e4SLinus Torvalds heads = IPS_COMP_HEADS; 4365*1da177e4SLinus Torvalds sectors = IPS_COMP_SECTORS; 4366*1da177e4SLinus Torvalds } 4367*1da177e4SLinus Torvalds 4368*1da177e4SLinus Torvalds cylinders = 4369*1da177e4SLinus Torvalds (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) - 4370*1da177e4SLinus Torvalds 1) / (heads * sectors); 4371*1da177e4SLinus Torvalds 4372*1da177e4SLinus Torvalds memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA)); 4373*1da177e4SLinus Torvalds 4374*1da177e4SLinus Torvalds mdata.hdr.BlockDescLength = 8; 4375*1da177e4SLinus Torvalds 4376*1da177e4SLinus Torvalds switch (scb->scsi_cmd->cmnd[2] & 0x3f) { 4377*1da177e4SLinus Torvalds case 0x03: /* page 3 */ 4378*1da177e4SLinus Torvalds mdata.pdata.pg3.PageCode = 3; 4379*1da177e4SLinus Torvalds mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3); 4380*1da177e4SLinus Torvalds mdata.hdr.DataLength = 4381*1da177e4SLinus Torvalds 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength; 4382*1da177e4SLinus Torvalds mdata.pdata.pg3.TracksPerZone = 0; 4383*1da177e4SLinus Torvalds mdata.pdata.pg3.AltSectorsPerZone = 0; 4384*1da177e4SLinus Torvalds mdata.pdata.pg3.AltTracksPerZone = 0; 4385*1da177e4SLinus Torvalds mdata.pdata.pg3.AltTracksPerVolume = 0; 4386*1da177e4SLinus Torvalds mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors); 4387*1da177e4SLinus Torvalds mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE); 4388*1da177e4SLinus Torvalds mdata.pdata.pg3.Interleave = cpu_to_be16(1); 4389*1da177e4SLinus Torvalds mdata.pdata.pg3.TrackSkew = 0; 4390*1da177e4SLinus Torvalds mdata.pdata.pg3.CylinderSkew = 0; 4391*1da177e4SLinus Torvalds mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector; 4392*1da177e4SLinus Torvalds break; 4393*1da177e4SLinus Torvalds 4394*1da177e4SLinus Torvalds case 0x4: 4395*1da177e4SLinus Torvalds mdata.pdata.pg4.PageCode = 4; 4396*1da177e4SLinus Torvalds mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4); 4397*1da177e4SLinus Torvalds mdata.hdr.DataLength = 4398*1da177e4SLinus Torvalds 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength; 4399*1da177e4SLinus Torvalds mdata.pdata.pg4.CylindersHigh = 4400*1da177e4SLinus Torvalds cpu_to_be16((cylinders >> 8) & 0xFFFF); 4401*1da177e4SLinus Torvalds mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF); 4402*1da177e4SLinus Torvalds mdata.pdata.pg4.Heads = heads; 4403*1da177e4SLinus Torvalds mdata.pdata.pg4.WritePrecompHigh = 0; 4404*1da177e4SLinus Torvalds mdata.pdata.pg4.WritePrecompLow = 0; 4405*1da177e4SLinus Torvalds mdata.pdata.pg4.ReducedWriteCurrentHigh = 0; 4406*1da177e4SLinus Torvalds mdata.pdata.pg4.ReducedWriteCurrentLow = 0; 4407*1da177e4SLinus Torvalds mdata.pdata.pg4.StepRate = cpu_to_be16(1); 4408*1da177e4SLinus Torvalds mdata.pdata.pg4.LandingZoneHigh = 0; 4409*1da177e4SLinus Torvalds mdata.pdata.pg4.LandingZoneLow = 0; 4410*1da177e4SLinus Torvalds mdata.pdata.pg4.flags = 0; 4411*1da177e4SLinus Torvalds mdata.pdata.pg4.RotationalOffset = 0; 4412*1da177e4SLinus Torvalds mdata.pdata.pg4.MediumRotationRate = 0; 4413*1da177e4SLinus Torvalds break; 4414*1da177e4SLinus Torvalds case 0x8: 4415*1da177e4SLinus Torvalds mdata.pdata.pg8.PageCode = 8; 4416*1da177e4SLinus Torvalds mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8); 4417*1da177e4SLinus Torvalds mdata.hdr.DataLength = 4418*1da177e4SLinus Torvalds 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength; 4419*1da177e4SLinus Torvalds /* everything else is left set to 0 */ 4420*1da177e4SLinus Torvalds break; 4421*1da177e4SLinus Torvalds 4422*1da177e4SLinus Torvalds default: 4423*1da177e4SLinus Torvalds return (0); 4424*1da177e4SLinus Torvalds } /* end switch */ 4425*1da177e4SLinus Torvalds 4426*1da177e4SLinus Torvalds ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata)); 4427*1da177e4SLinus Torvalds 4428*1da177e4SLinus Torvalds return (1); 4429*1da177e4SLinus Torvalds } 4430*1da177e4SLinus Torvalds 4431*1da177e4SLinus Torvalds /****************************************************************************/ 4432*1da177e4SLinus Torvalds /* */ 4433*1da177e4SLinus Torvalds /* Routine Name: ips_reqsen */ 4434*1da177e4SLinus Torvalds /* */ 4435*1da177e4SLinus Torvalds /* Routine Description: */ 4436*1da177e4SLinus Torvalds /* */ 4437*1da177e4SLinus Torvalds /* Simulate a request sense command to a logical drive */ 4438*1da177e4SLinus Torvalds /* */ 4439*1da177e4SLinus Torvalds /****************************************************************************/ 4440*1da177e4SLinus Torvalds static int 4441*1da177e4SLinus Torvalds ips_reqsen(ips_ha_t * ha, ips_scb_t * scb) 4442*1da177e4SLinus Torvalds { 4443*1da177e4SLinus Torvalds IPS_SCSI_REQSEN reqsen; 4444*1da177e4SLinus Torvalds 4445*1da177e4SLinus Torvalds METHOD_TRACE("ips_reqsen", 1); 4446*1da177e4SLinus Torvalds 4447*1da177e4SLinus Torvalds memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN)); 4448*1da177e4SLinus Torvalds 4449*1da177e4SLinus Torvalds reqsen.ResponseCode = 4450*1da177e4SLinus Torvalds IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR; 4451*1da177e4SLinus Torvalds reqsen.AdditionalLength = 10; 4452*1da177e4SLinus Torvalds reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE; 4453*1da177e4SLinus Torvalds reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE; 4454*1da177e4SLinus Torvalds 4455*1da177e4SLinus Torvalds ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen)); 4456*1da177e4SLinus Torvalds 4457*1da177e4SLinus Torvalds return (1); 4458*1da177e4SLinus Torvalds } 4459*1da177e4SLinus Torvalds 4460*1da177e4SLinus Torvalds /****************************************************************************/ 4461*1da177e4SLinus Torvalds /* */ 4462*1da177e4SLinus Torvalds /* Routine Name: ips_free */ 4463*1da177e4SLinus Torvalds /* */ 4464*1da177e4SLinus Torvalds /* Routine Description: */ 4465*1da177e4SLinus Torvalds /* */ 4466*1da177e4SLinus Torvalds /* Free any allocated space for this controller */ 4467*1da177e4SLinus Torvalds /* */ 4468*1da177e4SLinus Torvalds /****************************************************************************/ 4469*1da177e4SLinus Torvalds static void 4470*1da177e4SLinus Torvalds ips_free(ips_ha_t * ha) 4471*1da177e4SLinus Torvalds { 4472*1da177e4SLinus Torvalds 4473*1da177e4SLinus Torvalds METHOD_TRACE("ips_free", 1); 4474*1da177e4SLinus Torvalds 4475*1da177e4SLinus Torvalds if (ha) { 4476*1da177e4SLinus Torvalds if (ha->enq) { 4477*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ), 4478*1da177e4SLinus Torvalds ha->enq, ha->enq_busaddr); 4479*1da177e4SLinus Torvalds ha->enq = NULL; 4480*1da177e4SLinus Torvalds } 4481*1da177e4SLinus Torvalds 4482*1da177e4SLinus Torvalds if (ha->conf) { 4483*1da177e4SLinus Torvalds kfree(ha->conf); 4484*1da177e4SLinus Torvalds ha->conf = NULL; 4485*1da177e4SLinus Torvalds } 4486*1da177e4SLinus Torvalds 4487*1da177e4SLinus Torvalds if (ha->adapt) { 4488*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, 4489*1da177e4SLinus Torvalds sizeof (IPS_ADAPTER) + 4490*1da177e4SLinus Torvalds sizeof (IPS_IO_CMD), ha->adapt, 4491*1da177e4SLinus Torvalds ha->adapt->hw_status_start); 4492*1da177e4SLinus Torvalds ha->adapt = NULL; 4493*1da177e4SLinus Torvalds } 4494*1da177e4SLinus Torvalds 4495*1da177e4SLinus Torvalds if (ha->logical_drive_info) { 4496*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, 4497*1da177e4SLinus Torvalds sizeof (IPS_LD_INFO), 4498*1da177e4SLinus Torvalds ha->logical_drive_info, 4499*1da177e4SLinus Torvalds ha->logical_drive_info_dma_addr); 4500*1da177e4SLinus Torvalds ha->logical_drive_info = NULL; 4501*1da177e4SLinus Torvalds } 4502*1da177e4SLinus Torvalds 4503*1da177e4SLinus Torvalds if (ha->nvram) { 4504*1da177e4SLinus Torvalds kfree(ha->nvram); 4505*1da177e4SLinus Torvalds ha->nvram = NULL; 4506*1da177e4SLinus Torvalds } 4507*1da177e4SLinus Torvalds 4508*1da177e4SLinus Torvalds if (ha->subsys) { 4509*1da177e4SLinus Torvalds kfree(ha->subsys); 4510*1da177e4SLinus Torvalds ha->subsys = NULL; 4511*1da177e4SLinus Torvalds } 4512*1da177e4SLinus Torvalds 4513*1da177e4SLinus Torvalds if (ha->ioctl_data) { 4514*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, ha->ioctl_len, 4515*1da177e4SLinus Torvalds ha->ioctl_data, ha->ioctl_busaddr); 4516*1da177e4SLinus Torvalds ha->ioctl_data = NULL; 4517*1da177e4SLinus Torvalds ha->ioctl_datasize = 0; 4518*1da177e4SLinus Torvalds ha->ioctl_len = 0; 4519*1da177e4SLinus Torvalds } 4520*1da177e4SLinus Torvalds ips_deallocatescbs(ha, ha->max_cmds); 4521*1da177e4SLinus Torvalds 4522*1da177e4SLinus Torvalds /* free memory mapped (if applicable) */ 4523*1da177e4SLinus Torvalds if (ha->mem_ptr) { 4524*1da177e4SLinus Torvalds iounmap(ha->ioremap_ptr); 4525*1da177e4SLinus Torvalds ha->ioremap_ptr = NULL; 4526*1da177e4SLinus Torvalds ha->mem_ptr = NULL; 4527*1da177e4SLinus Torvalds } 4528*1da177e4SLinus Torvalds 4529*1da177e4SLinus Torvalds if (ha->mem_addr) 4530*1da177e4SLinus Torvalds release_mem_region(ha->mem_addr, ha->mem_len); 4531*1da177e4SLinus Torvalds ha->mem_addr = 0; 4532*1da177e4SLinus Torvalds 4533*1da177e4SLinus Torvalds } 4534*1da177e4SLinus Torvalds } 4535*1da177e4SLinus Torvalds 4536*1da177e4SLinus Torvalds /****************************************************************************/ 4537*1da177e4SLinus Torvalds /* */ 4538*1da177e4SLinus Torvalds /* Routine Name: ips_deallocatescbs */ 4539*1da177e4SLinus Torvalds /* */ 4540*1da177e4SLinus Torvalds /* Routine Description: */ 4541*1da177e4SLinus Torvalds /* */ 4542*1da177e4SLinus Torvalds /* Free the command blocks */ 4543*1da177e4SLinus Torvalds /* */ 4544*1da177e4SLinus Torvalds /****************************************************************************/ 4545*1da177e4SLinus Torvalds static int 4546*1da177e4SLinus Torvalds ips_deallocatescbs(ips_ha_t * ha, int cmds) 4547*1da177e4SLinus Torvalds { 4548*1da177e4SLinus Torvalds if (ha->scbs) { 4549*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, 4550*1da177e4SLinus Torvalds IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds, 4551*1da177e4SLinus Torvalds ha->scbs->sg_list.list, 4552*1da177e4SLinus Torvalds ha->scbs->sg_busaddr); 4553*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds, 4554*1da177e4SLinus Torvalds ha->scbs, ha->scbs->scb_busaddr); 4555*1da177e4SLinus Torvalds ha->scbs = NULL; 4556*1da177e4SLinus Torvalds } /* end if */ 4557*1da177e4SLinus Torvalds return 1; 4558*1da177e4SLinus Torvalds } 4559*1da177e4SLinus Torvalds 4560*1da177e4SLinus Torvalds /****************************************************************************/ 4561*1da177e4SLinus Torvalds /* */ 4562*1da177e4SLinus Torvalds /* Routine Name: ips_allocatescbs */ 4563*1da177e4SLinus Torvalds /* */ 4564*1da177e4SLinus Torvalds /* Routine Description: */ 4565*1da177e4SLinus Torvalds /* */ 4566*1da177e4SLinus Torvalds /* Allocate the command blocks */ 4567*1da177e4SLinus Torvalds /* */ 4568*1da177e4SLinus Torvalds /****************************************************************************/ 4569*1da177e4SLinus Torvalds static int 4570*1da177e4SLinus Torvalds ips_allocatescbs(ips_ha_t * ha) 4571*1da177e4SLinus Torvalds { 4572*1da177e4SLinus Torvalds ips_scb_t *scb_p; 4573*1da177e4SLinus Torvalds IPS_SG_LIST ips_sg; 4574*1da177e4SLinus Torvalds int i; 4575*1da177e4SLinus Torvalds dma_addr_t command_dma, sg_dma; 4576*1da177e4SLinus Torvalds 4577*1da177e4SLinus Torvalds METHOD_TRACE("ips_allocatescbs", 1); 4578*1da177e4SLinus Torvalds 4579*1da177e4SLinus Torvalds /* Allocate memory for the SCBs */ 4580*1da177e4SLinus Torvalds ha->scbs = 4581*1da177e4SLinus Torvalds pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t), 4582*1da177e4SLinus Torvalds &command_dma); 4583*1da177e4SLinus Torvalds if (ha->scbs == NULL) 4584*1da177e4SLinus Torvalds return 0; 4585*1da177e4SLinus Torvalds ips_sg.list = 4586*1da177e4SLinus Torvalds pci_alloc_consistent(ha->pcidev, 4587*1da177e4SLinus Torvalds IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * 4588*1da177e4SLinus Torvalds ha->max_cmds, &sg_dma); 4589*1da177e4SLinus Torvalds if (ips_sg.list == NULL) { 4590*1da177e4SLinus Torvalds pci_free_consistent(ha->pcidev, 4591*1da177e4SLinus Torvalds ha->max_cmds * sizeof (ips_scb_t), ha->scbs, 4592*1da177e4SLinus Torvalds command_dma); 4593*1da177e4SLinus Torvalds return 0; 4594*1da177e4SLinus Torvalds } 4595*1da177e4SLinus Torvalds 4596*1da177e4SLinus Torvalds memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t)); 4597*1da177e4SLinus Torvalds 4598*1da177e4SLinus Torvalds for (i = 0; i < ha->max_cmds; i++) { 4599*1da177e4SLinus Torvalds scb_p = &ha->scbs[i]; 4600*1da177e4SLinus Torvalds scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i; 4601*1da177e4SLinus Torvalds /* set up S/G list */ 4602*1da177e4SLinus Torvalds if (IPS_USE_ENH_SGLIST(ha)) { 4603*1da177e4SLinus Torvalds scb_p->sg_list.enh_list = 4604*1da177e4SLinus Torvalds ips_sg.enh_list + i * IPS_MAX_SG; 4605*1da177e4SLinus Torvalds scb_p->sg_busaddr = 4606*1da177e4SLinus Torvalds sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; 4607*1da177e4SLinus Torvalds } else { 4608*1da177e4SLinus Torvalds scb_p->sg_list.std_list = 4609*1da177e4SLinus Torvalds ips_sg.std_list + i * IPS_MAX_SG; 4610*1da177e4SLinus Torvalds scb_p->sg_busaddr = 4611*1da177e4SLinus Torvalds sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; 4612*1da177e4SLinus Torvalds } 4613*1da177e4SLinus Torvalds 4614*1da177e4SLinus Torvalds /* add to the free list */ 4615*1da177e4SLinus Torvalds if (i < ha->max_cmds - 1) { 4616*1da177e4SLinus Torvalds scb_p->q_next = ha->scb_freelist; 4617*1da177e4SLinus Torvalds ha->scb_freelist = scb_p; 4618*1da177e4SLinus Torvalds } 4619*1da177e4SLinus Torvalds } 4620*1da177e4SLinus Torvalds 4621*1da177e4SLinus Torvalds /* success */ 4622*1da177e4SLinus Torvalds return (1); 4623*1da177e4SLinus Torvalds } 4624*1da177e4SLinus Torvalds 4625*1da177e4SLinus Torvalds /****************************************************************************/ 4626*1da177e4SLinus Torvalds /* */ 4627*1da177e4SLinus Torvalds /* Routine Name: ips_init_scb */ 4628*1da177e4SLinus Torvalds /* */ 4629*1da177e4SLinus Torvalds /* Routine Description: */ 4630*1da177e4SLinus Torvalds /* */ 4631*1da177e4SLinus Torvalds /* Initialize a CCB to default values */ 4632*1da177e4SLinus Torvalds /* */ 4633*1da177e4SLinus Torvalds /****************************************************************************/ 4634*1da177e4SLinus Torvalds static void 4635*1da177e4SLinus Torvalds ips_init_scb(ips_ha_t * ha, ips_scb_t * scb) 4636*1da177e4SLinus Torvalds { 4637*1da177e4SLinus Torvalds IPS_SG_LIST sg_list; 4638*1da177e4SLinus Torvalds uint32_t cmd_busaddr, sg_busaddr; 4639*1da177e4SLinus Torvalds METHOD_TRACE("ips_init_scb", 1); 4640*1da177e4SLinus Torvalds 4641*1da177e4SLinus Torvalds if (scb == NULL) 4642*1da177e4SLinus Torvalds return; 4643*1da177e4SLinus Torvalds 4644*1da177e4SLinus Torvalds sg_list.list = scb->sg_list.list; 4645*1da177e4SLinus Torvalds cmd_busaddr = scb->scb_busaddr; 4646*1da177e4SLinus Torvalds sg_busaddr = scb->sg_busaddr; 4647*1da177e4SLinus Torvalds /* zero fill */ 4648*1da177e4SLinus Torvalds memset(scb, 0, sizeof (ips_scb_t)); 4649*1da177e4SLinus Torvalds memset(ha->dummy, 0, sizeof (IPS_IO_CMD)); 4650*1da177e4SLinus Torvalds 4651*1da177e4SLinus Torvalds /* Initialize dummy command bucket */ 4652*1da177e4SLinus Torvalds ha->dummy->op_code = 0xFF; 4653*1da177e4SLinus Torvalds ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start 4654*1da177e4SLinus Torvalds + sizeof (IPS_ADAPTER)); 4655*1da177e4SLinus Torvalds ha->dummy->command_id = IPS_MAX_CMDS; 4656*1da177e4SLinus Torvalds 4657*1da177e4SLinus Torvalds /* set bus address of scb */ 4658*1da177e4SLinus Torvalds scb->scb_busaddr = cmd_busaddr; 4659*1da177e4SLinus Torvalds scb->sg_busaddr = sg_busaddr; 4660*1da177e4SLinus Torvalds scb->sg_list.list = sg_list.list; 4661*1da177e4SLinus Torvalds 4662*1da177e4SLinus Torvalds /* Neptune Fix */ 4663*1da177e4SLinus Torvalds scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE); 4664*1da177e4SLinus Torvalds scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start 4665*1da177e4SLinus Torvalds + sizeof (IPS_ADAPTER)); 4666*1da177e4SLinus Torvalds } 4667*1da177e4SLinus Torvalds 4668*1da177e4SLinus Torvalds /****************************************************************************/ 4669*1da177e4SLinus Torvalds /* */ 4670*1da177e4SLinus Torvalds /* Routine Name: ips_get_scb */ 4671*1da177e4SLinus Torvalds /* */ 4672*1da177e4SLinus Torvalds /* Routine Description: */ 4673*1da177e4SLinus Torvalds /* */ 4674*1da177e4SLinus Torvalds /* Initialize a CCB to default values */ 4675*1da177e4SLinus Torvalds /* */ 4676*1da177e4SLinus Torvalds /* ASSUMED to be callled from within a lock */ 4677*1da177e4SLinus Torvalds /* */ 4678*1da177e4SLinus Torvalds /****************************************************************************/ 4679*1da177e4SLinus Torvalds static ips_scb_t * 4680*1da177e4SLinus Torvalds ips_getscb(ips_ha_t * ha) 4681*1da177e4SLinus Torvalds { 4682*1da177e4SLinus Torvalds ips_scb_t *scb; 4683*1da177e4SLinus Torvalds 4684*1da177e4SLinus Torvalds METHOD_TRACE("ips_getscb", 1); 4685*1da177e4SLinus Torvalds 4686*1da177e4SLinus Torvalds if ((scb = ha->scb_freelist) == NULL) { 4687*1da177e4SLinus Torvalds 4688*1da177e4SLinus Torvalds return (NULL); 4689*1da177e4SLinus Torvalds } 4690*1da177e4SLinus Torvalds 4691*1da177e4SLinus Torvalds ha->scb_freelist = scb->q_next; 4692*1da177e4SLinus Torvalds scb->flags = 0; 4693*1da177e4SLinus Torvalds scb->q_next = NULL; 4694*1da177e4SLinus Torvalds 4695*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 4696*1da177e4SLinus Torvalds 4697*1da177e4SLinus Torvalds return (scb); 4698*1da177e4SLinus Torvalds } 4699*1da177e4SLinus Torvalds 4700*1da177e4SLinus Torvalds /****************************************************************************/ 4701*1da177e4SLinus Torvalds /* */ 4702*1da177e4SLinus Torvalds /* Routine Name: ips_free_scb */ 4703*1da177e4SLinus Torvalds /* */ 4704*1da177e4SLinus Torvalds /* Routine Description: */ 4705*1da177e4SLinus Torvalds /* */ 4706*1da177e4SLinus Torvalds /* Return an unused CCB back to the free list */ 4707*1da177e4SLinus Torvalds /* */ 4708*1da177e4SLinus Torvalds /* ASSUMED to be called from within a lock */ 4709*1da177e4SLinus Torvalds /* */ 4710*1da177e4SLinus Torvalds /****************************************************************************/ 4711*1da177e4SLinus Torvalds static void 4712*1da177e4SLinus Torvalds ips_freescb(ips_ha_t * ha, ips_scb_t * scb) 4713*1da177e4SLinus Torvalds { 4714*1da177e4SLinus Torvalds 4715*1da177e4SLinus Torvalds METHOD_TRACE("ips_freescb", 1); 4716*1da177e4SLinus Torvalds if (scb->flags & IPS_SCB_MAP_SG) 4717*1da177e4SLinus Torvalds pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer, 4718*1da177e4SLinus Torvalds scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb)); 4719*1da177e4SLinus Torvalds else if (scb->flags & IPS_SCB_MAP_SINGLE) 4720*1da177e4SLinus Torvalds pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len, 4721*1da177e4SLinus Torvalds IPS_DMA_DIR(scb)); 4722*1da177e4SLinus Torvalds 4723*1da177e4SLinus Torvalds /* check to make sure this is not our "special" scb */ 4724*1da177e4SLinus Torvalds if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { 4725*1da177e4SLinus Torvalds scb->q_next = ha->scb_freelist; 4726*1da177e4SLinus Torvalds ha->scb_freelist = scb; 4727*1da177e4SLinus Torvalds } 4728*1da177e4SLinus Torvalds } 4729*1da177e4SLinus Torvalds 4730*1da177e4SLinus Torvalds /****************************************************************************/ 4731*1da177e4SLinus Torvalds /* */ 4732*1da177e4SLinus Torvalds /* Routine Name: ips_isinit_copperhead */ 4733*1da177e4SLinus Torvalds /* */ 4734*1da177e4SLinus Torvalds /* Routine Description: */ 4735*1da177e4SLinus Torvalds /* */ 4736*1da177e4SLinus Torvalds /* Is controller initialized ? */ 4737*1da177e4SLinus Torvalds /* */ 4738*1da177e4SLinus Torvalds /****************************************************************************/ 4739*1da177e4SLinus Torvalds static int 4740*1da177e4SLinus Torvalds ips_isinit_copperhead(ips_ha_t * ha) 4741*1da177e4SLinus Torvalds { 4742*1da177e4SLinus Torvalds uint8_t scpr; 4743*1da177e4SLinus Torvalds uint8_t isr; 4744*1da177e4SLinus Torvalds 4745*1da177e4SLinus Torvalds METHOD_TRACE("ips_isinit_copperhead", 1); 4746*1da177e4SLinus Torvalds 4747*1da177e4SLinus Torvalds isr = inb(ha->io_addr + IPS_REG_HISR); 4748*1da177e4SLinus Torvalds scpr = inb(ha->io_addr + IPS_REG_SCPR); 4749*1da177e4SLinus Torvalds 4750*1da177e4SLinus Torvalds if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) 4751*1da177e4SLinus Torvalds return (0); 4752*1da177e4SLinus Torvalds else 4753*1da177e4SLinus Torvalds return (1); 4754*1da177e4SLinus Torvalds } 4755*1da177e4SLinus Torvalds 4756*1da177e4SLinus Torvalds /****************************************************************************/ 4757*1da177e4SLinus Torvalds /* */ 4758*1da177e4SLinus Torvalds /* Routine Name: ips_isinit_copperhead_memio */ 4759*1da177e4SLinus Torvalds /* */ 4760*1da177e4SLinus Torvalds /* Routine Description: */ 4761*1da177e4SLinus Torvalds /* */ 4762*1da177e4SLinus Torvalds /* Is controller initialized ? */ 4763*1da177e4SLinus Torvalds /* */ 4764*1da177e4SLinus Torvalds /****************************************************************************/ 4765*1da177e4SLinus Torvalds static int 4766*1da177e4SLinus Torvalds ips_isinit_copperhead_memio(ips_ha_t * ha) 4767*1da177e4SLinus Torvalds { 4768*1da177e4SLinus Torvalds uint8_t isr = 0; 4769*1da177e4SLinus Torvalds uint8_t scpr; 4770*1da177e4SLinus Torvalds 4771*1da177e4SLinus Torvalds METHOD_TRACE("ips_is_init_copperhead_memio", 1); 4772*1da177e4SLinus Torvalds 4773*1da177e4SLinus Torvalds isr = readb(ha->mem_ptr + IPS_REG_HISR); 4774*1da177e4SLinus Torvalds scpr = readb(ha->mem_ptr + IPS_REG_SCPR); 4775*1da177e4SLinus Torvalds 4776*1da177e4SLinus Torvalds if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) 4777*1da177e4SLinus Torvalds return (0); 4778*1da177e4SLinus Torvalds else 4779*1da177e4SLinus Torvalds return (1); 4780*1da177e4SLinus Torvalds } 4781*1da177e4SLinus Torvalds 4782*1da177e4SLinus Torvalds /****************************************************************************/ 4783*1da177e4SLinus Torvalds /* */ 4784*1da177e4SLinus Torvalds /* Routine Name: ips_isinit_morpheus */ 4785*1da177e4SLinus Torvalds /* */ 4786*1da177e4SLinus Torvalds /* Routine Description: */ 4787*1da177e4SLinus Torvalds /* */ 4788*1da177e4SLinus Torvalds /* Is controller initialized ? */ 4789*1da177e4SLinus Torvalds /* */ 4790*1da177e4SLinus Torvalds /****************************************************************************/ 4791*1da177e4SLinus Torvalds static int 4792*1da177e4SLinus Torvalds ips_isinit_morpheus(ips_ha_t * ha) 4793*1da177e4SLinus Torvalds { 4794*1da177e4SLinus Torvalds uint32_t post; 4795*1da177e4SLinus Torvalds uint32_t bits; 4796*1da177e4SLinus Torvalds 4797*1da177e4SLinus Torvalds METHOD_TRACE("ips_is_init_morpheus", 1); 4798*1da177e4SLinus Torvalds 4799*1da177e4SLinus Torvalds post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); 4800*1da177e4SLinus Torvalds bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 4801*1da177e4SLinus Torvalds 4802*1da177e4SLinus Torvalds if (post == 0) 4803*1da177e4SLinus Torvalds return (0); 4804*1da177e4SLinus Torvalds else if (bits & 0x3) 4805*1da177e4SLinus Torvalds return (0); 4806*1da177e4SLinus Torvalds else 4807*1da177e4SLinus Torvalds return (1); 4808*1da177e4SLinus Torvalds } 4809*1da177e4SLinus Torvalds 4810*1da177e4SLinus Torvalds /****************************************************************************/ 4811*1da177e4SLinus Torvalds /* */ 4812*1da177e4SLinus Torvalds /* Routine Name: ips_enable_int_copperhead */ 4813*1da177e4SLinus Torvalds /* */ 4814*1da177e4SLinus Torvalds /* Routine Description: */ 4815*1da177e4SLinus Torvalds /* Turn on interrupts */ 4816*1da177e4SLinus Torvalds /* */ 4817*1da177e4SLinus Torvalds /****************************************************************************/ 4818*1da177e4SLinus Torvalds static void 4819*1da177e4SLinus Torvalds ips_enable_int_copperhead(ips_ha_t * ha) 4820*1da177e4SLinus Torvalds { 4821*1da177e4SLinus Torvalds METHOD_TRACE("ips_enable_int_copperhead", 1); 4822*1da177e4SLinus Torvalds 4823*1da177e4SLinus Torvalds outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI); 4824*1da177e4SLinus Torvalds inb(ha->io_addr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/ 4825*1da177e4SLinus Torvalds } 4826*1da177e4SLinus Torvalds 4827*1da177e4SLinus Torvalds /****************************************************************************/ 4828*1da177e4SLinus Torvalds /* */ 4829*1da177e4SLinus Torvalds /* Routine Name: ips_enable_int_copperhead_memio */ 4830*1da177e4SLinus Torvalds /* */ 4831*1da177e4SLinus Torvalds /* Routine Description: */ 4832*1da177e4SLinus Torvalds /* Turn on interrupts */ 4833*1da177e4SLinus Torvalds /* */ 4834*1da177e4SLinus Torvalds /****************************************************************************/ 4835*1da177e4SLinus Torvalds static void 4836*1da177e4SLinus Torvalds ips_enable_int_copperhead_memio(ips_ha_t * ha) 4837*1da177e4SLinus Torvalds { 4838*1da177e4SLinus Torvalds METHOD_TRACE("ips_enable_int_copperhead_memio", 1); 4839*1da177e4SLinus Torvalds 4840*1da177e4SLinus Torvalds writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); 4841*1da177e4SLinus Torvalds readb(ha->mem_ptr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/ 4842*1da177e4SLinus Torvalds } 4843*1da177e4SLinus Torvalds 4844*1da177e4SLinus Torvalds /****************************************************************************/ 4845*1da177e4SLinus Torvalds /* */ 4846*1da177e4SLinus Torvalds /* Routine Name: ips_enable_int_morpheus */ 4847*1da177e4SLinus Torvalds /* */ 4848*1da177e4SLinus Torvalds /* Routine Description: */ 4849*1da177e4SLinus Torvalds /* Turn on interrupts */ 4850*1da177e4SLinus Torvalds /* */ 4851*1da177e4SLinus Torvalds /****************************************************************************/ 4852*1da177e4SLinus Torvalds static void 4853*1da177e4SLinus Torvalds ips_enable_int_morpheus(ips_ha_t * ha) 4854*1da177e4SLinus Torvalds { 4855*1da177e4SLinus Torvalds uint32_t Oimr; 4856*1da177e4SLinus Torvalds 4857*1da177e4SLinus Torvalds METHOD_TRACE("ips_enable_int_morpheus", 1); 4858*1da177e4SLinus Torvalds 4859*1da177e4SLinus Torvalds Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); 4860*1da177e4SLinus Torvalds Oimr &= ~0x08; 4861*1da177e4SLinus Torvalds writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); 4862*1da177e4SLinus Torvalds readl(ha->mem_ptr + IPS_REG_I960_OIMR); /*Ensure PCI Posting Completes*/ 4863*1da177e4SLinus Torvalds } 4864*1da177e4SLinus Torvalds 4865*1da177e4SLinus Torvalds /****************************************************************************/ 4866*1da177e4SLinus Torvalds /* */ 4867*1da177e4SLinus Torvalds /* Routine Name: ips_init_copperhead */ 4868*1da177e4SLinus Torvalds /* */ 4869*1da177e4SLinus Torvalds /* Routine Description: */ 4870*1da177e4SLinus Torvalds /* */ 4871*1da177e4SLinus Torvalds /* Initialize a copperhead controller */ 4872*1da177e4SLinus Torvalds /* */ 4873*1da177e4SLinus Torvalds /****************************************************************************/ 4874*1da177e4SLinus Torvalds static int 4875*1da177e4SLinus Torvalds ips_init_copperhead(ips_ha_t * ha) 4876*1da177e4SLinus Torvalds { 4877*1da177e4SLinus Torvalds uint8_t Isr; 4878*1da177e4SLinus Torvalds uint8_t Cbsp; 4879*1da177e4SLinus Torvalds uint8_t PostByte[IPS_MAX_POST_BYTES]; 4880*1da177e4SLinus Torvalds uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; 4881*1da177e4SLinus Torvalds int i, j; 4882*1da177e4SLinus Torvalds 4883*1da177e4SLinus Torvalds METHOD_TRACE("ips_init_copperhead", 1); 4884*1da177e4SLinus Torvalds 4885*1da177e4SLinus Torvalds for (i = 0; i < IPS_MAX_POST_BYTES; i++) { 4886*1da177e4SLinus Torvalds for (j = 0; j < 45; j++) { 4887*1da177e4SLinus Torvalds Isr = inb(ha->io_addr + IPS_REG_HISR); 4888*1da177e4SLinus Torvalds if (Isr & IPS_BIT_GHI) 4889*1da177e4SLinus Torvalds break; 4890*1da177e4SLinus Torvalds 4891*1da177e4SLinus Torvalds /* Delay for 1 Second */ 4892*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 4893*1da177e4SLinus Torvalds } 4894*1da177e4SLinus Torvalds 4895*1da177e4SLinus Torvalds if (j >= 45) 4896*1da177e4SLinus Torvalds /* error occurred */ 4897*1da177e4SLinus Torvalds return (0); 4898*1da177e4SLinus Torvalds 4899*1da177e4SLinus Torvalds PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); 4900*1da177e4SLinus Torvalds outb(Isr, ha->io_addr + IPS_REG_HISR); 4901*1da177e4SLinus Torvalds } 4902*1da177e4SLinus Torvalds 4903*1da177e4SLinus Torvalds if (PostByte[0] < IPS_GOOD_POST_STATUS) { 4904*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 4905*1da177e4SLinus Torvalds "reset controller fails (post status %x %x).\n", 4906*1da177e4SLinus Torvalds PostByte[0], PostByte[1]); 4907*1da177e4SLinus Torvalds 4908*1da177e4SLinus Torvalds return (0); 4909*1da177e4SLinus Torvalds } 4910*1da177e4SLinus Torvalds 4911*1da177e4SLinus Torvalds for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { 4912*1da177e4SLinus Torvalds for (j = 0; j < 240; j++) { 4913*1da177e4SLinus Torvalds Isr = inb(ha->io_addr + IPS_REG_HISR); 4914*1da177e4SLinus Torvalds if (Isr & IPS_BIT_GHI) 4915*1da177e4SLinus Torvalds break; 4916*1da177e4SLinus Torvalds 4917*1da177e4SLinus Torvalds /* Delay for 1 Second */ 4918*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 4919*1da177e4SLinus Torvalds } 4920*1da177e4SLinus Torvalds 4921*1da177e4SLinus Torvalds if (j >= 240) 4922*1da177e4SLinus Torvalds /* error occurred */ 4923*1da177e4SLinus Torvalds return (0); 4924*1da177e4SLinus Torvalds 4925*1da177e4SLinus Torvalds ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); 4926*1da177e4SLinus Torvalds outb(Isr, ha->io_addr + IPS_REG_HISR); 4927*1da177e4SLinus Torvalds } 4928*1da177e4SLinus Torvalds 4929*1da177e4SLinus Torvalds for (i = 0; i < 240; i++) { 4930*1da177e4SLinus Torvalds Cbsp = inb(ha->io_addr + IPS_REG_CBSP); 4931*1da177e4SLinus Torvalds 4932*1da177e4SLinus Torvalds if ((Cbsp & IPS_BIT_OP) == 0) 4933*1da177e4SLinus Torvalds break; 4934*1da177e4SLinus Torvalds 4935*1da177e4SLinus Torvalds /* Delay for 1 Second */ 4936*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 4937*1da177e4SLinus Torvalds } 4938*1da177e4SLinus Torvalds 4939*1da177e4SLinus Torvalds if (i >= 240) 4940*1da177e4SLinus Torvalds /* reset failed */ 4941*1da177e4SLinus Torvalds return (0); 4942*1da177e4SLinus Torvalds 4943*1da177e4SLinus Torvalds /* setup CCCR */ 4944*1da177e4SLinus Torvalds outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR); 4945*1da177e4SLinus Torvalds 4946*1da177e4SLinus Torvalds /* Enable busmastering */ 4947*1da177e4SLinus Torvalds outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); 4948*1da177e4SLinus Torvalds 4949*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 4950*1da177e4SLinus Torvalds /* fix for anaconda64 */ 4951*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_NDAE); 4952*1da177e4SLinus Torvalds 4953*1da177e4SLinus Torvalds /* Enable interrupts */ 4954*1da177e4SLinus Torvalds outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); 4955*1da177e4SLinus Torvalds 4956*1da177e4SLinus Torvalds return (1); 4957*1da177e4SLinus Torvalds } 4958*1da177e4SLinus Torvalds 4959*1da177e4SLinus Torvalds /****************************************************************************/ 4960*1da177e4SLinus Torvalds /* */ 4961*1da177e4SLinus Torvalds /* Routine Name: ips_init_copperhead_memio */ 4962*1da177e4SLinus Torvalds /* */ 4963*1da177e4SLinus Torvalds /* Routine Description: */ 4964*1da177e4SLinus Torvalds /* */ 4965*1da177e4SLinus Torvalds /* Initialize a copperhead controller with memory mapped I/O */ 4966*1da177e4SLinus Torvalds /* */ 4967*1da177e4SLinus Torvalds /****************************************************************************/ 4968*1da177e4SLinus Torvalds static int 4969*1da177e4SLinus Torvalds ips_init_copperhead_memio(ips_ha_t * ha) 4970*1da177e4SLinus Torvalds { 4971*1da177e4SLinus Torvalds uint8_t Isr = 0; 4972*1da177e4SLinus Torvalds uint8_t Cbsp; 4973*1da177e4SLinus Torvalds uint8_t PostByte[IPS_MAX_POST_BYTES]; 4974*1da177e4SLinus Torvalds uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; 4975*1da177e4SLinus Torvalds int i, j; 4976*1da177e4SLinus Torvalds 4977*1da177e4SLinus Torvalds METHOD_TRACE("ips_init_copperhead_memio", 1); 4978*1da177e4SLinus Torvalds 4979*1da177e4SLinus Torvalds for (i = 0; i < IPS_MAX_POST_BYTES; i++) { 4980*1da177e4SLinus Torvalds for (j = 0; j < 45; j++) { 4981*1da177e4SLinus Torvalds Isr = readb(ha->mem_ptr + IPS_REG_HISR); 4982*1da177e4SLinus Torvalds if (Isr & IPS_BIT_GHI) 4983*1da177e4SLinus Torvalds break; 4984*1da177e4SLinus Torvalds 4985*1da177e4SLinus Torvalds /* Delay for 1 Second */ 4986*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 4987*1da177e4SLinus Torvalds } 4988*1da177e4SLinus Torvalds 4989*1da177e4SLinus Torvalds if (j >= 45) 4990*1da177e4SLinus Torvalds /* error occurred */ 4991*1da177e4SLinus Torvalds return (0); 4992*1da177e4SLinus Torvalds 4993*1da177e4SLinus Torvalds PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); 4994*1da177e4SLinus Torvalds writeb(Isr, ha->mem_ptr + IPS_REG_HISR); 4995*1da177e4SLinus Torvalds } 4996*1da177e4SLinus Torvalds 4997*1da177e4SLinus Torvalds if (PostByte[0] < IPS_GOOD_POST_STATUS) { 4998*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 4999*1da177e4SLinus Torvalds "reset controller fails (post status %x %x).\n", 5000*1da177e4SLinus Torvalds PostByte[0], PostByte[1]); 5001*1da177e4SLinus Torvalds 5002*1da177e4SLinus Torvalds return (0); 5003*1da177e4SLinus Torvalds } 5004*1da177e4SLinus Torvalds 5005*1da177e4SLinus Torvalds for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { 5006*1da177e4SLinus Torvalds for (j = 0; j < 240; j++) { 5007*1da177e4SLinus Torvalds Isr = readb(ha->mem_ptr + IPS_REG_HISR); 5008*1da177e4SLinus Torvalds if (Isr & IPS_BIT_GHI) 5009*1da177e4SLinus Torvalds break; 5010*1da177e4SLinus Torvalds 5011*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5012*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5013*1da177e4SLinus Torvalds } 5014*1da177e4SLinus Torvalds 5015*1da177e4SLinus Torvalds if (j >= 240) 5016*1da177e4SLinus Torvalds /* error occurred */ 5017*1da177e4SLinus Torvalds return (0); 5018*1da177e4SLinus Torvalds 5019*1da177e4SLinus Torvalds ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); 5020*1da177e4SLinus Torvalds writeb(Isr, ha->mem_ptr + IPS_REG_HISR); 5021*1da177e4SLinus Torvalds } 5022*1da177e4SLinus Torvalds 5023*1da177e4SLinus Torvalds for (i = 0; i < 240; i++) { 5024*1da177e4SLinus Torvalds Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP); 5025*1da177e4SLinus Torvalds 5026*1da177e4SLinus Torvalds if ((Cbsp & IPS_BIT_OP) == 0) 5027*1da177e4SLinus Torvalds break; 5028*1da177e4SLinus Torvalds 5029*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5030*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5031*1da177e4SLinus Torvalds } 5032*1da177e4SLinus Torvalds 5033*1da177e4SLinus Torvalds if (i >= 240) 5034*1da177e4SLinus Torvalds /* error occurred */ 5035*1da177e4SLinus Torvalds return (0); 5036*1da177e4SLinus Torvalds 5037*1da177e4SLinus Torvalds /* setup CCCR */ 5038*1da177e4SLinus Torvalds writel(0x1010, ha->mem_ptr + IPS_REG_CCCR); 5039*1da177e4SLinus Torvalds 5040*1da177e4SLinus Torvalds /* Enable busmastering */ 5041*1da177e4SLinus Torvalds writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); 5042*1da177e4SLinus Torvalds 5043*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 5044*1da177e4SLinus Torvalds /* fix for anaconda64 */ 5045*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_NDAE); 5046*1da177e4SLinus Torvalds 5047*1da177e4SLinus Torvalds /* Enable interrupts */ 5048*1da177e4SLinus Torvalds writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); 5049*1da177e4SLinus Torvalds 5050*1da177e4SLinus Torvalds /* if we get here then everything went OK */ 5051*1da177e4SLinus Torvalds return (1); 5052*1da177e4SLinus Torvalds } 5053*1da177e4SLinus Torvalds 5054*1da177e4SLinus Torvalds /****************************************************************************/ 5055*1da177e4SLinus Torvalds /* */ 5056*1da177e4SLinus Torvalds /* Routine Name: ips_init_morpheus */ 5057*1da177e4SLinus Torvalds /* */ 5058*1da177e4SLinus Torvalds /* Routine Description: */ 5059*1da177e4SLinus Torvalds /* */ 5060*1da177e4SLinus Torvalds /* Initialize a morpheus controller */ 5061*1da177e4SLinus Torvalds /* */ 5062*1da177e4SLinus Torvalds /****************************************************************************/ 5063*1da177e4SLinus Torvalds static int 5064*1da177e4SLinus Torvalds ips_init_morpheus(ips_ha_t * ha) 5065*1da177e4SLinus Torvalds { 5066*1da177e4SLinus Torvalds uint32_t Post; 5067*1da177e4SLinus Torvalds uint32_t Config; 5068*1da177e4SLinus Torvalds uint32_t Isr; 5069*1da177e4SLinus Torvalds uint32_t Oimr; 5070*1da177e4SLinus Torvalds int i; 5071*1da177e4SLinus Torvalds 5072*1da177e4SLinus Torvalds METHOD_TRACE("ips_init_morpheus", 1); 5073*1da177e4SLinus Torvalds 5074*1da177e4SLinus Torvalds /* Wait up to 45 secs for Post */ 5075*1da177e4SLinus Torvalds for (i = 0; i < 45; i++) { 5076*1da177e4SLinus Torvalds Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 5077*1da177e4SLinus Torvalds 5078*1da177e4SLinus Torvalds if (Isr & IPS_BIT_I960_MSG0I) 5079*1da177e4SLinus Torvalds break; 5080*1da177e4SLinus Torvalds 5081*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5082*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5083*1da177e4SLinus Torvalds } 5084*1da177e4SLinus Torvalds 5085*1da177e4SLinus Torvalds if (i >= 45) { 5086*1da177e4SLinus Torvalds /* error occurred */ 5087*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5088*1da177e4SLinus Torvalds "timeout waiting for post.\n"); 5089*1da177e4SLinus Torvalds 5090*1da177e4SLinus Torvalds return (0); 5091*1da177e4SLinus Torvalds } 5092*1da177e4SLinus Torvalds 5093*1da177e4SLinus Torvalds Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); 5094*1da177e4SLinus Torvalds 5095*1da177e4SLinus Torvalds if (Post == 0x4F00) { /* If Flashing the Battery PIC */ 5096*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5097*1da177e4SLinus Torvalds "Flashing Battery PIC, Please wait ...\n"); 5098*1da177e4SLinus Torvalds 5099*1da177e4SLinus Torvalds /* Clear the interrupt bit */ 5100*1da177e4SLinus Torvalds Isr = (uint32_t) IPS_BIT_I960_MSG0I; 5101*1da177e4SLinus Torvalds writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); 5102*1da177e4SLinus Torvalds 5103*1da177e4SLinus Torvalds for (i = 0; i < 120; i++) { /* Wait Up to 2 Min. for Completion */ 5104*1da177e4SLinus Torvalds Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); 5105*1da177e4SLinus Torvalds if (Post != 0x4F00) 5106*1da177e4SLinus Torvalds break; 5107*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5108*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5109*1da177e4SLinus Torvalds } 5110*1da177e4SLinus Torvalds 5111*1da177e4SLinus Torvalds if (i >= 120) { 5112*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5113*1da177e4SLinus Torvalds "timeout waiting for Battery PIC Flash\n"); 5114*1da177e4SLinus Torvalds return (0); 5115*1da177e4SLinus Torvalds } 5116*1da177e4SLinus Torvalds 5117*1da177e4SLinus Torvalds } 5118*1da177e4SLinus Torvalds 5119*1da177e4SLinus Torvalds /* Clear the interrupt bit */ 5120*1da177e4SLinus Torvalds Isr = (uint32_t) IPS_BIT_I960_MSG0I; 5121*1da177e4SLinus Torvalds writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); 5122*1da177e4SLinus Torvalds 5123*1da177e4SLinus Torvalds if (Post < (IPS_GOOD_POST_STATUS << 8)) { 5124*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5125*1da177e4SLinus Torvalds "reset controller fails (post status %x).\n", Post); 5126*1da177e4SLinus Torvalds 5127*1da177e4SLinus Torvalds return (0); 5128*1da177e4SLinus Torvalds } 5129*1da177e4SLinus Torvalds 5130*1da177e4SLinus Torvalds /* Wait up to 240 secs for config bytes */ 5131*1da177e4SLinus Torvalds for (i = 0; i < 240; i++) { 5132*1da177e4SLinus Torvalds Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 5133*1da177e4SLinus Torvalds 5134*1da177e4SLinus Torvalds if (Isr & IPS_BIT_I960_MSG1I) 5135*1da177e4SLinus Torvalds break; 5136*1da177e4SLinus Torvalds 5137*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5138*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5139*1da177e4SLinus Torvalds } 5140*1da177e4SLinus Torvalds 5141*1da177e4SLinus Torvalds if (i >= 240) { 5142*1da177e4SLinus Torvalds /* error occurred */ 5143*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5144*1da177e4SLinus Torvalds "timeout waiting for config.\n"); 5145*1da177e4SLinus Torvalds 5146*1da177e4SLinus Torvalds return (0); 5147*1da177e4SLinus Torvalds } 5148*1da177e4SLinus Torvalds 5149*1da177e4SLinus Torvalds Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1); 5150*1da177e4SLinus Torvalds 5151*1da177e4SLinus Torvalds /* Clear interrupt bit */ 5152*1da177e4SLinus Torvalds Isr = (uint32_t) IPS_BIT_I960_MSG1I; 5153*1da177e4SLinus Torvalds writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); 5154*1da177e4SLinus Torvalds 5155*1da177e4SLinus Torvalds /* Turn on the interrupts */ 5156*1da177e4SLinus Torvalds Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); 5157*1da177e4SLinus Torvalds Oimr &= ~0x8; 5158*1da177e4SLinus Torvalds writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); 5159*1da177e4SLinus Torvalds 5160*1da177e4SLinus Torvalds /* if we get here then everything went OK */ 5161*1da177e4SLinus Torvalds 5162*1da177e4SLinus Torvalds /* Since we did a RESET, an EraseStripeLock may be needed */ 5163*1da177e4SLinus Torvalds if (Post == 0xEF10) { 5164*1da177e4SLinus Torvalds if ((Config == 0x000F) || (Config == 0x0009)) 5165*1da177e4SLinus Torvalds ha->requires_esl = 1; 5166*1da177e4SLinus Torvalds } 5167*1da177e4SLinus Torvalds 5168*1da177e4SLinus Torvalds return (1); 5169*1da177e4SLinus Torvalds } 5170*1da177e4SLinus Torvalds 5171*1da177e4SLinus Torvalds /****************************************************************************/ 5172*1da177e4SLinus Torvalds /* */ 5173*1da177e4SLinus Torvalds /* Routine Name: ips_reset_copperhead */ 5174*1da177e4SLinus Torvalds /* */ 5175*1da177e4SLinus Torvalds /* Routine Description: */ 5176*1da177e4SLinus Torvalds /* */ 5177*1da177e4SLinus Torvalds /* Reset the controller */ 5178*1da177e4SLinus Torvalds /* */ 5179*1da177e4SLinus Torvalds /****************************************************************************/ 5180*1da177e4SLinus Torvalds static int 5181*1da177e4SLinus Torvalds ips_reset_copperhead(ips_ha_t * ha) 5182*1da177e4SLinus Torvalds { 5183*1da177e4SLinus Torvalds int reset_counter; 5184*1da177e4SLinus Torvalds 5185*1da177e4SLinus Torvalds METHOD_TRACE("ips_reset_copperhead", 1); 5186*1da177e4SLinus Torvalds 5187*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", 5188*1da177e4SLinus Torvalds ips_name, ha->host_num, ha->io_addr, ha->irq); 5189*1da177e4SLinus Torvalds 5190*1da177e4SLinus Torvalds reset_counter = 0; 5191*1da177e4SLinus Torvalds 5192*1da177e4SLinus Torvalds while (reset_counter < 2) { 5193*1da177e4SLinus Torvalds reset_counter++; 5194*1da177e4SLinus Torvalds 5195*1da177e4SLinus Torvalds outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR); 5196*1da177e4SLinus Torvalds 5197*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5198*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5199*1da177e4SLinus Torvalds 5200*1da177e4SLinus Torvalds outb(0, ha->io_addr + IPS_REG_SCPR); 5201*1da177e4SLinus Torvalds 5202*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5203*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5204*1da177e4SLinus Torvalds 5205*1da177e4SLinus Torvalds if ((*ha->func.init) (ha)) 5206*1da177e4SLinus Torvalds break; 5207*1da177e4SLinus Torvalds else if (reset_counter >= 2) { 5208*1da177e4SLinus Torvalds 5209*1da177e4SLinus Torvalds return (0); 5210*1da177e4SLinus Torvalds } 5211*1da177e4SLinus Torvalds } 5212*1da177e4SLinus Torvalds 5213*1da177e4SLinus Torvalds return (1); 5214*1da177e4SLinus Torvalds } 5215*1da177e4SLinus Torvalds 5216*1da177e4SLinus Torvalds /****************************************************************************/ 5217*1da177e4SLinus Torvalds /* */ 5218*1da177e4SLinus Torvalds /* Routine Name: ips_reset_copperhead_memio */ 5219*1da177e4SLinus Torvalds /* */ 5220*1da177e4SLinus Torvalds /* Routine Description: */ 5221*1da177e4SLinus Torvalds /* */ 5222*1da177e4SLinus Torvalds /* Reset the controller */ 5223*1da177e4SLinus Torvalds /* */ 5224*1da177e4SLinus Torvalds /****************************************************************************/ 5225*1da177e4SLinus Torvalds static int 5226*1da177e4SLinus Torvalds ips_reset_copperhead_memio(ips_ha_t * ha) 5227*1da177e4SLinus Torvalds { 5228*1da177e4SLinus Torvalds int reset_counter; 5229*1da177e4SLinus Torvalds 5230*1da177e4SLinus Torvalds METHOD_TRACE("ips_reset_copperhead_memio", 1); 5231*1da177e4SLinus Torvalds 5232*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", 5233*1da177e4SLinus Torvalds ips_name, ha->host_num, ha->mem_addr, ha->irq); 5234*1da177e4SLinus Torvalds 5235*1da177e4SLinus Torvalds reset_counter = 0; 5236*1da177e4SLinus Torvalds 5237*1da177e4SLinus Torvalds while (reset_counter < 2) { 5238*1da177e4SLinus Torvalds reset_counter++; 5239*1da177e4SLinus Torvalds 5240*1da177e4SLinus Torvalds writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); 5241*1da177e4SLinus Torvalds 5242*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5243*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5244*1da177e4SLinus Torvalds 5245*1da177e4SLinus Torvalds writeb(0, ha->mem_ptr + IPS_REG_SCPR); 5246*1da177e4SLinus Torvalds 5247*1da177e4SLinus Torvalds /* Delay for 1 Second */ 5248*1da177e4SLinus Torvalds MDELAY(IPS_ONE_SEC); 5249*1da177e4SLinus Torvalds 5250*1da177e4SLinus Torvalds if ((*ha->func.init) (ha)) 5251*1da177e4SLinus Torvalds break; 5252*1da177e4SLinus Torvalds else if (reset_counter >= 2) { 5253*1da177e4SLinus Torvalds 5254*1da177e4SLinus Torvalds return (0); 5255*1da177e4SLinus Torvalds } 5256*1da177e4SLinus Torvalds } 5257*1da177e4SLinus Torvalds 5258*1da177e4SLinus Torvalds return (1); 5259*1da177e4SLinus Torvalds } 5260*1da177e4SLinus Torvalds 5261*1da177e4SLinus Torvalds /****************************************************************************/ 5262*1da177e4SLinus Torvalds /* */ 5263*1da177e4SLinus Torvalds /* Routine Name: ips_reset_morpheus */ 5264*1da177e4SLinus Torvalds /* */ 5265*1da177e4SLinus Torvalds /* Routine Description: */ 5266*1da177e4SLinus Torvalds /* */ 5267*1da177e4SLinus Torvalds /* Reset the controller */ 5268*1da177e4SLinus Torvalds /* */ 5269*1da177e4SLinus Torvalds /****************************************************************************/ 5270*1da177e4SLinus Torvalds static int 5271*1da177e4SLinus Torvalds ips_reset_morpheus(ips_ha_t * ha) 5272*1da177e4SLinus Torvalds { 5273*1da177e4SLinus Torvalds int reset_counter; 5274*1da177e4SLinus Torvalds uint8_t junk; 5275*1da177e4SLinus Torvalds 5276*1da177e4SLinus Torvalds METHOD_TRACE("ips_reset_morpheus", 1); 5277*1da177e4SLinus Torvalds 5278*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", 5279*1da177e4SLinus Torvalds ips_name, ha->host_num, ha->mem_addr, ha->irq); 5280*1da177e4SLinus Torvalds 5281*1da177e4SLinus Torvalds reset_counter = 0; 5282*1da177e4SLinus Torvalds 5283*1da177e4SLinus Torvalds while (reset_counter < 2) { 5284*1da177e4SLinus Torvalds reset_counter++; 5285*1da177e4SLinus Torvalds 5286*1da177e4SLinus Torvalds writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); 5287*1da177e4SLinus Torvalds 5288*1da177e4SLinus Torvalds /* Delay for 5 Seconds */ 5289*1da177e4SLinus Torvalds MDELAY(5 * IPS_ONE_SEC); 5290*1da177e4SLinus Torvalds 5291*1da177e4SLinus Torvalds /* Do a PCI config read to wait for adapter */ 5292*1da177e4SLinus Torvalds pci_read_config_byte(ha->pcidev, 4, &junk); 5293*1da177e4SLinus Torvalds 5294*1da177e4SLinus Torvalds if ((*ha->func.init) (ha)) 5295*1da177e4SLinus Torvalds break; 5296*1da177e4SLinus Torvalds else if (reset_counter >= 2) { 5297*1da177e4SLinus Torvalds 5298*1da177e4SLinus Torvalds return (0); 5299*1da177e4SLinus Torvalds } 5300*1da177e4SLinus Torvalds } 5301*1da177e4SLinus Torvalds 5302*1da177e4SLinus Torvalds return (1); 5303*1da177e4SLinus Torvalds } 5304*1da177e4SLinus Torvalds 5305*1da177e4SLinus Torvalds /****************************************************************************/ 5306*1da177e4SLinus Torvalds /* */ 5307*1da177e4SLinus Torvalds /* Routine Name: ips_statinit */ 5308*1da177e4SLinus Torvalds /* */ 5309*1da177e4SLinus Torvalds /* Routine Description: */ 5310*1da177e4SLinus Torvalds /* */ 5311*1da177e4SLinus Torvalds /* Initialize the status queues on the controller */ 5312*1da177e4SLinus Torvalds /* */ 5313*1da177e4SLinus Torvalds /****************************************************************************/ 5314*1da177e4SLinus Torvalds static void 5315*1da177e4SLinus Torvalds ips_statinit(ips_ha_t * ha) 5316*1da177e4SLinus Torvalds { 5317*1da177e4SLinus Torvalds uint32_t phys_status_start; 5318*1da177e4SLinus Torvalds 5319*1da177e4SLinus Torvalds METHOD_TRACE("ips_statinit", 1); 5320*1da177e4SLinus Torvalds 5321*1da177e4SLinus Torvalds ha->adapt->p_status_start = ha->adapt->status; 5322*1da177e4SLinus Torvalds ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; 5323*1da177e4SLinus Torvalds ha->adapt->p_status_tail = ha->adapt->status; 5324*1da177e4SLinus Torvalds 5325*1da177e4SLinus Torvalds phys_status_start = ha->adapt->hw_status_start; 5326*1da177e4SLinus Torvalds outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR); 5327*1da177e4SLinus Torvalds outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), 5328*1da177e4SLinus Torvalds ha->io_addr + IPS_REG_SQER); 5329*1da177e4SLinus Torvalds outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), 5330*1da177e4SLinus Torvalds ha->io_addr + IPS_REG_SQHR); 5331*1da177e4SLinus Torvalds outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR); 5332*1da177e4SLinus Torvalds 5333*1da177e4SLinus Torvalds ha->adapt->hw_status_tail = phys_status_start; 5334*1da177e4SLinus Torvalds } 5335*1da177e4SLinus Torvalds 5336*1da177e4SLinus Torvalds /****************************************************************************/ 5337*1da177e4SLinus Torvalds /* */ 5338*1da177e4SLinus Torvalds /* Routine Name: ips_statinit_memio */ 5339*1da177e4SLinus Torvalds /* */ 5340*1da177e4SLinus Torvalds /* Routine Description: */ 5341*1da177e4SLinus Torvalds /* */ 5342*1da177e4SLinus Torvalds /* Initialize the status queues on the controller */ 5343*1da177e4SLinus Torvalds /* */ 5344*1da177e4SLinus Torvalds /****************************************************************************/ 5345*1da177e4SLinus Torvalds static void 5346*1da177e4SLinus Torvalds ips_statinit_memio(ips_ha_t * ha) 5347*1da177e4SLinus Torvalds { 5348*1da177e4SLinus Torvalds uint32_t phys_status_start; 5349*1da177e4SLinus Torvalds 5350*1da177e4SLinus Torvalds METHOD_TRACE("ips_statinit_memio", 1); 5351*1da177e4SLinus Torvalds 5352*1da177e4SLinus Torvalds ha->adapt->p_status_start = ha->adapt->status; 5353*1da177e4SLinus Torvalds ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; 5354*1da177e4SLinus Torvalds ha->adapt->p_status_tail = ha->adapt->status; 5355*1da177e4SLinus Torvalds 5356*1da177e4SLinus Torvalds phys_status_start = ha->adapt->hw_status_start; 5357*1da177e4SLinus Torvalds writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); 5358*1da177e4SLinus Torvalds writel(phys_status_start + IPS_STATUS_Q_SIZE, 5359*1da177e4SLinus Torvalds ha->mem_ptr + IPS_REG_SQER); 5360*1da177e4SLinus Torvalds writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); 5361*1da177e4SLinus Torvalds writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR); 5362*1da177e4SLinus Torvalds 5363*1da177e4SLinus Torvalds ha->adapt->hw_status_tail = phys_status_start; 5364*1da177e4SLinus Torvalds } 5365*1da177e4SLinus Torvalds 5366*1da177e4SLinus Torvalds /****************************************************************************/ 5367*1da177e4SLinus Torvalds /* */ 5368*1da177e4SLinus Torvalds /* Routine Name: ips_statupd_copperhead */ 5369*1da177e4SLinus Torvalds /* */ 5370*1da177e4SLinus Torvalds /* Routine Description: */ 5371*1da177e4SLinus Torvalds /* */ 5372*1da177e4SLinus Torvalds /* Remove an element from the status queue */ 5373*1da177e4SLinus Torvalds /* */ 5374*1da177e4SLinus Torvalds /****************************************************************************/ 5375*1da177e4SLinus Torvalds static uint32_t 5376*1da177e4SLinus Torvalds ips_statupd_copperhead(ips_ha_t * ha) 5377*1da177e4SLinus Torvalds { 5378*1da177e4SLinus Torvalds METHOD_TRACE("ips_statupd_copperhead", 1); 5379*1da177e4SLinus Torvalds 5380*1da177e4SLinus Torvalds if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { 5381*1da177e4SLinus Torvalds ha->adapt->p_status_tail++; 5382*1da177e4SLinus Torvalds ha->adapt->hw_status_tail += sizeof (IPS_STATUS); 5383*1da177e4SLinus Torvalds } else { 5384*1da177e4SLinus Torvalds ha->adapt->p_status_tail = ha->adapt->p_status_start; 5385*1da177e4SLinus Torvalds ha->adapt->hw_status_tail = ha->adapt->hw_status_start; 5386*1da177e4SLinus Torvalds } 5387*1da177e4SLinus Torvalds 5388*1da177e4SLinus Torvalds outl(cpu_to_le32(ha->adapt->hw_status_tail), 5389*1da177e4SLinus Torvalds ha->io_addr + IPS_REG_SQTR); 5390*1da177e4SLinus Torvalds 5391*1da177e4SLinus Torvalds return (ha->adapt->p_status_tail->value); 5392*1da177e4SLinus Torvalds } 5393*1da177e4SLinus Torvalds 5394*1da177e4SLinus Torvalds /****************************************************************************/ 5395*1da177e4SLinus Torvalds /* */ 5396*1da177e4SLinus Torvalds /* Routine Name: ips_statupd_copperhead_memio */ 5397*1da177e4SLinus Torvalds /* */ 5398*1da177e4SLinus Torvalds /* Routine Description: */ 5399*1da177e4SLinus Torvalds /* */ 5400*1da177e4SLinus Torvalds /* Remove an element from the status queue */ 5401*1da177e4SLinus Torvalds /* */ 5402*1da177e4SLinus Torvalds /****************************************************************************/ 5403*1da177e4SLinus Torvalds static uint32_t 5404*1da177e4SLinus Torvalds ips_statupd_copperhead_memio(ips_ha_t * ha) 5405*1da177e4SLinus Torvalds { 5406*1da177e4SLinus Torvalds METHOD_TRACE("ips_statupd_copperhead_memio", 1); 5407*1da177e4SLinus Torvalds 5408*1da177e4SLinus Torvalds if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { 5409*1da177e4SLinus Torvalds ha->adapt->p_status_tail++; 5410*1da177e4SLinus Torvalds ha->adapt->hw_status_tail += sizeof (IPS_STATUS); 5411*1da177e4SLinus Torvalds } else { 5412*1da177e4SLinus Torvalds ha->adapt->p_status_tail = ha->adapt->p_status_start; 5413*1da177e4SLinus Torvalds ha->adapt->hw_status_tail = ha->adapt->hw_status_start; 5414*1da177e4SLinus Torvalds } 5415*1da177e4SLinus Torvalds 5416*1da177e4SLinus Torvalds writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR); 5417*1da177e4SLinus Torvalds 5418*1da177e4SLinus Torvalds return (ha->adapt->p_status_tail->value); 5419*1da177e4SLinus Torvalds } 5420*1da177e4SLinus Torvalds 5421*1da177e4SLinus Torvalds /****************************************************************************/ 5422*1da177e4SLinus Torvalds /* */ 5423*1da177e4SLinus Torvalds /* Routine Name: ips_statupd_morpheus */ 5424*1da177e4SLinus Torvalds /* */ 5425*1da177e4SLinus Torvalds /* Routine Description: */ 5426*1da177e4SLinus Torvalds /* */ 5427*1da177e4SLinus Torvalds /* Remove an element from the status queue */ 5428*1da177e4SLinus Torvalds /* */ 5429*1da177e4SLinus Torvalds /****************************************************************************/ 5430*1da177e4SLinus Torvalds static uint32_t 5431*1da177e4SLinus Torvalds ips_statupd_morpheus(ips_ha_t * ha) 5432*1da177e4SLinus Torvalds { 5433*1da177e4SLinus Torvalds uint32_t val; 5434*1da177e4SLinus Torvalds 5435*1da177e4SLinus Torvalds METHOD_TRACE("ips_statupd_morpheus", 1); 5436*1da177e4SLinus Torvalds 5437*1da177e4SLinus Torvalds val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ); 5438*1da177e4SLinus Torvalds 5439*1da177e4SLinus Torvalds return (val); 5440*1da177e4SLinus Torvalds } 5441*1da177e4SLinus Torvalds 5442*1da177e4SLinus Torvalds /****************************************************************************/ 5443*1da177e4SLinus Torvalds /* */ 5444*1da177e4SLinus Torvalds /* Routine Name: ips_issue_copperhead */ 5445*1da177e4SLinus Torvalds /* */ 5446*1da177e4SLinus Torvalds /* Routine Description: */ 5447*1da177e4SLinus Torvalds /* */ 5448*1da177e4SLinus Torvalds /* Send a command down to the controller */ 5449*1da177e4SLinus Torvalds /* */ 5450*1da177e4SLinus Torvalds /****************************************************************************/ 5451*1da177e4SLinus Torvalds static int 5452*1da177e4SLinus Torvalds ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) 5453*1da177e4SLinus Torvalds { 5454*1da177e4SLinus Torvalds uint32_t TimeOut; 5455*1da177e4SLinus Torvalds uint32_t val; 5456*1da177e4SLinus Torvalds 5457*1da177e4SLinus Torvalds METHOD_TRACE("ips_issue_copperhead", 1); 5458*1da177e4SLinus Torvalds 5459*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 5460*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 5461*1da177e4SLinus Torvalds ips_name, 5462*1da177e4SLinus Torvalds ha->host_num, 5463*1da177e4SLinus Torvalds scb->cdb[0], 5464*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id, 5465*1da177e4SLinus Torvalds scb->bus, scb->target_id, scb->lun); 5466*1da177e4SLinus Torvalds } else { 5467*1da177e4SLinus Torvalds DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", 5468*1da177e4SLinus Torvalds ips_name, ha->host_num, scb->cmd.basic_io.command_id); 5469*1da177e4SLinus Torvalds } 5470*1da177e4SLinus Torvalds 5471*1da177e4SLinus Torvalds TimeOut = 0; 5472*1da177e4SLinus Torvalds 5473*1da177e4SLinus Torvalds while ((val = 5474*1da177e4SLinus Torvalds le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) { 5475*1da177e4SLinus Torvalds udelay(1000); 5476*1da177e4SLinus Torvalds 5477*1da177e4SLinus Torvalds if (++TimeOut >= IPS_SEM_TIMEOUT) { 5478*1da177e4SLinus Torvalds if (!(val & IPS_BIT_START_STOP)) 5479*1da177e4SLinus Torvalds break; 5480*1da177e4SLinus Torvalds 5481*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5482*1da177e4SLinus Torvalds "ips_issue val [0x%x].\n", val); 5483*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5484*1da177e4SLinus Torvalds "ips_issue semaphore chk timeout.\n"); 5485*1da177e4SLinus Torvalds 5486*1da177e4SLinus Torvalds return (IPS_FAILURE); 5487*1da177e4SLinus Torvalds } /* end if */ 5488*1da177e4SLinus Torvalds } /* end while */ 5489*1da177e4SLinus Torvalds 5490*1da177e4SLinus Torvalds outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR); 5491*1da177e4SLinus Torvalds outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR); 5492*1da177e4SLinus Torvalds 5493*1da177e4SLinus Torvalds return (IPS_SUCCESS); 5494*1da177e4SLinus Torvalds } 5495*1da177e4SLinus Torvalds 5496*1da177e4SLinus Torvalds /****************************************************************************/ 5497*1da177e4SLinus Torvalds /* */ 5498*1da177e4SLinus Torvalds /* Routine Name: ips_issue_copperhead_memio */ 5499*1da177e4SLinus Torvalds /* */ 5500*1da177e4SLinus Torvalds /* Routine Description: */ 5501*1da177e4SLinus Torvalds /* */ 5502*1da177e4SLinus Torvalds /* Send a command down to the controller */ 5503*1da177e4SLinus Torvalds /* */ 5504*1da177e4SLinus Torvalds /****************************************************************************/ 5505*1da177e4SLinus Torvalds static int 5506*1da177e4SLinus Torvalds ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) 5507*1da177e4SLinus Torvalds { 5508*1da177e4SLinus Torvalds uint32_t TimeOut; 5509*1da177e4SLinus Torvalds uint32_t val; 5510*1da177e4SLinus Torvalds 5511*1da177e4SLinus Torvalds METHOD_TRACE("ips_issue_copperhead_memio", 1); 5512*1da177e4SLinus Torvalds 5513*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 5514*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 5515*1da177e4SLinus Torvalds ips_name, 5516*1da177e4SLinus Torvalds ha->host_num, 5517*1da177e4SLinus Torvalds scb->cdb[0], 5518*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id, 5519*1da177e4SLinus Torvalds scb->bus, scb->target_id, scb->lun); 5520*1da177e4SLinus Torvalds } else { 5521*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", 5522*1da177e4SLinus Torvalds ips_name, ha->host_num, scb->cmd.basic_io.command_id); 5523*1da177e4SLinus Torvalds } 5524*1da177e4SLinus Torvalds 5525*1da177e4SLinus Torvalds TimeOut = 0; 5526*1da177e4SLinus Torvalds 5527*1da177e4SLinus Torvalds while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { 5528*1da177e4SLinus Torvalds udelay(1000); 5529*1da177e4SLinus Torvalds 5530*1da177e4SLinus Torvalds if (++TimeOut >= IPS_SEM_TIMEOUT) { 5531*1da177e4SLinus Torvalds if (!(val & IPS_BIT_START_STOP)) 5532*1da177e4SLinus Torvalds break; 5533*1da177e4SLinus Torvalds 5534*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5535*1da177e4SLinus Torvalds "ips_issue val [0x%x].\n", val); 5536*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5537*1da177e4SLinus Torvalds "ips_issue semaphore chk timeout.\n"); 5538*1da177e4SLinus Torvalds 5539*1da177e4SLinus Torvalds return (IPS_FAILURE); 5540*1da177e4SLinus Torvalds } /* end if */ 5541*1da177e4SLinus Torvalds } /* end while */ 5542*1da177e4SLinus Torvalds 5543*1da177e4SLinus Torvalds writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); 5544*1da177e4SLinus Torvalds writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR); 5545*1da177e4SLinus Torvalds 5546*1da177e4SLinus Torvalds return (IPS_SUCCESS); 5547*1da177e4SLinus Torvalds } 5548*1da177e4SLinus Torvalds 5549*1da177e4SLinus Torvalds /****************************************************************************/ 5550*1da177e4SLinus Torvalds /* */ 5551*1da177e4SLinus Torvalds /* Routine Name: ips_issue_i2o */ 5552*1da177e4SLinus Torvalds /* */ 5553*1da177e4SLinus Torvalds /* Routine Description: */ 5554*1da177e4SLinus Torvalds /* */ 5555*1da177e4SLinus Torvalds /* Send a command down to the controller */ 5556*1da177e4SLinus Torvalds /* */ 5557*1da177e4SLinus Torvalds /****************************************************************************/ 5558*1da177e4SLinus Torvalds static int 5559*1da177e4SLinus Torvalds ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) 5560*1da177e4SLinus Torvalds { 5561*1da177e4SLinus Torvalds 5562*1da177e4SLinus Torvalds METHOD_TRACE("ips_issue_i2o", 1); 5563*1da177e4SLinus Torvalds 5564*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 5565*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 5566*1da177e4SLinus Torvalds ips_name, 5567*1da177e4SLinus Torvalds ha->host_num, 5568*1da177e4SLinus Torvalds scb->cdb[0], 5569*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id, 5570*1da177e4SLinus Torvalds scb->bus, scb->target_id, scb->lun); 5571*1da177e4SLinus Torvalds } else { 5572*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", 5573*1da177e4SLinus Torvalds ips_name, ha->host_num, scb->cmd.basic_io.command_id); 5574*1da177e4SLinus Torvalds } 5575*1da177e4SLinus Torvalds 5576*1da177e4SLinus Torvalds outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ); 5577*1da177e4SLinus Torvalds 5578*1da177e4SLinus Torvalds return (IPS_SUCCESS); 5579*1da177e4SLinus Torvalds } 5580*1da177e4SLinus Torvalds 5581*1da177e4SLinus Torvalds /****************************************************************************/ 5582*1da177e4SLinus Torvalds /* */ 5583*1da177e4SLinus Torvalds /* Routine Name: ips_issue_i2o_memio */ 5584*1da177e4SLinus Torvalds /* */ 5585*1da177e4SLinus Torvalds /* Routine Description: */ 5586*1da177e4SLinus Torvalds /* */ 5587*1da177e4SLinus Torvalds /* Send a command down to the controller */ 5588*1da177e4SLinus Torvalds /* */ 5589*1da177e4SLinus Torvalds /****************************************************************************/ 5590*1da177e4SLinus Torvalds static int 5591*1da177e4SLinus Torvalds ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) 5592*1da177e4SLinus Torvalds { 5593*1da177e4SLinus Torvalds 5594*1da177e4SLinus Torvalds METHOD_TRACE("ips_issue_i2o_memio", 1); 5595*1da177e4SLinus Torvalds 5596*1da177e4SLinus Torvalds if (scb->scsi_cmd) { 5597*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 5598*1da177e4SLinus Torvalds ips_name, 5599*1da177e4SLinus Torvalds ha->host_num, 5600*1da177e4SLinus Torvalds scb->cdb[0], 5601*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id, 5602*1da177e4SLinus Torvalds scb->bus, scb->target_id, scb->lun); 5603*1da177e4SLinus Torvalds } else { 5604*1da177e4SLinus Torvalds DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", 5605*1da177e4SLinus Torvalds ips_name, ha->host_num, scb->cmd.basic_io.command_id); 5606*1da177e4SLinus Torvalds } 5607*1da177e4SLinus Torvalds 5608*1da177e4SLinus Torvalds writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ); 5609*1da177e4SLinus Torvalds 5610*1da177e4SLinus Torvalds return (IPS_SUCCESS); 5611*1da177e4SLinus Torvalds } 5612*1da177e4SLinus Torvalds 5613*1da177e4SLinus Torvalds /****************************************************************************/ 5614*1da177e4SLinus Torvalds /* */ 5615*1da177e4SLinus Torvalds /* Routine Name: ips_isintr_copperhead */ 5616*1da177e4SLinus Torvalds /* */ 5617*1da177e4SLinus Torvalds /* Routine Description: */ 5618*1da177e4SLinus Torvalds /* */ 5619*1da177e4SLinus Torvalds /* Test to see if an interrupt is for us */ 5620*1da177e4SLinus Torvalds /* */ 5621*1da177e4SLinus Torvalds /****************************************************************************/ 5622*1da177e4SLinus Torvalds static int 5623*1da177e4SLinus Torvalds ips_isintr_copperhead(ips_ha_t * ha) 5624*1da177e4SLinus Torvalds { 5625*1da177e4SLinus Torvalds uint8_t Isr; 5626*1da177e4SLinus Torvalds 5627*1da177e4SLinus Torvalds METHOD_TRACE("ips_isintr_copperhead", 2); 5628*1da177e4SLinus Torvalds 5629*1da177e4SLinus Torvalds Isr = inb(ha->io_addr + IPS_REG_HISR); 5630*1da177e4SLinus Torvalds 5631*1da177e4SLinus Torvalds if (Isr == 0xFF) 5632*1da177e4SLinus Torvalds /* ?!?! Nothing really there */ 5633*1da177e4SLinus Torvalds return (0); 5634*1da177e4SLinus Torvalds 5635*1da177e4SLinus Torvalds if (Isr & IPS_BIT_SCE) 5636*1da177e4SLinus Torvalds return (1); 5637*1da177e4SLinus Torvalds else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { 5638*1da177e4SLinus Torvalds /* status queue overflow or GHI */ 5639*1da177e4SLinus Torvalds /* just clear the interrupt */ 5640*1da177e4SLinus Torvalds outb(Isr, ha->io_addr + IPS_REG_HISR); 5641*1da177e4SLinus Torvalds } 5642*1da177e4SLinus Torvalds 5643*1da177e4SLinus Torvalds return (0); 5644*1da177e4SLinus Torvalds } 5645*1da177e4SLinus Torvalds 5646*1da177e4SLinus Torvalds /****************************************************************************/ 5647*1da177e4SLinus Torvalds /* */ 5648*1da177e4SLinus Torvalds /* Routine Name: ips_isintr_copperhead_memio */ 5649*1da177e4SLinus Torvalds /* */ 5650*1da177e4SLinus Torvalds /* Routine Description: */ 5651*1da177e4SLinus Torvalds /* */ 5652*1da177e4SLinus Torvalds /* Test to see if an interrupt is for us */ 5653*1da177e4SLinus Torvalds /* */ 5654*1da177e4SLinus Torvalds /****************************************************************************/ 5655*1da177e4SLinus Torvalds static int 5656*1da177e4SLinus Torvalds ips_isintr_copperhead_memio(ips_ha_t * ha) 5657*1da177e4SLinus Torvalds { 5658*1da177e4SLinus Torvalds uint8_t Isr; 5659*1da177e4SLinus Torvalds 5660*1da177e4SLinus Torvalds METHOD_TRACE("ips_isintr_memio", 2); 5661*1da177e4SLinus Torvalds 5662*1da177e4SLinus Torvalds Isr = readb(ha->mem_ptr + IPS_REG_HISR); 5663*1da177e4SLinus Torvalds 5664*1da177e4SLinus Torvalds if (Isr == 0xFF) 5665*1da177e4SLinus Torvalds /* ?!?! Nothing really there */ 5666*1da177e4SLinus Torvalds return (0); 5667*1da177e4SLinus Torvalds 5668*1da177e4SLinus Torvalds if (Isr & IPS_BIT_SCE) 5669*1da177e4SLinus Torvalds return (1); 5670*1da177e4SLinus Torvalds else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { 5671*1da177e4SLinus Torvalds /* status queue overflow or GHI */ 5672*1da177e4SLinus Torvalds /* just clear the interrupt */ 5673*1da177e4SLinus Torvalds writeb(Isr, ha->mem_ptr + IPS_REG_HISR); 5674*1da177e4SLinus Torvalds } 5675*1da177e4SLinus Torvalds 5676*1da177e4SLinus Torvalds return (0); 5677*1da177e4SLinus Torvalds } 5678*1da177e4SLinus Torvalds 5679*1da177e4SLinus Torvalds /****************************************************************************/ 5680*1da177e4SLinus Torvalds /* */ 5681*1da177e4SLinus Torvalds /* Routine Name: ips_isintr_morpheus */ 5682*1da177e4SLinus Torvalds /* */ 5683*1da177e4SLinus Torvalds /* Routine Description: */ 5684*1da177e4SLinus Torvalds /* */ 5685*1da177e4SLinus Torvalds /* Test to see if an interrupt is for us */ 5686*1da177e4SLinus Torvalds /* */ 5687*1da177e4SLinus Torvalds /****************************************************************************/ 5688*1da177e4SLinus Torvalds static int 5689*1da177e4SLinus Torvalds ips_isintr_morpheus(ips_ha_t * ha) 5690*1da177e4SLinus Torvalds { 5691*1da177e4SLinus Torvalds uint32_t Isr; 5692*1da177e4SLinus Torvalds 5693*1da177e4SLinus Torvalds METHOD_TRACE("ips_isintr_morpheus", 2); 5694*1da177e4SLinus Torvalds 5695*1da177e4SLinus Torvalds Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 5696*1da177e4SLinus Torvalds 5697*1da177e4SLinus Torvalds if (Isr & IPS_BIT_I2O_OPQI) 5698*1da177e4SLinus Torvalds return (1); 5699*1da177e4SLinus Torvalds else 5700*1da177e4SLinus Torvalds return (0); 5701*1da177e4SLinus Torvalds } 5702*1da177e4SLinus Torvalds 5703*1da177e4SLinus Torvalds /****************************************************************************/ 5704*1da177e4SLinus Torvalds /* */ 5705*1da177e4SLinus Torvalds /* Routine Name: ips_wait */ 5706*1da177e4SLinus Torvalds /* */ 5707*1da177e4SLinus Torvalds /* Routine Description: */ 5708*1da177e4SLinus Torvalds /* */ 5709*1da177e4SLinus Torvalds /* Wait for a command to complete */ 5710*1da177e4SLinus Torvalds /* */ 5711*1da177e4SLinus Torvalds /****************************************************************************/ 5712*1da177e4SLinus Torvalds static int 5713*1da177e4SLinus Torvalds ips_wait(ips_ha_t * ha, int time, int intr) 5714*1da177e4SLinus Torvalds { 5715*1da177e4SLinus Torvalds int ret; 5716*1da177e4SLinus Torvalds int done; 5717*1da177e4SLinus Torvalds 5718*1da177e4SLinus Torvalds METHOD_TRACE("ips_wait", 1); 5719*1da177e4SLinus Torvalds 5720*1da177e4SLinus Torvalds ret = IPS_FAILURE; 5721*1da177e4SLinus Torvalds done = FALSE; 5722*1da177e4SLinus Torvalds 5723*1da177e4SLinus Torvalds time *= IPS_ONE_SEC; /* convert seconds */ 5724*1da177e4SLinus Torvalds 5725*1da177e4SLinus Torvalds while ((time > 0) && (!done)) { 5726*1da177e4SLinus Torvalds if (intr == IPS_INTR_ON) { 5727*1da177e4SLinus Torvalds if (ha->waitflag == FALSE) { 5728*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 5729*1da177e4SLinus Torvalds done = TRUE; 5730*1da177e4SLinus Torvalds break; 5731*1da177e4SLinus Torvalds } 5732*1da177e4SLinus Torvalds } else if (intr == IPS_INTR_IORL) { 5733*1da177e4SLinus Torvalds if (ha->waitflag == FALSE) { 5734*1da177e4SLinus Torvalds /* 5735*1da177e4SLinus Torvalds * controller generated an interrupt to 5736*1da177e4SLinus Torvalds * acknowledge completion of the command 5737*1da177e4SLinus Torvalds * and ips_intr() has serviced the interrupt. 5738*1da177e4SLinus Torvalds */ 5739*1da177e4SLinus Torvalds ret = IPS_SUCCESS; 5740*1da177e4SLinus Torvalds done = TRUE; 5741*1da177e4SLinus Torvalds break; 5742*1da177e4SLinus Torvalds } 5743*1da177e4SLinus Torvalds 5744*1da177e4SLinus Torvalds /* 5745*1da177e4SLinus Torvalds * NOTE: we already have the io_request_lock so 5746*1da177e4SLinus Torvalds * even if we get an interrupt it won't get serviced 5747*1da177e4SLinus Torvalds * until after we finish. 5748*1da177e4SLinus Torvalds */ 5749*1da177e4SLinus Torvalds 5750*1da177e4SLinus Torvalds (*ha->func.intr) (ha); 5751*1da177e4SLinus Torvalds } 5752*1da177e4SLinus Torvalds 5753*1da177e4SLinus Torvalds /* This looks like a very evil loop, but it only does this during start-up */ 5754*1da177e4SLinus Torvalds udelay(1000); 5755*1da177e4SLinus Torvalds time--; 5756*1da177e4SLinus Torvalds } 5757*1da177e4SLinus Torvalds 5758*1da177e4SLinus Torvalds return (ret); 5759*1da177e4SLinus Torvalds } 5760*1da177e4SLinus Torvalds 5761*1da177e4SLinus Torvalds /****************************************************************************/ 5762*1da177e4SLinus Torvalds /* */ 5763*1da177e4SLinus Torvalds /* Routine Name: ips_write_driver_status */ 5764*1da177e4SLinus Torvalds /* */ 5765*1da177e4SLinus Torvalds /* Routine Description: */ 5766*1da177e4SLinus Torvalds /* */ 5767*1da177e4SLinus Torvalds /* Write OS/Driver version to Page 5 of the nvram on the controller */ 5768*1da177e4SLinus Torvalds /* */ 5769*1da177e4SLinus Torvalds /****************************************************************************/ 5770*1da177e4SLinus Torvalds static int 5771*1da177e4SLinus Torvalds ips_write_driver_status(ips_ha_t * ha, int intr) 5772*1da177e4SLinus Torvalds { 5773*1da177e4SLinus Torvalds METHOD_TRACE("ips_write_driver_status", 1); 5774*1da177e4SLinus Torvalds 5775*1da177e4SLinus Torvalds if (!ips_readwrite_page5(ha, FALSE, intr)) { 5776*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5777*1da177e4SLinus Torvalds "unable to read NVRAM page 5.\n"); 5778*1da177e4SLinus Torvalds 5779*1da177e4SLinus Torvalds return (0); 5780*1da177e4SLinus Torvalds } 5781*1da177e4SLinus Torvalds 5782*1da177e4SLinus Torvalds /* check to make sure the page has a valid */ 5783*1da177e4SLinus Torvalds /* signature */ 5784*1da177e4SLinus Torvalds if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) { 5785*1da177e4SLinus Torvalds DEBUG_VAR(1, 5786*1da177e4SLinus Torvalds "(%s%d) NVRAM page 5 has an invalid signature: %X.", 5787*1da177e4SLinus Torvalds ips_name, ha->host_num, ha->nvram->signature); 5788*1da177e4SLinus Torvalds ha->nvram->signature = IPS_NVRAM_P5_SIG; 5789*1da177e4SLinus Torvalds } 5790*1da177e4SLinus Torvalds 5791*1da177e4SLinus Torvalds DEBUG_VAR(2, 5792*1da177e4SLinus Torvalds "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", 5793*1da177e4SLinus Torvalds ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type), 5794*1da177e4SLinus Torvalds ha->nvram->adapter_slot, ha->nvram->bios_high[0], 5795*1da177e4SLinus Torvalds ha->nvram->bios_high[1], ha->nvram->bios_high[2], 5796*1da177e4SLinus Torvalds ha->nvram->bios_high[3], ha->nvram->bios_low[0], 5797*1da177e4SLinus Torvalds ha->nvram->bios_low[1], ha->nvram->bios_low[2], 5798*1da177e4SLinus Torvalds ha->nvram->bios_low[3]); 5799*1da177e4SLinus Torvalds 5800*1da177e4SLinus Torvalds ips_get_bios_version(ha, intr); 5801*1da177e4SLinus Torvalds 5802*1da177e4SLinus Torvalds /* change values (as needed) */ 5803*1da177e4SLinus Torvalds ha->nvram->operating_system = IPS_OS_LINUX; 5804*1da177e4SLinus Torvalds ha->nvram->adapter_type = ha->ad_type; 5805*1da177e4SLinus Torvalds strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); 5806*1da177e4SLinus Torvalds strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); 5807*1da177e4SLinus Torvalds strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4); 5808*1da177e4SLinus Torvalds strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4); 5809*1da177e4SLinus Torvalds 5810*1da177e4SLinus Torvalds ips_version_check(ha, intr); /* Check BIOS/FW/Driver Versions */ 5811*1da177e4SLinus Torvalds 5812*1da177e4SLinus Torvalds /* now update the page */ 5813*1da177e4SLinus Torvalds if (!ips_readwrite_page5(ha, TRUE, intr)) { 5814*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 5815*1da177e4SLinus Torvalds "unable to write NVRAM page 5.\n"); 5816*1da177e4SLinus Torvalds 5817*1da177e4SLinus Torvalds return (0); 5818*1da177e4SLinus Torvalds } 5819*1da177e4SLinus Torvalds 5820*1da177e4SLinus Torvalds /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ 5821*1da177e4SLinus Torvalds ha->slot_num = ha->nvram->adapter_slot; 5822*1da177e4SLinus Torvalds 5823*1da177e4SLinus Torvalds return (1); 5824*1da177e4SLinus Torvalds } 5825*1da177e4SLinus Torvalds 5826*1da177e4SLinus Torvalds /****************************************************************************/ 5827*1da177e4SLinus Torvalds /* */ 5828*1da177e4SLinus Torvalds /* Routine Name: ips_read_adapter_status */ 5829*1da177e4SLinus Torvalds /* */ 5830*1da177e4SLinus Torvalds /* Routine Description: */ 5831*1da177e4SLinus Torvalds /* */ 5832*1da177e4SLinus Torvalds /* Do an Inquiry command to the adapter */ 5833*1da177e4SLinus Torvalds /* */ 5834*1da177e4SLinus Torvalds /****************************************************************************/ 5835*1da177e4SLinus Torvalds static int 5836*1da177e4SLinus Torvalds ips_read_adapter_status(ips_ha_t * ha, int intr) 5837*1da177e4SLinus Torvalds { 5838*1da177e4SLinus Torvalds ips_scb_t *scb; 5839*1da177e4SLinus Torvalds int ret; 5840*1da177e4SLinus Torvalds 5841*1da177e4SLinus Torvalds METHOD_TRACE("ips_read_adapter_status", 1); 5842*1da177e4SLinus Torvalds 5843*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 5844*1da177e4SLinus Torvalds 5845*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 5846*1da177e4SLinus Torvalds 5847*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 5848*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_ENQUIRY; 5849*1da177e4SLinus Torvalds 5850*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; 5851*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 5852*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_count = 0; 5853*1da177e4SLinus Torvalds scb->cmd.basic_io.lba = 0; 5854*1da177e4SLinus Torvalds scb->cmd.basic_io.sector_count = 0; 5855*1da177e4SLinus Torvalds scb->cmd.basic_io.log_drv = 0; 5856*1da177e4SLinus Torvalds scb->data_len = sizeof (*ha->enq); 5857*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = ha->enq_busaddr; 5858*1da177e4SLinus Torvalds 5859*1da177e4SLinus Torvalds /* send command */ 5860*1da177e4SLinus Torvalds if (((ret = 5861*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 5862*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 5863*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 5864*1da177e4SLinus Torvalds return (0); 5865*1da177e4SLinus Torvalds 5866*1da177e4SLinus Torvalds return (1); 5867*1da177e4SLinus Torvalds } 5868*1da177e4SLinus Torvalds 5869*1da177e4SLinus Torvalds /****************************************************************************/ 5870*1da177e4SLinus Torvalds /* */ 5871*1da177e4SLinus Torvalds /* Routine Name: ips_read_subsystem_parameters */ 5872*1da177e4SLinus Torvalds /* */ 5873*1da177e4SLinus Torvalds /* Routine Description: */ 5874*1da177e4SLinus Torvalds /* */ 5875*1da177e4SLinus Torvalds /* Read subsystem parameters from the adapter */ 5876*1da177e4SLinus Torvalds /* */ 5877*1da177e4SLinus Torvalds /****************************************************************************/ 5878*1da177e4SLinus Torvalds static int 5879*1da177e4SLinus Torvalds ips_read_subsystem_parameters(ips_ha_t * ha, int intr) 5880*1da177e4SLinus Torvalds { 5881*1da177e4SLinus Torvalds ips_scb_t *scb; 5882*1da177e4SLinus Torvalds int ret; 5883*1da177e4SLinus Torvalds 5884*1da177e4SLinus Torvalds METHOD_TRACE("ips_read_subsystem_parameters", 1); 5885*1da177e4SLinus Torvalds 5886*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 5887*1da177e4SLinus Torvalds 5888*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 5889*1da177e4SLinus Torvalds 5890*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 5891*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_GET_SUBSYS; 5892*1da177e4SLinus Torvalds 5893*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS; 5894*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 5895*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_count = 0; 5896*1da177e4SLinus Torvalds scb->cmd.basic_io.lba = 0; 5897*1da177e4SLinus Torvalds scb->cmd.basic_io.sector_count = 0; 5898*1da177e4SLinus Torvalds scb->cmd.basic_io.log_drv = 0; 5899*1da177e4SLinus Torvalds scb->data_len = sizeof (*ha->subsys); 5900*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; 5901*1da177e4SLinus Torvalds 5902*1da177e4SLinus Torvalds /* send command */ 5903*1da177e4SLinus Torvalds if (((ret = 5904*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 5905*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 5906*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 5907*1da177e4SLinus Torvalds return (0); 5908*1da177e4SLinus Torvalds 5909*1da177e4SLinus Torvalds memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys)); 5910*1da177e4SLinus Torvalds return (1); 5911*1da177e4SLinus Torvalds } 5912*1da177e4SLinus Torvalds 5913*1da177e4SLinus Torvalds /****************************************************************************/ 5914*1da177e4SLinus Torvalds /* */ 5915*1da177e4SLinus Torvalds /* Routine Name: ips_read_config */ 5916*1da177e4SLinus Torvalds /* */ 5917*1da177e4SLinus Torvalds /* Routine Description: */ 5918*1da177e4SLinus Torvalds /* */ 5919*1da177e4SLinus Torvalds /* Read the configuration on the adapter */ 5920*1da177e4SLinus Torvalds /* */ 5921*1da177e4SLinus Torvalds /****************************************************************************/ 5922*1da177e4SLinus Torvalds static int 5923*1da177e4SLinus Torvalds ips_read_config(ips_ha_t * ha, int intr) 5924*1da177e4SLinus Torvalds { 5925*1da177e4SLinus Torvalds ips_scb_t *scb; 5926*1da177e4SLinus Torvalds int i; 5927*1da177e4SLinus Torvalds int ret; 5928*1da177e4SLinus Torvalds 5929*1da177e4SLinus Torvalds METHOD_TRACE("ips_read_config", 1); 5930*1da177e4SLinus Torvalds 5931*1da177e4SLinus Torvalds /* set defaults for initiator IDs */ 5932*1da177e4SLinus Torvalds for (i = 0; i < 4; i++) 5933*1da177e4SLinus Torvalds ha->conf->init_id[i] = 7; 5934*1da177e4SLinus Torvalds 5935*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 5936*1da177e4SLinus Torvalds 5937*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 5938*1da177e4SLinus Torvalds 5939*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 5940*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_READ_CONF; 5941*1da177e4SLinus Torvalds 5942*1da177e4SLinus Torvalds scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF; 5943*1da177e4SLinus Torvalds scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 5944*1da177e4SLinus Torvalds scb->data_len = sizeof (*ha->conf); 5945*1da177e4SLinus Torvalds scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; 5946*1da177e4SLinus Torvalds 5947*1da177e4SLinus Torvalds /* send command */ 5948*1da177e4SLinus Torvalds if (((ret = 5949*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 5950*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 5951*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { 5952*1da177e4SLinus Torvalds 5953*1da177e4SLinus Torvalds memset(ha->conf, 0, sizeof (IPS_CONF)); 5954*1da177e4SLinus Torvalds 5955*1da177e4SLinus Torvalds /* reset initiator IDs */ 5956*1da177e4SLinus Torvalds for (i = 0; i < 4; i++) 5957*1da177e4SLinus Torvalds ha->conf->init_id[i] = 7; 5958*1da177e4SLinus Torvalds 5959*1da177e4SLinus Torvalds /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */ 5960*1da177e4SLinus Torvalds if ((scb->basic_status & IPS_GSC_STATUS_MASK) == 5961*1da177e4SLinus Torvalds IPS_CMD_CMPLT_WERROR) 5962*1da177e4SLinus Torvalds return (1); 5963*1da177e4SLinus Torvalds 5964*1da177e4SLinus Torvalds return (0); 5965*1da177e4SLinus Torvalds } 5966*1da177e4SLinus Torvalds 5967*1da177e4SLinus Torvalds memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); 5968*1da177e4SLinus Torvalds return (1); 5969*1da177e4SLinus Torvalds } 5970*1da177e4SLinus Torvalds 5971*1da177e4SLinus Torvalds /****************************************************************************/ 5972*1da177e4SLinus Torvalds /* */ 5973*1da177e4SLinus Torvalds /* Routine Name: ips_readwrite_page5 */ 5974*1da177e4SLinus Torvalds /* */ 5975*1da177e4SLinus Torvalds /* Routine Description: */ 5976*1da177e4SLinus Torvalds /* */ 5977*1da177e4SLinus Torvalds /* Read nvram page 5 from the adapter */ 5978*1da177e4SLinus Torvalds /* */ 5979*1da177e4SLinus Torvalds /****************************************************************************/ 5980*1da177e4SLinus Torvalds static int 5981*1da177e4SLinus Torvalds ips_readwrite_page5(ips_ha_t * ha, int write, int intr) 5982*1da177e4SLinus Torvalds { 5983*1da177e4SLinus Torvalds ips_scb_t *scb; 5984*1da177e4SLinus Torvalds int ret; 5985*1da177e4SLinus Torvalds 5986*1da177e4SLinus Torvalds METHOD_TRACE("ips_readwrite_page5", 1); 5987*1da177e4SLinus Torvalds 5988*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 5989*1da177e4SLinus Torvalds 5990*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 5991*1da177e4SLinus Torvalds 5992*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 5993*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE; 5994*1da177e4SLinus Torvalds 5995*1da177e4SLinus Torvalds scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE; 5996*1da177e4SLinus Torvalds scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); 5997*1da177e4SLinus Torvalds scb->cmd.nvram.page = 5; 5998*1da177e4SLinus Torvalds scb->cmd.nvram.write = write; 5999*1da177e4SLinus Torvalds scb->cmd.nvram.reserved = 0; 6000*1da177e4SLinus Torvalds scb->cmd.nvram.reserved2 = 0; 6001*1da177e4SLinus Torvalds scb->data_len = sizeof (*ha->nvram); 6002*1da177e4SLinus Torvalds scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; 6003*1da177e4SLinus Torvalds if (write) 6004*1da177e4SLinus Torvalds memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram)); 6005*1da177e4SLinus Torvalds 6006*1da177e4SLinus Torvalds /* issue the command */ 6007*1da177e4SLinus Torvalds if (((ret = 6008*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 6009*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 6010*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { 6011*1da177e4SLinus Torvalds 6012*1da177e4SLinus Torvalds memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5)); 6013*1da177e4SLinus Torvalds 6014*1da177e4SLinus Torvalds return (0); 6015*1da177e4SLinus Torvalds } 6016*1da177e4SLinus Torvalds if (!write) 6017*1da177e4SLinus Torvalds memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram)); 6018*1da177e4SLinus Torvalds return (1); 6019*1da177e4SLinus Torvalds } 6020*1da177e4SLinus Torvalds 6021*1da177e4SLinus Torvalds /****************************************************************************/ 6022*1da177e4SLinus Torvalds /* */ 6023*1da177e4SLinus Torvalds /* Routine Name: ips_clear_adapter */ 6024*1da177e4SLinus Torvalds /* */ 6025*1da177e4SLinus Torvalds /* Routine Description: */ 6026*1da177e4SLinus Torvalds /* */ 6027*1da177e4SLinus Torvalds /* Clear the stripe lock tables */ 6028*1da177e4SLinus Torvalds /* */ 6029*1da177e4SLinus Torvalds /****************************************************************************/ 6030*1da177e4SLinus Torvalds static int 6031*1da177e4SLinus Torvalds ips_clear_adapter(ips_ha_t * ha, int intr) 6032*1da177e4SLinus Torvalds { 6033*1da177e4SLinus Torvalds ips_scb_t *scb; 6034*1da177e4SLinus Torvalds int ret; 6035*1da177e4SLinus Torvalds 6036*1da177e4SLinus Torvalds METHOD_TRACE("ips_clear_adapter", 1); 6037*1da177e4SLinus Torvalds 6038*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 6039*1da177e4SLinus Torvalds 6040*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 6041*1da177e4SLinus Torvalds 6042*1da177e4SLinus Torvalds scb->timeout = ips_reset_timeout; 6043*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_CONFIG_SYNC; 6044*1da177e4SLinus Torvalds 6045*1da177e4SLinus Torvalds scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC; 6046*1da177e4SLinus Torvalds scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); 6047*1da177e4SLinus Torvalds scb->cmd.config_sync.channel = 0; 6048*1da177e4SLinus Torvalds scb->cmd.config_sync.source_target = IPS_POCL; 6049*1da177e4SLinus Torvalds scb->cmd.config_sync.reserved = 0; 6050*1da177e4SLinus Torvalds scb->cmd.config_sync.reserved2 = 0; 6051*1da177e4SLinus Torvalds scb->cmd.config_sync.reserved3 = 0; 6052*1da177e4SLinus Torvalds 6053*1da177e4SLinus Torvalds /* issue command */ 6054*1da177e4SLinus Torvalds if (((ret = 6055*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) 6056*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 6057*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 6058*1da177e4SLinus Torvalds return (0); 6059*1da177e4SLinus Torvalds 6060*1da177e4SLinus Torvalds /* send unlock stripe command */ 6061*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 6062*1da177e4SLinus Torvalds 6063*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_ERROR_TABLE; 6064*1da177e4SLinus Torvalds scb->timeout = ips_reset_timeout; 6065*1da177e4SLinus Torvalds 6066*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE; 6067*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); 6068*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.log_drv = 0; 6069*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.control = IPS_CSL; 6070*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.reserved = 0; 6071*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.reserved2 = 0; 6072*1da177e4SLinus Torvalds scb->cmd.unlock_stripe.reserved3 = 0; 6073*1da177e4SLinus Torvalds 6074*1da177e4SLinus Torvalds /* issue command */ 6075*1da177e4SLinus Torvalds if (((ret = 6076*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 6077*1da177e4SLinus Torvalds || (ret == IPS_SUCCESS_IMM) 6078*1da177e4SLinus Torvalds || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 6079*1da177e4SLinus Torvalds return (0); 6080*1da177e4SLinus Torvalds 6081*1da177e4SLinus Torvalds return (1); 6082*1da177e4SLinus Torvalds } 6083*1da177e4SLinus Torvalds 6084*1da177e4SLinus Torvalds /****************************************************************************/ 6085*1da177e4SLinus Torvalds /* */ 6086*1da177e4SLinus Torvalds /* Routine Name: ips_ffdc_reset */ 6087*1da177e4SLinus Torvalds /* */ 6088*1da177e4SLinus Torvalds /* Routine Description: */ 6089*1da177e4SLinus Torvalds /* */ 6090*1da177e4SLinus Torvalds /* FFDC: write reset info */ 6091*1da177e4SLinus Torvalds /* */ 6092*1da177e4SLinus Torvalds /****************************************************************************/ 6093*1da177e4SLinus Torvalds static void 6094*1da177e4SLinus Torvalds ips_ffdc_reset(ips_ha_t * ha, int intr) 6095*1da177e4SLinus Torvalds { 6096*1da177e4SLinus Torvalds ips_scb_t *scb; 6097*1da177e4SLinus Torvalds 6098*1da177e4SLinus Torvalds METHOD_TRACE("ips_ffdc_reset", 1); 6099*1da177e4SLinus Torvalds 6100*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 6101*1da177e4SLinus Torvalds 6102*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 6103*1da177e4SLinus Torvalds 6104*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 6105*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_FFDC; 6106*1da177e4SLinus Torvalds scb->cmd.ffdc.op_code = IPS_CMD_FFDC; 6107*1da177e4SLinus Torvalds scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); 6108*1da177e4SLinus Torvalds scb->cmd.ffdc.reset_count = ha->reset_count; 6109*1da177e4SLinus Torvalds scb->cmd.ffdc.reset_type = 0x80; 6110*1da177e4SLinus Torvalds 6111*1da177e4SLinus Torvalds /* convert time to what the card wants */ 6112*1da177e4SLinus Torvalds ips_fix_ffdc_time(ha, scb, ha->last_ffdc); 6113*1da177e4SLinus Torvalds 6114*1da177e4SLinus Torvalds /* issue command */ 6115*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, intr); 6116*1da177e4SLinus Torvalds } 6117*1da177e4SLinus Torvalds 6118*1da177e4SLinus Torvalds /****************************************************************************/ 6119*1da177e4SLinus Torvalds /* */ 6120*1da177e4SLinus Torvalds /* Routine Name: ips_ffdc_time */ 6121*1da177e4SLinus Torvalds /* */ 6122*1da177e4SLinus Torvalds /* Routine Description: */ 6123*1da177e4SLinus Torvalds /* */ 6124*1da177e4SLinus Torvalds /* FFDC: write time info */ 6125*1da177e4SLinus Torvalds /* */ 6126*1da177e4SLinus Torvalds /****************************************************************************/ 6127*1da177e4SLinus Torvalds static void 6128*1da177e4SLinus Torvalds ips_ffdc_time(ips_ha_t * ha) 6129*1da177e4SLinus Torvalds { 6130*1da177e4SLinus Torvalds ips_scb_t *scb; 6131*1da177e4SLinus Torvalds 6132*1da177e4SLinus Torvalds METHOD_TRACE("ips_ffdc_time", 1); 6133*1da177e4SLinus Torvalds 6134*1da177e4SLinus Torvalds DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num); 6135*1da177e4SLinus Torvalds 6136*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 6137*1da177e4SLinus Torvalds 6138*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 6139*1da177e4SLinus Torvalds 6140*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 6141*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_FFDC; 6142*1da177e4SLinus Torvalds scb->cmd.ffdc.op_code = IPS_CMD_FFDC; 6143*1da177e4SLinus Torvalds scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); 6144*1da177e4SLinus Torvalds scb->cmd.ffdc.reset_count = 0; 6145*1da177e4SLinus Torvalds scb->cmd.ffdc.reset_type = 0; 6146*1da177e4SLinus Torvalds 6147*1da177e4SLinus Torvalds /* convert time to what the card wants */ 6148*1da177e4SLinus Torvalds ips_fix_ffdc_time(ha, scb, ha->last_ffdc); 6149*1da177e4SLinus Torvalds 6150*1da177e4SLinus Torvalds /* issue command */ 6151*1da177e4SLinus Torvalds ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC); 6152*1da177e4SLinus Torvalds } 6153*1da177e4SLinus Torvalds 6154*1da177e4SLinus Torvalds /****************************************************************************/ 6155*1da177e4SLinus Torvalds /* */ 6156*1da177e4SLinus Torvalds /* Routine Name: ips_fix_ffdc_time */ 6157*1da177e4SLinus Torvalds /* */ 6158*1da177e4SLinus Torvalds /* Routine Description: */ 6159*1da177e4SLinus Torvalds /* Adjust time_t to what the card wants */ 6160*1da177e4SLinus Torvalds /* */ 6161*1da177e4SLinus Torvalds /****************************************************************************/ 6162*1da177e4SLinus Torvalds static void 6163*1da177e4SLinus Torvalds ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time) 6164*1da177e4SLinus Torvalds { 6165*1da177e4SLinus Torvalds long days; 6166*1da177e4SLinus Torvalds long rem; 6167*1da177e4SLinus Torvalds int i; 6168*1da177e4SLinus Torvalds int year; 6169*1da177e4SLinus Torvalds int yleap; 6170*1da177e4SLinus Torvalds int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR }; 6171*1da177e4SLinus Torvalds int month_lengths[12][2] = { {31, 31}, 6172*1da177e4SLinus Torvalds {28, 29}, 6173*1da177e4SLinus Torvalds {31, 31}, 6174*1da177e4SLinus Torvalds {30, 30}, 6175*1da177e4SLinus Torvalds {31, 31}, 6176*1da177e4SLinus Torvalds {30, 30}, 6177*1da177e4SLinus Torvalds {31, 31}, 6178*1da177e4SLinus Torvalds {31, 31}, 6179*1da177e4SLinus Torvalds {30, 30}, 6180*1da177e4SLinus Torvalds {31, 31}, 6181*1da177e4SLinus Torvalds {30, 30}, 6182*1da177e4SLinus Torvalds {31, 31} 6183*1da177e4SLinus Torvalds }; 6184*1da177e4SLinus Torvalds 6185*1da177e4SLinus Torvalds METHOD_TRACE("ips_fix_ffdc_time", 1); 6186*1da177e4SLinus Torvalds 6187*1da177e4SLinus Torvalds days = current_time / IPS_SECS_DAY; 6188*1da177e4SLinus Torvalds rem = current_time % IPS_SECS_DAY; 6189*1da177e4SLinus Torvalds 6190*1da177e4SLinus Torvalds scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR); 6191*1da177e4SLinus Torvalds rem = rem % IPS_SECS_HOUR; 6192*1da177e4SLinus Torvalds scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN); 6193*1da177e4SLinus Torvalds scb->cmd.ffdc.second = (rem % IPS_SECS_MIN); 6194*1da177e4SLinus Torvalds 6195*1da177e4SLinus Torvalds year = IPS_EPOCH_YEAR; 6196*1da177e4SLinus Torvalds while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) { 6197*1da177e4SLinus Torvalds int newy; 6198*1da177e4SLinus Torvalds 6199*1da177e4SLinus Torvalds newy = year + (days / IPS_DAYS_NORMAL_YEAR); 6200*1da177e4SLinus Torvalds if (days < 0) 6201*1da177e4SLinus Torvalds --newy; 6202*1da177e4SLinus Torvalds days -= (newy - year) * IPS_DAYS_NORMAL_YEAR + 6203*1da177e4SLinus Torvalds IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) - 6204*1da177e4SLinus Torvalds IPS_NUM_LEAP_YEARS_THROUGH(year - 1); 6205*1da177e4SLinus Torvalds year = newy; 6206*1da177e4SLinus Torvalds } 6207*1da177e4SLinus Torvalds 6208*1da177e4SLinus Torvalds scb->cmd.ffdc.yearH = year / 100; 6209*1da177e4SLinus Torvalds scb->cmd.ffdc.yearL = year % 100; 6210*1da177e4SLinus Torvalds 6211*1da177e4SLinus Torvalds for (i = 0; days >= month_lengths[i][yleap]; ++i) 6212*1da177e4SLinus Torvalds days -= month_lengths[i][yleap]; 6213*1da177e4SLinus Torvalds 6214*1da177e4SLinus Torvalds scb->cmd.ffdc.month = i + 1; 6215*1da177e4SLinus Torvalds scb->cmd.ffdc.day = days + 1; 6216*1da177e4SLinus Torvalds } 6217*1da177e4SLinus Torvalds 6218*1da177e4SLinus Torvalds /**************************************************************************** 6219*1da177e4SLinus Torvalds * BIOS Flash Routines * 6220*1da177e4SLinus Torvalds ****************************************************************************/ 6221*1da177e4SLinus Torvalds 6222*1da177e4SLinus Torvalds /****************************************************************************/ 6223*1da177e4SLinus Torvalds /* */ 6224*1da177e4SLinus Torvalds /* Routine Name: ips_erase_bios */ 6225*1da177e4SLinus Torvalds /* */ 6226*1da177e4SLinus Torvalds /* Routine Description: */ 6227*1da177e4SLinus Torvalds /* Erase the BIOS on the adapter */ 6228*1da177e4SLinus Torvalds /* */ 6229*1da177e4SLinus Torvalds /****************************************************************************/ 6230*1da177e4SLinus Torvalds static int 6231*1da177e4SLinus Torvalds ips_erase_bios(ips_ha_t * ha) 6232*1da177e4SLinus Torvalds { 6233*1da177e4SLinus Torvalds int timeout; 6234*1da177e4SLinus Torvalds uint8_t status = 0; 6235*1da177e4SLinus Torvalds 6236*1da177e4SLinus Torvalds METHOD_TRACE("ips_erase_bios", 1); 6237*1da177e4SLinus Torvalds 6238*1da177e4SLinus Torvalds status = 0; 6239*1da177e4SLinus Torvalds 6240*1da177e4SLinus Torvalds /* Clear the status register */ 6241*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6242*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6243*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6244*1da177e4SLinus Torvalds 6245*1da177e4SLinus Torvalds outb(0x50, ha->io_addr + IPS_REG_FLDP); 6246*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6247*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6248*1da177e4SLinus Torvalds 6249*1da177e4SLinus Torvalds /* Erase Setup */ 6250*1da177e4SLinus Torvalds outb(0x20, ha->io_addr + IPS_REG_FLDP); 6251*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6252*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6253*1da177e4SLinus Torvalds 6254*1da177e4SLinus Torvalds /* Erase Confirm */ 6255*1da177e4SLinus Torvalds outb(0xD0, ha->io_addr + IPS_REG_FLDP); 6256*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6257*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6258*1da177e4SLinus Torvalds 6259*1da177e4SLinus Torvalds /* Erase Status */ 6260*1da177e4SLinus Torvalds outb(0x70, ha->io_addr + IPS_REG_FLDP); 6261*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6262*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6263*1da177e4SLinus Torvalds 6264*1da177e4SLinus Torvalds timeout = 80000; /* 80 seconds */ 6265*1da177e4SLinus Torvalds 6266*1da177e4SLinus Torvalds while (timeout > 0) { 6267*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) { 6268*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6269*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6270*1da177e4SLinus Torvalds } 6271*1da177e4SLinus Torvalds 6272*1da177e4SLinus Torvalds status = inb(ha->io_addr + IPS_REG_FLDP); 6273*1da177e4SLinus Torvalds 6274*1da177e4SLinus Torvalds if (status & 0x80) 6275*1da177e4SLinus Torvalds break; 6276*1da177e4SLinus Torvalds 6277*1da177e4SLinus Torvalds MDELAY(1); 6278*1da177e4SLinus Torvalds timeout--; 6279*1da177e4SLinus Torvalds } 6280*1da177e4SLinus Torvalds 6281*1da177e4SLinus Torvalds /* check for timeout */ 6282*1da177e4SLinus Torvalds if (timeout <= 0) { 6283*1da177e4SLinus Torvalds /* timeout */ 6284*1da177e4SLinus Torvalds 6285*1da177e4SLinus Torvalds /* try to suspend the erase */ 6286*1da177e4SLinus Torvalds outb(0xB0, ha->io_addr + IPS_REG_FLDP); 6287*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6288*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6289*1da177e4SLinus Torvalds 6290*1da177e4SLinus Torvalds /* wait for 10 seconds */ 6291*1da177e4SLinus Torvalds timeout = 10000; 6292*1da177e4SLinus Torvalds while (timeout > 0) { 6293*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) { 6294*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6295*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6296*1da177e4SLinus Torvalds } 6297*1da177e4SLinus Torvalds 6298*1da177e4SLinus Torvalds status = inb(ha->io_addr + IPS_REG_FLDP); 6299*1da177e4SLinus Torvalds 6300*1da177e4SLinus Torvalds if (status & 0xC0) 6301*1da177e4SLinus Torvalds break; 6302*1da177e4SLinus Torvalds 6303*1da177e4SLinus Torvalds MDELAY(1); 6304*1da177e4SLinus Torvalds timeout--; 6305*1da177e4SLinus Torvalds } 6306*1da177e4SLinus Torvalds 6307*1da177e4SLinus Torvalds return (1); 6308*1da177e4SLinus Torvalds } 6309*1da177e4SLinus Torvalds 6310*1da177e4SLinus Torvalds /* check for valid VPP */ 6311*1da177e4SLinus Torvalds if (status & 0x08) 6312*1da177e4SLinus Torvalds /* VPP failure */ 6313*1da177e4SLinus Torvalds return (1); 6314*1da177e4SLinus Torvalds 6315*1da177e4SLinus Torvalds /* check for succesful flash */ 6316*1da177e4SLinus Torvalds if (status & 0x30) 6317*1da177e4SLinus Torvalds /* sequence error */ 6318*1da177e4SLinus Torvalds return (1); 6319*1da177e4SLinus Torvalds 6320*1da177e4SLinus Torvalds /* Otherwise, we were successful */ 6321*1da177e4SLinus Torvalds /* clear status */ 6322*1da177e4SLinus Torvalds outb(0x50, ha->io_addr + IPS_REG_FLDP); 6323*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6324*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6325*1da177e4SLinus Torvalds 6326*1da177e4SLinus Torvalds /* enable reads */ 6327*1da177e4SLinus Torvalds outb(0xFF, ha->io_addr + IPS_REG_FLDP); 6328*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6329*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6330*1da177e4SLinus Torvalds 6331*1da177e4SLinus Torvalds return (0); 6332*1da177e4SLinus Torvalds } 6333*1da177e4SLinus Torvalds 6334*1da177e4SLinus Torvalds /****************************************************************************/ 6335*1da177e4SLinus Torvalds /* */ 6336*1da177e4SLinus Torvalds /* Routine Name: ips_erase_bios_memio */ 6337*1da177e4SLinus Torvalds /* */ 6338*1da177e4SLinus Torvalds /* Routine Description: */ 6339*1da177e4SLinus Torvalds /* Erase the BIOS on the adapter */ 6340*1da177e4SLinus Torvalds /* */ 6341*1da177e4SLinus Torvalds /****************************************************************************/ 6342*1da177e4SLinus Torvalds static int 6343*1da177e4SLinus Torvalds ips_erase_bios_memio(ips_ha_t * ha) 6344*1da177e4SLinus Torvalds { 6345*1da177e4SLinus Torvalds int timeout; 6346*1da177e4SLinus Torvalds uint8_t status; 6347*1da177e4SLinus Torvalds 6348*1da177e4SLinus Torvalds METHOD_TRACE("ips_erase_bios_memio", 1); 6349*1da177e4SLinus Torvalds 6350*1da177e4SLinus Torvalds status = 0; 6351*1da177e4SLinus Torvalds 6352*1da177e4SLinus Torvalds /* Clear the status register */ 6353*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6354*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6355*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6356*1da177e4SLinus Torvalds 6357*1da177e4SLinus Torvalds writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); 6358*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6359*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6360*1da177e4SLinus Torvalds 6361*1da177e4SLinus Torvalds /* Erase Setup */ 6362*1da177e4SLinus Torvalds writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); 6363*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6364*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6365*1da177e4SLinus Torvalds 6366*1da177e4SLinus Torvalds /* Erase Confirm */ 6367*1da177e4SLinus Torvalds writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); 6368*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6369*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6370*1da177e4SLinus Torvalds 6371*1da177e4SLinus Torvalds /* Erase Status */ 6372*1da177e4SLinus Torvalds writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); 6373*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6374*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6375*1da177e4SLinus Torvalds 6376*1da177e4SLinus Torvalds timeout = 80000; /* 80 seconds */ 6377*1da177e4SLinus Torvalds 6378*1da177e4SLinus Torvalds while (timeout > 0) { 6379*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) { 6380*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6381*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6382*1da177e4SLinus Torvalds } 6383*1da177e4SLinus Torvalds 6384*1da177e4SLinus Torvalds status = readb(ha->mem_ptr + IPS_REG_FLDP); 6385*1da177e4SLinus Torvalds 6386*1da177e4SLinus Torvalds if (status & 0x80) 6387*1da177e4SLinus Torvalds break; 6388*1da177e4SLinus Torvalds 6389*1da177e4SLinus Torvalds MDELAY(1); 6390*1da177e4SLinus Torvalds timeout--; 6391*1da177e4SLinus Torvalds } 6392*1da177e4SLinus Torvalds 6393*1da177e4SLinus Torvalds /* check for timeout */ 6394*1da177e4SLinus Torvalds if (timeout <= 0) { 6395*1da177e4SLinus Torvalds /* timeout */ 6396*1da177e4SLinus Torvalds 6397*1da177e4SLinus Torvalds /* try to suspend the erase */ 6398*1da177e4SLinus Torvalds writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); 6399*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6400*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6401*1da177e4SLinus Torvalds 6402*1da177e4SLinus Torvalds /* wait for 10 seconds */ 6403*1da177e4SLinus Torvalds timeout = 10000; 6404*1da177e4SLinus Torvalds while (timeout > 0) { 6405*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) { 6406*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6407*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6408*1da177e4SLinus Torvalds } 6409*1da177e4SLinus Torvalds 6410*1da177e4SLinus Torvalds status = readb(ha->mem_ptr + IPS_REG_FLDP); 6411*1da177e4SLinus Torvalds 6412*1da177e4SLinus Torvalds if (status & 0xC0) 6413*1da177e4SLinus Torvalds break; 6414*1da177e4SLinus Torvalds 6415*1da177e4SLinus Torvalds MDELAY(1); 6416*1da177e4SLinus Torvalds timeout--; 6417*1da177e4SLinus Torvalds } 6418*1da177e4SLinus Torvalds 6419*1da177e4SLinus Torvalds return (1); 6420*1da177e4SLinus Torvalds } 6421*1da177e4SLinus Torvalds 6422*1da177e4SLinus Torvalds /* check for valid VPP */ 6423*1da177e4SLinus Torvalds if (status & 0x08) 6424*1da177e4SLinus Torvalds /* VPP failure */ 6425*1da177e4SLinus Torvalds return (1); 6426*1da177e4SLinus Torvalds 6427*1da177e4SLinus Torvalds /* check for succesful flash */ 6428*1da177e4SLinus Torvalds if (status & 0x30) 6429*1da177e4SLinus Torvalds /* sequence error */ 6430*1da177e4SLinus Torvalds return (1); 6431*1da177e4SLinus Torvalds 6432*1da177e4SLinus Torvalds /* Otherwise, we were successful */ 6433*1da177e4SLinus Torvalds /* clear status */ 6434*1da177e4SLinus Torvalds writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); 6435*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6436*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6437*1da177e4SLinus Torvalds 6438*1da177e4SLinus Torvalds /* enable reads */ 6439*1da177e4SLinus Torvalds writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 6440*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6441*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6442*1da177e4SLinus Torvalds 6443*1da177e4SLinus Torvalds return (0); 6444*1da177e4SLinus Torvalds } 6445*1da177e4SLinus Torvalds 6446*1da177e4SLinus Torvalds /****************************************************************************/ 6447*1da177e4SLinus Torvalds /* */ 6448*1da177e4SLinus Torvalds /* Routine Name: ips_program_bios */ 6449*1da177e4SLinus Torvalds /* */ 6450*1da177e4SLinus Torvalds /* Routine Description: */ 6451*1da177e4SLinus Torvalds /* Program the BIOS on the adapter */ 6452*1da177e4SLinus Torvalds /* */ 6453*1da177e4SLinus Torvalds /****************************************************************************/ 6454*1da177e4SLinus Torvalds static int 6455*1da177e4SLinus Torvalds ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, 6456*1da177e4SLinus Torvalds uint32_t offset) 6457*1da177e4SLinus Torvalds { 6458*1da177e4SLinus Torvalds int i; 6459*1da177e4SLinus Torvalds int timeout; 6460*1da177e4SLinus Torvalds uint8_t status = 0; 6461*1da177e4SLinus Torvalds 6462*1da177e4SLinus Torvalds METHOD_TRACE("ips_program_bios", 1); 6463*1da177e4SLinus Torvalds 6464*1da177e4SLinus Torvalds status = 0; 6465*1da177e4SLinus Torvalds 6466*1da177e4SLinus Torvalds for (i = 0; i < buffersize; i++) { 6467*1da177e4SLinus Torvalds /* write a byte */ 6468*1da177e4SLinus Torvalds outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); 6469*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6470*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6471*1da177e4SLinus Torvalds 6472*1da177e4SLinus Torvalds outb(0x40, ha->io_addr + IPS_REG_FLDP); 6473*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6474*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6475*1da177e4SLinus Torvalds 6476*1da177e4SLinus Torvalds outb(buffer[i], ha->io_addr + IPS_REG_FLDP); 6477*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6478*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6479*1da177e4SLinus Torvalds 6480*1da177e4SLinus Torvalds /* wait up to one second */ 6481*1da177e4SLinus Torvalds timeout = 1000; 6482*1da177e4SLinus Torvalds while (timeout > 0) { 6483*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) { 6484*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6485*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6486*1da177e4SLinus Torvalds } 6487*1da177e4SLinus Torvalds 6488*1da177e4SLinus Torvalds status = inb(ha->io_addr + IPS_REG_FLDP); 6489*1da177e4SLinus Torvalds 6490*1da177e4SLinus Torvalds if (status & 0x80) 6491*1da177e4SLinus Torvalds break; 6492*1da177e4SLinus Torvalds 6493*1da177e4SLinus Torvalds MDELAY(1); 6494*1da177e4SLinus Torvalds timeout--; 6495*1da177e4SLinus Torvalds } 6496*1da177e4SLinus Torvalds 6497*1da177e4SLinus Torvalds if (timeout == 0) { 6498*1da177e4SLinus Torvalds /* timeout error */ 6499*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6500*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6501*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6502*1da177e4SLinus Torvalds 6503*1da177e4SLinus Torvalds outb(0xFF, ha->io_addr + IPS_REG_FLDP); 6504*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6505*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6506*1da177e4SLinus Torvalds 6507*1da177e4SLinus Torvalds return (1); 6508*1da177e4SLinus Torvalds } 6509*1da177e4SLinus Torvalds 6510*1da177e4SLinus Torvalds /* check the status */ 6511*1da177e4SLinus Torvalds if (status & 0x18) { 6512*1da177e4SLinus Torvalds /* programming error */ 6513*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6514*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6515*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6516*1da177e4SLinus Torvalds 6517*1da177e4SLinus Torvalds outb(0xFF, ha->io_addr + IPS_REG_FLDP); 6518*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6519*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6520*1da177e4SLinus Torvalds 6521*1da177e4SLinus Torvalds return (1); 6522*1da177e4SLinus Torvalds } 6523*1da177e4SLinus Torvalds } /* end for */ 6524*1da177e4SLinus Torvalds 6525*1da177e4SLinus Torvalds /* Enable reading */ 6526*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6527*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6528*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6529*1da177e4SLinus Torvalds 6530*1da177e4SLinus Torvalds outb(0xFF, ha->io_addr + IPS_REG_FLDP); 6531*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6532*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6533*1da177e4SLinus Torvalds 6534*1da177e4SLinus Torvalds return (0); 6535*1da177e4SLinus Torvalds } 6536*1da177e4SLinus Torvalds 6537*1da177e4SLinus Torvalds /****************************************************************************/ 6538*1da177e4SLinus Torvalds /* */ 6539*1da177e4SLinus Torvalds /* Routine Name: ips_program_bios_memio */ 6540*1da177e4SLinus Torvalds /* */ 6541*1da177e4SLinus Torvalds /* Routine Description: */ 6542*1da177e4SLinus Torvalds /* Program the BIOS on the adapter */ 6543*1da177e4SLinus Torvalds /* */ 6544*1da177e4SLinus Torvalds /****************************************************************************/ 6545*1da177e4SLinus Torvalds static int 6546*1da177e4SLinus Torvalds ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, 6547*1da177e4SLinus Torvalds uint32_t offset) 6548*1da177e4SLinus Torvalds { 6549*1da177e4SLinus Torvalds int i; 6550*1da177e4SLinus Torvalds int timeout; 6551*1da177e4SLinus Torvalds uint8_t status = 0; 6552*1da177e4SLinus Torvalds 6553*1da177e4SLinus Torvalds METHOD_TRACE("ips_program_bios_memio", 1); 6554*1da177e4SLinus Torvalds 6555*1da177e4SLinus Torvalds status = 0; 6556*1da177e4SLinus Torvalds 6557*1da177e4SLinus Torvalds for (i = 0; i < buffersize; i++) { 6558*1da177e4SLinus Torvalds /* write a byte */ 6559*1da177e4SLinus Torvalds writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); 6560*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6561*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6562*1da177e4SLinus Torvalds 6563*1da177e4SLinus Torvalds writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); 6564*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6565*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6566*1da177e4SLinus Torvalds 6567*1da177e4SLinus Torvalds writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); 6568*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6569*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6570*1da177e4SLinus Torvalds 6571*1da177e4SLinus Torvalds /* wait up to one second */ 6572*1da177e4SLinus Torvalds timeout = 1000; 6573*1da177e4SLinus Torvalds while (timeout > 0) { 6574*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) { 6575*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6576*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6577*1da177e4SLinus Torvalds } 6578*1da177e4SLinus Torvalds 6579*1da177e4SLinus Torvalds status = readb(ha->mem_ptr + IPS_REG_FLDP); 6580*1da177e4SLinus Torvalds 6581*1da177e4SLinus Torvalds if (status & 0x80) 6582*1da177e4SLinus Torvalds break; 6583*1da177e4SLinus Torvalds 6584*1da177e4SLinus Torvalds MDELAY(1); 6585*1da177e4SLinus Torvalds timeout--; 6586*1da177e4SLinus Torvalds } 6587*1da177e4SLinus Torvalds 6588*1da177e4SLinus Torvalds if (timeout == 0) { 6589*1da177e4SLinus Torvalds /* timeout error */ 6590*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6591*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6592*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6593*1da177e4SLinus Torvalds 6594*1da177e4SLinus Torvalds writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 6595*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6596*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6597*1da177e4SLinus Torvalds 6598*1da177e4SLinus Torvalds return (1); 6599*1da177e4SLinus Torvalds } 6600*1da177e4SLinus Torvalds 6601*1da177e4SLinus Torvalds /* check the status */ 6602*1da177e4SLinus Torvalds if (status & 0x18) { 6603*1da177e4SLinus Torvalds /* programming error */ 6604*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6605*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6606*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6607*1da177e4SLinus Torvalds 6608*1da177e4SLinus Torvalds writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 6609*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6610*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6611*1da177e4SLinus Torvalds 6612*1da177e4SLinus Torvalds return (1); 6613*1da177e4SLinus Torvalds } 6614*1da177e4SLinus Torvalds } /* end for */ 6615*1da177e4SLinus Torvalds 6616*1da177e4SLinus Torvalds /* Enable reading */ 6617*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6618*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6619*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6620*1da177e4SLinus Torvalds 6621*1da177e4SLinus Torvalds writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 6622*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6623*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6624*1da177e4SLinus Torvalds 6625*1da177e4SLinus Torvalds return (0); 6626*1da177e4SLinus Torvalds } 6627*1da177e4SLinus Torvalds 6628*1da177e4SLinus Torvalds /****************************************************************************/ 6629*1da177e4SLinus Torvalds /* */ 6630*1da177e4SLinus Torvalds /* Routine Name: ips_verify_bios */ 6631*1da177e4SLinus Torvalds /* */ 6632*1da177e4SLinus Torvalds /* Routine Description: */ 6633*1da177e4SLinus Torvalds /* Verify the BIOS on the adapter */ 6634*1da177e4SLinus Torvalds /* */ 6635*1da177e4SLinus Torvalds /****************************************************************************/ 6636*1da177e4SLinus Torvalds static int 6637*1da177e4SLinus Torvalds ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, 6638*1da177e4SLinus Torvalds uint32_t offset) 6639*1da177e4SLinus Torvalds { 6640*1da177e4SLinus Torvalds uint8_t checksum; 6641*1da177e4SLinus Torvalds int i; 6642*1da177e4SLinus Torvalds 6643*1da177e4SLinus Torvalds METHOD_TRACE("ips_verify_bios", 1); 6644*1da177e4SLinus Torvalds 6645*1da177e4SLinus Torvalds /* test 1st byte */ 6646*1da177e4SLinus Torvalds outl(0, ha->io_addr + IPS_REG_FLAP); 6647*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6648*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6649*1da177e4SLinus Torvalds 6650*1da177e4SLinus Torvalds if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) 6651*1da177e4SLinus Torvalds return (1); 6652*1da177e4SLinus Torvalds 6653*1da177e4SLinus Torvalds outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); 6654*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6655*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6656*1da177e4SLinus Torvalds if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) 6657*1da177e4SLinus Torvalds return (1); 6658*1da177e4SLinus Torvalds 6659*1da177e4SLinus Torvalds checksum = 0xff; 6660*1da177e4SLinus Torvalds for (i = 2; i < buffersize; i++) { 6661*1da177e4SLinus Torvalds 6662*1da177e4SLinus Torvalds outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); 6663*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6664*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6665*1da177e4SLinus Torvalds 6666*1da177e4SLinus Torvalds checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); 6667*1da177e4SLinus Torvalds } 6668*1da177e4SLinus Torvalds 6669*1da177e4SLinus Torvalds if (checksum != 0) 6670*1da177e4SLinus Torvalds /* failure */ 6671*1da177e4SLinus Torvalds return (1); 6672*1da177e4SLinus Torvalds else 6673*1da177e4SLinus Torvalds /* success */ 6674*1da177e4SLinus Torvalds return (0); 6675*1da177e4SLinus Torvalds } 6676*1da177e4SLinus Torvalds 6677*1da177e4SLinus Torvalds /****************************************************************************/ 6678*1da177e4SLinus Torvalds /* */ 6679*1da177e4SLinus Torvalds /* Routine Name: ips_verify_bios_memio */ 6680*1da177e4SLinus Torvalds /* */ 6681*1da177e4SLinus Torvalds /* Routine Description: */ 6682*1da177e4SLinus Torvalds /* Verify the BIOS on the adapter */ 6683*1da177e4SLinus Torvalds /* */ 6684*1da177e4SLinus Torvalds /****************************************************************************/ 6685*1da177e4SLinus Torvalds static int 6686*1da177e4SLinus Torvalds ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, 6687*1da177e4SLinus Torvalds uint32_t offset) 6688*1da177e4SLinus Torvalds { 6689*1da177e4SLinus Torvalds uint8_t checksum; 6690*1da177e4SLinus Torvalds int i; 6691*1da177e4SLinus Torvalds 6692*1da177e4SLinus Torvalds METHOD_TRACE("ips_verify_bios_memio", 1); 6693*1da177e4SLinus Torvalds 6694*1da177e4SLinus Torvalds /* test 1st byte */ 6695*1da177e4SLinus Torvalds writel(0, ha->mem_ptr + IPS_REG_FLAP); 6696*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6697*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6698*1da177e4SLinus Torvalds 6699*1da177e4SLinus Torvalds if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) 6700*1da177e4SLinus Torvalds return (1); 6701*1da177e4SLinus Torvalds 6702*1da177e4SLinus Torvalds writel(1, ha->mem_ptr + IPS_REG_FLAP); 6703*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6704*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6705*1da177e4SLinus Torvalds if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) 6706*1da177e4SLinus Torvalds return (1); 6707*1da177e4SLinus Torvalds 6708*1da177e4SLinus Torvalds checksum = 0xff; 6709*1da177e4SLinus Torvalds for (i = 2; i < buffersize; i++) { 6710*1da177e4SLinus Torvalds 6711*1da177e4SLinus Torvalds writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); 6712*1da177e4SLinus Torvalds if (ha->revision_id == IPS_REVID_TROMBONE64) 6713*1da177e4SLinus Torvalds udelay(25); /* 25 us */ 6714*1da177e4SLinus Torvalds 6715*1da177e4SLinus Torvalds checksum = 6716*1da177e4SLinus Torvalds (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); 6717*1da177e4SLinus Torvalds } 6718*1da177e4SLinus Torvalds 6719*1da177e4SLinus Torvalds if (checksum != 0) 6720*1da177e4SLinus Torvalds /* failure */ 6721*1da177e4SLinus Torvalds return (1); 6722*1da177e4SLinus Torvalds else 6723*1da177e4SLinus Torvalds /* success */ 6724*1da177e4SLinus Torvalds return (0); 6725*1da177e4SLinus Torvalds } 6726*1da177e4SLinus Torvalds 6727*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 6728*1da177e4SLinus Torvalds /* Routine Name: ips_version_check */ 6729*1da177e4SLinus Torvalds /* */ 6730*1da177e4SLinus Torvalds /* Dependencies: */ 6731*1da177e4SLinus Torvalds /* Assumes that ips_read_adapter_status() is called first filling in */ 6732*1da177e4SLinus Torvalds /* the data for SubSystem Parameters. */ 6733*1da177e4SLinus Torvalds /* Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */ 6734*1da177e4SLinus Torvalds /* Data is available. */ 6735*1da177e4SLinus Torvalds /* */ 6736*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 6737*1da177e4SLinus Torvalds static void 6738*1da177e4SLinus Torvalds ips_version_check(ips_ha_t * ha, int intr) 6739*1da177e4SLinus Torvalds { 6740*1da177e4SLinus Torvalds IPS_VERSION_DATA *VersionInfo; 6741*1da177e4SLinus Torvalds uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1]; 6742*1da177e4SLinus Torvalds uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1]; 6743*1da177e4SLinus Torvalds int MatchError; 6744*1da177e4SLinus Torvalds int rc; 6745*1da177e4SLinus Torvalds char BiosString[10]; 6746*1da177e4SLinus Torvalds char FirmwareString[10]; 6747*1da177e4SLinus Torvalds 6748*1da177e4SLinus Torvalds METHOD_TRACE("ips_version_check", 1); 6749*1da177e4SLinus Torvalds 6750*1da177e4SLinus Torvalds VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data; 6751*1da177e4SLinus Torvalds 6752*1da177e4SLinus Torvalds memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1); 6753*1da177e4SLinus Torvalds memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1); 6754*1da177e4SLinus Torvalds 6755*1da177e4SLinus Torvalds /* Get the Compatible BIOS Version from NVRAM Page 5 */ 6756*1da177e4SLinus Torvalds memcpy(BiosVersion, ha->nvram->BiosCompatibilityID, 6757*1da177e4SLinus Torvalds IPS_COMPAT_ID_LENGTH); 6758*1da177e4SLinus Torvalds 6759*1da177e4SLinus Torvalds rc = IPS_FAILURE; 6760*1da177e4SLinus Torvalds if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) { /* If Versioning is Supported */ 6761*1da177e4SLinus Torvalds /* Get the Version Info with a Get Version Command */ 6762*1da177e4SLinus Torvalds memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA)); 6763*1da177e4SLinus Torvalds rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr); 6764*1da177e4SLinus Torvalds if (rc == IPS_SUCCESS) 6765*1da177e4SLinus Torvalds memcpy(FirmwareVersion, VersionInfo->compatibilityId, 6766*1da177e4SLinus Torvalds IPS_COMPAT_ID_LENGTH); 6767*1da177e4SLinus Torvalds } 6768*1da177e4SLinus Torvalds 6769*1da177e4SLinus Torvalds if (rc != IPS_SUCCESS) { /* If Data Not Obtainable from a GetVersion Command */ 6770*1da177e4SLinus Torvalds /* Get the Firmware Version from Enquiry Data */ 6771*1da177e4SLinus Torvalds memcpy(FirmwareVersion, ha->enq->CodeBlkVersion, 6772*1da177e4SLinus Torvalds IPS_COMPAT_ID_LENGTH); 6773*1da177e4SLinus Torvalds } 6774*1da177e4SLinus Torvalds 6775*1da177e4SLinus Torvalds /* printk(KERN_WARNING "Adapter's BIOS Version = %s\n", BiosVersion); */ 6776*1da177e4SLinus Torvalds /* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS); */ 6777*1da177e4SLinus Torvalds /* printk(KERN_WARNING "Adapter's Firmware Version = %s\n", FirmwareVersion); */ 6778*1da177e4SLinus Torvalds /* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */ 6779*1da177e4SLinus Torvalds 6780*1da177e4SLinus Torvalds MatchError = 0; 6781*1da177e4SLinus Torvalds 6782*1da177e4SLinus Torvalds if (strncmp 6783*1da177e4SLinus Torvalds (FirmwareVersion, Compatable[ha->nvram->adapter_type], 6784*1da177e4SLinus Torvalds IPS_COMPAT_ID_LENGTH) != 0) 6785*1da177e4SLinus Torvalds MatchError = 1; 6786*1da177e4SLinus Torvalds 6787*1da177e4SLinus Torvalds if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0) 6788*1da177e4SLinus Torvalds MatchError = 1; 6789*1da177e4SLinus Torvalds 6790*1da177e4SLinus Torvalds ha->nvram->versioning = 1; /* Indicate the Driver Supports Versioning */ 6791*1da177e4SLinus Torvalds 6792*1da177e4SLinus Torvalds if (MatchError) { 6793*1da177e4SLinus Torvalds ha->nvram->version_mismatch = 1; 6794*1da177e4SLinus Torvalds if (ips_cd_boot == 0) { 6795*1da177e4SLinus Torvalds strncpy(&BiosString[0], ha->nvram->bios_high, 4); 6796*1da177e4SLinus Torvalds strncpy(&BiosString[4], ha->nvram->bios_low, 4); 6797*1da177e4SLinus Torvalds BiosString[8] = 0; 6798*1da177e4SLinus Torvalds 6799*1da177e4SLinus Torvalds strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8); 6800*1da177e4SLinus Torvalds FirmwareString[8] = 0; 6801*1da177e4SLinus Torvalds 6802*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 6803*1da177e4SLinus Torvalds "Warning ! ! ! ServeRAID Version Mismatch\n"); 6804*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 6805*1da177e4SLinus Torvalds "Bios = %s, Firmware = %s, Device Driver = %s%s\n", 6806*1da177e4SLinus Torvalds BiosString, FirmwareString, IPS_VERSION_HIGH, 6807*1da177e4SLinus Torvalds IPS_VERSION_LOW); 6808*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 6809*1da177e4SLinus Torvalds "These levels should match to avoid possible compatibility problems.\n"); 6810*1da177e4SLinus Torvalds } 6811*1da177e4SLinus Torvalds } else { 6812*1da177e4SLinus Torvalds ha->nvram->version_mismatch = 0; 6813*1da177e4SLinus Torvalds } 6814*1da177e4SLinus Torvalds 6815*1da177e4SLinus Torvalds return; 6816*1da177e4SLinus Torvalds } 6817*1da177e4SLinus Torvalds 6818*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 6819*1da177e4SLinus Torvalds /* Routine Name: ips_get_version_info */ 6820*1da177e4SLinus Torvalds /* */ 6821*1da177e4SLinus Torvalds /* Routine Description: */ 6822*1da177e4SLinus Torvalds /* Issue an internal GETVERSION Command */ 6823*1da177e4SLinus Torvalds /* */ 6824*1da177e4SLinus Torvalds /* Return Value: */ 6825*1da177e4SLinus Torvalds /* 0 if Successful, else non-zero */ 6826*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 6827*1da177e4SLinus Torvalds static int 6828*1da177e4SLinus Torvalds ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr) 6829*1da177e4SLinus Torvalds { 6830*1da177e4SLinus Torvalds ips_scb_t *scb; 6831*1da177e4SLinus Torvalds int rc; 6832*1da177e4SLinus Torvalds 6833*1da177e4SLinus Torvalds METHOD_TRACE("ips_get_version_info", 1); 6834*1da177e4SLinus Torvalds 6835*1da177e4SLinus Torvalds scb = &ha->scbs[ha->max_cmds - 1]; 6836*1da177e4SLinus Torvalds 6837*1da177e4SLinus Torvalds ips_init_scb(ha, scb); 6838*1da177e4SLinus Torvalds 6839*1da177e4SLinus Torvalds scb->timeout = ips_cmd_timeout; 6840*1da177e4SLinus Torvalds scb->cdb[0] = IPS_CMD_GET_VERSION_INFO; 6841*1da177e4SLinus Torvalds scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO; 6842*1da177e4SLinus Torvalds scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb); 6843*1da177e4SLinus Torvalds scb->cmd.version_info.reserved = 0; 6844*1da177e4SLinus Torvalds scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA); 6845*1da177e4SLinus Torvalds scb->cmd.version_info.reserved2 = 0; 6846*1da177e4SLinus Torvalds scb->data_len = sizeof (IPS_VERSION_DATA); 6847*1da177e4SLinus Torvalds scb->data_busaddr = Buffer; 6848*1da177e4SLinus Torvalds scb->cmd.version_info.buffer_addr = Buffer; 6849*1da177e4SLinus Torvalds scb->flags = 0; 6850*1da177e4SLinus Torvalds 6851*1da177e4SLinus Torvalds /* issue command */ 6852*1da177e4SLinus Torvalds rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr); 6853*1da177e4SLinus Torvalds return (rc); 6854*1da177e4SLinus Torvalds } 6855*1da177e4SLinus Torvalds 6856*1da177e4SLinus Torvalds /****************************************************************************/ 6857*1da177e4SLinus Torvalds /* */ 6858*1da177e4SLinus Torvalds /* Routine Name: ips_abort_init */ 6859*1da177e4SLinus Torvalds /* */ 6860*1da177e4SLinus Torvalds /* Routine Description: */ 6861*1da177e4SLinus Torvalds /* cleanup routine for a failed adapter initialization */ 6862*1da177e4SLinus Torvalds /****************************************************************************/ 6863*1da177e4SLinus Torvalds static int 6864*1da177e4SLinus Torvalds ips_abort_init(ips_ha_t * ha, int index) 6865*1da177e4SLinus Torvalds { 6866*1da177e4SLinus Torvalds ha->active = 0; 6867*1da177e4SLinus Torvalds ips_free(ha); 6868*1da177e4SLinus Torvalds ips_ha[index] = NULL; 6869*1da177e4SLinus Torvalds ips_sh[index] = NULL; 6870*1da177e4SLinus Torvalds return -1; 6871*1da177e4SLinus Torvalds } 6872*1da177e4SLinus Torvalds 6873*1da177e4SLinus Torvalds /****************************************************************************/ 6874*1da177e4SLinus Torvalds /* */ 6875*1da177e4SLinus Torvalds /* Routine Name: ips_shift_controllers */ 6876*1da177e4SLinus Torvalds /* */ 6877*1da177e4SLinus Torvalds /* Routine Description: */ 6878*1da177e4SLinus Torvalds /* helper function for ordering adapters */ 6879*1da177e4SLinus Torvalds /****************************************************************************/ 6880*1da177e4SLinus Torvalds static void 6881*1da177e4SLinus Torvalds ips_shift_controllers(int lowindex, int highindex) 6882*1da177e4SLinus Torvalds { 6883*1da177e4SLinus Torvalds ips_ha_t *ha_sav = ips_ha[highindex]; 6884*1da177e4SLinus Torvalds struct Scsi_Host *sh_sav = ips_sh[highindex]; 6885*1da177e4SLinus Torvalds int i; 6886*1da177e4SLinus Torvalds 6887*1da177e4SLinus Torvalds for (i = highindex; i > lowindex; i--) { 6888*1da177e4SLinus Torvalds ips_ha[i] = ips_ha[i - 1]; 6889*1da177e4SLinus Torvalds ips_sh[i] = ips_sh[i - 1]; 6890*1da177e4SLinus Torvalds ips_ha[i]->host_num = i; 6891*1da177e4SLinus Torvalds } 6892*1da177e4SLinus Torvalds ha_sav->host_num = lowindex; 6893*1da177e4SLinus Torvalds ips_ha[lowindex] = ha_sav; 6894*1da177e4SLinus Torvalds ips_sh[lowindex] = sh_sav; 6895*1da177e4SLinus Torvalds } 6896*1da177e4SLinus Torvalds 6897*1da177e4SLinus Torvalds /****************************************************************************/ 6898*1da177e4SLinus Torvalds /* */ 6899*1da177e4SLinus Torvalds /* Routine Name: ips_order_controllers */ 6900*1da177e4SLinus Torvalds /* */ 6901*1da177e4SLinus Torvalds /* Routine Description: */ 6902*1da177e4SLinus Torvalds /* place controllers is the "proper" boot order */ 6903*1da177e4SLinus Torvalds /****************************************************************************/ 6904*1da177e4SLinus Torvalds static void 6905*1da177e4SLinus Torvalds ips_order_controllers(void) 6906*1da177e4SLinus Torvalds { 6907*1da177e4SLinus Torvalds int i, j, tmp, position = 0; 6908*1da177e4SLinus Torvalds IPS_NVRAM_P5 *nvram; 6909*1da177e4SLinus Torvalds if (!ips_ha[0]) 6910*1da177e4SLinus Torvalds return; 6911*1da177e4SLinus Torvalds nvram = ips_ha[0]->nvram; 6912*1da177e4SLinus Torvalds 6913*1da177e4SLinus Torvalds if (nvram->adapter_order[0]) { 6914*1da177e4SLinus Torvalds for (i = 1; i <= nvram->adapter_order[0]; i++) { 6915*1da177e4SLinus Torvalds for (j = position; j < ips_num_controllers; j++) { 6916*1da177e4SLinus Torvalds switch (ips_ha[j]->ad_type) { 6917*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID6M: 6918*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID7M: 6919*1da177e4SLinus Torvalds if (nvram->adapter_order[i] == 'M') { 6920*1da177e4SLinus Torvalds ips_shift_controllers(position, 6921*1da177e4SLinus Torvalds j); 6922*1da177e4SLinus Torvalds position++; 6923*1da177e4SLinus Torvalds } 6924*1da177e4SLinus Torvalds break; 6925*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID4L: 6926*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID4M: 6927*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID4MX: 6928*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID4LX: 6929*1da177e4SLinus Torvalds if (nvram->adapter_order[i] == 'N') { 6930*1da177e4SLinus Torvalds ips_shift_controllers(position, 6931*1da177e4SLinus Torvalds j); 6932*1da177e4SLinus Torvalds position++; 6933*1da177e4SLinus Torvalds } 6934*1da177e4SLinus Torvalds break; 6935*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID6I: 6936*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID5I2: 6937*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID5I1: 6938*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID7k: 6939*1da177e4SLinus Torvalds if (nvram->adapter_order[i] == 'S') { 6940*1da177e4SLinus Torvalds ips_shift_controllers(position, 6941*1da177e4SLinus Torvalds j); 6942*1da177e4SLinus Torvalds position++; 6943*1da177e4SLinus Torvalds } 6944*1da177e4SLinus Torvalds break; 6945*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID: 6946*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID2: 6947*1da177e4SLinus Torvalds case IPS_ADTYPE_NAVAJO: 6948*1da177e4SLinus Torvalds case IPS_ADTYPE_KIOWA: 6949*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID3L: 6950*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID3: 6951*1da177e4SLinus Torvalds case IPS_ADTYPE_SERVERAID4H: 6952*1da177e4SLinus Torvalds if (nvram->adapter_order[i] == 'A') { 6953*1da177e4SLinus Torvalds ips_shift_controllers(position, 6954*1da177e4SLinus Torvalds j); 6955*1da177e4SLinus Torvalds position++; 6956*1da177e4SLinus Torvalds } 6957*1da177e4SLinus Torvalds break; 6958*1da177e4SLinus Torvalds default: 6959*1da177e4SLinus Torvalds break; 6960*1da177e4SLinus Torvalds } 6961*1da177e4SLinus Torvalds } 6962*1da177e4SLinus Torvalds } 6963*1da177e4SLinus Torvalds /* if adapter_order[0], then ordering is complete */ 6964*1da177e4SLinus Torvalds return; 6965*1da177e4SLinus Torvalds } 6966*1da177e4SLinus Torvalds /* old bios, use older ordering */ 6967*1da177e4SLinus Torvalds tmp = 0; 6968*1da177e4SLinus Torvalds for (i = position; i < ips_num_controllers; i++) { 6969*1da177e4SLinus Torvalds if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 || 6970*1da177e4SLinus Torvalds ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) { 6971*1da177e4SLinus Torvalds ips_shift_controllers(position, i); 6972*1da177e4SLinus Torvalds position++; 6973*1da177e4SLinus Torvalds tmp = 1; 6974*1da177e4SLinus Torvalds } 6975*1da177e4SLinus Torvalds } 6976*1da177e4SLinus Torvalds /* if there were no 5I cards, then don't do any extra ordering */ 6977*1da177e4SLinus Torvalds if (!tmp) 6978*1da177e4SLinus Torvalds return; 6979*1da177e4SLinus Torvalds for (i = position; i < ips_num_controllers; i++) { 6980*1da177e4SLinus Torvalds if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L || 6981*1da177e4SLinus Torvalds ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M || 6982*1da177e4SLinus Torvalds ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX || 6983*1da177e4SLinus Torvalds ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) { 6984*1da177e4SLinus Torvalds ips_shift_controllers(position, i); 6985*1da177e4SLinus Torvalds position++; 6986*1da177e4SLinus Torvalds } 6987*1da177e4SLinus Torvalds } 6988*1da177e4SLinus Torvalds 6989*1da177e4SLinus Torvalds return; 6990*1da177e4SLinus Torvalds } 6991*1da177e4SLinus Torvalds 6992*1da177e4SLinus Torvalds /****************************************************************************/ 6993*1da177e4SLinus Torvalds /* */ 6994*1da177e4SLinus Torvalds /* Routine Name: ips_register_scsi */ 6995*1da177e4SLinus Torvalds /* */ 6996*1da177e4SLinus Torvalds /* Routine Description: */ 6997*1da177e4SLinus Torvalds /* perform any registration and setup with the scsi layer */ 6998*1da177e4SLinus Torvalds /****************************************************************************/ 6999*1da177e4SLinus Torvalds static int 7000*1da177e4SLinus Torvalds ips_register_scsi(int index) 7001*1da177e4SLinus Torvalds { 7002*1da177e4SLinus Torvalds struct Scsi_Host *sh; 7003*1da177e4SLinus Torvalds ips_ha_t *ha, *oldha = ips_ha[index]; 7004*1da177e4SLinus Torvalds sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t)); 7005*1da177e4SLinus Torvalds if (!sh) { 7006*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, oldha->pcidev, 7007*1da177e4SLinus Torvalds "Unable to register controller with SCSI subsystem\n"); 7008*1da177e4SLinus Torvalds return -1; 7009*1da177e4SLinus Torvalds } 7010*1da177e4SLinus Torvalds ha = IPS_HA(sh); 7011*1da177e4SLinus Torvalds memcpy(ha, oldha, sizeof (ips_ha_t)); 7012*1da177e4SLinus Torvalds free_irq(oldha->irq, oldha); 7013*1da177e4SLinus Torvalds /* Install the interrupt handler with the new ha */ 7014*1da177e4SLinus Torvalds if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { 7015*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 7016*1da177e4SLinus Torvalds "Unable to install interrupt handler\n"); 7017*1da177e4SLinus Torvalds scsi_host_put(sh); 7018*1da177e4SLinus Torvalds return -1; 7019*1da177e4SLinus Torvalds } 7020*1da177e4SLinus Torvalds 7021*1da177e4SLinus Torvalds kfree(oldha); 7022*1da177e4SLinus Torvalds ips_sh[index] = sh; 7023*1da177e4SLinus Torvalds ips_ha[index] = ha; 7024*1da177e4SLinus Torvalds IPS_SCSI_SET_DEVICE(sh, ha); 7025*1da177e4SLinus Torvalds 7026*1da177e4SLinus Torvalds /* Store away needed values for later use */ 7027*1da177e4SLinus Torvalds sh->io_port = ha->io_addr; 7028*1da177e4SLinus Torvalds sh->n_io_port = ha->io_addr ? 255 : 0; 7029*1da177e4SLinus Torvalds sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; 7030*1da177e4SLinus Torvalds sh->irq = ha->irq; 7031*1da177e4SLinus Torvalds sh->sg_tablesize = sh->hostt->sg_tablesize; 7032*1da177e4SLinus Torvalds sh->can_queue = sh->hostt->can_queue; 7033*1da177e4SLinus Torvalds sh->cmd_per_lun = sh->hostt->cmd_per_lun; 7034*1da177e4SLinus Torvalds sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; 7035*1da177e4SLinus Torvalds sh->use_clustering = sh->hostt->use_clustering; 7036*1da177e4SLinus Torvalds 7037*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) 7038*1da177e4SLinus Torvalds sh->max_sectors = 128; 7039*1da177e4SLinus Torvalds #endif 7040*1da177e4SLinus Torvalds 7041*1da177e4SLinus Torvalds sh->max_id = ha->ntargets; 7042*1da177e4SLinus Torvalds sh->max_lun = ha->nlun; 7043*1da177e4SLinus Torvalds sh->max_channel = ha->nbus - 1; 7044*1da177e4SLinus Torvalds sh->can_queue = ha->max_cmds - 1; 7045*1da177e4SLinus Torvalds 7046*1da177e4SLinus Torvalds IPS_ADD_HOST(sh, NULL); 7047*1da177e4SLinus Torvalds return 0; 7048*1da177e4SLinus Torvalds } 7049*1da177e4SLinus Torvalds 7050*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7051*1da177e4SLinus Torvalds /* Routine Name: ips_remove_device */ 7052*1da177e4SLinus Torvalds /* */ 7053*1da177e4SLinus Torvalds /* Routine Description: */ 7054*1da177e4SLinus Torvalds /* Remove one Adapter ( Hot Plugging ) */ 7055*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7056*1da177e4SLinus Torvalds static void __devexit 7057*1da177e4SLinus Torvalds ips_remove_device(struct pci_dev *pci_dev) 7058*1da177e4SLinus Torvalds { 7059*1da177e4SLinus Torvalds int i; 7060*1da177e4SLinus Torvalds struct Scsi_Host *sh; 7061*1da177e4SLinus Torvalds ips_ha_t *ha; 7062*1da177e4SLinus Torvalds 7063*1da177e4SLinus Torvalds for (i = 0; i < IPS_MAX_ADAPTERS; i++) { 7064*1da177e4SLinus Torvalds ha = ips_ha[i]; 7065*1da177e4SLinus Torvalds if (ha) { 7066*1da177e4SLinus Torvalds if ((pci_dev->bus->number == ha->pcidev->bus->number) && 7067*1da177e4SLinus Torvalds (pci_dev->devfn == ha->pcidev->devfn)) { 7068*1da177e4SLinus Torvalds sh = ips_sh[i]; 7069*1da177e4SLinus Torvalds ips_release(sh); 7070*1da177e4SLinus Torvalds } 7071*1da177e4SLinus Torvalds } 7072*1da177e4SLinus Torvalds } 7073*1da177e4SLinus Torvalds } 7074*1da177e4SLinus Torvalds 7075*1da177e4SLinus Torvalds /****************************************************************************/ 7076*1da177e4SLinus Torvalds /* */ 7077*1da177e4SLinus Torvalds /* Routine Name: ips_module_init */ 7078*1da177e4SLinus Torvalds /* */ 7079*1da177e4SLinus Torvalds /* Routine Description: */ 7080*1da177e4SLinus Torvalds /* function called on module load */ 7081*1da177e4SLinus Torvalds /****************************************************************************/ 7082*1da177e4SLinus Torvalds static int __init 7083*1da177e4SLinus Torvalds ips_module_init(void) 7084*1da177e4SLinus Torvalds { 7085*1da177e4SLinus Torvalds if (pci_module_init(&ips_pci_driver) < 0) 7086*1da177e4SLinus Torvalds return -ENODEV; 7087*1da177e4SLinus Torvalds ips_driver_template.module = THIS_MODULE; 7088*1da177e4SLinus Torvalds ips_order_controllers(); 7089*1da177e4SLinus Torvalds if (IPS_REGISTER_HOSTS(&ips_driver_template)) { 7090*1da177e4SLinus Torvalds pci_unregister_driver(&ips_pci_driver); 7091*1da177e4SLinus Torvalds return -ENODEV; 7092*1da177e4SLinus Torvalds } 7093*1da177e4SLinus Torvalds register_reboot_notifier(&ips_notifier); 7094*1da177e4SLinus Torvalds return 0; 7095*1da177e4SLinus Torvalds } 7096*1da177e4SLinus Torvalds 7097*1da177e4SLinus Torvalds /****************************************************************************/ 7098*1da177e4SLinus Torvalds /* */ 7099*1da177e4SLinus Torvalds /* Routine Name: ips_module_exit */ 7100*1da177e4SLinus Torvalds /* */ 7101*1da177e4SLinus Torvalds /* Routine Description: */ 7102*1da177e4SLinus Torvalds /* function called on module unload */ 7103*1da177e4SLinus Torvalds /****************************************************************************/ 7104*1da177e4SLinus Torvalds static void __exit 7105*1da177e4SLinus Torvalds ips_module_exit(void) 7106*1da177e4SLinus Torvalds { 7107*1da177e4SLinus Torvalds IPS_UNREGISTER_HOSTS(&ips_driver_template); 7108*1da177e4SLinus Torvalds pci_unregister_driver(&ips_pci_driver); 7109*1da177e4SLinus Torvalds unregister_reboot_notifier(&ips_notifier); 7110*1da177e4SLinus Torvalds } 7111*1da177e4SLinus Torvalds 7112*1da177e4SLinus Torvalds module_init(ips_module_init); 7113*1da177e4SLinus Torvalds module_exit(ips_module_exit); 7114*1da177e4SLinus Torvalds 7115*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7116*1da177e4SLinus Torvalds /* Routine Name: ips_insert_device */ 7117*1da177e4SLinus Torvalds /* */ 7118*1da177e4SLinus Torvalds /* Routine Description: */ 7119*1da177e4SLinus Torvalds /* Add One Adapter ( Hot Plug ) */ 7120*1da177e4SLinus Torvalds /* */ 7121*1da177e4SLinus Torvalds /* Return Value: */ 7122*1da177e4SLinus Torvalds /* 0 if Successful, else non-zero */ 7123*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7124*1da177e4SLinus Torvalds static int __devinit 7125*1da177e4SLinus Torvalds ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) 7126*1da177e4SLinus Torvalds { 7127*1da177e4SLinus Torvalds int index; 7128*1da177e4SLinus Torvalds int rc; 7129*1da177e4SLinus Torvalds 7130*1da177e4SLinus Torvalds METHOD_TRACE("ips_insert_device", 1); 7131*1da177e4SLinus Torvalds if (pci_enable_device(pci_dev)) 7132*1da177e4SLinus Torvalds return -1; 7133*1da177e4SLinus Torvalds 7134*1da177e4SLinus Torvalds rc = ips_init_phase1(pci_dev, &index); 7135*1da177e4SLinus Torvalds if (rc == SUCCESS) 7136*1da177e4SLinus Torvalds rc = ips_init_phase2(index); 7137*1da177e4SLinus Torvalds 7138*1da177e4SLinus Torvalds if (ips_hotplug) 7139*1da177e4SLinus Torvalds if (ips_register_scsi(index)) { 7140*1da177e4SLinus Torvalds ips_free(ips_ha[index]); 7141*1da177e4SLinus Torvalds rc = -1; 7142*1da177e4SLinus Torvalds } 7143*1da177e4SLinus Torvalds 7144*1da177e4SLinus Torvalds if (rc == SUCCESS) 7145*1da177e4SLinus Torvalds ips_num_controllers++; 7146*1da177e4SLinus Torvalds 7147*1da177e4SLinus Torvalds ips_next_controller = ips_num_controllers; 7148*1da177e4SLinus Torvalds return rc; 7149*1da177e4SLinus Torvalds } 7150*1da177e4SLinus Torvalds 7151*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7152*1da177e4SLinus Torvalds /* Routine Name: ips_init_phase1 */ 7153*1da177e4SLinus Torvalds /* */ 7154*1da177e4SLinus Torvalds /* Routine Description: */ 7155*1da177e4SLinus Torvalds /* Adapter Initialization */ 7156*1da177e4SLinus Torvalds /* */ 7157*1da177e4SLinus Torvalds /* Return Value: */ 7158*1da177e4SLinus Torvalds /* 0 if Successful, else non-zero */ 7159*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7160*1da177e4SLinus Torvalds static int 7161*1da177e4SLinus Torvalds ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) 7162*1da177e4SLinus Torvalds { 7163*1da177e4SLinus Torvalds ips_ha_t *ha; 7164*1da177e4SLinus Torvalds uint32_t io_addr; 7165*1da177e4SLinus Torvalds uint32_t mem_addr; 7166*1da177e4SLinus Torvalds uint32_t io_len; 7167*1da177e4SLinus Torvalds uint32_t mem_len; 7168*1da177e4SLinus Torvalds uint8_t revision_id; 7169*1da177e4SLinus Torvalds uint8_t bus; 7170*1da177e4SLinus Torvalds uint8_t func; 7171*1da177e4SLinus Torvalds uint8_t irq; 7172*1da177e4SLinus Torvalds uint16_t subdevice_id; 7173*1da177e4SLinus Torvalds int j; 7174*1da177e4SLinus Torvalds int index; 7175*1da177e4SLinus Torvalds dma_addr_t dma_address; 7176*1da177e4SLinus Torvalds char __iomem *ioremap_ptr; 7177*1da177e4SLinus Torvalds char __iomem *mem_ptr; 7178*1da177e4SLinus Torvalds uint32_t IsDead; 7179*1da177e4SLinus Torvalds 7180*1da177e4SLinus Torvalds METHOD_TRACE("ips_init_phase1", 1); 7181*1da177e4SLinus Torvalds index = IPS_MAX_ADAPTERS; 7182*1da177e4SLinus Torvalds for (j = 0; j < IPS_MAX_ADAPTERS; j++) { 7183*1da177e4SLinus Torvalds if (ips_ha[j] == 0) { 7184*1da177e4SLinus Torvalds index = j; 7185*1da177e4SLinus Torvalds break; 7186*1da177e4SLinus Torvalds } 7187*1da177e4SLinus Torvalds } 7188*1da177e4SLinus Torvalds 7189*1da177e4SLinus Torvalds if (index >= IPS_MAX_ADAPTERS) 7190*1da177e4SLinus Torvalds return -1; 7191*1da177e4SLinus Torvalds 7192*1da177e4SLinus Torvalds /* stuff that we get in dev */ 7193*1da177e4SLinus Torvalds irq = pci_dev->irq; 7194*1da177e4SLinus Torvalds bus = pci_dev->bus->number; 7195*1da177e4SLinus Torvalds func = pci_dev->devfn; 7196*1da177e4SLinus Torvalds 7197*1da177e4SLinus Torvalds /* Init MEM/IO addresses to 0 */ 7198*1da177e4SLinus Torvalds mem_addr = 0; 7199*1da177e4SLinus Torvalds io_addr = 0; 7200*1da177e4SLinus Torvalds mem_len = 0; 7201*1da177e4SLinus Torvalds io_len = 0; 7202*1da177e4SLinus Torvalds 7203*1da177e4SLinus Torvalds for (j = 0; j < 2; j++) { 7204*1da177e4SLinus Torvalds if (!pci_resource_start(pci_dev, j)) 7205*1da177e4SLinus Torvalds break; 7206*1da177e4SLinus Torvalds 7207*1da177e4SLinus Torvalds if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) { 7208*1da177e4SLinus Torvalds io_addr = pci_resource_start(pci_dev, j); 7209*1da177e4SLinus Torvalds io_len = pci_resource_len(pci_dev, j); 7210*1da177e4SLinus Torvalds } else { 7211*1da177e4SLinus Torvalds mem_addr = pci_resource_start(pci_dev, j); 7212*1da177e4SLinus Torvalds mem_len = pci_resource_len(pci_dev, j); 7213*1da177e4SLinus Torvalds } 7214*1da177e4SLinus Torvalds } 7215*1da177e4SLinus Torvalds 7216*1da177e4SLinus Torvalds /* setup memory mapped area (if applicable) */ 7217*1da177e4SLinus Torvalds if (mem_addr) { 7218*1da177e4SLinus Torvalds uint32_t base; 7219*1da177e4SLinus Torvalds uint32_t offs; 7220*1da177e4SLinus Torvalds 7221*1da177e4SLinus Torvalds if (!request_mem_region(mem_addr, mem_len, "ips")) { 7222*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7223*1da177e4SLinus Torvalds "Couldn't allocate IO Memory space %x len %d.\n", 7224*1da177e4SLinus Torvalds mem_addr, mem_len); 7225*1da177e4SLinus Torvalds return -1; 7226*1da177e4SLinus Torvalds } 7227*1da177e4SLinus Torvalds 7228*1da177e4SLinus Torvalds base = mem_addr & PAGE_MASK; 7229*1da177e4SLinus Torvalds offs = mem_addr - base; 7230*1da177e4SLinus Torvalds ioremap_ptr = ioremap(base, PAGE_SIZE); 7231*1da177e4SLinus Torvalds mem_ptr = ioremap_ptr + offs; 7232*1da177e4SLinus Torvalds } else { 7233*1da177e4SLinus Torvalds ioremap_ptr = NULL; 7234*1da177e4SLinus Torvalds mem_ptr = NULL; 7235*1da177e4SLinus Torvalds } 7236*1da177e4SLinus Torvalds 7237*1da177e4SLinus Torvalds /* setup I/O mapped area (if applicable) */ 7238*1da177e4SLinus Torvalds if (io_addr) { 7239*1da177e4SLinus Torvalds if (!request_region(io_addr, io_len, "ips")) { 7240*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7241*1da177e4SLinus Torvalds "Couldn't allocate IO space %x len %d.\n", 7242*1da177e4SLinus Torvalds io_addr, io_len); 7243*1da177e4SLinus Torvalds return -1; 7244*1da177e4SLinus Torvalds } 7245*1da177e4SLinus Torvalds } 7246*1da177e4SLinus Torvalds 7247*1da177e4SLinus Torvalds /* get the revision ID */ 7248*1da177e4SLinus Torvalds if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) { 7249*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n"); 7250*1da177e4SLinus Torvalds return -1; 7251*1da177e4SLinus Torvalds } 7252*1da177e4SLinus Torvalds 7253*1da177e4SLinus Torvalds subdevice_id = pci_dev->subsystem_device; 7254*1da177e4SLinus Torvalds 7255*1da177e4SLinus Torvalds /* found a controller */ 7256*1da177e4SLinus Torvalds ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL); 7257*1da177e4SLinus Torvalds if (ha == NULL) { 7258*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7259*1da177e4SLinus Torvalds "Unable to allocate temporary ha struct\n"); 7260*1da177e4SLinus Torvalds return -1; 7261*1da177e4SLinus Torvalds } 7262*1da177e4SLinus Torvalds 7263*1da177e4SLinus Torvalds memset(ha, 0, sizeof (ips_ha_t)); 7264*1da177e4SLinus Torvalds 7265*1da177e4SLinus Torvalds ips_sh[index] = NULL; 7266*1da177e4SLinus Torvalds ips_ha[index] = ha; 7267*1da177e4SLinus Torvalds ha->active = 1; 7268*1da177e4SLinus Torvalds 7269*1da177e4SLinus Torvalds /* Store info in HA structure */ 7270*1da177e4SLinus Torvalds ha->irq = irq; 7271*1da177e4SLinus Torvalds ha->io_addr = io_addr; 7272*1da177e4SLinus Torvalds ha->io_len = io_len; 7273*1da177e4SLinus Torvalds ha->mem_addr = mem_addr; 7274*1da177e4SLinus Torvalds ha->mem_len = mem_len; 7275*1da177e4SLinus Torvalds ha->mem_ptr = mem_ptr; 7276*1da177e4SLinus Torvalds ha->ioremap_ptr = ioremap_ptr; 7277*1da177e4SLinus Torvalds ha->host_num = (uint32_t) index; 7278*1da177e4SLinus Torvalds ha->revision_id = revision_id; 7279*1da177e4SLinus Torvalds ha->slot_num = PCI_SLOT(pci_dev->devfn); 7280*1da177e4SLinus Torvalds ha->device_id = pci_dev->device; 7281*1da177e4SLinus Torvalds ha->subdevice_id = subdevice_id; 7282*1da177e4SLinus Torvalds ha->pcidev = pci_dev; 7283*1da177e4SLinus Torvalds 7284*1da177e4SLinus Torvalds /* 7285*1da177e4SLinus Torvalds * Set the pci_dev's dma_mask. Not all adapters support 64bit 7286*1da177e4SLinus Torvalds * addressing so don't enable it if the adapter can't support 7287*1da177e4SLinus Torvalds * it! Also, don't use 64bit addressing if dma addresses 7288*1da177e4SLinus Torvalds * are guaranteed to be < 4G. 7289*1da177e4SLinus Torvalds */ 7290*1da177e4SLinus Torvalds if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) && 7291*1da177e4SLinus Torvalds !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) { 7292*1da177e4SLinus Torvalds (ha)->flags |= IPS_HA_ENH_SG; 7293*1da177e4SLinus Torvalds } else { 7294*1da177e4SLinus Torvalds if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) { 7295*1da177e4SLinus Torvalds printk(KERN_WARNING "Unable to set DMA Mask\n"); 7296*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7297*1da177e4SLinus Torvalds } 7298*1da177e4SLinus Torvalds } 7299*1da177e4SLinus Torvalds if(ips_cd_boot && !ips_FlashData){ 7300*1da177e4SLinus Torvalds ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7, 7301*1da177e4SLinus Torvalds &ips_flashbusaddr); 7302*1da177e4SLinus Torvalds } 7303*1da177e4SLinus Torvalds 7304*1da177e4SLinus Torvalds ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ), 7305*1da177e4SLinus Torvalds &ha->enq_busaddr); 7306*1da177e4SLinus Torvalds if (!ha->enq) { 7307*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7308*1da177e4SLinus Torvalds "Unable to allocate host inquiry structure\n"); 7309*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7310*1da177e4SLinus Torvalds } 7311*1da177e4SLinus Torvalds 7312*1da177e4SLinus Torvalds ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) + 7313*1da177e4SLinus Torvalds sizeof (IPS_IO_CMD), &dma_address); 7314*1da177e4SLinus Torvalds if (!ha->adapt) { 7315*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7316*1da177e4SLinus Torvalds "Unable to allocate host adapt & dummy structures\n"); 7317*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7318*1da177e4SLinus Torvalds } 7319*1da177e4SLinus Torvalds ha->adapt->hw_status_start = dma_address; 7320*1da177e4SLinus Torvalds ha->dummy = (void *) (ha->adapt + 1); 7321*1da177e4SLinus Torvalds 7322*1da177e4SLinus Torvalds 7323*1da177e4SLinus Torvalds 7324*1da177e4SLinus Torvalds ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address); 7325*1da177e4SLinus Torvalds if (!ha->logical_drive_info) { 7326*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7327*1da177e4SLinus Torvalds "Unable to allocate logical drive info structure\n"); 7328*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7329*1da177e4SLinus Torvalds } 7330*1da177e4SLinus Torvalds ha->logical_drive_info_dma_addr = dma_address; 7331*1da177e4SLinus Torvalds 7332*1da177e4SLinus Torvalds 7333*1da177e4SLinus Torvalds ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL); 7334*1da177e4SLinus Torvalds 7335*1da177e4SLinus Torvalds if (!ha->conf) { 7336*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7337*1da177e4SLinus Torvalds "Unable to allocate host conf structure\n"); 7338*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7339*1da177e4SLinus Torvalds } 7340*1da177e4SLinus Torvalds 7341*1da177e4SLinus Torvalds ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL); 7342*1da177e4SLinus Torvalds 7343*1da177e4SLinus Torvalds if (!ha->nvram) { 7344*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7345*1da177e4SLinus Torvalds "Unable to allocate host NVRAM structure\n"); 7346*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7347*1da177e4SLinus Torvalds } 7348*1da177e4SLinus Torvalds 7349*1da177e4SLinus Torvalds ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL); 7350*1da177e4SLinus Torvalds 7351*1da177e4SLinus Torvalds if (!ha->subsys) { 7352*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7353*1da177e4SLinus Torvalds "Unable to allocate host subsystem structure\n"); 7354*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7355*1da177e4SLinus Torvalds } 7356*1da177e4SLinus Torvalds 7357*1da177e4SLinus Torvalds /* the ioctl buffer is now used during adapter initialization, so its 7358*1da177e4SLinus Torvalds * successful allocation is now required */ 7359*1da177e4SLinus Torvalds if (ips_ioctlsize < PAGE_SIZE) 7360*1da177e4SLinus Torvalds ips_ioctlsize = PAGE_SIZE; 7361*1da177e4SLinus Torvalds 7362*1da177e4SLinus Torvalds ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize, 7363*1da177e4SLinus Torvalds &ha->ioctl_busaddr); 7364*1da177e4SLinus Torvalds ha->ioctl_len = ips_ioctlsize; 7365*1da177e4SLinus Torvalds if (!ha->ioctl_data) { 7366*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7367*1da177e4SLinus Torvalds "Unable to allocate IOCTL data\n"); 7368*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7369*1da177e4SLinus Torvalds } 7370*1da177e4SLinus Torvalds 7371*1da177e4SLinus Torvalds /* 7372*1da177e4SLinus Torvalds * Setup Functions 7373*1da177e4SLinus Torvalds */ 7374*1da177e4SLinus Torvalds ips_setup_funclist(ha); 7375*1da177e4SLinus Torvalds 7376*1da177e4SLinus Torvalds if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) { 7377*1da177e4SLinus Torvalds /* If Morpheus appears dead, reset it */ 7378*1da177e4SLinus Torvalds IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1); 7379*1da177e4SLinus Torvalds if (IsDead == 0xDEADBEEF) { 7380*1da177e4SLinus Torvalds ips_reset_morpheus(ha); 7381*1da177e4SLinus Torvalds } 7382*1da177e4SLinus Torvalds } 7383*1da177e4SLinus Torvalds 7384*1da177e4SLinus Torvalds /* 7385*1da177e4SLinus Torvalds * Initialize the card if it isn't already 7386*1da177e4SLinus Torvalds */ 7387*1da177e4SLinus Torvalds 7388*1da177e4SLinus Torvalds if (!(*ha->func.isinit) (ha)) { 7389*1da177e4SLinus Torvalds if (!(*ha->func.init) (ha)) { 7390*1da177e4SLinus Torvalds /* 7391*1da177e4SLinus Torvalds * Initialization failed 7392*1da177e4SLinus Torvalds */ 7393*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, pci_dev, 7394*1da177e4SLinus Torvalds "Unable to initialize controller\n"); 7395*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7396*1da177e4SLinus Torvalds } 7397*1da177e4SLinus Torvalds } 7398*1da177e4SLinus Torvalds 7399*1da177e4SLinus Torvalds *indexPtr = index; 7400*1da177e4SLinus Torvalds return SUCCESS; 7401*1da177e4SLinus Torvalds } 7402*1da177e4SLinus Torvalds 7403*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7404*1da177e4SLinus Torvalds /* Routine Name: ips_init_phase2 */ 7405*1da177e4SLinus Torvalds /* */ 7406*1da177e4SLinus Torvalds /* Routine Description: */ 7407*1da177e4SLinus Torvalds /* Adapter Initialization Phase 2 */ 7408*1da177e4SLinus Torvalds /* */ 7409*1da177e4SLinus Torvalds /* Return Value: */ 7410*1da177e4SLinus Torvalds /* 0 if Successful, else non-zero */ 7411*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/ 7412*1da177e4SLinus Torvalds static int 7413*1da177e4SLinus Torvalds ips_init_phase2(int index) 7414*1da177e4SLinus Torvalds { 7415*1da177e4SLinus Torvalds ips_ha_t *ha; 7416*1da177e4SLinus Torvalds 7417*1da177e4SLinus Torvalds ha = ips_ha[index]; 7418*1da177e4SLinus Torvalds 7419*1da177e4SLinus Torvalds METHOD_TRACE("ips_init_phase2", 1); 7420*1da177e4SLinus Torvalds if (!ha->active) { 7421*1da177e4SLinus Torvalds ips_ha[index] = NULL; 7422*1da177e4SLinus Torvalds return -1; 7423*1da177e4SLinus Torvalds } 7424*1da177e4SLinus Torvalds 7425*1da177e4SLinus Torvalds /* Install the interrupt handler */ 7426*1da177e4SLinus Torvalds if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { 7427*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 7428*1da177e4SLinus Torvalds "Unable to install interrupt handler\n"); 7429*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7430*1da177e4SLinus Torvalds } 7431*1da177e4SLinus Torvalds 7432*1da177e4SLinus Torvalds /* 7433*1da177e4SLinus Torvalds * Allocate a temporary SCB for initialization 7434*1da177e4SLinus Torvalds */ 7435*1da177e4SLinus Torvalds ha->max_cmds = 1; 7436*1da177e4SLinus Torvalds if (!ips_allocatescbs(ha)) { 7437*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 7438*1da177e4SLinus Torvalds "Unable to allocate a CCB\n"); 7439*1da177e4SLinus Torvalds free_irq(ha->irq, ha); 7440*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7441*1da177e4SLinus Torvalds } 7442*1da177e4SLinus Torvalds 7443*1da177e4SLinus Torvalds if (!ips_hainit(ha)) { 7444*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 7445*1da177e4SLinus Torvalds "Unable to initialize controller\n"); 7446*1da177e4SLinus Torvalds free_irq(ha->irq, ha); 7447*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7448*1da177e4SLinus Torvalds } 7449*1da177e4SLinus Torvalds /* Free the temporary SCB */ 7450*1da177e4SLinus Torvalds ips_deallocatescbs(ha, 1); 7451*1da177e4SLinus Torvalds 7452*1da177e4SLinus Torvalds /* allocate CCBs */ 7453*1da177e4SLinus Torvalds if (!ips_allocatescbs(ha)) { 7454*1da177e4SLinus Torvalds IPS_PRINTK(KERN_WARNING, ha->pcidev, 7455*1da177e4SLinus Torvalds "Unable to allocate CCBs\n"); 7456*1da177e4SLinus Torvalds free_irq(ha->irq, ha); 7457*1da177e4SLinus Torvalds return ips_abort_init(ha, index); 7458*1da177e4SLinus Torvalds } 7459*1da177e4SLinus Torvalds 7460*1da177e4SLinus Torvalds return SUCCESS; 7461*1da177e4SLinus Torvalds } 7462*1da177e4SLinus Torvalds 7463*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9) 7464*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 7465*1da177e4SLinus Torvalds #endif 7466*1da177e4SLinus Torvalds 7467*1da177e4SLinus Torvalds MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING); 7468*1da177e4SLinus Torvalds 7469*1da177e4SLinus Torvalds #ifdef MODULE_VERSION 7470*1da177e4SLinus Torvalds MODULE_VERSION(IPS_VER_STRING); 7471*1da177e4SLinus Torvalds #endif 7472*1da177e4SLinus Torvalds 7473*1da177e4SLinus Torvalds 7474*1da177e4SLinus Torvalds /* 7475*1da177e4SLinus Torvalds * Overrides for Emacs so that we almost follow Linus's tabbing style. 7476*1da177e4SLinus Torvalds * Emacs will notice this stuff at the end of the file and automatically 7477*1da177e4SLinus Torvalds * adjust the settings for this buffer only. This must remain at the end 7478*1da177e4SLinus Torvalds * of the file. 7479*1da177e4SLinus Torvalds * --------------------------------------------------------------------------- 7480*1da177e4SLinus Torvalds * Local variables: 7481*1da177e4SLinus Torvalds * c-indent-level: 2 7482*1da177e4SLinus Torvalds * c-brace-imaginary-offset: 0 7483*1da177e4SLinus Torvalds * c-brace-offset: -2 7484*1da177e4SLinus Torvalds * c-argdecl-indent: 2 7485*1da177e4SLinus Torvalds * c-label-offset: -2 7486*1da177e4SLinus Torvalds * c-continued-statement-offset: 2 7487*1da177e4SLinus Torvalds * c-continued-brace-offset: 0 7488*1da177e4SLinus Torvalds * indent-tabs-mode: nil 7489*1da177e4SLinus Torvalds * tab-width: 8 7490*1da177e4SLinus Torvalds * End: 7491*1da177e4SLinus Torvalds */ 7492