| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /*****************************************************************************/ | 
|  | 2 | /* ips.c -- driver for the Adaptec / IBM ServeRAID controller                */ | 
|  | 3 | /*                                                                           */ | 
|  | 4 | /* Written By: Keith Mitchell, IBM Corporation                               */ | 
|  | 5 | /*             Jack Hammer, Adaptec, Inc.                                    */ | 
|  | 6 | /*             David Jeffery, Adaptec, Inc.                                  */ | 
|  | 7 | /*                                                                           */ | 
|  | 8 | /* Copyright (C) 2000 IBM Corporation                                        */ | 
|  | 9 | /* Copyright (C) 2002,2003 Adaptec, Inc.                                     */ | 
|  | 10 | /*                                                                           */ | 
|  | 11 | /* This program is free software; you can redistribute it and/or modify      */ | 
|  | 12 | /* it under the terms of the GNU General Public License as published by      */ | 
|  | 13 | /* the Free Software Foundation; either version 2 of the License, or         */ | 
|  | 14 | /* (at your option) any later version.                                       */ | 
|  | 15 | /*                                                                           */ | 
|  | 16 | /* This program is distributed in the hope that it will be useful,           */ | 
|  | 17 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */ | 
|  | 18 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */ | 
|  | 19 | /* GNU General Public License for more details.                              */ | 
|  | 20 | /*                                                                           */ | 
|  | 21 | /* NO WARRANTY                                                               */ | 
|  | 22 | /* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        */ | 
|  | 23 | /* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      */ | 
|  | 24 | /* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      */ | 
|  | 25 | /* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    */ | 
|  | 26 | /* solely responsible for determining the appropriateness of using and       */ | 
|  | 27 | /* distributing the Program and assumes all risks associated with its        */ | 
|  | 28 | /* exercise of rights under this Agreement, including but not limited to     */ | 
|  | 29 | /* the risks and costs of program errors, damage to or loss of data,         */ | 
|  | 30 | /* programs or equipment, and unavailability or interruption of operations.  */ | 
|  | 31 | /*                                                                           */ | 
|  | 32 | /* DISCLAIMER OF LIABILITY                                                   */ | 
|  | 33 | /* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   */ | 
|  | 34 | /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */ | 
|  | 35 | /* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   */ | 
|  | 36 | /* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     */ | 
|  | 37 | /* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    */ | 
|  | 38 | /* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  */ | 
|  | 39 | /* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             */ | 
|  | 40 | /*                                                                           */ | 
|  | 41 | /* You should have received a copy of the GNU General Public License         */ | 
|  | 42 | /* along with this program; if not, write to the Free Software               */ | 
|  | 43 | /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */ | 
|  | 44 | /*                                                                           */ | 
|  | 45 | /* Bugs/Comments/Suggestions about this driver should be mailed to:          */ | 
|  | 46 | /*      ipslinux@adaptec.com        	                                     */ | 
|  | 47 | /*                                                                           */ | 
|  | 48 | /* For system support issues, contact your local IBM Customer support.       */ | 
|  | 49 | /* Directions to find IBM Customer Support for each country can be found at: */ | 
|  | 50 | /*      http://www.ibm.com/planetwide/                                       */ | 
|  | 51 | /*                                                                           */ | 
|  | 52 | /*****************************************************************************/ | 
|  | 53 |  | 
|  | 54 | /*****************************************************************************/ | 
|  | 55 | /* Change Log                                                                */ | 
|  | 56 | /*                                                                           */ | 
|  | 57 | /* 0.99.02  - Breakup commands that are bigger than 8 * the stripe size      */ | 
|  | 58 | /* 0.99.03  - Make interrupt routine handle all completed request on the     */ | 
|  | 59 | /*            adapter not just the first one                                 */ | 
|  | 60 | /*          - Make sure passthru commands get woken up if we run out of      */ | 
|  | 61 | /*            SCBs                                                           */ | 
|  | 62 | /*          - Send all of the commands on the queue at once rather than      */ | 
|  | 63 | /*            one at a time since the card will support it.                  */ | 
|  | 64 | /* 0.99.04  - Fix race condition in the passthru mechanism -- this required  */ | 
|  | 65 | /*            the interface to the utilities to change                       */ | 
|  | 66 | /*          - Fix error recovery code                                        */ | 
|  | 67 | /* 0.99.05  - Fix an oops when we get certain passthru commands              */ | 
|  | 68 | /* 1.00.00  - Initial Public Release                                         */ | 
|  | 69 | /*            Functionally equivalent to 0.99.05                             */ | 
|  | 70 | /* 3.60.00  - Bump max commands to 128 for use with firmware 3.60            */ | 
|  | 71 | /*          - Change version to 3.60 to coincide with release numbering.     */ | 
|  | 72 | /* 3.60.01  - Remove bogus error check in passthru routine                   */ | 
|  | 73 | /* 3.60.02  - Make DCDB direction based on lookup table                      */ | 
|  | 74 | /*          - Only allow one DCDB command to a SCSI ID at a time             */ | 
|  | 75 | /* 4.00.00  - Add support for ServeRAID 4                                    */ | 
|  | 76 | /* 4.00.01  - Add support for First Failure Data Capture                     */ | 
|  | 77 | /* 4.00.02  - Fix problem with PT DCDB with no buffer                        */ | 
|  | 78 | /* 4.00.03  - Add alternative passthru interface                             */ | 
|  | 79 | /*          - Add ability to flash BIOS                                      */ | 
|  | 80 | /* 4.00.04  - Rename structures/constants to be prefixed with IPS_           */ | 
|  | 81 | /* 4.00.05  - Remove wish_block from init routine                            */ | 
|  | 82 | /*          - Use linux/spinlock.h instead of asm/spinlock.h for kernels     */ | 
|  | 83 | /*            2.3.18 and later                                               */ | 
|  | 84 | /*          - Sync with other changes from the 2.3 kernels                   */ | 
|  | 85 | /* 4.00.06  - Fix timeout with initial FFDC command                          */ | 
|  | 86 | /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */ | 
|  | 87 | /* 4.10.00  - Add support for ServeRAID 4M/4L                                */ | 
|  | 88 | /* 4.10.13  - Fix for dynamic unload and proc file system                    */ | 
|  | 89 | /* 4.20.03  - Rename version to coincide with new release schedules          */ | 
|  | 90 | /*            Performance fixes                                              */ | 
|  | 91 | /*            Fix truncation of /proc files with cat                         */ | 
|  | 92 | /*            Merge in changes through kernel 2.4.0test1ac21                 */ | 
|  | 93 | /* 4.20.13  - Fix some failure cases / reset code                            */ | 
|  | 94 | /*          - Hook into the reboot_notifier to flush the controller cache    */ | 
|  | 95 | /* 4.50.01  - Fix problem when there is a hole in logical drive numbering    */ | 
|  | 96 | /* 4.70.09  - Use a Common ( Large Buffer ) for Flashing from the JCRM CD    */ | 
|  | 97 | /*          - Add IPSSEND Flash Support                                      */ | 
|  | 98 | /*          - Set Sense Data for Unknown SCSI Command                        */ | 
|  | 99 | /*          - Use Slot Number from NVRAM Page 5                              */ | 
|  | 100 | /*          - Restore caller's DCDB Structure                                */ | 
|  | 101 | /* 4.70.12  - Corrective actions for bad controller ( during initialization )*/ | 
|  | 102 | /* 4.70.13  - Don't Send CDB's if we already know the device is not present  */ | 
|  | 103 | /*          - Don't release HA Lock in ips_next() until SC taken off queue   */ | 
|  | 104 | /*          - Unregister SCSI device in ips_release()                        */ | 
|  | 105 | /* 4.70.15  - Fix Breakup for very large ( non-SG ) requests in ips_done()   */ | 
|  | 106 | /* 4.71.00  - Change all memory allocations to not use GFP_DMA flag          */ | 
|  | 107 | /*            Code Clean-Up for 2.4.x kernel                                 */ | 
|  | 108 | /* 4.72.00  - Allow for a Scatter-Gather Element to exceed MAX_XFER Size     */ | 
|  | 109 | /* 4.72.01  - I/O Mapped Memory release ( so "insmod ips" does not Fail )    */ | 
|  | 110 | /*          - Don't Issue Internal FFDC Command if there are Active Commands */ | 
|  | 111 | /*          - Close Window for getting too many IOCTL's active               */ | 
|  | 112 | /* 4.80.00  - Make ia64 Safe                                                 */ | 
|  | 113 | /* 4.80.04  - Eliminate calls to strtok() if 2.4.x or greater                */ | 
|  | 114 | /*          - Adjustments to Device Queue Depth                              */ | 
|  | 115 | /* 4.80.14  - Take all semaphores off stack                                  */ | 
|  | 116 | /*          - Clean Up New_IOCTL path                                        */ | 
|  | 117 | /* 4.80.20  - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel )  */ | 
|  | 118 | /*          - 5 second delay needed after resetting an i960 adapter          */ | 
|  | 119 | /* 4.80.26  - Clean up potential code problems ( Arjan's recommendations )   */ | 
|  | 120 | /* 4.90.01  - Version Matching for FirmWare, BIOS, and Driver                */ | 
|  | 121 | /* 4.90.05  - Use New PCI Architecture to facilitate Hot Plug Development    */ | 
|  | 122 | /* 4.90.08  - Increase Delays in Flashing ( Trombone Only - 4H )             */ | 
|  | 123 | /* 4.90.08  - Data Corruption if First Scatter Gather Element is > 64K       */ | 
|  | 124 | /* 4.90.11  - Don't actually RESET unless it's physically required           */ | 
|  | 125 | /*          - Remove unused compile options                                  */ | 
|  | 126 | /* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */ | 
|  | 127 | /*          - Get rid on IOCTL_NEW_COMMAND code                              */ | 
|  | 128 | /*          - Add Extended DCDB Commands for Tape Support in 5I              */ | 
|  | 129 | /* 5.10.12  - use pci_dma interfaces, update for 2.5 kernel changes          */ | 
|  | 130 | /* 5.10.15  - remove unused code (sem, macros, etc.)                         */ | 
|  | 131 | /* 5.30.00  - use __devexit_p()                                              */ | 
|  | 132 | /* 6.00.00  - Add 6x Adapters and Battery Flash                              */ | 
|  | 133 | /* 6.10.00  - Remove 1G Addressing Limitations                               */ | 
|  | 134 | /* 6.11.xx  - Get VersionInfo buffer off the stack !              DDTS 60401 */ | 
|  | 135 | /* 6.11.xx  - Make Logical Drive Info structure safe for DMA      DDTS 60639 */ | 
| Jack Hammer | c1a1546 | 2005-07-26 10:20:33 -0400 | [diff] [blame] | 136 | /* 7.10.18  - Add highmem_io flag in SCSI Templete for 2.4 kernels           */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 | /*          - Fix path/name for scsi_hosts.h include for 2.6 kernels         */ | 
|  | 138 | /*          - Fix sort order of 7k                                           */ | 
|  | 139 | /*          - Remove 3 unused "inline" functions                             */ | 
| Jack Hammer | c1a1546 | 2005-07-26 10:20:33 -0400 | [diff] [blame] | 140 | /* 7.12.xx  - Use STATIC functions whereever possible                        */ | 
|  | 141 | /*          - Clean up deprecated MODULE_PARM calls                          */ | 
| Jack Hammer | a60768e | 2005-11-03 09:46:00 -0500 | [diff] [blame] | 142 | /* 7.12.05  - Remove Version Matching per IBM request                        */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | /*****************************************************************************/ | 
|  | 144 |  | 
|  | 145 | /* | 
|  | 146 | * Conditional Compilation directives for this driver: | 
|  | 147 | * | 
|  | 148 | * IPS_DEBUG            - Turn on debugging info | 
|  | 149 | * | 
|  | 150 | * Parameters: | 
|  | 151 | * | 
|  | 152 | * debug:<number>       - Set debug level to <number> | 
|  | 153 | *                        NOTE: only works when IPS_DEBUG compile directive is used. | 
|  | 154 | *       1              - Normal debug messages | 
|  | 155 | *       2              - Verbose debug messages | 
|  | 156 | *       11             - Method trace (non interrupt) | 
|  | 157 | *       12             - Method trace (includes interrupt) | 
|  | 158 | * | 
|  | 159 | * noi2o                - Don't use I2O Queues (ServeRAID 4 only) | 
|  | 160 | * nommap               - Don't use memory mapped I/O | 
|  | 161 | * ioctlsize            - Initial size of the IOCTL buffer | 
|  | 162 | */ | 
|  | 163 |  | 
|  | 164 | #include <asm/io.h> | 
|  | 165 | #include <asm/byteorder.h> | 
|  | 166 | #include <asm/page.h> | 
|  | 167 | #include <linux/stddef.h> | 
|  | 168 | #include <linux/version.h> | 
|  | 169 | #include <linux/string.h> | 
|  | 170 | #include <linux/errno.h> | 
|  | 171 | #include <linux/kernel.h> | 
|  | 172 | #include <linux/ioport.h> | 
|  | 173 | #include <linux/slab.h> | 
|  | 174 | #include <linux/delay.h> | 
|  | 175 | #include <linux/pci.h> | 
|  | 176 | #include <linux/proc_fs.h> | 
|  | 177 | #include <linux/reboot.h> | 
|  | 178 | #include <linux/interrupt.h> | 
|  | 179 |  | 
|  | 180 | #include <linux/blkdev.h> | 
|  | 181 | #include <linux/types.h> | 
| Matthias Gehre | 910638a | 2006-03-28 01:56:48 -0800 | [diff] [blame] | 182 | #include <linux/dma-mapping.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 183 |  | 
|  | 184 | #include <scsi/sg.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 185 | #include "scsi.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 | #include <scsi/scsi_host.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 187 |  | 
|  | 188 | #include "ips.h" | 
|  | 189 |  | 
|  | 190 | #include <linux/module.h> | 
|  | 191 |  | 
|  | 192 | #include <linux/stat.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 193 |  | 
|  | 194 | #include <linux/spinlock.h> | 
|  | 195 | #include <linux/init.h> | 
|  | 196 |  | 
|  | 197 | #include <linux/smp.h> | 
|  | 198 |  | 
|  | 199 | #ifdef MODULE | 
|  | 200 | static char *ips = NULL; | 
|  | 201 | module_param(ips, charp, 0); | 
|  | 202 | #endif | 
|  | 203 |  | 
|  | 204 | /* | 
|  | 205 | * DRIVER_VER | 
|  | 206 | */ | 
| Bernhard Walle | 8c8fdc5 | 2007-09-22 21:55:19 +0200 | [diff] [blame] | 207 | #define IPS_VERSION_HIGH        IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING | 
|  | 208 | #define IPS_VERSION_LOW         "." IPS_VER_BUILD_STRING " " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 209 |  | 
|  | 210 | #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) | 
|  | 211 | #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" | 
|  | 212 | #endif | 
|  | 213 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \ | 
|  | be7db05 | 2005-04-17 15:26:13 -0500 | [diff] [blame] | 215 | DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 216 | PCI_DMA_BIDIRECTIONAL : \ | 
|  | be7db05 | 2005-04-17 15:26:13 -0500 | [diff] [blame] | 217 | scb->scsi_cmd->sc_data_direction) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 |  | 
|  | 219 | #ifdef IPS_DEBUG | 
|  | 220 | #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); | 
|  | 221 | #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n"); | 
|  | 222 | #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v); | 
|  | 223 | #else | 
|  | 224 | #define METHOD_TRACE(s, i) | 
|  | 225 | #define DEBUG(i, s) | 
|  | 226 | #define DEBUG_VAR(i, s, v...) | 
|  | 227 | #endif | 
|  | 228 |  | 
|  | 229 | /* | 
|  | 230 | * Function prototypes | 
|  | 231 | */ | 
| Christoph Hellwig | d0be4a7d | 2005-10-31 18:31:40 +0100 | [diff] [blame] | 232 | static int ips_detect(struct scsi_host_template *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 233 | static int ips_release(struct Scsi_Host *); | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 234 | static int ips_eh_abort(struct scsi_cmnd *); | 
|  | 235 | static int ips_eh_reset(struct scsi_cmnd *); | 
|  | 236 | static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 237 | static const char *ips_info(struct Scsi_Host *); | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 238 | static irqreturn_t do_ipsintr(int, void *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 239 | static int ips_hainit(ips_ha_t *); | 
|  | 240 | static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); | 
|  | 241 | static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); | 
|  | 242 | static int ips_send_cmd(ips_ha_t *, ips_scb_t *); | 
|  | 243 | static int ips_online(ips_ha_t *, ips_scb_t *); | 
|  | 244 | static int ips_inquiry(ips_ha_t *, ips_scb_t *); | 
|  | 245 | static int ips_rdcap(ips_ha_t *, ips_scb_t *); | 
|  | 246 | static int ips_msense(ips_ha_t *, ips_scb_t *); | 
|  | 247 | static int ips_reqsen(ips_ha_t *, ips_scb_t *); | 
|  | 248 | static int ips_deallocatescbs(ips_ha_t *, int); | 
|  | 249 | static int ips_allocatescbs(ips_ha_t *); | 
|  | 250 | static int ips_reset_copperhead(ips_ha_t *); | 
|  | 251 | static int ips_reset_copperhead_memio(ips_ha_t *); | 
|  | 252 | static int ips_reset_morpheus(ips_ha_t *); | 
|  | 253 | static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); | 
|  | 254 | static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); | 
|  | 255 | static int ips_issue_i2o(ips_ha_t *, ips_scb_t *); | 
|  | 256 | static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); | 
|  | 257 | static int ips_isintr_copperhead(ips_ha_t *); | 
|  | 258 | static int ips_isintr_copperhead_memio(ips_ha_t *); | 
|  | 259 | static int ips_isintr_morpheus(ips_ha_t *); | 
|  | 260 | static int ips_wait(ips_ha_t *, int, int); | 
|  | 261 | static int ips_write_driver_status(ips_ha_t *, int); | 
|  | 262 | static int ips_read_adapter_status(ips_ha_t *, int); | 
|  | 263 | static int ips_read_subsystem_parameters(ips_ha_t *, int); | 
|  | 264 | static int ips_read_config(ips_ha_t *, int); | 
|  | 265 | static int ips_clear_adapter(ips_ha_t *, int); | 
|  | 266 | static int ips_readwrite_page5(ips_ha_t *, int, int); | 
|  | 267 | static int ips_init_copperhead(ips_ha_t *); | 
|  | 268 | static int ips_init_copperhead_memio(ips_ha_t *); | 
|  | 269 | static int ips_init_morpheus(ips_ha_t *); | 
|  | 270 | static int ips_isinit_copperhead(ips_ha_t *); | 
|  | 271 | static int ips_isinit_copperhead_memio(ips_ha_t *); | 
|  | 272 | static int ips_isinit_morpheus(ips_ha_t *); | 
|  | 273 | static int ips_erase_bios(ips_ha_t *); | 
|  | 274 | static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 275 | static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 276 | static int ips_erase_bios_memio(ips_ha_t *); | 
|  | 277 | static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 278 | static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 279 | static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 280 | static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 281 | static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 282 | static void ips_free_flash_copperhead(ips_ha_t * ha); | 
|  | 283 | static void ips_get_bios_version(ips_ha_t *, int); | 
|  | 284 | static void ips_identify_controller(ips_ha_t *); | 
|  | 285 | static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); | 
|  | 286 | static void ips_enable_int_copperhead(ips_ha_t *); | 
|  | 287 | static void ips_enable_int_copperhead_memio(ips_ha_t *); | 
|  | 288 | static void ips_enable_int_morpheus(ips_ha_t *); | 
|  | 289 | static int ips_intr_copperhead(ips_ha_t *); | 
|  | 290 | static int ips_intr_morpheus(ips_ha_t *); | 
|  | 291 | static void ips_next(ips_ha_t *, int); | 
|  | 292 | static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); | 
|  | 293 | static void ipsintr_done(ips_ha_t *, struct ips_scb *); | 
|  | 294 | static void ips_done(ips_ha_t *, ips_scb_t *); | 
|  | 295 | static void ips_free(ips_ha_t *); | 
|  | 296 | static void ips_init_scb(ips_ha_t *, ips_scb_t *); | 
|  | 297 | static void ips_freescb(ips_ha_t *, ips_scb_t *); | 
|  | 298 | static void ips_setup_funclist(ips_ha_t *); | 
|  | 299 | static void ips_statinit(ips_ha_t *); | 
|  | 300 | static void ips_statinit_memio(ips_ha_t *); | 
|  | 301 | static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t); | 
|  | 302 | static void ips_ffdc_reset(ips_ha_t *, int); | 
|  | 303 | static void ips_ffdc_time(ips_ha_t *); | 
|  | 304 | static uint32_t ips_statupd_copperhead(ips_ha_t *); | 
|  | 305 | static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); | 
|  | 306 | static uint32_t ips_statupd_morpheus(ips_ha_t *); | 
|  | 307 | static ips_scb_t *ips_getscb(ips_ha_t *); | 
|  | 308 | static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 309 | static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 310 | static void ips_putq_copp_tail(ips_copp_queue_t *, | 
|  | 311 | ips_copp_wait_item_t *); | 
|  | 312 | static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); | 
|  | 313 | static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 314 | static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *); | 
|  | 315 | static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *, | 
|  | 316 | struct scsi_cmnd *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 317 | static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, | 
|  | 318 | ips_copp_wait_item_t *); | 
|  | 319 | static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); | 
|  | 320 |  | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 321 | static int ips_is_passthru(struct scsi_cmnd *); | 
|  | 322 | static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 323 | static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 324 | static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 325 | static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 326 | unsigned int count); | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 327 | static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data, | 
|  | 328 | unsigned int count); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 329 |  | 
|  | 330 | static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); | 
|  | 331 | static int ips_host_info(ips_ha_t *, char *, off_t, int); | 
|  | 332 | static void copy_mem_info(IPS_INFOSTR *, char *, int); | 
|  | 333 | static int copy_info(IPS_INFOSTR *, char *, ...); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 334 | static int ips_abort_init(ips_ha_t * ha, int index); | 
|  | 335 | static int ips_init_phase2(int index); | 
|  | 336 |  | 
|  | 337 | static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr); | 
|  | 338 | static int ips_register_scsi(int index); | 
|  | 339 |  | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 340 | static int  ips_poll_for_flush_complete(ips_ha_t * ha); | 
|  | 341 | static void ips_flush_and_reset(ips_ha_t *ha); | 
|  | 342 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 343 | /* | 
|  | 344 | * global variables | 
|  | 345 | */ | 
|  | 346 | static const char ips_name[] = "ips"; | 
|  | 347 | static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];	/* Array of host controller structures */ | 
|  | 348 | static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS];	/* Array of HA structures */ | 
|  | 349 | static unsigned int ips_next_controller; | 
|  | 350 | static unsigned int ips_num_controllers; | 
|  | 351 | static unsigned int ips_released_controllers; | 
|  | 352 | static int ips_hotplug; | 
|  | 353 | static int ips_cmd_timeout = 60; | 
|  | 354 | static int ips_reset_timeout = 60 * 5; | 
|  | 355 | static int ips_force_memio = 1;		/* Always use Memory Mapped I/O    */ | 
|  | 356 | static int ips_force_i2o = 1;	/* Always use I2O command delivery */ | 
|  | 357 | static int ips_ioctlsize = IPS_IOCTL_SIZE;	/* Size of the ioctl buffer        */ | 
|  | 358 | static int ips_cd_boot;			/* Booting from Manager CD         */ | 
|  | 359 | static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */ | 
|  | 360 | static dma_addr_t ips_flashbusaddr; | 
|  | 361 | static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */ | 
|  | 362 | static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */ | 
| Christoph Hellwig | d0be4a7d | 2005-10-31 18:31:40 +0100 | [diff] [blame] | 363 | static struct scsi_host_template ips_driver_template = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 364 | .detect			= ips_detect, | 
|  | 365 | .release		= ips_release, | 
|  | 366 | .info			= ips_info, | 
|  | 367 | .queuecommand		= ips_queue, | 
|  | 368 | .eh_abort_handler	= ips_eh_abort, | 
|  | 369 | .eh_host_reset_handler	= ips_eh_reset, | 
|  | 370 | .proc_name		= "ips", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 371 | .proc_info		= ips_proc_info, | 
|  | 372 | .slave_configure	= ips_slave_configure, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 373 | .bios_param		= ips_biosparam, | 
|  | 374 | .this_id		= -1, | 
|  | 375 | .sg_tablesize		= IPS_MAX_SG, | 
|  | 376 | .cmd_per_lun		= 3, | 
|  | 377 | .use_clustering		= ENABLE_CLUSTERING, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 378 | }; | 
|  | 379 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 380 |  | 
|  | 381 | /* This table describes all ServeRAID Adapters */ | 
|  | 382 | static struct  pci_device_id  ips_pci_table[] = { | 
|  | 383 | { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, | 
|  | 384 | { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, | 
|  | 385 | { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, | 
|  | 386 | { 0, } | 
|  | 387 | }; | 
|  | 388 |  | 
|  | 389 | MODULE_DEVICE_TABLE( pci, ips_pci_table ); | 
|  | 390 |  | 
|  | 391 | static char ips_hot_plug_name[] = "ips"; | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 392 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 393 | static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); | 
|  | 394 | static void __devexit ips_remove_device(struct pci_dev *pci_dev); | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 395 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 396 | static struct pci_driver ips_pci_driver = { | 
|  | 397 | .name		= ips_hot_plug_name, | 
|  | 398 | .id_table	= ips_pci_table, | 
|  | 399 | .probe		= ips_insert_device, | 
|  | 400 | .remove		= __devexit_p(ips_remove_device), | 
|  | 401 | }; | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 402 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 403 |  | 
|  | 404 | /* | 
|  | 405 | * Necessary forward function protoypes | 
|  | 406 | */ | 
|  | 407 | static int ips_halt(struct notifier_block *nb, ulong event, void *buf); | 
|  | 408 |  | 
|  | 409 | #define MAX_ADAPTER_NAME 15 | 
|  | 410 |  | 
|  | 411 | static char ips_adapter_name[][30] = { | 
|  | 412 | "ServeRAID", | 
|  | 413 | "ServeRAID II", | 
|  | 414 | "ServeRAID on motherboard", | 
|  | 415 | "ServeRAID on motherboard", | 
|  | 416 | "ServeRAID 3H", | 
|  | 417 | "ServeRAID 3L", | 
|  | 418 | "ServeRAID 4H", | 
|  | 419 | "ServeRAID 4M", | 
|  | 420 | "ServeRAID 4L", | 
|  | 421 | "ServeRAID 4Mx", | 
|  | 422 | "ServeRAID 4Lx", | 
|  | 423 | "ServeRAID 5i", | 
|  | 424 | "ServeRAID 5i", | 
|  | 425 | "ServeRAID 6M", | 
|  | 426 | "ServeRAID 6i", | 
|  | 427 | "ServeRAID 7t", | 
|  | 428 | "ServeRAID 7k", | 
|  | 429 | "ServeRAID 7M" | 
|  | 430 | }; | 
|  | 431 |  | 
|  | 432 | static struct notifier_block ips_notifier = { | 
|  | 433 | ips_halt, NULL, 0 | 
|  | 434 | }; | 
|  | 435 |  | 
|  | 436 | /* | 
|  | 437 | * Direction table | 
|  | 438 | */ | 
|  | 439 | static char ips_command_direction[] = { | 
|  | 440 | IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, | 
|  | 441 | IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, | 
|  | 442 | IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 443 | IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, | 
|  | 444 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT, | 
|  | 445 | IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, | 
|  | 446 | IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN, | 
|  | 447 | IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 448 | IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK, | 
|  | 449 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, | 
|  | 450 | IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, | 
|  | 451 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, | 
|  | 452 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, | 
|  | 453 | IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE, | 
|  | 454 | IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, | 
|  | 455 | IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 456 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 457 | IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 458 | IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 459 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 460 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 461 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 462 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 463 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 464 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 465 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 466 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 467 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 468 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 469 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 470 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 471 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 472 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 473 | IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE, | 
|  | 474 | IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT, | 
|  | 475 | IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE, | 
|  | 476 | IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, | 
|  | 477 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 478 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 479 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 480 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 481 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 482 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 483 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 484 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 485 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 486 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT, | 
|  | 487 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 488 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 489 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 490 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK | 
|  | 491 | }; | 
|  | 492 |  | 
|  | 493 |  | 
|  | 494 | /****************************************************************************/ | 
|  | 495 | /*                                                                          */ | 
|  | 496 | /* Routine Name: ips_setup                                                  */ | 
|  | 497 | /*                                                                          */ | 
|  | 498 | /* Routine Description:                                                     */ | 
|  | 499 | /*                                                                          */ | 
|  | 500 | /*   setup parameters to the driver                                         */ | 
|  | 501 | /*                                                                          */ | 
|  | 502 | /****************************************************************************/ | 
|  | 503 | static int | 
|  | 504 | ips_setup(char *ips_str) | 
|  | 505 | { | 
|  | 506 |  | 
|  | 507 | int i; | 
|  | 508 | char *key; | 
|  | 509 | char *value; | 
|  | 510 | IPS_OPTION options[] = { | 
|  | 511 | {"noi2o", &ips_force_i2o, 0}, | 
|  | 512 | {"nommap", &ips_force_memio, 0}, | 
|  | 513 | {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, | 
|  | 514 | {"cdboot", &ips_cd_boot, 0}, | 
|  | 515 | {"maxcmds", &MaxLiteCmds, 32}, | 
|  | 516 | }; | 
|  | 517 |  | 
|  | 518 | /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */ | 
|  | 519 | /* Search for value */ | 
|  | 520 | while ((key = strsep(&ips_str, ",."))) { | 
|  | 521 | if (!*key) | 
|  | 522 | continue; | 
|  | 523 | value = strchr(key, ':'); | 
|  | 524 | if (value) | 
|  | 525 | *value++ = '\0'; | 
|  | 526 | /* | 
|  | 527 | * We now have key/value pairs. | 
|  | 528 | * Update the variables | 
|  | 529 | */ | 
| Tobias Klauser | 6391a11 | 2006-06-08 22:23:48 -0700 | [diff] [blame] | 530 | for (i = 0; i < ARRAY_SIZE(options); i++) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 531 | if (strnicmp | 
|  | 532 | (key, options[i].option_name, | 
|  | 533 | strlen(options[i].option_name)) == 0) { | 
|  | 534 | if (value) | 
|  | 535 | *options[i].option_flag = | 
|  | 536 | simple_strtoul(value, NULL, 0); | 
|  | 537 | else | 
|  | 538 | *options[i].option_flag = | 
|  | 539 | options[i].option_value; | 
|  | 540 | break; | 
|  | 541 | } | 
|  | 542 | } | 
|  | 543 | } | 
|  | 544 |  | 
|  | 545 | return (1); | 
|  | 546 | } | 
|  | 547 |  | 
|  | 548 | __setup("ips=", ips_setup); | 
|  | 549 |  | 
|  | 550 | /****************************************************************************/ | 
|  | 551 | /*                                                                          */ | 
|  | 552 | /* Routine Name: ips_detect                                                 */ | 
|  | 553 | /*                                                                          */ | 
|  | 554 | /* Routine Description:                                                     */ | 
|  | 555 | /*                                                                          */ | 
|  | 556 | /*   Detect and initialize the driver                                       */ | 
|  | 557 | /*                                                                          */ | 
|  | 558 | /* NOTE: this routine is called under the io_request_lock spinlock          */ | 
|  | 559 | /*                                                                          */ | 
|  | 560 | /****************************************************************************/ | 
|  | 561 | static int | 
| Christoph Hellwig | d0be4a7d | 2005-10-31 18:31:40 +0100 | [diff] [blame] | 562 | ips_detect(struct scsi_host_template * SHT) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 563 | { | 
|  | 564 | int i; | 
|  | 565 |  | 
|  | 566 | METHOD_TRACE("ips_detect", 1); | 
|  | 567 |  | 
|  | 568 | #ifdef MODULE | 
|  | 569 | if (ips) | 
|  | 570 | ips_setup(ips); | 
|  | 571 | #endif | 
|  | 572 |  | 
|  | 573 | for (i = 0; i < ips_num_controllers; i++) { | 
|  | 574 | if (ips_register_scsi(i)) | 
|  | 575 | ips_free(ips_ha[i]); | 
|  | 576 | ips_released_controllers++; | 
|  | 577 | } | 
|  | 578 | ips_hotplug = 1; | 
|  | 579 | return (ips_num_controllers); | 
|  | 580 | } | 
|  | 581 |  | 
|  | 582 | /****************************************************************************/ | 
|  | 583 | /*   configure the function pointers to use the functions that will work    */ | 
|  | 584 | /*   with the found version of the adapter                                  */ | 
|  | 585 | /****************************************************************************/ | 
|  | 586 | static void | 
|  | 587 | ips_setup_funclist(ips_ha_t * ha) | 
|  | 588 | { | 
|  | 589 |  | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 590 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 591 | * Setup Functions | 
|  | 592 | */ | 
|  | 593 | if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) { | 
|  | 594 | /* morpheus / marco / sebring */ | 
|  | 595 | ha->func.isintr = ips_isintr_morpheus; | 
|  | 596 | ha->func.isinit = ips_isinit_morpheus; | 
|  | 597 | ha->func.issue = ips_issue_i2o_memio; | 
|  | 598 | ha->func.init = ips_init_morpheus; | 
|  | 599 | ha->func.statupd = ips_statupd_morpheus; | 
|  | 600 | ha->func.reset = ips_reset_morpheus; | 
|  | 601 | ha->func.intr = ips_intr_morpheus; | 
|  | 602 | ha->func.enableint = ips_enable_int_morpheus; | 
|  | 603 | } else if (IPS_USE_MEMIO(ha)) { | 
|  | 604 | /* copperhead w/MEMIO */ | 
|  | 605 | ha->func.isintr = ips_isintr_copperhead_memio; | 
|  | 606 | ha->func.isinit = ips_isinit_copperhead_memio; | 
|  | 607 | ha->func.init = ips_init_copperhead_memio; | 
|  | 608 | ha->func.statupd = ips_statupd_copperhead_memio; | 
|  | 609 | ha->func.statinit = ips_statinit_memio; | 
|  | 610 | ha->func.reset = ips_reset_copperhead_memio; | 
|  | 611 | ha->func.intr = ips_intr_copperhead; | 
|  | 612 | ha->func.erasebios = ips_erase_bios_memio; | 
|  | 613 | ha->func.programbios = ips_program_bios_memio; | 
|  | 614 | ha->func.verifybios = ips_verify_bios_memio; | 
|  | 615 | ha->func.enableint = ips_enable_int_copperhead_memio; | 
|  | 616 | if (IPS_USE_I2O_DELIVER(ha)) | 
|  | 617 | ha->func.issue = ips_issue_i2o_memio; | 
|  | 618 | else | 
|  | 619 | ha->func.issue = ips_issue_copperhead_memio; | 
|  | 620 | } else { | 
|  | 621 | /* copperhead */ | 
|  | 622 | ha->func.isintr = ips_isintr_copperhead; | 
|  | 623 | ha->func.isinit = ips_isinit_copperhead; | 
|  | 624 | ha->func.init = ips_init_copperhead; | 
|  | 625 | ha->func.statupd = ips_statupd_copperhead; | 
|  | 626 | ha->func.statinit = ips_statinit; | 
|  | 627 | ha->func.reset = ips_reset_copperhead; | 
|  | 628 | ha->func.intr = ips_intr_copperhead; | 
|  | 629 | ha->func.erasebios = ips_erase_bios; | 
|  | 630 | ha->func.programbios = ips_program_bios; | 
|  | 631 | ha->func.verifybios = ips_verify_bios; | 
|  | 632 | ha->func.enableint = ips_enable_int_copperhead; | 
|  | 633 |  | 
|  | 634 | if (IPS_USE_I2O_DELIVER(ha)) | 
|  | 635 | ha->func.issue = ips_issue_i2o; | 
|  | 636 | else | 
|  | 637 | ha->func.issue = ips_issue_copperhead; | 
|  | 638 | } | 
|  | 639 | } | 
|  | 640 |  | 
|  | 641 | /****************************************************************************/ | 
|  | 642 | /*                                                                          */ | 
|  | 643 | /* Routine Name: ips_release                                                */ | 
|  | 644 | /*                                                                          */ | 
|  | 645 | /* Routine Description:                                                     */ | 
|  | 646 | /*                                                                          */ | 
|  | 647 | /*   Remove a driver                                                        */ | 
|  | 648 | /*                                                                          */ | 
|  | 649 | /****************************************************************************/ | 
|  | 650 | static int | 
|  | 651 | ips_release(struct Scsi_Host *sh) | 
|  | 652 | { | 
|  | 653 | ips_scb_t *scb; | 
|  | 654 | ips_ha_t *ha; | 
|  | 655 | int i; | 
|  | 656 |  | 
|  | 657 | METHOD_TRACE("ips_release", 1); | 
|  | 658 |  | 
| Matthew Wilcox | a50ee7a | 2007-08-15 12:57:00 -0600 | [diff] [blame] | 659 | scsi_remove_host(sh); | 
|  | 660 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 661 | for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ; | 
|  | 662 |  | 
|  | 663 | if (i == IPS_MAX_ADAPTERS) { | 
|  | 664 | printk(KERN_WARNING | 
|  | 665 | "(%s) release, invalid Scsi_Host pointer.\n", ips_name); | 
|  | 666 | BUG(); | 
|  | 667 | return (FALSE); | 
|  | 668 | } | 
|  | 669 |  | 
|  | 670 | ha = IPS_HA(sh); | 
|  | 671 |  | 
|  | 672 | if (!ha) | 
|  | 673 | return (FALSE); | 
|  | 674 |  | 
|  | 675 | /* flush the cache on the controller */ | 
|  | 676 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 677 |  | 
|  | 678 | ips_init_scb(ha, scb); | 
|  | 679 |  | 
|  | 680 | scb->timeout = ips_cmd_timeout; | 
|  | 681 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 682 |  | 
|  | 683 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 684 | scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 685 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 686 | scb->cmd.flush_cache.reserved = 0; | 
|  | 687 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 688 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 689 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 690 |  | 
|  | 691 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); | 
|  | 692 |  | 
|  | 693 | /* send command */ | 
|  | 694 | if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) | 
|  | 695 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n"); | 
|  | 696 |  | 
|  | 697 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); | 
|  | 698 |  | 
|  | 699 | ips_sh[i] = NULL; | 
|  | 700 | ips_ha[i] = NULL; | 
|  | 701 |  | 
|  | 702 | /* free extra memory */ | 
|  | 703 | ips_free(ha); | 
|  | 704 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 705 | /* free IRQ */ | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 706 | free_irq(ha->pcidev->irq, ha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 707 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 708 | scsi_host_put(sh); | 
|  | 709 |  | 
|  | 710 | ips_released_controllers++; | 
|  | 711 |  | 
|  | 712 | return (FALSE); | 
|  | 713 | } | 
|  | 714 |  | 
|  | 715 | /****************************************************************************/ | 
|  | 716 | /*                                                                          */ | 
|  | 717 | /* Routine Name: ips_halt                                                   */ | 
|  | 718 | /*                                                                          */ | 
|  | 719 | /* Routine Description:                                                     */ | 
|  | 720 | /*                                                                          */ | 
|  | 721 | /*   Perform cleanup when the system reboots                                */ | 
|  | 722 | /*                                                                          */ | 
|  | 723 | /****************************************************************************/ | 
|  | 724 | static int | 
|  | 725 | ips_halt(struct notifier_block *nb, ulong event, void *buf) | 
|  | 726 | { | 
|  | 727 | ips_scb_t *scb; | 
|  | 728 | ips_ha_t *ha; | 
|  | 729 | int i; | 
|  | 730 |  | 
|  | 731 | if ((event != SYS_RESTART) && (event != SYS_HALT) && | 
|  | 732 | (event != SYS_POWER_OFF)) | 
|  | 733 | return (NOTIFY_DONE); | 
|  | 734 |  | 
|  | 735 | for (i = 0; i < ips_next_controller; i++) { | 
|  | 736 | ha = (ips_ha_t *) ips_ha[i]; | 
|  | 737 |  | 
|  | 738 | if (!ha) | 
|  | 739 | continue; | 
|  | 740 |  | 
|  | 741 | if (!ha->active) | 
|  | 742 | continue; | 
|  | 743 |  | 
|  | 744 | /* flush the cache on the controller */ | 
|  | 745 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 746 |  | 
|  | 747 | ips_init_scb(ha, scb); | 
|  | 748 |  | 
|  | 749 | scb->timeout = ips_cmd_timeout; | 
|  | 750 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 751 |  | 
|  | 752 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 753 | scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 754 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 755 | scb->cmd.flush_cache.reserved = 0; | 
|  | 756 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 757 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 758 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 759 |  | 
|  | 760 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); | 
|  | 761 |  | 
|  | 762 | /* send command */ | 
|  | 763 | if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == | 
|  | 764 | IPS_FAILURE) | 
|  | 765 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 766 | "Incomplete Flush.\n"); | 
|  | 767 | else | 
|  | 768 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 769 | "Flushing Complete.\n"); | 
|  | 770 | } | 
|  | 771 |  | 
|  | 772 | return (NOTIFY_OK); | 
|  | 773 | } | 
|  | 774 |  | 
|  | 775 | /****************************************************************************/ | 
|  | 776 | /*                                                                          */ | 
|  | 777 | /* Routine Name: ips_eh_abort                                               */ | 
|  | 778 | /*                                                                          */ | 
|  | 779 | /* Routine Description:                                                     */ | 
|  | 780 | /*                                                                          */ | 
|  | 781 | /*   Abort a command (using the new error code stuff)                       */ | 
|  | 782 | /* Note: this routine is called under the io_request_lock                   */ | 
|  | 783 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 784 | int ips_eh_abort(struct scsi_cmnd *SC) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 785 | { | 
|  | 786 | ips_ha_t *ha; | 
|  | 787 | ips_copp_wait_item_t *item; | 
|  | 788 | int ret; | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 789 | struct Scsi_Host *host; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 790 |  | 
|  | 791 | METHOD_TRACE("ips_eh_abort", 1); | 
|  | 792 |  | 
|  | 793 | if (!SC) | 
|  | 794 | return (FAILED); | 
|  | 795 |  | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 796 | host = SC->device->host; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 797 | ha = (ips_ha_t *) SC->device->host->hostdata; | 
|  | 798 |  | 
|  | 799 | if (!ha) | 
|  | 800 | return (FAILED); | 
|  | 801 |  | 
|  | 802 | if (!ha->active) | 
|  | 803 | return (FAILED); | 
|  | 804 |  | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 805 | spin_lock(host->host_lock); | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 806 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 807 | /* See if the command is on the copp queue */ | 
|  | 808 | item = ha->copp_waitlist.head; | 
|  | 809 | while ((item) && (item->scsi_cmd != SC)) | 
|  | 810 | item = item->next; | 
|  | 811 |  | 
|  | 812 | if (item) { | 
|  | 813 | /* Found it */ | 
|  | 814 | ips_removeq_copp(&ha->copp_waitlist, item); | 
|  | 815 | ret = (SUCCESS); | 
|  | 816 |  | 
|  | 817 | /* See if the command is on the wait queue */ | 
|  | 818 | } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) { | 
|  | 819 | /* command not sent yet */ | 
|  | 820 | ret = (SUCCESS); | 
|  | 821 | } else { | 
|  | 822 | /* command must have already been sent */ | 
|  | 823 | ret = (FAILED); | 
|  | 824 | } | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 825 |  | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 826 | spin_unlock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 827 | return ret; | 
|  | 828 | } | 
|  | 829 |  | 
|  | 830 | /****************************************************************************/ | 
|  | 831 | /*                                                                          */ | 
|  | 832 | /* Routine Name: ips_eh_reset                                               */ | 
|  | 833 | /*                                                                          */ | 
|  | 834 | /* Routine Description:                                                     */ | 
|  | 835 | /*                                                                          */ | 
|  | 836 | /*   Reset the controller (with new eh error code)                          */ | 
|  | 837 | /*                                                                          */ | 
|  | 838 | /* NOTE: this routine is called under the io_request_lock spinlock          */ | 
|  | 839 | /*                                                                          */ | 
|  | 840 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 841 | static int __ips_eh_reset(struct scsi_cmnd *SC) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 842 | { | 
|  | 843 | int ret; | 
|  | 844 | int i; | 
|  | 845 | ips_ha_t *ha; | 
|  | 846 | ips_scb_t *scb; | 
|  | 847 | ips_copp_wait_item_t *item; | 
|  | 848 |  | 
|  | 849 | METHOD_TRACE("ips_eh_reset", 1); | 
|  | 850 |  | 
|  | 851 | #ifdef NO_IPS_RESET | 
|  | 852 | return (FAILED); | 
|  | 853 | #else | 
|  | 854 |  | 
|  | 855 | if (!SC) { | 
|  | 856 | DEBUG(1, "Reset called with NULL scsi command"); | 
|  | 857 |  | 
|  | 858 | return (FAILED); | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 | ha = (ips_ha_t *) SC->device->host->hostdata; | 
|  | 862 |  | 
|  | 863 | if (!ha) { | 
|  | 864 | DEBUG(1, "Reset called with NULL ha struct"); | 
|  | 865 |  | 
|  | 866 | return (FAILED); | 
|  | 867 | } | 
|  | 868 |  | 
|  | 869 | if (!ha->active) | 
|  | 870 | return (FAILED); | 
|  | 871 |  | 
|  | 872 | /* See if the command is on the copp queue */ | 
|  | 873 | item = ha->copp_waitlist.head; | 
|  | 874 | while ((item) && (item->scsi_cmd != SC)) | 
|  | 875 | item = item->next; | 
|  | 876 |  | 
|  | 877 | if (item) { | 
|  | 878 | /* Found it */ | 
|  | 879 | ips_removeq_copp(&ha->copp_waitlist, item); | 
|  | 880 | return (SUCCESS); | 
|  | 881 | } | 
|  | 882 |  | 
|  | 883 | /* See if the command is on the wait queue */ | 
|  | 884 | if (ips_removeq_wait(&ha->scb_waitlist, SC)) { | 
|  | 885 | /* command not sent yet */ | 
|  | 886 | return (SUCCESS); | 
|  | 887 | } | 
|  | 888 |  | 
|  | 889 | /* An explanation for the casual observer:                              */ | 
|  | 890 | /* Part of the function of a RAID controller is automatic error         */ | 
|  | 891 | /* detection and recovery.  As such, the only problem that physically   */ | 
|  | 892 | /* resetting an adapter will ever fix is when, for some reason,         */ | 
|  | 893 | /* the driver is not successfully communicating with the adapter.       */ | 
|  | 894 | /* Therefore, we will attempt to flush this adapter.  If that succeeds, */ | 
|  | 895 | /* then there's no real purpose in a physical reset. This will complete */ | 
|  | 896 | /* much faster and avoids any problems that might be caused by a        */ | 
|  | 897 | /* physical reset ( such as having to fail all the outstanding I/O's ). */ | 
|  | 898 |  | 
|  | 899 | if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */ | 
|  | 900 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 901 |  | 
|  | 902 | ips_init_scb(ha, scb); | 
|  | 903 |  | 
|  | 904 | scb->timeout = ips_cmd_timeout; | 
|  | 905 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 906 |  | 
|  | 907 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 908 | scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 909 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 910 | scb->cmd.flush_cache.reserved = 0; | 
|  | 911 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 912 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 913 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 914 |  | 
|  | 915 | /* Attempt the flush command */ | 
|  | 916 | ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL); | 
|  | 917 | if (ret == IPS_SUCCESS) { | 
|  | 918 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, | 
|  | 919 | "Reset Request - Flushed Cache\n"); | 
|  | 920 | return (SUCCESS); | 
|  | 921 | } | 
|  | 922 | } | 
|  | 923 |  | 
|  | 924 | /* Either we can't communicate with the adapter or it's an IOCTL request */ | 
|  | 925 | /* from a utility.  A physical reset is needed at this point.            */ | 
|  | 926 |  | 
|  | 927 | ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */ | 
|  | 928 |  | 
|  | 929 | /* | 
|  | 930 | * command must have already been sent | 
|  | 931 | * reset the controller | 
|  | 932 | */ | 
|  | 933 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n"); | 
|  | 934 | ret = (*ha->func.reset) (ha); | 
|  | 935 |  | 
|  | 936 | if (!ret) { | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 937 | struct scsi_cmnd *scsi_cmd; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 938 |  | 
|  | 939 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, | 
|  | 940 | "Controller reset failed - controller now offline.\n"); | 
|  | 941 |  | 
|  | 942 | /* Now fail all of the active commands */ | 
|  | 943 | DEBUG_VAR(1, "(%s%d) Failing active commands", | 
|  | 944 | ips_name, ha->host_num); | 
|  | 945 |  | 
|  | 946 | while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { | 
|  | 947 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 948 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 949 | ips_freescb(ha, scb); | 
|  | 950 | } | 
|  | 951 |  | 
|  | 952 | /* Now fail all of the pending commands */ | 
|  | 953 | DEBUG_VAR(1, "(%s%d) Failing pending commands", | 
|  | 954 | ips_name, ha->host_num); | 
|  | 955 |  | 
|  | 956 | while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { | 
|  | 957 | scsi_cmd->result = DID_ERROR; | 
|  | 958 | scsi_cmd->scsi_done(scsi_cmd); | 
|  | 959 | } | 
|  | 960 |  | 
|  | 961 | ha->active = FALSE; | 
|  | 962 | return (FAILED); | 
|  | 963 | } | 
|  | 964 |  | 
|  | 965 | if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 966 | struct scsi_cmnd *scsi_cmd; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 967 |  | 
|  | 968 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, | 
|  | 969 | "Controller reset failed - controller now offline.\n"); | 
|  | 970 |  | 
|  | 971 | /* Now fail all of the active commands */ | 
|  | 972 | DEBUG_VAR(1, "(%s%d) Failing active commands", | 
|  | 973 | ips_name, ha->host_num); | 
|  | 974 |  | 
|  | 975 | while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { | 
|  | 976 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 977 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 978 | ips_freescb(ha, scb); | 
|  | 979 | } | 
|  | 980 |  | 
|  | 981 | /* Now fail all of the pending commands */ | 
|  | 982 | DEBUG_VAR(1, "(%s%d) Failing pending commands", | 
|  | 983 | ips_name, ha->host_num); | 
|  | 984 |  | 
|  | 985 | while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { | 
|  | 986 | scsi_cmd->result = DID_ERROR << 16; | 
|  | 987 | scsi_cmd->scsi_done(scsi_cmd); | 
|  | 988 | } | 
|  | 989 |  | 
|  | 990 | ha->active = FALSE; | 
|  | 991 | return (FAILED); | 
|  | 992 | } | 
|  | 993 |  | 
|  | 994 | /* FFDC */ | 
|  | 995 | if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) { | 
|  | 996 | struct timeval tv; | 
|  | 997 |  | 
|  | 998 | do_gettimeofday(&tv); | 
|  | 999 | ha->last_ffdc = tv.tv_sec; | 
|  | 1000 | ha->reset_count++; | 
|  | 1001 | ips_ffdc_reset(ha, IPS_INTR_IORL); | 
|  | 1002 | } | 
|  | 1003 |  | 
|  | 1004 | /* Now fail all of the active commands */ | 
|  | 1005 | DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); | 
|  | 1006 |  | 
|  | 1007 | while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { | 
|  | 1008 | scb->scsi_cmd->result = | 
|  | 1009 | (DID_RESET << 16) | (SUGGEST_RETRY << 24); | 
|  | 1010 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 1011 | ips_freescb(ha, scb); | 
|  | 1012 | } | 
|  | 1013 |  | 
|  | 1014 | /* Reset DCDB active command bits */ | 
|  | 1015 | for (i = 1; i < ha->nbus; i++) | 
|  | 1016 | ha->dcdb_active[i - 1] = 0; | 
|  | 1017 |  | 
|  | 1018 | /* Reset the number of active IOCTLs */ | 
|  | 1019 | ha->num_ioctl = 0; | 
|  | 1020 |  | 
|  | 1021 | ips_next(ha, IPS_INTR_IORL); | 
|  | 1022 |  | 
|  | 1023 | return (SUCCESS); | 
|  | 1024 | #endif				/* NO_IPS_RESET */ | 
|  | 1025 |  | 
|  | 1026 | } | 
|  | 1027 |  | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 1028 | static int ips_eh_reset(struct scsi_cmnd *SC) | 
| Jeff Garzik | df0ae24 | 2005-05-28 07:57:14 -0400 | [diff] [blame] | 1029 | { | 
|  | 1030 | int rc; | 
|  | 1031 |  | 
|  | 1032 | spin_lock_irq(SC->device->host->host_lock); | 
|  | 1033 | rc = __ips_eh_reset(SC); | 
|  | 1034 | spin_unlock_irq(SC->device->host->host_lock); | 
|  | 1035 |  | 
|  | 1036 | return rc; | 
|  | 1037 | } | 
|  | 1038 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1039 | /****************************************************************************/ | 
|  | 1040 | /*                                                                          */ | 
|  | 1041 | /* Routine Name: ips_queue                                                  */ | 
|  | 1042 | /*                                                                          */ | 
|  | 1043 | /* Routine Description:                                                     */ | 
|  | 1044 | /*                                                                          */ | 
|  | 1045 | /*   Send a command to the controller                                       */ | 
|  | 1046 | /*                                                                          */ | 
|  | 1047 | /* NOTE:                                                                    */ | 
|  | 1048 | /*    Linux obtains io_request_lock before calling this function            */ | 
|  | 1049 | /*                                                                          */ | 
|  | 1050 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 1051 | static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1052 | { | 
|  | 1053 | ips_ha_t *ha; | 
|  | 1054 | ips_passthru_t *pt; | 
|  | 1055 |  | 
|  | 1056 | METHOD_TRACE("ips_queue", 1); | 
|  | 1057 |  | 
|  | 1058 | ha = (ips_ha_t *) SC->device->host->hostdata; | 
|  | 1059 |  | 
|  | 1060 | if (!ha) | 
|  | 1061 | return (1); | 
|  | 1062 |  | 
|  | 1063 | if (!ha->active) | 
|  | 1064 | return (DID_ERROR); | 
|  | 1065 |  | 
|  | 1066 | if (ips_is_passthru(SC)) { | 
|  | 1067 | if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) { | 
|  | 1068 | SC->result = DID_BUS_BUSY << 16; | 
|  | 1069 | done(SC); | 
|  | 1070 |  | 
|  | 1071 | return (0); | 
|  | 1072 | } | 
|  | 1073 | } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) { | 
|  | 1074 | SC->result = DID_BUS_BUSY << 16; | 
|  | 1075 | done(SC); | 
|  | 1076 |  | 
|  | 1077 | return (0); | 
|  | 1078 | } | 
|  | 1079 |  | 
|  | 1080 | SC->scsi_done = done; | 
|  | 1081 |  | 
|  | 1082 | DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)", | 
|  | 1083 | ips_name, | 
|  | 1084 | ha->host_num, | 
|  | 1085 | SC->cmnd[0], | 
|  | 1086 | SC->device->channel, SC->device->id, SC->device->lun); | 
|  | 1087 |  | 
|  | 1088 | /* Check for command to initiator IDs */ | 
| Jeff Garzik | 422c0d6 | 2005-10-24 18:05:09 -0400 | [diff] [blame] | 1089 | if ((scmd_channel(SC) > 0) | 
|  | 1090 | && (scmd_id(SC) == ha->ha_id[scmd_channel(SC)])) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1091 | SC->result = DID_NO_CONNECT << 16; | 
|  | 1092 | done(SC); | 
|  | 1093 |  | 
|  | 1094 | return (0); | 
|  | 1095 | } | 
|  | 1096 |  | 
|  | 1097 | if (ips_is_passthru(SC)) { | 
|  | 1098 |  | 
|  | 1099 | ips_copp_wait_item_t *scratch; | 
|  | 1100 |  | 
|  | 1101 | /* A Reset IOCTL is only sent by the boot CD in extreme cases.           */ | 
|  | 1102 | /* There can never be any system activity ( network or disk ), but check */ | 
|  | 1103 | /* anyway just as a good practice.                                       */ | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 1104 | pt = (ips_passthru_t *) scsi_sglist(SC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1105 | if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) && | 
|  | 1106 | (pt->CoppCP.cmd.reset.adapter_flag == 1)) { | 
|  | 1107 | if (ha->scb_activelist.count != 0) { | 
|  | 1108 | SC->result = DID_BUS_BUSY << 16; | 
|  | 1109 | done(SC); | 
|  | 1110 | return (0); | 
|  | 1111 | } | 
|  | 1112 | ha->ioctl_reset = 1;	/* This reset request is from an IOCTL */ | 
| Mike Christie | ba3af0a | 2006-02-22 02:11:59 -0600 | [diff] [blame] | 1113 | __ips_eh_reset(SC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1114 | SC->result = DID_OK << 16; | 
|  | 1115 | SC->scsi_done(SC); | 
|  | 1116 | return (0); | 
|  | 1117 | } | 
|  | 1118 |  | 
|  | 1119 | /* allocate space for the scribble */ | 
|  | 1120 | scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC); | 
|  | 1121 |  | 
|  | 1122 | if (!scratch) { | 
|  | 1123 | SC->result = DID_ERROR << 16; | 
|  | 1124 | done(SC); | 
|  | 1125 |  | 
|  | 1126 | return (0); | 
|  | 1127 | } | 
|  | 1128 |  | 
|  | 1129 | scratch->scsi_cmd = SC; | 
|  | 1130 | scratch->next = NULL; | 
|  | 1131 |  | 
|  | 1132 | ips_putq_copp_tail(&ha->copp_waitlist, scratch); | 
|  | 1133 | } else { | 
|  | 1134 | ips_putq_wait_tail(&ha->scb_waitlist, SC); | 
|  | 1135 | } | 
|  | 1136 |  | 
|  | 1137 | ips_next(ha, IPS_INTR_IORL); | 
|  | 1138 |  | 
|  | 1139 | return (0); | 
|  | 1140 | } | 
|  | 1141 |  | 
|  | 1142 | /****************************************************************************/ | 
|  | 1143 | /*                                                                          */ | 
|  | 1144 | /* Routine Name: ips_biosparam                                              */ | 
|  | 1145 | /*                                                                          */ | 
|  | 1146 | /* Routine Description:                                                     */ | 
|  | 1147 | /*                                                                          */ | 
|  | 1148 | /*   Set bios geometry for the controller                                   */ | 
|  | 1149 | /*                                                                          */ | 
|  | 1150 | /****************************************************************************/ | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 1151 | static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, | 
|  | 1152 | sector_t capacity, int geom[]) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1153 | { | 
|  | 1154 | ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1155 | int heads; | 
|  | 1156 | int sectors; | 
|  | 1157 | int cylinders; | 
|  | 1158 |  | 
|  | 1159 | METHOD_TRACE("ips_biosparam", 1); | 
|  | 1160 |  | 
|  | 1161 | if (!ha) | 
|  | 1162 | /* ?!?! host adater info invalid */ | 
|  | 1163 | return (0); | 
|  | 1164 |  | 
|  | 1165 | if (!ha->active) | 
|  | 1166 | return (0); | 
|  | 1167 |  | 
|  | 1168 | if (!ips_read_adapter_status(ha, IPS_INTR_ON)) | 
|  | 1169 | /* ?!?! Enquiry command failed */ | 
|  | 1170 | return (0); | 
|  | 1171 |  | 
|  | 1172 | if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) { | 
|  | 1173 | heads = IPS_NORM_HEADS; | 
|  | 1174 | sectors = IPS_NORM_SECTORS; | 
|  | 1175 | } else { | 
|  | 1176 | heads = IPS_COMP_HEADS; | 
|  | 1177 | sectors = IPS_COMP_SECTORS; | 
|  | 1178 | } | 
|  | 1179 |  | 
|  | 1180 | cylinders = (unsigned long) capacity / (heads * sectors); | 
|  | 1181 |  | 
|  | 1182 | DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d", | 
|  | 1183 | heads, sectors, cylinders); | 
|  | 1184 |  | 
|  | 1185 | geom[0] = heads; | 
|  | 1186 | geom[1] = sectors; | 
|  | 1187 | geom[2] = cylinders; | 
|  | 1188 |  | 
|  | 1189 | return (0); | 
|  | 1190 | } | 
|  | 1191 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1192 | /****************************************************************************/ | 
|  | 1193 | /*                                                                          */ | 
|  | 1194 | /* Routine Name: ips_slave_configure                                        */ | 
|  | 1195 | /*                                                                          */ | 
|  | 1196 | /* Routine Description:                                                     */ | 
|  | 1197 | /*                                                                          */ | 
|  | 1198 | /*   Set queue depths on devices once scan is complete                      */ | 
|  | 1199 | /*                                                                          */ | 
|  | 1200 | /****************************************************************************/ | 
|  | 1201 | static int | 
| Christoph Hellwig | f64a181 | 2005-10-31 18:32:08 +0100 | [diff] [blame] | 1202 | ips_slave_configure(struct scsi_device * SDptr) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1203 | { | 
|  | 1204 | ips_ha_t *ha; | 
|  | 1205 | int min; | 
|  | 1206 |  | 
|  | 1207 | ha = IPS_HA(SDptr->host); | 
|  | 1208 | if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) { | 
|  | 1209 | min = ha->max_cmds / 2; | 
|  | 1210 | if (ha->enq->ucLogDriveCount <= 2) | 
|  | 1211 | min = ha->max_cmds - 1; | 
|  | 1212 | scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); | 
|  | 1213 | } | 
| Jack Hammer | 560c26c | 2006-01-13 10:06:50 -0500 | [diff] [blame] | 1214 |  | 
|  | 1215 | SDptr->skip_ms_page_8 = 1; | 
|  | 1216 | SDptr->skip_ms_page_3f = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1217 | return 0; | 
|  | 1218 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1219 |  | 
|  | 1220 | /****************************************************************************/ | 
|  | 1221 | /*                                                                          */ | 
|  | 1222 | /* Routine Name: do_ipsintr                                                 */ | 
|  | 1223 | /*                                                                          */ | 
|  | 1224 | /* Routine Description:                                                     */ | 
|  | 1225 | /*                                                                          */ | 
|  | 1226 | /*   Wrapper for the interrupt handler                                      */ | 
|  | 1227 | /*                                                                          */ | 
|  | 1228 | /****************************************************************************/ | 
|  | 1229 | static irqreturn_t | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 1230 | do_ipsintr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1231 | { | 
|  | 1232 | ips_ha_t *ha; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1233 | struct Scsi_Host *host; | 
|  | 1234 | int irqstatus; | 
|  | 1235 |  | 
|  | 1236 | METHOD_TRACE("do_ipsintr", 2); | 
|  | 1237 |  | 
|  | 1238 | ha = (ips_ha_t *) dev_id; | 
|  | 1239 | if (!ha) | 
|  | 1240 | return IRQ_NONE; | 
|  | 1241 | host = ips_sh[ha->host_num]; | 
|  | 1242 | /* interrupt during initialization */ | 
|  | 1243 | if (!host) { | 
|  | 1244 | (*ha->func.intr) (ha); | 
|  | 1245 | return IRQ_HANDLED; | 
|  | 1246 | } | 
|  | 1247 |  | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 1248 | spin_lock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1249 |  | 
|  | 1250 | if (!ha->active) { | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 1251 | spin_unlock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1252 | return IRQ_HANDLED; | 
|  | 1253 | } | 
|  | 1254 |  | 
|  | 1255 | irqstatus = (*ha->func.intr) (ha); | 
|  | 1256 |  | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 1257 | spin_unlock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1258 |  | 
|  | 1259 | /* start the next command */ | 
|  | 1260 | ips_next(ha, IPS_INTR_ON); | 
|  | 1261 | return IRQ_RETVAL(irqstatus); | 
|  | 1262 | } | 
|  | 1263 |  | 
|  | 1264 | /****************************************************************************/ | 
|  | 1265 | /*                                                                          */ | 
|  | 1266 | /* Routine Name: ips_intr_copperhead                                        */ | 
|  | 1267 | /*                                                                          */ | 
|  | 1268 | /* Routine Description:                                                     */ | 
|  | 1269 | /*                                                                          */ | 
|  | 1270 | /*   Polling interrupt handler                                              */ | 
|  | 1271 | /*                                                                          */ | 
|  | 1272 | /*   ASSUMES interrupts are disabled                                        */ | 
|  | 1273 | /*                                                                          */ | 
|  | 1274 | /****************************************************************************/ | 
|  | 1275 | int | 
|  | 1276 | ips_intr_copperhead(ips_ha_t * ha) | 
|  | 1277 | { | 
|  | 1278 | ips_stat_t *sp; | 
|  | 1279 | ips_scb_t *scb; | 
|  | 1280 | IPS_STATUS cstatus; | 
|  | 1281 | int intrstatus; | 
|  | 1282 |  | 
|  | 1283 | METHOD_TRACE("ips_intr", 2); | 
|  | 1284 |  | 
|  | 1285 | if (!ha) | 
|  | 1286 | return 0; | 
|  | 1287 |  | 
|  | 1288 | if (!ha->active) | 
|  | 1289 | return 0; | 
|  | 1290 |  | 
|  | 1291 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1292 |  | 
|  | 1293 | if (!intrstatus) { | 
|  | 1294 | /* | 
|  | 1295 | * Unexpected/Shared interrupt | 
|  | 1296 | */ | 
|  | 1297 |  | 
|  | 1298 | return 0; | 
|  | 1299 | } | 
|  | 1300 |  | 
|  | 1301 | while (TRUE) { | 
|  | 1302 | sp = &ha->sp; | 
|  | 1303 |  | 
|  | 1304 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1305 |  | 
|  | 1306 | if (!intrstatus) | 
|  | 1307 | break; | 
|  | 1308 | else | 
|  | 1309 | cstatus.value = (*ha->func.statupd) (ha); | 
|  | 1310 |  | 
|  | 1311 | if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { | 
|  | 1312 | /* Spurious Interupt ? */ | 
|  | 1313 | continue; | 
|  | 1314 | } | 
|  | 1315 |  | 
|  | 1316 | ips_chkstatus(ha, &cstatus); | 
|  | 1317 | scb = (ips_scb_t *) sp->scb_addr; | 
|  | 1318 |  | 
|  | 1319 | /* | 
|  | 1320 | * use the callback function to finish things up | 
|  | 1321 | * NOTE: interrupts are OFF for this | 
|  | 1322 | */ | 
|  | 1323 | (*scb->callback) (ha, scb); | 
|  | 1324 | }			/* end while */ | 
|  | 1325 | return 1; | 
|  | 1326 | } | 
|  | 1327 |  | 
|  | 1328 | /****************************************************************************/ | 
|  | 1329 | /*                                                                          */ | 
|  | 1330 | /* Routine Name: ips_intr_morpheus                                          */ | 
|  | 1331 | /*                                                                          */ | 
|  | 1332 | /* Routine Description:                                                     */ | 
|  | 1333 | /*                                                                          */ | 
|  | 1334 | /*   Polling interrupt handler                                              */ | 
|  | 1335 | /*                                                                          */ | 
|  | 1336 | /*   ASSUMES interrupts are disabled                                        */ | 
|  | 1337 | /*                                                                          */ | 
|  | 1338 | /****************************************************************************/ | 
|  | 1339 | int | 
|  | 1340 | ips_intr_morpheus(ips_ha_t * ha) | 
|  | 1341 | { | 
|  | 1342 | ips_stat_t *sp; | 
|  | 1343 | ips_scb_t *scb; | 
|  | 1344 | IPS_STATUS cstatus; | 
|  | 1345 | int intrstatus; | 
|  | 1346 |  | 
|  | 1347 | METHOD_TRACE("ips_intr_morpheus", 2); | 
|  | 1348 |  | 
|  | 1349 | if (!ha) | 
|  | 1350 | return 0; | 
|  | 1351 |  | 
|  | 1352 | if (!ha->active) | 
|  | 1353 | return 0; | 
|  | 1354 |  | 
|  | 1355 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1356 |  | 
|  | 1357 | if (!intrstatus) { | 
|  | 1358 | /* | 
|  | 1359 | * Unexpected/Shared interrupt | 
|  | 1360 | */ | 
|  | 1361 |  | 
|  | 1362 | return 0; | 
|  | 1363 | } | 
|  | 1364 |  | 
|  | 1365 | while (TRUE) { | 
|  | 1366 | sp = &ha->sp; | 
|  | 1367 |  | 
|  | 1368 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1369 |  | 
|  | 1370 | if (!intrstatus) | 
|  | 1371 | break; | 
|  | 1372 | else | 
|  | 1373 | cstatus.value = (*ha->func.statupd) (ha); | 
|  | 1374 |  | 
|  | 1375 | if (cstatus.value == 0xffffffff) | 
|  | 1376 | /* No more to process */ | 
|  | 1377 | break; | 
|  | 1378 |  | 
|  | 1379 | if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { | 
|  | 1380 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 1381 | "Spurious interrupt; no ccb.\n"); | 
|  | 1382 |  | 
|  | 1383 | continue; | 
|  | 1384 | } | 
|  | 1385 |  | 
|  | 1386 | ips_chkstatus(ha, &cstatus); | 
|  | 1387 | scb = (ips_scb_t *) sp->scb_addr; | 
|  | 1388 |  | 
|  | 1389 | /* | 
|  | 1390 | * use the callback function to finish things up | 
|  | 1391 | * NOTE: interrupts are OFF for this | 
|  | 1392 | */ | 
|  | 1393 | (*scb->callback) (ha, scb); | 
|  | 1394 | }			/* end while */ | 
|  | 1395 | return 1; | 
|  | 1396 | } | 
|  | 1397 |  | 
|  | 1398 | /****************************************************************************/ | 
|  | 1399 | /*                                                                          */ | 
|  | 1400 | /* Routine Name: ips_info                                                   */ | 
|  | 1401 | /*                                                                          */ | 
|  | 1402 | /* Routine Description:                                                     */ | 
|  | 1403 | /*                                                                          */ | 
|  | 1404 | /*   Return info about the driver                                           */ | 
|  | 1405 | /*                                                                          */ | 
|  | 1406 | /****************************************************************************/ | 
|  | 1407 | static const char * | 
|  | 1408 | ips_info(struct Scsi_Host *SH) | 
|  | 1409 | { | 
|  | 1410 | static char buffer[256]; | 
|  | 1411 | char *bp; | 
|  | 1412 | ips_ha_t *ha; | 
|  | 1413 |  | 
|  | 1414 | METHOD_TRACE("ips_info", 1); | 
|  | 1415 |  | 
|  | 1416 | ha = IPS_HA(SH); | 
|  | 1417 |  | 
|  | 1418 | if (!ha) | 
|  | 1419 | return (NULL); | 
|  | 1420 |  | 
|  | 1421 | bp = &buffer[0]; | 
|  | 1422 | memset(bp, 0, sizeof (buffer)); | 
|  | 1423 |  | 
|  | 1424 | sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ", | 
|  | 1425 | IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT); | 
|  | 1426 |  | 
|  | 1427 | if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) { | 
|  | 1428 | strcat(bp, " <"); | 
|  | 1429 | strcat(bp, ips_adapter_name[ha->ad_type - 1]); | 
|  | 1430 | strcat(bp, ">"); | 
|  | 1431 | } | 
|  | 1432 |  | 
|  | 1433 | return (bp); | 
|  | 1434 | } | 
|  | 1435 |  | 
|  | 1436 | /****************************************************************************/ | 
|  | 1437 | /*                                                                          */ | 
|  | 1438 | /* Routine Name: ips_proc_info                                              */ | 
|  | 1439 | /*                                                                          */ | 
|  | 1440 | /* Routine Description:                                                     */ | 
|  | 1441 | /*                                                                          */ | 
|  | 1442 | /*   The passthru interface for the driver                                  */ | 
|  | 1443 | /*                                                                          */ | 
|  | 1444 | /****************************************************************************/ | 
|  | 1445 | static int | 
|  | 1446 | ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, | 
|  | 1447 | int length, int func) | 
|  | 1448 | { | 
|  | 1449 | int i; | 
|  | 1450 | int ret; | 
|  | 1451 | ips_ha_t *ha = NULL; | 
|  | 1452 |  | 
|  | 1453 | METHOD_TRACE("ips_proc_info", 1); | 
|  | 1454 |  | 
|  | 1455 | /* Find our host structure */ | 
|  | 1456 | for (i = 0; i < ips_next_controller; i++) { | 
|  | 1457 | if (ips_sh[i]) { | 
|  | 1458 | if (ips_sh[i] == host) { | 
|  | 1459 | ha = (ips_ha_t *) ips_sh[i]->hostdata; | 
|  | 1460 | break; | 
|  | 1461 | } | 
|  | 1462 | } | 
|  | 1463 | } | 
|  | 1464 |  | 
|  | 1465 | if (!ha) | 
|  | 1466 | return (-EINVAL); | 
|  | 1467 |  | 
|  | 1468 | if (func) { | 
|  | 1469 | /* write */ | 
|  | 1470 | return (0); | 
|  | 1471 | } else { | 
|  | 1472 | /* read */ | 
|  | 1473 | if (start) | 
|  | 1474 | *start = buffer; | 
|  | 1475 |  | 
|  | 1476 | ret = ips_host_info(ha, buffer, offset, length); | 
|  | 1477 |  | 
|  | 1478 | return (ret); | 
|  | 1479 | } | 
|  | 1480 | } | 
|  | 1481 |  | 
|  | 1482 | /*--------------------------------------------------------------------------*/ | 
|  | 1483 | /* Helper Functions                                                         */ | 
|  | 1484 | /*--------------------------------------------------------------------------*/ | 
|  | 1485 |  | 
|  | 1486 | /****************************************************************************/ | 
|  | 1487 | /*                                                                          */ | 
|  | 1488 | /* Routine Name: ips_is_passthru                                            */ | 
|  | 1489 | /*                                                                          */ | 
|  | 1490 | /* Routine Description:                                                     */ | 
|  | 1491 | /*                                                                          */ | 
|  | 1492 | /*   Determine if the specified SCSI command is really a passthru command   */ | 
|  | 1493 | /*                                                                          */ | 
|  | 1494 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 1495 | static int ips_is_passthru(struct scsi_cmnd *SC) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1496 | { | 
| Jack Hammer | a3632fa | 2005-10-25 14:13:03 -0400 | [diff] [blame] | 1497 | unsigned long flags; | 
|  | 1498 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1499 | METHOD_TRACE("ips_is_passthru", 1); | 
|  | 1500 |  | 
|  | 1501 | if (!SC) | 
|  | 1502 | return (0); | 
|  | 1503 |  | 
|  | 1504 | if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) && | 
|  | 1505 | (SC->device->channel == 0) && | 
|  | 1506 | (SC->device->id == IPS_ADAPTER_ID) && | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 1507 | (SC->device->lun == 0) && scsi_sglist(SC)) { | 
|  | 1508 | struct scatterlist *sg = scsi_sglist(SC); | 
|  | 1509 | char  *buffer; | 
| Jack Hammer | a3632fa | 2005-10-25 14:13:03 -0400 | [diff] [blame] | 1510 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 1511 | /* kmap_atomic() ensures addressability of the user buffer.*/ | 
|  | 1512 | /* local_irq_save() protects the KM_IRQ0 address slot.     */ | 
|  | 1513 | local_irq_save(flags); | 
| Jens Axboe | 45711f1 | 2007-10-22 21:19:53 +0200 | [diff] [blame] | 1514 | buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 1515 | if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && | 
|  | 1516 | buffer[2] == 'P' && buffer[3] == 'P') { | 
|  | 1517 | kunmap_atomic(buffer - sg->offset, KM_IRQ0); | 
|  | 1518 | local_irq_restore(flags); | 
|  | 1519 | return 1; | 
|  | 1520 | } | 
|  | 1521 | kunmap_atomic(buffer - sg->offset, KM_IRQ0); | 
|  | 1522 | local_irq_restore(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1523 | } | 
|  | 1524 | return 0; | 
|  | 1525 | } | 
|  | 1526 |  | 
|  | 1527 | /****************************************************************************/ | 
|  | 1528 | /*                                                                          */ | 
|  | 1529 | /* Routine Name: ips_alloc_passthru_buffer                                  */ | 
|  | 1530 | /*                                                                          */ | 
|  | 1531 | /* Routine Description:                                                     */ | 
|  | 1532 | /*   allocate a buffer large enough for the ioctl data if the ioctl buffer  */ | 
|  | 1533 | /*   is too small or doesn't exist                                          */ | 
|  | 1534 | /****************************************************************************/ | 
|  | 1535 | static int | 
|  | 1536 | ips_alloc_passthru_buffer(ips_ha_t * ha, int length) | 
|  | 1537 | { | 
|  | 1538 | void *bigger_buf; | 
|  | 1539 | dma_addr_t dma_busaddr; | 
|  | 1540 |  | 
|  | 1541 | if (ha->ioctl_data && length <= ha->ioctl_len) | 
|  | 1542 | return 0; | 
|  | 1543 | /* there is no buffer or it's not big enough, allocate a new one */ | 
|  | 1544 | bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr); | 
|  | 1545 | if (bigger_buf) { | 
|  | 1546 | /* free the old memory */ | 
|  | 1547 | pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data, | 
|  | 1548 | ha->ioctl_busaddr); | 
|  | 1549 | /* use the new memory */ | 
|  | 1550 | ha->ioctl_data = (char *) bigger_buf; | 
|  | 1551 | ha->ioctl_len = length; | 
|  | 1552 | ha->ioctl_busaddr = dma_busaddr; | 
|  | 1553 | } else { | 
|  | 1554 | return -1; | 
|  | 1555 | } | 
|  | 1556 | return 0; | 
|  | 1557 | } | 
|  | 1558 |  | 
|  | 1559 | /****************************************************************************/ | 
|  | 1560 | /*                                                                          */ | 
|  | 1561 | /* Routine Name: ips_make_passthru                                          */ | 
|  | 1562 | /*                                                                          */ | 
|  | 1563 | /* Routine Description:                                                     */ | 
|  | 1564 | /*                                                                          */ | 
|  | 1565 | /*   Make a passthru command out of the info in the Scsi block              */ | 
|  | 1566 | /*                                                                          */ | 
|  | 1567 | /****************************************************************************/ | 
|  | 1568 | static int | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 1569 | ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1570 | { | 
|  | 1571 | ips_passthru_t *pt; | 
|  | 1572 | int length = 0; | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 1573 | int i, ret; | 
|  | 1574 | struct scatterlist *sg = scsi_sglist(SC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1575 |  | 
|  | 1576 | METHOD_TRACE("ips_make_passthru", 1); | 
|  | 1577 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 1578 | scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i) | 
|  | 1579 | length += sg[i].length; | 
|  | 1580 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1581 | if (length < sizeof (ips_passthru_t)) { | 
|  | 1582 | /* wrong size */ | 
|  | 1583 | DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", | 
|  | 1584 | ips_name, ha->host_num); | 
|  | 1585 | return (IPS_FAILURE); | 
|  | 1586 | } | 
|  | 1587 | if (ips_alloc_passthru_buffer(ha, length)) { | 
|  | 1588 | /* allocation failure!  If ha->ioctl_data exists, use it to return | 
|  | 1589 | some error codes.  Return a failed command to the scsi layer. */ | 
|  | 1590 | if (ha->ioctl_data) { | 
|  | 1591 | pt = (ips_passthru_t *) ha->ioctl_data; | 
|  | 1592 | ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t)); | 
|  | 1593 | pt->BasicStatus = 0x0B; | 
|  | 1594 | pt->ExtendedStatus = 0x00; | 
|  | 1595 | ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t)); | 
|  | 1596 | } | 
|  | 1597 | return IPS_FAILURE; | 
|  | 1598 | } | 
|  | 1599 | ha->ioctl_datasize = length; | 
|  | 1600 |  | 
|  | 1601 | ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize); | 
|  | 1602 | pt = (ips_passthru_t *) ha->ioctl_data; | 
|  | 1603 |  | 
|  | 1604 | /* | 
|  | 1605 | * Some notes about the passthru interface used | 
|  | 1606 | * | 
|  | 1607 | * IF the scsi op_code == 0x0d then we assume | 
|  | 1608 | * that the data came along with/goes with the | 
|  | 1609 | * packet we received from the sg driver. In this | 
|  | 1610 | * case the CmdBSize field of the pt structure is | 
|  | 1611 | * used for the size of the buffer. | 
|  | 1612 | */ | 
|  | 1613 |  | 
|  | 1614 | switch (pt->CoppCmd) { | 
|  | 1615 | case IPS_NUMCTRLS: | 
|  | 1616 | memcpy(ha->ioctl_data + sizeof (ips_passthru_t), | 
|  | 1617 | &ips_num_controllers, sizeof (int)); | 
|  | 1618 | ips_scmd_buf_write(SC, ha->ioctl_data, | 
|  | 1619 | sizeof (ips_passthru_t) + sizeof (int)); | 
|  | 1620 | SC->result = DID_OK << 16; | 
|  | 1621 |  | 
|  | 1622 | return (IPS_SUCCESS_IMM); | 
|  | 1623 |  | 
|  | 1624 | case IPS_COPPUSRCMD: | 
|  | 1625 | case IPS_COPPIOCCMD: | 
|  | 1626 | if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { | 
|  | 1627 | if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) { | 
|  | 1628 | /* wrong size */ | 
|  | 1629 | DEBUG_VAR(1, | 
|  | 1630 | "(%s%d) Passthru structure wrong size", | 
|  | 1631 | ips_name, ha->host_num); | 
|  | 1632 |  | 
|  | 1633 | return (IPS_FAILURE); | 
|  | 1634 | } | 
|  | 1635 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 1636 | if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1637 | pt->CoppCP.cmd.flashfw.op_code == | 
|  | 1638 | IPS_CMD_RW_BIOSFW) { | 
|  | 1639 | ret = ips_flash_copperhead(ha, pt, scb); | 
|  | 1640 | ips_scmd_buf_write(SC, ha->ioctl_data, | 
|  | 1641 | sizeof (ips_passthru_t)); | 
|  | 1642 | return ret; | 
|  | 1643 | } | 
|  | 1644 | if (ips_usrcmd(ha, pt, scb)) | 
|  | 1645 | return (IPS_SUCCESS); | 
|  | 1646 | else | 
|  | 1647 | return (IPS_FAILURE); | 
|  | 1648 | } | 
|  | 1649 |  | 
|  | 1650 | break; | 
|  | 1651 |  | 
|  | 1652 | }			/* end switch */ | 
|  | 1653 |  | 
|  | 1654 | return (IPS_FAILURE); | 
|  | 1655 | } | 
|  | 1656 |  | 
|  | 1657 | /****************************************************************************/ | 
|  | 1658 | /* Routine Name: ips_flash_copperhead                                       */ | 
|  | 1659 | /* Routine Description:                                                     */ | 
|  | 1660 | /*   Flash the BIOS/FW on a Copperhead style controller                     */ | 
|  | 1661 | /****************************************************************************/ | 
|  | 1662 | static int | 
|  | 1663 | ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1664 | { | 
|  | 1665 | int datasize; | 
|  | 1666 |  | 
|  | 1667 | /* Trombone is the only copperhead that can do packet flash, but only | 
|  | 1668 | * for firmware. No one said it had to make sence. */ | 
|  | 1669 | if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { | 
|  | 1670 | if (ips_usrcmd(ha, pt, scb)) | 
|  | 1671 | return IPS_SUCCESS; | 
|  | 1672 | else | 
|  | 1673 | return IPS_FAILURE; | 
|  | 1674 | } | 
|  | 1675 | pt->BasicStatus = 0x0B; | 
|  | 1676 | pt->ExtendedStatus = 0; | 
|  | 1677 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 1678 | /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */ | 
|  | 1679 | /* avoid allocating a huge buffer per adapter ( which can fail ). */ | 
|  | 1680 | if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && | 
|  | 1681 | pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { | 
|  | 1682 | pt->BasicStatus = 0; | 
|  | 1683 | return ips_flash_bios(ha, pt, scb); | 
|  | 1684 | } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) { | 
|  | 1685 | if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){ | 
|  | 1686 | ha->flash_data = ips_FlashData; | 
|  | 1687 | ha->flash_busaddr = ips_flashbusaddr; | 
|  | 1688 | ha->flash_len = PAGE_SIZE << 7; | 
|  | 1689 | ha->flash_datasize = 0; | 
|  | 1690 | } else if (!ha->flash_data) { | 
|  | 1691 | datasize = pt->CoppCP.cmd.flashfw.total_packets * | 
|  | 1692 | pt->CoppCP.cmd.flashfw.count; | 
|  | 1693 | ha->flash_data = pci_alloc_consistent(ha->pcidev, | 
|  | 1694 | datasize, | 
|  | 1695 | &ha->flash_busaddr); | 
|  | 1696 | if (!ha->flash_data){ | 
|  | 1697 | printk(KERN_WARNING "Unable to allocate a flash buffer\n"); | 
|  | 1698 | return IPS_FAILURE; | 
|  | 1699 | } | 
|  | 1700 | ha->flash_datasize = 0; | 
|  | 1701 | ha->flash_len = datasize; | 
|  | 1702 | } else | 
|  | 1703 | return IPS_FAILURE; | 
|  | 1704 | } else { | 
|  | 1705 | if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize > | 
|  | 1706 | ha->flash_len) { | 
|  | 1707 | ips_free_flash_copperhead(ha); | 
|  | 1708 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 1709 | "failed size sanity check\n"); | 
|  | 1710 | return IPS_FAILURE; | 
|  | 1711 | } | 
|  | 1712 | } | 
|  | 1713 | if (!ha->flash_data) | 
|  | 1714 | return IPS_FAILURE; | 
|  | 1715 | pt->BasicStatus = 0; | 
|  | 1716 | memcpy(&ha->flash_data[ha->flash_datasize], pt + 1, | 
|  | 1717 | pt->CoppCP.cmd.flashfw.count); | 
|  | 1718 | ha->flash_datasize += pt->CoppCP.cmd.flashfw.count; | 
|  | 1719 | if (pt->CoppCP.cmd.flashfw.packet_num == | 
|  | 1720 | pt->CoppCP.cmd.flashfw.total_packets - 1) { | 
|  | 1721 | if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE) | 
|  | 1722 | return ips_flash_bios(ha, pt, scb); | 
|  | 1723 | else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) | 
|  | 1724 | return ips_flash_firmware(ha, pt, scb); | 
|  | 1725 | } | 
|  | 1726 | return IPS_SUCCESS_IMM; | 
|  | 1727 | } | 
|  | 1728 |  | 
|  | 1729 | /****************************************************************************/ | 
|  | 1730 | /* Routine Name: ips_flash_bios                                             */ | 
|  | 1731 | /* Routine Description:                                                     */ | 
|  | 1732 | /*   flashes the bios of a copperhead adapter                               */ | 
|  | 1733 | /****************************************************************************/ | 
|  | 1734 | static int | 
|  | 1735 | ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1736 | { | 
|  | 1737 |  | 
|  | 1738 | if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && | 
|  | 1739 | pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) { | 
|  | 1740 | if ((!ha->func.programbios) || (!ha->func.erasebios) || | 
|  | 1741 | (!ha->func.verifybios)) | 
|  | 1742 | goto error; | 
|  | 1743 | if ((*ha->func.erasebios) (ha)) { | 
|  | 1744 | DEBUG_VAR(1, | 
|  | 1745 | "(%s%d) flash bios failed - unable to erase flash", | 
|  | 1746 | ips_name, ha->host_num); | 
|  | 1747 | goto error; | 
|  | 1748 | } else | 
|  | 1749 | if ((*ha->func.programbios) (ha, | 
|  | 1750 | ha->flash_data + | 
|  | 1751 | IPS_BIOS_HEADER, | 
|  | 1752 | ha->flash_datasize - | 
|  | 1753 | IPS_BIOS_HEADER, 0)) { | 
|  | 1754 | DEBUG_VAR(1, | 
|  | 1755 | "(%s%d) flash bios failed - unable to flash", | 
|  | 1756 | ips_name, ha->host_num); | 
|  | 1757 | goto error; | 
|  | 1758 | } else | 
|  | 1759 | if ((*ha->func.verifybios) (ha, | 
|  | 1760 | ha->flash_data + | 
|  | 1761 | IPS_BIOS_HEADER, | 
|  | 1762 | ha->flash_datasize - | 
|  | 1763 | IPS_BIOS_HEADER, 0)) { | 
|  | 1764 | DEBUG_VAR(1, | 
|  | 1765 | "(%s%d) flash bios failed - unable to verify flash", | 
|  | 1766 | ips_name, ha->host_num); | 
|  | 1767 | goto error; | 
|  | 1768 | } | 
|  | 1769 | ips_free_flash_copperhead(ha); | 
|  | 1770 | return IPS_SUCCESS_IMM; | 
|  | 1771 | } else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && | 
|  | 1772 | pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { | 
|  | 1773 | if (!ha->func.erasebios) | 
|  | 1774 | goto error; | 
|  | 1775 | if ((*ha->func.erasebios) (ha)) { | 
|  | 1776 | DEBUG_VAR(1, | 
|  | 1777 | "(%s%d) flash bios failed - unable to erase flash", | 
|  | 1778 | ips_name, ha->host_num); | 
|  | 1779 | goto error; | 
|  | 1780 | } | 
|  | 1781 | return IPS_SUCCESS_IMM; | 
|  | 1782 | } | 
|  | 1783 | error: | 
|  | 1784 | pt->BasicStatus = 0x0B; | 
|  | 1785 | pt->ExtendedStatus = 0x00; | 
|  | 1786 | ips_free_flash_copperhead(ha); | 
|  | 1787 | return IPS_FAILURE; | 
|  | 1788 | } | 
|  | 1789 |  | 
|  | 1790 | /****************************************************************************/ | 
|  | 1791 | /*                                                                          */ | 
|  | 1792 | /* Routine Name: ips_fill_scb_sg_single                                     */ | 
|  | 1793 | /*                                                                          */ | 
|  | 1794 | /* Routine Description:                                                     */ | 
|  | 1795 | /*   Fill in a single scb sg_list element from an address                   */ | 
|  | 1796 | /*   return a -1 if a breakup occurred                                      */ | 
|  | 1797 | /****************************************************************************/ | 
|  | 1798 | static int | 
|  | 1799 | ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, | 
|  | 1800 | ips_scb_t * scb, int indx, unsigned int e_len) | 
|  | 1801 | { | 
|  | 1802 |  | 
|  | 1803 | int ret_val = 0; | 
|  | 1804 |  | 
|  | 1805 | if ((scb->data_len + e_len) > ha->max_xfer) { | 
|  | 1806 | e_len = ha->max_xfer - scb->data_len; | 
|  | 1807 | scb->breakup = indx; | 
|  | 1808 | ++scb->sg_break; | 
|  | 1809 | ret_val = -1; | 
|  | 1810 | } else { | 
|  | 1811 | scb->breakup = 0; | 
|  | 1812 | scb->sg_break = 0; | 
|  | 1813 | } | 
|  | 1814 | if (IPS_USE_ENH_SGLIST(ha)) { | 
|  | 1815 | scb->sg_list.enh_list[indx].address_lo = | 
|  | 1816 | cpu_to_le32(pci_dma_lo32(busaddr)); | 
|  | 1817 | scb->sg_list.enh_list[indx].address_hi = | 
|  | 1818 | cpu_to_le32(pci_dma_hi32(busaddr)); | 
|  | 1819 | scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len); | 
|  | 1820 | } else { | 
|  | 1821 | scb->sg_list.std_list[indx].address = | 
|  | 1822 | cpu_to_le32(pci_dma_lo32(busaddr)); | 
|  | 1823 | scb->sg_list.std_list[indx].length = cpu_to_le32(e_len); | 
|  | 1824 | } | 
|  | 1825 |  | 
|  | 1826 | ++scb->sg_len; | 
|  | 1827 | scb->data_len += e_len; | 
|  | 1828 | return ret_val; | 
|  | 1829 | } | 
|  | 1830 |  | 
|  | 1831 | /****************************************************************************/ | 
|  | 1832 | /* Routine Name: ips_flash_firmware                                         */ | 
|  | 1833 | /* Routine Description:                                                     */ | 
|  | 1834 | /*   flashes the firmware of a copperhead adapter                           */ | 
|  | 1835 | /****************************************************************************/ | 
|  | 1836 | static int | 
|  | 1837 | ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1838 | { | 
|  | 1839 | IPS_SG_LIST sg_list; | 
|  | 1840 | uint32_t cmd_busaddr; | 
|  | 1841 |  | 
|  | 1842 | if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE && | 
|  | 1843 | pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) { | 
|  | 1844 | memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND)); | 
|  | 1845 | pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD; | 
|  | 1846 | pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize); | 
|  | 1847 | } else { | 
|  | 1848 | pt->BasicStatus = 0x0B; | 
|  | 1849 | pt->ExtendedStatus = 0x00; | 
|  | 1850 | ips_free_flash_copperhead(ha); | 
|  | 1851 | return IPS_FAILURE; | 
|  | 1852 | } | 
|  | 1853 | /* Save the S/G list pointer so it doesn't get clobbered */ | 
|  | 1854 | sg_list.list = scb->sg_list.list; | 
|  | 1855 | cmd_busaddr = scb->scb_busaddr; | 
|  | 1856 | /* copy in the CP */ | 
|  | 1857 | memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); | 
|  | 1858 | /* FIX stuff that might be wrong */ | 
|  | 1859 | scb->sg_list.list = sg_list.list; | 
|  | 1860 | scb->scb_busaddr = cmd_busaddr; | 
|  | 1861 | scb->bus = scb->scsi_cmd->device->channel; | 
|  | 1862 | scb->target_id = scb->scsi_cmd->device->id; | 
|  | 1863 | scb->lun = scb->scsi_cmd->device->lun; | 
|  | 1864 | scb->sg_len = 0; | 
|  | 1865 | scb->data_len = 0; | 
|  | 1866 | scb->flags = 0; | 
|  | 1867 | scb->op_code = 0; | 
|  | 1868 | scb->callback = ipsintr_done; | 
|  | 1869 | scb->timeout = ips_cmd_timeout; | 
|  | 1870 |  | 
|  | 1871 | scb->data_len = ha->flash_datasize; | 
|  | 1872 | scb->data_busaddr = | 
|  | 1873 | pci_map_single(ha->pcidev, ha->flash_data, scb->data_len, | 
|  | 1874 | IPS_DMA_DIR(scb)); | 
|  | 1875 | scb->flags |= IPS_SCB_MAP_SINGLE; | 
|  | 1876 | scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 1877 | scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr); | 
|  | 1878 | if (pt->TimeOut) | 
|  | 1879 | scb->timeout = pt->TimeOut; | 
|  | 1880 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 1881 | return IPS_SUCCESS; | 
|  | 1882 | } | 
|  | 1883 |  | 
|  | 1884 | /****************************************************************************/ | 
|  | 1885 | /* Routine Name: ips_free_flash_copperhead                                  */ | 
|  | 1886 | /* Routine Description:                                                     */ | 
|  | 1887 | /*   release the memory resources used to hold the flash image              */ | 
|  | 1888 | /****************************************************************************/ | 
|  | 1889 | static void | 
|  | 1890 | ips_free_flash_copperhead(ips_ha_t * ha) | 
|  | 1891 | { | 
|  | 1892 | if (ha->flash_data == ips_FlashData) | 
|  | 1893 | test_and_clear_bit(0, &ips_FlashDataInUse); | 
|  | 1894 | else if (ha->flash_data) | 
|  | 1895 | pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data, | 
|  | 1896 | ha->flash_busaddr); | 
|  | 1897 | ha->flash_data = NULL; | 
|  | 1898 | } | 
|  | 1899 |  | 
|  | 1900 | /****************************************************************************/ | 
|  | 1901 | /*                                                                          */ | 
|  | 1902 | /* Routine Name: ips_usrcmd                                                 */ | 
|  | 1903 | /*                                                                          */ | 
|  | 1904 | /* Routine Description:                                                     */ | 
|  | 1905 | /*                                                                          */ | 
|  | 1906 | /*   Process a user command and make it ready to send                       */ | 
|  | 1907 | /*                                                                          */ | 
|  | 1908 | /****************************************************************************/ | 
|  | 1909 | static int | 
|  | 1910 | ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1911 | { | 
|  | 1912 | IPS_SG_LIST sg_list; | 
|  | 1913 | uint32_t cmd_busaddr; | 
|  | 1914 |  | 
|  | 1915 | METHOD_TRACE("ips_usrcmd", 1); | 
|  | 1916 |  | 
|  | 1917 | if ((!scb) || (!pt) || (!ha)) | 
|  | 1918 | return (0); | 
|  | 1919 |  | 
|  | 1920 | /* Save the S/G list pointer so it doesn't get clobbered */ | 
|  | 1921 | sg_list.list = scb->sg_list.list; | 
|  | 1922 | cmd_busaddr = scb->scb_busaddr; | 
|  | 1923 | /* copy in the CP */ | 
|  | 1924 | memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); | 
|  | 1925 | memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE)); | 
|  | 1926 |  | 
|  | 1927 | /* FIX stuff that might be wrong */ | 
|  | 1928 | scb->sg_list.list = sg_list.list; | 
|  | 1929 | scb->scb_busaddr = cmd_busaddr; | 
|  | 1930 | scb->bus = scb->scsi_cmd->device->channel; | 
|  | 1931 | scb->target_id = scb->scsi_cmd->device->id; | 
|  | 1932 | scb->lun = scb->scsi_cmd->device->lun; | 
|  | 1933 | scb->sg_len = 0; | 
|  | 1934 | scb->data_len = 0; | 
|  | 1935 | scb->flags = 0; | 
|  | 1936 | scb->op_code = 0; | 
|  | 1937 | scb->callback = ipsintr_done; | 
|  | 1938 | scb->timeout = ips_cmd_timeout; | 
|  | 1939 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 1940 |  | 
|  | 1941 | /* we don't support DCDB/READ/WRITE Scatter Gather */ | 
|  | 1942 | if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) || | 
|  | 1943 | (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) || | 
|  | 1944 | (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG)) | 
|  | 1945 | return (0); | 
|  | 1946 |  | 
|  | 1947 | if (pt->CmdBSize) { | 
|  | 1948 | scb->data_len = pt->CmdBSize; | 
|  | 1949 | scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t); | 
|  | 1950 | } else { | 
|  | 1951 | scb->data_busaddr = 0L; | 
|  | 1952 | } | 
|  | 1953 |  | 
|  | 1954 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) | 
|  | 1955 | scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + | 
|  | 1956 | (unsigned long) &scb-> | 
|  | 1957 | dcdb - | 
|  | 1958 | (unsigned long) scb); | 
|  | 1959 |  | 
|  | 1960 | if (pt->CmdBSize) { | 
|  | 1961 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) | 
|  | 1962 | scb->dcdb.buffer_pointer = | 
|  | 1963 | cpu_to_le32(scb->data_busaddr); | 
|  | 1964 | else | 
|  | 1965 | scb->cmd.basic_io.sg_addr = | 
|  | 1966 | cpu_to_le32(scb->data_busaddr); | 
|  | 1967 | } | 
|  | 1968 |  | 
|  | 1969 | /* set timeouts */ | 
|  | 1970 | if (pt->TimeOut) { | 
|  | 1971 | scb->timeout = pt->TimeOut; | 
|  | 1972 |  | 
|  | 1973 | if (pt->TimeOut <= 10) | 
|  | 1974 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; | 
|  | 1975 | else if (pt->TimeOut <= 60) | 
|  | 1976 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; | 
|  | 1977 | else | 
|  | 1978 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; | 
|  | 1979 | } | 
|  | 1980 |  | 
|  | 1981 | /* assume success */ | 
|  | 1982 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 1983 |  | 
|  | 1984 | /* success */ | 
|  | 1985 | return (1); | 
|  | 1986 | } | 
|  | 1987 |  | 
|  | 1988 | /****************************************************************************/ | 
|  | 1989 | /*                                                                          */ | 
|  | 1990 | /* Routine Name: ips_cleanup_passthru                                       */ | 
|  | 1991 | /*                                                                          */ | 
|  | 1992 | /* Routine Description:                                                     */ | 
|  | 1993 | /*                                                                          */ | 
|  | 1994 | /*   Cleanup after a passthru command                                       */ | 
|  | 1995 | /*                                                                          */ | 
|  | 1996 | /****************************************************************************/ | 
|  | 1997 | static void | 
|  | 1998 | ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 1999 | { | 
|  | 2000 | ips_passthru_t *pt; | 
|  | 2001 |  | 
|  | 2002 | METHOD_TRACE("ips_cleanup_passthru", 1); | 
|  | 2003 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 2004 | if ((!scb) || (!scb->scsi_cmd) || (!scsi_sglist(scb->scsi_cmd))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2005 | DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru", | 
|  | 2006 | ips_name, ha->host_num); | 
|  | 2007 |  | 
|  | 2008 | return; | 
|  | 2009 | } | 
|  | 2010 | pt = (ips_passthru_t *) ha->ioctl_data; | 
|  | 2011 |  | 
|  | 2012 | /* Copy data back to the user */ | 
|  | 2013 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)	/* Copy DCDB Back to Caller's Area */ | 
|  | 2014 | memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE)); | 
|  | 2015 |  | 
|  | 2016 | pt->BasicStatus = scb->basic_status; | 
|  | 2017 | pt->ExtendedStatus = scb->extended_status; | 
|  | 2018 | pt->AdapterType = ha->ad_type; | 
|  | 2019 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2020 | if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2021 | (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || | 
|  | 2022 | scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)) | 
|  | 2023 | ips_free_flash_copperhead(ha); | 
|  | 2024 |  | 
|  | 2025 | ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize); | 
|  | 2026 | } | 
|  | 2027 |  | 
|  | 2028 | /****************************************************************************/ | 
|  | 2029 | /*                                                                          */ | 
|  | 2030 | /* Routine Name: ips_host_info                                              */ | 
|  | 2031 | /*                                                                          */ | 
|  | 2032 | /* Routine Description:                                                     */ | 
|  | 2033 | /*                                                                          */ | 
|  | 2034 | /*   The passthru interface for the driver                                  */ | 
|  | 2035 | /*                                                                          */ | 
|  | 2036 | /****************************************************************************/ | 
|  | 2037 | static int | 
|  | 2038 | ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len) | 
|  | 2039 | { | 
|  | 2040 | IPS_INFOSTR info; | 
|  | 2041 |  | 
|  | 2042 | METHOD_TRACE("ips_host_info", 1); | 
|  | 2043 |  | 
|  | 2044 | info.buffer = ptr; | 
|  | 2045 | info.length = len; | 
|  | 2046 | info.offset = offset; | 
|  | 2047 | info.pos = 0; | 
|  | 2048 | info.localpos = 0; | 
|  | 2049 |  | 
|  | 2050 | copy_info(&info, "\nIBM ServeRAID General Information:\n\n"); | 
|  | 2051 |  | 
|  | 2052 | if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) && | 
|  | 2053 | (le16_to_cpu(ha->nvram->adapter_type) != 0)) | 
|  | 2054 | copy_info(&info, "\tController Type                   : %s\n", | 
|  | 2055 | ips_adapter_name[ha->ad_type - 1]); | 
|  | 2056 | else | 
|  | 2057 | copy_info(&info, | 
|  | 2058 | "\tController Type                   : Unknown\n"); | 
|  | 2059 |  | 
|  | 2060 | if (ha->io_addr) | 
|  | 2061 | copy_info(&info, | 
|  | 2062 | "\tIO region                         : 0x%lx (%d bytes)\n", | 
|  | 2063 | ha->io_addr, ha->io_len); | 
|  | 2064 |  | 
|  | 2065 | if (ha->mem_addr) { | 
|  | 2066 | copy_info(&info, | 
|  | 2067 | "\tMemory region                     : 0x%lx (%d bytes)\n", | 
|  | 2068 | ha->mem_addr, ha->mem_len); | 
|  | 2069 | copy_info(&info, | 
|  | 2070 | "\tShared memory address             : 0x%lx\n", | 
|  | 2071 | ha->mem_ptr); | 
|  | 2072 | } | 
|  | 2073 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2074 | copy_info(&info, "\tIRQ number                        : %d\n", ha->pcidev->irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2075 |  | 
|  | 2076 | /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */ | 
|  | 2077 | /* That keeps everything happy for "text" operations on the proc file.                    */ | 
|  | 2078 |  | 
|  | 2079 | if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) { | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 2080 | if (ha->nvram->bios_low[3] == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2081 | copy_info(&info, | 
|  | 2082 | "\tBIOS Version                      : %c%c%c%c%c%c%c\n", | 
|  | 2083 | ha->nvram->bios_high[0], ha->nvram->bios_high[1], | 
|  | 2084 | ha->nvram->bios_high[2], ha->nvram->bios_high[3], | 
|  | 2085 | ha->nvram->bios_low[0], ha->nvram->bios_low[1], | 
|  | 2086 | ha->nvram->bios_low[2]); | 
|  | 2087 |  | 
|  | 2088 | } else { | 
|  | 2089 | copy_info(&info, | 
|  | 2090 | "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n", | 
|  | 2091 | ha->nvram->bios_high[0], ha->nvram->bios_high[1], | 
|  | 2092 | ha->nvram->bios_high[2], ha->nvram->bios_high[3], | 
|  | 2093 | ha->nvram->bios_low[0], ha->nvram->bios_low[1], | 
|  | 2094 | ha->nvram->bios_low[2], ha->nvram->bios_low[3]); | 
|  | 2095 | } | 
|  | 2096 |  | 
|  | 2097 | } | 
|  | 2098 |  | 
|  | 2099 | if (ha->enq->CodeBlkVersion[7] == 0) { | 
|  | 2100 | copy_info(&info, | 
|  | 2101 | "\tFirmware Version                  : %c%c%c%c%c%c%c\n", | 
|  | 2102 | ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], | 
|  | 2103 | ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], | 
|  | 2104 | ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], | 
|  | 2105 | ha->enq->CodeBlkVersion[6]); | 
|  | 2106 | } else { | 
|  | 2107 | copy_info(&info, | 
|  | 2108 | "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n", | 
|  | 2109 | ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], | 
|  | 2110 | ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], | 
|  | 2111 | ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], | 
|  | 2112 | ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]); | 
|  | 2113 | } | 
|  | 2114 |  | 
|  | 2115 | if (ha->enq->BootBlkVersion[7] == 0) { | 
|  | 2116 | copy_info(&info, | 
|  | 2117 | "\tBoot Block Version                : %c%c%c%c%c%c%c\n", | 
|  | 2118 | ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], | 
|  | 2119 | ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], | 
|  | 2120 | ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], | 
|  | 2121 | ha->enq->BootBlkVersion[6]); | 
|  | 2122 | } else { | 
|  | 2123 | copy_info(&info, | 
|  | 2124 | "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n", | 
|  | 2125 | ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], | 
|  | 2126 | ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], | 
|  | 2127 | ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], | 
|  | 2128 | ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]); | 
|  | 2129 | } | 
|  | 2130 |  | 
|  | 2131 | copy_info(&info, "\tDriver Version                    : %s%s\n", | 
|  | 2132 | IPS_VERSION_HIGH, IPS_VERSION_LOW); | 
|  | 2133 |  | 
|  | 2134 | copy_info(&info, "\tDriver Build                      : %d\n", | 
|  | 2135 | IPS_BUILD_IDENT); | 
|  | 2136 |  | 
|  | 2137 | copy_info(&info, "\tMax Physical Devices              : %d\n", | 
|  | 2138 | ha->enq->ucMaxPhysicalDevices); | 
|  | 2139 | copy_info(&info, "\tMax Active Commands               : %d\n", | 
|  | 2140 | ha->max_cmds); | 
|  | 2141 | copy_info(&info, "\tCurrent Queued Commands           : %d\n", | 
|  | 2142 | ha->scb_waitlist.count); | 
|  | 2143 | copy_info(&info, "\tCurrent Active Commands           : %d\n", | 
|  | 2144 | ha->scb_activelist.count - ha->num_ioctl); | 
|  | 2145 | copy_info(&info, "\tCurrent Queued PT Commands        : %d\n", | 
|  | 2146 | ha->copp_waitlist.count); | 
|  | 2147 | copy_info(&info, "\tCurrent Active PT Commands        : %d\n", | 
|  | 2148 | ha->num_ioctl); | 
|  | 2149 |  | 
|  | 2150 | copy_info(&info, "\n"); | 
|  | 2151 |  | 
|  | 2152 | return (info.localpos); | 
|  | 2153 | } | 
|  | 2154 |  | 
|  | 2155 | /****************************************************************************/ | 
|  | 2156 | /*                                                                          */ | 
|  | 2157 | /* Routine Name: copy_mem_info                                              */ | 
|  | 2158 | /*                                                                          */ | 
|  | 2159 | /* Routine Description:                                                     */ | 
|  | 2160 | /*                                                                          */ | 
|  | 2161 | /*   Copy data into an IPS_INFOSTR structure                                */ | 
|  | 2162 | /*                                                                          */ | 
|  | 2163 | /****************************************************************************/ | 
|  | 2164 | static void | 
|  | 2165 | copy_mem_info(IPS_INFOSTR * info, char *data, int len) | 
|  | 2166 | { | 
|  | 2167 | METHOD_TRACE("copy_mem_info", 1); | 
|  | 2168 |  | 
|  | 2169 | if (info->pos + len < info->offset) { | 
|  | 2170 | info->pos += len; | 
|  | 2171 | return; | 
|  | 2172 | } | 
|  | 2173 |  | 
|  | 2174 | if (info->pos < info->offset) { | 
|  | 2175 | data += (info->offset - info->pos); | 
|  | 2176 | len -= (info->offset - info->pos); | 
|  | 2177 | info->pos += (info->offset - info->pos); | 
|  | 2178 | } | 
|  | 2179 |  | 
|  | 2180 | if (info->localpos + len > info->length) | 
|  | 2181 | len = info->length - info->localpos; | 
|  | 2182 |  | 
|  | 2183 | if (len > 0) { | 
|  | 2184 | memcpy(info->buffer + info->localpos, data, len); | 
|  | 2185 | info->pos += len; | 
|  | 2186 | info->localpos += len; | 
|  | 2187 | } | 
|  | 2188 | } | 
|  | 2189 |  | 
|  | 2190 | /****************************************************************************/ | 
|  | 2191 | /*                                                                          */ | 
|  | 2192 | /* Routine Name: copy_info                                                  */ | 
|  | 2193 | /*                                                                          */ | 
|  | 2194 | /* Routine Description:                                                     */ | 
|  | 2195 | /*                                                                          */ | 
|  | 2196 | /*   printf style wrapper for an info structure                             */ | 
|  | 2197 | /*                                                                          */ | 
|  | 2198 | /****************************************************************************/ | 
|  | 2199 | static int | 
|  | 2200 | copy_info(IPS_INFOSTR * info, char *fmt, ...) | 
|  | 2201 | { | 
|  | 2202 | va_list args; | 
|  | 2203 | char buf[128]; | 
|  | 2204 | int len; | 
|  | 2205 |  | 
|  | 2206 | METHOD_TRACE("copy_info", 1); | 
|  | 2207 |  | 
|  | 2208 | va_start(args, fmt); | 
|  | 2209 | len = vsprintf(buf, fmt, args); | 
|  | 2210 | va_end(args); | 
|  | 2211 |  | 
|  | 2212 | copy_mem_info(info, buf, len); | 
|  | 2213 |  | 
|  | 2214 | return (len); | 
|  | 2215 | } | 
|  | 2216 |  | 
|  | 2217 | /****************************************************************************/ | 
|  | 2218 | /*                                                                          */ | 
|  | 2219 | /* Routine Name: ips_identify_controller                                    */ | 
|  | 2220 | /*                                                                          */ | 
|  | 2221 | /* Routine Description:                                                     */ | 
|  | 2222 | /*                                                                          */ | 
|  | 2223 | /*   Identify this controller                                               */ | 
|  | 2224 | /*                                                                          */ | 
|  | 2225 | /****************************************************************************/ | 
|  | 2226 | static void | 
|  | 2227 | ips_identify_controller(ips_ha_t * ha) | 
|  | 2228 | { | 
|  | 2229 | METHOD_TRACE("ips_identify_controller", 1); | 
|  | 2230 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2231 | switch (ha->pcidev->device) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2232 | case IPS_DEVICEID_COPPERHEAD: | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2233 | if (ha->pcidev->revision <= IPS_REVID_SERVERAID) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2234 | ha->ad_type = IPS_ADTYPE_SERVERAID; | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2235 | } else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2236 | ha->ad_type = IPS_ADTYPE_SERVERAID2; | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2237 | } else if (ha->pcidev->revision == IPS_REVID_NAVAJO) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2238 | ha->ad_type = IPS_ADTYPE_NAVAJO; | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2239 | } else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2240 | && (ha->slot_num == 0)) { | 
|  | 2241 | ha->ad_type = IPS_ADTYPE_KIOWA; | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2242 | } else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) && | 
|  | 2243 | (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2244 | if (ha->enq->ucMaxPhysicalDevices == 15) | 
|  | 2245 | ha->ad_type = IPS_ADTYPE_SERVERAID3L; | 
|  | 2246 | else | 
|  | 2247 | ha->ad_type = IPS_ADTYPE_SERVERAID3; | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2248 | } else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) && | 
|  | 2249 | (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2250 | ha->ad_type = IPS_ADTYPE_SERVERAID4H; | 
|  | 2251 | } | 
|  | 2252 | break; | 
|  | 2253 |  | 
|  | 2254 | case IPS_DEVICEID_MORPHEUS: | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2255 | switch (ha->pcidev->subsystem_device) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2256 | case IPS_SUBDEVICEID_4L: | 
|  | 2257 | ha->ad_type = IPS_ADTYPE_SERVERAID4L; | 
|  | 2258 | break; | 
|  | 2259 |  | 
|  | 2260 | case IPS_SUBDEVICEID_4M: | 
|  | 2261 | ha->ad_type = IPS_ADTYPE_SERVERAID4M; | 
|  | 2262 | break; | 
|  | 2263 |  | 
|  | 2264 | case IPS_SUBDEVICEID_4MX: | 
|  | 2265 | ha->ad_type = IPS_ADTYPE_SERVERAID4MX; | 
|  | 2266 | break; | 
|  | 2267 |  | 
|  | 2268 | case IPS_SUBDEVICEID_4LX: | 
|  | 2269 | ha->ad_type = IPS_ADTYPE_SERVERAID4LX; | 
|  | 2270 | break; | 
|  | 2271 |  | 
|  | 2272 | case IPS_SUBDEVICEID_5I2: | 
|  | 2273 | ha->ad_type = IPS_ADTYPE_SERVERAID5I2; | 
|  | 2274 | break; | 
|  | 2275 |  | 
|  | 2276 | case IPS_SUBDEVICEID_5I1: | 
|  | 2277 | ha->ad_type = IPS_ADTYPE_SERVERAID5I1; | 
|  | 2278 | break; | 
|  | 2279 | } | 
|  | 2280 |  | 
|  | 2281 | break; | 
|  | 2282 |  | 
|  | 2283 | case IPS_DEVICEID_MARCO: | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2284 | switch (ha->pcidev->subsystem_device) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2285 | case IPS_SUBDEVICEID_6M: | 
|  | 2286 | ha->ad_type = IPS_ADTYPE_SERVERAID6M; | 
|  | 2287 | break; | 
|  | 2288 | case IPS_SUBDEVICEID_6I: | 
|  | 2289 | ha->ad_type = IPS_ADTYPE_SERVERAID6I; | 
|  | 2290 | break; | 
|  | 2291 | case IPS_SUBDEVICEID_7k: | 
|  | 2292 | ha->ad_type = IPS_ADTYPE_SERVERAID7k; | 
|  | 2293 | break; | 
|  | 2294 | case IPS_SUBDEVICEID_7M: | 
|  | 2295 | ha->ad_type = IPS_ADTYPE_SERVERAID7M; | 
|  | 2296 | break; | 
|  | 2297 | } | 
|  | 2298 | break; | 
|  | 2299 | } | 
|  | 2300 | } | 
|  | 2301 |  | 
|  | 2302 | /****************************************************************************/ | 
|  | 2303 | /*                                                                          */ | 
|  | 2304 | /* Routine Name: ips_get_bios_version                                       */ | 
|  | 2305 | /*                                                                          */ | 
|  | 2306 | /* Routine Description:                                                     */ | 
|  | 2307 | /*                                                                          */ | 
|  | 2308 | /*   Get the BIOS revision number                                           */ | 
|  | 2309 | /*                                                                          */ | 
|  | 2310 | /****************************************************************************/ | 
|  | 2311 | static void | 
|  | 2312 | ips_get_bios_version(ips_ha_t * ha, int intr) | 
|  | 2313 | { | 
|  | 2314 | ips_scb_t *scb; | 
|  | 2315 | int ret; | 
|  | 2316 | uint8_t major; | 
|  | 2317 | uint8_t minor; | 
|  | 2318 | uint8_t subminor; | 
|  | 2319 | uint8_t *buffer; | 
|  | 2320 | char hexDigits[] = | 
|  | 2321 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', | 
|  | 2322 | 'D', 'E', 'F' }; | 
|  | 2323 |  | 
|  | 2324 | METHOD_TRACE("ips_get_bios_version", 1); | 
|  | 2325 |  | 
|  | 2326 | major = 0; | 
|  | 2327 | minor = 0; | 
|  | 2328 |  | 
|  | 2329 | strncpy(ha->bios_version, "       ?", 8); | 
|  | 2330 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2331 | if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2332 | if (IPS_USE_MEMIO(ha)) { | 
|  | 2333 | /* Memory Mapped I/O */ | 
|  | 2334 |  | 
|  | 2335 | /* test 1st byte */ | 
|  | 2336 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2337 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2338 | udelay(25);	/* 25 us */ | 
|  | 2339 |  | 
|  | 2340 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) | 
|  | 2341 | return; | 
|  | 2342 |  | 
|  | 2343 | writel(1, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2344 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2345 | udelay(25);	/* 25 us */ | 
|  | 2346 |  | 
|  | 2347 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) | 
|  | 2348 | return; | 
|  | 2349 |  | 
|  | 2350 | /* Get Major version */ | 
|  | 2351 | writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2352 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2353 | udelay(25);	/* 25 us */ | 
|  | 2354 |  | 
|  | 2355 | major = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 2356 |  | 
|  | 2357 | /* Get Minor version */ | 
|  | 2358 | writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2359 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2360 | udelay(25);	/* 25 us */ | 
|  | 2361 | minor = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 2362 |  | 
|  | 2363 | /* Get SubMinor version */ | 
|  | 2364 | writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2365 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2366 | udelay(25);	/* 25 us */ | 
|  | 2367 | subminor = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 2368 |  | 
|  | 2369 | } else { | 
|  | 2370 | /* Programmed I/O */ | 
|  | 2371 |  | 
|  | 2372 | /* test 1st byte */ | 
|  | 2373 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2374 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2375 | udelay(25);	/* 25 us */ | 
|  | 2376 |  | 
|  | 2377 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) | 
|  | 2378 | return; | 
|  | 2379 |  | 
|  | 2380 | outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2381 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2382 | udelay(25);	/* 25 us */ | 
|  | 2383 |  | 
|  | 2384 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) | 
|  | 2385 | return; | 
|  | 2386 |  | 
|  | 2387 | /* Get Major version */ | 
|  | 2388 | outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2389 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2390 | udelay(25);	/* 25 us */ | 
|  | 2391 |  | 
|  | 2392 | major = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 2393 |  | 
|  | 2394 | /* Get Minor version */ | 
|  | 2395 | outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2396 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2397 | udelay(25);	/* 25 us */ | 
|  | 2398 |  | 
|  | 2399 | minor = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 2400 |  | 
|  | 2401 | /* Get SubMinor version */ | 
|  | 2402 | outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 2403 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2404 | udelay(25);	/* 25 us */ | 
|  | 2405 |  | 
|  | 2406 | subminor = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 2407 |  | 
|  | 2408 | } | 
|  | 2409 | } else { | 
|  | 2410 | /* Morpheus Family - Send Command to the card */ | 
|  | 2411 |  | 
|  | 2412 | buffer = ha->ioctl_data; | 
|  | 2413 |  | 
|  | 2414 | memset(buffer, 0, 0x1000); | 
|  | 2415 |  | 
|  | 2416 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 2417 |  | 
|  | 2418 | ips_init_scb(ha, scb); | 
|  | 2419 |  | 
|  | 2420 | scb->timeout = ips_cmd_timeout; | 
|  | 2421 | scb->cdb[0] = IPS_CMD_RW_BIOSFW; | 
|  | 2422 |  | 
|  | 2423 | scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW; | 
|  | 2424 | scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 2425 | scb->cmd.flashfw.type = 1; | 
|  | 2426 | scb->cmd.flashfw.direction = 0; | 
|  | 2427 | scb->cmd.flashfw.count = cpu_to_le32(0x800); | 
|  | 2428 | scb->cmd.flashfw.total_packets = 1; | 
|  | 2429 | scb->cmd.flashfw.packet_num = 0; | 
|  | 2430 | scb->data_len = 0x1000; | 
|  | 2431 | scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr; | 
|  | 2432 |  | 
|  | 2433 | /* issue the command */ | 
|  | 2434 | if (((ret = | 
|  | 2435 | ips_send_wait(ha, scb, ips_cmd_timeout, | 
|  | 2436 | intr)) == IPS_FAILURE) | 
|  | 2437 | || (ret == IPS_SUCCESS_IMM) | 
|  | 2438 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { | 
|  | 2439 | /* Error occurred */ | 
|  | 2440 |  | 
|  | 2441 | return; | 
|  | 2442 | } | 
|  | 2443 |  | 
|  | 2444 | if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) { | 
|  | 2445 | major = buffer[0x1ff + 0xC0];	/* Offset 0x1ff after the header (0xc0) */ | 
|  | 2446 | minor = buffer[0x1fe + 0xC0];	/* Offset 0x1fe after the header (0xc0) */ | 
|  | 2447 | subminor = buffer[0x1fd + 0xC0];	/* Offset 0x1fd after the header (0xc0) */ | 
|  | 2448 | } else { | 
|  | 2449 | return; | 
|  | 2450 | } | 
|  | 2451 | } | 
|  | 2452 |  | 
|  | 2453 | ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4]; | 
|  | 2454 | ha->bios_version[1] = '.'; | 
|  | 2455 | ha->bios_version[2] = hexDigits[major & 0x0F]; | 
|  | 2456 | ha->bios_version[3] = hexDigits[subminor]; | 
|  | 2457 | ha->bios_version[4] = '.'; | 
|  | 2458 | ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4]; | 
|  | 2459 | ha->bios_version[6] = hexDigits[minor & 0x0F]; | 
|  | 2460 | ha->bios_version[7] = 0; | 
|  | 2461 | } | 
|  | 2462 |  | 
|  | 2463 | /****************************************************************************/ | 
|  | 2464 | /*                                                                          */ | 
|  | 2465 | /* Routine Name: ips_hainit                                                 */ | 
|  | 2466 | /*                                                                          */ | 
|  | 2467 | /* Routine Description:                                                     */ | 
|  | 2468 | /*                                                                          */ | 
|  | 2469 | /*   Initialize the controller                                              */ | 
|  | 2470 | /*                                                                          */ | 
|  | 2471 | /* NOTE: Assumes to be called from with a lock                              */ | 
|  | 2472 | /*                                                                          */ | 
|  | 2473 | /****************************************************************************/ | 
|  | 2474 | static int | 
|  | 2475 | ips_hainit(ips_ha_t * ha) | 
|  | 2476 | { | 
|  | 2477 | int i; | 
|  | 2478 | struct timeval tv; | 
|  | 2479 |  | 
|  | 2480 | METHOD_TRACE("ips_hainit", 1); | 
|  | 2481 |  | 
|  | 2482 | if (!ha) | 
|  | 2483 | return (0); | 
|  | 2484 |  | 
|  | 2485 | if (ha->func.statinit) | 
|  | 2486 | (*ha->func.statinit) (ha); | 
|  | 2487 |  | 
|  | 2488 | if (ha->func.enableint) | 
|  | 2489 | (*ha->func.enableint) (ha); | 
|  | 2490 |  | 
|  | 2491 | /* Send FFDC */ | 
|  | 2492 | ha->reset_count = 1; | 
|  | 2493 | do_gettimeofday(&tv); | 
|  | 2494 | ha->last_ffdc = tv.tv_sec; | 
|  | 2495 | ips_ffdc_reset(ha, IPS_INTR_IORL); | 
|  | 2496 |  | 
|  | 2497 | if (!ips_read_config(ha, IPS_INTR_IORL)) { | 
|  | 2498 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2499 | "unable to read config from controller.\n"); | 
|  | 2500 |  | 
|  | 2501 | return (0); | 
|  | 2502 | } | 
|  | 2503 | /* end if */ | 
|  | 2504 | if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) { | 
|  | 2505 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2506 | "unable to read controller status.\n"); | 
|  | 2507 |  | 
|  | 2508 | return (0); | 
|  | 2509 | } | 
|  | 2510 |  | 
|  | 2511 | /* Identify this controller */ | 
|  | 2512 | ips_identify_controller(ha); | 
|  | 2513 |  | 
|  | 2514 | if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) { | 
|  | 2515 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2516 | "unable to read subsystem parameters.\n"); | 
|  | 2517 |  | 
|  | 2518 | return (0); | 
|  | 2519 | } | 
|  | 2520 |  | 
|  | 2521 | /* write nvram user page 5 */ | 
|  | 2522 | if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { | 
|  | 2523 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2524 | "unable to write driver info to controller.\n"); | 
|  | 2525 |  | 
|  | 2526 | return (0); | 
|  | 2527 | } | 
|  | 2528 |  | 
|  | 2529 | /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */ | 
|  | 2530 | if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1)) | 
|  | 2531 | ips_clear_adapter(ha, IPS_INTR_IORL); | 
|  | 2532 |  | 
|  | 2533 | /* set limits on SID, LUN, BUS */ | 
|  | 2534 | ha->ntargets = IPS_MAX_TARGETS + 1; | 
|  | 2535 | ha->nlun = 1; | 
|  | 2536 | ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1; | 
|  | 2537 |  | 
|  | 2538 | switch (ha->conf->logical_drive[0].ucStripeSize) { | 
|  | 2539 | case 4: | 
|  | 2540 | ha->max_xfer = 0x10000; | 
|  | 2541 | break; | 
|  | 2542 |  | 
|  | 2543 | case 5: | 
|  | 2544 | ha->max_xfer = 0x20000; | 
|  | 2545 | break; | 
|  | 2546 |  | 
|  | 2547 | case 6: | 
|  | 2548 | ha->max_xfer = 0x40000; | 
|  | 2549 | break; | 
|  | 2550 |  | 
|  | 2551 | case 7: | 
|  | 2552 | default: | 
|  | 2553 | ha->max_xfer = 0x80000; | 
|  | 2554 | break; | 
|  | 2555 | } | 
|  | 2556 |  | 
|  | 2557 | /* setup max concurrent commands */ | 
|  | 2558 | if (le32_to_cpu(ha->subsys->param[4]) & 0x1) { | 
|  | 2559 | /* Use the new method */ | 
|  | 2560 | ha->max_cmds = ha->enq->ucConcurrentCmdCount; | 
|  | 2561 | } else { | 
|  | 2562 | /* use the old method */ | 
|  | 2563 | switch (ha->conf->logical_drive[0].ucStripeSize) { | 
|  | 2564 | case 4: | 
|  | 2565 | ha->max_cmds = 32; | 
|  | 2566 | break; | 
|  | 2567 |  | 
|  | 2568 | case 5: | 
|  | 2569 | ha->max_cmds = 16; | 
|  | 2570 | break; | 
|  | 2571 |  | 
|  | 2572 | case 6: | 
|  | 2573 | ha->max_cmds = 8; | 
|  | 2574 | break; | 
|  | 2575 |  | 
|  | 2576 | case 7: | 
|  | 2577 | default: | 
|  | 2578 | ha->max_cmds = 4; | 
|  | 2579 | break; | 
|  | 2580 | } | 
|  | 2581 | } | 
|  | 2582 |  | 
|  | 2583 | /* Limit the Active Commands on a Lite Adapter */ | 
|  | 2584 | if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) || | 
|  | 2585 | (ha->ad_type == IPS_ADTYPE_SERVERAID4L) || | 
|  | 2586 | (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) { | 
|  | 2587 | if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) | 
|  | 2588 | ha->max_cmds = MaxLiteCmds; | 
|  | 2589 | } | 
|  | 2590 |  | 
|  | 2591 | /* set controller IDs */ | 
|  | 2592 | ha->ha_id[0] = IPS_ADAPTER_ID; | 
|  | 2593 | for (i = 1; i < ha->nbus; i++) { | 
|  | 2594 | ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f; | 
|  | 2595 | ha->dcdb_active[i - 1] = 0; | 
|  | 2596 | } | 
|  | 2597 |  | 
|  | 2598 | return (1); | 
|  | 2599 | } | 
|  | 2600 |  | 
|  | 2601 | /****************************************************************************/ | 
|  | 2602 | /*                                                                          */ | 
|  | 2603 | /* Routine Name: ips_next                                                   */ | 
|  | 2604 | /*                                                                          */ | 
|  | 2605 | /* Routine Description:                                                     */ | 
|  | 2606 | /*                                                                          */ | 
|  | 2607 | /*   Take the next command off the queue and send it to the controller      */ | 
|  | 2608 | /*                                                                          */ | 
|  | 2609 | /****************************************************************************/ | 
|  | 2610 | static void | 
|  | 2611 | ips_next(ips_ha_t * ha, int intr) | 
|  | 2612 | { | 
|  | 2613 | ips_scb_t *scb; | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2614 | struct scsi_cmnd *SC; | 
|  | 2615 | struct scsi_cmnd *p; | 
|  | 2616 | struct scsi_cmnd *q; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2617 | ips_copp_wait_item_t *item; | 
|  | 2618 | int ret; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2619 | struct Scsi_Host *host; | 
|  | 2620 | METHOD_TRACE("ips_next", 1); | 
|  | 2621 |  | 
|  | 2622 | if (!ha) | 
|  | 2623 | return; | 
|  | 2624 | host = ips_sh[ha->host_num]; | 
|  | 2625 | /* | 
|  | 2626 | * Block access to the queue function so | 
|  | 2627 | * this command won't time out | 
|  | 2628 | */ | 
|  | 2629 | if (intr == IPS_INTR_ON) | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 2630 | spin_lock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2631 |  | 
|  | 2632 | if ((ha->subsys->param[3] & 0x300000) | 
|  | 2633 | && (ha->scb_activelist.count == 0)) { | 
|  | 2634 | struct timeval tv; | 
|  | 2635 |  | 
|  | 2636 | do_gettimeofday(&tv); | 
|  | 2637 |  | 
|  | 2638 | if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) { | 
|  | 2639 | ha->last_ffdc = tv.tv_sec; | 
|  | 2640 | ips_ffdc_time(ha); | 
|  | 2641 | } | 
|  | 2642 | } | 
|  | 2643 |  | 
|  | 2644 | /* | 
|  | 2645 | * Send passthru commands | 
|  | 2646 | * These have priority over normal I/O | 
|  | 2647 | * but shouldn't affect performance too much | 
|  | 2648 | * since we limit the number that can be active | 
|  | 2649 | * on the card at any one time | 
|  | 2650 | */ | 
|  | 2651 | while ((ha->num_ioctl < IPS_MAX_IOCTL) && | 
|  | 2652 | (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) { | 
|  | 2653 |  | 
|  | 2654 | item = ips_removeq_copp_head(&ha->copp_waitlist); | 
|  | 2655 | ha->num_ioctl++; | 
|  | 2656 | if (intr == IPS_INTR_ON) | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 2657 | spin_unlock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2658 | scb->scsi_cmd = item->scsi_cmd; | 
|  | 2659 | kfree(item); | 
|  | 2660 |  | 
|  | 2661 | ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr); | 
|  | 2662 |  | 
|  | 2663 | if (intr == IPS_INTR_ON) | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 2664 | spin_lock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2665 | switch (ret) { | 
|  | 2666 | case IPS_FAILURE: | 
|  | 2667 | if (scb->scsi_cmd) { | 
|  | 2668 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 2669 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2670 | } | 
|  | 2671 |  | 
|  | 2672 | ips_freescb(ha, scb); | 
|  | 2673 | break; | 
|  | 2674 | case IPS_SUCCESS_IMM: | 
|  | 2675 | if (scb->scsi_cmd) { | 
|  | 2676 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 2677 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2678 | } | 
|  | 2679 |  | 
|  | 2680 | ips_freescb(ha, scb); | 
|  | 2681 | break; | 
|  | 2682 | default: | 
|  | 2683 | break; | 
|  | 2684 | }		/* end case */ | 
|  | 2685 |  | 
|  | 2686 | if (ret != IPS_SUCCESS) { | 
|  | 2687 | ha->num_ioctl--; | 
|  | 2688 | continue; | 
|  | 2689 | } | 
|  | 2690 |  | 
|  | 2691 | ret = ips_send_cmd(ha, scb); | 
|  | 2692 |  | 
|  | 2693 | if (ret == IPS_SUCCESS) | 
|  | 2694 | ips_putq_scb_head(&ha->scb_activelist, scb); | 
|  | 2695 | else | 
|  | 2696 | ha->num_ioctl--; | 
|  | 2697 |  | 
|  | 2698 | switch (ret) { | 
|  | 2699 | case IPS_FAILURE: | 
|  | 2700 | if (scb->scsi_cmd) { | 
|  | 2701 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 2702 | } | 
|  | 2703 |  | 
|  | 2704 | ips_freescb(ha, scb); | 
|  | 2705 | break; | 
|  | 2706 | case IPS_SUCCESS_IMM: | 
|  | 2707 | ips_freescb(ha, scb); | 
|  | 2708 | break; | 
|  | 2709 | default: | 
|  | 2710 | break; | 
|  | 2711 | }		/* end case */ | 
|  | 2712 |  | 
|  | 2713 | } | 
|  | 2714 |  | 
|  | 2715 | /* | 
|  | 2716 | * Send "Normal" I/O commands | 
|  | 2717 | */ | 
|  | 2718 |  | 
|  | 2719 | p = ha->scb_waitlist.head; | 
|  | 2720 | while ((p) && (scb = ips_getscb(ha))) { | 
| Jeff Garzik | 422c0d6 | 2005-10-24 18:05:09 -0400 | [diff] [blame] | 2721 | if ((scmd_channel(p) > 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2722 | && (ha-> | 
| Jeff Garzik | 422c0d6 | 2005-10-24 18:05:09 -0400 | [diff] [blame] | 2723 | dcdb_active[scmd_channel(p) - | 
|  | 2724 | 1] & (1 << scmd_id(p)))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2725 | ips_freescb(ha, scb); | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2726 | p = (struct scsi_cmnd *) p->host_scribble; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2727 | continue; | 
|  | 2728 | } | 
|  | 2729 |  | 
|  | 2730 | q = p; | 
|  | 2731 | SC = ips_removeq_wait(&ha->scb_waitlist, q); | 
|  | 2732 |  | 
|  | 2733 | if (intr == IPS_INTR_ON) | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 2734 | spin_unlock(host->host_lock);	/* Unlock HA after command is taken off queue */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2735 |  | 
|  | 2736 | SC->result = DID_OK; | 
|  | 2737 | SC->host_scribble = NULL; | 
|  | 2738 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2739 | scb->target_id = SC->device->id; | 
|  | 2740 | scb->lun = SC->device->lun; | 
|  | 2741 | scb->bus = SC->device->channel; | 
|  | 2742 | scb->scsi_cmd = SC; | 
|  | 2743 | scb->breakup = 0; | 
|  | 2744 | scb->data_len = 0; | 
|  | 2745 | scb->callback = ipsintr_done; | 
|  | 2746 | scb->timeout = ips_cmd_timeout; | 
|  | 2747 | memset(&scb->cmd, 0, 16); | 
|  | 2748 |  | 
|  | 2749 | /* copy in the CDB */ | 
|  | 2750 | memcpy(scb->cdb, SC->cmnd, SC->cmd_len); | 
|  | 2751 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 2752 | scb->sg_count = scsi_dma_map(SC); | 
|  | 2753 | BUG_ON(scb->sg_count < 0); | 
|  | 2754 | if (scb->sg_count) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2755 | struct scatterlist *sg; | 
|  | 2756 | int i; | 
|  | 2757 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2758 | scb->flags |= IPS_SCB_MAP_SG; | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 2759 |  | 
|  | 2760 | scsi_for_each_sg(SC, sg, scb->sg_count, i) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2761 | if (ips_fill_scb_sg_single | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 2762 | (ha, sg_dma_address(sg), scb, i, | 
|  | 2763 | sg_dma_len(sg)) < 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2764 | break; | 
|  | 2765 | } | 
|  | 2766 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 2767 | } else { | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 2768 | scb->data_busaddr = 0L; | 
|  | 2769 | scb->sg_len = 0; | 
|  | 2770 | scb->data_len = 0; | 
|  | 2771 | scb->dcdb.transfer_length = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2772 | } | 
|  | 2773 |  | 
|  | 2774 | scb->dcdb.cmd_attribute = | 
|  | 2775 | ips_command_direction[scb->scsi_cmd->cmnd[0]]; | 
|  | 2776 |  | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 2777 | /* Allow a WRITE BUFFER Command to Have no Data */ | 
|  | 2778 | /* This is Used by Tape Flash Utilites          */ | 
|  | 2779 | if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && | 
|  | 2780 | (scb->data_len == 0)) | 
|  | 2781 | scb->dcdb.cmd_attribute = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2782 |  | 
|  | 2783 | if (!(scb->dcdb.cmd_attribute & 0x3)) | 
|  | 2784 | scb->dcdb.transfer_length = 0; | 
|  | 2785 |  | 
|  | 2786 | if (scb->data_len >= IPS_MAX_XFER) { | 
|  | 2787 | scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; | 
|  | 2788 | scb->dcdb.transfer_length = 0; | 
|  | 2789 | } | 
|  | 2790 | if (intr == IPS_INTR_ON) | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 2791 | spin_lock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2792 |  | 
|  | 2793 | ret = ips_send_cmd(ha, scb); | 
|  | 2794 |  | 
|  | 2795 | switch (ret) { | 
|  | 2796 | case IPS_SUCCESS: | 
|  | 2797 | ips_putq_scb_head(&ha->scb_activelist, scb); | 
|  | 2798 | break; | 
|  | 2799 | case IPS_FAILURE: | 
|  | 2800 | if (scb->scsi_cmd) { | 
|  | 2801 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 2802 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2803 | } | 
|  | 2804 |  | 
|  | 2805 | if (scb->bus) | 
|  | 2806 | ha->dcdb_active[scb->bus - 1] &= | 
|  | 2807 | ~(1 << scb->target_id); | 
|  | 2808 |  | 
|  | 2809 | ips_freescb(ha, scb); | 
|  | 2810 | break; | 
|  | 2811 | case IPS_SUCCESS_IMM: | 
|  | 2812 | if (scb->scsi_cmd) | 
|  | 2813 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2814 |  | 
|  | 2815 | if (scb->bus) | 
|  | 2816 | ha->dcdb_active[scb->bus - 1] &= | 
|  | 2817 | ~(1 << scb->target_id); | 
|  | 2818 |  | 
|  | 2819 | ips_freescb(ha, scb); | 
|  | 2820 | break; | 
|  | 2821 | default: | 
|  | 2822 | break; | 
|  | 2823 | }		/* end case */ | 
|  | 2824 |  | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2825 | p = (struct scsi_cmnd *) p->host_scribble; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2826 |  | 
|  | 2827 | }			/* end while */ | 
|  | 2828 |  | 
|  | 2829 | if (intr == IPS_INTR_ON) | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 2830 | spin_unlock(host->host_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2831 | } | 
|  | 2832 |  | 
|  | 2833 | /****************************************************************************/ | 
|  | 2834 | /*                                                                          */ | 
|  | 2835 | /* Routine Name: ips_putq_scb_head                                          */ | 
|  | 2836 | /*                                                                          */ | 
|  | 2837 | /* Routine Description:                                                     */ | 
|  | 2838 | /*                                                                          */ | 
|  | 2839 | /*   Add an item to the head of the queue                                   */ | 
|  | 2840 | /*                                                                          */ | 
|  | 2841 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2842 | /*                                                                          */ | 
|  | 2843 | /****************************************************************************/ | 
|  | 2844 | static void | 
|  | 2845 | ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) | 
|  | 2846 | { | 
|  | 2847 | METHOD_TRACE("ips_putq_scb_head", 1); | 
|  | 2848 |  | 
|  | 2849 | if (!item) | 
|  | 2850 | return; | 
|  | 2851 |  | 
|  | 2852 | item->q_next = queue->head; | 
|  | 2853 | queue->head = item; | 
|  | 2854 |  | 
|  | 2855 | if (!queue->tail) | 
|  | 2856 | queue->tail = item; | 
|  | 2857 |  | 
|  | 2858 | queue->count++; | 
|  | 2859 | } | 
|  | 2860 |  | 
|  | 2861 | /****************************************************************************/ | 
|  | 2862 | /*                                                                          */ | 
|  | 2863 | /* Routine Name: ips_removeq_scb_head                                       */ | 
|  | 2864 | /*                                                                          */ | 
|  | 2865 | /* Routine Description:                                                     */ | 
|  | 2866 | /*                                                                          */ | 
|  | 2867 | /*   Remove the head of the queue                                           */ | 
|  | 2868 | /*                                                                          */ | 
|  | 2869 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2870 | /*                                                                          */ | 
|  | 2871 | /****************************************************************************/ | 
|  | 2872 | static ips_scb_t * | 
|  | 2873 | ips_removeq_scb_head(ips_scb_queue_t * queue) | 
|  | 2874 | { | 
|  | 2875 | ips_scb_t *item; | 
|  | 2876 |  | 
|  | 2877 | METHOD_TRACE("ips_removeq_scb_head", 1); | 
|  | 2878 |  | 
|  | 2879 | item = queue->head; | 
|  | 2880 |  | 
|  | 2881 | if (!item) { | 
|  | 2882 | return (NULL); | 
|  | 2883 | } | 
|  | 2884 |  | 
|  | 2885 | queue->head = item->q_next; | 
|  | 2886 | item->q_next = NULL; | 
|  | 2887 |  | 
|  | 2888 | if (queue->tail == item) | 
|  | 2889 | queue->tail = NULL; | 
|  | 2890 |  | 
|  | 2891 | queue->count--; | 
|  | 2892 |  | 
|  | 2893 | return (item); | 
|  | 2894 | } | 
|  | 2895 |  | 
|  | 2896 | /****************************************************************************/ | 
|  | 2897 | /*                                                                          */ | 
|  | 2898 | /* Routine Name: ips_removeq_scb                                            */ | 
|  | 2899 | /*                                                                          */ | 
|  | 2900 | /* Routine Description:                                                     */ | 
|  | 2901 | /*                                                                          */ | 
|  | 2902 | /*   Remove an item from a queue                                            */ | 
|  | 2903 | /*                                                                          */ | 
|  | 2904 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2905 | /*                                                                          */ | 
|  | 2906 | /****************************************************************************/ | 
|  | 2907 | static ips_scb_t * | 
|  | 2908 | ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) | 
|  | 2909 | { | 
|  | 2910 | ips_scb_t *p; | 
|  | 2911 |  | 
|  | 2912 | METHOD_TRACE("ips_removeq_scb", 1); | 
|  | 2913 |  | 
|  | 2914 | if (!item) | 
|  | 2915 | return (NULL); | 
|  | 2916 |  | 
|  | 2917 | if (item == queue->head) { | 
|  | 2918 | return (ips_removeq_scb_head(queue)); | 
|  | 2919 | } | 
|  | 2920 |  | 
|  | 2921 | p = queue->head; | 
|  | 2922 |  | 
|  | 2923 | while ((p) && (item != p->q_next)) | 
|  | 2924 | p = p->q_next; | 
|  | 2925 |  | 
|  | 2926 | if (p) { | 
|  | 2927 | /* found a match */ | 
|  | 2928 | p->q_next = item->q_next; | 
|  | 2929 |  | 
|  | 2930 | if (!item->q_next) | 
|  | 2931 | queue->tail = p; | 
|  | 2932 |  | 
|  | 2933 | item->q_next = NULL; | 
|  | 2934 | queue->count--; | 
|  | 2935 |  | 
|  | 2936 | return (item); | 
|  | 2937 | } | 
|  | 2938 |  | 
|  | 2939 | return (NULL); | 
|  | 2940 | } | 
|  | 2941 |  | 
|  | 2942 | /****************************************************************************/ | 
|  | 2943 | /*                                                                          */ | 
|  | 2944 | /* Routine Name: ips_putq_wait_tail                                         */ | 
|  | 2945 | /*                                                                          */ | 
|  | 2946 | /* Routine Description:                                                     */ | 
|  | 2947 | /*                                                                          */ | 
|  | 2948 | /*   Add an item to the tail of the queue                                   */ | 
|  | 2949 | /*                                                                          */ | 
|  | 2950 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2951 | /*                                                                          */ | 
|  | 2952 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2953 | static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2954 | { | 
|  | 2955 | METHOD_TRACE("ips_putq_wait_tail", 1); | 
|  | 2956 |  | 
|  | 2957 | if (!item) | 
|  | 2958 | return; | 
|  | 2959 |  | 
|  | 2960 | item->host_scribble = NULL; | 
|  | 2961 |  | 
|  | 2962 | if (queue->tail) | 
|  | 2963 | queue->tail->host_scribble = (char *) item; | 
|  | 2964 |  | 
|  | 2965 | queue->tail = item; | 
|  | 2966 |  | 
|  | 2967 | if (!queue->head) | 
|  | 2968 | queue->head = item; | 
|  | 2969 |  | 
|  | 2970 | queue->count++; | 
|  | 2971 | } | 
|  | 2972 |  | 
|  | 2973 | /****************************************************************************/ | 
|  | 2974 | /*                                                                          */ | 
|  | 2975 | /* Routine Name: ips_removeq_wait_head                                      */ | 
|  | 2976 | /*                                                                          */ | 
|  | 2977 | /* Routine Description:                                                     */ | 
|  | 2978 | /*                                                                          */ | 
|  | 2979 | /*   Remove the head of the queue                                           */ | 
|  | 2980 | /*                                                                          */ | 
|  | 2981 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2982 | /*                                                                          */ | 
|  | 2983 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2984 | static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2985 | { | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2986 | struct scsi_cmnd *item; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2987 |  | 
|  | 2988 | METHOD_TRACE("ips_removeq_wait_head", 1); | 
|  | 2989 |  | 
|  | 2990 | item = queue->head; | 
|  | 2991 |  | 
|  | 2992 | if (!item) { | 
|  | 2993 | return (NULL); | 
|  | 2994 | } | 
|  | 2995 |  | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 2996 | queue->head = (struct scsi_cmnd *) item->host_scribble; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2997 | item->host_scribble = NULL; | 
|  | 2998 |  | 
|  | 2999 | if (queue->tail == item) | 
|  | 3000 | queue->tail = NULL; | 
|  | 3001 |  | 
|  | 3002 | queue->count--; | 
|  | 3003 |  | 
|  | 3004 | return (item); | 
|  | 3005 | } | 
|  | 3006 |  | 
|  | 3007 | /****************************************************************************/ | 
|  | 3008 | /*                                                                          */ | 
|  | 3009 | /* Routine Name: ips_removeq_wait                                           */ | 
|  | 3010 | /*                                                                          */ | 
|  | 3011 | /* Routine Description:                                                     */ | 
|  | 3012 | /*                                                                          */ | 
|  | 3013 | /*   Remove an item from a queue                                            */ | 
|  | 3014 | /*                                                                          */ | 
|  | 3015 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3016 | /*                                                                          */ | 
|  | 3017 | /****************************************************************************/ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3018 | static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue, | 
|  | 3019 | struct scsi_cmnd *item) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3020 | { | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3021 | struct scsi_cmnd *p; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3022 |  | 
|  | 3023 | METHOD_TRACE("ips_removeq_wait", 1); | 
|  | 3024 |  | 
|  | 3025 | if (!item) | 
|  | 3026 | return (NULL); | 
|  | 3027 |  | 
|  | 3028 | if (item == queue->head) { | 
|  | 3029 | return (ips_removeq_wait_head(queue)); | 
|  | 3030 | } | 
|  | 3031 |  | 
|  | 3032 | p = queue->head; | 
|  | 3033 |  | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3034 | while ((p) && (item != (struct scsi_cmnd *) p->host_scribble)) | 
|  | 3035 | p = (struct scsi_cmnd *) p->host_scribble; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3036 |  | 
|  | 3037 | if (p) { | 
|  | 3038 | /* found a match */ | 
|  | 3039 | p->host_scribble = item->host_scribble; | 
|  | 3040 |  | 
|  | 3041 | if (!item->host_scribble) | 
|  | 3042 | queue->tail = p; | 
|  | 3043 |  | 
|  | 3044 | item->host_scribble = NULL; | 
|  | 3045 | queue->count--; | 
|  | 3046 |  | 
|  | 3047 | return (item); | 
|  | 3048 | } | 
|  | 3049 |  | 
|  | 3050 | return (NULL); | 
|  | 3051 | } | 
|  | 3052 |  | 
|  | 3053 | /****************************************************************************/ | 
|  | 3054 | /*                                                                          */ | 
|  | 3055 | /* Routine Name: ips_putq_copp_tail                                         */ | 
|  | 3056 | /*                                                                          */ | 
|  | 3057 | /* Routine Description:                                                     */ | 
|  | 3058 | /*                                                                          */ | 
|  | 3059 | /*   Add an item to the tail of the queue                                   */ | 
|  | 3060 | /*                                                                          */ | 
|  | 3061 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3062 | /*                                                                          */ | 
|  | 3063 | /****************************************************************************/ | 
|  | 3064 | static void | 
|  | 3065 | ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) | 
|  | 3066 | { | 
|  | 3067 | METHOD_TRACE("ips_putq_copp_tail", 1); | 
|  | 3068 |  | 
|  | 3069 | if (!item) | 
|  | 3070 | return; | 
|  | 3071 |  | 
|  | 3072 | item->next = NULL; | 
|  | 3073 |  | 
|  | 3074 | if (queue->tail) | 
|  | 3075 | queue->tail->next = item; | 
|  | 3076 |  | 
|  | 3077 | queue->tail = item; | 
|  | 3078 |  | 
|  | 3079 | if (!queue->head) | 
|  | 3080 | queue->head = item; | 
|  | 3081 |  | 
|  | 3082 | queue->count++; | 
|  | 3083 | } | 
|  | 3084 |  | 
|  | 3085 | /****************************************************************************/ | 
|  | 3086 | /*                                                                          */ | 
|  | 3087 | /* Routine Name: ips_removeq_copp_head                                      */ | 
|  | 3088 | /*                                                                          */ | 
|  | 3089 | /* Routine Description:                                                     */ | 
|  | 3090 | /*                                                                          */ | 
|  | 3091 | /*   Remove the head of the queue                                           */ | 
|  | 3092 | /*                                                                          */ | 
|  | 3093 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3094 | /*                                                                          */ | 
|  | 3095 | /****************************************************************************/ | 
|  | 3096 | static ips_copp_wait_item_t * | 
|  | 3097 | ips_removeq_copp_head(ips_copp_queue_t * queue) | 
|  | 3098 | { | 
|  | 3099 | ips_copp_wait_item_t *item; | 
|  | 3100 |  | 
|  | 3101 | METHOD_TRACE("ips_removeq_copp_head", 1); | 
|  | 3102 |  | 
|  | 3103 | item = queue->head; | 
|  | 3104 |  | 
|  | 3105 | if (!item) { | 
|  | 3106 | return (NULL); | 
|  | 3107 | } | 
|  | 3108 |  | 
|  | 3109 | queue->head = item->next; | 
|  | 3110 | item->next = NULL; | 
|  | 3111 |  | 
|  | 3112 | if (queue->tail == item) | 
|  | 3113 | queue->tail = NULL; | 
|  | 3114 |  | 
|  | 3115 | queue->count--; | 
|  | 3116 |  | 
|  | 3117 | return (item); | 
|  | 3118 | } | 
|  | 3119 |  | 
|  | 3120 | /****************************************************************************/ | 
|  | 3121 | /*                                                                          */ | 
|  | 3122 | /* Routine Name: ips_removeq_copp                                           */ | 
|  | 3123 | /*                                                                          */ | 
|  | 3124 | /* Routine Description:                                                     */ | 
|  | 3125 | /*                                                                          */ | 
|  | 3126 | /*   Remove an item from a queue                                            */ | 
|  | 3127 | /*                                                                          */ | 
|  | 3128 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3129 | /*                                                                          */ | 
|  | 3130 | /****************************************************************************/ | 
|  | 3131 | static ips_copp_wait_item_t * | 
|  | 3132 | ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) | 
|  | 3133 | { | 
|  | 3134 | ips_copp_wait_item_t *p; | 
|  | 3135 |  | 
|  | 3136 | METHOD_TRACE("ips_removeq_copp", 1); | 
|  | 3137 |  | 
|  | 3138 | if (!item) | 
|  | 3139 | return (NULL); | 
|  | 3140 |  | 
|  | 3141 | if (item == queue->head) { | 
|  | 3142 | return (ips_removeq_copp_head(queue)); | 
|  | 3143 | } | 
|  | 3144 |  | 
|  | 3145 | p = queue->head; | 
|  | 3146 |  | 
|  | 3147 | while ((p) && (item != p->next)) | 
|  | 3148 | p = p->next; | 
|  | 3149 |  | 
|  | 3150 | if (p) { | 
|  | 3151 | /* found a match */ | 
|  | 3152 | p->next = item->next; | 
|  | 3153 |  | 
|  | 3154 | if (!item->next) | 
|  | 3155 | queue->tail = p; | 
|  | 3156 |  | 
|  | 3157 | item->next = NULL; | 
|  | 3158 | queue->count--; | 
|  | 3159 |  | 
|  | 3160 | return (item); | 
|  | 3161 | } | 
|  | 3162 |  | 
|  | 3163 | return (NULL); | 
|  | 3164 | } | 
|  | 3165 |  | 
|  | 3166 | /****************************************************************************/ | 
|  | 3167 | /*                                                                          */ | 
|  | 3168 | /* Routine Name: ipsintr_blocking                                           */ | 
|  | 3169 | /*                                                                          */ | 
|  | 3170 | /* Routine Description:                                                     */ | 
|  | 3171 | /*                                                                          */ | 
|  | 3172 | /*   Finalize an interrupt for internal commands                            */ | 
|  | 3173 | /*                                                                          */ | 
|  | 3174 | /****************************************************************************/ | 
|  | 3175 | static void | 
|  | 3176 | ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3177 | { | 
|  | 3178 | METHOD_TRACE("ipsintr_blocking", 2); | 
|  | 3179 |  | 
|  | 3180 | ips_freescb(ha, scb); | 
|  | 3181 | if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) { | 
|  | 3182 | ha->waitflag = FALSE; | 
|  | 3183 |  | 
|  | 3184 | return; | 
|  | 3185 | } | 
|  | 3186 | } | 
|  | 3187 |  | 
|  | 3188 | /****************************************************************************/ | 
|  | 3189 | /*                                                                          */ | 
|  | 3190 | /* Routine Name: ipsintr_done                                               */ | 
|  | 3191 | /*                                                                          */ | 
|  | 3192 | /* Routine Description:                                                     */ | 
|  | 3193 | /*                                                                          */ | 
|  | 3194 | /*   Finalize an interrupt for non-internal commands                        */ | 
|  | 3195 | /*                                                                          */ | 
|  | 3196 | /****************************************************************************/ | 
|  | 3197 | static void | 
|  | 3198 | ipsintr_done(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3199 | { | 
|  | 3200 | METHOD_TRACE("ipsintr_done", 2); | 
|  | 3201 |  | 
|  | 3202 | if (!scb) { | 
|  | 3203 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 3204 | "Spurious interrupt; scb NULL.\n"); | 
|  | 3205 |  | 
|  | 3206 | return; | 
|  | 3207 | } | 
|  | 3208 |  | 
|  | 3209 | if (scb->scsi_cmd == NULL) { | 
|  | 3210 | /* unexpected interrupt */ | 
|  | 3211 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 3212 | "Spurious interrupt; scsi_cmd not set.\n"); | 
|  | 3213 |  | 
|  | 3214 | return; | 
|  | 3215 | } | 
|  | 3216 |  | 
|  | 3217 | ips_done(ha, scb); | 
|  | 3218 | } | 
|  | 3219 |  | 
|  | 3220 | /****************************************************************************/ | 
|  | 3221 | /*                                                                          */ | 
|  | 3222 | /* Routine Name: ips_done                                                   */ | 
|  | 3223 | /*                                                                          */ | 
|  | 3224 | /* Routine Description:                                                     */ | 
|  | 3225 | /*                                                                          */ | 
|  | 3226 | /*   Do housekeeping on completed commands                                  */ | 
|  | 3227 | /*  ASSUMED to be called form within the request lock                       */ | 
|  | 3228 | /****************************************************************************/ | 
|  | 3229 | static void | 
|  | 3230 | ips_done(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3231 | { | 
|  | 3232 | int ret; | 
|  | 3233 |  | 
|  | 3234 | METHOD_TRACE("ips_done", 1); | 
|  | 3235 |  | 
|  | 3236 | if (!scb) | 
|  | 3237 | return; | 
|  | 3238 |  | 
|  | 3239 | if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) { | 
|  | 3240 | ips_cleanup_passthru(ha, scb); | 
|  | 3241 | ha->num_ioctl--; | 
|  | 3242 | } else { | 
|  | 3243 | /* | 
|  | 3244 | * Check to see if this command had too much | 
|  | 3245 | * data and had to be broke up.  If so, queue | 
|  | 3246 | * the rest of the data and continue. | 
|  | 3247 | */ | 
|  | 3248 | if ((scb->breakup) || (scb->sg_break)) { | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3249 | struct scatterlist *sg; | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3250 | int i, sg_dma_index, ips_sg_index = 0; | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3251 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3252 | /* we had a data breakup */ | 
|  | 3253 | scb->data_len = 0; | 
|  | 3254 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3255 | sg = scsi_sglist(scb->scsi_cmd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3256 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3257 | /* Spin forward to last dma chunk */ | 
|  | 3258 | sg_dma_index = scb->breakup; | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3259 | for (i = 0; i < scb->breakup; i++) | 
|  | 3260 | sg = sg_next(sg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3261 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3262 | /* Take care of possible partial on last chunk */ | 
|  | 3263 | ips_fill_scb_sg_single(ha, | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3264 | sg_dma_address(sg), | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3265 | scb, ips_sg_index++, | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3266 | sg_dma_len(sg)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3267 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3268 | for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd); | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3269 | sg_dma_index++, sg = sg_next(sg)) { | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3270 | if (ips_fill_scb_sg_single | 
|  | 3271 | (ha, | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3272 | sg_dma_address(sg), | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3273 | scb, ips_sg_index++, | 
| FUJITA Tomonori | e0eaf88 | 2007-07-16 15:24:14 +0200 | [diff] [blame] | 3274 | sg_dma_len(sg)) < 0) | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3275 | break; | 
|  | 3276 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3277 |  | 
|  | 3278 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 3279 | scb->dcdb.cmd_attribute |= | 
|  | 3280 | ips_command_direction[scb->scsi_cmd->cmnd[0]]; | 
|  | 3281 |  | 
|  | 3282 | if (!(scb->dcdb.cmd_attribute & 0x3)) | 
|  | 3283 | scb->dcdb.transfer_length = 0; | 
|  | 3284 |  | 
|  | 3285 | if (scb->data_len >= IPS_MAX_XFER) { | 
|  | 3286 | scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; | 
|  | 3287 | scb->dcdb.transfer_length = 0; | 
|  | 3288 | } | 
|  | 3289 |  | 
|  | 3290 | ret = ips_send_cmd(ha, scb); | 
|  | 3291 |  | 
|  | 3292 | switch (ret) { | 
|  | 3293 | case IPS_FAILURE: | 
|  | 3294 | if (scb->scsi_cmd) { | 
|  | 3295 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 3296 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 3297 | } | 
|  | 3298 |  | 
|  | 3299 | ips_freescb(ha, scb); | 
|  | 3300 | break; | 
|  | 3301 | case IPS_SUCCESS_IMM: | 
|  | 3302 | if (scb->scsi_cmd) { | 
|  | 3303 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 3304 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 3305 | } | 
|  | 3306 |  | 
|  | 3307 | ips_freescb(ha, scb); | 
|  | 3308 | break; | 
|  | 3309 | default: | 
|  | 3310 | break; | 
|  | 3311 | }	/* end case */ | 
|  | 3312 |  | 
|  | 3313 | return; | 
|  | 3314 | } | 
|  | 3315 | }			/* end if passthru */ | 
|  | 3316 |  | 
|  | 3317 | if (scb->bus) { | 
|  | 3318 | ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id); | 
|  | 3319 | } | 
|  | 3320 |  | 
|  | 3321 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 3322 |  | 
|  | 3323 | ips_freescb(ha, scb); | 
|  | 3324 | } | 
|  | 3325 |  | 
|  | 3326 | /****************************************************************************/ | 
|  | 3327 | /*                                                                          */ | 
|  | 3328 | /* Routine Name: ips_map_status                                             */ | 
|  | 3329 | /*                                                                          */ | 
|  | 3330 | /* Routine Description:                                                     */ | 
|  | 3331 | /*                                                                          */ | 
|  | 3332 | /*   Map Controller Error codes to Linux Error Codes                        */ | 
|  | 3333 | /*                                                                          */ | 
|  | 3334 | /****************************************************************************/ | 
|  | 3335 | static int | 
|  | 3336 | ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) | 
|  | 3337 | { | 
|  | 3338 | int errcode; | 
|  | 3339 | int device_error; | 
|  | 3340 | uint32_t transfer_len; | 
|  | 3341 | IPS_DCDB_TABLE_TAPE *tapeDCDB; | 
| Jack Hammer | a5b3c86 | 2006-01-31 13:17:55 -0500 | [diff] [blame] | 3342 | IPS_SCSI_INQ_DATA inquiryData; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3343 |  | 
|  | 3344 | METHOD_TRACE("ips_map_status", 1); | 
|  | 3345 |  | 
|  | 3346 | if (scb->bus) { | 
|  | 3347 | DEBUG_VAR(2, | 
|  | 3348 | "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x", | 
|  | 3349 | ips_name, ha->host_num, | 
|  | 3350 | scb->scsi_cmd->device->channel, | 
|  | 3351 | scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun, | 
|  | 3352 | scb->basic_status, scb->extended_status, | 
|  | 3353 | scb->extended_status == | 
|  | 3354 | IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0, | 
|  | 3355 | scb->extended_status == | 
|  | 3356 | IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0, | 
|  | 3357 | scb->extended_status == | 
|  | 3358 | IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0); | 
|  | 3359 | } | 
|  | 3360 |  | 
|  | 3361 | /* default driver error */ | 
|  | 3362 | errcode = DID_ERROR; | 
|  | 3363 | device_error = 0; | 
|  | 3364 |  | 
|  | 3365 | switch (scb->basic_status & IPS_GSC_STATUS_MASK) { | 
|  | 3366 | case IPS_CMD_TIMEOUT: | 
|  | 3367 | errcode = DID_TIME_OUT; | 
|  | 3368 | break; | 
|  | 3369 |  | 
|  | 3370 | case IPS_INVAL_OPCO: | 
|  | 3371 | case IPS_INVAL_CMD_BLK: | 
|  | 3372 | case IPS_INVAL_PARM_BLK: | 
|  | 3373 | case IPS_LD_ERROR: | 
|  | 3374 | case IPS_CMD_CMPLT_WERROR: | 
|  | 3375 | break; | 
|  | 3376 |  | 
|  | 3377 | case IPS_PHYS_DRV_ERROR: | 
|  | 3378 | switch (scb->extended_status) { | 
|  | 3379 | case IPS_ERR_SEL_TO: | 
|  | 3380 | if (scb->bus) | 
|  | 3381 | errcode = DID_NO_CONNECT; | 
|  | 3382 |  | 
|  | 3383 | break; | 
|  | 3384 |  | 
|  | 3385 | case IPS_ERR_OU_RUN: | 
|  | 3386 | if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) || | 
|  | 3387 | (scb->cmd.dcdb.op_code == | 
|  | 3388 | IPS_CMD_EXTENDED_DCDB_SG)) { | 
|  | 3389 | tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; | 
|  | 3390 | transfer_len = tapeDCDB->transfer_length; | 
|  | 3391 | } else { | 
|  | 3392 | transfer_len = | 
|  | 3393 | (uint32_t) scb->dcdb.transfer_length; | 
|  | 3394 | } | 
|  | 3395 |  | 
|  | 3396 | if ((scb->bus) && (transfer_len < scb->data_len)) { | 
|  | 3397 | /* Underrun - set default to no error */ | 
|  | 3398 | errcode = DID_OK; | 
|  | 3399 |  | 
|  | 3400 | /* Restrict access to physical DASD */ | 
| Jack Hammer | a5b3c86 | 2006-01-31 13:17:55 -0500 | [diff] [blame] | 3401 | if (scb->scsi_cmd->cmnd[0] == INQUIRY) { | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 3402 | ips_scmd_buf_read(scb->scsi_cmd, | 
| Jack Hammer | a5b3c86 | 2006-01-31 13:17:55 -0500 | [diff] [blame] | 3403 | &inquiryData, sizeof (inquiryData)); | 
|  | 3404 | if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) { | 
|  | 3405 | errcode = DID_TIME_OUT; | 
|  | 3406 | break; | 
|  | 3407 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3408 | } | 
|  | 3409 | } else | 
|  | 3410 | errcode = DID_ERROR; | 
|  | 3411 |  | 
|  | 3412 | break; | 
|  | 3413 |  | 
|  | 3414 | case IPS_ERR_RECOVERY: | 
|  | 3415 | /* don't fail recovered errors */ | 
|  | 3416 | if (scb->bus) | 
|  | 3417 | errcode = DID_OK; | 
|  | 3418 |  | 
|  | 3419 | break; | 
|  | 3420 |  | 
|  | 3421 | case IPS_ERR_HOST_RESET: | 
|  | 3422 | case IPS_ERR_DEV_RESET: | 
|  | 3423 | errcode = DID_RESET; | 
|  | 3424 | break; | 
|  | 3425 |  | 
|  | 3426 | case IPS_ERR_CKCOND: | 
|  | 3427 | if (scb->bus) { | 
|  | 3428 | if ((scb->cmd.dcdb.op_code == | 
|  | 3429 | IPS_CMD_EXTENDED_DCDB) | 
|  | 3430 | || (scb->cmd.dcdb.op_code == | 
|  | 3431 | IPS_CMD_EXTENDED_DCDB_SG)) { | 
|  | 3432 | tapeDCDB = | 
|  | 3433 | (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; | 
|  | 3434 | memcpy(scb->scsi_cmd->sense_buffer, | 
|  | 3435 | tapeDCDB->sense_info, | 
| FUJITA Tomonori | b80ca4f | 2008-01-13 15:46:13 +0900 | [diff] [blame] | 3436 | SCSI_SENSE_BUFFERSIZE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3437 | } else { | 
|  | 3438 | memcpy(scb->scsi_cmd->sense_buffer, | 
|  | 3439 | scb->dcdb.sense_info, | 
| FUJITA Tomonori | b80ca4f | 2008-01-13 15:46:13 +0900 | [diff] [blame] | 3440 | SCSI_SENSE_BUFFERSIZE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3441 | } | 
|  | 3442 | device_error = 2;	/* check condition */ | 
|  | 3443 | } | 
|  | 3444 |  | 
|  | 3445 | errcode = DID_OK; | 
|  | 3446 |  | 
|  | 3447 | break; | 
|  | 3448 |  | 
|  | 3449 | default: | 
|  | 3450 | errcode = DID_ERROR; | 
|  | 3451 | break; | 
|  | 3452 |  | 
|  | 3453 | }		/* end switch */ | 
|  | 3454 | }			/* end switch */ | 
|  | 3455 |  | 
|  | 3456 | scb->scsi_cmd->result = device_error | (errcode << 16); | 
|  | 3457 |  | 
|  | 3458 | return (1); | 
|  | 3459 | } | 
|  | 3460 |  | 
|  | 3461 | /****************************************************************************/ | 
|  | 3462 | /*                                                                          */ | 
|  | 3463 | /* Routine Name: ips_send_wait                                              */ | 
|  | 3464 | /*                                                                          */ | 
|  | 3465 | /* Routine Description:                                                     */ | 
|  | 3466 | /*                                                                          */ | 
|  | 3467 | /*   Send a command to the controller and wait for it to return             */ | 
|  | 3468 | /*                                                                          */ | 
|  | 3469 | /*   The FFDC Time Stamp use this function for the callback, but doesn't    */ | 
|  | 3470 | /*   actually need to wait.                                                 */ | 
|  | 3471 | /****************************************************************************/ | 
|  | 3472 | static int | 
|  | 3473 | ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) | 
|  | 3474 | { | 
|  | 3475 | int ret; | 
|  | 3476 |  | 
|  | 3477 | METHOD_TRACE("ips_send_wait", 1); | 
|  | 3478 |  | 
|  | 3479 | if (intr != IPS_FFDC) {	/* Won't be Waiting if this is a Time Stamp */ | 
|  | 3480 | ha->waitflag = TRUE; | 
|  | 3481 | ha->cmd_in_progress = scb->cdb[0]; | 
|  | 3482 | } | 
|  | 3483 | scb->callback = ipsintr_blocking; | 
|  | 3484 | ret = ips_send_cmd(ha, scb); | 
|  | 3485 |  | 
|  | 3486 | if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) | 
|  | 3487 | return (ret); | 
|  | 3488 |  | 
|  | 3489 | if (intr != IPS_FFDC)	/* Don't Wait around if this is a Time Stamp */ | 
|  | 3490 | ret = ips_wait(ha, timeout, intr); | 
|  | 3491 |  | 
|  | 3492 | return (ret); | 
|  | 3493 | } | 
|  | 3494 |  | 
|  | 3495 | /****************************************************************************/ | 
|  | 3496 | /*                                                                          */ | 
|  | 3497 | /* Routine Name: ips_scmd_buf_write                                         */ | 
|  | 3498 | /*                                                                          */ | 
|  | 3499 | /* Routine Description:                                                     */ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3500 | /*  Write data to struct scsi_cmnd request_buffer at proper offsets	    */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3501 | /****************************************************************************/ | 
|  | 3502 | static void | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3503 | ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3504 | { | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3505 | int i; | 
|  | 3506 | unsigned int min_cnt, xfer_cnt; | 
|  | 3507 | char *cdata = (char *) data; | 
|  | 3508 | unsigned char *buffer; | 
|  | 3509 | unsigned long flags; | 
|  | 3510 | struct scatterlist *sg = scsi_sglist(scmd); | 
| Jack Hammer | a3632fa | 2005-10-25 14:13:03 -0400 | [diff] [blame] | 3511 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3512 | for (i = 0, xfer_cnt = 0; | 
|  | 3513 | (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) { | 
|  | 3514 | min_cnt = min(count - xfer_cnt, sg[i].length); | 
| Jack Hammer | a3632fa | 2005-10-25 14:13:03 -0400 | [diff] [blame] | 3515 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3516 | /* kmap_atomic() ensures addressability of the data buffer.*/ | 
|  | 3517 | /* local_irq_save() protects the KM_IRQ0 address slot.     */ | 
|  | 3518 | local_irq_save(flags); | 
| Jens Axboe | 45711f1 | 2007-10-22 21:19:53 +0200 | [diff] [blame] | 3519 | buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset; | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3520 | memcpy(buffer, &cdata[xfer_cnt], min_cnt); | 
|  | 3521 | kunmap_atomic(buffer - sg[i].offset, KM_IRQ0); | 
|  | 3522 | local_irq_restore(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3523 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3524 | xfer_cnt += min_cnt; | 
|  | 3525 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3526 | } | 
|  | 3527 |  | 
|  | 3528 | /****************************************************************************/ | 
|  | 3529 | /*                                                                          */ | 
|  | 3530 | /* Routine Name: ips_scmd_buf_read                                          */ | 
|  | 3531 | /*                                                                          */ | 
|  | 3532 | /* Routine Description:                                                     */ | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3533 | /*  Copy data from a struct scsi_cmnd to a new, linear buffer		    */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3534 | /****************************************************************************/ | 
|  | 3535 | static void | 
| Henne | 1516b55 | 2006-10-02 14:56:23 +0200 | [diff] [blame] | 3536 | ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3537 | { | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3538 | int i; | 
|  | 3539 | unsigned int min_cnt, xfer_cnt; | 
|  | 3540 | char *cdata = (char *) data; | 
|  | 3541 | unsigned char *buffer; | 
|  | 3542 | unsigned long flags; | 
|  | 3543 | struct scatterlist *sg = scsi_sglist(scmd); | 
| Jack Hammer | a3632fa | 2005-10-25 14:13:03 -0400 | [diff] [blame] | 3544 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3545 | for (i = 0, xfer_cnt = 0; | 
|  | 3546 | (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) { | 
|  | 3547 | min_cnt = min(count - xfer_cnt, sg[i].length); | 
| Jack Hammer | a3632fa | 2005-10-25 14:13:03 -0400 | [diff] [blame] | 3548 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3549 | /* kmap_atomic() ensures addressability of the data buffer.*/ | 
|  | 3550 | /* local_irq_save() protects the KM_IRQ0 address slot.     */ | 
|  | 3551 | local_irq_save(flags); | 
| Jens Axboe | 45711f1 | 2007-10-22 21:19:53 +0200 | [diff] [blame] | 3552 | buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset; | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3553 | memcpy(&cdata[xfer_cnt], buffer, min_cnt); | 
|  | 3554 | kunmap_atomic(buffer - sg[i].offset, KM_IRQ0); | 
|  | 3555 | local_irq_restore(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3556 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 3557 | xfer_cnt += min_cnt; | 
|  | 3558 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3559 | } | 
|  | 3560 |  | 
|  | 3561 | /****************************************************************************/ | 
|  | 3562 | /*                                                                          */ | 
|  | 3563 | /* Routine Name: ips_send_cmd                                               */ | 
|  | 3564 | /*                                                                          */ | 
|  | 3565 | /* Routine Description:                                                     */ | 
|  | 3566 | /*                                                                          */ | 
|  | 3567 | /*   Map SCSI commands to ServeRAID commands for logical drives             */ | 
|  | 3568 | /*                                                                          */ | 
|  | 3569 | /****************************************************************************/ | 
|  | 3570 | static int | 
|  | 3571 | ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3572 | { | 
|  | 3573 | int ret; | 
|  | 3574 | char *sp; | 
|  | 3575 | int device_error; | 
|  | 3576 | IPS_DCDB_TABLE_TAPE *tapeDCDB; | 
|  | 3577 | int TimeOut; | 
|  | 3578 |  | 
|  | 3579 | METHOD_TRACE("ips_send_cmd", 1); | 
|  | 3580 |  | 
|  | 3581 | ret = IPS_SUCCESS; | 
|  | 3582 |  | 
|  | 3583 | if (!scb->scsi_cmd) { | 
|  | 3584 | /* internal command */ | 
|  | 3585 |  | 
|  | 3586 | if (scb->bus > 0) { | 
|  | 3587 | /* Controller commands can't be issued */ | 
|  | 3588 | /* to real devices -- fail them        */ | 
|  | 3589 | if ((ha->waitflag == TRUE) && | 
|  | 3590 | (ha->cmd_in_progress == scb->cdb[0])) { | 
|  | 3591 | ha->waitflag = FALSE; | 
|  | 3592 | } | 
|  | 3593 |  | 
|  | 3594 | return (1); | 
|  | 3595 | } | 
|  | 3596 | } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) { | 
|  | 3597 | /* command to logical bus -- interpret */ | 
|  | 3598 | ret = IPS_SUCCESS_IMM; | 
|  | 3599 |  | 
|  | 3600 | switch (scb->scsi_cmd->cmnd[0]) { | 
|  | 3601 | case ALLOW_MEDIUM_REMOVAL: | 
|  | 3602 | case REZERO_UNIT: | 
|  | 3603 | case ERASE: | 
|  | 3604 | case WRITE_FILEMARKS: | 
|  | 3605 | case SPACE: | 
|  | 3606 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 3607 | break; | 
|  | 3608 |  | 
|  | 3609 | case START_STOP: | 
|  | 3610 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3611 |  | 
|  | 3612 | case TEST_UNIT_READY: | 
|  | 3613 | case INQUIRY: | 
|  | 3614 | if (scb->target_id == IPS_ADAPTER_ID) { | 
|  | 3615 | /* | 
|  | 3616 | * Either we have a TUR | 
|  | 3617 | * or we have a SCSI inquiry | 
|  | 3618 | */ | 
|  | 3619 | if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY) | 
|  | 3620 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3621 |  | 
|  | 3622 | if (scb->scsi_cmd->cmnd[0] == INQUIRY) { | 
|  | 3623 | IPS_SCSI_INQ_DATA inquiry; | 
|  | 3624 |  | 
|  | 3625 | memset(&inquiry, 0, | 
|  | 3626 | sizeof (IPS_SCSI_INQ_DATA)); | 
|  | 3627 |  | 
|  | 3628 | inquiry.DeviceType = | 
|  | 3629 | IPS_SCSI_INQ_TYPE_PROCESSOR; | 
|  | 3630 | inquiry.DeviceTypeQualifier = | 
|  | 3631 | IPS_SCSI_INQ_LU_CONNECTED; | 
|  | 3632 | inquiry.Version = IPS_SCSI_INQ_REV2; | 
|  | 3633 | inquiry.ResponseDataFormat = | 
|  | 3634 | IPS_SCSI_INQ_RD_REV2; | 
|  | 3635 | inquiry.AdditionalLength = 31; | 
|  | 3636 | inquiry.Flags[0] = | 
|  | 3637 | IPS_SCSI_INQ_Address16; | 
|  | 3638 | inquiry.Flags[1] = | 
|  | 3639 | IPS_SCSI_INQ_WBus16 | | 
|  | 3640 | IPS_SCSI_INQ_Sync; | 
|  | 3641 | strncpy(inquiry.VendorId, "IBM     ", | 
|  | 3642 | 8); | 
|  | 3643 | strncpy(inquiry.ProductId, | 
|  | 3644 | "SERVERAID       ", 16); | 
|  | 3645 | strncpy(inquiry.ProductRevisionLevel, | 
|  | 3646 | "1.00", 4); | 
|  | 3647 |  | 
|  | 3648 | ips_scmd_buf_write(scb->scsi_cmd, | 
|  | 3649 | &inquiry, | 
|  | 3650 | sizeof (inquiry)); | 
|  | 3651 |  | 
|  | 3652 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3653 | } | 
|  | 3654 | } else { | 
|  | 3655 | scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; | 
|  | 3656 | scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3657 | scb->cmd.logical_info.reserved = 0; | 
|  | 3658 | scb->cmd.logical_info.reserved2 = 0; | 
|  | 3659 | scb->data_len = sizeof (IPS_LD_INFO); | 
|  | 3660 | scb->data_busaddr = ha->logical_drive_info_dma_addr; | 
|  | 3661 | scb->flags = 0; | 
|  | 3662 | scb->cmd.logical_info.buffer_addr = scb->data_busaddr; | 
|  | 3663 | ret = IPS_SUCCESS; | 
|  | 3664 | } | 
|  | 3665 |  | 
|  | 3666 | break; | 
|  | 3667 |  | 
|  | 3668 | case REQUEST_SENSE: | 
|  | 3669 | ips_reqsen(ha, scb); | 
|  | 3670 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3671 | break; | 
|  | 3672 |  | 
|  | 3673 | case READ_6: | 
|  | 3674 | case WRITE_6: | 
|  | 3675 | if (!scb->sg_len) { | 
|  | 3676 | scb->cmd.basic_io.op_code = | 
|  | 3677 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3678 | READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE; | 
|  | 3679 | scb->cmd.basic_io.enhanced_sg = 0; | 
|  | 3680 | scb->cmd.basic_io.sg_addr = | 
|  | 3681 | cpu_to_le32(scb->data_busaddr); | 
|  | 3682 | } else { | 
|  | 3683 | scb->cmd.basic_io.op_code = | 
|  | 3684 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3685 | READ_6) ? IPS_CMD_READ_SG : | 
|  | 3686 | IPS_CMD_WRITE_SG; | 
|  | 3687 | scb->cmd.basic_io.enhanced_sg = | 
|  | 3688 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 3689 | scb->cmd.basic_io.sg_addr = | 
|  | 3690 | cpu_to_le32(scb->sg_busaddr); | 
|  | 3691 | } | 
|  | 3692 |  | 
|  | 3693 | scb->cmd.basic_io.segment_4G = 0; | 
|  | 3694 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3695 | scb->cmd.basic_io.log_drv = scb->target_id; | 
|  | 3696 | scb->cmd.basic_io.sg_count = scb->sg_len; | 
|  | 3697 |  | 
|  | 3698 | if (scb->cmd.basic_io.lba) | 
|  | 3699 | scb->cmd.basic_io.lba = | 
|  | 3700 | cpu_to_le32(le32_to_cpu | 
|  | 3701 | (scb->cmd.basic_io.lba) + | 
|  | 3702 | le16_to_cpu(scb->cmd.basic_io. | 
|  | 3703 | sector_count)); | 
|  | 3704 | else | 
|  | 3705 | scb->cmd.basic_io.lba = | 
|  | 3706 | (((scb->scsi_cmd-> | 
|  | 3707 | cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd-> | 
|  | 3708 | cmnd[2] << 8) | | 
|  | 3709 | (scb->scsi_cmd->cmnd[3])); | 
|  | 3710 |  | 
|  | 3711 | scb->cmd.basic_io.sector_count = | 
|  | 3712 | cpu_to_le16(scb->data_len / IPS_BLKSIZE); | 
|  | 3713 |  | 
|  | 3714 | if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0) | 
|  | 3715 | scb->cmd.basic_io.sector_count = | 
|  | 3716 | cpu_to_le16(256); | 
|  | 3717 |  | 
|  | 3718 | ret = IPS_SUCCESS; | 
|  | 3719 | break; | 
|  | 3720 |  | 
|  | 3721 | case READ_10: | 
|  | 3722 | case WRITE_10: | 
|  | 3723 | if (!scb->sg_len) { | 
|  | 3724 | scb->cmd.basic_io.op_code = | 
|  | 3725 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3726 | READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE; | 
|  | 3727 | scb->cmd.basic_io.enhanced_sg = 0; | 
|  | 3728 | scb->cmd.basic_io.sg_addr = | 
|  | 3729 | cpu_to_le32(scb->data_busaddr); | 
|  | 3730 | } else { | 
|  | 3731 | scb->cmd.basic_io.op_code = | 
|  | 3732 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3733 | READ_10) ? IPS_CMD_READ_SG : | 
|  | 3734 | IPS_CMD_WRITE_SG; | 
|  | 3735 | scb->cmd.basic_io.enhanced_sg = | 
|  | 3736 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 3737 | scb->cmd.basic_io.sg_addr = | 
|  | 3738 | cpu_to_le32(scb->sg_busaddr); | 
|  | 3739 | } | 
|  | 3740 |  | 
|  | 3741 | scb->cmd.basic_io.segment_4G = 0; | 
|  | 3742 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3743 | scb->cmd.basic_io.log_drv = scb->target_id; | 
|  | 3744 | scb->cmd.basic_io.sg_count = scb->sg_len; | 
|  | 3745 |  | 
|  | 3746 | if (scb->cmd.basic_io.lba) | 
|  | 3747 | scb->cmd.basic_io.lba = | 
|  | 3748 | cpu_to_le32(le32_to_cpu | 
|  | 3749 | (scb->cmd.basic_io.lba) + | 
|  | 3750 | le16_to_cpu(scb->cmd.basic_io. | 
|  | 3751 | sector_count)); | 
|  | 3752 | else | 
|  | 3753 | scb->cmd.basic_io.lba = | 
|  | 3754 | ((scb->scsi_cmd->cmnd[2] << 24) | (scb-> | 
|  | 3755 | scsi_cmd-> | 
|  | 3756 | cmnd[3] | 
|  | 3757 | << 16) | | 
|  | 3758 | (scb->scsi_cmd->cmnd[4] << 8) | scb-> | 
|  | 3759 | scsi_cmd->cmnd[5]); | 
|  | 3760 |  | 
|  | 3761 | scb->cmd.basic_io.sector_count = | 
|  | 3762 | cpu_to_le16(scb->data_len / IPS_BLKSIZE); | 
|  | 3763 |  | 
|  | 3764 | if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) { | 
|  | 3765 | /* | 
|  | 3766 | * This is a null condition | 
|  | 3767 | * we don't have to do anything | 
|  | 3768 | * so just return | 
|  | 3769 | */ | 
|  | 3770 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3771 | } else | 
|  | 3772 | ret = IPS_SUCCESS; | 
|  | 3773 |  | 
|  | 3774 | break; | 
|  | 3775 |  | 
|  | 3776 | case RESERVE: | 
|  | 3777 | case RELEASE: | 
|  | 3778 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3779 | break; | 
|  | 3780 |  | 
|  | 3781 | case MODE_SENSE: | 
|  | 3782 | scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; | 
|  | 3783 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3784 | scb->cmd.basic_io.segment_4G = 0; | 
|  | 3785 | scb->cmd.basic_io.enhanced_sg = 0; | 
|  | 3786 | scb->data_len = sizeof (*ha->enq); | 
|  | 3787 | scb->cmd.basic_io.sg_addr = ha->enq_busaddr; | 
|  | 3788 | ret = IPS_SUCCESS; | 
|  | 3789 | break; | 
|  | 3790 |  | 
|  | 3791 | case READ_CAPACITY: | 
|  | 3792 | scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; | 
|  | 3793 | scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3794 | scb->cmd.logical_info.reserved = 0; | 
|  | 3795 | scb->cmd.logical_info.reserved2 = 0; | 
|  | 3796 | scb->cmd.logical_info.reserved3 = 0; | 
|  | 3797 | scb->data_len = sizeof (IPS_LD_INFO); | 
|  | 3798 | scb->data_busaddr = ha->logical_drive_info_dma_addr; | 
|  | 3799 | scb->flags = 0; | 
|  | 3800 | scb->cmd.logical_info.buffer_addr = scb->data_busaddr; | 
|  | 3801 | ret = IPS_SUCCESS; | 
|  | 3802 | break; | 
|  | 3803 |  | 
|  | 3804 | case SEND_DIAGNOSTIC: | 
|  | 3805 | case REASSIGN_BLOCKS: | 
|  | 3806 | case FORMAT_UNIT: | 
|  | 3807 | case SEEK_10: | 
|  | 3808 | case VERIFY: | 
|  | 3809 | case READ_DEFECT_DATA: | 
|  | 3810 | case READ_BUFFER: | 
|  | 3811 | case WRITE_BUFFER: | 
|  | 3812 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3813 | break; | 
|  | 3814 |  | 
|  | 3815 | default: | 
|  | 3816 | /* Set the Return Info to appear like the Command was */ | 
|  | 3817 | /* attempted, a Check Condition occurred, and Sense   */ | 
|  | 3818 | /* Data indicating an Invalid CDB OpCode is returned. */ | 
|  | 3819 | sp = (char *) scb->scsi_cmd->sense_buffer; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3820 |  | 
|  | 3821 | sp[0] = 0x70;	/* Error Code               */ | 
|  | 3822 | sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */ | 
|  | 3823 | sp[7] = 0x0A;	/* Additional Sense Length  */ | 
|  | 3824 | sp[12] = 0x20;	/* ASC = Invalid OpCode     */ | 
|  | 3825 | sp[13] = 0x00;	/* ASCQ                     */ | 
|  | 3826 |  | 
|  | 3827 | device_error = 2;	/* Indicate Check Condition */ | 
|  | 3828 | scb->scsi_cmd->result = device_error | (DID_OK << 16); | 
|  | 3829 | break; | 
|  | 3830 | }		/* end switch */ | 
|  | 3831 | } | 
|  | 3832 | /* end if */ | 
|  | 3833 | if (ret == IPS_SUCCESS_IMM) | 
|  | 3834 | return (ret); | 
|  | 3835 |  | 
|  | 3836 | /* setup DCDB */ | 
|  | 3837 | if (scb->bus > 0) { | 
|  | 3838 |  | 
|  | 3839 | /* If we already know the Device is Not there, no need to attempt a Command   */ | 
|  | 3840 | /* This also protects an NT FailOver Controller from getting CDB's sent to it */ | 
|  | 3841 | if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) { | 
|  | 3842 | scb->scsi_cmd->result = DID_NO_CONNECT << 16; | 
|  | 3843 | return (IPS_SUCCESS_IMM); | 
|  | 3844 | } | 
|  | 3845 |  | 
|  | 3846 | ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id); | 
|  | 3847 | scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3848 | scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + | 
|  | 3849 | (unsigned long) &scb-> | 
|  | 3850 | dcdb - | 
|  | 3851 | (unsigned long) scb); | 
|  | 3852 | scb->cmd.dcdb.reserved = 0; | 
|  | 3853 | scb->cmd.dcdb.reserved2 = 0; | 
|  | 3854 | scb->cmd.dcdb.reserved3 = 0; | 
|  | 3855 | scb->cmd.dcdb.segment_4G = 0; | 
|  | 3856 | scb->cmd.dcdb.enhanced_sg = 0; | 
|  | 3857 |  | 
|  | 3858 | TimeOut = scb->scsi_cmd->timeout_per_command; | 
|  | 3859 |  | 
|  | 3860 | if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */ | 
|  | 3861 | if (!scb->sg_len) { | 
|  | 3862 | scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB; | 
|  | 3863 | } else { | 
|  | 3864 | scb->cmd.dcdb.op_code = | 
|  | 3865 | IPS_CMD_EXTENDED_DCDB_SG; | 
|  | 3866 | scb->cmd.dcdb.enhanced_sg = | 
|  | 3867 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 3868 | } | 
|  | 3869 |  | 
|  | 3870 | tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;	/* Use Same Data Area as Old DCDB Struct */ | 
|  | 3871 | tapeDCDB->device_address = | 
|  | 3872 | ((scb->bus - 1) << 4) | scb->target_id; | 
|  | 3873 | tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED; | 
|  | 3874 | tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;	/* Always Turn OFF 64K Size Flag */ | 
|  | 3875 |  | 
|  | 3876 | if (TimeOut) { | 
|  | 3877 | if (TimeOut < (10 * HZ)) | 
|  | 3878 | tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */ | 
|  | 3879 | else if (TimeOut < (60 * HZ)) | 
|  | 3880 | tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */ | 
|  | 3881 | else if (TimeOut < (1200 * HZ)) | 
|  | 3882 | tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */ | 
|  | 3883 | } | 
|  | 3884 |  | 
|  | 3885 | tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len; | 
|  | 3886 | tapeDCDB->reserved_for_LUN = 0; | 
|  | 3887 | tapeDCDB->transfer_length = scb->data_len; | 
|  | 3888 | if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG) | 
|  | 3889 | tapeDCDB->buffer_pointer = | 
|  | 3890 | cpu_to_le32(scb->sg_busaddr); | 
|  | 3891 | else | 
|  | 3892 | tapeDCDB->buffer_pointer = | 
|  | 3893 | cpu_to_le32(scb->data_busaddr); | 
|  | 3894 | tapeDCDB->sg_count = scb->sg_len; | 
|  | 3895 | tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info); | 
|  | 3896 | tapeDCDB->scsi_status = 0; | 
|  | 3897 | tapeDCDB->reserved = 0; | 
|  | 3898 | memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, | 
|  | 3899 | scb->scsi_cmd->cmd_len); | 
|  | 3900 | } else { | 
|  | 3901 | if (!scb->sg_len) { | 
|  | 3902 | scb->cmd.dcdb.op_code = IPS_CMD_DCDB; | 
|  | 3903 | } else { | 
|  | 3904 | scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG; | 
|  | 3905 | scb->cmd.dcdb.enhanced_sg = | 
|  | 3906 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 3907 | } | 
|  | 3908 |  | 
|  | 3909 | scb->dcdb.device_address = | 
|  | 3910 | ((scb->bus - 1) << 4) | scb->target_id; | 
|  | 3911 | scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED; | 
|  | 3912 |  | 
|  | 3913 | if (TimeOut) { | 
|  | 3914 | if (TimeOut < (10 * HZ)) | 
|  | 3915 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */ | 
|  | 3916 | else if (TimeOut < (60 * HZ)) | 
|  | 3917 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */ | 
|  | 3918 | else if (TimeOut < (1200 * HZ)) | 
|  | 3919 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */ | 
|  | 3920 | } | 
|  | 3921 |  | 
|  | 3922 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 3923 | if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K) | 
|  | 3924 | scb->dcdb.transfer_length = 0; | 
|  | 3925 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG) | 
|  | 3926 | scb->dcdb.buffer_pointer = | 
|  | 3927 | cpu_to_le32(scb->sg_busaddr); | 
|  | 3928 | else | 
|  | 3929 | scb->dcdb.buffer_pointer = | 
|  | 3930 | cpu_to_le32(scb->data_busaddr); | 
|  | 3931 | scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len; | 
|  | 3932 | scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info); | 
|  | 3933 | scb->dcdb.sg_count = scb->sg_len; | 
|  | 3934 | scb->dcdb.reserved = 0; | 
|  | 3935 | memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, | 
|  | 3936 | scb->scsi_cmd->cmd_len); | 
|  | 3937 | scb->dcdb.scsi_status = 0; | 
|  | 3938 | scb->dcdb.reserved2[0] = 0; | 
|  | 3939 | scb->dcdb.reserved2[1] = 0; | 
|  | 3940 | scb->dcdb.reserved2[2] = 0; | 
|  | 3941 | } | 
|  | 3942 | } | 
|  | 3943 |  | 
|  | 3944 | return ((*ha->func.issue) (ha, scb)); | 
|  | 3945 | } | 
|  | 3946 |  | 
|  | 3947 | /****************************************************************************/ | 
|  | 3948 | /*                                                                          */ | 
|  | 3949 | /* Routine Name: ips_chk_status                                             */ | 
|  | 3950 | /*                                                                          */ | 
|  | 3951 | /* Routine Description:                                                     */ | 
|  | 3952 | /*                                                                          */ | 
|  | 3953 | /*   Check the status of commands to logical drives                         */ | 
|  | 3954 | /*   Assumed to be called with the HA lock                                  */ | 
|  | 3955 | /****************************************************************************/ | 
|  | 3956 | static void | 
|  | 3957 | ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) | 
|  | 3958 | { | 
|  | 3959 | ips_scb_t *scb; | 
|  | 3960 | ips_stat_t *sp; | 
|  | 3961 | uint8_t basic_status; | 
|  | 3962 | uint8_t ext_status; | 
|  | 3963 | int errcode; | 
| Jack Hammer | a5b3c86 | 2006-01-31 13:17:55 -0500 | [diff] [blame] | 3964 | IPS_SCSI_INQ_DATA inquiryData; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3965 |  | 
|  | 3966 | METHOD_TRACE("ips_chkstatus", 1); | 
|  | 3967 |  | 
|  | 3968 | scb = &ha->scbs[pstatus->fields.command_id]; | 
|  | 3969 | scb->basic_status = basic_status = | 
|  | 3970 | pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK; | 
|  | 3971 | scb->extended_status = ext_status = pstatus->fields.extended_status; | 
|  | 3972 |  | 
|  | 3973 | sp = &ha->sp; | 
|  | 3974 | sp->residue_len = 0; | 
|  | 3975 | sp->scb_addr = (void *) scb; | 
|  | 3976 |  | 
|  | 3977 | /* Remove the item from the active queue */ | 
|  | 3978 | ips_removeq_scb(&ha->scb_activelist, scb); | 
|  | 3979 |  | 
|  | 3980 | if (!scb->scsi_cmd) | 
|  | 3981 | /* internal commands are handled in do_ipsintr */ | 
|  | 3982 | return; | 
|  | 3983 |  | 
|  | 3984 | DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)", | 
|  | 3985 | ips_name, | 
|  | 3986 | ha->host_num, | 
|  | 3987 | scb->cdb[0], | 
|  | 3988 | scb->cmd.basic_io.command_id, | 
|  | 3989 | scb->bus, scb->target_id, scb->lun); | 
|  | 3990 |  | 
|  | 3991 | if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) | 
|  | 3992 | /* passthru - just returns the raw result */ | 
|  | 3993 | return; | 
|  | 3994 |  | 
|  | 3995 | errcode = DID_OK; | 
|  | 3996 |  | 
|  | 3997 | if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) || | 
|  | 3998 | ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) { | 
|  | 3999 |  | 
|  | 4000 | if (scb->bus == 0) { | 
|  | 4001 | if ((basic_status & IPS_GSC_STATUS_MASK) == | 
|  | 4002 | IPS_CMD_RECOVERED_ERROR) { | 
|  | 4003 | DEBUG_VAR(1, | 
|  | 4004 | "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", | 
|  | 4005 | ips_name, ha->host_num, | 
|  | 4006 | scb->cmd.basic_io.op_code, | 
|  | 4007 | basic_status, ext_status); | 
|  | 4008 | } | 
|  | 4009 |  | 
|  | 4010 | switch (scb->scsi_cmd->cmnd[0]) { | 
|  | 4011 | case ALLOW_MEDIUM_REMOVAL: | 
|  | 4012 | case REZERO_UNIT: | 
|  | 4013 | case ERASE: | 
|  | 4014 | case WRITE_FILEMARKS: | 
|  | 4015 | case SPACE: | 
|  | 4016 | errcode = DID_ERROR; | 
|  | 4017 | break; | 
|  | 4018 |  | 
|  | 4019 | case START_STOP: | 
|  | 4020 | break; | 
|  | 4021 |  | 
|  | 4022 | case TEST_UNIT_READY: | 
|  | 4023 | if (!ips_online(ha, scb)) { | 
|  | 4024 | errcode = DID_TIME_OUT; | 
|  | 4025 | } | 
|  | 4026 | break; | 
|  | 4027 |  | 
|  | 4028 | case INQUIRY: | 
|  | 4029 | if (ips_online(ha, scb)) { | 
|  | 4030 | ips_inquiry(ha, scb); | 
|  | 4031 | } else { | 
|  | 4032 | errcode = DID_TIME_OUT; | 
|  | 4033 | } | 
|  | 4034 | break; | 
|  | 4035 |  | 
|  | 4036 | case REQUEST_SENSE: | 
|  | 4037 | ips_reqsen(ha, scb); | 
|  | 4038 | break; | 
|  | 4039 |  | 
|  | 4040 | case READ_6: | 
|  | 4041 | case WRITE_6: | 
|  | 4042 | case READ_10: | 
|  | 4043 | case WRITE_10: | 
|  | 4044 | case RESERVE: | 
|  | 4045 | case RELEASE: | 
|  | 4046 | break; | 
|  | 4047 |  | 
|  | 4048 | case MODE_SENSE: | 
|  | 4049 | if (!ips_online(ha, scb) | 
|  | 4050 | || !ips_msense(ha, scb)) { | 
|  | 4051 | errcode = DID_ERROR; | 
|  | 4052 | } | 
|  | 4053 | break; | 
|  | 4054 |  | 
|  | 4055 | case READ_CAPACITY: | 
|  | 4056 | if (ips_online(ha, scb)) | 
|  | 4057 | ips_rdcap(ha, scb); | 
|  | 4058 | else { | 
|  | 4059 | errcode = DID_TIME_OUT; | 
|  | 4060 | } | 
|  | 4061 | break; | 
|  | 4062 |  | 
|  | 4063 | case SEND_DIAGNOSTIC: | 
|  | 4064 | case REASSIGN_BLOCKS: | 
|  | 4065 | break; | 
|  | 4066 |  | 
|  | 4067 | case FORMAT_UNIT: | 
|  | 4068 | errcode = DID_ERROR; | 
|  | 4069 | break; | 
|  | 4070 |  | 
|  | 4071 | case SEEK_10: | 
|  | 4072 | case VERIFY: | 
|  | 4073 | case READ_DEFECT_DATA: | 
|  | 4074 | case READ_BUFFER: | 
|  | 4075 | case WRITE_BUFFER: | 
|  | 4076 | break; | 
|  | 4077 |  | 
|  | 4078 | default: | 
|  | 4079 | errcode = DID_ERROR; | 
|  | 4080 | }	/* end switch */ | 
|  | 4081 |  | 
|  | 4082 | scb->scsi_cmd->result = errcode << 16; | 
|  | 4083 | } else {	/* bus == 0 */ | 
|  | 4084 | /* restrict access to physical drives */ | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4085 | if (scb->scsi_cmd->cmnd[0] == INQUIRY) { | 
|  | 4086 | ips_scmd_buf_read(scb->scsi_cmd, | 
| Jack Hammer | a5b3c86 | 2006-01-31 13:17:55 -0500 | [diff] [blame] | 4087 | &inquiryData, sizeof (inquiryData)); | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4088 | if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) | 
| Jack Hammer | a5b3c86 | 2006-01-31 13:17:55 -0500 | [diff] [blame] | 4089 | scb->scsi_cmd->result = DID_TIME_OUT << 16; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4090 | } | 
|  | 4091 | }		/* else */ | 
|  | 4092 | } else {		/* recovered error / success */ | 
|  | 4093 | if (scb->bus == 0) { | 
|  | 4094 | DEBUG_VAR(1, | 
|  | 4095 | "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", | 
|  | 4096 | ips_name, ha->host_num, | 
|  | 4097 | scb->cmd.basic_io.op_code, basic_status, | 
|  | 4098 | ext_status); | 
|  | 4099 | } | 
|  | 4100 |  | 
|  | 4101 | ips_map_status(ha, scb, sp); | 
|  | 4102 | }			/* else */ | 
|  | 4103 | } | 
|  | 4104 |  | 
|  | 4105 | /****************************************************************************/ | 
|  | 4106 | /*                                                                          */ | 
|  | 4107 | /* Routine Name: ips_online                                                 */ | 
|  | 4108 | /*                                                                          */ | 
|  | 4109 | /* Routine Description:                                                     */ | 
|  | 4110 | /*                                                                          */ | 
|  | 4111 | /*   Determine if a logical drive is online                                 */ | 
|  | 4112 | /*                                                                          */ | 
|  | 4113 | /****************************************************************************/ | 
|  | 4114 | static int | 
|  | 4115 | ips_online(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4116 | { | 
|  | 4117 | METHOD_TRACE("ips_online", 1); | 
|  | 4118 |  | 
|  | 4119 | if (scb->target_id >= IPS_MAX_LD) | 
|  | 4120 | return (0); | 
|  | 4121 |  | 
|  | 4122 | if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) { | 
|  | 4123 | memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO)); | 
|  | 4124 | return (0); | 
|  | 4125 | } | 
|  | 4126 |  | 
|  | 4127 | if (ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4128 | IPS_LD_OFFLINE | 
|  | 4129 | && ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4130 | IPS_LD_FREE | 
|  | 4131 | && ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4132 | IPS_LD_CRS | 
|  | 4133 | && ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4134 | IPS_LD_SYS) | 
|  | 4135 | return (1); | 
|  | 4136 | else | 
|  | 4137 | return (0); | 
|  | 4138 | } | 
|  | 4139 |  | 
|  | 4140 | /****************************************************************************/ | 
|  | 4141 | /*                                                                          */ | 
|  | 4142 | /* Routine Name: ips_inquiry                                                */ | 
|  | 4143 | /*                                                                          */ | 
|  | 4144 | /* Routine Description:                                                     */ | 
|  | 4145 | /*                                                                          */ | 
|  | 4146 | /*   Simulate an inquiry command to a logical drive                         */ | 
|  | 4147 | /*                                                                          */ | 
|  | 4148 | /****************************************************************************/ | 
|  | 4149 | static int | 
|  | 4150 | ips_inquiry(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4151 | { | 
|  | 4152 | IPS_SCSI_INQ_DATA inquiry; | 
|  | 4153 |  | 
|  | 4154 | METHOD_TRACE("ips_inquiry", 1); | 
|  | 4155 |  | 
|  | 4156 | memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA)); | 
|  | 4157 |  | 
|  | 4158 | inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD; | 
|  | 4159 | inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED; | 
|  | 4160 | inquiry.Version = IPS_SCSI_INQ_REV2; | 
|  | 4161 | inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2; | 
|  | 4162 | inquiry.AdditionalLength = 31; | 
|  | 4163 | inquiry.Flags[0] = IPS_SCSI_INQ_Address16; | 
|  | 4164 | inquiry.Flags[1] = | 
|  | 4165 | IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue; | 
|  | 4166 | strncpy(inquiry.VendorId, "IBM     ", 8); | 
|  | 4167 | strncpy(inquiry.ProductId, "SERVERAID       ", 16); | 
|  | 4168 | strncpy(inquiry.ProductRevisionLevel, "1.00", 4); | 
|  | 4169 |  | 
|  | 4170 | ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry)); | 
|  | 4171 |  | 
|  | 4172 | return (1); | 
|  | 4173 | } | 
|  | 4174 |  | 
|  | 4175 | /****************************************************************************/ | 
|  | 4176 | /*                                                                          */ | 
|  | 4177 | /* Routine Name: ips_rdcap                                                  */ | 
|  | 4178 | /*                                                                          */ | 
|  | 4179 | /* Routine Description:                                                     */ | 
|  | 4180 | /*                                                                          */ | 
|  | 4181 | /*   Simulate a read capacity command to a logical drive                    */ | 
|  | 4182 | /*                                                                          */ | 
|  | 4183 | /****************************************************************************/ | 
|  | 4184 | static int | 
|  | 4185 | ips_rdcap(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4186 | { | 
|  | 4187 | IPS_SCSI_CAPACITY cap; | 
|  | 4188 |  | 
|  | 4189 | METHOD_TRACE("ips_rdcap", 1); | 
|  | 4190 |  | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 4191 | if (scsi_bufflen(scb->scsi_cmd) < 8) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4192 | return (0); | 
|  | 4193 |  | 
|  | 4194 | cap.lba = | 
|  | 4195 | cpu_to_be32(le32_to_cpu | 
|  | 4196 | (ha->logical_drive_info-> | 
|  | 4197 | drive_info[scb->target_id].sector_count) - 1); | 
|  | 4198 | cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE); | 
|  | 4199 |  | 
|  | 4200 | ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap)); | 
|  | 4201 |  | 
|  | 4202 | return (1); | 
|  | 4203 | } | 
|  | 4204 |  | 
|  | 4205 | /****************************************************************************/ | 
|  | 4206 | /*                                                                          */ | 
|  | 4207 | /* Routine Name: ips_msense                                                 */ | 
|  | 4208 | /*                                                                          */ | 
|  | 4209 | /* Routine Description:                                                     */ | 
|  | 4210 | /*                                                                          */ | 
|  | 4211 | /*   Simulate a mode sense command to a logical drive                       */ | 
|  | 4212 | /*                                                                          */ | 
|  | 4213 | /****************************************************************************/ | 
|  | 4214 | static int | 
|  | 4215 | ips_msense(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4216 | { | 
|  | 4217 | uint16_t heads; | 
|  | 4218 | uint16_t sectors; | 
|  | 4219 | uint32_t cylinders; | 
|  | 4220 | IPS_SCSI_MODE_PAGE_DATA mdata; | 
|  | 4221 |  | 
|  | 4222 | METHOD_TRACE("ips_msense", 1); | 
|  | 4223 |  | 
|  | 4224 | if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 && | 
|  | 4225 | (ha->enq->ucMiscFlag & 0x8) == 0) { | 
|  | 4226 | heads = IPS_NORM_HEADS; | 
|  | 4227 | sectors = IPS_NORM_SECTORS; | 
|  | 4228 | } else { | 
|  | 4229 | heads = IPS_COMP_HEADS; | 
|  | 4230 | sectors = IPS_COMP_SECTORS; | 
|  | 4231 | } | 
|  | 4232 |  | 
|  | 4233 | cylinders = | 
|  | 4234 | (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) - | 
|  | 4235 | 1) / (heads * sectors); | 
|  | 4236 |  | 
|  | 4237 | memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA)); | 
|  | 4238 |  | 
|  | 4239 | mdata.hdr.BlockDescLength = 8; | 
|  | 4240 |  | 
|  | 4241 | switch (scb->scsi_cmd->cmnd[2] & 0x3f) { | 
|  | 4242 | case 0x03:		/* page 3 */ | 
|  | 4243 | mdata.pdata.pg3.PageCode = 3; | 
|  | 4244 | mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3); | 
|  | 4245 | mdata.hdr.DataLength = | 
|  | 4246 | 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength; | 
|  | 4247 | mdata.pdata.pg3.TracksPerZone = 0; | 
|  | 4248 | mdata.pdata.pg3.AltSectorsPerZone = 0; | 
|  | 4249 | mdata.pdata.pg3.AltTracksPerZone = 0; | 
|  | 4250 | mdata.pdata.pg3.AltTracksPerVolume = 0; | 
|  | 4251 | mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors); | 
|  | 4252 | mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE); | 
|  | 4253 | mdata.pdata.pg3.Interleave = cpu_to_be16(1); | 
|  | 4254 | mdata.pdata.pg3.TrackSkew = 0; | 
|  | 4255 | mdata.pdata.pg3.CylinderSkew = 0; | 
|  | 4256 | mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector; | 
|  | 4257 | break; | 
|  | 4258 |  | 
|  | 4259 | case 0x4: | 
|  | 4260 | mdata.pdata.pg4.PageCode = 4; | 
|  | 4261 | mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4); | 
|  | 4262 | mdata.hdr.DataLength = | 
|  | 4263 | 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength; | 
|  | 4264 | mdata.pdata.pg4.CylindersHigh = | 
|  | 4265 | cpu_to_be16((cylinders >> 8) & 0xFFFF); | 
|  | 4266 | mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF); | 
|  | 4267 | mdata.pdata.pg4.Heads = heads; | 
|  | 4268 | mdata.pdata.pg4.WritePrecompHigh = 0; | 
|  | 4269 | mdata.pdata.pg4.WritePrecompLow = 0; | 
|  | 4270 | mdata.pdata.pg4.ReducedWriteCurrentHigh = 0; | 
|  | 4271 | mdata.pdata.pg4.ReducedWriteCurrentLow = 0; | 
|  | 4272 | mdata.pdata.pg4.StepRate = cpu_to_be16(1); | 
|  | 4273 | mdata.pdata.pg4.LandingZoneHigh = 0; | 
|  | 4274 | mdata.pdata.pg4.LandingZoneLow = 0; | 
|  | 4275 | mdata.pdata.pg4.flags = 0; | 
|  | 4276 | mdata.pdata.pg4.RotationalOffset = 0; | 
|  | 4277 | mdata.pdata.pg4.MediumRotationRate = 0; | 
|  | 4278 | break; | 
|  | 4279 | case 0x8: | 
|  | 4280 | mdata.pdata.pg8.PageCode = 8; | 
|  | 4281 | mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8); | 
|  | 4282 | mdata.hdr.DataLength = | 
|  | 4283 | 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength; | 
|  | 4284 | /* everything else is left set to 0 */ | 
|  | 4285 | break; | 
|  | 4286 |  | 
|  | 4287 | default: | 
|  | 4288 | return (0); | 
|  | 4289 | }			/* end switch */ | 
|  | 4290 |  | 
|  | 4291 | ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata)); | 
|  | 4292 |  | 
|  | 4293 | return (1); | 
|  | 4294 | } | 
|  | 4295 |  | 
|  | 4296 | /****************************************************************************/ | 
|  | 4297 | /*                                                                          */ | 
|  | 4298 | /* Routine Name: ips_reqsen                                                 */ | 
|  | 4299 | /*                                                                          */ | 
|  | 4300 | /* Routine Description:                                                     */ | 
|  | 4301 | /*                                                                          */ | 
|  | 4302 | /*   Simulate a request sense command to a logical drive                    */ | 
|  | 4303 | /*                                                                          */ | 
|  | 4304 | /****************************************************************************/ | 
|  | 4305 | static int | 
|  | 4306 | ips_reqsen(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4307 | { | 
|  | 4308 | IPS_SCSI_REQSEN reqsen; | 
|  | 4309 |  | 
|  | 4310 | METHOD_TRACE("ips_reqsen", 1); | 
|  | 4311 |  | 
|  | 4312 | memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN)); | 
|  | 4313 |  | 
|  | 4314 | reqsen.ResponseCode = | 
|  | 4315 | IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR; | 
|  | 4316 | reqsen.AdditionalLength = 10; | 
|  | 4317 | reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE; | 
|  | 4318 | reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE; | 
|  | 4319 |  | 
|  | 4320 | ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen)); | 
|  | 4321 |  | 
|  | 4322 | return (1); | 
|  | 4323 | } | 
|  | 4324 |  | 
|  | 4325 | /****************************************************************************/ | 
|  | 4326 | /*                                                                          */ | 
|  | 4327 | /* Routine Name: ips_free                                                   */ | 
|  | 4328 | /*                                                                          */ | 
|  | 4329 | /* Routine Description:                                                     */ | 
|  | 4330 | /*                                                                          */ | 
|  | 4331 | /*   Free any allocated space for this controller                           */ | 
|  | 4332 | /*                                                                          */ | 
|  | 4333 | /****************************************************************************/ | 
|  | 4334 | static void | 
|  | 4335 | ips_free(ips_ha_t * ha) | 
|  | 4336 | { | 
|  | 4337 |  | 
|  | 4338 | METHOD_TRACE("ips_free", 1); | 
|  | 4339 |  | 
|  | 4340 | if (ha) { | 
|  | 4341 | if (ha->enq) { | 
|  | 4342 | pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ), | 
|  | 4343 | ha->enq, ha->enq_busaddr); | 
|  | 4344 | ha->enq = NULL; | 
|  | 4345 | } | 
|  | 4346 |  | 
| Jesper Juhl | c9475cb | 2005-11-07 01:01:26 -0800 | [diff] [blame] | 4347 | kfree(ha->conf); | 
|  | 4348 | ha->conf = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4349 |  | 
|  | 4350 | if (ha->adapt) { | 
|  | 4351 | pci_free_consistent(ha->pcidev, | 
|  | 4352 | sizeof (IPS_ADAPTER) + | 
|  | 4353 | sizeof (IPS_IO_CMD), ha->adapt, | 
|  | 4354 | ha->adapt->hw_status_start); | 
|  | 4355 | ha->adapt = NULL; | 
|  | 4356 | } | 
|  | 4357 |  | 
|  | 4358 | if (ha->logical_drive_info) { | 
|  | 4359 | pci_free_consistent(ha->pcidev, | 
|  | 4360 | sizeof (IPS_LD_INFO), | 
|  | 4361 | ha->logical_drive_info, | 
|  | 4362 | ha->logical_drive_info_dma_addr); | 
|  | 4363 | ha->logical_drive_info = NULL; | 
|  | 4364 | } | 
|  | 4365 |  | 
| Jesper Juhl | c9475cb | 2005-11-07 01:01:26 -0800 | [diff] [blame] | 4366 | kfree(ha->nvram); | 
|  | 4367 | ha->nvram = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4368 |  | 
| Jesper Juhl | c9475cb | 2005-11-07 01:01:26 -0800 | [diff] [blame] | 4369 | kfree(ha->subsys); | 
|  | 4370 | ha->subsys = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4371 |  | 
|  | 4372 | if (ha->ioctl_data) { | 
|  | 4373 | pci_free_consistent(ha->pcidev, ha->ioctl_len, | 
|  | 4374 | ha->ioctl_data, ha->ioctl_busaddr); | 
|  | 4375 | ha->ioctl_data = NULL; | 
|  | 4376 | ha->ioctl_datasize = 0; | 
|  | 4377 | ha->ioctl_len = 0; | 
|  | 4378 | } | 
|  | 4379 | ips_deallocatescbs(ha, ha->max_cmds); | 
|  | 4380 |  | 
|  | 4381 | /* free memory mapped (if applicable) */ | 
|  | 4382 | if (ha->mem_ptr) { | 
|  | 4383 | iounmap(ha->ioremap_ptr); | 
|  | 4384 | ha->ioremap_ptr = NULL; | 
|  | 4385 | ha->mem_ptr = NULL; | 
|  | 4386 | } | 
|  | 4387 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4388 | ha->mem_addr = 0; | 
|  | 4389 |  | 
|  | 4390 | } | 
|  | 4391 | } | 
|  | 4392 |  | 
|  | 4393 | /****************************************************************************/ | 
|  | 4394 | /*                                                                          */ | 
|  | 4395 | /* Routine Name: ips_deallocatescbs                                         */ | 
|  | 4396 | /*                                                                          */ | 
|  | 4397 | /* Routine Description:                                                     */ | 
|  | 4398 | /*                                                                          */ | 
|  | 4399 | /*   Free the command blocks                                                */ | 
|  | 4400 | /*                                                                          */ | 
|  | 4401 | /****************************************************************************/ | 
|  | 4402 | static int | 
|  | 4403 | ips_deallocatescbs(ips_ha_t * ha, int cmds) | 
|  | 4404 | { | 
|  | 4405 | if (ha->scbs) { | 
|  | 4406 | pci_free_consistent(ha->pcidev, | 
|  | 4407 | IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds, | 
|  | 4408 | ha->scbs->sg_list.list, | 
|  | 4409 | ha->scbs->sg_busaddr); | 
|  | 4410 | pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds, | 
|  | 4411 | ha->scbs, ha->scbs->scb_busaddr); | 
|  | 4412 | ha->scbs = NULL; | 
|  | 4413 | }			/* end if */ | 
|  | 4414 | return 1; | 
|  | 4415 | } | 
|  | 4416 |  | 
|  | 4417 | /****************************************************************************/ | 
|  | 4418 | /*                                                                          */ | 
|  | 4419 | /* Routine Name: ips_allocatescbs                                           */ | 
|  | 4420 | /*                                                                          */ | 
|  | 4421 | /* Routine Description:                                                     */ | 
|  | 4422 | /*                                                                          */ | 
|  | 4423 | /*   Allocate the command blocks                                            */ | 
|  | 4424 | /*                                                                          */ | 
|  | 4425 | /****************************************************************************/ | 
|  | 4426 | static int | 
|  | 4427 | ips_allocatescbs(ips_ha_t * ha) | 
|  | 4428 | { | 
|  | 4429 | ips_scb_t *scb_p; | 
|  | 4430 | IPS_SG_LIST ips_sg; | 
|  | 4431 | int i; | 
|  | 4432 | dma_addr_t command_dma, sg_dma; | 
|  | 4433 |  | 
|  | 4434 | METHOD_TRACE("ips_allocatescbs", 1); | 
|  | 4435 |  | 
|  | 4436 | /* Allocate memory for the SCBs */ | 
|  | 4437 | ha->scbs = | 
|  | 4438 | pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t), | 
|  | 4439 | &command_dma); | 
|  | 4440 | if (ha->scbs == NULL) | 
|  | 4441 | return 0; | 
|  | 4442 | ips_sg.list = | 
|  | 4443 | pci_alloc_consistent(ha->pcidev, | 
|  | 4444 | IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * | 
|  | 4445 | ha->max_cmds, &sg_dma); | 
|  | 4446 | if (ips_sg.list == NULL) { | 
|  | 4447 | pci_free_consistent(ha->pcidev, | 
|  | 4448 | ha->max_cmds * sizeof (ips_scb_t), ha->scbs, | 
|  | 4449 | command_dma); | 
|  | 4450 | return 0; | 
|  | 4451 | } | 
|  | 4452 |  | 
|  | 4453 | memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t)); | 
|  | 4454 |  | 
|  | 4455 | for (i = 0; i < ha->max_cmds; i++) { | 
|  | 4456 | scb_p = &ha->scbs[i]; | 
|  | 4457 | scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i; | 
|  | 4458 | /* set up S/G list */ | 
|  | 4459 | if (IPS_USE_ENH_SGLIST(ha)) { | 
|  | 4460 | scb_p->sg_list.enh_list = | 
|  | 4461 | ips_sg.enh_list + i * IPS_MAX_SG; | 
|  | 4462 | scb_p->sg_busaddr = | 
|  | 4463 | sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; | 
|  | 4464 | } else { | 
|  | 4465 | scb_p->sg_list.std_list = | 
|  | 4466 | ips_sg.std_list + i * IPS_MAX_SG; | 
|  | 4467 | scb_p->sg_busaddr = | 
|  | 4468 | sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; | 
|  | 4469 | } | 
|  | 4470 |  | 
|  | 4471 | /* add to the free list */ | 
|  | 4472 | if (i < ha->max_cmds - 1) { | 
|  | 4473 | scb_p->q_next = ha->scb_freelist; | 
|  | 4474 | ha->scb_freelist = scb_p; | 
|  | 4475 | } | 
|  | 4476 | } | 
|  | 4477 |  | 
|  | 4478 | /* success */ | 
|  | 4479 | return (1); | 
|  | 4480 | } | 
|  | 4481 |  | 
|  | 4482 | /****************************************************************************/ | 
|  | 4483 | /*                                                                          */ | 
|  | 4484 | /* Routine Name: ips_init_scb                                               */ | 
|  | 4485 | /*                                                                          */ | 
|  | 4486 | /* Routine Description:                                                     */ | 
|  | 4487 | /*                                                                          */ | 
|  | 4488 | /*   Initialize a CCB to default values                                     */ | 
|  | 4489 | /*                                                                          */ | 
|  | 4490 | /****************************************************************************/ | 
|  | 4491 | static void | 
|  | 4492 | ips_init_scb(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4493 | { | 
|  | 4494 | IPS_SG_LIST sg_list; | 
|  | 4495 | uint32_t cmd_busaddr, sg_busaddr; | 
|  | 4496 | METHOD_TRACE("ips_init_scb", 1); | 
|  | 4497 |  | 
|  | 4498 | if (scb == NULL) | 
|  | 4499 | return; | 
|  | 4500 |  | 
|  | 4501 | sg_list.list = scb->sg_list.list; | 
|  | 4502 | cmd_busaddr = scb->scb_busaddr; | 
|  | 4503 | sg_busaddr = scb->sg_busaddr; | 
|  | 4504 | /* zero fill */ | 
|  | 4505 | memset(scb, 0, sizeof (ips_scb_t)); | 
|  | 4506 | memset(ha->dummy, 0, sizeof (IPS_IO_CMD)); | 
|  | 4507 |  | 
|  | 4508 | /* Initialize dummy command bucket */ | 
|  | 4509 | ha->dummy->op_code = 0xFF; | 
|  | 4510 | ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start | 
|  | 4511 | + sizeof (IPS_ADAPTER)); | 
|  | 4512 | ha->dummy->command_id = IPS_MAX_CMDS; | 
|  | 4513 |  | 
|  | 4514 | /* set bus address of scb */ | 
|  | 4515 | scb->scb_busaddr = cmd_busaddr; | 
|  | 4516 | scb->sg_busaddr = sg_busaddr; | 
|  | 4517 | scb->sg_list.list = sg_list.list; | 
|  | 4518 |  | 
|  | 4519 | /* Neptune Fix */ | 
|  | 4520 | scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE); | 
|  | 4521 | scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start | 
|  | 4522 | + sizeof (IPS_ADAPTER)); | 
|  | 4523 | } | 
|  | 4524 |  | 
|  | 4525 | /****************************************************************************/ | 
|  | 4526 | /*                                                                          */ | 
|  | 4527 | /* Routine Name: ips_get_scb                                                */ | 
|  | 4528 | /*                                                                          */ | 
|  | 4529 | /* Routine Description:                                                     */ | 
|  | 4530 | /*                                                                          */ | 
|  | 4531 | /*   Initialize a CCB to default values                                     */ | 
|  | 4532 | /*                                                                          */ | 
|  | 4533 | /* ASSUMED to be callled from within a lock                                 */ | 
|  | 4534 | /*                                                                          */ | 
|  | 4535 | /****************************************************************************/ | 
|  | 4536 | static ips_scb_t * | 
|  | 4537 | ips_getscb(ips_ha_t * ha) | 
|  | 4538 | { | 
|  | 4539 | ips_scb_t *scb; | 
|  | 4540 |  | 
|  | 4541 | METHOD_TRACE("ips_getscb", 1); | 
|  | 4542 |  | 
|  | 4543 | if ((scb = ha->scb_freelist) == NULL) { | 
|  | 4544 |  | 
|  | 4545 | return (NULL); | 
|  | 4546 | } | 
|  | 4547 |  | 
|  | 4548 | ha->scb_freelist = scb->q_next; | 
|  | 4549 | scb->flags = 0; | 
|  | 4550 | scb->q_next = NULL; | 
|  | 4551 |  | 
|  | 4552 | ips_init_scb(ha, scb); | 
|  | 4553 |  | 
|  | 4554 | return (scb); | 
|  | 4555 | } | 
|  | 4556 |  | 
|  | 4557 | /****************************************************************************/ | 
|  | 4558 | /*                                                                          */ | 
|  | 4559 | /* Routine Name: ips_free_scb                                               */ | 
|  | 4560 | /*                                                                          */ | 
|  | 4561 | /* Routine Description:                                                     */ | 
|  | 4562 | /*                                                                          */ | 
|  | 4563 | /*   Return an unused CCB back to the free list                             */ | 
|  | 4564 | /*                                                                          */ | 
|  | 4565 | /* ASSUMED to be called from within a lock                                  */ | 
|  | 4566 | /*                                                                          */ | 
|  | 4567 | /****************************************************************************/ | 
|  | 4568 | static void | 
|  | 4569 | ips_freescb(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4570 | { | 
|  | 4571 |  | 
|  | 4572 | METHOD_TRACE("ips_freescb", 1); | 
|  | 4573 | if (scb->flags & IPS_SCB_MAP_SG) | 
| FUJITA Tomonori | 2f4cf91 | 2007-06-13 23:27:09 +0900 | [diff] [blame] | 4574 | scsi_dma_unmap(scb->scsi_cmd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4575 | else if (scb->flags & IPS_SCB_MAP_SINGLE) | 
|  | 4576 | pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len, | 
|  | 4577 | IPS_DMA_DIR(scb)); | 
|  | 4578 |  | 
|  | 4579 | /* check to make sure this is not our "special" scb */ | 
|  | 4580 | if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { | 
|  | 4581 | scb->q_next = ha->scb_freelist; | 
|  | 4582 | ha->scb_freelist = scb; | 
|  | 4583 | } | 
|  | 4584 | } | 
|  | 4585 |  | 
|  | 4586 | /****************************************************************************/ | 
|  | 4587 | /*                                                                          */ | 
|  | 4588 | /* Routine Name: ips_isinit_copperhead                                      */ | 
|  | 4589 | /*                                                                          */ | 
|  | 4590 | /* Routine Description:                                                     */ | 
|  | 4591 | /*                                                                          */ | 
|  | 4592 | /*   Is controller initialized ?                                            */ | 
|  | 4593 | /*                                                                          */ | 
|  | 4594 | /****************************************************************************/ | 
|  | 4595 | static int | 
|  | 4596 | ips_isinit_copperhead(ips_ha_t * ha) | 
|  | 4597 | { | 
|  | 4598 | uint8_t scpr; | 
|  | 4599 | uint8_t isr; | 
|  | 4600 |  | 
|  | 4601 | METHOD_TRACE("ips_isinit_copperhead", 1); | 
|  | 4602 |  | 
|  | 4603 | isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 4604 | scpr = inb(ha->io_addr + IPS_REG_SCPR); | 
|  | 4605 |  | 
|  | 4606 | if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) | 
|  | 4607 | return (0); | 
|  | 4608 | else | 
|  | 4609 | return (1); | 
|  | 4610 | } | 
|  | 4611 |  | 
|  | 4612 | /****************************************************************************/ | 
|  | 4613 | /*                                                                          */ | 
|  | 4614 | /* Routine Name: ips_isinit_copperhead_memio                                */ | 
|  | 4615 | /*                                                                          */ | 
|  | 4616 | /* Routine Description:                                                     */ | 
|  | 4617 | /*                                                                          */ | 
|  | 4618 | /*   Is controller initialized ?                                            */ | 
|  | 4619 | /*                                                                          */ | 
|  | 4620 | /****************************************************************************/ | 
|  | 4621 | static int | 
|  | 4622 | ips_isinit_copperhead_memio(ips_ha_t * ha) | 
|  | 4623 | { | 
|  | 4624 | uint8_t isr = 0; | 
|  | 4625 | uint8_t scpr; | 
|  | 4626 |  | 
|  | 4627 | METHOD_TRACE("ips_is_init_copperhead_memio", 1); | 
|  | 4628 |  | 
|  | 4629 | isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 4630 | scpr = readb(ha->mem_ptr + IPS_REG_SCPR); | 
|  | 4631 |  | 
|  | 4632 | if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) | 
|  | 4633 | return (0); | 
|  | 4634 | else | 
|  | 4635 | return (1); | 
|  | 4636 | } | 
|  | 4637 |  | 
|  | 4638 | /****************************************************************************/ | 
|  | 4639 | /*                                                                          */ | 
|  | 4640 | /* Routine Name: ips_isinit_morpheus                                        */ | 
|  | 4641 | /*                                                                          */ | 
|  | 4642 | /* Routine Description:                                                     */ | 
|  | 4643 | /*                                                                          */ | 
|  | 4644 | /*   Is controller initialized ?                                            */ | 
|  | 4645 | /*                                                                          */ | 
|  | 4646 | /****************************************************************************/ | 
|  | 4647 | static int | 
|  | 4648 | ips_isinit_morpheus(ips_ha_t * ha) | 
|  | 4649 | { | 
|  | 4650 | uint32_t post; | 
|  | 4651 | uint32_t bits; | 
|  | 4652 |  | 
|  | 4653 | METHOD_TRACE("ips_is_init_morpheus", 1); | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4654 |  | 
|  | 4655 | if (ips_isintr_morpheus(ha)) | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4656 | ips_flush_and_reset(ha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4657 |  | 
|  | 4658 | post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); | 
|  | 4659 | bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 4660 |  | 
|  | 4661 | if (post == 0) | 
|  | 4662 | return (0); | 
|  | 4663 | else if (bits & 0x3) | 
|  | 4664 | return (0); | 
|  | 4665 | else | 
|  | 4666 | return (1); | 
|  | 4667 | } | 
|  | 4668 |  | 
|  | 4669 | /****************************************************************************/ | 
|  | 4670 | /*                                                                          */ | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4671 | /* Routine Name: ips_flush_and_reset                                        */ | 
|  | 4672 | /*                                                                          */ | 
|  | 4673 | /* Routine Description:                                                     */ | 
|  | 4674 | /*                                                                          */ | 
|  | 4675 | /*   Perform cleanup ( FLUSH and RESET ) when the adapter is in an unknown  */ | 
|  | 4676 | /*   state ( was trying to INIT and an interrupt was already pending ) ...  */ | 
|  | 4677 | /*                                                                          */ | 
|  | 4678 | /****************************************************************************/ | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4679 | static void | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4680 | ips_flush_and_reset(ips_ha_t *ha) | 
|  | 4681 | { | 
|  | 4682 | ips_scb_t *scb; | 
|  | 4683 | int  ret; | 
|  | 4684 | int  time; | 
|  | 4685 | int  done; | 
|  | 4686 | dma_addr_t command_dma; | 
|  | 4687 |  | 
|  | 4688 | /* Create a usuable SCB */ | 
|  | 4689 | scb = pci_alloc_consistent(ha->pcidev, sizeof(ips_scb_t), &command_dma); | 
|  | 4690 | if (scb) { | 
|  | 4691 | memset(scb, 0, sizeof(ips_scb_t)); | 
|  | 4692 | ips_init_scb(ha, scb); | 
|  | 4693 | scb->scb_busaddr = command_dma; | 
|  | 4694 |  | 
|  | 4695 | scb->timeout = ips_cmd_timeout; | 
|  | 4696 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 4697 |  | 
|  | 4698 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 4699 | scb->cmd.flush_cache.command_id = IPS_MAX_CMDS;   /* Use an ID that would otherwise not exist */ | 
|  | 4700 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 4701 | scb->cmd.flush_cache.reserved = 0; | 
|  | 4702 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 4703 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 4704 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 4705 |  | 
|  | 4706 | ret = ips_send_cmd(ha, scb);                      /* Send the Flush Command */ | 
|  | 4707 |  | 
|  | 4708 | if (ret == IPS_SUCCESS) { | 
|  | 4709 | time = 60 * IPS_ONE_SEC;	              /* Max Wait time is 60 seconds */ | 
|  | 4710 | done = 0; | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4711 |  | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4712 | while ((time > 0) && (!done)) { | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4713 | done = ips_poll_for_flush_complete(ha); | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4714 | /* This may look evil, but it's only done during extremely rare start-up conditions ! */ | 
|  | 4715 | udelay(1000); | 
|  | 4716 | time--; | 
|  | 4717 | } | 
|  | 4718 | } | 
|  | 4719 | } | 
|  | 4720 |  | 
|  | 4721 | /* Now RESET and INIT the adapter */ | 
|  | 4722 | (*ha->func.reset) (ha); | 
|  | 4723 |  | 
|  | 4724 | pci_free_consistent(ha->pcidev, sizeof(ips_scb_t), scb, command_dma); | 
|  | 4725 | return; | 
|  | 4726 | } | 
|  | 4727 |  | 
|  | 4728 | /****************************************************************************/ | 
|  | 4729 | /*                                                                          */ | 
|  | 4730 | /* Routine Name: ips_poll_for_flush_complete                                */ | 
|  | 4731 | /*                                                                          */ | 
|  | 4732 | /* Routine Description:                                                     */ | 
|  | 4733 | /*                                                                          */ | 
|  | 4734 | /*   Poll for the Flush Command issued by ips_flush_and_reset() to complete */ | 
|  | 4735 | /*   All other responses are just taken off the queue and ignored           */ | 
|  | 4736 | /*                                                                          */ | 
|  | 4737 | /****************************************************************************/ | 
|  | 4738 | static int | 
|  | 4739 | ips_poll_for_flush_complete(ips_ha_t * ha) | 
|  | 4740 | { | 
|  | 4741 | IPS_STATUS cstatus; | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4742 |  | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4743 | while (TRUE) { | 
|  | 4744 | cstatus.value = (*ha->func.statupd) (ha); | 
|  | 4745 |  | 
|  | 4746 | if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */ | 
|  | 4747 | break; | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4748 |  | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4749 | /* Success is when we see the Flush Command ID */ | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4750 | if (cstatus.fields.command_id == IPS_MAX_CMDS) | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4751 | return 1; | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 4752 | } | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4753 |  | 
|  | 4754 | return 0; | 
| James Bottomley | 0ee957c | 2005-11-04 23:22:55 -0600 | [diff] [blame] | 4755 | } | 
| Jack Hammer | ee807c2 | 2005-08-29 10:44:34 -0400 | [diff] [blame] | 4756 |  | 
|  | 4757 | /****************************************************************************/ | 
|  | 4758 | /*                                                                          */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4759 | /* Routine Name: ips_enable_int_copperhead                                  */ | 
|  | 4760 | /*                                                                          */ | 
|  | 4761 | /* Routine Description:                                                     */ | 
|  | 4762 | /*   Turn on interrupts                                                     */ | 
|  | 4763 | /*                                                                          */ | 
|  | 4764 | /****************************************************************************/ | 
|  | 4765 | static void | 
|  | 4766 | ips_enable_int_copperhead(ips_ha_t * ha) | 
|  | 4767 | { | 
|  | 4768 | METHOD_TRACE("ips_enable_int_copperhead", 1); | 
|  | 4769 |  | 
|  | 4770 | outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI); | 
|  | 4771 | inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/ | 
|  | 4772 | } | 
|  | 4773 |  | 
|  | 4774 | /****************************************************************************/ | 
|  | 4775 | /*                                                                          */ | 
|  | 4776 | /* Routine Name: ips_enable_int_copperhead_memio                            */ | 
|  | 4777 | /*                                                                          */ | 
|  | 4778 | /* Routine Description:                                                     */ | 
|  | 4779 | /*   Turn on interrupts                                                     */ | 
|  | 4780 | /*                                                                          */ | 
|  | 4781 | /****************************************************************************/ | 
|  | 4782 | static void | 
|  | 4783 | ips_enable_int_copperhead_memio(ips_ha_t * ha) | 
|  | 4784 | { | 
|  | 4785 | METHOD_TRACE("ips_enable_int_copperhead_memio", 1); | 
|  | 4786 |  | 
|  | 4787 | writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); | 
|  | 4788 | readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/ | 
|  | 4789 | } | 
|  | 4790 |  | 
|  | 4791 | /****************************************************************************/ | 
|  | 4792 | /*                                                                          */ | 
|  | 4793 | /* Routine Name: ips_enable_int_morpheus                                    */ | 
|  | 4794 | /*                                                                          */ | 
|  | 4795 | /* Routine Description:                                                     */ | 
|  | 4796 | /*   Turn on interrupts                                                     */ | 
|  | 4797 | /*                                                                          */ | 
|  | 4798 | /****************************************************************************/ | 
|  | 4799 | static void | 
|  | 4800 | ips_enable_int_morpheus(ips_ha_t * ha) | 
|  | 4801 | { | 
|  | 4802 | uint32_t Oimr; | 
|  | 4803 |  | 
|  | 4804 | METHOD_TRACE("ips_enable_int_morpheus", 1); | 
|  | 4805 |  | 
|  | 4806 | Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 4807 | Oimr &= ~0x08; | 
|  | 4808 | writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 4809 | readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/ | 
|  | 4810 | } | 
|  | 4811 |  | 
|  | 4812 | /****************************************************************************/ | 
|  | 4813 | /*                                                                          */ | 
|  | 4814 | /* Routine Name: ips_init_copperhead                                        */ | 
|  | 4815 | /*                                                                          */ | 
|  | 4816 | /* Routine Description:                                                     */ | 
|  | 4817 | /*                                                                          */ | 
|  | 4818 | /*   Initialize a copperhead controller                                     */ | 
|  | 4819 | /*                                                                          */ | 
|  | 4820 | /****************************************************************************/ | 
|  | 4821 | static int | 
|  | 4822 | ips_init_copperhead(ips_ha_t * ha) | 
|  | 4823 | { | 
|  | 4824 | uint8_t Isr; | 
|  | 4825 | uint8_t Cbsp; | 
|  | 4826 | uint8_t PostByte[IPS_MAX_POST_BYTES]; | 
|  | 4827 | uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; | 
|  | 4828 | int i, j; | 
|  | 4829 |  | 
|  | 4830 | METHOD_TRACE("ips_init_copperhead", 1); | 
|  | 4831 |  | 
|  | 4832 | for (i = 0; i < IPS_MAX_POST_BYTES; i++) { | 
|  | 4833 | for (j = 0; j < 45; j++) { | 
|  | 4834 | Isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 4835 | if (Isr & IPS_BIT_GHI) | 
|  | 4836 | break; | 
|  | 4837 |  | 
|  | 4838 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 4839 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4840 | } | 
|  | 4841 |  | 
|  | 4842 | if (j >= 45) | 
|  | 4843 | /* error occurred */ | 
|  | 4844 | return (0); | 
|  | 4845 |  | 
|  | 4846 | PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); | 
|  | 4847 | outb(Isr, ha->io_addr + IPS_REG_HISR); | 
|  | 4848 | } | 
|  | 4849 |  | 
|  | 4850 | if (PostByte[0] < IPS_GOOD_POST_STATUS) { | 
|  | 4851 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 4852 | "reset controller fails (post status %x %x).\n", | 
|  | 4853 | PostByte[0], PostByte[1]); | 
|  | 4854 |  | 
|  | 4855 | return (0); | 
|  | 4856 | } | 
|  | 4857 |  | 
|  | 4858 | for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { | 
|  | 4859 | for (j = 0; j < 240; j++) { | 
|  | 4860 | Isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 4861 | if (Isr & IPS_BIT_GHI) | 
|  | 4862 | break; | 
|  | 4863 |  | 
|  | 4864 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 4865 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4866 | } | 
|  | 4867 |  | 
|  | 4868 | if (j >= 240) | 
|  | 4869 | /* error occurred */ | 
|  | 4870 | return (0); | 
|  | 4871 |  | 
|  | 4872 | ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); | 
|  | 4873 | outb(Isr, ha->io_addr + IPS_REG_HISR); | 
|  | 4874 | } | 
|  | 4875 |  | 
|  | 4876 | for (i = 0; i < 240; i++) { | 
|  | 4877 | Cbsp = inb(ha->io_addr + IPS_REG_CBSP); | 
|  | 4878 |  | 
|  | 4879 | if ((Cbsp & IPS_BIT_OP) == 0) | 
|  | 4880 | break; | 
|  | 4881 |  | 
|  | 4882 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 4883 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4884 | } | 
|  | 4885 |  | 
|  | 4886 | if (i >= 240) | 
|  | 4887 | /* reset failed */ | 
|  | 4888 | return (0); | 
|  | 4889 |  | 
|  | 4890 | /* setup CCCR */ | 
|  | 4891 | outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR); | 
|  | 4892 |  | 
|  | 4893 | /* Enable busmastering */ | 
|  | 4894 | outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); | 
|  | 4895 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 4896 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4897 | /* fix for anaconda64 */ | 
|  | 4898 | outl(0, ha->io_addr + IPS_REG_NDAE); | 
|  | 4899 |  | 
|  | 4900 | /* Enable interrupts */ | 
|  | 4901 | outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); | 
|  | 4902 |  | 
|  | 4903 | return (1); | 
|  | 4904 | } | 
|  | 4905 |  | 
|  | 4906 | /****************************************************************************/ | 
|  | 4907 | /*                                                                          */ | 
|  | 4908 | /* Routine Name: ips_init_copperhead_memio                                  */ | 
|  | 4909 | /*                                                                          */ | 
|  | 4910 | /* Routine Description:                                                     */ | 
|  | 4911 | /*                                                                          */ | 
|  | 4912 | /*   Initialize a copperhead controller with memory mapped I/O              */ | 
|  | 4913 | /*                                                                          */ | 
|  | 4914 | /****************************************************************************/ | 
|  | 4915 | static int | 
|  | 4916 | ips_init_copperhead_memio(ips_ha_t * ha) | 
|  | 4917 | { | 
|  | 4918 | uint8_t Isr = 0; | 
|  | 4919 | uint8_t Cbsp; | 
|  | 4920 | uint8_t PostByte[IPS_MAX_POST_BYTES]; | 
|  | 4921 | uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; | 
|  | 4922 | int i, j; | 
|  | 4923 |  | 
|  | 4924 | METHOD_TRACE("ips_init_copperhead_memio", 1); | 
|  | 4925 |  | 
|  | 4926 | for (i = 0; i < IPS_MAX_POST_BYTES; i++) { | 
|  | 4927 | for (j = 0; j < 45; j++) { | 
|  | 4928 | Isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 4929 | if (Isr & IPS_BIT_GHI) | 
|  | 4930 | break; | 
|  | 4931 |  | 
|  | 4932 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 4933 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4934 | } | 
|  | 4935 |  | 
|  | 4936 | if (j >= 45) | 
|  | 4937 | /* error occurred */ | 
|  | 4938 | return (0); | 
|  | 4939 |  | 
|  | 4940 | PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); | 
|  | 4941 | writeb(Isr, ha->mem_ptr + IPS_REG_HISR); | 
|  | 4942 | } | 
|  | 4943 |  | 
|  | 4944 | if (PostByte[0] < IPS_GOOD_POST_STATUS) { | 
|  | 4945 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 4946 | "reset controller fails (post status %x %x).\n", | 
|  | 4947 | PostByte[0], PostByte[1]); | 
|  | 4948 |  | 
|  | 4949 | return (0); | 
|  | 4950 | } | 
|  | 4951 |  | 
|  | 4952 | for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { | 
|  | 4953 | for (j = 0; j < 240; j++) { | 
|  | 4954 | Isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 4955 | if (Isr & IPS_BIT_GHI) | 
|  | 4956 | break; | 
|  | 4957 |  | 
|  | 4958 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 4959 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4960 | } | 
|  | 4961 |  | 
|  | 4962 | if (j >= 240) | 
|  | 4963 | /* error occurred */ | 
|  | 4964 | return (0); | 
|  | 4965 |  | 
|  | 4966 | ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); | 
|  | 4967 | writeb(Isr, ha->mem_ptr + IPS_REG_HISR); | 
|  | 4968 | } | 
|  | 4969 |  | 
|  | 4970 | for (i = 0; i < 240; i++) { | 
|  | 4971 | Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP); | 
|  | 4972 |  | 
|  | 4973 | if ((Cbsp & IPS_BIT_OP) == 0) | 
|  | 4974 | break; | 
|  | 4975 |  | 
|  | 4976 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 4977 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4978 | } | 
|  | 4979 |  | 
|  | 4980 | if (i >= 240) | 
|  | 4981 | /* error occurred */ | 
|  | 4982 | return (0); | 
|  | 4983 |  | 
|  | 4984 | /* setup CCCR */ | 
|  | 4985 | writel(0x1010, ha->mem_ptr + IPS_REG_CCCR); | 
|  | 4986 |  | 
|  | 4987 | /* Enable busmastering */ | 
|  | 4988 | writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); | 
|  | 4989 |  | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 4990 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4991 | /* fix for anaconda64 */ | 
|  | 4992 | writel(0, ha->mem_ptr + IPS_REG_NDAE); | 
|  | 4993 |  | 
|  | 4994 | /* Enable interrupts */ | 
|  | 4995 | writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); | 
|  | 4996 |  | 
|  | 4997 | /* if we get here then everything went OK */ | 
|  | 4998 | return (1); | 
|  | 4999 | } | 
|  | 5000 |  | 
|  | 5001 | /****************************************************************************/ | 
|  | 5002 | /*                                                                          */ | 
|  | 5003 | /* Routine Name: ips_init_morpheus                                          */ | 
|  | 5004 | /*                                                                          */ | 
|  | 5005 | /* Routine Description:                                                     */ | 
|  | 5006 | /*                                                                          */ | 
|  | 5007 | /*   Initialize a morpheus controller                                       */ | 
|  | 5008 | /*                                                                          */ | 
|  | 5009 | /****************************************************************************/ | 
|  | 5010 | static int | 
|  | 5011 | ips_init_morpheus(ips_ha_t * ha) | 
|  | 5012 | { | 
|  | 5013 | uint32_t Post; | 
|  | 5014 | uint32_t Config; | 
|  | 5015 | uint32_t Isr; | 
|  | 5016 | uint32_t Oimr; | 
|  | 5017 | int i; | 
|  | 5018 |  | 
|  | 5019 | METHOD_TRACE("ips_init_morpheus", 1); | 
|  | 5020 |  | 
|  | 5021 | /* Wait up to 45 secs for Post */ | 
|  | 5022 | for (i = 0; i < 45; i++) { | 
|  | 5023 | Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5024 |  | 
|  | 5025 | if (Isr & IPS_BIT_I960_MSG0I) | 
|  | 5026 | break; | 
|  | 5027 |  | 
|  | 5028 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5029 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5030 | } | 
|  | 5031 |  | 
|  | 5032 | if (i >= 45) { | 
|  | 5033 | /* error occurred */ | 
|  | 5034 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5035 | "timeout waiting for post.\n"); | 
|  | 5036 |  | 
|  | 5037 | return (0); | 
|  | 5038 | } | 
|  | 5039 |  | 
|  | 5040 | Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); | 
|  | 5041 |  | 
|  | 5042 | if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */ | 
|  | 5043 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5044 | "Flashing Battery PIC, Please wait ...\n"); | 
|  | 5045 |  | 
|  | 5046 | /* Clear the interrupt bit */ | 
|  | 5047 | Isr = (uint32_t) IPS_BIT_I960_MSG0I; | 
|  | 5048 | writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5049 |  | 
|  | 5050 | for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */ | 
|  | 5051 | Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); | 
|  | 5052 | if (Post != 0x4F00) | 
|  | 5053 | break; | 
|  | 5054 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5055 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5056 | } | 
|  | 5057 |  | 
|  | 5058 | if (i >= 120) { | 
|  | 5059 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5060 | "timeout waiting for Battery PIC Flash\n"); | 
|  | 5061 | return (0); | 
|  | 5062 | } | 
|  | 5063 |  | 
|  | 5064 | } | 
|  | 5065 |  | 
|  | 5066 | /* Clear the interrupt bit */ | 
|  | 5067 | Isr = (uint32_t) IPS_BIT_I960_MSG0I; | 
|  | 5068 | writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5069 |  | 
|  | 5070 | if (Post < (IPS_GOOD_POST_STATUS << 8)) { | 
|  | 5071 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5072 | "reset controller fails (post status %x).\n", Post); | 
|  | 5073 |  | 
|  | 5074 | return (0); | 
|  | 5075 | } | 
|  | 5076 |  | 
|  | 5077 | /* Wait up to 240 secs for config bytes */ | 
|  | 5078 | for (i = 0; i < 240; i++) { | 
|  | 5079 | Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5080 |  | 
|  | 5081 | if (Isr & IPS_BIT_I960_MSG1I) | 
|  | 5082 | break; | 
|  | 5083 |  | 
|  | 5084 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5085 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5086 | } | 
|  | 5087 |  | 
|  | 5088 | if (i >= 240) { | 
|  | 5089 | /* error occurred */ | 
|  | 5090 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5091 | "timeout waiting for config.\n"); | 
|  | 5092 |  | 
|  | 5093 | return (0); | 
|  | 5094 | } | 
|  | 5095 |  | 
|  | 5096 | Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1); | 
|  | 5097 |  | 
|  | 5098 | /* Clear interrupt bit */ | 
|  | 5099 | Isr = (uint32_t) IPS_BIT_I960_MSG1I; | 
|  | 5100 | writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5101 |  | 
|  | 5102 | /* Turn on the interrupts */ | 
|  | 5103 | Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 5104 | Oimr &= ~0x8; | 
|  | 5105 | writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 5106 |  | 
|  | 5107 | /* if we get here then everything went OK */ | 
|  | 5108 |  | 
|  | 5109 | /* Since we did a RESET, an EraseStripeLock may be needed */ | 
|  | 5110 | if (Post == 0xEF10) { | 
|  | 5111 | if ((Config == 0x000F) || (Config == 0x0009)) | 
|  | 5112 | ha->requires_esl = 1; | 
|  | 5113 | } | 
|  | 5114 |  | 
|  | 5115 | return (1); | 
|  | 5116 | } | 
|  | 5117 |  | 
|  | 5118 | /****************************************************************************/ | 
|  | 5119 | /*                                                                          */ | 
|  | 5120 | /* Routine Name: ips_reset_copperhead                                       */ | 
|  | 5121 | /*                                                                          */ | 
|  | 5122 | /* Routine Description:                                                     */ | 
|  | 5123 | /*                                                                          */ | 
|  | 5124 | /*   Reset the controller                                                   */ | 
|  | 5125 | /*                                                                          */ | 
|  | 5126 | /****************************************************************************/ | 
|  | 5127 | static int | 
|  | 5128 | ips_reset_copperhead(ips_ha_t * ha) | 
|  | 5129 | { | 
|  | 5130 | int reset_counter; | 
|  | 5131 |  | 
|  | 5132 | METHOD_TRACE("ips_reset_copperhead", 1); | 
|  | 5133 |  | 
|  | 5134 | DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 5135 | ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5136 |  | 
|  | 5137 | reset_counter = 0; | 
|  | 5138 |  | 
|  | 5139 | while (reset_counter < 2) { | 
|  | 5140 | reset_counter++; | 
|  | 5141 |  | 
|  | 5142 | outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR); | 
|  | 5143 |  | 
|  | 5144 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5145 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5146 |  | 
|  | 5147 | outb(0, ha->io_addr + IPS_REG_SCPR); | 
|  | 5148 |  | 
|  | 5149 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5150 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5151 |  | 
|  | 5152 | if ((*ha->func.init) (ha)) | 
|  | 5153 | break; | 
|  | 5154 | else if (reset_counter >= 2) { | 
|  | 5155 |  | 
|  | 5156 | return (0); | 
|  | 5157 | } | 
|  | 5158 | } | 
|  | 5159 |  | 
|  | 5160 | return (1); | 
|  | 5161 | } | 
|  | 5162 |  | 
|  | 5163 | /****************************************************************************/ | 
|  | 5164 | /*                                                                          */ | 
|  | 5165 | /* Routine Name: ips_reset_copperhead_memio                                 */ | 
|  | 5166 | /*                                                                          */ | 
|  | 5167 | /* Routine Description:                                                     */ | 
|  | 5168 | /*                                                                          */ | 
|  | 5169 | /*   Reset the controller                                                   */ | 
|  | 5170 | /*                                                                          */ | 
|  | 5171 | /****************************************************************************/ | 
|  | 5172 | static int | 
|  | 5173 | ips_reset_copperhead_memio(ips_ha_t * ha) | 
|  | 5174 | { | 
|  | 5175 | int reset_counter; | 
|  | 5176 |  | 
|  | 5177 | METHOD_TRACE("ips_reset_copperhead_memio", 1); | 
|  | 5178 |  | 
|  | 5179 | DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 5180 | ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5181 |  | 
|  | 5182 | reset_counter = 0; | 
|  | 5183 |  | 
|  | 5184 | while (reset_counter < 2) { | 
|  | 5185 | reset_counter++; | 
|  | 5186 |  | 
|  | 5187 | writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); | 
|  | 5188 |  | 
|  | 5189 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5190 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5191 |  | 
|  | 5192 | writeb(0, ha->mem_ptr + IPS_REG_SCPR); | 
|  | 5193 |  | 
|  | 5194 | /* Delay for 1 Second */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5195 | MDELAY(IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5196 |  | 
|  | 5197 | if ((*ha->func.init) (ha)) | 
|  | 5198 | break; | 
|  | 5199 | else if (reset_counter >= 2) { | 
|  | 5200 |  | 
|  | 5201 | return (0); | 
|  | 5202 | } | 
|  | 5203 | } | 
|  | 5204 |  | 
|  | 5205 | return (1); | 
|  | 5206 | } | 
|  | 5207 |  | 
|  | 5208 | /****************************************************************************/ | 
|  | 5209 | /*                                                                          */ | 
|  | 5210 | /* Routine Name: ips_reset_morpheus                                         */ | 
|  | 5211 | /*                                                                          */ | 
|  | 5212 | /* Routine Description:                                                     */ | 
|  | 5213 | /*                                                                          */ | 
|  | 5214 | /*   Reset the controller                                                   */ | 
|  | 5215 | /*                                                                          */ | 
|  | 5216 | /****************************************************************************/ | 
|  | 5217 | static int | 
|  | 5218 | ips_reset_morpheus(ips_ha_t * ha) | 
|  | 5219 | { | 
|  | 5220 | int reset_counter; | 
|  | 5221 | uint8_t junk; | 
|  | 5222 |  | 
|  | 5223 | METHOD_TRACE("ips_reset_morpheus", 1); | 
|  | 5224 |  | 
|  | 5225 | DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 5226 | ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5227 |  | 
|  | 5228 | reset_counter = 0; | 
|  | 5229 |  | 
|  | 5230 | while (reset_counter < 2) { | 
|  | 5231 | reset_counter++; | 
|  | 5232 |  | 
|  | 5233 | writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); | 
|  | 5234 |  | 
|  | 5235 | /* Delay for 5 Seconds */ | 
| Andrew Morton | bf47134 | 2006-11-08 19:56:24 -0800 | [diff] [blame] | 5236 | MDELAY(5 * IPS_ONE_SEC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5237 |  | 
|  | 5238 | /* Do a PCI config read to wait for adapter */ | 
|  | 5239 | pci_read_config_byte(ha->pcidev, 4, &junk); | 
|  | 5240 |  | 
|  | 5241 | if ((*ha->func.init) (ha)) | 
|  | 5242 | break; | 
|  | 5243 | else if (reset_counter >= 2) { | 
|  | 5244 |  | 
|  | 5245 | return (0); | 
|  | 5246 | } | 
|  | 5247 | } | 
|  | 5248 |  | 
|  | 5249 | return (1); | 
|  | 5250 | } | 
|  | 5251 |  | 
|  | 5252 | /****************************************************************************/ | 
|  | 5253 | /*                                                                          */ | 
|  | 5254 | /* Routine Name: ips_statinit                                               */ | 
|  | 5255 | /*                                                                          */ | 
|  | 5256 | /* Routine Description:                                                     */ | 
|  | 5257 | /*                                                                          */ | 
|  | 5258 | /*   Initialize the status queues on the controller                         */ | 
|  | 5259 | /*                                                                          */ | 
|  | 5260 | /****************************************************************************/ | 
|  | 5261 | static void | 
|  | 5262 | ips_statinit(ips_ha_t * ha) | 
|  | 5263 | { | 
|  | 5264 | uint32_t phys_status_start; | 
|  | 5265 |  | 
|  | 5266 | METHOD_TRACE("ips_statinit", 1); | 
|  | 5267 |  | 
|  | 5268 | ha->adapt->p_status_start = ha->adapt->status; | 
|  | 5269 | ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; | 
|  | 5270 | ha->adapt->p_status_tail = ha->adapt->status; | 
|  | 5271 |  | 
|  | 5272 | phys_status_start = ha->adapt->hw_status_start; | 
|  | 5273 | outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR); | 
|  | 5274 | outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), | 
|  | 5275 | ha->io_addr + IPS_REG_SQER); | 
|  | 5276 | outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), | 
|  | 5277 | ha->io_addr + IPS_REG_SQHR); | 
|  | 5278 | outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR); | 
|  | 5279 |  | 
|  | 5280 | ha->adapt->hw_status_tail = phys_status_start; | 
|  | 5281 | } | 
|  | 5282 |  | 
|  | 5283 | /****************************************************************************/ | 
|  | 5284 | /*                                                                          */ | 
|  | 5285 | /* Routine Name: ips_statinit_memio                                         */ | 
|  | 5286 | /*                                                                          */ | 
|  | 5287 | /* Routine Description:                                                     */ | 
|  | 5288 | /*                                                                          */ | 
|  | 5289 | /*   Initialize the status queues on the controller                         */ | 
|  | 5290 | /*                                                                          */ | 
|  | 5291 | /****************************************************************************/ | 
|  | 5292 | static void | 
|  | 5293 | ips_statinit_memio(ips_ha_t * ha) | 
|  | 5294 | { | 
|  | 5295 | uint32_t phys_status_start; | 
|  | 5296 |  | 
|  | 5297 | METHOD_TRACE("ips_statinit_memio", 1); | 
|  | 5298 |  | 
|  | 5299 | ha->adapt->p_status_start = ha->adapt->status; | 
|  | 5300 | ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; | 
|  | 5301 | ha->adapt->p_status_tail = ha->adapt->status; | 
|  | 5302 |  | 
|  | 5303 | phys_status_start = ha->adapt->hw_status_start; | 
|  | 5304 | writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); | 
|  | 5305 | writel(phys_status_start + IPS_STATUS_Q_SIZE, | 
|  | 5306 | ha->mem_ptr + IPS_REG_SQER); | 
|  | 5307 | writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); | 
|  | 5308 | writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR); | 
|  | 5309 |  | 
|  | 5310 | ha->adapt->hw_status_tail = phys_status_start; | 
|  | 5311 | } | 
|  | 5312 |  | 
|  | 5313 | /****************************************************************************/ | 
|  | 5314 | /*                                                                          */ | 
|  | 5315 | /* Routine Name: ips_statupd_copperhead                                     */ | 
|  | 5316 | /*                                                                          */ | 
|  | 5317 | /* Routine Description:                                                     */ | 
|  | 5318 | /*                                                                          */ | 
|  | 5319 | /*   Remove an element from the status queue                                */ | 
|  | 5320 | /*                                                                          */ | 
|  | 5321 | /****************************************************************************/ | 
|  | 5322 | static uint32_t | 
|  | 5323 | ips_statupd_copperhead(ips_ha_t * ha) | 
|  | 5324 | { | 
|  | 5325 | METHOD_TRACE("ips_statupd_copperhead", 1); | 
|  | 5326 |  | 
|  | 5327 | if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { | 
|  | 5328 | ha->adapt->p_status_tail++; | 
|  | 5329 | ha->adapt->hw_status_tail += sizeof (IPS_STATUS); | 
|  | 5330 | } else { | 
|  | 5331 | ha->adapt->p_status_tail = ha->adapt->p_status_start; | 
|  | 5332 | ha->adapt->hw_status_tail = ha->adapt->hw_status_start; | 
|  | 5333 | } | 
|  | 5334 |  | 
|  | 5335 | outl(cpu_to_le32(ha->adapt->hw_status_tail), | 
|  | 5336 | ha->io_addr + IPS_REG_SQTR); | 
|  | 5337 |  | 
|  | 5338 | return (ha->adapt->p_status_tail->value); | 
|  | 5339 | } | 
|  | 5340 |  | 
|  | 5341 | /****************************************************************************/ | 
|  | 5342 | /*                                                                          */ | 
|  | 5343 | /* Routine Name: ips_statupd_copperhead_memio                               */ | 
|  | 5344 | /*                                                                          */ | 
|  | 5345 | /* Routine Description:                                                     */ | 
|  | 5346 | /*                                                                          */ | 
|  | 5347 | /*   Remove an element from the status queue                                */ | 
|  | 5348 | /*                                                                          */ | 
|  | 5349 | /****************************************************************************/ | 
|  | 5350 | static uint32_t | 
|  | 5351 | ips_statupd_copperhead_memio(ips_ha_t * ha) | 
|  | 5352 | { | 
|  | 5353 | METHOD_TRACE("ips_statupd_copperhead_memio", 1); | 
|  | 5354 |  | 
|  | 5355 | if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { | 
|  | 5356 | ha->adapt->p_status_tail++; | 
|  | 5357 | ha->adapt->hw_status_tail += sizeof (IPS_STATUS); | 
|  | 5358 | } else { | 
|  | 5359 | ha->adapt->p_status_tail = ha->adapt->p_status_start; | 
|  | 5360 | ha->adapt->hw_status_tail = ha->adapt->hw_status_start; | 
|  | 5361 | } | 
|  | 5362 |  | 
|  | 5363 | writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR); | 
|  | 5364 |  | 
|  | 5365 | return (ha->adapt->p_status_tail->value); | 
|  | 5366 | } | 
|  | 5367 |  | 
|  | 5368 | /****************************************************************************/ | 
|  | 5369 | /*                                                                          */ | 
|  | 5370 | /* Routine Name: ips_statupd_morpheus                                       */ | 
|  | 5371 | /*                                                                          */ | 
|  | 5372 | /* Routine Description:                                                     */ | 
|  | 5373 | /*                                                                          */ | 
|  | 5374 | /*   Remove an element from the status queue                                */ | 
|  | 5375 | /*                                                                          */ | 
|  | 5376 | /****************************************************************************/ | 
|  | 5377 | static uint32_t | 
|  | 5378 | ips_statupd_morpheus(ips_ha_t * ha) | 
|  | 5379 | { | 
|  | 5380 | uint32_t val; | 
|  | 5381 |  | 
|  | 5382 | METHOD_TRACE("ips_statupd_morpheus", 1); | 
|  | 5383 |  | 
|  | 5384 | val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ); | 
|  | 5385 |  | 
|  | 5386 | return (val); | 
|  | 5387 | } | 
|  | 5388 |  | 
|  | 5389 | /****************************************************************************/ | 
|  | 5390 | /*                                                                          */ | 
|  | 5391 | /* Routine Name: ips_issue_copperhead                                       */ | 
|  | 5392 | /*                                                                          */ | 
|  | 5393 | /* Routine Description:                                                     */ | 
|  | 5394 | /*                                                                          */ | 
|  | 5395 | /*   Send a command down to the controller                                  */ | 
|  | 5396 | /*                                                                          */ | 
|  | 5397 | /****************************************************************************/ | 
|  | 5398 | static int | 
|  | 5399 | ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5400 | { | 
|  | 5401 | uint32_t TimeOut; | 
|  | 5402 | uint32_t val; | 
|  | 5403 |  | 
|  | 5404 | METHOD_TRACE("ips_issue_copperhead", 1); | 
|  | 5405 |  | 
|  | 5406 | if (scb->scsi_cmd) { | 
|  | 5407 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5408 | ips_name, | 
|  | 5409 | ha->host_num, | 
|  | 5410 | scb->cdb[0], | 
|  | 5411 | scb->cmd.basic_io.command_id, | 
|  | 5412 | scb->bus, scb->target_id, scb->lun); | 
|  | 5413 | } else { | 
|  | 5414 | DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5415 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5416 | } | 
|  | 5417 |  | 
|  | 5418 | TimeOut = 0; | 
|  | 5419 |  | 
|  | 5420 | while ((val = | 
|  | 5421 | le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) { | 
|  | 5422 | udelay(1000); | 
|  | 5423 |  | 
|  | 5424 | if (++TimeOut >= IPS_SEM_TIMEOUT) { | 
|  | 5425 | if (!(val & IPS_BIT_START_STOP)) | 
|  | 5426 | break; | 
|  | 5427 |  | 
|  | 5428 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5429 | "ips_issue val [0x%x].\n", val); | 
|  | 5430 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5431 | "ips_issue semaphore chk timeout.\n"); | 
|  | 5432 |  | 
|  | 5433 | return (IPS_FAILURE); | 
|  | 5434 | }		/* end if */ | 
|  | 5435 | }			/* end while */ | 
|  | 5436 |  | 
|  | 5437 | outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR); | 
|  | 5438 | outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR); | 
|  | 5439 |  | 
|  | 5440 | return (IPS_SUCCESS); | 
|  | 5441 | } | 
|  | 5442 |  | 
|  | 5443 | /****************************************************************************/ | 
|  | 5444 | /*                                                                          */ | 
|  | 5445 | /* Routine Name: ips_issue_copperhead_memio                                 */ | 
|  | 5446 | /*                                                                          */ | 
|  | 5447 | /* Routine Description:                                                     */ | 
|  | 5448 | /*                                                                          */ | 
|  | 5449 | /*   Send a command down to the controller                                  */ | 
|  | 5450 | /*                                                                          */ | 
|  | 5451 | /****************************************************************************/ | 
|  | 5452 | static int | 
|  | 5453 | ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5454 | { | 
|  | 5455 | uint32_t TimeOut; | 
|  | 5456 | uint32_t val; | 
|  | 5457 |  | 
|  | 5458 | METHOD_TRACE("ips_issue_copperhead_memio", 1); | 
|  | 5459 |  | 
|  | 5460 | if (scb->scsi_cmd) { | 
|  | 5461 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5462 | ips_name, | 
|  | 5463 | ha->host_num, | 
|  | 5464 | scb->cdb[0], | 
|  | 5465 | scb->cmd.basic_io.command_id, | 
|  | 5466 | scb->bus, scb->target_id, scb->lun); | 
|  | 5467 | } else { | 
|  | 5468 | DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5469 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5470 | } | 
|  | 5471 |  | 
|  | 5472 | TimeOut = 0; | 
|  | 5473 |  | 
|  | 5474 | while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { | 
|  | 5475 | udelay(1000); | 
|  | 5476 |  | 
|  | 5477 | if (++TimeOut >= IPS_SEM_TIMEOUT) { | 
|  | 5478 | if (!(val & IPS_BIT_START_STOP)) | 
|  | 5479 | break; | 
|  | 5480 |  | 
|  | 5481 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5482 | "ips_issue val [0x%x].\n", val); | 
|  | 5483 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5484 | "ips_issue semaphore chk timeout.\n"); | 
|  | 5485 |  | 
|  | 5486 | return (IPS_FAILURE); | 
|  | 5487 | }		/* end if */ | 
|  | 5488 | }			/* end while */ | 
|  | 5489 |  | 
|  | 5490 | writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); | 
|  | 5491 | writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR); | 
|  | 5492 |  | 
|  | 5493 | return (IPS_SUCCESS); | 
|  | 5494 | } | 
|  | 5495 |  | 
|  | 5496 | /****************************************************************************/ | 
|  | 5497 | /*                                                                          */ | 
|  | 5498 | /* Routine Name: ips_issue_i2o                                              */ | 
|  | 5499 | /*                                                                          */ | 
|  | 5500 | /* Routine Description:                                                     */ | 
|  | 5501 | /*                                                                          */ | 
|  | 5502 | /*   Send a command down to the controller                                  */ | 
|  | 5503 | /*                                                                          */ | 
|  | 5504 | /****************************************************************************/ | 
|  | 5505 | static int | 
|  | 5506 | ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5507 | { | 
|  | 5508 |  | 
|  | 5509 | METHOD_TRACE("ips_issue_i2o", 1); | 
|  | 5510 |  | 
|  | 5511 | if (scb->scsi_cmd) { | 
|  | 5512 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5513 | ips_name, | 
|  | 5514 | ha->host_num, | 
|  | 5515 | scb->cdb[0], | 
|  | 5516 | scb->cmd.basic_io.command_id, | 
|  | 5517 | scb->bus, scb->target_id, scb->lun); | 
|  | 5518 | } else { | 
|  | 5519 | DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5520 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5521 | } | 
|  | 5522 |  | 
|  | 5523 | outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ); | 
|  | 5524 |  | 
|  | 5525 | return (IPS_SUCCESS); | 
|  | 5526 | } | 
|  | 5527 |  | 
|  | 5528 | /****************************************************************************/ | 
|  | 5529 | /*                                                                          */ | 
|  | 5530 | /* Routine Name: ips_issue_i2o_memio                                        */ | 
|  | 5531 | /*                                                                          */ | 
|  | 5532 | /* Routine Description:                                                     */ | 
|  | 5533 | /*                                                                          */ | 
|  | 5534 | /*   Send a command down to the controller                                  */ | 
|  | 5535 | /*                                                                          */ | 
|  | 5536 | /****************************************************************************/ | 
|  | 5537 | static int | 
|  | 5538 | ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5539 | { | 
|  | 5540 |  | 
|  | 5541 | METHOD_TRACE("ips_issue_i2o_memio", 1); | 
|  | 5542 |  | 
|  | 5543 | if (scb->scsi_cmd) { | 
|  | 5544 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5545 | ips_name, | 
|  | 5546 | ha->host_num, | 
|  | 5547 | scb->cdb[0], | 
|  | 5548 | scb->cmd.basic_io.command_id, | 
|  | 5549 | scb->bus, scb->target_id, scb->lun); | 
|  | 5550 | } else { | 
|  | 5551 | DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5552 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5553 | } | 
|  | 5554 |  | 
|  | 5555 | writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ); | 
|  | 5556 |  | 
|  | 5557 | return (IPS_SUCCESS); | 
|  | 5558 | } | 
|  | 5559 |  | 
|  | 5560 | /****************************************************************************/ | 
|  | 5561 | /*                                                                          */ | 
|  | 5562 | /* Routine Name: ips_isintr_copperhead                                      */ | 
|  | 5563 | /*                                                                          */ | 
|  | 5564 | /* Routine Description:                                                     */ | 
|  | 5565 | /*                                                                          */ | 
|  | 5566 | /*   Test to see if an interrupt is for us                                  */ | 
|  | 5567 | /*                                                                          */ | 
|  | 5568 | /****************************************************************************/ | 
|  | 5569 | static int | 
|  | 5570 | ips_isintr_copperhead(ips_ha_t * ha) | 
|  | 5571 | { | 
|  | 5572 | uint8_t Isr; | 
|  | 5573 |  | 
|  | 5574 | METHOD_TRACE("ips_isintr_copperhead", 2); | 
|  | 5575 |  | 
|  | 5576 | Isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 5577 |  | 
|  | 5578 | if (Isr == 0xFF) | 
|  | 5579 | /* ?!?! Nothing really there */ | 
|  | 5580 | return (0); | 
|  | 5581 |  | 
|  | 5582 | if (Isr & IPS_BIT_SCE) | 
|  | 5583 | return (1); | 
|  | 5584 | else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { | 
|  | 5585 | /* status queue overflow or GHI */ | 
|  | 5586 | /* just clear the interrupt */ | 
|  | 5587 | outb(Isr, ha->io_addr + IPS_REG_HISR); | 
|  | 5588 | } | 
|  | 5589 |  | 
|  | 5590 | return (0); | 
|  | 5591 | } | 
|  | 5592 |  | 
|  | 5593 | /****************************************************************************/ | 
|  | 5594 | /*                                                                          */ | 
|  | 5595 | /* Routine Name: ips_isintr_copperhead_memio                                */ | 
|  | 5596 | /*                                                                          */ | 
|  | 5597 | /* Routine Description:                                                     */ | 
|  | 5598 | /*                                                                          */ | 
|  | 5599 | /*   Test to see if an interrupt is for us                                  */ | 
|  | 5600 | /*                                                                          */ | 
|  | 5601 | /****************************************************************************/ | 
|  | 5602 | static int | 
|  | 5603 | ips_isintr_copperhead_memio(ips_ha_t * ha) | 
|  | 5604 | { | 
|  | 5605 | uint8_t Isr; | 
|  | 5606 |  | 
|  | 5607 | METHOD_TRACE("ips_isintr_memio", 2); | 
|  | 5608 |  | 
|  | 5609 | Isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 5610 |  | 
|  | 5611 | if (Isr == 0xFF) | 
|  | 5612 | /* ?!?! Nothing really there */ | 
|  | 5613 | return (0); | 
|  | 5614 |  | 
|  | 5615 | if (Isr & IPS_BIT_SCE) | 
|  | 5616 | return (1); | 
|  | 5617 | else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { | 
|  | 5618 | /* status queue overflow or GHI */ | 
|  | 5619 | /* just clear the interrupt */ | 
|  | 5620 | writeb(Isr, ha->mem_ptr + IPS_REG_HISR); | 
|  | 5621 | } | 
|  | 5622 |  | 
|  | 5623 | return (0); | 
|  | 5624 | } | 
|  | 5625 |  | 
|  | 5626 | /****************************************************************************/ | 
|  | 5627 | /*                                                                          */ | 
|  | 5628 | /* Routine Name: ips_isintr_morpheus                                        */ | 
|  | 5629 | /*                                                                          */ | 
|  | 5630 | /* Routine Description:                                                     */ | 
|  | 5631 | /*                                                                          */ | 
|  | 5632 | /*   Test to see if an interrupt is for us                                  */ | 
|  | 5633 | /*                                                                          */ | 
|  | 5634 | /****************************************************************************/ | 
|  | 5635 | static int | 
|  | 5636 | ips_isintr_morpheus(ips_ha_t * ha) | 
|  | 5637 | { | 
|  | 5638 | uint32_t Isr; | 
|  | 5639 |  | 
|  | 5640 | METHOD_TRACE("ips_isintr_morpheus", 2); | 
|  | 5641 |  | 
|  | 5642 | Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5643 |  | 
|  | 5644 | if (Isr & IPS_BIT_I2O_OPQI) | 
|  | 5645 | return (1); | 
|  | 5646 | else | 
|  | 5647 | return (0); | 
|  | 5648 | } | 
|  | 5649 |  | 
|  | 5650 | /****************************************************************************/ | 
|  | 5651 | /*                                                                          */ | 
|  | 5652 | /* Routine Name: ips_wait                                                   */ | 
|  | 5653 | /*                                                                          */ | 
|  | 5654 | /* Routine Description:                                                     */ | 
|  | 5655 | /*                                                                          */ | 
|  | 5656 | /*   Wait for a command to complete                                         */ | 
|  | 5657 | /*                                                                          */ | 
|  | 5658 | /****************************************************************************/ | 
|  | 5659 | static int | 
|  | 5660 | ips_wait(ips_ha_t * ha, int time, int intr) | 
|  | 5661 | { | 
|  | 5662 | int ret; | 
|  | 5663 | int done; | 
|  | 5664 |  | 
|  | 5665 | METHOD_TRACE("ips_wait", 1); | 
|  | 5666 |  | 
|  | 5667 | ret = IPS_FAILURE; | 
|  | 5668 | done = FALSE; | 
|  | 5669 |  | 
|  | 5670 | time *= IPS_ONE_SEC;	/* convert seconds */ | 
|  | 5671 |  | 
|  | 5672 | while ((time > 0) && (!done)) { | 
|  | 5673 | if (intr == IPS_INTR_ON) { | 
|  | 5674 | if (ha->waitflag == FALSE) { | 
|  | 5675 | ret = IPS_SUCCESS; | 
|  | 5676 | done = TRUE; | 
|  | 5677 | break; | 
|  | 5678 | } | 
|  | 5679 | } else if (intr == IPS_INTR_IORL) { | 
|  | 5680 | if (ha->waitflag == FALSE) { | 
|  | 5681 | /* | 
|  | 5682 | * controller generated an interrupt to | 
|  | 5683 | * acknowledge completion of the command | 
|  | 5684 | * and ips_intr() has serviced the interrupt. | 
|  | 5685 | */ | 
|  | 5686 | ret = IPS_SUCCESS; | 
|  | 5687 | done = TRUE; | 
|  | 5688 | break; | 
|  | 5689 | } | 
|  | 5690 |  | 
|  | 5691 | /* | 
|  | 5692 | * NOTE: we already have the io_request_lock so | 
|  | 5693 | * even if we get an interrupt it won't get serviced | 
|  | 5694 | * until after we finish. | 
|  | 5695 | */ | 
|  | 5696 |  | 
|  | 5697 | (*ha->func.intr) (ha); | 
|  | 5698 | } | 
|  | 5699 |  | 
|  | 5700 | /* This looks like a very evil loop, but it only does this during start-up */ | 
|  | 5701 | udelay(1000); | 
|  | 5702 | time--; | 
|  | 5703 | } | 
|  | 5704 |  | 
|  | 5705 | return (ret); | 
|  | 5706 | } | 
|  | 5707 |  | 
|  | 5708 | /****************************************************************************/ | 
|  | 5709 | /*                                                                          */ | 
|  | 5710 | /* Routine Name: ips_write_driver_status                                    */ | 
|  | 5711 | /*                                                                          */ | 
|  | 5712 | /* Routine Description:                                                     */ | 
|  | 5713 | /*                                                                          */ | 
|  | 5714 | /*   Write OS/Driver version to Page 5 of the nvram on the controller       */ | 
|  | 5715 | /*                                                                          */ | 
|  | 5716 | /****************************************************************************/ | 
|  | 5717 | static int | 
|  | 5718 | ips_write_driver_status(ips_ha_t * ha, int intr) | 
|  | 5719 | { | 
|  | 5720 | METHOD_TRACE("ips_write_driver_status", 1); | 
|  | 5721 |  | 
|  | 5722 | if (!ips_readwrite_page5(ha, FALSE, intr)) { | 
|  | 5723 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5724 | "unable to read NVRAM page 5.\n"); | 
|  | 5725 |  | 
|  | 5726 | return (0); | 
|  | 5727 | } | 
|  | 5728 |  | 
|  | 5729 | /* check to make sure the page has a valid */ | 
|  | 5730 | /* signature */ | 
|  | 5731 | if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) { | 
|  | 5732 | DEBUG_VAR(1, | 
|  | 5733 | "(%s%d) NVRAM page 5 has an invalid signature: %X.", | 
|  | 5734 | ips_name, ha->host_num, ha->nvram->signature); | 
|  | 5735 | ha->nvram->signature = IPS_NVRAM_P5_SIG; | 
|  | 5736 | } | 
|  | 5737 |  | 
|  | 5738 | DEBUG_VAR(2, | 
|  | 5739 | "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", | 
|  | 5740 | ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type), | 
|  | 5741 | ha->nvram->adapter_slot, ha->nvram->bios_high[0], | 
|  | 5742 | ha->nvram->bios_high[1], ha->nvram->bios_high[2], | 
|  | 5743 | ha->nvram->bios_high[3], ha->nvram->bios_low[0], | 
|  | 5744 | ha->nvram->bios_low[1], ha->nvram->bios_low[2], | 
|  | 5745 | ha->nvram->bios_low[3]); | 
|  | 5746 |  | 
|  | 5747 | ips_get_bios_version(ha, intr); | 
|  | 5748 |  | 
|  | 5749 | /* change values (as needed) */ | 
|  | 5750 | ha->nvram->operating_system = IPS_OS_LINUX; | 
|  | 5751 | ha->nvram->adapter_type = ha->ad_type; | 
|  | 5752 | strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); | 
|  | 5753 | strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); | 
|  | 5754 | strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4); | 
|  | 5755 | strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4); | 
|  | 5756 |  | 
| Jack Hammer | a60768e | 2005-11-03 09:46:00 -0500 | [diff] [blame] | 5757 | ha->nvram->versioning = 0;	/* Indicate the Driver Does Not Support Versioning */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5758 |  | 
|  | 5759 | /* now update the page */ | 
|  | 5760 | if (!ips_readwrite_page5(ha, TRUE, intr)) { | 
|  | 5761 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5762 | "unable to write NVRAM page 5.\n"); | 
|  | 5763 |  | 
|  | 5764 | return (0); | 
|  | 5765 | } | 
|  | 5766 |  | 
|  | 5767 | /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ | 
|  | 5768 | ha->slot_num = ha->nvram->adapter_slot; | 
|  | 5769 |  | 
|  | 5770 | return (1); | 
|  | 5771 | } | 
|  | 5772 |  | 
|  | 5773 | /****************************************************************************/ | 
|  | 5774 | /*                                                                          */ | 
|  | 5775 | /* Routine Name: ips_read_adapter_status                                    */ | 
|  | 5776 | /*                                                                          */ | 
|  | 5777 | /* Routine Description:                                                     */ | 
|  | 5778 | /*                                                                          */ | 
|  | 5779 | /*   Do an Inquiry command to the adapter                                   */ | 
|  | 5780 | /*                                                                          */ | 
|  | 5781 | /****************************************************************************/ | 
|  | 5782 | static int | 
|  | 5783 | ips_read_adapter_status(ips_ha_t * ha, int intr) | 
|  | 5784 | { | 
|  | 5785 | ips_scb_t *scb; | 
|  | 5786 | int ret; | 
|  | 5787 |  | 
|  | 5788 | METHOD_TRACE("ips_read_adapter_status", 1); | 
|  | 5789 |  | 
|  | 5790 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5791 |  | 
|  | 5792 | ips_init_scb(ha, scb); | 
|  | 5793 |  | 
|  | 5794 | scb->timeout = ips_cmd_timeout; | 
|  | 5795 | scb->cdb[0] = IPS_CMD_ENQUIRY; | 
|  | 5796 |  | 
|  | 5797 | scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; | 
|  | 5798 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5799 | scb->cmd.basic_io.sg_count = 0; | 
|  | 5800 | scb->cmd.basic_io.lba = 0; | 
|  | 5801 | scb->cmd.basic_io.sector_count = 0; | 
|  | 5802 | scb->cmd.basic_io.log_drv = 0; | 
|  | 5803 | scb->data_len = sizeof (*ha->enq); | 
|  | 5804 | scb->cmd.basic_io.sg_addr = ha->enq_busaddr; | 
|  | 5805 |  | 
|  | 5806 | /* send command */ | 
|  | 5807 | if (((ret = | 
|  | 5808 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5809 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5810 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 5811 | return (0); | 
|  | 5812 |  | 
|  | 5813 | return (1); | 
|  | 5814 | } | 
|  | 5815 |  | 
|  | 5816 | /****************************************************************************/ | 
|  | 5817 | /*                                                                          */ | 
|  | 5818 | /* Routine Name: ips_read_subsystem_parameters                              */ | 
|  | 5819 | /*                                                                          */ | 
|  | 5820 | /* Routine Description:                                                     */ | 
|  | 5821 | /*                                                                          */ | 
|  | 5822 | /*   Read subsystem parameters from the adapter                             */ | 
|  | 5823 | /*                                                                          */ | 
|  | 5824 | /****************************************************************************/ | 
|  | 5825 | static int | 
|  | 5826 | ips_read_subsystem_parameters(ips_ha_t * ha, int intr) | 
|  | 5827 | { | 
|  | 5828 | ips_scb_t *scb; | 
|  | 5829 | int ret; | 
|  | 5830 |  | 
|  | 5831 | METHOD_TRACE("ips_read_subsystem_parameters", 1); | 
|  | 5832 |  | 
|  | 5833 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5834 |  | 
|  | 5835 | ips_init_scb(ha, scb); | 
|  | 5836 |  | 
|  | 5837 | scb->timeout = ips_cmd_timeout; | 
|  | 5838 | scb->cdb[0] = IPS_CMD_GET_SUBSYS; | 
|  | 5839 |  | 
|  | 5840 | scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS; | 
|  | 5841 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5842 | scb->cmd.basic_io.sg_count = 0; | 
|  | 5843 | scb->cmd.basic_io.lba = 0; | 
|  | 5844 | scb->cmd.basic_io.sector_count = 0; | 
|  | 5845 | scb->cmd.basic_io.log_drv = 0; | 
|  | 5846 | scb->data_len = sizeof (*ha->subsys); | 
|  | 5847 | scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; | 
|  | 5848 |  | 
|  | 5849 | /* send command */ | 
|  | 5850 | if (((ret = | 
|  | 5851 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5852 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5853 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 5854 | return (0); | 
|  | 5855 |  | 
|  | 5856 | memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys)); | 
|  | 5857 | return (1); | 
|  | 5858 | } | 
|  | 5859 |  | 
|  | 5860 | /****************************************************************************/ | 
|  | 5861 | /*                                                                          */ | 
|  | 5862 | /* Routine Name: ips_read_config                                            */ | 
|  | 5863 | /*                                                                          */ | 
|  | 5864 | /* Routine Description:                                                     */ | 
|  | 5865 | /*                                                                          */ | 
|  | 5866 | /*   Read the configuration on the adapter                                  */ | 
|  | 5867 | /*                                                                          */ | 
|  | 5868 | /****************************************************************************/ | 
|  | 5869 | static int | 
|  | 5870 | ips_read_config(ips_ha_t * ha, int intr) | 
|  | 5871 | { | 
|  | 5872 | ips_scb_t *scb; | 
|  | 5873 | int i; | 
|  | 5874 | int ret; | 
|  | 5875 |  | 
|  | 5876 | METHOD_TRACE("ips_read_config", 1); | 
|  | 5877 |  | 
|  | 5878 | /* set defaults for initiator IDs */ | 
|  | 5879 | for (i = 0; i < 4; i++) | 
|  | 5880 | ha->conf->init_id[i] = 7; | 
|  | 5881 |  | 
|  | 5882 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5883 |  | 
|  | 5884 | ips_init_scb(ha, scb); | 
|  | 5885 |  | 
|  | 5886 | scb->timeout = ips_cmd_timeout; | 
|  | 5887 | scb->cdb[0] = IPS_CMD_READ_CONF; | 
|  | 5888 |  | 
|  | 5889 | scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF; | 
|  | 5890 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5891 | scb->data_len = sizeof (*ha->conf); | 
|  | 5892 | scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; | 
|  | 5893 |  | 
|  | 5894 | /* send command */ | 
|  | 5895 | if (((ret = | 
|  | 5896 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5897 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5898 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { | 
|  | 5899 |  | 
|  | 5900 | memset(ha->conf, 0, sizeof (IPS_CONF)); | 
|  | 5901 |  | 
|  | 5902 | /* reset initiator IDs */ | 
|  | 5903 | for (i = 0; i < 4; i++) | 
|  | 5904 | ha->conf->init_id[i] = 7; | 
|  | 5905 |  | 
|  | 5906 | /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */ | 
|  | 5907 | if ((scb->basic_status & IPS_GSC_STATUS_MASK) == | 
|  | 5908 | IPS_CMD_CMPLT_WERROR) | 
|  | 5909 | return (1); | 
|  | 5910 |  | 
|  | 5911 | return (0); | 
|  | 5912 | } | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 5913 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5914 | memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); | 
|  | 5915 | return (1); | 
|  | 5916 | } | 
|  | 5917 |  | 
|  | 5918 | /****************************************************************************/ | 
|  | 5919 | /*                                                                          */ | 
|  | 5920 | /* Routine Name: ips_readwrite_page5                                        */ | 
|  | 5921 | /*                                                                          */ | 
|  | 5922 | /* Routine Description:                                                     */ | 
|  | 5923 | /*                                                                          */ | 
|  | 5924 | /*   Read nvram page 5 from the adapter                                     */ | 
|  | 5925 | /*                                                                          */ | 
|  | 5926 | /****************************************************************************/ | 
|  | 5927 | static int | 
|  | 5928 | ips_readwrite_page5(ips_ha_t * ha, int write, int intr) | 
|  | 5929 | { | 
|  | 5930 | ips_scb_t *scb; | 
|  | 5931 | int ret; | 
|  | 5932 |  | 
|  | 5933 | METHOD_TRACE("ips_readwrite_page5", 1); | 
|  | 5934 |  | 
|  | 5935 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5936 |  | 
|  | 5937 | ips_init_scb(ha, scb); | 
|  | 5938 |  | 
|  | 5939 | scb->timeout = ips_cmd_timeout; | 
|  | 5940 | scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE; | 
|  | 5941 |  | 
|  | 5942 | scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE; | 
|  | 5943 | scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5944 | scb->cmd.nvram.page = 5; | 
|  | 5945 | scb->cmd.nvram.write = write; | 
|  | 5946 | scb->cmd.nvram.reserved = 0; | 
|  | 5947 | scb->cmd.nvram.reserved2 = 0; | 
|  | 5948 | scb->data_len = sizeof (*ha->nvram); | 
|  | 5949 | scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; | 
|  | 5950 | if (write) | 
|  | 5951 | memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram)); | 
| Jeff Garzik | 2f277d6 | 2007-12-13 16:14:08 -0800 | [diff] [blame] | 5952 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5953 | /* issue the command */ | 
|  | 5954 | if (((ret = | 
|  | 5955 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5956 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5957 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { | 
|  | 5958 |  | 
|  | 5959 | memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5)); | 
|  | 5960 |  | 
|  | 5961 | return (0); | 
|  | 5962 | } | 
|  | 5963 | if (!write) | 
|  | 5964 | memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram)); | 
|  | 5965 | return (1); | 
|  | 5966 | } | 
|  | 5967 |  | 
|  | 5968 | /****************************************************************************/ | 
|  | 5969 | /*                                                                          */ | 
|  | 5970 | /* Routine Name: ips_clear_adapter                                          */ | 
|  | 5971 | /*                                                                          */ | 
|  | 5972 | /* Routine Description:                                                     */ | 
|  | 5973 | /*                                                                          */ | 
|  | 5974 | /*   Clear the stripe lock tables                                           */ | 
|  | 5975 | /*                                                                          */ | 
|  | 5976 | /****************************************************************************/ | 
|  | 5977 | static int | 
|  | 5978 | ips_clear_adapter(ips_ha_t * ha, int intr) | 
|  | 5979 | { | 
|  | 5980 | ips_scb_t *scb; | 
|  | 5981 | int ret; | 
|  | 5982 |  | 
|  | 5983 | METHOD_TRACE("ips_clear_adapter", 1); | 
|  | 5984 |  | 
|  | 5985 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5986 |  | 
|  | 5987 | ips_init_scb(ha, scb); | 
|  | 5988 |  | 
|  | 5989 | scb->timeout = ips_reset_timeout; | 
|  | 5990 | scb->cdb[0] = IPS_CMD_CONFIG_SYNC; | 
|  | 5991 |  | 
|  | 5992 | scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC; | 
|  | 5993 | scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5994 | scb->cmd.config_sync.channel = 0; | 
|  | 5995 | scb->cmd.config_sync.source_target = IPS_POCL; | 
|  | 5996 | scb->cmd.config_sync.reserved = 0; | 
|  | 5997 | scb->cmd.config_sync.reserved2 = 0; | 
|  | 5998 | scb->cmd.config_sync.reserved3 = 0; | 
|  | 5999 |  | 
|  | 6000 | /* issue command */ | 
|  | 6001 | if (((ret = | 
|  | 6002 | ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) | 
|  | 6003 | || (ret == IPS_SUCCESS_IMM) | 
|  | 6004 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 6005 | return (0); | 
|  | 6006 |  | 
|  | 6007 | /* send unlock stripe command */ | 
|  | 6008 | ips_init_scb(ha, scb); | 
|  | 6009 |  | 
|  | 6010 | scb->cdb[0] = IPS_CMD_ERROR_TABLE; | 
|  | 6011 | scb->timeout = ips_reset_timeout; | 
|  | 6012 |  | 
|  | 6013 | scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE; | 
|  | 6014 | scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6015 | scb->cmd.unlock_stripe.log_drv = 0; | 
|  | 6016 | scb->cmd.unlock_stripe.control = IPS_CSL; | 
|  | 6017 | scb->cmd.unlock_stripe.reserved = 0; | 
|  | 6018 | scb->cmd.unlock_stripe.reserved2 = 0; | 
|  | 6019 | scb->cmd.unlock_stripe.reserved3 = 0; | 
|  | 6020 |  | 
|  | 6021 | /* issue command */ | 
|  | 6022 | if (((ret = | 
|  | 6023 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 6024 | || (ret == IPS_SUCCESS_IMM) | 
|  | 6025 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 6026 | return (0); | 
|  | 6027 |  | 
|  | 6028 | return (1); | 
|  | 6029 | } | 
|  | 6030 |  | 
|  | 6031 | /****************************************************************************/ | 
|  | 6032 | /*                                                                          */ | 
|  | 6033 | /* Routine Name: ips_ffdc_reset                                             */ | 
|  | 6034 | /*                                                                          */ | 
|  | 6035 | /* Routine Description:                                                     */ | 
|  | 6036 | /*                                                                          */ | 
|  | 6037 | /*   FFDC: write reset info                                                 */ | 
|  | 6038 | /*                                                                          */ | 
|  | 6039 | /****************************************************************************/ | 
|  | 6040 | static void | 
|  | 6041 | ips_ffdc_reset(ips_ha_t * ha, int intr) | 
|  | 6042 | { | 
|  | 6043 | ips_scb_t *scb; | 
|  | 6044 |  | 
|  | 6045 | METHOD_TRACE("ips_ffdc_reset", 1); | 
|  | 6046 |  | 
|  | 6047 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 6048 |  | 
|  | 6049 | ips_init_scb(ha, scb); | 
|  | 6050 |  | 
|  | 6051 | scb->timeout = ips_cmd_timeout; | 
|  | 6052 | scb->cdb[0] = IPS_CMD_FFDC; | 
|  | 6053 | scb->cmd.ffdc.op_code = IPS_CMD_FFDC; | 
|  | 6054 | scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6055 | scb->cmd.ffdc.reset_count = ha->reset_count; | 
|  | 6056 | scb->cmd.ffdc.reset_type = 0x80; | 
|  | 6057 |  | 
|  | 6058 | /* convert time to what the card wants */ | 
|  | 6059 | ips_fix_ffdc_time(ha, scb, ha->last_ffdc); | 
|  | 6060 |  | 
|  | 6061 | /* issue command */ | 
|  | 6062 | ips_send_wait(ha, scb, ips_cmd_timeout, intr); | 
|  | 6063 | } | 
|  | 6064 |  | 
|  | 6065 | /****************************************************************************/ | 
|  | 6066 | /*                                                                          */ | 
|  | 6067 | /* Routine Name: ips_ffdc_time                                              */ | 
|  | 6068 | /*                                                                          */ | 
|  | 6069 | /* Routine Description:                                                     */ | 
|  | 6070 | /*                                                                          */ | 
|  | 6071 | /*   FFDC: write time info                                                  */ | 
|  | 6072 | /*                                                                          */ | 
|  | 6073 | /****************************************************************************/ | 
|  | 6074 | static void | 
|  | 6075 | ips_ffdc_time(ips_ha_t * ha) | 
|  | 6076 | { | 
|  | 6077 | ips_scb_t *scb; | 
|  | 6078 |  | 
|  | 6079 | METHOD_TRACE("ips_ffdc_time", 1); | 
|  | 6080 |  | 
|  | 6081 | DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num); | 
|  | 6082 |  | 
|  | 6083 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 6084 |  | 
|  | 6085 | ips_init_scb(ha, scb); | 
|  | 6086 |  | 
|  | 6087 | scb->timeout = ips_cmd_timeout; | 
|  | 6088 | scb->cdb[0] = IPS_CMD_FFDC; | 
|  | 6089 | scb->cmd.ffdc.op_code = IPS_CMD_FFDC; | 
|  | 6090 | scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6091 | scb->cmd.ffdc.reset_count = 0; | 
|  | 6092 | scb->cmd.ffdc.reset_type = 0; | 
|  | 6093 |  | 
|  | 6094 | /* convert time to what the card wants */ | 
|  | 6095 | ips_fix_ffdc_time(ha, scb, ha->last_ffdc); | 
|  | 6096 |  | 
|  | 6097 | /* issue command */ | 
|  | 6098 | ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC); | 
|  | 6099 | } | 
|  | 6100 |  | 
|  | 6101 | /****************************************************************************/ | 
|  | 6102 | /*                                                                          */ | 
|  | 6103 | /* Routine Name: ips_fix_ffdc_time                                          */ | 
|  | 6104 | /*                                                                          */ | 
|  | 6105 | /* Routine Description:                                                     */ | 
|  | 6106 | /*   Adjust time_t to what the card wants                                   */ | 
|  | 6107 | /*                                                                          */ | 
|  | 6108 | /****************************************************************************/ | 
|  | 6109 | static void | 
|  | 6110 | ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time) | 
|  | 6111 | { | 
|  | 6112 | long days; | 
|  | 6113 | long rem; | 
|  | 6114 | int i; | 
|  | 6115 | int year; | 
|  | 6116 | int yleap; | 
|  | 6117 | int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR }; | 
|  | 6118 | int month_lengths[12][2] = { {31, 31}, | 
|  | 6119 | {28, 29}, | 
|  | 6120 | {31, 31}, | 
|  | 6121 | {30, 30}, | 
|  | 6122 | {31, 31}, | 
|  | 6123 | {30, 30}, | 
|  | 6124 | {31, 31}, | 
|  | 6125 | {31, 31}, | 
|  | 6126 | {30, 30}, | 
|  | 6127 | {31, 31}, | 
|  | 6128 | {30, 30}, | 
|  | 6129 | {31, 31} | 
|  | 6130 | }; | 
|  | 6131 |  | 
|  | 6132 | METHOD_TRACE("ips_fix_ffdc_time", 1); | 
|  | 6133 |  | 
|  | 6134 | days = current_time / IPS_SECS_DAY; | 
|  | 6135 | rem = current_time % IPS_SECS_DAY; | 
|  | 6136 |  | 
|  | 6137 | scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR); | 
|  | 6138 | rem = rem % IPS_SECS_HOUR; | 
|  | 6139 | scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN); | 
|  | 6140 | scb->cmd.ffdc.second = (rem % IPS_SECS_MIN); | 
|  | 6141 |  | 
|  | 6142 | year = IPS_EPOCH_YEAR; | 
|  | 6143 | while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) { | 
|  | 6144 | int newy; | 
|  | 6145 |  | 
|  | 6146 | newy = year + (days / IPS_DAYS_NORMAL_YEAR); | 
|  | 6147 | if (days < 0) | 
|  | 6148 | --newy; | 
|  | 6149 | days -= (newy - year) * IPS_DAYS_NORMAL_YEAR + | 
|  | 6150 | IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) - | 
|  | 6151 | IPS_NUM_LEAP_YEARS_THROUGH(year - 1); | 
|  | 6152 | year = newy; | 
|  | 6153 | } | 
|  | 6154 |  | 
|  | 6155 | scb->cmd.ffdc.yearH = year / 100; | 
|  | 6156 | scb->cmd.ffdc.yearL = year % 100; | 
|  | 6157 |  | 
|  | 6158 | for (i = 0; days >= month_lengths[i][yleap]; ++i) | 
|  | 6159 | days -= month_lengths[i][yleap]; | 
|  | 6160 |  | 
|  | 6161 | scb->cmd.ffdc.month = i + 1; | 
|  | 6162 | scb->cmd.ffdc.day = days + 1; | 
|  | 6163 | } | 
|  | 6164 |  | 
|  | 6165 | /**************************************************************************** | 
|  | 6166 | * BIOS Flash Routines                                                      * | 
|  | 6167 | ****************************************************************************/ | 
|  | 6168 |  | 
|  | 6169 | /****************************************************************************/ | 
|  | 6170 | /*                                                                          */ | 
|  | 6171 | /* Routine Name: ips_erase_bios                                             */ | 
|  | 6172 | /*                                                                          */ | 
|  | 6173 | /* Routine Description:                                                     */ | 
|  | 6174 | /*   Erase the BIOS on the adapter                                          */ | 
|  | 6175 | /*                                                                          */ | 
|  | 6176 | /****************************************************************************/ | 
|  | 6177 | static int | 
|  | 6178 | ips_erase_bios(ips_ha_t * ha) | 
|  | 6179 | { | 
|  | 6180 | int timeout; | 
|  | 6181 | uint8_t status = 0; | 
|  | 6182 |  | 
|  | 6183 | METHOD_TRACE("ips_erase_bios", 1); | 
|  | 6184 |  | 
|  | 6185 | status = 0; | 
|  | 6186 |  | 
|  | 6187 | /* Clear the status register */ | 
|  | 6188 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6189 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6190 | udelay(25);	/* 25 us */ | 
|  | 6191 |  | 
|  | 6192 | outb(0x50, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6193 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6194 | udelay(25);	/* 25 us */ | 
|  | 6195 |  | 
|  | 6196 | /* Erase Setup */ | 
|  | 6197 | outb(0x20, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6198 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6199 | udelay(25);	/* 25 us */ | 
|  | 6200 |  | 
|  | 6201 | /* Erase Confirm */ | 
|  | 6202 | outb(0xD0, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6203 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6204 | udelay(25);	/* 25 us */ | 
|  | 6205 |  | 
|  | 6206 | /* Erase Status */ | 
|  | 6207 | outb(0x70, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6208 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6209 | udelay(25);	/* 25 us */ | 
|  | 6210 |  | 
|  | 6211 | timeout = 80000;	/* 80 seconds */ | 
|  | 6212 |  | 
|  | 6213 | while (timeout > 0) { | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6214 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6215 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6216 | udelay(25);	/* 25 us */ | 
|  | 6217 | } | 
|  | 6218 |  | 
|  | 6219 | status = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6220 |  | 
|  | 6221 | if (status & 0x80) | 
|  | 6222 | break; | 
|  | 6223 |  | 
|  | 6224 | MDELAY(1); | 
|  | 6225 | timeout--; | 
|  | 6226 | } | 
|  | 6227 |  | 
|  | 6228 | /* check for timeout */ | 
|  | 6229 | if (timeout <= 0) { | 
|  | 6230 | /* timeout */ | 
|  | 6231 |  | 
|  | 6232 | /* try to suspend the erase */ | 
|  | 6233 | outb(0xB0, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6234 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6235 | udelay(25);	/* 25 us */ | 
|  | 6236 |  | 
|  | 6237 | /* wait for 10 seconds */ | 
|  | 6238 | timeout = 10000; | 
|  | 6239 | while (timeout > 0) { | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6240 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6241 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6242 | udelay(25);	/* 25 us */ | 
|  | 6243 | } | 
|  | 6244 |  | 
|  | 6245 | status = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6246 |  | 
|  | 6247 | if (status & 0xC0) | 
|  | 6248 | break; | 
|  | 6249 |  | 
|  | 6250 | MDELAY(1); | 
|  | 6251 | timeout--; | 
|  | 6252 | } | 
|  | 6253 |  | 
|  | 6254 | return (1); | 
|  | 6255 | } | 
|  | 6256 |  | 
|  | 6257 | /* check for valid VPP */ | 
|  | 6258 | if (status & 0x08) | 
|  | 6259 | /* VPP failure */ | 
|  | 6260 | return (1); | 
|  | 6261 |  | 
| Andreas Mohr | d6e05ed | 2006-06-26 18:35:02 +0200 | [diff] [blame] | 6262 | /* check for successful flash */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6263 | if (status & 0x30) | 
|  | 6264 | /* sequence error */ | 
|  | 6265 | return (1); | 
|  | 6266 |  | 
|  | 6267 | /* Otherwise, we were successful */ | 
|  | 6268 | /* clear status */ | 
|  | 6269 | outb(0x50, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6270 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6271 | udelay(25);	/* 25 us */ | 
|  | 6272 |  | 
|  | 6273 | /* enable reads */ | 
|  | 6274 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6275 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6276 | udelay(25);	/* 25 us */ | 
|  | 6277 |  | 
|  | 6278 | return (0); | 
|  | 6279 | } | 
|  | 6280 |  | 
|  | 6281 | /****************************************************************************/ | 
|  | 6282 | /*                                                                          */ | 
|  | 6283 | /* Routine Name: ips_erase_bios_memio                                       */ | 
|  | 6284 | /*                                                                          */ | 
|  | 6285 | /* Routine Description:                                                     */ | 
|  | 6286 | /*   Erase the BIOS on the adapter                                          */ | 
|  | 6287 | /*                                                                          */ | 
|  | 6288 | /****************************************************************************/ | 
|  | 6289 | static int | 
|  | 6290 | ips_erase_bios_memio(ips_ha_t * ha) | 
|  | 6291 | { | 
|  | 6292 | int timeout; | 
|  | 6293 | uint8_t status; | 
|  | 6294 |  | 
|  | 6295 | METHOD_TRACE("ips_erase_bios_memio", 1); | 
|  | 6296 |  | 
|  | 6297 | status = 0; | 
|  | 6298 |  | 
|  | 6299 | /* Clear the status register */ | 
|  | 6300 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6301 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6302 | udelay(25);	/* 25 us */ | 
|  | 6303 |  | 
|  | 6304 | writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6305 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6306 | udelay(25);	/* 25 us */ | 
|  | 6307 |  | 
|  | 6308 | /* Erase Setup */ | 
|  | 6309 | writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6310 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6311 | udelay(25);	/* 25 us */ | 
|  | 6312 |  | 
|  | 6313 | /* Erase Confirm */ | 
|  | 6314 | writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6315 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6316 | udelay(25);	/* 25 us */ | 
|  | 6317 |  | 
|  | 6318 | /* Erase Status */ | 
|  | 6319 | writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6320 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6321 | udelay(25);	/* 25 us */ | 
|  | 6322 |  | 
|  | 6323 | timeout = 80000;	/* 80 seconds */ | 
|  | 6324 |  | 
|  | 6325 | while (timeout > 0) { | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6326 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6327 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6328 | udelay(25);	/* 25 us */ | 
|  | 6329 | } | 
|  | 6330 |  | 
|  | 6331 | status = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6332 |  | 
|  | 6333 | if (status & 0x80) | 
|  | 6334 | break; | 
|  | 6335 |  | 
|  | 6336 | MDELAY(1); | 
|  | 6337 | timeout--; | 
|  | 6338 | } | 
|  | 6339 |  | 
|  | 6340 | /* check for timeout */ | 
|  | 6341 | if (timeout <= 0) { | 
|  | 6342 | /* timeout */ | 
|  | 6343 |  | 
|  | 6344 | /* try to suspend the erase */ | 
|  | 6345 | writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6346 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6347 | udelay(25);	/* 25 us */ | 
|  | 6348 |  | 
|  | 6349 | /* wait for 10 seconds */ | 
|  | 6350 | timeout = 10000; | 
|  | 6351 | while (timeout > 0) { | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6352 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6353 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6354 | udelay(25);	/* 25 us */ | 
|  | 6355 | } | 
|  | 6356 |  | 
|  | 6357 | status = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6358 |  | 
|  | 6359 | if (status & 0xC0) | 
|  | 6360 | break; | 
|  | 6361 |  | 
|  | 6362 | MDELAY(1); | 
|  | 6363 | timeout--; | 
|  | 6364 | } | 
|  | 6365 |  | 
|  | 6366 | return (1); | 
|  | 6367 | } | 
|  | 6368 |  | 
|  | 6369 | /* check for valid VPP */ | 
|  | 6370 | if (status & 0x08) | 
|  | 6371 | /* VPP failure */ | 
|  | 6372 | return (1); | 
|  | 6373 |  | 
| Andreas Mohr | d6e05ed | 2006-06-26 18:35:02 +0200 | [diff] [blame] | 6374 | /* check for successful flash */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6375 | if (status & 0x30) | 
|  | 6376 | /* sequence error */ | 
|  | 6377 | return (1); | 
|  | 6378 |  | 
|  | 6379 | /* Otherwise, we were successful */ | 
|  | 6380 | /* clear status */ | 
|  | 6381 | writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6382 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6383 | udelay(25);	/* 25 us */ | 
|  | 6384 |  | 
|  | 6385 | /* enable reads */ | 
|  | 6386 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6387 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6388 | udelay(25);	/* 25 us */ | 
|  | 6389 |  | 
|  | 6390 | return (0); | 
|  | 6391 | } | 
|  | 6392 |  | 
|  | 6393 | /****************************************************************************/ | 
|  | 6394 | /*                                                                          */ | 
|  | 6395 | /* Routine Name: ips_program_bios                                           */ | 
|  | 6396 | /*                                                                          */ | 
|  | 6397 | /* Routine Description:                                                     */ | 
|  | 6398 | /*   Program the BIOS on the adapter                                        */ | 
|  | 6399 | /*                                                                          */ | 
|  | 6400 | /****************************************************************************/ | 
|  | 6401 | static int | 
|  | 6402 | ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6403 | uint32_t offset) | 
|  | 6404 | { | 
|  | 6405 | int i; | 
|  | 6406 | int timeout; | 
|  | 6407 | uint8_t status = 0; | 
|  | 6408 |  | 
|  | 6409 | METHOD_TRACE("ips_program_bios", 1); | 
|  | 6410 |  | 
|  | 6411 | status = 0; | 
|  | 6412 |  | 
|  | 6413 | for (i = 0; i < buffersize; i++) { | 
|  | 6414 | /* write a byte */ | 
|  | 6415 | outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6416 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6417 | udelay(25);	/* 25 us */ | 
|  | 6418 |  | 
|  | 6419 | outb(0x40, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6420 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6421 | udelay(25);	/* 25 us */ | 
|  | 6422 |  | 
|  | 6423 | outb(buffer[i], ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6424 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6425 | udelay(25);	/* 25 us */ | 
|  | 6426 |  | 
|  | 6427 | /* wait up to one second */ | 
|  | 6428 | timeout = 1000; | 
|  | 6429 | while (timeout > 0) { | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6430 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6431 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6432 | udelay(25);	/* 25 us */ | 
|  | 6433 | } | 
|  | 6434 |  | 
|  | 6435 | status = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6436 |  | 
|  | 6437 | if (status & 0x80) | 
|  | 6438 | break; | 
|  | 6439 |  | 
|  | 6440 | MDELAY(1); | 
|  | 6441 | timeout--; | 
|  | 6442 | } | 
|  | 6443 |  | 
|  | 6444 | if (timeout == 0) { | 
|  | 6445 | /* timeout error */ | 
|  | 6446 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6447 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6448 | udelay(25);	/* 25 us */ | 
|  | 6449 |  | 
|  | 6450 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6451 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6452 | udelay(25);	/* 25 us */ | 
|  | 6453 |  | 
|  | 6454 | return (1); | 
|  | 6455 | } | 
|  | 6456 |  | 
|  | 6457 | /* check the status */ | 
|  | 6458 | if (status & 0x18) { | 
|  | 6459 | /* programming error */ | 
|  | 6460 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6461 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6462 | udelay(25);	/* 25 us */ | 
|  | 6463 |  | 
|  | 6464 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6465 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6466 | udelay(25);	/* 25 us */ | 
|  | 6467 |  | 
|  | 6468 | return (1); | 
|  | 6469 | } | 
|  | 6470 | }			/* end for */ | 
|  | 6471 |  | 
|  | 6472 | /* Enable reading */ | 
|  | 6473 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6474 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6475 | udelay(25);	/* 25 us */ | 
|  | 6476 |  | 
|  | 6477 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6478 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6479 | udelay(25);	/* 25 us */ | 
|  | 6480 |  | 
|  | 6481 | return (0); | 
|  | 6482 | } | 
|  | 6483 |  | 
|  | 6484 | /****************************************************************************/ | 
|  | 6485 | /*                                                                          */ | 
|  | 6486 | /* Routine Name: ips_program_bios_memio                                     */ | 
|  | 6487 | /*                                                                          */ | 
|  | 6488 | /* Routine Description:                                                     */ | 
|  | 6489 | /*   Program the BIOS on the adapter                                        */ | 
|  | 6490 | /*                                                                          */ | 
|  | 6491 | /****************************************************************************/ | 
|  | 6492 | static int | 
|  | 6493 | ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6494 | uint32_t offset) | 
|  | 6495 | { | 
|  | 6496 | int i; | 
|  | 6497 | int timeout; | 
|  | 6498 | uint8_t status = 0; | 
|  | 6499 |  | 
|  | 6500 | METHOD_TRACE("ips_program_bios_memio", 1); | 
|  | 6501 |  | 
|  | 6502 | status = 0; | 
|  | 6503 |  | 
|  | 6504 | for (i = 0; i < buffersize; i++) { | 
|  | 6505 | /* write a byte */ | 
|  | 6506 | writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6507 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6508 | udelay(25);	/* 25 us */ | 
|  | 6509 |  | 
|  | 6510 | writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6511 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6512 | udelay(25);	/* 25 us */ | 
|  | 6513 |  | 
|  | 6514 | writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6515 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6516 | udelay(25);	/* 25 us */ | 
|  | 6517 |  | 
|  | 6518 | /* wait up to one second */ | 
|  | 6519 | timeout = 1000; | 
|  | 6520 | while (timeout > 0) { | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6521 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6522 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6523 | udelay(25);	/* 25 us */ | 
|  | 6524 | } | 
|  | 6525 |  | 
|  | 6526 | status = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6527 |  | 
|  | 6528 | if (status & 0x80) | 
|  | 6529 | break; | 
|  | 6530 |  | 
|  | 6531 | MDELAY(1); | 
|  | 6532 | timeout--; | 
|  | 6533 | } | 
|  | 6534 |  | 
|  | 6535 | if (timeout == 0) { | 
|  | 6536 | /* timeout error */ | 
|  | 6537 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6538 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6539 | udelay(25);	/* 25 us */ | 
|  | 6540 |  | 
|  | 6541 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6542 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6543 | udelay(25);	/* 25 us */ | 
|  | 6544 |  | 
|  | 6545 | return (1); | 
|  | 6546 | } | 
|  | 6547 |  | 
|  | 6548 | /* check the status */ | 
|  | 6549 | if (status & 0x18) { | 
|  | 6550 | /* programming error */ | 
|  | 6551 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6552 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6553 | udelay(25);	/* 25 us */ | 
|  | 6554 |  | 
|  | 6555 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6556 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6557 | udelay(25);	/* 25 us */ | 
|  | 6558 |  | 
|  | 6559 | return (1); | 
|  | 6560 | } | 
|  | 6561 | }			/* end for */ | 
|  | 6562 |  | 
|  | 6563 | /* Enable reading */ | 
|  | 6564 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6565 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6566 | udelay(25);	/* 25 us */ | 
|  | 6567 |  | 
|  | 6568 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6569 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6570 | udelay(25);	/* 25 us */ | 
|  | 6571 |  | 
|  | 6572 | return (0); | 
|  | 6573 | } | 
|  | 6574 |  | 
|  | 6575 | /****************************************************************************/ | 
|  | 6576 | /*                                                                          */ | 
|  | 6577 | /* Routine Name: ips_verify_bios                                            */ | 
|  | 6578 | /*                                                                          */ | 
|  | 6579 | /* Routine Description:                                                     */ | 
|  | 6580 | /*   Verify the BIOS on the adapter                                         */ | 
|  | 6581 | /*                                                                          */ | 
|  | 6582 | /****************************************************************************/ | 
|  | 6583 | static int | 
|  | 6584 | ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6585 | uint32_t offset) | 
|  | 6586 | { | 
|  | 6587 | uint8_t checksum; | 
|  | 6588 | int i; | 
|  | 6589 |  | 
|  | 6590 | METHOD_TRACE("ips_verify_bios", 1); | 
|  | 6591 |  | 
|  | 6592 | /* test 1st byte */ | 
|  | 6593 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6594 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6595 | udelay(25);	/* 25 us */ | 
|  | 6596 |  | 
|  | 6597 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) | 
|  | 6598 | return (1); | 
|  | 6599 |  | 
|  | 6600 | outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6601 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6602 | udelay(25);	/* 25 us */ | 
|  | 6603 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) | 
|  | 6604 | return (1); | 
|  | 6605 |  | 
|  | 6606 | checksum = 0xff; | 
|  | 6607 | for (i = 2; i < buffersize; i++) { | 
|  | 6608 |  | 
|  | 6609 | outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6610 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6611 | udelay(25);	/* 25 us */ | 
|  | 6612 |  | 
|  | 6613 | checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6614 | } | 
|  | 6615 |  | 
|  | 6616 | if (checksum != 0) | 
|  | 6617 | /* failure */ | 
|  | 6618 | return (1); | 
|  | 6619 | else | 
|  | 6620 | /* success */ | 
|  | 6621 | return (0); | 
|  | 6622 | } | 
|  | 6623 |  | 
|  | 6624 | /****************************************************************************/ | 
|  | 6625 | /*                                                                          */ | 
|  | 6626 | /* Routine Name: ips_verify_bios_memio                                      */ | 
|  | 6627 | /*                                                                          */ | 
|  | 6628 | /* Routine Description:                                                     */ | 
|  | 6629 | /*   Verify the BIOS on the adapter                                         */ | 
|  | 6630 | /*                                                                          */ | 
|  | 6631 | /****************************************************************************/ | 
|  | 6632 | static int | 
|  | 6633 | ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6634 | uint32_t offset) | 
|  | 6635 | { | 
|  | 6636 | uint8_t checksum; | 
|  | 6637 | int i; | 
|  | 6638 |  | 
|  | 6639 | METHOD_TRACE("ips_verify_bios_memio", 1); | 
|  | 6640 |  | 
|  | 6641 | /* test 1st byte */ | 
|  | 6642 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6643 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6644 | udelay(25);	/* 25 us */ | 
|  | 6645 |  | 
|  | 6646 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) | 
|  | 6647 | return (1); | 
|  | 6648 |  | 
|  | 6649 | writel(1, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6650 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6651 | udelay(25);	/* 25 us */ | 
|  | 6652 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) | 
|  | 6653 | return (1); | 
|  | 6654 |  | 
|  | 6655 | checksum = 0xff; | 
|  | 6656 | for (i = 2; i < buffersize; i++) { | 
|  | 6657 |  | 
|  | 6658 | writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6659 | if (ha->pcidev->revision == IPS_REVID_TROMBONE64) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6660 | udelay(25);	/* 25 us */ | 
|  | 6661 |  | 
|  | 6662 | checksum = | 
|  | 6663 | (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6664 | } | 
|  | 6665 |  | 
|  | 6666 | if (checksum != 0) | 
|  | 6667 | /* failure */ | 
|  | 6668 | return (1); | 
|  | 6669 | else | 
|  | 6670 | /* success */ | 
|  | 6671 | return (0); | 
|  | 6672 | } | 
|  | 6673 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6674 | /****************************************************************************/ | 
|  | 6675 | /*                                                                          */ | 
|  | 6676 | /* Routine Name: ips_abort_init                                             */ | 
|  | 6677 | /*                                                                          */ | 
|  | 6678 | /* Routine Description:                                                     */ | 
|  | 6679 | /*   cleanup routine for a failed adapter initialization                    */ | 
|  | 6680 | /****************************************************************************/ | 
|  | 6681 | static int | 
|  | 6682 | ips_abort_init(ips_ha_t * ha, int index) | 
|  | 6683 | { | 
|  | 6684 | ha->active = 0; | 
|  | 6685 | ips_free(ha); | 
|  | 6686 | ips_ha[index] = NULL; | 
|  | 6687 | ips_sh[index] = NULL; | 
|  | 6688 | return -1; | 
|  | 6689 | } | 
|  | 6690 |  | 
|  | 6691 | /****************************************************************************/ | 
|  | 6692 | /*                                                                          */ | 
|  | 6693 | /* Routine Name: ips_shift_controllers                                      */ | 
|  | 6694 | /*                                                                          */ | 
|  | 6695 | /* Routine Description:                                                     */ | 
|  | 6696 | /*   helper function for ordering adapters                                  */ | 
|  | 6697 | /****************************************************************************/ | 
|  | 6698 | static void | 
|  | 6699 | ips_shift_controllers(int lowindex, int highindex) | 
|  | 6700 | { | 
|  | 6701 | ips_ha_t *ha_sav = ips_ha[highindex]; | 
|  | 6702 | struct Scsi_Host *sh_sav = ips_sh[highindex]; | 
|  | 6703 | int i; | 
|  | 6704 |  | 
|  | 6705 | for (i = highindex; i > lowindex; i--) { | 
|  | 6706 | ips_ha[i] = ips_ha[i - 1]; | 
|  | 6707 | ips_sh[i] = ips_sh[i - 1]; | 
|  | 6708 | ips_ha[i]->host_num = i; | 
|  | 6709 | } | 
|  | 6710 | ha_sav->host_num = lowindex; | 
|  | 6711 | ips_ha[lowindex] = ha_sav; | 
|  | 6712 | ips_sh[lowindex] = sh_sav; | 
|  | 6713 | } | 
|  | 6714 |  | 
|  | 6715 | /****************************************************************************/ | 
|  | 6716 | /*                                                                          */ | 
|  | 6717 | /* Routine Name: ips_order_controllers                                      */ | 
|  | 6718 | /*                                                                          */ | 
|  | 6719 | /* Routine Description:                                                     */ | 
|  | 6720 | /*   place controllers is the "proper" boot order                           */ | 
|  | 6721 | /****************************************************************************/ | 
|  | 6722 | static void | 
|  | 6723 | ips_order_controllers(void) | 
|  | 6724 | { | 
|  | 6725 | int i, j, tmp, position = 0; | 
|  | 6726 | IPS_NVRAM_P5 *nvram; | 
|  | 6727 | if (!ips_ha[0]) | 
|  | 6728 | return; | 
|  | 6729 | nvram = ips_ha[0]->nvram; | 
|  | 6730 |  | 
|  | 6731 | if (nvram->adapter_order[0]) { | 
|  | 6732 | for (i = 1; i <= nvram->adapter_order[0]; i++) { | 
|  | 6733 | for (j = position; j < ips_num_controllers; j++) { | 
|  | 6734 | switch (ips_ha[j]->ad_type) { | 
|  | 6735 | case IPS_ADTYPE_SERVERAID6M: | 
|  | 6736 | case IPS_ADTYPE_SERVERAID7M: | 
|  | 6737 | if (nvram->adapter_order[i] == 'M') { | 
|  | 6738 | ips_shift_controllers(position, | 
|  | 6739 | j); | 
|  | 6740 | position++; | 
|  | 6741 | } | 
|  | 6742 | break; | 
|  | 6743 | case IPS_ADTYPE_SERVERAID4L: | 
|  | 6744 | case IPS_ADTYPE_SERVERAID4M: | 
|  | 6745 | case IPS_ADTYPE_SERVERAID4MX: | 
|  | 6746 | case IPS_ADTYPE_SERVERAID4LX: | 
|  | 6747 | if (nvram->adapter_order[i] == 'N') { | 
|  | 6748 | ips_shift_controllers(position, | 
|  | 6749 | j); | 
|  | 6750 | position++; | 
|  | 6751 | } | 
|  | 6752 | break; | 
|  | 6753 | case IPS_ADTYPE_SERVERAID6I: | 
|  | 6754 | case IPS_ADTYPE_SERVERAID5I2: | 
|  | 6755 | case IPS_ADTYPE_SERVERAID5I1: | 
|  | 6756 | case IPS_ADTYPE_SERVERAID7k: | 
|  | 6757 | if (nvram->adapter_order[i] == 'S') { | 
|  | 6758 | ips_shift_controllers(position, | 
|  | 6759 | j); | 
|  | 6760 | position++; | 
|  | 6761 | } | 
|  | 6762 | break; | 
|  | 6763 | case IPS_ADTYPE_SERVERAID: | 
|  | 6764 | case IPS_ADTYPE_SERVERAID2: | 
|  | 6765 | case IPS_ADTYPE_NAVAJO: | 
|  | 6766 | case IPS_ADTYPE_KIOWA: | 
|  | 6767 | case IPS_ADTYPE_SERVERAID3L: | 
|  | 6768 | case IPS_ADTYPE_SERVERAID3: | 
|  | 6769 | case IPS_ADTYPE_SERVERAID4H: | 
|  | 6770 | if (nvram->adapter_order[i] == 'A') { | 
|  | 6771 | ips_shift_controllers(position, | 
|  | 6772 | j); | 
|  | 6773 | position++; | 
|  | 6774 | } | 
|  | 6775 | break; | 
|  | 6776 | default: | 
|  | 6777 | break; | 
|  | 6778 | } | 
|  | 6779 | } | 
|  | 6780 | } | 
|  | 6781 | /* if adapter_order[0], then ordering is complete */ | 
|  | 6782 | return; | 
|  | 6783 | } | 
|  | 6784 | /* old bios, use older ordering */ | 
|  | 6785 | tmp = 0; | 
|  | 6786 | for (i = position; i < ips_num_controllers; i++) { | 
|  | 6787 | if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 || | 
|  | 6788 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) { | 
|  | 6789 | ips_shift_controllers(position, i); | 
|  | 6790 | position++; | 
|  | 6791 | tmp = 1; | 
|  | 6792 | } | 
|  | 6793 | } | 
|  | 6794 | /* if there were no 5I cards, then don't do any extra ordering */ | 
|  | 6795 | if (!tmp) | 
|  | 6796 | return; | 
|  | 6797 | for (i = position; i < ips_num_controllers; i++) { | 
|  | 6798 | if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L || | 
|  | 6799 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M || | 
|  | 6800 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX || | 
|  | 6801 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) { | 
|  | 6802 | ips_shift_controllers(position, i); | 
|  | 6803 | position++; | 
|  | 6804 | } | 
|  | 6805 | } | 
|  | 6806 |  | 
|  | 6807 | return; | 
|  | 6808 | } | 
|  | 6809 |  | 
|  | 6810 | /****************************************************************************/ | 
|  | 6811 | /*                                                                          */ | 
|  | 6812 | /* Routine Name: ips_register_scsi                                          */ | 
|  | 6813 | /*                                                                          */ | 
|  | 6814 | /* Routine Description:                                                     */ | 
|  | 6815 | /*   perform any registration and setup with the scsi layer                 */ | 
|  | 6816 | /****************************************************************************/ | 
|  | 6817 | static int | 
|  | 6818 | ips_register_scsi(int index) | 
|  | 6819 | { | 
|  | 6820 | struct Scsi_Host *sh; | 
|  | 6821 | ips_ha_t *ha, *oldha = ips_ha[index]; | 
|  | 6822 | sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t)); | 
|  | 6823 | if (!sh) { | 
|  | 6824 | IPS_PRINTK(KERN_WARNING, oldha->pcidev, | 
|  | 6825 | "Unable to register controller with SCSI subsystem\n"); | 
|  | 6826 | return -1; | 
|  | 6827 | } | 
|  | 6828 | ha = IPS_HA(sh); | 
|  | 6829 | memcpy(ha, oldha, sizeof (ips_ha_t)); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6830 | free_irq(oldha->pcidev->irq, oldha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6831 | /* Install the interrupt handler with the new ha */ | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 6832 | if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6833 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 6834 | "Unable to install interrupt handler\n"); | 
| Jeff Garzik | 2551a13 | 2007-12-13 16:14:10 -0800 | [diff] [blame] | 6835 | goto err_out_sh; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6836 | } | 
|  | 6837 |  | 
|  | 6838 | kfree(oldha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6839 |  | 
|  | 6840 | /* Store away needed values for later use */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6841 | sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6842 | sh->sg_tablesize = sh->hostt->sg_tablesize; | 
|  | 6843 | sh->can_queue = sh->hostt->can_queue; | 
|  | 6844 | sh->cmd_per_lun = sh->hostt->cmd_per_lun; | 
|  | 6845 | sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; | 
|  | 6846 | sh->use_clustering = sh->hostt->use_clustering; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6847 | sh->max_sectors = 128; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6848 |  | 
|  | 6849 | sh->max_id = ha->ntargets; | 
|  | 6850 | sh->max_lun = ha->nlun; | 
|  | 6851 | sh->max_channel = ha->nbus - 1; | 
|  | 6852 | sh->can_queue = ha->max_cmds - 1; | 
|  | 6853 |  | 
| Jeff Garzik | 2551a13 | 2007-12-13 16:14:10 -0800 | [diff] [blame] | 6854 | if (scsi_add_host(sh, &ha->pcidev->dev)) | 
|  | 6855 | goto err_out; | 
|  | 6856 |  | 
|  | 6857 | ips_sh[index] = sh; | 
|  | 6858 | ips_ha[index] = ha; | 
|  | 6859 |  | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 6860 | scsi_scan_host(sh); | 
|  | 6861 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6862 | return 0; | 
| Jeff Garzik | 2551a13 | 2007-12-13 16:14:10 -0800 | [diff] [blame] | 6863 |  | 
|  | 6864 | err_out: | 
|  | 6865 | free_irq(ha->pcidev->irq, ha); | 
|  | 6866 | err_out_sh: | 
|  | 6867 | scsi_host_put(sh); | 
|  | 6868 | return -1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6869 | } | 
|  | 6870 |  | 
|  | 6871 | /*---------------------------------------------------------------------------*/ | 
|  | 6872 | /*   Routine Name: ips_remove_device                                         */ | 
|  | 6873 | /*                                                                           */ | 
|  | 6874 | /*   Routine Description:                                                    */ | 
|  | 6875 | /*     Remove one Adapter ( Hot Plugging )                                   */ | 
|  | 6876 | /*---------------------------------------------------------------------------*/ | 
|  | 6877 | static void __devexit | 
|  | 6878 | ips_remove_device(struct pci_dev *pci_dev) | 
|  | 6879 | { | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 6880 | struct Scsi_Host *sh = pci_get_drvdata(pci_dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6881 |  | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 6882 | pci_set_drvdata(pci_dev, NULL); | 
|  | 6883 |  | 
|  | 6884 | ips_release(sh); | 
|  | 6885 |  | 
|  | 6886 | pci_release_regions(pci_dev); | 
|  | 6887 | pci_disable_device(pci_dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6888 | } | 
|  | 6889 |  | 
|  | 6890 | /****************************************************************************/ | 
|  | 6891 | /*                                                                          */ | 
|  | 6892 | /* Routine Name: ips_module_init                                            */ | 
|  | 6893 | /*                                                                          */ | 
|  | 6894 | /* Routine Description:                                                     */ | 
|  | 6895 | /*   function called on module load                                         */ | 
|  | 6896 | /****************************************************************************/ | 
|  | 6897 | static int __init | 
|  | 6898 | ips_module_init(void) | 
|  | 6899 | { | 
| Alan Cox | 02a0fa6 | 2006-09-25 23:45:51 +0100 | [diff] [blame] | 6900 | if (pci_register_driver(&ips_pci_driver) < 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6901 | return -ENODEV; | 
|  | 6902 | ips_driver_template.module = THIS_MODULE; | 
|  | 6903 | ips_order_controllers(); | 
| Adrian Bunk | c6a6c81 | 2007-05-23 14:41:46 -0700 | [diff] [blame] | 6904 | if (!ips_detect(&ips_driver_template)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6905 | pci_unregister_driver(&ips_pci_driver); | 
|  | 6906 | return -ENODEV; | 
|  | 6907 | } | 
|  | 6908 | register_reboot_notifier(&ips_notifier); | 
|  | 6909 | return 0; | 
|  | 6910 | } | 
|  | 6911 |  | 
|  | 6912 | /****************************************************************************/ | 
|  | 6913 | /*                                                                          */ | 
|  | 6914 | /* Routine Name: ips_module_exit                                            */ | 
|  | 6915 | /*                                                                          */ | 
|  | 6916 | /* Routine Description:                                                     */ | 
|  | 6917 | /*   function called on module unload                                       */ | 
|  | 6918 | /****************************************************************************/ | 
|  | 6919 | static void __exit | 
|  | 6920 | ips_module_exit(void) | 
|  | 6921 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6922 | pci_unregister_driver(&ips_pci_driver); | 
|  | 6923 | unregister_reboot_notifier(&ips_notifier); | 
|  | 6924 | } | 
|  | 6925 |  | 
|  | 6926 | module_init(ips_module_init); | 
|  | 6927 | module_exit(ips_module_exit); | 
|  | 6928 |  | 
|  | 6929 | /*---------------------------------------------------------------------------*/ | 
|  | 6930 | /*   Routine Name: ips_insert_device                                         */ | 
|  | 6931 | /*                                                                           */ | 
|  | 6932 | /*   Routine Description:                                                    */ | 
|  | 6933 | /*     Add One Adapter ( Hot Plug )                                          */ | 
|  | 6934 | /*                                                                           */ | 
|  | 6935 | /*   Return Value:                                                           */ | 
|  | 6936 | /*     0 if Successful, else non-zero                                        */ | 
|  | 6937 | /*---------------------------------------------------------------------------*/ | 
|  | 6938 | static int __devinit | 
|  | 6939 | ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) | 
|  | 6940 | { | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 6941 | int index = -1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6942 | int rc; | 
|  | 6943 |  | 
|  | 6944 | METHOD_TRACE("ips_insert_device", 1); | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 6945 | rc = pci_enable_device(pci_dev); | 
|  | 6946 | if (rc) | 
|  | 6947 | return rc; | 
|  | 6948 |  | 
|  | 6949 | rc = pci_request_regions(pci_dev, "ips"); | 
|  | 6950 | if (rc) | 
|  | 6951 | goto err_out; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6952 |  | 
|  | 6953 | rc = ips_init_phase1(pci_dev, &index); | 
|  | 6954 | if (rc == SUCCESS) | 
|  | 6955 | rc = ips_init_phase2(index); | 
|  | 6956 |  | 
|  | 6957 | if (ips_hotplug) | 
|  | 6958 | if (ips_register_scsi(index)) { | 
|  | 6959 | ips_free(ips_ha[index]); | 
|  | 6960 | rc = -1; | 
|  | 6961 | } | 
|  | 6962 |  | 
|  | 6963 | if (rc == SUCCESS) | 
|  | 6964 | ips_num_controllers++; | 
|  | 6965 |  | 
|  | 6966 | ips_next_controller = ips_num_controllers; | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 6967 |  | 
|  | 6968 | if (rc < 0) { | 
|  | 6969 | rc = -ENODEV; | 
|  | 6970 | goto err_out_regions; | 
|  | 6971 | } | 
|  | 6972 |  | 
|  | 6973 | pci_set_drvdata(pci_dev, ips_sh[index]); | 
|  | 6974 | return 0; | 
|  | 6975 |  | 
|  | 6976 | err_out_regions: | 
|  | 6977 | pci_release_regions(pci_dev); | 
|  | 6978 | err_out: | 
|  | 6979 | pci_disable_device(pci_dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6980 | return rc; | 
|  | 6981 | } | 
|  | 6982 |  | 
|  | 6983 | /*---------------------------------------------------------------------------*/ | 
|  | 6984 | /*   Routine Name: ips_init_phase1                                           */ | 
|  | 6985 | /*                                                                           */ | 
|  | 6986 | /*   Routine Description:                                                    */ | 
|  | 6987 | /*     Adapter Initialization                                                */ | 
|  | 6988 | /*                                                                           */ | 
|  | 6989 | /*   Return Value:                                                           */ | 
|  | 6990 | /*     0 if Successful, else non-zero                                        */ | 
|  | 6991 | /*---------------------------------------------------------------------------*/ | 
|  | 6992 | static int | 
|  | 6993 | ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) | 
|  | 6994 | { | 
|  | 6995 | ips_ha_t *ha; | 
|  | 6996 | uint32_t io_addr; | 
|  | 6997 | uint32_t mem_addr; | 
|  | 6998 | uint32_t io_len; | 
|  | 6999 | uint32_t mem_len; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7000 | uint8_t bus; | 
|  | 7001 | uint8_t func; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7002 | int j; | 
|  | 7003 | int index; | 
|  | 7004 | dma_addr_t dma_address; | 
|  | 7005 | char __iomem *ioremap_ptr; | 
|  | 7006 | char __iomem *mem_ptr; | 
|  | 7007 | uint32_t IsDead; | 
|  | 7008 |  | 
|  | 7009 | METHOD_TRACE("ips_init_phase1", 1); | 
|  | 7010 | index = IPS_MAX_ADAPTERS; | 
|  | 7011 | for (j = 0; j < IPS_MAX_ADAPTERS; j++) { | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 7012 | if (ips_ha[j] == NULL) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7013 | index = j; | 
|  | 7014 | break; | 
|  | 7015 | } | 
|  | 7016 | } | 
|  | 7017 |  | 
|  | 7018 | if (index >= IPS_MAX_ADAPTERS) | 
|  | 7019 | return -1; | 
|  | 7020 |  | 
|  | 7021 | /* stuff that we get in dev */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7022 | bus = pci_dev->bus->number; | 
|  | 7023 | func = pci_dev->devfn; | 
|  | 7024 |  | 
|  | 7025 | /* Init MEM/IO addresses to 0 */ | 
|  | 7026 | mem_addr = 0; | 
|  | 7027 | io_addr = 0; | 
|  | 7028 | mem_len = 0; | 
|  | 7029 | io_len = 0; | 
|  | 7030 |  | 
|  | 7031 | for (j = 0; j < 2; j++) { | 
|  | 7032 | if (!pci_resource_start(pci_dev, j)) | 
|  | 7033 | break; | 
|  | 7034 |  | 
|  | 7035 | if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) { | 
|  | 7036 | io_addr = pci_resource_start(pci_dev, j); | 
|  | 7037 | io_len = pci_resource_len(pci_dev, j); | 
|  | 7038 | } else { | 
|  | 7039 | mem_addr = pci_resource_start(pci_dev, j); | 
|  | 7040 | mem_len = pci_resource_len(pci_dev, j); | 
|  | 7041 | } | 
|  | 7042 | } | 
|  | 7043 |  | 
|  | 7044 | /* setup memory mapped area (if applicable) */ | 
|  | 7045 | if (mem_addr) { | 
|  | 7046 | uint32_t base; | 
|  | 7047 | uint32_t offs; | 
|  | 7048 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7049 | base = mem_addr & PAGE_MASK; | 
|  | 7050 | offs = mem_addr - base; | 
|  | 7051 | ioremap_ptr = ioremap(base, PAGE_SIZE); | 
| Jeff Garzik | 21e1a5f | 2007-12-13 16:14:09 -0800 | [diff] [blame] | 7052 | if (!ioremap_ptr) | 
|  | 7053 | return -1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7054 | mem_ptr = ioremap_ptr + offs; | 
|  | 7055 | } else { | 
|  | 7056 | ioremap_ptr = NULL; | 
|  | 7057 | mem_ptr = NULL; | 
|  | 7058 | } | 
|  | 7059 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7060 | /* found a controller */ | 
| Yoann Padioleau | dd00cc4 | 2007-07-19 01:49:03 -0700 | [diff] [blame] | 7061 | ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7062 | if (ha == NULL) { | 
|  | 7063 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7064 | "Unable to allocate temporary ha struct\n"); | 
|  | 7065 | return -1; | 
|  | 7066 | } | 
|  | 7067 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7068 | ips_sh[index] = NULL; | 
|  | 7069 | ips_ha[index] = ha; | 
|  | 7070 | ha->active = 1; | 
|  | 7071 |  | 
|  | 7072 | /* Store info in HA structure */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7073 | ha->io_addr = io_addr; | 
|  | 7074 | ha->io_len = io_len; | 
|  | 7075 | ha->mem_addr = mem_addr; | 
|  | 7076 | ha->mem_len = mem_len; | 
|  | 7077 | ha->mem_ptr = mem_ptr; | 
|  | 7078 | ha->ioremap_ptr = ioremap_ptr; | 
|  | 7079 | ha->host_num = (uint32_t) index; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7080 | ha->slot_num = PCI_SLOT(pci_dev->devfn); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7081 | ha->pcidev = pci_dev; | 
|  | 7082 |  | 
|  | 7083 | /* | 
|  | 7084 | * Set the pci_dev's dma_mask.  Not all adapters support 64bit | 
|  | 7085 | * addressing so don't enable it if the adapter can't support | 
|  | 7086 | * it!  Also, don't use 64bit addressing if dma addresses | 
|  | 7087 | * are guaranteed to be < 4G. | 
|  | 7088 | */ | 
|  | 7089 | if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) && | 
| Matthias Gehre | 910638a | 2006-03-28 01:56:48 -0800 | [diff] [blame] | 7090 | !pci_set_dma_mask(ha->pcidev, DMA_64BIT_MASK)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7091 | (ha)->flags |= IPS_HA_ENH_SG; | 
|  | 7092 | } else { | 
| Matthias Gehre | 910638a | 2006-03-28 01:56:48 -0800 | [diff] [blame] | 7093 | if (pci_set_dma_mask(ha->pcidev, DMA_32BIT_MASK) != 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7094 | printk(KERN_WARNING "Unable to set DMA Mask\n"); | 
|  | 7095 | return ips_abort_init(ha, index); | 
|  | 7096 | } | 
|  | 7097 | } | 
|  | 7098 | if(ips_cd_boot && !ips_FlashData){ | 
|  | 7099 | ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7, | 
|  | 7100 | &ips_flashbusaddr); | 
|  | 7101 | } | 
|  | 7102 |  | 
|  | 7103 | ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ), | 
|  | 7104 | &ha->enq_busaddr); | 
|  | 7105 | if (!ha->enq) { | 
|  | 7106 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7107 | "Unable to allocate host inquiry structure\n"); | 
|  | 7108 | return ips_abort_init(ha, index); | 
|  | 7109 | } | 
|  | 7110 |  | 
|  | 7111 | ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) + | 
|  | 7112 | sizeof (IPS_IO_CMD), &dma_address); | 
|  | 7113 | if (!ha->adapt) { | 
|  | 7114 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7115 | "Unable to allocate host adapt & dummy structures\n"); | 
|  | 7116 | return ips_abort_init(ha, index); | 
|  | 7117 | } | 
|  | 7118 | ha->adapt->hw_status_start = dma_address; | 
|  | 7119 | ha->dummy = (void *) (ha->adapt + 1); | 
|  | 7120 |  | 
|  | 7121 |  | 
|  | 7122 |  | 
|  | 7123 | ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address); | 
|  | 7124 | if (!ha->logical_drive_info) { | 
|  | 7125 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7126 | "Unable to allocate logical drive info structure\n"); | 
|  | 7127 | return ips_abort_init(ha, index); | 
|  | 7128 | } | 
|  | 7129 | ha->logical_drive_info_dma_addr = dma_address; | 
|  | 7130 |  | 
|  | 7131 |  | 
|  | 7132 | ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL); | 
|  | 7133 |  | 
|  | 7134 | if (!ha->conf) { | 
|  | 7135 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7136 | "Unable to allocate host conf structure\n"); | 
|  | 7137 | return ips_abort_init(ha, index); | 
|  | 7138 | } | 
|  | 7139 |  | 
|  | 7140 | ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL); | 
|  | 7141 |  | 
|  | 7142 | if (!ha->nvram) { | 
|  | 7143 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7144 | "Unable to allocate host NVRAM structure\n"); | 
|  | 7145 | return ips_abort_init(ha, index); | 
|  | 7146 | } | 
|  | 7147 |  | 
|  | 7148 | ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL); | 
|  | 7149 |  | 
|  | 7150 | if (!ha->subsys) { | 
|  | 7151 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7152 | "Unable to allocate host subsystem structure\n"); | 
|  | 7153 | return ips_abort_init(ha, index); | 
|  | 7154 | } | 
|  | 7155 |  | 
|  | 7156 | /* the ioctl buffer is now used during adapter initialization, so its | 
|  | 7157 | * successful allocation is now required */ | 
|  | 7158 | if (ips_ioctlsize < PAGE_SIZE) | 
|  | 7159 | ips_ioctlsize = PAGE_SIZE; | 
|  | 7160 |  | 
|  | 7161 | ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize, | 
|  | 7162 | &ha->ioctl_busaddr); | 
|  | 7163 | ha->ioctl_len = ips_ioctlsize; | 
|  | 7164 | if (!ha->ioctl_data) { | 
|  | 7165 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7166 | "Unable to allocate IOCTL data\n"); | 
|  | 7167 | return ips_abort_init(ha, index); | 
|  | 7168 | } | 
|  | 7169 |  | 
|  | 7170 | /* | 
|  | 7171 | * Setup Functions | 
|  | 7172 | */ | 
|  | 7173 | ips_setup_funclist(ha); | 
|  | 7174 |  | 
|  | 7175 | if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) { | 
|  | 7176 | /* If Morpheus appears dead, reset it */ | 
|  | 7177 | IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1); | 
|  | 7178 | if (IsDead == 0xDEADBEEF) { | 
|  | 7179 | ips_reset_morpheus(ha); | 
|  | 7180 | } | 
|  | 7181 | } | 
|  | 7182 |  | 
|  | 7183 | /* | 
|  | 7184 | * Initialize the card if it isn't already | 
|  | 7185 | */ | 
|  | 7186 |  | 
|  | 7187 | if (!(*ha->func.isinit) (ha)) { | 
|  | 7188 | if (!(*ha->func.init) (ha)) { | 
|  | 7189 | /* | 
|  | 7190 | * Initialization failed | 
|  | 7191 | */ | 
|  | 7192 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7193 | "Unable to initialize controller\n"); | 
|  | 7194 | return ips_abort_init(ha, index); | 
|  | 7195 | } | 
|  | 7196 | } | 
|  | 7197 |  | 
|  | 7198 | *indexPtr = index; | 
|  | 7199 | return SUCCESS; | 
|  | 7200 | } | 
|  | 7201 |  | 
|  | 7202 | /*---------------------------------------------------------------------------*/ | 
|  | 7203 | /*   Routine Name: ips_init_phase2                                           */ | 
|  | 7204 | /*                                                                           */ | 
|  | 7205 | /*   Routine Description:                                                    */ | 
|  | 7206 | /*     Adapter Initialization Phase 2                                        */ | 
|  | 7207 | /*                                                                           */ | 
|  | 7208 | /*   Return Value:                                                           */ | 
|  | 7209 | /*     0 if Successful, else non-zero                                        */ | 
|  | 7210 | /*---------------------------------------------------------------------------*/ | 
|  | 7211 | static int | 
|  | 7212 | ips_init_phase2(int index) | 
|  | 7213 | { | 
|  | 7214 | ips_ha_t *ha; | 
|  | 7215 |  | 
|  | 7216 | ha = ips_ha[index]; | 
|  | 7217 |  | 
|  | 7218 | METHOD_TRACE("ips_init_phase2", 1); | 
|  | 7219 | if (!ha->active) { | 
|  | 7220 | ips_ha[index] = NULL; | 
|  | 7221 | return -1; | 
|  | 7222 | } | 
|  | 7223 |  | 
|  | 7224 | /* Install the interrupt handler */ | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 7225 | if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7226 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7227 | "Unable to install interrupt handler\n"); | 
|  | 7228 | return ips_abort_init(ha, index); | 
|  | 7229 | } | 
|  | 7230 |  | 
|  | 7231 | /* | 
|  | 7232 | * Allocate a temporary SCB for initialization | 
|  | 7233 | */ | 
|  | 7234 | ha->max_cmds = 1; | 
|  | 7235 | if (!ips_allocatescbs(ha)) { | 
|  | 7236 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7237 | "Unable to allocate a CCB\n"); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 7238 | free_irq(ha->pcidev->irq, ha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7239 | return ips_abort_init(ha, index); | 
|  | 7240 | } | 
|  | 7241 |  | 
|  | 7242 | if (!ips_hainit(ha)) { | 
|  | 7243 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7244 | "Unable to initialize controller\n"); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 7245 | free_irq(ha->pcidev->irq, ha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7246 | return ips_abort_init(ha, index); | 
|  | 7247 | } | 
|  | 7248 | /* Free the temporary SCB */ | 
|  | 7249 | ips_deallocatescbs(ha, 1); | 
|  | 7250 |  | 
|  | 7251 | /* allocate CCBs */ | 
|  | 7252 | if (!ips_allocatescbs(ha)) { | 
|  | 7253 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7254 | "Unable to allocate CCBs\n"); | 
| Jeff Garzik | 8a694cc | 2007-12-13 16:14:07 -0800 | [diff] [blame] | 7255 | free_irq(ha->pcidev->irq, ha); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7256 | return ips_abort_init(ha, index); | 
|  | 7257 | } | 
|  | 7258 |  | 
|  | 7259 | return SUCCESS; | 
|  | 7260 | } | 
|  | 7261 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7262 | MODULE_LICENSE("GPL"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7263 | MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7264 | MODULE_VERSION(IPS_VER_STRING); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7265 |  | 
|  | 7266 |  | 
|  | 7267 | /* | 
|  | 7268 | * Overrides for Emacs so that we almost follow Linus's tabbing style. | 
|  | 7269 | * Emacs will notice this stuff at the end of the file and automatically | 
|  | 7270 | * adjust the settings for this buffer only.  This must remain at the end | 
|  | 7271 | * of the file. | 
|  | 7272 | * --------------------------------------------------------------------------- | 
|  | 7273 | * Local variables: | 
|  | 7274 | * c-indent-level: 2 | 
|  | 7275 | * c-brace-imaginary-offset: 0 | 
|  | 7276 | * c-brace-offset: -2 | 
|  | 7277 | * c-argdecl-indent: 2 | 
|  | 7278 | * c-label-offset: -2 | 
|  | 7279 | * c-continued-statement-offset: 2 | 
|  | 7280 | * c-continued-brace-offset: 0 | 
|  | 7281 | * indent-tabs-mode: nil | 
|  | 7282 | * tab-width: 8 | 
|  | 7283 | * End: | 
|  | 7284 | */ |