| 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 */ | 
|  | 136 | /* 7.10.xx  - Add highmem_io flag in SCSI Templete for 2.4 kernels           */ | 
|  | 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                             */ | 
|  | 140 | /*****************************************************************************/ | 
|  | 141 |  | 
|  | 142 | /* | 
|  | 143 | * Conditional Compilation directives for this driver: | 
|  | 144 | * | 
|  | 145 | * IPS_DEBUG            - Turn on debugging info | 
|  | 146 | * | 
|  | 147 | * Parameters: | 
|  | 148 | * | 
|  | 149 | * debug:<number>       - Set debug level to <number> | 
|  | 150 | *                        NOTE: only works when IPS_DEBUG compile directive is used. | 
|  | 151 | *       1              - Normal debug messages | 
|  | 152 | *       2              - Verbose debug messages | 
|  | 153 | *       11             - Method trace (non interrupt) | 
|  | 154 | *       12             - Method trace (includes interrupt) | 
|  | 155 | * | 
|  | 156 | * noi2o                - Don't use I2O Queues (ServeRAID 4 only) | 
|  | 157 | * nommap               - Don't use memory mapped I/O | 
|  | 158 | * ioctlsize            - Initial size of the IOCTL buffer | 
|  | 159 | */ | 
|  | 160 |  | 
|  | 161 | #include <asm/io.h> | 
|  | 162 | #include <asm/byteorder.h> | 
|  | 163 | #include <asm/page.h> | 
|  | 164 | #include <linux/stddef.h> | 
|  | 165 | #include <linux/version.h> | 
|  | 166 | #include <linux/string.h> | 
|  | 167 | #include <linux/errno.h> | 
|  | 168 | #include <linux/kernel.h> | 
|  | 169 | #include <linux/ioport.h> | 
|  | 170 | #include <linux/slab.h> | 
|  | 171 | #include <linux/delay.h> | 
|  | 172 | #include <linux/pci.h> | 
|  | 173 | #include <linux/proc_fs.h> | 
|  | 174 | #include <linux/reboot.h> | 
|  | 175 | #include <linux/interrupt.h> | 
|  | 176 |  | 
|  | 177 | #include <linux/blkdev.h> | 
|  | 178 | #include <linux/types.h> | 
|  | 179 |  | 
|  | 180 | #include <scsi/sg.h> | 
|  | 181 |  | 
|  | 182 | #include "scsi.h" | 
|  | 183 |  | 
|  | 184 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) | 
|  | 185 | #include "hosts.h" | 
|  | 186 | #else | 
|  | 187 | #include <scsi/scsi_host.h> | 
|  | 188 | #endif | 
|  | 189 |  | 
|  | 190 | #include "ips.h" | 
|  | 191 |  | 
|  | 192 | #include <linux/module.h> | 
|  | 193 |  | 
|  | 194 | #include <linux/stat.h> | 
|  | 195 | #include <linux/config.h> | 
|  | 196 |  | 
|  | 197 | #include <linux/spinlock.h> | 
|  | 198 | #include <linux/init.h> | 
|  | 199 |  | 
|  | 200 | #include <linux/smp.h> | 
|  | 201 |  | 
|  | 202 | #ifdef MODULE | 
|  | 203 | static char *ips = NULL; | 
|  | 204 | module_param(ips, charp, 0); | 
|  | 205 | #endif | 
|  | 206 |  | 
|  | 207 | /* | 
|  | 208 | * DRIVER_VER | 
|  | 209 | */ | 
|  | 210 | #define IPS_VERSION_HIGH        "7.10" | 
|  | 211 | #define IPS_VERSION_LOW         ".18 " | 
|  | 212 |  | 
|  | 213 | #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) | 
|  | 214 | #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" | 
|  | 215 | #endif | 
|  | 216 |  | 
|  | 217 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) | 
|  | 218 | #include <linux/blk.h> | 
|  | 219 | #include "sd.h" | 
|  | 220 | #define IPS_SG_ADDRESS(sg)       ((sg)->address) | 
|  | 221 | #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags) | 
|  | 222 | #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags) | 
|  | 223 | #ifndef __devexit_p | 
|  | 224 | #define __devexit_p(x) x | 
|  | 225 | #endif | 
|  | 226 | #else | 
|  | 227 | #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \ | 
|  | 228 | page_address((sg)->page)+(sg)->offset : NULL) | 
|  | 229 | #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0) | 
|  | 230 | #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0) | 
|  | 231 | #endif | 
|  | 232 |  | 
|  | 233 | #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \ | 
|  | be7db05 | 2005-04-17 15:26:13 -0500 | [diff] [blame] | 234 | DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | PCI_DMA_BIDIRECTIONAL : \ | 
|  | be7db05 | 2005-04-17 15:26:13 -0500 | [diff] [blame] | 236 | scb->scsi_cmd->sc_data_direction) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 237 |  | 
|  | 238 | #ifdef IPS_DEBUG | 
|  | 239 | #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); | 
|  | 240 | #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n"); | 
|  | 241 | #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v); | 
|  | 242 | #else | 
|  | 243 | #define METHOD_TRACE(s, i) | 
|  | 244 | #define DEBUG(i, s) | 
|  | 245 | #define DEBUG_VAR(i, s, v...) | 
|  | 246 | #endif | 
|  | 247 |  | 
|  | 248 | /* | 
|  | 249 | * Function prototypes | 
|  | 250 | */ | 
|  | 251 | static int ips_detect(Scsi_Host_Template *); | 
|  | 252 | static int ips_release(struct Scsi_Host *); | 
|  | 253 | static int ips_eh_abort(Scsi_Cmnd *); | 
|  | 254 | static int ips_eh_reset(Scsi_Cmnd *); | 
|  | 255 | static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); | 
|  | 256 | static const char *ips_info(struct Scsi_Host *); | 
|  | 257 | static irqreturn_t do_ipsintr(int, void *, struct pt_regs *); | 
|  | 258 | static int ips_hainit(ips_ha_t *); | 
|  | 259 | static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); | 
|  | 260 | static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); | 
|  | 261 | static int ips_send_cmd(ips_ha_t *, ips_scb_t *); | 
|  | 262 | static int ips_online(ips_ha_t *, ips_scb_t *); | 
|  | 263 | static int ips_inquiry(ips_ha_t *, ips_scb_t *); | 
|  | 264 | static int ips_rdcap(ips_ha_t *, ips_scb_t *); | 
|  | 265 | static int ips_msense(ips_ha_t *, ips_scb_t *); | 
|  | 266 | static int ips_reqsen(ips_ha_t *, ips_scb_t *); | 
|  | 267 | static int ips_deallocatescbs(ips_ha_t *, int); | 
|  | 268 | static int ips_allocatescbs(ips_ha_t *); | 
|  | 269 | static int ips_reset_copperhead(ips_ha_t *); | 
|  | 270 | static int ips_reset_copperhead_memio(ips_ha_t *); | 
|  | 271 | static int ips_reset_morpheus(ips_ha_t *); | 
|  | 272 | static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); | 
|  | 273 | static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); | 
|  | 274 | static int ips_issue_i2o(ips_ha_t *, ips_scb_t *); | 
|  | 275 | static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); | 
|  | 276 | static int ips_isintr_copperhead(ips_ha_t *); | 
|  | 277 | static int ips_isintr_copperhead_memio(ips_ha_t *); | 
|  | 278 | static int ips_isintr_morpheus(ips_ha_t *); | 
|  | 279 | static int ips_wait(ips_ha_t *, int, int); | 
|  | 280 | static int ips_write_driver_status(ips_ha_t *, int); | 
|  | 281 | static int ips_read_adapter_status(ips_ha_t *, int); | 
|  | 282 | static int ips_read_subsystem_parameters(ips_ha_t *, int); | 
|  | 283 | static int ips_read_config(ips_ha_t *, int); | 
|  | 284 | static int ips_clear_adapter(ips_ha_t *, int); | 
|  | 285 | static int ips_readwrite_page5(ips_ha_t *, int, int); | 
|  | 286 | static int ips_init_copperhead(ips_ha_t *); | 
|  | 287 | static int ips_init_copperhead_memio(ips_ha_t *); | 
|  | 288 | static int ips_init_morpheus(ips_ha_t *); | 
|  | 289 | static int ips_isinit_copperhead(ips_ha_t *); | 
|  | 290 | static int ips_isinit_copperhead_memio(ips_ha_t *); | 
|  | 291 | static int ips_isinit_morpheus(ips_ha_t *); | 
|  | 292 | static int ips_erase_bios(ips_ha_t *); | 
|  | 293 | static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 294 | static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 295 | static int ips_erase_bios_memio(ips_ha_t *); | 
|  | 296 | static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 297 | static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); | 
|  | 298 | static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 299 | static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 300 | static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 301 | static void ips_free_flash_copperhead(ips_ha_t * ha); | 
|  | 302 | static void ips_get_bios_version(ips_ha_t *, int); | 
|  | 303 | static void ips_identify_controller(ips_ha_t *); | 
|  | 304 | static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); | 
|  | 305 | static void ips_enable_int_copperhead(ips_ha_t *); | 
|  | 306 | static void ips_enable_int_copperhead_memio(ips_ha_t *); | 
|  | 307 | static void ips_enable_int_morpheus(ips_ha_t *); | 
|  | 308 | static int ips_intr_copperhead(ips_ha_t *); | 
|  | 309 | static int ips_intr_morpheus(ips_ha_t *); | 
|  | 310 | static void ips_next(ips_ha_t *, int); | 
|  | 311 | static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); | 
|  | 312 | static void ipsintr_done(ips_ha_t *, struct ips_scb *); | 
|  | 313 | static void ips_done(ips_ha_t *, ips_scb_t *); | 
|  | 314 | static void ips_free(ips_ha_t *); | 
|  | 315 | static void ips_init_scb(ips_ha_t *, ips_scb_t *); | 
|  | 316 | static void ips_freescb(ips_ha_t *, ips_scb_t *); | 
|  | 317 | static void ips_setup_funclist(ips_ha_t *); | 
|  | 318 | static void ips_statinit(ips_ha_t *); | 
|  | 319 | static void ips_statinit_memio(ips_ha_t *); | 
|  | 320 | static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t); | 
|  | 321 | static void ips_ffdc_reset(ips_ha_t *, int); | 
|  | 322 | static void ips_ffdc_time(ips_ha_t *); | 
|  | 323 | static uint32_t ips_statupd_copperhead(ips_ha_t *); | 
|  | 324 | static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); | 
|  | 325 | static uint32_t ips_statupd_morpheus(ips_ha_t *); | 
|  | 326 | static ips_scb_t *ips_getscb(ips_ha_t *); | 
|  | 327 | static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); | 
|  | 328 | static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); | 
|  | 329 | static void ips_putq_copp_tail(ips_copp_queue_t *, | 
|  | 330 | ips_copp_wait_item_t *); | 
|  | 331 | static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); | 
|  | 332 | static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); | 
|  | 333 | static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); | 
|  | 334 | static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); | 
|  | 335 | static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, | 
|  | 336 | ips_copp_wait_item_t *); | 
|  | 337 | static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); | 
|  | 338 |  | 
|  | 339 | static int ips_is_passthru(Scsi_Cmnd *); | 
|  | 340 | static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); | 
|  | 341 | static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); | 
|  | 342 | static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); | 
|  | 343 | static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, | 
|  | 344 | unsigned int count); | 
|  | 345 | static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count); | 
|  | 346 |  | 
|  | 347 | static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); | 
|  | 348 | static int ips_host_info(ips_ha_t *, char *, off_t, int); | 
|  | 349 | static void copy_mem_info(IPS_INFOSTR *, char *, int); | 
|  | 350 | static int copy_info(IPS_INFOSTR *, char *, ...); | 
|  | 351 | static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr); | 
|  | 352 | static void ips_version_check(ips_ha_t * ha, int intr); | 
|  | 353 | static int ips_abort_init(ips_ha_t * ha, int index); | 
|  | 354 | static int ips_init_phase2(int index); | 
|  | 355 |  | 
|  | 356 | static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr); | 
|  | 357 | static int ips_register_scsi(int index); | 
|  | 358 |  | 
|  | 359 | /* | 
|  | 360 | * global variables | 
|  | 361 | */ | 
|  | 362 | static const char ips_name[] = "ips"; | 
|  | 363 | static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];	/* Array of host controller structures */ | 
|  | 364 | static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS];	/* Array of HA structures */ | 
|  | 365 | static unsigned int ips_next_controller; | 
|  | 366 | static unsigned int ips_num_controllers; | 
|  | 367 | static unsigned int ips_released_controllers; | 
|  | 368 | static int ips_hotplug; | 
|  | 369 | static int ips_cmd_timeout = 60; | 
|  | 370 | static int ips_reset_timeout = 60 * 5; | 
|  | 371 | static int ips_force_memio = 1;		/* Always use Memory Mapped I/O    */ | 
|  | 372 | static int ips_force_i2o = 1;	/* Always use I2O command delivery */ | 
|  | 373 | static int ips_ioctlsize = IPS_IOCTL_SIZE;	/* Size of the ioctl buffer        */ | 
|  | 374 | static int ips_cd_boot;			/* Booting from Manager CD         */ | 
|  | 375 | static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */ | 
|  | 376 | static dma_addr_t ips_flashbusaddr; | 
|  | 377 | static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */ | 
|  | 378 | static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */ | 
|  | 379 | static Scsi_Host_Template ips_driver_template = { | 
|  | 380 | .detect			= ips_detect, | 
|  | 381 | .release		= ips_release, | 
|  | 382 | .info			= ips_info, | 
|  | 383 | .queuecommand		= ips_queue, | 
|  | 384 | .eh_abort_handler	= ips_eh_abort, | 
|  | 385 | .eh_host_reset_handler	= ips_eh_reset, | 
|  | 386 | .proc_name		= "ips", | 
|  | 387 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 
|  | 388 | .proc_info		= ips_proc_info, | 
|  | 389 | .slave_configure	= ips_slave_configure, | 
|  | 390 | #else | 
|  | 391 | .proc_info		= ips_proc24_info, | 
|  | 392 | .select_queue_depths	= ips_select_queue_depth, | 
|  | 393 | #endif | 
|  | 394 | .bios_param		= ips_biosparam, | 
|  | 395 | .this_id		= -1, | 
|  | 396 | .sg_tablesize		= IPS_MAX_SG, | 
|  | 397 | .cmd_per_lun		= 3, | 
|  | 398 | .use_clustering		= ENABLE_CLUSTERING, | 
|  | 399 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 
|  | 400 | .use_new_eh_code	= 1, | 
|  | 401 | #endif | 
|  | 402 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)  &&  LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 
|  | 403 | .highmem_io          = 1, | 
|  | 404 | #endif | 
|  | 405 | }; | 
|  | 406 |  | 
|  | 407 | static IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */ | 
|  | 408 |  | 
|  | 409 |  | 
|  | 410 | /* This table describes all ServeRAID Adapters */ | 
|  | 411 | static struct  pci_device_id  ips_pci_table[] = { | 
|  | 412 | { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, | 
|  | 413 | { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, | 
|  | 414 | { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, | 
|  | 415 | { 0, } | 
|  | 416 | }; | 
|  | 417 |  | 
|  | 418 | MODULE_DEVICE_TABLE( pci, ips_pci_table ); | 
|  | 419 |  | 
|  | 420 | static char ips_hot_plug_name[] = "ips"; | 
|  | 421 |  | 
|  | 422 | static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); | 
|  | 423 | static void __devexit ips_remove_device(struct pci_dev *pci_dev); | 
|  | 424 |  | 
|  | 425 | static struct pci_driver ips_pci_driver = { | 
|  | 426 | .name		= ips_hot_plug_name, | 
|  | 427 | .id_table	= ips_pci_table, | 
|  | 428 | .probe		= ips_insert_device, | 
|  | 429 | .remove		= __devexit_p(ips_remove_device), | 
|  | 430 | }; | 
|  | 431 |  | 
|  | 432 |  | 
|  | 433 | /* | 
|  | 434 | * Necessary forward function protoypes | 
|  | 435 | */ | 
|  | 436 | static int ips_halt(struct notifier_block *nb, ulong event, void *buf); | 
|  | 437 |  | 
|  | 438 | #define MAX_ADAPTER_NAME 15 | 
|  | 439 |  | 
|  | 440 | static char ips_adapter_name[][30] = { | 
|  | 441 | "ServeRAID", | 
|  | 442 | "ServeRAID II", | 
|  | 443 | "ServeRAID on motherboard", | 
|  | 444 | "ServeRAID on motherboard", | 
|  | 445 | "ServeRAID 3H", | 
|  | 446 | "ServeRAID 3L", | 
|  | 447 | "ServeRAID 4H", | 
|  | 448 | "ServeRAID 4M", | 
|  | 449 | "ServeRAID 4L", | 
|  | 450 | "ServeRAID 4Mx", | 
|  | 451 | "ServeRAID 4Lx", | 
|  | 452 | "ServeRAID 5i", | 
|  | 453 | "ServeRAID 5i", | 
|  | 454 | "ServeRAID 6M", | 
|  | 455 | "ServeRAID 6i", | 
|  | 456 | "ServeRAID 7t", | 
|  | 457 | "ServeRAID 7k", | 
|  | 458 | "ServeRAID 7M" | 
|  | 459 | }; | 
|  | 460 |  | 
|  | 461 | static struct notifier_block ips_notifier = { | 
|  | 462 | ips_halt, NULL, 0 | 
|  | 463 | }; | 
|  | 464 |  | 
|  | 465 | /* | 
|  | 466 | * Direction table | 
|  | 467 | */ | 
|  | 468 | static char ips_command_direction[] = { | 
|  | 469 | IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, | 
|  | 470 | IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, | 
|  | 471 | IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 472 | IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, | 
|  | 473 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT, | 
|  | 474 | IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, | 
|  | 475 | IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN, | 
|  | 476 | IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 477 | IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK, | 
|  | 478 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, | 
|  | 479 | IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, | 
|  | 480 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, | 
|  | 481 | IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, | 
|  | 482 | IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE, | 
|  | 483 | IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, | 
|  | 484 | IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, 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_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 487 | IPS_DATA_IN, 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 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 492 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 493 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 494 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 495 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 496 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 497 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 498 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 499 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 500 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 501 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 502 | IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE, | 
|  | 503 | IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT, | 
|  | 504 | IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE, | 
|  | 505 | IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, | 
|  | 506 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 507 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 508 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 509 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 510 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 511 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 512 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 513 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 514 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 515 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT, | 
|  | 516 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 517 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 518 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, | 
|  | 519 | IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK | 
|  | 520 | }; | 
|  | 521 |  | 
|  | 522 |  | 
|  | 523 | /****************************************************************************/ | 
|  | 524 | /*                                                                          */ | 
|  | 525 | /* Routine Name: ips_setup                                                  */ | 
|  | 526 | /*                                                                          */ | 
|  | 527 | /* Routine Description:                                                     */ | 
|  | 528 | /*                                                                          */ | 
|  | 529 | /*   setup parameters to the driver                                         */ | 
|  | 530 | /*                                                                          */ | 
|  | 531 | /****************************************************************************/ | 
|  | 532 | static int | 
|  | 533 | ips_setup(char *ips_str) | 
|  | 534 | { | 
|  | 535 |  | 
|  | 536 | int i; | 
|  | 537 | char *key; | 
|  | 538 | char *value; | 
|  | 539 | IPS_OPTION options[] = { | 
|  | 540 | {"noi2o", &ips_force_i2o, 0}, | 
|  | 541 | {"nommap", &ips_force_memio, 0}, | 
|  | 542 | {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, | 
|  | 543 | {"cdboot", &ips_cd_boot, 0}, | 
|  | 544 | {"maxcmds", &MaxLiteCmds, 32}, | 
|  | 545 | }; | 
|  | 546 |  | 
|  | 547 | /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */ | 
|  | 548 | /* Search for value */ | 
|  | 549 | while ((key = strsep(&ips_str, ",."))) { | 
|  | 550 | if (!*key) | 
|  | 551 | continue; | 
|  | 552 | value = strchr(key, ':'); | 
|  | 553 | if (value) | 
|  | 554 | *value++ = '\0'; | 
|  | 555 | /* | 
|  | 556 | * We now have key/value pairs. | 
|  | 557 | * Update the variables | 
|  | 558 | */ | 
|  | 559 | for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) { | 
|  | 560 | if (strnicmp | 
|  | 561 | (key, options[i].option_name, | 
|  | 562 | strlen(options[i].option_name)) == 0) { | 
|  | 563 | if (value) | 
|  | 564 | *options[i].option_flag = | 
|  | 565 | simple_strtoul(value, NULL, 0); | 
|  | 566 | else | 
|  | 567 | *options[i].option_flag = | 
|  | 568 | options[i].option_value; | 
|  | 569 | break; | 
|  | 570 | } | 
|  | 571 | } | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | return (1); | 
|  | 575 | } | 
|  | 576 |  | 
|  | 577 | __setup("ips=", ips_setup); | 
|  | 578 |  | 
|  | 579 | /****************************************************************************/ | 
|  | 580 | /*                                                                          */ | 
|  | 581 | /* Routine Name: ips_detect                                                 */ | 
|  | 582 | /*                                                                          */ | 
|  | 583 | /* Routine Description:                                                     */ | 
|  | 584 | /*                                                                          */ | 
|  | 585 | /*   Detect and initialize the driver                                       */ | 
|  | 586 | /*                                                                          */ | 
|  | 587 | /* NOTE: this routine is called under the io_request_lock spinlock          */ | 
|  | 588 | /*                                                                          */ | 
|  | 589 | /****************************************************************************/ | 
|  | 590 | static int | 
|  | 591 | ips_detect(Scsi_Host_Template * SHT) | 
|  | 592 | { | 
|  | 593 | int i; | 
|  | 594 |  | 
|  | 595 | METHOD_TRACE("ips_detect", 1); | 
|  | 596 |  | 
|  | 597 | #ifdef MODULE | 
|  | 598 | if (ips) | 
|  | 599 | ips_setup(ips); | 
|  | 600 | #endif | 
|  | 601 |  | 
|  | 602 | for (i = 0; i < ips_num_controllers; i++) { | 
|  | 603 | if (ips_register_scsi(i)) | 
|  | 604 | ips_free(ips_ha[i]); | 
|  | 605 | ips_released_controllers++; | 
|  | 606 | } | 
|  | 607 | ips_hotplug = 1; | 
|  | 608 | return (ips_num_controllers); | 
|  | 609 | } | 
|  | 610 |  | 
|  | 611 | /****************************************************************************/ | 
|  | 612 | /*   configure the function pointers to use the functions that will work    */ | 
|  | 613 | /*   with the found version of the adapter                                  */ | 
|  | 614 | /****************************************************************************/ | 
|  | 615 | static void | 
|  | 616 | ips_setup_funclist(ips_ha_t * ha) | 
|  | 617 | { | 
|  | 618 |  | 
|  | 619 | /* | 
|  | 620 | * Setup Functions | 
|  | 621 | */ | 
|  | 622 | if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) { | 
|  | 623 | /* morpheus / marco / sebring */ | 
|  | 624 | ha->func.isintr = ips_isintr_morpheus; | 
|  | 625 | ha->func.isinit = ips_isinit_morpheus; | 
|  | 626 | ha->func.issue = ips_issue_i2o_memio; | 
|  | 627 | ha->func.init = ips_init_morpheus; | 
|  | 628 | ha->func.statupd = ips_statupd_morpheus; | 
|  | 629 | ha->func.reset = ips_reset_morpheus; | 
|  | 630 | ha->func.intr = ips_intr_morpheus; | 
|  | 631 | ha->func.enableint = ips_enable_int_morpheus; | 
|  | 632 | } else if (IPS_USE_MEMIO(ha)) { | 
|  | 633 | /* copperhead w/MEMIO */ | 
|  | 634 | ha->func.isintr = ips_isintr_copperhead_memio; | 
|  | 635 | ha->func.isinit = ips_isinit_copperhead_memio; | 
|  | 636 | ha->func.init = ips_init_copperhead_memio; | 
|  | 637 | ha->func.statupd = ips_statupd_copperhead_memio; | 
|  | 638 | ha->func.statinit = ips_statinit_memio; | 
|  | 639 | ha->func.reset = ips_reset_copperhead_memio; | 
|  | 640 | ha->func.intr = ips_intr_copperhead; | 
|  | 641 | ha->func.erasebios = ips_erase_bios_memio; | 
|  | 642 | ha->func.programbios = ips_program_bios_memio; | 
|  | 643 | ha->func.verifybios = ips_verify_bios_memio; | 
|  | 644 | ha->func.enableint = ips_enable_int_copperhead_memio; | 
|  | 645 | if (IPS_USE_I2O_DELIVER(ha)) | 
|  | 646 | ha->func.issue = ips_issue_i2o_memio; | 
|  | 647 | else | 
|  | 648 | ha->func.issue = ips_issue_copperhead_memio; | 
|  | 649 | } else { | 
|  | 650 | /* copperhead */ | 
|  | 651 | ha->func.isintr = ips_isintr_copperhead; | 
|  | 652 | ha->func.isinit = ips_isinit_copperhead; | 
|  | 653 | ha->func.init = ips_init_copperhead; | 
|  | 654 | ha->func.statupd = ips_statupd_copperhead; | 
|  | 655 | ha->func.statinit = ips_statinit; | 
|  | 656 | ha->func.reset = ips_reset_copperhead; | 
|  | 657 | ha->func.intr = ips_intr_copperhead; | 
|  | 658 | ha->func.erasebios = ips_erase_bios; | 
|  | 659 | ha->func.programbios = ips_program_bios; | 
|  | 660 | ha->func.verifybios = ips_verify_bios; | 
|  | 661 | ha->func.enableint = ips_enable_int_copperhead; | 
|  | 662 |  | 
|  | 663 | if (IPS_USE_I2O_DELIVER(ha)) | 
|  | 664 | ha->func.issue = ips_issue_i2o; | 
|  | 665 | else | 
|  | 666 | ha->func.issue = ips_issue_copperhead; | 
|  | 667 | } | 
|  | 668 | } | 
|  | 669 |  | 
|  | 670 | /****************************************************************************/ | 
|  | 671 | /*                                                                          */ | 
|  | 672 | /* Routine Name: ips_release                                                */ | 
|  | 673 | /*                                                                          */ | 
|  | 674 | /* Routine Description:                                                     */ | 
|  | 675 | /*                                                                          */ | 
|  | 676 | /*   Remove a driver                                                        */ | 
|  | 677 | /*                                                                          */ | 
|  | 678 | /****************************************************************************/ | 
|  | 679 | static int | 
|  | 680 | ips_release(struct Scsi_Host *sh) | 
|  | 681 | { | 
|  | 682 | ips_scb_t *scb; | 
|  | 683 | ips_ha_t *ha; | 
|  | 684 | int i; | 
|  | 685 |  | 
|  | 686 | METHOD_TRACE("ips_release", 1); | 
|  | 687 |  | 
|  | 688 | for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ; | 
|  | 689 |  | 
|  | 690 | if (i == IPS_MAX_ADAPTERS) { | 
|  | 691 | printk(KERN_WARNING | 
|  | 692 | "(%s) release, invalid Scsi_Host pointer.\n", ips_name); | 
|  | 693 | BUG(); | 
|  | 694 | return (FALSE); | 
|  | 695 | } | 
|  | 696 |  | 
|  | 697 | ha = IPS_HA(sh); | 
|  | 698 |  | 
|  | 699 | if (!ha) | 
|  | 700 | return (FALSE); | 
|  | 701 |  | 
|  | 702 | /* flush the cache on the controller */ | 
|  | 703 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 704 |  | 
|  | 705 | ips_init_scb(ha, scb); | 
|  | 706 |  | 
|  | 707 | scb->timeout = ips_cmd_timeout; | 
|  | 708 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 709 |  | 
|  | 710 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 711 | scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 712 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 713 | scb->cmd.flush_cache.reserved = 0; | 
|  | 714 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 715 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 716 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 717 |  | 
|  | 718 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); | 
|  | 719 |  | 
|  | 720 | /* send command */ | 
|  | 721 | if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) | 
|  | 722 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n"); | 
|  | 723 |  | 
|  | 724 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); | 
|  | 725 |  | 
|  | 726 | ips_sh[i] = NULL; | 
|  | 727 | ips_ha[i] = NULL; | 
|  | 728 |  | 
|  | 729 | /* free extra memory */ | 
|  | 730 | ips_free(ha); | 
|  | 731 |  | 
|  | 732 | /* Free I/O Region */ | 
|  | 733 | if (ha->io_addr) | 
|  | 734 | release_region(ha->io_addr, ha->io_len); | 
|  | 735 |  | 
|  | 736 | /* free IRQ */ | 
|  | 737 | free_irq(ha->irq, ha); | 
|  | 738 |  | 
|  | 739 | IPS_REMOVE_HOST(sh); | 
|  | 740 | scsi_host_put(sh); | 
|  | 741 |  | 
|  | 742 | ips_released_controllers++; | 
|  | 743 |  | 
|  | 744 | return (FALSE); | 
|  | 745 | } | 
|  | 746 |  | 
|  | 747 | /****************************************************************************/ | 
|  | 748 | /*                                                                          */ | 
|  | 749 | /* Routine Name: ips_halt                                                   */ | 
|  | 750 | /*                                                                          */ | 
|  | 751 | /* Routine Description:                                                     */ | 
|  | 752 | /*                                                                          */ | 
|  | 753 | /*   Perform cleanup when the system reboots                                */ | 
|  | 754 | /*                                                                          */ | 
|  | 755 | /****************************************************************************/ | 
|  | 756 | static int | 
|  | 757 | ips_halt(struct notifier_block *nb, ulong event, void *buf) | 
|  | 758 | { | 
|  | 759 | ips_scb_t *scb; | 
|  | 760 | ips_ha_t *ha; | 
|  | 761 | int i; | 
|  | 762 |  | 
|  | 763 | if ((event != SYS_RESTART) && (event != SYS_HALT) && | 
|  | 764 | (event != SYS_POWER_OFF)) | 
|  | 765 | return (NOTIFY_DONE); | 
|  | 766 |  | 
|  | 767 | for (i = 0; i < ips_next_controller; i++) { | 
|  | 768 | ha = (ips_ha_t *) ips_ha[i]; | 
|  | 769 |  | 
|  | 770 | if (!ha) | 
|  | 771 | continue; | 
|  | 772 |  | 
|  | 773 | if (!ha->active) | 
|  | 774 | continue; | 
|  | 775 |  | 
|  | 776 | /* flush the cache on the controller */ | 
|  | 777 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 778 |  | 
|  | 779 | ips_init_scb(ha, scb); | 
|  | 780 |  | 
|  | 781 | scb->timeout = ips_cmd_timeout; | 
|  | 782 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 783 |  | 
|  | 784 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 785 | scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 786 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 787 | scb->cmd.flush_cache.reserved = 0; | 
|  | 788 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 789 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 790 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 791 |  | 
|  | 792 | IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); | 
|  | 793 |  | 
|  | 794 | /* send command */ | 
|  | 795 | if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == | 
|  | 796 | IPS_FAILURE) | 
|  | 797 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 798 | "Incomplete Flush.\n"); | 
|  | 799 | else | 
|  | 800 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 801 | "Flushing Complete.\n"); | 
|  | 802 | } | 
|  | 803 |  | 
|  | 804 | return (NOTIFY_OK); | 
|  | 805 | } | 
|  | 806 |  | 
|  | 807 | /****************************************************************************/ | 
|  | 808 | /*                                                                          */ | 
|  | 809 | /* Routine Name: ips_eh_abort                                               */ | 
|  | 810 | /*                                                                          */ | 
|  | 811 | /* Routine Description:                                                     */ | 
|  | 812 | /*                                                                          */ | 
|  | 813 | /*   Abort a command (using the new error code stuff)                       */ | 
|  | 814 | /* Note: this routine is called under the io_request_lock                   */ | 
|  | 815 | /****************************************************************************/ | 
|  | 816 | int | 
|  | 817 | ips_eh_abort(Scsi_Cmnd * SC) | 
|  | 818 | { | 
|  | 819 | ips_ha_t *ha; | 
|  | 820 | ips_copp_wait_item_t *item; | 
|  | 821 | int ret; | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 822 | unsigned long cpu_flags; | 
|  | 823 | struct Scsi_Host *host; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 824 |  | 
|  | 825 | METHOD_TRACE("ips_eh_abort", 1); | 
|  | 826 |  | 
|  | 827 | if (!SC) | 
|  | 828 | return (FAILED); | 
|  | 829 |  | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 830 | host = SC->device->host; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 831 | ha = (ips_ha_t *) SC->device->host->hostdata; | 
|  | 832 |  | 
|  | 833 | if (!ha) | 
|  | 834 | return (FAILED); | 
|  | 835 |  | 
|  | 836 | if (!ha->active) | 
|  | 837 | return (FAILED); | 
|  | 838 |  | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 839 | IPS_LOCK_SAVE(host->host_lock, cpu_flags); | 
|  | 840 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 841 | /* See if the command is on the copp queue */ | 
|  | 842 | item = ha->copp_waitlist.head; | 
|  | 843 | while ((item) && (item->scsi_cmd != SC)) | 
|  | 844 | item = item->next; | 
|  | 845 |  | 
|  | 846 | if (item) { | 
|  | 847 | /* Found it */ | 
|  | 848 | ips_removeq_copp(&ha->copp_waitlist, item); | 
|  | 849 | ret = (SUCCESS); | 
|  | 850 |  | 
|  | 851 | /* See if the command is on the wait queue */ | 
|  | 852 | } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) { | 
|  | 853 | /* command not sent yet */ | 
|  | 854 | ret = (SUCCESS); | 
|  | 855 | } else { | 
|  | 856 | /* command must have already been sent */ | 
|  | 857 | ret = (FAILED); | 
|  | 858 | } | 
| Jeff Garzik | 8fa728a | 2005-05-28 07:54:40 -0400 | [diff] [blame] | 859 |  | 
|  | 860 | IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 861 | return ret; | 
|  | 862 | } | 
|  | 863 |  | 
|  | 864 | /****************************************************************************/ | 
|  | 865 | /*                                                                          */ | 
|  | 866 | /* Routine Name: ips_eh_reset                                               */ | 
|  | 867 | /*                                                                          */ | 
|  | 868 | /* Routine Description:                                                     */ | 
|  | 869 | /*                                                                          */ | 
|  | 870 | /*   Reset the controller (with new eh error code)                          */ | 
|  | 871 | /*                                                                          */ | 
|  | 872 | /* NOTE: this routine is called under the io_request_lock spinlock          */ | 
|  | 873 | /*                                                                          */ | 
|  | 874 | /****************************************************************************/ | 
|  | 875 | static int | 
| Jeff Garzik | df0ae24 | 2005-05-28 07:57:14 -0400 | [diff] [blame] | 876 | __ips_eh_reset(Scsi_Cmnd * SC) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 877 | { | 
|  | 878 | int ret; | 
|  | 879 | int i; | 
|  | 880 | ips_ha_t *ha; | 
|  | 881 | ips_scb_t *scb; | 
|  | 882 | ips_copp_wait_item_t *item; | 
|  | 883 |  | 
|  | 884 | METHOD_TRACE("ips_eh_reset", 1); | 
|  | 885 |  | 
|  | 886 | #ifdef NO_IPS_RESET | 
|  | 887 | return (FAILED); | 
|  | 888 | #else | 
|  | 889 |  | 
|  | 890 | if (!SC) { | 
|  | 891 | DEBUG(1, "Reset called with NULL scsi command"); | 
|  | 892 |  | 
|  | 893 | return (FAILED); | 
|  | 894 | } | 
|  | 895 |  | 
|  | 896 | ha = (ips_ha_t *) SC->device->host->hostdata; | 
|  | 897 |  | 
|  | 898 | if (!ha) { | 
|  | 899 | DEBUG(1, "Reset called with NULL ha struct"); | 
|  | 900 |  | 
|  | 901 | return (FAILED); | 
|  | 902 | } | 
|  | 903 |  | 
|  | 904 | if (!ha->active) | 
|  | 905 | return (FAILED); | 
|  | 906 |  | 
|  | 907 | /* See if the command is on the copp queue */ | 
|  | 908 | item = ha->copp_waitlist.head; | 
|  | 909 | while ((item) && (item->scsi_cmd != SC)) | 
|  | 910 | item = item->next; | 
|  | 911 |  | 
|  | 912 | if (item) { | 
|  | 913 | /* Found it */ | 
|  | 914 | ips_removeq_copp(&ha->copp_waitlist, item); | 
|  | 915 | return (SUCCESS); | 
|  | 916 | } | 
|  | 917 |  | 
|  | 918 | /* See if the command is on the wait queue */ | 
|  | 919 | if (ips_removeq_wait(&ha->scb_waitlist, SC)) { | 
|  | 920 | /* command not sent yet */ | 
|  | 921 | return (SUCCESS); | 
|  | 922 | } | 
|  | 923 |  | 
|  | 924 | /* An explanation for the casual observer:                              */ | 
|  | 925 | /* Part of the function of a RAID controller is automatic error         */ | 
|  | 926 | /* detection and recovery.  As such, the only problem that physically   */ | 
|  | 927 | /* resetting an adapter will ever fix is when, for some reason,         */ | 
|  | 928 | /* the driver is not successfully communicating with the adapter.       */ | 
|  | 929 | /* Therefore, we will attempt to flush this adapter.  If that succeeds, */ | 
|  | 930 | /* then there's no real purpose in a physical reset. This will complete */ | 
|  | 931 | /* much faster and avoids any problems that might be caused by a        */ | 
|  | 932 | /* physical reset ( such as having to fail all the outstanding I/O's ). */ | 
|  | 933 |  | 
|  | 934 | if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */ | 
|  | 935 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 936 |  | 
|  | 937 | ips_init_scb(ha, scb); | 
|  | 938 |  | 
|  | 939 | scb->timeout = ips_cmd_timeout; | 
|  | 940 | scb->cdb[0] = IPS_CMD_FLUSH; | 
|  | 941 |  | 
|  | 942 | scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; | 
|  | 943 | scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 944 | scb->cmd.flush_cache.state = IPS_NORM_STATE; | 
|  | 945 | scb->cmd.flush_cache.reserved = 0; | 
|  | 946 | scb->cmd.flush_cache.reserved2 = 0; | 
|  | 947 | scb->cmd.flush_cache.reserved3 = 0; | 
|  | 948 | scb->cmd.flush_cache.reserved4 = 0; | 
|  | 949 |  | 
|  | 950 | /* Attempt the flush command */ | 
|  | 951 | ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL); | 
|  | 952 | if (ret == IPS_SUCCESS) { | 
|  | 953 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, | 
|  | 954 | "Reset Request - Flushed Cache\n"); | 
|  | 955 | return (SUCCESS); | 
|  | 956 | } | 
|  | 957 | } | 
|  | 958 |  | 
|  | 959 | /* Either we can't communicate with the adapter or it's an IOCTL request */ | 
|  | 960 | /* from a utility.  A physical reset is needed at this point.            */ | 
|  | 961 |  | 
|  | 962 | ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */ | 
|  | 963 |  | 
|  | 964 | /* | 
|  | 965 | * command must have already been sent | 
|  | 966 | * reset the controller | 
|  | 967 | */ | 
|  | 968 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n"); | 
|  | 969 | ret = (*ha->func.reset) (ha); | 
|  | 970 |  | 
|  | 971 | if (!ret) { | 
|  | 972 | Scsi_Cmnd *scsi_cmd; | 
|  | 973 |  | 
|  | 974 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, | 
|  | 975 | "Controller reset failed - controller now offline.\n"); | 
|  | 976 |  | 
|  | 977 | /* Now fail all of the active commands */ | 
|  | 978 | DEBUG_VAR(1, "(%s%d) Failing active commands", | 
|  | 979 | ips_name, ha->host_num); | 
|  | 980 |  | 
|  | 981 | while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { | 
|  | 982 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 983 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 984 | ips_freescb(ha, scb); | 
|  | 985 | } | 
|  | 986 |  | 
|  | 987 | /* Now fail all of the pending commands */ | 
|  | 988 | DEBUG_VAR(1, "(%s%d) Failing pending commands", | 
|  | 989 | ips_name, ha->host_num); | 
|  | 990 |  | 
|  | 991 | while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { | 
|  | 992 | scsi_cmd->result = DID_ERROR; | 
|  | 993 | scsi_cmd->scsi_done(scsi_cmd); | 
|  | 994 | } | 
|  | 995 |  | 
|  | 996 | ha->active = FALSE; | 
|  | 997 | return (FAILED); | 
|  | 998 | } | 
|  | 999 |  | 
|  | 1000 | if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { | 
|  | 1001 | Scsi_Cmnd *scsi_cmd; | 
|  | 1002 |  | 
|  | 1003 | IPS_PRINTK(KERN_NOTICE, ha->pcidev, | 
|  | 1004 | "Controller reset failed - controller now offline.\n"); | 
|  | 1005 |  | 
|  | 1006 | /* Now fail all of the active commands */ | 
|  | 1007 | DEBUG_VAR(1, "(%s%d) Failing active commands", | 
|  | 1008 | ips_name, ha->host_num); | 
|  | 1009 |  | 
|  | 1010 | while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { | 
|  | 1011 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 1012 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 1013 | ips_freescb(ha, scb); | 
|  | 1014 | } | 
|  | 1015 |  | 
|  | 1016 | /* Now fail all of the pending commands */ | 
|  | 1017 | DEBUG_VAR(1, "(%s%d) Failing pending commands", | 
|  | 1018 | ips_name, ha->host_num); | 
|  | 1019 |  | 
|  | 1020 | while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { | 
|  | 1021 | scsi_cmd->result = DID_ERROR << 16; | 
|  | 1022 | scsi_cmd->scsi_done(scsi_cmd); | 
|  | 1023 | } | 
|  | 1024 |  | 
|  | 1025 | ha->active = FALSE; | 
|  | 1026 | return (FAILED); | 
|  | 1027 | } | 
|  | 1028 |  | 
|  | 1029 | /* FFDC */ | 
|  | 1030 | if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) { | 
|  | 1031 | struct timeval tv; | 
|  | 1032 |  | 
|  | 1033 | do_gettimeofday(&tv); | 
|  | 1034 | ha->last_ffdc = tv.tv_sec; | 
|  | 1035 | ha->reset_count++; | 
|  | 1036 | ips_ffdc_reset(ha, IPS_INTR_IORL); | 
|  | 1037 | } | 
|  | 1038 |  | 
|  | 1039 | /* Now fail all of the active commands */ | 
|  | 1040 | DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); | 
|  | 1041 |  | 
|  | 1042 | while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { | 
|  | 1043 | scb->scsi_cmd->result = | 
|  | 1044 | (DID_RESET << 16) | (SUGGEST_RETRY << 24); | 
|  | 1045 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 1046 | ips_freescb(ha, scb); | 
|  | 1047 | } | 
|  | 1048 |  | 
|  | 1049 | /* Reset DCDB active command bits */ | 
|  | 1050 | for (i = 1; i < ha->nbus; i++) | 
|  | 1051 | ha->dcdb_active[i - 1] = 0; | 
|  | 1052 |  | 
|  | 1053 | /* Reset the number of active IOCTLs */ | 
|  | 1054 | ha->num_ioctl = 0; | 
|  | 1055 |  | 
|  | 1056 | ips_next(ha, IPS_INTR_IORL); | 
|  | 1057 |  | 
|  | 1058 | return (SUCCESS); | 
|  | 1059 | #endif				/* NO_IPS_RESET */ | 
|  | 1060 |  | 
|  | 1061 | } | 
|  | 1062 |  | 
| Jeff Garzik | df0ae24 | 2005-05-28 07:57:14 -0400 | [diff] [blame] | 1063 | static int | 
|  | 1064 | ips_eh_reset(Scsi_Cmnd * SC) | 
|  | 1065 | { | 
|  | 1066 | int rc; | 
|  | 1067 |  | 
|  | 1068 | spin_lock_irq(SC->device->host->host_lock); | 
|  | 1069 | rc = __ips_eh_reset(SC); | 
|  | 1070 | spin_unlock_irq(SC->device->host->host_lock); | 
|  | 1071 |  | 
|  | 1072 | return rc; | 
|  | 1073 | } | 
|  | 1074 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1075 | /****************************************************************************/ | 
|  | 1076 | /*                                                                          */ | 
|  | 1077 | /* Routine Name: ips_queue                                                  */ | 
|  | 1078 | /*                                                                          */ | 
|  | 1079 | /* Routine Description:                                                     */ | 
|  | 1080 | /*                                                                          */ | 
|  | 1081 | /*   Send a command to the controller                                       */ | 
|  | 1082 | /*                                                                          */ | 
|  | 1083 | /* NOTE:                                                                    */ | 
|  | 1084 | /*    Linux obtains io_request_lock before calling this function            */ | 
|  | 1085 | /*                                                                          */ | 
|  | 1086 | /****************************************************************************/ | 
|  | 1087 | static int | 
|  | 1088 | ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *)) | 
|  | 1089 | { | 
|  | 1090 | ips_ha_t *ha; | 
|  | 1091 | ips_passthru_t *pt; | 
|  | 1092 |  | 
|  | 1093 | METHOD_TRACE("ips_queue", 1); | 
|  | 1094 |  | 
|  | 1095 | ha = (ips_ha_t *) SC->device->host->hostdata; | 
|  | 1096 |  | 
|  | 1097 | if (!ha) | 
|  | 1098 | return (1); | 
|  | 1099 |  | 
|  | 1100 | if (!ha->active) | 
|  | 1101 | return (DID_ERROR); | 
|  | 1102 |  | 
|  | 1103 | if (ips_is_passthru(SC)) { | 
|  | 1104 | if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) { | 
|  | 1105 | SC->result = DID_BUS_BUSY << 16; | 
|  | 1106 | done(SC); | 
|  | 1107 |  | 
|  | 1108 | return (0); | 
|  | 1109 | } | 
|  | 1110 | } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) { | 
|  | 1111 | SC->result = DID_BUS_BUSY << 16; | 
|  | 1112 | done(SC); | 
|  | 1113 |  | 
|  | 1114 | return (0); | 
|  | 1115 | } | 
|  | 1116 |  | 
|  | 1117 | SC->scsi_done = done; | 
|  | 1118 |  | 
|  | 1119 | DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)", | 
|  | 1120 | ips_name, | 
|  | 1121 | ha->host_num, | 
|  | 1122 | SC->cmnd[0], | 
|  | 1123 | SC->device->channel, SC->device->id, SC->device->lun); | 
|  | 1124 |  | 
|  | 1125 | /* Check for command to initiator IDs */ | 
|  | 1126 | if ((SC->device->channel > 0) | 
|  | 1127 | && (SC->device->id == ha->ha_id[SC->device->channel])) { | 
|  | 1128 | SC->result = DID_NO_CONNECT << 16; | 
|  | 1129 | done(SC); | 
|  | 1130 |  | 
|  | 1131 | return (0); | 
|  | 1132 | } | 
|  | 1133 |  | 
|  | 1134 | if (ips_is_passthru(SC)) { | 
|  | 1135 |  | 
|  | 1136 | ips_copp_wait_item_t *scratch; | 
|  | 1137 |  | 
|  | 1138 | /* A Reset IOCTL is only sent by the boot CD in extreme cases.           */ | 
|  | 1139 | /* There can never be any system activity ( network or disk ), but check */ | 
|  | 1140 | /* anyway just as a good practice.                                       */ | 
|  | 1141 | pt = (ips_passthru_t *) SC->request_buffer; | 
|  | 1142 | if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) && | 
|  | 1143 | (pt->CoppCP.cmd.reset.adapter_flag == 1)) { | 
|  | 1144 | if (ha->scb_activelist.count != 0) { | 
|  | 1145 | SC->result = DID_BUS_BUSY << 16; | 
|  | 1146 | done(SC); | 
|  | 1147 | return (0); | 
|  | 1148 | } | 
|  | 1149 | ha->ioctl_reset = 1;	/* This reset request is from an IOCTL */ | 
|  | 1150 | ips_eh_reset(SC); | 
|  | 1151 | SC->result = DID_OK << 16; | 
|  | 1152 | SC->scsi_done(SC); | 
|  | 1153 | return (0); | 
|  | 1154 | } | 
|  | 1155 |  | 
|  | 1156 | /* allocate space for the scribble */ | 
|  | 1157 | scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC); | 
|  | 1158 |  | 
|  | 1159 | if (!scratch) { | 
|  | 1160 | SC->result = DID_ERROR << 16; | 
|  | 1161 | done(SC); | 
|  | 1162 |  | 
|  | 1163 | return (0); | 
|  | 1164 | } | 
|  | 1165 |  | 
|  | 1166 | scratch->scsi_cmd = SC; | 
|  | 1167 | scratch->next = NULL; | 
|  | 1168 |  | 
|  | 1169 | ips_putq_copp_tail(&ha->copp_waitlist, scratch); | 
|  | 1170 | } else { | 
|  | 1171 | ips_putq_wait_tail(&ha->scb_waitlist, SC); | 
|  | 1172 | } | 
|  | 1173 |  | 
|  | 1174 | ips_next(ha, IPS_INTR_IORL); | 
|  | 1175 |  | 
|  | 1176 | return (0); | 
|  | 1177 | } | 
|  | 1178 |  | 
|  | 1179 | /****************************************************************************/ | 
|  | 1180 | /*                                                                          */ | 
|  | 1181 | /* Routine Name: ips_biosparam                                              */ | 
|  | 1182 | /*                                                                          */ | 
|  | 1183 | /* Routine Description:                                                     */ | 
|  | 1184 | /*                                                                          */ | 
|  | 1185 | /*   Set bios geometry for the controller                                   */ | 
|  | 1186 | /*                                                                          */ | 
|  | 1187 | /****************************************************************************/ | 
|  | 1188 | static int | 
|  | 1189 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 
|  | 1190 | ips_biosparam(Disk * disk, kdev_t dev, int geom[]) | 
|  | 1191 | { | 
|  | 1192 | ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata; | 
|  | 1193 | unsigned long capacity = disk->capacity; | 
|  | 1194 | #else | 
|  | 1195 | ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, | 
|  | 1196 | sector_t capacity, int geom[]) | 
|  | 1197 | { | 
|  | 1198 | ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; | 
|  | 1199 | #endif | 
|  | 1200 | int heads; | 
|  | 1201 | int sectors; | 
|  | 1202 | int cylinders; | 
|  | 1203 |  | 
|  | 1204 | METHOD_TRACE("ips_biosparam", 1); | 
|  | 1205 |  | 
|  | 1206 | if (!ha) | 
|  | 1207 | /* ?!?! host adater info invalid */ | 
|  | 1208 | return (0); | 
|  | 1209 |  | 
|  | 1210 | if (!ha->active) | 
|  | 1211 | return (0); | 
|  | 1212 |  | 
|  | 1213 | if (!ips_read_adapter_status(ha, IPS_INTR_ON)) | 
|  | 1214 | /* ?!?! Enquiry command failed */ | 
|  | 1215 | return (0); | 
|  | 1216 |  | 
|  | 1217 | if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) { | 
|  | 1218 | heads = IPS_NORM_HEADS; | 
|  | 1219 | sectors = IPS_NORM_SECTORS; | 
|  | 1220 | } else { | 
|  | 1221 | heads = IPS_COMP_HEADS; | 
|  | 1222 | sectors = IPS_COMP_SECTORS; | 
|  | 1223 | } | 
|  | 1224 |  | 
|  | 1225 | cylinders = (unsigned long) capacity / (heads * sectors); | 
|  | 1226 |  | 
|  | 1227 | DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d", | 
|  | 1228 | heads, sectors, cylinders); | 
|  | 1229 |  | 
|  | 1230 | geom[0] = heads; | 
|  | 1231 | geom[1] = sectors; | 
|  | 1232 | geom[2] = cylinders; | 
|  | 1233 |  | 
|  | 1234 | return (0); | 
|  | 1235 | } | 
|  | 1236 |  | 
|  | 1237 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 
|  | 1238 |  | 
|  | 1239 | /* ips_proc24_info is a wrapper around ips_proc_info * | 
|  | 1240 | * for compatibility with the 2.4 scsi parameters    */ | 
|  | 1241 | static int | 
|  | 1242 | ips_proc24_info(char *buffer, char **start, off_t offset, int length, | 
|  | 1243 | int hostno, int func) | 
|  | 1244 | { | 
|  | 1245 | int i; | 
|  | 1246 |  | 
|  | 1247 | for (i = 0; i < ips_next_controller; i++) { | 
|  | 1248 | if (ips_sh[i] && ips_sh[i]->host_no == hostno) { | 
|  | 1249 | return ips_proc_info(ips_sh[i], buffer, start, | 
|  | 1250 | offset, length, func); | 
|  | 1251 | } | 
|  | 1252 | } | 
|  | 1253 | return -EINVAL; | 
|  | 1254 | } | 
|  | 1255 |  | 
|  | 1256 | /****************************************************************************/ | 
|  | 1257 | /*                                                                          */ | 
|  | 1258 | /* Routine Name: ips_select_queue_depth                                     */ | 
|  | 1259 | /*                                                                          */ | 
|  | 1260 | /* Routine Description:                                                     */ | 
|  | 1261 | /*                                                                          */ | 
|  | 1262 | /*   Select queue depths for the devices on the contoller                   */ | 
|  | 1263 | /*                                                                          */ | 
|  | 1264 | /****************************************************************************/ | 
|  | 1265 | static void | 
|  | 1266 | ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs) | 
|  | 1267 | { | 
|  | 1268 | Scsi_Device *device; | 
|  | 1269 | ips_ha_t *ha; | 
|  | 1270 | int count = 0; | 
|  | 1271 | int min; | 
|  | 1272 |  | 
|  | 1273 | ha = IPS_HA(host); | 
|  | 1274 | min = ha->max_cmds / 4; | 
|  | 1275 |  | 
|  | 1276 | for (device = scsi_devs; device; device = device->next) { | 
|  | 1277 | if (device->host == host) { | 
|  | 1278 | if ((device->channel == 0) && (device->type == 0)) | 
|  | 1279 | count++; | 
|  | 1280 | } | 
|  | 1281 | } | 
|  | 1282 |  | 
|  | 1283 | for (device = scsi_devs; device; device = device->next) { | 
|  | 1284 | if (device->host == host) { | 
|  | 1285 | if ((device->channel == 0) && (device->type == 0)) { | 
|  | 1286 | device->queue_depth = | 
|  | 1287 | (ha->max_cmds - 1) / count; | 
|  | 1288 | if (device->queue_depth < min) | 
|  | 1289 | device->queue_depth = min; | 
|  | 1290 | } else { | 
|  | 1291 | device->queue_depth = 2; | 
|  | 1292 | } | 
|  | 1293 |  | 
|  | 1294 | if (device->queue_depth < 2) | 
|  | 1295 | device->queue_depth = 2; | 
|  | 1296 | } | 
|  | 1297 | } | 
|  | 1298 | } | 
|  | 1299 |  | 
|  | 1300 | #else | 
|  | 1301 | /****************************************************************************/ | 
|  | 1302 | /*                                                                          */ | 
|  | 1303 | /* Routine Name: ips_slave_configure                                        */ | 
|  | 1304 | /*                                                                          */ | 
|  | 1305 | /* Routine Description:                                                     */ | 
|  | 1306 | /*                                                                          */ | 
|  | 1307 | /*   Set queue depths on devices once scan is complete                      */ | 
|  | 1308 | /*                                                                          */ | 
|  | 1309 | /****************************************************************************/ | 
|  | 1310 | static int | 
|  | 1311 | ips_slave_configure(Scsi_Device * SDptr) | 
|  | 1312 | { | 
|  | 1313 | ips_ha_t *ha; | 
|  | 1314 | int min; | 
|  | 1315 |  | 
|  | 1316 | ha = IPS_HA(SDptr->host); | 
|  | 1317 | if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) { | 
|  | 1318 | min = ha->max_cmds / 2; | 
|  | 1319 | if (ha->enq->ucLogDriveCount <= 2) | 
|  | 1320 | min = ha->max_cmds - 1; | 
|  | 1321 | scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); | 
|  | 1322 | } | 
|  | 1323 | return 0; | 
|  | 1324 | } | 
|  | 1325 | #endif | 
|  | 1326 |  | 
|  | 1327 | /****************************************************************************/ | 
|  | 1328 | /*                                                                          */ | 
|  | 1329 | /* Routine Name: do_ipsintr                                                 */ | 
|  | 1330 | /*                                                                          */ | 
|  | 1331 | /* Routine Description:                                                     */ | 
|  | 1332 | /*                                                                          */ | 
|  | 1333 | /*   Wrapper for the interrupt handler                                      */ | 
|  | 1334 | /*                                                                          */ | 
|  | 1335 | /****************************************************************************/ | 
|  | 1336 | static irqreturn_t | 
|  | 1337 | do_ipsintr(int irq, void *dev_id, struct pt_regs * regs) | 
|  | 1338 | { | 
|  | 1339 | ips_ha_t *ha; | 
|  | 1340 | unsigned long cpu_flags; | 
|  | 1341 | struct Scsi_Host *host; | 
|  | 1342 | int irqstatus; | 
|  | 1343 |  | 
|  | 1344 | METHOD_TRACE("do_ipsintr", 2); | 
|  | 1345 |  | 
|  | 1346 | ha = (ips_ha_t *) dev_id; | 
|  | 1347 | if (!ha) | 
|  | 1348 | return IRQ_NONE; | 
|  | 1349 | host = ips_sh[ha->host_num]; | 
|  | 1350 | /* interrupt during initialization */ | 
|  | 1351 | if (!host) { | 
|  | 1352 | (*ha->func.intr) (ha); | 
|  | 1353 | return IRQ_HANDLED; | 
|  | 1354 | } | 
|  | 1355 |  | 
|  | 1356 | IPS_LOCK_SAVE(host->host_lock, cpu_flags); | 
|  | 1357 |  | 
|  | 1358 | if (!ha->active) { | 
|  | 1359 | IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); | 
|  | 1360 | return IRQ_HANDLED; | 
|  | 1361 | } | 
|  | 1362 |  | 
|  | 1363 | irqstatus = (*ha->func.intr) (ha); | 
|  | 1364 |  | 
|  | 1365 | IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); | 
|  | 1366 |  | 
|  | 1367 | /* start the next command */ | 
|  | 1368 | ips_next(ha, IPS_INTR_ON); | 
|  | 1369 | return IRQ_RETVAL(irqstatus); | 
|  | 1370 | } | 
|  | 1371 |  | 
|  | 1372 | /****************************************************************************/ | 
|  | 1373 | /*                                                                          */ | 
|  | 1374 | /* Routine Name: ips_intr_copperhead                                        */ | 
|  | 1375 | /*                                                                          */ | 
|  | 1376 | /* Routine Description:                                                     */ | 
|  | 1377 | /*                                                                          */ | 
|  | 1378 | /*   Polling interrupt handler                                              */ | 
|  | 1379 | /*                                                                          */ | 
|  | 1380 | /*   ASSUMES interrupts are disabled                                        */ | 
|  | 1381 | /*                                                                          */ | 
|  | 1382 | /****************************************************************************/ | 
|  | 1383 | int | 
|  | 1384 | ips_intr_copperhead(ips_ha_t * ha) | 
|  | 1385 | { | 
|  | 1386 | ips_stat_t *sp; | 
|  | 1387 | ips_scb_t *scb; | 
|  | 1388 | IPS_STATUS cstatus; | 
|  | 1389 | int intrstatus; | 
|  | 1390 |  | 
|  | 1391 | METHOD_TRACE("ips_intr", 2); | 
|  | 1392 |  | 
|  | 1393 | if (!ha) | 
|  | 1394 | return 0; | 
|  | 1395 |  | 
|  | 1396 | if (!ha->active) | 
|  | 1397 | return 0; | 
|  | 1398 |  | 
|  | 1399 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1400 |  | 
|  | 1401 | if (!intrstatus) { | 
|  | 1402 | /* | 
|  | 1403 | * Unexpected/Shared interrupt | 
|  | 1404 | */ | 
|  | 1405 |  | 
|  | 1406 | return 0; | 
|  | 1407 | } | 
|  | 1408 |  | 
|  | 1409 | while (TRUE) { | 
|  | 1410 | sp = &ha->sp; | 
|  | 1411 |  | 
|  | 1412 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1413 |  | 
|  | 1414 | if (!intrstatus) | 
|  | 1415 | break; | 
|  | 1416 | else | 
|  | 1417 | cstatus.value = (*ha->func.statupd) (ha); | 
|  | 1418 |  | 
|  | 1419 | if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { | 
|  | 1420 | /* Spurious Interupt ? */ | 
|  | 1421 | continue; | 
|  | 1422 | } | 
|  | 1423 |  | 
|  | 1424 | ips_chkstatus(ha, &cstatus); | 
|  | 1425 | scb = (ips_scb_t *) sp->scb_addr; | 
|  | 1426 |  | 
|  | 1427 | /* | 
|  | 1428 | * use the callback function to finish things up | 
|  | 1429 | * NOTE: interrupts are OFF for this | 
|  | 1430 | */ | 
|  | 1431 | (*scb->callback) (ha, scb); | 
|  | 1432 | }			/* end while */ | 
|  | 1433 | return 1; | 
|  | 1434 | } | 
|  | 1435 |  | 
|  | 1436 | /****************************************************************************/ | 
|  | 1437 | /*                                                                          */ | 
|  | 1438 | /* Routine Name: ips_intr_morpheus                                          */ | 
|  | 1439 | /*                                                                          */ | 
|  | 1440 | /* Routine Description:                                                     */ | 
|  | 1441 | /*                                                                          */ | 
|  | 1442 | /*   Polling interrupt handler                                              */ | 
|  | 1443 | /*                                                                          */ | 
|  | 1444 | /*   ASSUMES interrupts are disabled                                        */ | 
|  | 1445 | /*                                                                          */ | 
|  | 1446 | /****************************************************************************/ | 
|  | 1447 | int | 
|  | 1448 | ips_intr_morpheus(ips_ha_t * ha) | 
|  | 1449 | { | 
|  | 1450 | ips_stat_t *sp; | 
|  | 1451 | ips_scb_t *scb; | 
|  | 1452 | IPS_STATUS cstatus; | 
|  | 1453 | int intrstatus; | 
|  | 1454 |  | 
|  | 1455 | METHOD_TRACE("ips_intr_morpheus", 2); | 
|  | 1456 |  | 
|  | 1457 | if (!ha) | 
|  | 1458 | return 0; | 
|  | 1459 |  | 
|  | 1460 | if (!ha->active) | 
|  | 1461 | return 0; | 
|  | 1462 |  | 
|  | 1463 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1464 |  | 
|  | 1465 | if (!intrstatus) { | 
|  | 1466 | /* | 
|  | 1467 | * Unexpected/Shared interrupt | 
|  | 1468 | */ | 
|  | 1469 |  | 
|  | 1470 | return 0; | 
|  | 1471 | } | 
|  | 1472 |  | 
|  | 1473 | while (TRUE) { | 
|  | 1474 | sp = &ha->sp; | 
|  | 1475 |  | 
|  | 1476 | intrstatus = (*ha->func.isintr) (ha); | 
|  | 1477 |  | 
|  | 1478 | if (!intrstatus) | 
|  | 1479 | break; | 
|  | 1480 | else | 
|  | 1481 | cstatus.value = (*ha->func.statupd) (ha); | 
|  | 1482 |  | 
|  | 1483 | if (cstatus.value == 0xffffffff) | 
|  | 1484 | /* No more to process */ | 
|  | 1485 | break; | 
|  | 1486 |  | 
|  | 1487 | if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { | 
|  | 1488 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 1489 | "Spurious interrupt; no ccb.\n"); | 
|  | 1490 |  | 
|  | 1491 | continue; | 
|  | 1492 | } | 
|  | 1493 |  | 
|  | 1494 | ips_chkstatus(ha, &cstatus); | 
|  | 1495 | scb = (ips_scb_t *) sp->scb_addr; | 
|  | 1496 |  | 
|  | 1497 | /* | 
|  | 1498 | * use the callback function to finish things up | 
|  | 1499 | * NOTE: interrupts are OFF for this | 
|  | 1500 | */ | 
|  | 1501 | (*scb->callback) (ha, scb); | 
|  | 1502 | }			/* end while */ | 
|  | 1503 | return 1; | 
|  | 1504 | } | 
|  | 1505 |  | 
|  | 1506 | /****************************************************************************/ | 
|  | 1507 | /*                                                                          */ | 
|  | 1508 | /* Routine Name: ips_info                                                   */ | 
|  | 1509 | /*                                                                          */ | 
|  | 1510 | /* Routine Description:                                                     */ | 
|  | 1511 | /*                                                                          */ | 
|  | 1512 | /*   Return info about the driver                                           */ | 
|  | 1513 | /*                                                                          */ | 
|  | 1514 | /****************************************************************************/ | 
|  | 1515 | static const char * | 
|  | 1516 | ips_info(struct Scsi_Host *SH) | 
|  | 1517 | { | 
|  | 1518 | static char buffer[256]; | 
|  | 1519 | char *bp; | 
|  | 1520 | ips_ha_t *ha; | 
|  | 1521 |  | 
|  | 1522 | METHOD_TRACE("ips_info", 1); | 
|  | 1523 |  | 
|  | 1524 | ha = IPS_HA(SH); | 
|  | 1525 |  | 
|  | 1526 | if (!ha) | 
|  | 1527 | return (NULL); | 
|  | 1528 |  | 
|  | 1529 | bp = &buffer[0]; | 
|  | 1530 | memset(bp, 0, sizeof (buffer)); | 
|  | 1531 |  | 
|  | 1532 | sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ", | 
|  | 1533 | IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT); | 
|  | 1534 |  | 
|  | 1535 | if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) { | 
|  | 1536 | strcat(bp, " <"); | 
|  | 1537 | strcat(bp, ips_adapter_name[ha->ad_type - 1]); | 
|  | 1538 | strcat(bp, ">"); | 
|  | 1539 | } | 
|  | 1540 |  | 
|  | 1541 | return (bp); | 
|  | 1542 | } | 
|  | 1543 |  | 
|  | 1544 | /****************************************************************************/ | 
|  | 1545 | /*                                                                          */ | 
|  | 1546 | /* Routine Name: ips_proc_info                                              */ | 
|  | 1547 | /*                                                                          */ | 
|  | 1548 | /* Routine Description:                                                     */ | 
|  | 1549 | /*                                                                          */ | 
|  | 1550 | /*   The passthru interface for the driver                                  */ | 
|  | 1551 | /*                                                                          */ | 
|  | 1552 | /****************************************************************************/ | 
|  | 1553 | static int | 
|  | 1554 | ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, | 
|  | 1555 | int length, int func) | 
|  | 1556 | { | 
|  | 1557 | int i; | 
|  | 1558 | int ret; | 
|  | 1559 | ips_ha_t *ha = NULL; | 
|  | 1560 |  | 
|  | 1561 | METHOD_TRACE("ips_proc_info", 1); | 
|  | 1562 |  | 
|  | 1563 | /* Find our host structure */ | 
|  | 1564 | for (i = 0; i < ips_next_controller; i++) { | 
|  | 1565 | if (ips_sh[i]) { | 
|  | 1566 | if (ips_sh[i] == host) { | 
|  | 1567 | ha = (ips_ha_t *) ips_sh[i]->hostdata; | 
|  | 1568 | break; | 
|  | 1569 | } | 
|  | 1570 | } | 
|  | 1571 | } | 
|  | 1572 |  | 
|  | 1573 | if (!ha) | 
|  | 1574 | return (-EINVAL); | 
|  | 1575 |  | 
|  | 1576 | if (func) { | 
|  | 1577 | /* write */ | 
|  | 1578 | return (0); | 
|  | 1579 | } else { | 
|  | 1580 | /* read */ | 
|  | 1581 | if (start) | 
|  | 1582 | *start = buffer; | 
|  | 1583 |  | 
|  | 1584 | ret = ips_host_info(ha, buffer, offset, length); | 
|  | 1585 |  | 
|  | 1586 | return (ret); | 
|  | 1587 | } | 
|  | 1588 | } | 
|  | 1589 |  | 
|  | 1590 | /*--------------------------------------------------------------------------*/ | 
|  | 1591 | /* Helper Functions                                                         */ | 
|  | 1592 | /*--------------------------------------------------------------------------*/ | 
|  | 1593 |  | 
|  | 1594 | /****************************************************************************/ | 
|  | 1595 | /*                                                                          */ | 
|  | 1596 | /* Routine Name: ips_is_passthru                                            */ | 
|  | 1597 | /*                                                                          */ | 
|  | 1598 | /* Routine Description:                                                     */ | 
|  | 1599 | /*                                                                          */ | 
|  | 1600 | /*   Determine if the specified SCSI command is really a passthru command   */ | 
|  | 1601 | /*                                                                          */ | 
|  | 1602 | /****************************************************************************/ | 
|  | 1603 | static int | 
|  | 1604 | ips_is_passthru(Scsi_Cmnd * SC) | 
|  | 1605 | { | 
|  | 1606 | METHOD_TRACE("ips_is_passthru", 1); | 
|  | 1607 |  | 
|  | 1608 | if (!SC) | 
|  | 1609 | return (0); | 
|  | 1610 |  | 
|  | 1611 | if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) && | 
|  | 1612 | (SC->device->channel == 0) && | 
|  | 1613 | (SC->device->id == IPS_ADAPTER_ID) && | 
|  | 1614 | (SC->device->lun == 0) && SC->request_buffer) { | 
|  | 1615 | if ((!SC->use_sg) && SC->request_bufflen && | 
|  | 1616 | (((char *) SC->request_buffer)[0] == 'C') && | 
|  | 1617 | (((char *) SC->request_buffer)[1] == 'O') && | 
|  | 1618 | (((char *) SC->request_buffer)[2] == 'P') && | 
|  | 1619 | (((char *) SC->request_buffer)[3] == 'P')) | 
|  | 1620 | return 1; | 
|  | 1621 | else if (SC->use_sg) { | 
|  | 1622 | struct scatterlist *sg = SC->request_buffer; | 
|  | 1623 | char *buffer = IPS_SG_ADDRESS(sg); | 
|  | 1624 | if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && | 
|  | 1625 | buffer[2] == 'P' && buffer[3] == 'P') | 
|  | 1626 | return 1; | 
|  | 1627 | } | 
|  | 1628 | } | 
|  | 1629 | return 0; | 
|  | 1630 | } | 
|  | 1631 |  | 
|  | 1632 | /****************************************************************************/ | 
|  | 1633 | /*                                                                          */ | 
|  | 1634 | /* Routine Name: ips_alloc_passthru_buffer                                  */ | 
|  | 1635 | /*                                                                          */ | 
|  | 1636 | /* Routine Description:                                                     */ | 
|  | 1637 | /*   allocate a buffer large enough for the ioctl data if the ioctl buffer  */ | 
|  | 1638 | /*   is too small or doesn't exist                                          */ | 
|  | 1639 | /****************************************************************************/ | 
|  | 1640 | static int | 
|  | 1641 | ips_alloc_passthru_buffer(ips_ha_t * ha, int length) | 
|  | 1642 | { | 
|  | 1643 | void *bigger_buf; | 
|  | 1644 | dma_addr_t dma_busaddr; | 
|  | 1645 |  | 
|  | 1646 | if (ha->ioctl_data && length <= ha->ioctl_len) | 
|  | 1647 | return 0; | 
|  | 1648 | /* there is no buffer or it's not big enough, allocate a new one */ | 
|  | 1649 | bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr); | 
|  | 1650 | if (bigger_buf) { | 
|  | 1651 | /* free the old memory */ | 
|  | 1652 | pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data, | 
|  | 1653 | ha->ioctl_busaddr); | 
|  | 1654 | /* use the new memory */ | 
|  | 1655 | ha->ioctl_data = (char *) bigger_buf; | 
|  | 1656 | ha->ioctl_len = length; | 
|  | 1657 | ha->ioctl_busaddr = dma_busaddr; | 
|  | 1658 | } else { | 
|  | 1659 | return -1; | 
|  | 1660 | } | 
|  | 1661 | return 0; | 
|  | 1662 | } | 
|  | 1663 |  | 
|  | 1664 | /****************************************************************************/ | 
|  | 1665 | /*                                                                          */ | 
|  | 1666 | /* Routine Name: ips_make_passthru                                          */ | 
|  | 1667 | /*                                                                          */ | 
|  | 1668 | /* Routine Description:                                                     */ | 
|  | 1669 | /*                                                                          */ | 
|  | 1670 | /*   Make a passthru command out of the info in the Scsi block              */ | 
|  | 1671 | /*                                                                          */ | 
|  | 1672 | /****************************************************************************/ | 
|  | 1673 | static int | 
|  | 1674 | ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr) | 
|  | 1675 | { | 
|  | 1676 | ips_passthru_t *pt; | 
|  | 1677 | int length = 0; | 
|  | 1678 | int ret; | 
|  | 1679 |  | 
|  | 1680 | METHOD_TRACE("ips_make_passthru", 1); | 
|  | 1681 |  | 
|  | 1682 | if (!SC->use_sg) { | 
|  | 1683 | length = SC->request_bufflen; | 
|  | 1684 | } else { | 
|  | 1685 | struct scatterlist *sg = SC->request_buffer; | 
|  | 1686 | int i; | 
|  | 1687 | for (i = 0; i < SC->use_sg; i++) | 
|  | 1688 | length += sg[i].length; | 
|  | 1689 | } | 
|  | 1690 | if (length < sizeof (ips_passthru_t)) { | 
|  | 1691 | /* wrong size */ | 
|  | 1692 | DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", | 
|  | 1693 | ips_name, ha->host_num); | 
|  | 1694 | return (IPS_FAILURE); | 
|  | 1695 | } | 
|  | 1696 | if (ips_alloc_passthru_buffer(ha, length)) { | 
|  | 1697 | /* allocation failure!  If ha->ioctl_data exists, use it to return | 
|  | 1698 | some error codes.  Return a failed command to the scsi layer. */ | 
|  | 1699 | if (ha->ioctl_data) { | 
|  | 1700 | pt = (ips_passthru_t *) ha->ioctl_data; | 
|  | 1701 | ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t)); | 
|  | 1702 | pt->BasicStatus = 0x0B; | 
|  | 1703 | pt->ExtendedStatus = 0x00; | 
|  | 1704 | ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t)); | 
|  | 1705 | } | 
|  | 1706 | return IPS_FAILURE; | 
|  | 1707 | } | 
|  | 1708 | ha->ioctl_datasize = length; | 
|  | 1709 |  | 
|  | 1710 | ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize); | 
|  | 1711 | pt = (ips_passthru_t *) ha->ioctl_data; | 
|  | 1712 |  | 
|  | 1713 | /* | 
|  | 1714 | * Some notes about the passthru interface used | 
|  | 1715 | * | 
|  | 1716 | * IF the scsi op_code == 0x0d then we assume | 
|  | 1717 | * that the data came along with/goes with the | 
|  | 1718 | * packet we received from the sg driver. In this | 
|  | 1719 | * case the CmdBSize field of the pt structure is | 
|  | 1720 | * used for the size of the buffer. | 
|  | 1721 | */ | 
|  | 1722 |  | 
|  | 1723 | switch (pt->CoppCmd) { | 
|  | 1724 | case IPS_NUMCTRLS: | 
|  | 1725 | memcpy(ha->ioctl_data + sizeof (ips_passthru_t), | 
|  | 1726 | &ips_num_controllers, sizeof (int)); | 
|  | 1727 | ips_scmd_buf_write(SC, ha->ioctl_data, | 
|  | 1728 | sizeof (ips_passthru_t) + sizeof (int)); | 
|  | 1729 | SC->result = DID_OK << 16; | 
|  | 1730 |  | 
|  | 1731 | return (IPS_SUCCESS_IMM); | 
|  | 1732 |  | 
|  | 1733 | case IPS_COPPUSRCMD: | 
|  | 1734 | case IPS_COPPIOCCMD: | 
|  | 1735 | if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { | 
|  | 1736 | if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) { | 
|  | 1737 | /* wrong size */ | 
|  | 1738 | DEBUG_VAR(1, | 
|  | 1739 | "(%s%d) Passthru structure wrong size", | 
|  | 1740 | ips_name, ha->host_num); | 
|  | 1741 |  | 
|  | 1742 | return (IPS_FAILURE); | 
|  | 1743 | } | 
|  | 1744 |  | 
|  | 1745 | if (ha->device_id == IPS_DEVICEID_COPPERHEAD && | 
|  | 1746 | pt->CoppCP.cmd.flashfw.op_code == | 
|  | 1747 | IPS_CMD_RW_BIOSFW) { | 
|  | 1748 | ret = ips_flash_copperhead(ha, pt, scb); | 
|  | 1749 | ips_scmd_buf_write(SC, ha->ioctl_data, | 
|  | 1750 | sizeof (ips_passthru_t)); | 
|  | 1751 | return ret; | 
|  | 1752 | } | 
|  | 1753 | if (ips_usrcmd(ha, pt, scb)) | 
|  | 1754 | return (IPS_SUCCESS); | 
|  | 1755 | else | 
|  | 1756 | return (IPS_FAILURE); | 
|  | 1757 | } | 
|  | 1758 |  | 
|  | 1759 | break; | 
|  | 1760 |  | 
|  | 1761 | }			/* end switch */ | 
|  | 1762 |  | 
|  | 1763 | return (IPS_FAILURE); | 
|  | 1764 | } | 
|  | 1765 |  | 
|  | 1766 | /****************************************************************************/ | 
|  | 1767 | /* Routine Name: ips_flash_copperhead                                       */ | 
|  | 1768 | /* Routine Description:                                                     */ | 
|  | 1769 | /*   Flash the BIOS/FW on a Copperhead style controller                     */ | 
|  | 1770 | /****************************************************************************/ | 
|  | 1771 | static int | 
|  | 1772 | ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1773 | { | 
|  | 1774 | int datasize; | 
|  | 1775 |  | 
|  | 1776 | /* Trombone is the only copperhead that can do packet flash, but only | 
|  | 1777 | * for firmware. No one said it had to make sence. */ | 
|  | 1778 | if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { | 
|  | 1779 | if (ips_usrcmd(ha, pt, scb)) | 
|  | 1780 | return IPS_SUCCESS; | 
|  | 1781 | else | 
|  | 1782 | return IPS_FAILURE; | 
|  | 1783 | } | 
|  | 1784 | pt->BasicStatus = 0x0B; | 
|  | 1785 | pt->ExtendedStatus = 0; | 
|  | 1786 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 1787 | /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */ | 
|  | 1788 | /* avoid allocating a huge buffer per adapter ( which can fail ). */ | 
|  | 1789 | if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && | 
|  | 1790 | pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { | 
|  | 1791 | pt->BasicStatus = 0; | 
|  | 1792 | return ips_flash_bios(ha, pt, scb); | 
|  | 1793 | } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) { | 
|  | 1794 | if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){ | 
|  | 1795 | ha->flash_data = ips_FlashData; | 
|  | 1796 | ha->flash_busaddr = ips_flashbusaddr; | 
|  | 1797 | ha->flash_len = PAGE_SIZE << 7; | 
|  | 1798 | ha->flash_datasize = 0; | 
|  | 1799 | } else if (!ha->flash_data) { | 
|  | 1800 | datasize = pt->CoppCP.cmd.flashfw.total_packets * | 
|  | 1801 | pt->CoppCP.cmd.flashfw.count; | 
|  | 1802 | ha->flash_data = pci_alloc_consistent(ha->pcidev, | 
|  | 1803 | datasize, | 
|  | 1804 | &ha->flash_busaddr); | 
|  | 1805 | if (!ha->flash_data){ | 
|  | 1806 | printk(KERN_WARNING "Unable to allocate a flash buffer\n"); | 
|  | 1807 | return IPS_FAILURE; | 
|  | 1808 | } | 
|  | 1809 | ha->flash_datasize = 0; | 
|  | 1810 | ha->flash_len = datasize; | 
|  | 1811 | } else | 
|  | 1812 | return IPS_FAILURE; | 
|  | 1813 | } else { | 
|  | 1814 | if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize > | 
|  | 1815 | ha->flash_len) { | 
|  | 1816 | ips_free_flash_copperhead(ha); | 
|  | 1817 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 1818 | "failed size sanity check\n"); | 
|  | 1819 | return IPS_FAILURE; | 
|  | 1820 | } | 
|  | 1821 | } | 
|  | 1822 | if (!ha->flash_data) | 
|  | 1823 | return IPS_FAILURE; | 
|  | 1824 | pt->BasicStatus = 0; | 
|  | 1825 | memcpy(&ha->flash_data[ha->flash_datasize], pt + 1, | 
|  | 1826 | pt->CoppCP.cmd.flashfw.count); | 
|  | 1827 | ha->flash_datasize += pt->CoppCP.cmd.flashfw.count; | 
|  | 1828 | if (pt->CoppCP.cmd.flashfw.packet_num == | 
|  | 1829 | pt->CoppCP.cmd.flashfw.total_packets - 1) { | 
|  | 1830 | if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE) | 
|  | 1831 | return ips_flash_bios(ha, pt, scb); | 
|  | 1832 | else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) | 
|  | 1833 | return ips_flash_firmware(ha, pt, scb); | 
|  | 1834 | } | 
|  | 1835 | return IPS_SUCCESS_IMM; | 
|  | 1836 | } | 
|  | 1837 |  | 
|  | 1838 | /****************************************************************************/ | 
|  | 1839 | /* Routine Name: ips_flash_bios                                             */ | 
|  | 1840 | /* Routine Description:                                                     */ | 
|  | 1841 | /*   flashes the bios of a copperhead adapter                               */ | 
|  | 1842 | /****************************************************************************/ | 
|  | 1843 | static int | 
|  | 1844 | ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1845 | { | 
|  | 1846 |  | 
|  | 1847 | if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && | 
|  | 1848 | pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) { | 
|  | 1849 | if ((!ha->func.programbios) || (!ha->func.erasebios) || | 
|  | 1850 | (!ha->func.verifybios)) | 
|  | 1851 | goto error; | 
|  | 1852 | if ((*ha->func.erasebios) (ha)) { | 
|  | 1853 | DEBUG_VAR(1, | 
|  | 1854 | "(%s%d) flash bios failed - unable to erase flash", | 
|  | 1855 | ips_name, ha->host_num); | 
|  | 1856 | goto error; | 
|  | 1857 | } else | 
|  | 1858 | if ((*ha->func.programbios) (ha, | 
|  | 1859 | ha->flash_data + | 
|  | 1860 | IPS_BIOS_HEADER, | 
|  | 1861 | ha->flash_datasize - | 
|  | 1862 | IPS_BIOS_HEADER, 0)) { | 
|  | 1863 | DEBUG_VAR(1, | 
|  | 1864 | "(%s%d) flash bios failed - unable to flash", | 
|  | 1865 | ips_name, ha->host_num); | 
|  | 1866 | goto error; | 
|  | 1867 | } else | 
|  | 1868 | if ((*ha->func.verifybios) (ha, | 
|  | 1869 | ha->flash_data + | 
|  | 1870 | IPS_BIOS_HEADER, | 
|  | 1871 | ha->flash_datasize - | 
|  | 1872 | IPS_BIOS_HEADER, 0)) { | 
|  | 1873 | DEBUG_VAR(1, | 
|  | 1874 | "(%s%d) flash bios failed - unable to verify flash", | 
|  | 1875 | ips_name, ha->host_num); | 
|  | 1876 | goto error; | 
|  | 1877 | } | 
|  | 1878 | ips_free_flash_copperhead(ha); | 
|  | 1879 | return IPS_SUCCESS_IMM; | 
|  | 1880 | } else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && | 
|  | 1881 | pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { | 
|  | 1882 | if (!ha->func.erasebios) | 
|  | 1883 | goto error; | 
|  | 1884 | if ((*ha->func.erasebios) (ha)) { | 
|  | 1885 | DEBUG_VAR(1, | 
|  | 1886 | "(%s%d) flash bios failed - unable to erase flash", | 
|  | 1887 | ips_name, ha->host_num); | 
|  | 1888 | goto error; | 
|  | 1889 | } | 
|  | 1890 | return IPS_SUCCESS_IMM; | 
|  | 1891 | } | 
|  | 1892 | error: | 
|  | 1893 | pt->BasicStatus = 0x0B; | 
|  | 1894 | pt->ExtendedStatus = 0x00; | 
|  | 1895 | ips_free_flash_copperhead(ha); | 
|  | 1896 | return IPS_FAILURE; | 
|  | 1897 | } | 
|  | 1898 |  | 
|  | 1899 | /****************************************************************************/ | 
|  | 1900 | /*                                                                          */ | 
|  | 1901 | /* Routine Name: ips_fill_scb_sg_single                                     */ | 
|  | 1902 | /*                                                                          */ | 
|  | 1903 | /* Routine Description:                                                     */ | 
|  | 1904 | /*   Fill in a single scb sg_list element from an address                   */ | 
|  | 1905 | /*   return a -1 if a breakup occurred                                      */ | 
|  | 1906 | /****************************************************************************/ | 
|  | 1907 | static int | 
|  | 1908 | ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, | 
|  | 1909 | ips_scb_t * scb, int indx, unsigned int e_len) | 
|  | 1910 | { | 
|  | 1911 |  | 
|  | 1912 | int ret_val = 0; | 
|  | 1913 |  | 
|  | 1914 | if ((scb->data_len + e_len) > ha->max_xfer) { | 
|  | 1915 | e_len = ha->max_xfer - scb->data_len; | 
|  | 1916 | scb->breakup = indx; | 
|  | 1917 | ++scb->sg_break; | 
|  | 1918 | ret_val = -1; | 
|  | 1919 | } else { | 
|  | 1920 | scb->breakup = 0; | 
|  | 1921 | scb->sg_break = 0; | 
|  | 1922 | } | 
|  | 1923 | if (IPS_USE_ENH_SGLIST(ha)) { | 
|  | 1924 | scb->sg_list.enh_list[indx].address_lo = | 
|  | 1925 | cpu_to_le32(pci_dma_lo32(busaddr)); | 
|  | 1926 | scb->sg_list.enh_list[indx].address_hi = | 
|  | 1927 | cpu_to_le32(pci_dma_hi32(busaddr)); | 
|  | 1928 | scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len); | 
|  | 1929 | } else { | 
|  | 1930 | scb->sg_list.std_list[indx].address = | 
|  | 1931 | cpu_to_le32(pci_dma_lo32(busaddr)); | 
|  | 1932 | scb->sg_list.std_list[indx].length = cpu_to_le32(e_len); | 
|  | 1933 | } | 
|  | 1934 |  | 
|  | 1935 | ++scb->sg_len; | 
|  | 1936 | scb->data_len += e_len; | 
|  | 1937 | return ret_val; | 
|  | 1938 | } | 
|  | 1939 |  | 
|  | 1940 | /****************************************************************************/ | 
|  | 1941 | /* Routine Name: ips_flash_firmware                                         */ | 
|  | 1942 | /* Routine Description:                                                     */ | 
|  | 1943 | /*   flashes the firmware of a copperhead adapter                           */ | 
|  | 1944 | /****************************************************************************/ | 
|  | 1945 | static int | 
|  | 1946 | ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 1947 | { | 
|  | 1948 | IPS_SG_LIST sg_list; | 
|  | 1949 | uint32_t cmd_busaddr; | 
|  | 1950 |  | 
|  | 1951 | if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE && | 
|  | 1952 | pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) { | 
|  | 1953 | memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND)); | 
|  | 1954 | pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD; | 
|  | 1955 | pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize); | 
|  | 1956 | } else { | 
|  | 1957 | pt->BasicStatus = 0x0B; | 
|  | 1958 | pt->ExtendedStatus = 0x00; | 
|  | 1959 | ips_free_flash_copperhead(ha); | 
|  | 1960 | return IPS_FAILURE; | 
|  | 1961 | } | 
|  | 1962 | /* Save the S/G list pointer so it doesn't get clobbered */ | 
|  | 1963 | sg_list.list = scb->sg_list.list; | 
|  | 1964 | cmd_busaddr = scb->scb_busaddr; | 
|  | 1965 | /* copy in the CP */ | 
|  | 1966 | memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); | 
|  | 1967 | /* FIX stuff that might be wrong */ | 
|  | 1968 | scb->sg_list.list = sg_list.list; | 
|  | 1969 | scb->scb_busaddr = cmd_busaddr; | 
|  | 1970 | scb->bus = scb->scsi_cmd->device->channel; | 
|  | 1971 | scb->target_id = scb->scsi_cmd->device->id; | 
|  | 1972 | scb->lun = scb->scsi_cmd->device->lun; | 
|  | 1973 | scb->sg_len = 0; | 
|  | 1974 | scb->data_len = 0; | 
|  | 1975 | scb->flags = 0; | 
|  | 1976 | scb->op_code = 0; | 
|  | 1977 | scb->callback = ipsintr_done; | 
|  | 1978 | scb->timeout = ips_cmd_timeout; | 
|  | 1979 |  | 
|  | 1980 | scb->data_len = ha->flash_datasize; | 
|  | 1981 | scb->data_busaddr = | 
|  | 1982 | pci_map_single(ha->pcidev, ha->flash_data, scb->data_len, | 
|  | 1983 | IPS_DMA_DIR(scb)); | 
|  | 1984 | scb->flags |= IPS_SCB_MAP_SINGLE; | 
|  | 1985 | scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 1986 | scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr); | 
|  | 1987 | if (pt->TimeOut) | 
|  | 1988 | scb->timeout = pt->TimeOut; | 
|  | 1989 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 1990 | return IPS_SUCCESS; | 
|  | 1991 | } | 
|  | 1992 |  | 
|  | 1993 | /****************************************************************************/ | 
|  | 1994 | /* Routine Name: ips_free_flash_copperhead                                  */ | 
|  | 1995 | /* Routine Description:                                                     */ | 
|  | 1996 | /*   release the memory resources used to hold the flash image              */ | 
|  | 1997 | /****************************************************************************/ | 
|  | 1998 | static void | 
|  | 1999 | ips_free_flash_copperhead(ips_ha_t * ha) | 
|  | 2000 | { | 
|  | 2001 | if (ha->flash_data == ips_FlashData) | 
|  | 2002 | test_and_clear_bit(0, &ips_FlashDataInUse); | 
|  | 2003 | else if (ha->flash_data) | 
|  | 2004 | pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data, | 
|  | 2005 | ha->flash_busaddr); | 
|  | 2006 | ha->flash_data = NULL; | 
|  | 2007 | } | 
|  | 2008 |  | 
|  | 2009 | /****************************************************************************/ | 
|  | 2010 | /*                                                                          */ | 
|  | 2011 | /* Routine Name: ips_usrcmd                                                 */ | 
|  | 2012 | /*                                                                          */ | 
|  | 2013 | /* Routine Description:                                                     */ | 
|  | 2014 | /*                                                                          */ | 
|  | 2015 | /*   Process a user command and make it ready to send                       */ | 
|  | 2016 | /*                                                                          */ | 
|  | 2017 | /****************************************************************************/ | 
|  | 2018 | static int | 
|  | 2019 | ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) | 
|  | 2020 | { | 
|  | 2021 | IPS_SG_LIST sg_list; | 
|  | 2022 | uint32_t cmd_busaddr; | 
|  | 2023 |  | 
|  | 2024 | METHOD_TRACE("ips_usrcmd", 1); | 
|  | 2025 |  | 
|  | 2026 | if ((!scb) || (!pt) || (!ha)) | 
|  | 2027 | return (0); | 
|  | 2028 |  | 
|  | 2029 | /* Save the S/G list pointer so it doesn't get clobbered */ | 
|  | 2030 | sg_list.list = scb->sg_list.list; | 
|  | 2031 | cmd_busaddr = scb->scb_busaddr; | 
|  | 2032 | /* copy in the CP */ | 
|  | 2033 | memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); | 
|  | 2034 | memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE)); | 
|  | 2035 |  | 
|  | 2036 | /* FIX stuff that might be wrong */ | 
|  | 2037 | scb->sg_list.list = sg_list.list; | 
|  | 2038 | scb->scb_busaddr = cmd_busaddr; | 
|  | 2039 | scb->bus = scb->scsi_cmd->device->channel; | 
|  | 2040 | scb->target_id = scb->scsi_cmd->device->id; | 
|  | 2041 | scb->lun = scb->scsi_cmd->device->lun; | 
|  | 2042 | scb->sg_len = 0; | 
|  | 2043 | scb->data_len = 0; | 
|  | 2044 | scb->flags = 0; | 
|  | 2045 | scb->op_code = 0; | 
|  | 2046 | scb->callback = ipsintr_done; | 
|  | 2047 | scb->timeout = ips_cmd_timeout; | 
|  | 2048 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 2049 |  | 
|  | 2050 | /* we don't support DCDB/READ/WRITE Scatter Gather */ | 
|  | 2051 | if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) || | 
|  | 2052 | (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) || | 
|  | 2053 | (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG)) | 
|  | 2054 | return (0); | 
|  | 2055 |  | 
|  | 2056 | if (pt->CmdBSize) { | 
|  | 2057 | scb->data_len = pt->CmdBSize; | 
|  | 2058 | scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t); | 
|  | 2059 | } else { | 
|  | 2060 | scb->data_busaddr = 0L; | 
|  | 2061 | } | 
|  | 2062 |  | 
|  | 2063 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) | 
|  | 2064 | scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + | 
|  | 2065 | (unsigned long) &scb-> | 
|  | 2066 | dcdb - | 
|  | 2067 | (unsigned long) scb); | 
|  | 2068 |  | 
|  | 2069 | if (pt->CmdBSize) { | 
|  | 2070 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) | 
|  | 2071 | scb->dcdb.buffer_pointer = | 
|  | 2072 | cpu_to_le32(scb->data_busaddr); | 
|  | 2073 | else | 
|  | 2074 | scb->cmd.basic_io.sg_addr = | 
|  | 2075 | cpu_to_le32(scb->data_busaddr); | 
|  | 2076 | } | 
|  | 2077 |  | 
|  | 2078 | /* set timeouts */ | 
|  | 2079 | if (pt->TimeOut) { | 
|  | 2080 | scb->timeout = pt->TimeOut; | 
|  | 2081 |  | 
|  | 2082 | if (pt->TimeOut <= 10) | 
|  | 2083 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; | 
|  | 2084 | else if (pt->TimeOut <= 60) | 
|  | 2085 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; | 
|  | 2086 | else | 
|  | 2087 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; | 
|  | 2088 | } | 
|  | 2089 |  | 
|  | 2090 | /* assume success */ | 
|  | 2091 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 2092 |  | 
|  | 2093 | /* success */ | 
|  | 2094 | return (1); | 
|  | 2095 | } | 
|  | 2096 |  | 
|  | 2097 | /****************************************************************************/ | 
|  | 2098 | /*                                                                          */ | 
|  | 2099 | /* Routine Name: ips_cleanup_passthru                                       */ | 
|  | 2100 | /*                                                                          */ | 
|  | 2101 | /* Routine Description:                                                     */ | 
|  | 2102 | /*                                                                          */ | 
|  | 2103 | /*   Cleanup after a passthru command                                       */ | 
|  | 2104 | /*                                                                          */ | 
|  | 2105 | /****************************************************************************/ | 
|  | 2106 | static void | 
|  | 2107 | ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 2108 | { | 
|  | 2109 | ips_passthru_t *pt; | 
|  | 2110 |  | 
|  | 2111 | METHOD_TRACE("ips_cleanup_passthru", 1); | 
|  | 2112 |  | 
|  | 2113 | if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) { | 
|  | 2114 | DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru", | 
|  | 2115 | ips_name, ha->host_num); | 
|  | 2116 |  | 
|  | 2117 | return; | 
|  | 2118 | } | 
|  | 2119 | pt = (ips_passthru_t *) ha->ioctl_data; | 
|  | 2120 |  | 
|  | 2121 | /* Copy data back to the user */ | 
|  | 2122 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)	/* Copy DCDB Back to Caller's Area */ | 
|  | 2123 | memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE)); | 
|  | 2124 |  | 
|  | 2125 | pt->BasicStatus = scb->basic_status; | 
|  | 2126 | pt->ExtendedStatus = scb->extended_status; | 
|  | 2127 | pt->AdapterType = ha->ad_type; | 
|  | 2128 |  | 
|  | 2129 | if (ha->device_id == IPS_DEVICEID_COPPERHEAD && | 
|  | 2130 | (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || | 
|  | 2131 | scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)) | 
|  | 2132 | ips_free_flash_copperhead(ha); | 
|  | 2133 |  | 
|  | 2134 | ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize); | 
|  | 2135 | } | 
|  | 2136 |  | 
|  | 2137 | /****************************************************************************/ | 
|  | 2138 | /*                                                                          */ | 
|  | 2139 | /* Routine Name: ips_host_info                                              */ | 
|  | 2140 | /*                                                                          */ | 
|  | 2141 | /* Routine Description:                                                     */ | 
|  | 2142 | /*                                                                          */ | 
|  | 2143 | /*   The passthru interface for the driver                                  */ | 
|  | 2144 | /*                                                                          */ | 
|  | 2145 | /****************************************************************************/ | 
|  | 2146 | static int | 
|  | 2147 | ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len) | 
|  | 2148 | { | 
|  | 2149 | IPS_INFOSTR info; | 
|  | 2150 |  | 
|  | 2151 | METHOD_TRACE("ips_host_info", 1); | 
|  | 2152 |  | 
|  | 2153 | info.buffer = ptr; | 
|  | 2154 | info.length = len; | 
|  | 2155 | info.offset = offset; | 
|  | 2156 | info.pos = 0; | 
|  | 2157 | info.localpos = 0; | 
|  | 2158 |  | 
|  | 2159 | copy_info(&info, "\nIBM ServeRAID General Information:\n\n"); | 
|  | 2160 |  | 
|  | 2161 | if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) && | 
|  | 2162 | (le16_to_cpu(ha->nvram->adapter_type) != 0)) | 
|  | 2163 | copy_info(&info, "\tController Type                   : %s\n", | 
|  | 2164 | ips_adapter_name[ha->ad_type - 1]); | 
|  | 2165 | else | 
|  | 2166 | copy_info(&info, | 
|  | 2167 | "\tController Type                   : Unknown\n"); | 
|  | 2168 |  | 
|  | 2169 | if (ha->io_addr) | 
|  | 2170 | copy_info(&info, | 
|  | 2171 | "\tIO region                         : 0x%lx (%d bytes)\n", | 
|  | 2172 | ha->io_addr, ha->io_len); | 
|  | 2173 |  | 
|  | 2174 | if (ha->mem_addr) { | 
|  | 2175 | copy_info(&info, | 
|  | 2176 | "\tMemory region                     : 0x%lx (%d bytes)\n", | 
|  | 2177 | ha->mem_addr, ha->mem_len); | 
|  | 2178 | copy_info(&info, | 
|  | 2179 | "\tShared memory address             : 0x%lx\n", | 
|  | 2180 | ha->mem_ptr); | 
|  | 2181 | } | 
|  | 2182 |  | 
|  | 2183 | copy_info(&info, "\tIRQ number                        : %d\n", ha->irq); | 
|  | 2184 |  | 
|  | 2185 | /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */ | 
|  | 2186 | /* That keeps everything happy for "text" operations on the proc file.                    */ | 
|  | 2187 |  | 
|  | 2188 | if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) { | 
|  | 2189 | if (ha->nvram->bios_low[3] == 0) { | 
|  | 2190 | copy_info(&info, | 
|  | 2191 | "\tBIOS Version                      : %c%c%c%c%c%c%c\n", | 
|  | 2192 | ha->nvram->bios_high[0], ha->nvram->bios_high[1], | 
|  | 2193 | ha->nvram->bios_high[2], ha->nvram->bios_high[3], | 
|  | 2194 | ha->nvram->bios_low[0], ha->nvram->bios_low[1], | 
|  | 2195 | ha->nvram->bios_low[2]); | 
|  | 2196 |  | 
|  | 2197 | } else { | 
|  | 2198 | copy_info(&info, | 
|  | 2199 | "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n", | 
|  | 2200 | ha->nvram->bios_high[0], ha->nvram->bios_high[1], | 
|  | 2201 | ha->nvram->bios_high[2], ha->nvram->bios_high[3], | 
|  | 2202 | ha->nvram->bios_low[0], ha->nvram->bios_low[1], | 
|  | 2203 | ha->nvram->bios_low[2], ha->nvram->bios_low[3]); | 
|  | 2204 | } | 
|  | 2205 |  | 
|  | 2206 | } | 
|  | 2207 |  | 
|  | 2208 | if (ha->enq->CodeBlkVersion[7] == 0) { | 
|  | 2209 | copy_info(&info, | 
|  | 2210 | "\tFirmware Version                  : %c%c%c%c%c%c%c\n", | 
|  | 2211 | ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], | 
|  | 2212 | ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], | 
|  | 2213 | ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], | 
|  | 2214 | ha->enq->CodeBlkVersion[6]); | 
|  | 2215 | } else { | 
|  | 2216 | copy_info(&info, | 
|  | 2217 | "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n", | 
|  | 2218 | ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], | 
|  | 2219 | ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], | 
|  | 2220 | ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], | 
|  | 2221 | ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]); | 
|  | 2222 | } | 
|  | 2223 |  | 
|  | 2224 | if (ha->enq->BootBlkVersion[7] == 0) { | 
|  | 2225 | copy_info(&info, | 
|  | 2226 | "\tBoot Block Version                : %c%c%c%c%c%c%c\n", | 
|  | 2227 | ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], | 
|  | 2228 | ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], | 
|  | 2229 | ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], | 
|  | 2230 | ha->enq->BootBlkVersion[6]); | 
|  | 2231 | } else { | 
|  | 2232 | copy_info(&info, | 
|  | 2233 | "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n", | 
|  | 2234 | ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], | 
|  | 2235 | ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], | 
|  | 2236 | ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], | 
|  | 2237 | ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]); | 
|  | 2238 | } | 
|  | 2239 |  | 
|  | 2240 | copy_info(&info, "\tDriver Version                    : %s%s\n", | 
|  | 2241 | IPS_VERSION_HIGH, IPS_VERSION_LOW); | 
|  | 2242 |  | 
|  | 2243 | copy_info(&info, "\tDriver Build                      : %d\n", | 
|  | 2244 | IPS_BUILD_IDENT); | 
|  | 2245 |  | 
|  | 2246 | copy_info(&info, "\tMax Physical Devices              : %d\n", | 
|  | 2247 | ha->enq->ucMaxPhysicalDevices); | 
|  | 2248 | copy_info(&info, "\tMax Active Commands               : %d\n", | 
|  | 2249 | ha->max_cmds); | 
|  | 2250 | copy_info(&info, "\tCurrent Queued Commands           : %d\n", | 
|  | 2251 | ha->scb_waitlist.count); | 
|  | 2252 | copy_info(&info, "\tCurrent Active Commands           : %d\n", | 
|  | 2253 | ha->scb_activelist.count - ha->num_ioctl); | 
|  | 2254 | copy_info(&info, "\tCurrent Queued PT Commands        : %d\n", | 
|  | 2255 | ha->copp_waitlist.count); | 
|  | 2256 | copy_info(&info, "\tCurrent Active PT Commands        : %d\n", | 
|  | 2257 | ha->num_ioctl); | 
|  | 2258 |  | 
|  | 2259 | copy_info(&info, "\n"); | 
|  | 2260 |  | 
|  | 2261 | return (info.localpos); | 
|  | 2262 | } | 
|  | 2263 |  | 
|  | 2264 | /****************************************************************************/ | 
|  | 2265 | /*                                                                          */ | 
|  | 2266 | /* Routine Name: copy_mem_info                                              */ | 
|  | 2267 | /*                                                                          */ | 
|  | 2268 | /* Routine Description:                                                     */ | 
|  | 2269 | /*                                                                          */ | 
|  | 2270 | /*   Copy data into an IPS_INFOSTR structure                                */ | 
|  | 2271 | /*                                                                          */ | 
|  | 2272 | /****************************************************************************/ | 
|  | 2273 | static void | 
|  | 2274 | copy_mem_info(IPS_INFOSTR * info, char *data, int len) | 
|  | 2275 | { | 
|  | 2276 | METHOD_TRACE("copy_mem_info", 1); | 
|  | 2277 |  | 
|  | 2278 | if (info->pos + len < info->offset) { | 
|  | 2279 | info->pos += len; | 
|  | 2280 | return; | 
|  | 2281 | } | 
|  | 2282 |  | 
|  | 2283 | if (info->pos < info->offset) { | 
|  | 2284 | data += (info->offset - info->pos); | 
|  | 2285 | len -= (info->offset - info->pos); | 
|  | 2286 | info->pos += (info->offset - info->pos); | 
|  | 2287 | } | 
|  | 2288 |  | 
|  | 2289 | if (info->localpos + len > info->length) | 
|  | 2290 | len = info->length - info->localpos; | 
|  | 2291 |  | 
|  | 2292 | if (len > 0) { | 
|  | 2293 | memcpy(info->buffer + info->localpos, data, len); | 
|  | 2294 | info->pos += len; | 
|  | 2295 | info->localpos += len; | 
|  | 2296 | } | 
|  | 2297 | } | 
|  | 2298 |  | 
|  | 2299 | /****************************************************************************/ | 
|  | 2300 | /*                                                                          */ | 
|  | 2301 | /* Routine Name: copy_info                                                  */ | 
|  | 2302 | /*                                                                          */ | 
|  | 2303 | /* Routine Description:                                                     */ | 
|  | 2304 | /*                                                                          */ | 
|  | 2305 | /*   printf style wrapper for an info structure                             */ | 
|  | 2306 | /*                                                                          */ | 
|  | 2307 | /****************************************************************************/ | 
|  | 2308 | static int | 
|  | 2309 | copy_info(IPS_INFOSTR * info, char *fmt, ...) | 
|  | 2310 | { | 
|  | 2311 | va_list args; | 
|  | 2312 | char buf[128]; | 
|  | 2313 | int len; | 
|  | 2314 |  | 
|  | 2315 | METHOD_TRACE("copy_info", 1); | 
|  | 2316 |  | 
|  | 2317 | va_start(args, fmt); | 
|  | 2318 | len = vsprintf(buf, fmt, args); | 
|  | 2319 | va_end(args); | 
|  | 2320 |  | 
|  | 2321 | copy_mem_info(info, buf, len); | 
|  | 2322 |  | 
|  | 2323 | return (len); | 
|  | 2324 | } | 
|  | 2325 |  | 
|  | 2326 | /****************************************************************************/ | 
|  | 2327 | /*                                                                          */ | 
|  | 2328 | /* Routine Name: ips_identify_controller                                    */ | 
|  | 2329 | /*                                                                          */ | 
|  | 2330 | /* Routine Description:                                                     */ | 
|  | 2331 | /*                                                                          */ | 
|  | 2332 | /*   Identify this controller                                               */ | 
|  | 2333 | /*                                                                          */ | 
|  | 2334 | /****************************************************************************/ | 
|  | 2335 | static void | 
|  | 2336 | ips_identify_controller(ips_ha_t * ha) | 
|  | 2337 | { | 
|  | 2338 | METHOD_TRACE("ips_identify_controller", 1); | 
|  | 2339 |  | 
|  | 2340 | switch (ha->device_id) { | 
|  | 2341 | case IPS_DEVICEID_COPPERHEAD: | 
|  | 2342 | if (ha->revision_id <= IPS_REVID_SERVERAID) { | 
|  | 2343 | ha->ad_type = IPS_ADTYPE_SERVERAID; | 
|  | 2344 | } else if (ha->revision_id == IPS_REVID_SERVERAID2) { | 
|  | 2345 | ha->ad_type = IPS_ADTYPE_SERVERAID2; | 
|  | 2346 | } else if (ha->revision_id == IPS_REVID_NAVAJO) { | 
|  | 2347 | ha->ad_type = IPS_ADTYPE_NAVAJO; | 
|  | 2348 | } else if ((ha->revision_id == IPS_REVID_SERVERAID2) | 
|  | 2349 | && (ha->slot_num == 0)) { | 
|  | 2350 | ha->ad_type = IPS_ADTYPE_KIOWA; | 
|  | 2351 | } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) && | 
|  | 2352 | (ha->revision_id <= IPS_REVID_CLARINETP3)) { | 
|  | 2353 | if (ha->enq->ucMaxPhysicalDevices == 15) | 
|  | 2354 | ha->ad_type = IPS_ADTYPE_SERVERAID3L; | 
|  | 2355 | else | 
|  | 2356 | ha->ad_type = IPS_ADTYPE_SERVERAID3; | 
|  | 2357 | } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) && | 
|  | 2358 | (ha->revision_id <= IPS_REVID_TROMBONE64)) { | 
|  | 2359 | ha->ad_type = IPS_ADTYPE_SERVERAID4H; | 
|  | 2360 | } | 
|  | 2361 | break; | 
|  | 2362 |  | 
|  | 2363 | case IPS_DEVICEID_MORPHEUS: | 
|  | 2364 | switch (ha->subdevice_id) { | 
|  | 2365 | case IPS_SUBDEVICEID_4L: | 
|  | 2366 | ha->ad_type = IPS_ADTYPE_SERVERAID4L; | 
|  | 2367 | break; | 
|  | 2368 |  | 
|  | 2369 | case IPS_SUBDEVICEID_4M: | 
|  | 2370 | ha->ad_type = IPS_ADTYPE_SERVERAID4M; | 
|  | 2371 | break; | 
|  | 2372 |  | 
|  | 2373 | case IPS_SUBDEVICEID_4MX: | 
|  | 2374 | ha->ad_type = IPS_ADTYPE_SERVERAID4MX; | 
|  | 2375 | break; | 
|  | 2376 |  | 
|  | 2377 | case IPS_SUBDEVICEID_4LX: | 
|  | 2378 | ha->ad_type = IPS_ADTYPE_SERVERAID4LX; | 
|  | 2379 | break; | 
|  | 2380 |  | 
|  | 2381 | case IPS_SUBDEVICEID_5I2: | 
|  | 2382 | ha->ad_type = IPS_ADTYPE_SERVERAID5I2; | 
|  | 2383 | break; | 
|  | 2384 |  | 
|  | 2385 | case IPS_SUBDEVICEID_5I1: | 
|  | 2386 | ha->ad_type = IPS_ADTYPE_SERVERAID5I1; | 
|  | 2387 | break; | 
|  | 2388 | } | 
|  | 2389 |  | 
|  | 2390 | break; | 
|  | 2391 |  | 
|  | 2392 | case IPS_DEVICEID_MARCO: | 
|  | 2393 | switch (ha->subdevice_id) { | 
|  | 2394 | case IPS_SUBDEVICEID_6M: | 
|  | 2395 | ha->ad_type = IPS_ADTYPE_SERVERAID6M; | 
|  | 2396 | break; | 
|  | 2397 | case IPS_SUBDEVICEID_6I: | 
|  | 2398 | ha->ad_type = IPS_ADTYPE_SERVERAID6I; | 
|  | 2399 | break; | 
|  | 2400 | case IPS_SUBDEVICEID_7k: | 
|  | 2401 | ha->ad_type = IPS_ADTYPE_SERVERAID7k; | 
|  | 2402 | break; | 
|  | 2403 | case IPS_SUBDEVICEID_7M: | 
|  | 2404 | ha->ad_type = IPS_ADTYPE_SERVERAID7M; | 
|  | 2405 | break; | 
|  | 2406 | } | 
|  | 2407 | break; | 
|  | 2408 | } | 
|  | 2409 | } | 
|  | 2410 |  | 
|  | 2411 | /****************************************************************************/ | 
|  | 2412 | /*                                                                          */ | 
|  | 2413 | /* Routine Name: ips_get_bios_version                                       */ | 
|  | 2414 | /*                                                                          */ | 
|  | 2415 | /* Routine Description:                                                     */ | 
|  | 2416 | /*                                                                          */ | 
|  | 2417 | /*   Get the BIOS revision number                                           */ | 
|  | 2418 | /*                                                                          */ | 
|  | 2419 | /****************************************************************************/ | 
|  | 2420 | static void | 
|  | 2421 | ips_get_bios_version(ips_ha_t * ha, int intr) | 
|  | 2422 | { | 
|  | 2423 | ips_scb_t *scb; | 
|  | 2424 | int ret; | 
|  | 2425 | uint8_t major; | 
|  | 2426 | uint8_t minor; | 
|  | 2427 | uint8_t subminor; | 
|  | 2428 | uint8_t *buffer; | 
|  | 2429 | char hexDigits[] = | 
|  | 2430 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', | 
|  | 2431 | 'D', 'E', 'F' }; | 
|  | 2432 |  | 
|  | 2433 | METHOD_TRACE("ips_get_bios_version", 1); | 
|  | 2434 |  | 
|  | 2435 | major = 0; | 
|  | 2436 | minor = 0; | 
|  | 2437 |  | 
|  | 2438 | strncpy(ha->bios_version, "       ?", 8); | 
|  | 2439 |  | 
|  | 2440 | if (ha->device_id == IPS_DEVICEID_COPPERHEAD) { | 
|  | 2441 | if (IPS_USE_MEMIO(ha)) { | 
|  | 2442 | /* Memory Mapped I/O */ | 
|  | 2443 |  | 
|  | 2444 | /* test 1st byte */ | 
|  | 2445 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 2446 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2447 | udelay(25);	/* 25 us */ | 
|  | 2448 |  | 
|  | 2449 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) | 
|  | 2450 | return; | 
|  | 2451 |  | 
|  | 2452 | writel(1, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 2453 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2454 | udelay(25);	/* 25 us */ | 
|  | 2455 |  | 
|  | 2456 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) | 
|  | 2457 | return; | 
|  | 2458 |  | 
|  | 2459 | /* Get Major version */ | 
|  | 2460 | writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 2461 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2462 | udelay(25);	/* 25 us */ | 
|  | 2463 |  | 
|  | 2464 | major = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 2465 |  | 
|  | 2466 | /* Get Minor version */ | 
|  | 2467 | writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 2468 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2469 | udelay(25);	/* 25 us */ | 
|  | 2470 | minor = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 2471 |  | 
|  | 2472 | /* Get SubMinor version */ | 
|  | 2473 | writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 2474 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2475 | udelay(25);	/* 25 us */ | 
|  | 2476 | subminor = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 2477 |  | 
|  | 2478 | } else { | 
|  | 2479 | /* Programmed I/O */ | 
|  | 2480 |  | 
|  | 2481 | /* test 1st byte */ | 
|  | 2482 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 2483 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2484 | udelay(25);	/* 25 us */ | 
|  | 2485 |  | 
|  | 2486 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) | 
|  | 2487 | return; | 
|  | 2488 |  | 
|  | 2489 | outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); | 
|  | 2490 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2491 | udelay(25);	/* 25 us */ | 
|  | 2492 |  | 
|  | 2493 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) | 
|  | 2494 | return; | 
|  | 2495 |  | 
|  | 2496 | /* Get Major version */ | 
|  | 2497 | outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP); | 
|  | 2498 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2499 | udelay(25);	/* 25 us */ | 
|  | 2500 |  | 
|  | 2501 | major = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 2502 |  | 
|  | 2503 | /* Get Minor version */ | 
|  | 2504 | outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP); | 
|  | 2505 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2506 | udelay(25);	/* 25 us */ | 
|  | 2507 |  | 
|  | 2508 | minor = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 2509 |  | 
|  | 2510 | /* Get SubMinor version */ | 
|  | 2511 | outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP); | 
|  | 2512 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 2513 | udelay(25);	/* 25 us */ | 
|  | 2514 |  | 
|  | 2515 | subminor = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 2516 |  | 
|  | 2517 | } | 
|  | 2518 | } else { | 
|  | 2519 | /* Morpheus Family - Send Command to the card */ | 
|  | 2520 |  | 
|  | 2521 | buffer = ha->ioctl_data; | 
|  | 2522 |  | 
|  | 2523 | memset(buffer, 0, 0x1000); | 
|  | 2524 |  | 
|  | 2525 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 2526 |  | 
|  | 2527 | ips_init_scb(ha, scb); | 
|  | 2528 |  | 
|  | 2529 | scb->timeout = ips_cmd_timeout; | 
|  | 2530 | scb->cdb[0] = IPS_CMD_RW_BIOSFW; | 
|  | 2531 |  | 
|  | 2532 | scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW; | 
|  | 2533 | scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 2534 | scb->cmd.flashfw.type = 1; | 
|  | 2535 | scb->cmd.flashfw.direction = 0; | 
|  | 2536 | scb->cmd.flashfw.count = cpu_to_le32(0x800); | 
|  | 2537 | scb->cmd.flashfw.total_packets = 1; | 
|  | 2538 | scb->cmd.flashfw.packet_num = 0; | 
|  | 2539 | scb->data_len = 0x1000; | 
|  | 2540 | scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr; | 
|  | 2541 |  | 
|  | 2542 | /* issue the command */ | 
|  | 2543 | if (((ret = | 
|  | 2544 | ips_send_wait(ha, scb, ips_cmd_timeout, | 
|  | 2545 | intr)) == IPS_FAILURE) | 
|  | 2546 | || (ret == IPS_SUCCESS_IMM) | 
|  | 2547 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { | 
|  | 2548 | /* Error occurred */ | 
|  | 2549 |  | 
|  | 2550 | return; | 
|  | 2551 | } | 
|  | 2552 |  | 
|  | 2553 | if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) { | 
|  | 2554 | major = buffer[0x1ff + 0xC0];	/* Offset 0x1ff after the header (0xc0) */ | 
|  | 2555 | minor = buffer[0x1fe + 0xC0];	/* Offset 0x1fe after the header (0xc0) */ | 
|  | 2556 | subminor = buffer[0x1fd + 0xC0];	/* Offset 0x1fd after the header (0xc0) */ | 
|  | 2557 | } else { | 
|  | 2558 | return; | 
|  | 2559 | } | 
|  | 2560 | } | 
|  | 2561 |  | 
|  | 2562 | ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4]; | 
|  | 2563 | ha->bios_version[1] = '.'; | 
|  | 2564 | ha->bios_version[2] = hexDigits[major & 0x0F]; | 
|  | 2565 | ha->bios_version[3] = hexDigits[subminor]; | 
|  | 2566 | ha->bios_version[4] = '.'; | 
|  | 2567 | ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4]; | 
|  | 2568 | ha->bios_version[6] = hexDigits[minor & 0x0F]; | 
|  | 2569 | ha->bios_version[7] = 0; | 
|  | 2570 | } | 
|  | 2571 |  | 
|  | 2572 | /****************************************************************************/ | 
|  | 2573 | /*                                                                          */ | 
|  | 2574 | /* Routine Name: ips_hainit                                                 */ | 
|  | 2575 | /*                                                                          */ | 
|  | 2576 | /* Routine Description:                                                     */ | 
|  | 2577 | /*                                                                          */ | 
|  | 2578 | /*   Initialize the controller                                              */ | 
|  | 2579 | /*                                                                          */ | 
|  | 2580 | /* NOTE: Assumes to be called from with a lock                              */ | 
|  | 2581 | /*                                                                          */ | 
|  | 2582 | /****************************************************************************/ | 
|  | 2583 | static int | 
|  | 2584 | ips_hainit(ips_ha_t * ha) | 
|  | 2585 | { | 
|  | 2586 | int i; | 
|  | 2587 | struct timeval tv; | 
|  | 2588 |  | 
|  | 2589 | METHOD_TRACE("ips_hainit", 1); | 
|  | 2590 |  | 
|  | 2591 | if (!ha) | 
|  | 2592 | return (0); | 
|  | 2593 |  | 
|  | 2594 | if (ha->func.statinit) | 
|  | 2595 | (*ha->func.statinit) (ha); | 
|  | 2596 |  | 
|  | 2597 | if (ha->func.enableint) | 
|  | 2598 | (*ha->func.enableint) (ha); | 
|  | 2599 |  | 
|  | 2600 | /* Send FFDC */ | 
|  | 2601 | ha->reset_count = 1; | 
|  | 2602 | do_gettimeofday(&tv); | 
|  | 2603 | ha->last_ffdc = tv.tv_sec; | 
|  | 2604 | ips_ffdc_reset(ha, IPS_INTR_IORL); | 
|  | 2605 |  | 
|  | 2606 | if (!ips_read_config(ha, IPS_INTR_IORL)) { | 
|  | 2607 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2608 | "unable to read config from controller.\n"); | 
|  | 2609 |  | 
|  | 2610 | return (0); | 
|  | 2611 | } | 
|  | 2612 | /* end if */ | 
|  | 2613 | if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) { | 
|  | 2614 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2615 | "unable to read controller status.\n"); | 
|  | 2616 |  | 
|  | 2617 | return (0); | 
|  | 2618 | } | 
|  | 2619 |  | 
|  | 2620 | /* Identify this controller */ | 
|  | 2621 | ips_identify_controller(ha); | 
|  | 2622 |  | 
|  | 2623 | if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) { | 
|  | 2624 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2625 | "unable to read subsystem parameters.\n"); | 
|  | 2626 |  | 
|  | 2627 | return (0); | 
|  | 2628 | } | 
|  | 2629 |  | 
|  | 2630 | /* write nvram user page 5 */ | 
|  | 2631 | if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { | 
|  | 2632 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 2633 | "unable to write driver info to controller.\n"); | 
|  | 2634 |  | 
|  | 2635 | return (0); | 
|  | 2636 | } | 
|  | 2637 |  | 
|  | 2638 | /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */ | 
|  | 2639 | if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1)) | 
|  | 2640 | ips_clear_adapter(ha, IPS_INTR_IORL); | 
|  | 2641 |  | 
|  | 2642 | /* set limits on SID, LUN, BUS */ | 
|  | 2643 | ha->ntargets = IPS_MAX_TARGETS + 1; | 
|  | 2644 | ha->nlun = 1; | 
|  | 2645 | ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1; | 
|  | 2646 |  | 
|  | 2647 | switch (ha->conf->logical_drive[0].ucStripeSize) { | 
|  | 2648 | case 4: | 
|  | 2649 | ha->max_xfer = 0x10000; | 
|  | 2650 | break; | 
|  | 2651 |  | 
|  | 2652 | case 5: | 
|  | 2653 | ha->max_xfer = 0x20000; | 
|  | 2654 | break; | 
|  | 2655 |  | 
|  | 2656 | case 6: | 
|  | 2657 | ha->max_xfer = 0x40000; | 
|  | 2658 | break; | 
|  | 2659 |  | 
|  | 2660 | case 7: | 
|  | 2661 | default: | 
|  | 2662 | ha->max_xfer = 0x80000; | 
|  | 2663 | break; | 
|  | 2664 | } | 
|  | 2665 |  | 
|  | 2666 | /* setup max concurrent commands */ | 
|  | 2667 | if (le32_to_cpu(ha->subsys->param[4]) & 0x1) { | 
|  | 2668 | /* Use the new method */ | 
|  | 2669 | ha->max_cmds = ha->enq->ucConcurrentCmdCount; | 
|  | 2670 | } else { | 
|  | 2671 | /* use the old method */ | 
|  | 2672 | switch (ha->conf->logical_drive[0].ucStripeSize) { | 
|  | 2673 | case 4: | 
|  | 2674 | ha->max_cmds = 32; | 
|  | 2675 | break; | 
|  | 2676 |  | 
|  | 2677 | case 5: | 
|  | 2678 | ha->max_cmds = 16; | 
|  | 2679 | break; | 
|  | 2680 |  | 
|  | 2681 | case 6: | 
|  | 2682 | ha->max_cmds = 8; | 
|  | 2683 | break; | 
|  | 2684 |  | 
|  | 2685 | case 7: | 
|  | 2686 | default: | 
|  | 2687 | ha->max_cmds = 4; | 
|  | 2688 | break; | 
|  | 2689 | } | 
|  | 2690 | } | 
|  | 2691 |  | 
|  | 2692 | /* Limit the Active Commands on a Lite Adapter */ | 
|  | 2693 | if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) || | 
|  | 2694 | (ha->ad_type == IPS_ADTYPE_SERVERAID4L) || | 
|  | 2695 | (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) { | 
|  | 2696 | if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) | 
|  | 2697 | ha->max_cmds = MaxLiteCmds; | 
|  | 2698 | } | 
|  | 2699 |  | 
|  | 2700 | /* set controller IDs */ | 
|  | 2701 | ha->ha_id[0] = IPS_ADAPTER_ID; | 
|  | 2702 | for (i = 1; i < ha->nbus; i++) { | 
|  | 2703 | ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f; | 
|  | 2704 | ha->dcdb_active[i - 1] = 0; | 
|  | 2705 | } | 
|  | 2706 |  | 
|  | 2707 | return (1); | 
|  | 2708 | } | 
|  | 2709 |  | 
|  | 2710 | /****************************************************************************/ | 
|  | 2711 | /*                                                                          */ | 
|  | 2712 | /* Routine Name: ips_next                                                   */ | 
|  | 2713 | /*                                                                          */ | 
|  | 2714 | /* Routine Description:                                                     */ | 
|  | 2715 | /*                                                                          */ | 
|  | 2716 | /*   Take the next command off the queue and send it to the controller      */ | 
|  | 2717 | /*                                                                          */ | 
|  | 2718 | /****************************************************************************/ | 
|  | 2719 | static void | 
|  | 2720 | ips_next(ips_ha_t * ha, int intr) | 
|  | 2721 | { | 
|  | 2722 | ips_scb_t *scb; | 
|  | 2723 | Scsi_Cmnd *SC; | 
|  | 2724 | Scsi_Cmnd *p; | 
|  | 2725 | Scsi_Cmnd *q; | 
|  | 2726 | ips_copp_wait_item_t *item; | 
|  | 2727 | int ret; | 
|  | 2728 | unsigned long cpu_flags = 0; | 
|  | 2729 | struct Scsi_Host *host; | 
|  | 2730 | METHOD_TRACE("ips_next", 1); | 
|  | 2731 |  | 
|  | 2732 | if (!ha) | 
|  | 2733 | return; | 
|  | 2734 | host = ips_sh[ha->host_num]; | 
|  | 2735 | /* | 
|  | 2736 | * Block access to the queue function so | 
|  | 2737 | * this command won't time out | 
|  | 2738 | */ | 
|  | 2739 | if (intr == IPS_INTR_ON) | 
|  | 2740 | IPS_LOCK_SAVE(host->host_lock, cpu_flags); | 
|  | 2741 |  | 
|  | 2742 | if ((ha->subsys->param[3] & 0x300000) | 
|  | 2743 | && (ha->scb_activelist.count == 0)) { | 
|  | 2744 | struct timeval tv; | 
|  | 2745 |  | 
|  | 2746 | do_gettimeofday(&tv); | 
|  | 2747 |  | 
|  | 2748 | if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) { | 
|  | 2749 | ha->last_ffdc = tv.tv_sec; | 
|  | 2750 | ips_ffdc_time(ha); | 
|  | 2751 | } | 
|  | 2752 | } | 
|  | 2753 |  | 
|  | 2754 | /* | 
|  | 2755 | * Send passthru commands | 
|  | 2756 | * These have priority over normal I/O | 
|  | 2757 | * but shouldn't affect performance too much | 
|  | 2758 | * since we limit the number that can be active | 
|  | 2759 | * on the card at any one time | 
|  | 2760 | */ | 
|  | 2761 | while ((ha->num_ioctl < IPS_MAX_IOCTL) && | 
|  | 2762 | (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) { | 
|  | 2763 |  | 
|  | 2764 | item = ips_removeq_copp_head(&ha->copp_waitlist); | 
|  | 2765 | ha->num_ioctl++; | 
|  | 2766 | if (intr == IPS_INTR_ON) | 
|  | 2767 | IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); | 
|  | 2768 | scb->scsi_cmd = item->scsi_cmd; | 
|  | 2769 | kfree(item); | 
|  | 2770 |  | 
|  | 2771 | ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr); | 
|  | 2772 |  | 
|  | 2773 | if (intr == IPS_INTR_ON) | 
|  | 2774 | IPS_LOCK_SAVE(host->host_lock, cpu_flags); | 
|  | 2775 | switch (ret) { | 
|  | 2776 | case IPS_FAILURE: | 
|  | 2777 | if (scb->scsi_cmd) { | 
|  | 2778 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 2779 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2780 | } | 
|  | 2781 |  | 
|  | 2782 | ips_freescb(ha, scb); | 
|  | 2783 | break; | 
|  | 2784 | case IPS_SUCCESS_IMM: | 
|  | 2785 | if (scb->scsi_cmd) { | 
|  | 2786 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 2787 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2788 | } | 
|  | 2789 |  | 
|  | 2790 | ips_freescb(ha, scb); | 
|  | 2791 | break; | 
|  | 2792 | default: | 
|  | 2793 | break; | 
|  | 2794 | }		/* end case */ | 
|  | 2795 |  | 
|  | 2796 | if (ret != IPS_SUCCESS) { | 
|  | 2797 | ha->num_ioctl--; | 
|  | 2798 | continue; | 
|  | 2799 | } | 
|  | 2800 |  | 
|  | 2801 | ret = ips_send_cmd(ha, scb); | 
|  | 2802 |  | 
|  | 2803 | if (ret == IPS_SUCCESS) | 
|  | 2804 | ips_putq_scb_head(&ha->scb_activelist, scb); | 
|  | 2805 | else | 
|  | 2806 | ha->num_ioctl--; | 
|  | 2807 |  | 
|  | 2808 | switch (ret) { | 
|  | 2809 | case IPS_FAILURE: | 
|  | 2810 | if (scb->scsi_cmd) { | 
|  | 2811 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 2812 | } | 
|  | 2813 |  | 
|  | 2814 | ips_freescb(ha, scb); | 
|  | 2815 | break; | 
|  | 2816 | case IPS_SUCCESS_IMM: | 
|  | 2817 | ips_freescb(ha, scb); | 
|  | 2818 | break; | 
|  | 2819 | default: | 
|  | 2820 | break; | 
|  | 2821 | }		/* end case */ | 
|  | 2822 |  | 
|  | 2823 | } | 
|  | 2824 |  | 
|  | 2825 | /* | 
|  | 2826 | * Send "Normal" I/O commands | 
|  | 2827 | */ | 
|  | 2828 |  | 
|  | 2829 | p = ha->scb_waitlist.head; | 
|  | 2830 | while ((p) && (scb = ips_getscb(ha))) { | 
|  | 2831 | if ((p->device->channel > 0) | 
|  | 2832 | && (ha-> | 
|  | 2833 | dcdb_active[p->device->channel - | 
|  | 2834 | 1] & (1 << p->device->id))) { | 
|  | 2835 | ips_freescb(ha, scb); | 
|  | 2836 | p = (Scsi_Cmnd *) p->host_scribble; | 
|  | 2837 | continue; | 
|  | 2838 | } | 
|  | 2839 |  | 
|  | 2840 | q = p; | 
|  | 2841 | SC = ips_removeq_wait(&ha->scb_waitlist, q); | 
|  | 2842 |  | 
|  | 2843 | if (intr == IPS_INTR_ON) | 
|  | 2844 | IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);	/* Unlock HA after command is taken off queue */ | 
|  | 2845 |  | 
|  | 2846 | SC->result = DID_OK; | 
|  | 2847 | SC->host_scribble = NULL; | 
|  | 2848 |  | 
|  | 2849 | memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer)); | 
|  | 2850 |  | 
|  | 2851 | scb->target_id = SC->device->id; | 
|  | 2852 | scb->lun = SC->device->lun; | 
|  | 2853 | scb->bus = SC->device->channel; | 
|  | 2854 | scb->scsi_cmd = SC; | 
|  | 2855 | scb->breakup = 0; | 
|  | 2856 | scb->data_len = 0; | 
|  | 2857 | scb->callback = ipsintr_done; | 
|  | 2858 | scb->timeout = ips_cmd_timeout; | 
|  | 2859 | memset(&scb->cmd, 0, 16); | 
|  | 2860 |  | 
|  | 2861 | /* copy in the CDB */ | 
|  | 2862 | memcpy(scb->cdb, SC->cmnd, SC->cmd_len); | 
|  | 2863 |  | 
|  | 2864 | /* Now handle the data buffer */ | 
|  | 2865 | if (SC->use_sg) { | 
|  | 2866 | struct scatterlist *sg; | 
|  | 2867 | int i; | 
|  | 2868 |  | 
|  | 2869 | sg = SC->request_buffer; | 
|  | 2870 | scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg, | 
|  | be7db05 | 2005-04-17 15:26:13 -0500 | [diff] [blame] | 2871 | SC->sc_data_direction); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2872 | scb->flags |= IPS_SCB_MAP_SG; | 
|  | 2873 | for (i = 0; i < scb->sg_count; i++) { | 
|  | 2874 | if (ips_fill_scb_sg_single | 
|  | 2875 | (ha, sg_dma_address(&sg[i]), scb, i, | 
|  | 2876 | sg_dma_len(&sg[i])) < 0) | 
|  | 2877 | break; | 
|  | 2878 | } | 
|  | 2879 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 2880 | } else { | 
|  | 2881 | if (SC->request_bufflen) { | 
|  | 2882 | scb->data_busaddr = | 
|  | 2883 | pci_map_single(ha->pcidev, | 
|  | 2884 | SC->request_buffer, | 
|  | 2885 | SC->request_bufflen, | 
|  | be7db05 | 2005-04-17 15:26:13 -0500 | [diff] [blame] | 2886 | SC->sc_data_direction); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2887 | scb->flags |= IPS_SCB_MAP_SINGLE; | 
|  | 2888 | ips_fill_scb_sg_single(ha, scb->data_busaddr, | 
|  | 2889 | scb, 0, | 
|  | 2890 | SC->request_bufflen); | 
|  | 2891 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 2892 | } else { | 
|  | 2893 | scb->data_busaddr = 0L; | 
|  | 2894 | scb->sg_len = 0; | 
|  | 2895 | scb->data_len = 0; | 
|  | 2896 | scb->dcdb.transfer_length = 0; | 
|  | 2897 | } | 
|  | 2898 |  | 
|  | 2899 | } | 
|  | 2900 |  | 
|  | 2901 | scb->dcdb.cmd_attribute = | 
|  | 2902 | ips_command_direction[scb->scsi_cmd->cmnd[0]]; | 
|  | 2903 |  | 
|  | 2904 | /* Allow a WRITE BUFFER Command to Have no Data */ | 
|  | 2905 | /* This is Used by Tape Flash Utilites          */ | 
|  | 2906 | if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) | 
|  | 2907 | scb->dcdb.cmd_attribute = 0; | 
|  | 2908 |  | 
|  | 2909 | if (!(scb->dcdb.cmd_attribute & 0x3)) | 
|  | 2910 | scb->dcdb.transfer_length = 0; | 
|  | 2911 |  | 
|  | 2912 | if (scb->data_len >= IPS_MAX_XFER) { | 
|  | 2913 | scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; | 
|  | 2914 | scb->dcdb.transfer_length = 0; | 
|  | 2915 | } | 
|  | 2916 | if (intr == IPS_INTR_ON) | 
|  | 2917 | IPS_LOCK_SAVE(host->host_lock, cpu_flags); | 
|  | 2918 |  | 
|  | 2919 | ret = ips_send_cmd(ha, scb); | 
|  | 2920 |  | 
|  | 2921 | switch (ret) { | 
|  | 2922 | case IPS_SUCCESS: | 
|  | 2923 | ips_putq_scb_head(&ha->scb_activelist, scb); | 
|  | 2924 | break; | 
|  | 2925 | case IPS_FAILURE: | 
|  | 2926 | if (scb->scsi_cmd) { | 
|  | 2927 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 2928 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2929 | } | 
|  | 2930 |  | 
|  | 2931 | if (scb->bus) | 
|  | 2932 | ha->dcdb_active[scb->bus - 1] &= | 
|  | 2933 | ~(1 << scb->target_id); | 
|  | 2934 |  | 
|  | 2935 | ips_freescb(ha, scb); | 
|  | 2936 | break; | 
|  | 2937 | case IPS_SUCCESS_IMM: | 
|  | 2938 | if (scb->scsi_cmd) | 
|  | 2939 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 2940 |  | 
|  | 2941 | if (scb->bus) | 
|  | 2942 | ha->dcdb_active[scb->bus - 1] &= | 
|  | 2943 | ~(1 << scb->target_id); | 
|  | 2944 |  | 
|  | 2945 | ips_freescb(ha, scb); | 
|  | 2946 | break; | 
|  | 2947 | default: | 
|  | 2948 | break; | 
|  | 2949 | }		/* end case */ | 
|  | 2950 |  | 
|  | 2951 | p = (Scsi_Cmnd *) p->host_scribble; | 
|  | 2952 |  | 
|  | 2953 | }			/* end while */ | 
|  | 2954 |  | 
|  | 2955 | if (intr == IPS_INTR_ON) | 
|  | 2956 | IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); | 
|  | 2957 | } | 
|  | 2958 |  | 
|  | 2959 | /****************************************************************************/ | 
|  | 2960 | /*                                                                          */ | 
|  | 2961 | /* Routine Name: ips_putq_scb_head                                          */ | 
|  | 2962 | /*                                                                          */ | 
|  | 2963 | /* Routine Description:                                                     */ | 
|  | 2964 | /*                                                                          */ | 
|  | 2965 | /*   Add an item to the head of the queue                                   */ | 
|  | 2966 | /*                                                                          */ | 
|  | 2967 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2968 | /*                                                                          */ | 
|  | 2969 | /****************************************************************************/ | 
|  | 2970 | static void | 
|  | 2971 | ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) | 
|  | 2972 | { | 
|  | 2973 | METHOD_TRACE("ips_putq_scb_head", 1); | 
|  | 2974 |  | 
|  | 2975 | if (!item) | 
|  | 2976 | return; | 
|  | 2977 |  | 
|  | 2978 | item->q_next = queue->head; | 
|  | 2979 | queue->head = item; | 
|  | 2980 |  | 
|  | 2981 | if (!queue->tail) | 
|  | 2982 | queue->tail = item; | 
|  | 2983 |  | 
|  | 2984 | queue->count++; | 
|  | 2985 | } | 
|  | 2986 |  | 
|  | 2987 | /****************************************************************************/ | 
|  | 2988 | /*                                                                          */ | 
|  | 2989 | /* Routine Name: ips_removeq_scb_head                                       */ | 
|  | 2990 | /*                                                                          */ | 
|  | 2991 | /* Routine Description:                                                     */ | 
|  | 2992 | /*                                                                          */ | 
|  | 2993 | /*   Remove the head of the queue                                           */ | 
|  | 2994 | /*                                                                          */ | 
|  | 2995 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 2996 | /*                                                                          */ | 
|  | 2997 | /****************************************************************************/ | 
|  | 2998 | static ips_scb_t * | 
|  | 2999 | ips_removeq_scb_head(ips_scb_queue_t * queue) | 
|  | 3000 | { | 
|  | 3001 | ips_scb_t *item; | 
|  | 3002 |  | 
|  | 3003 | METHOD_TRACE("ips_removeq_scb_head", 1); | 
|  | 3004 |  | 
|  | 3005 | item = queue->head; | 
|  | 3006 |  | 
|  | 3007 | if (!item) { | 
|  | 3008 | return (NULL); | 
|  | 3009 | } | 
|  | 3010 |  | 
|  | 3011 | queue->head = item->q_next; | 
|  | 3012 | item->q_next = NULL; | 
|  | 3013 |  | 
|  | 3014 | if (queue->tail == item) | 
|  | 3015 | queue->tail = NULL; | 
|  | 3016 |  | 
|  | 3017 | queue->count--; | 
|  | 3018 |  | 
|  | 3019 | return (item); | 
|  | 3020 | } | 
|  | 3021 |  | 
|  | 3022 | /****************************************************************************/ | 
|  | 3023 | /*                                                                          */ | 
|  | 3024 | /* Routine Name: ips_removeq_scb                                            */ | 
|  | 3025 | /*                                                                          */ | 
|  | 3026 | /* Routine Description:                                                     */ | 
|  | 3027 | /*                                                                          */ | 
|  | 3028 | /*   Remove an item from a queue                                            */ | 
|  | 3029 | /*                                                                          */ | 
|  | 3030 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3031 | /*                                                                          */ | 
|  | 3032 | /****************************************************************************/ | 
|  | 3033 | static ips_scb_t * | 
|  | 3034 | ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) | 
|  | 3035 | { | 
|  | 3036 | ips_scb_t *p; | 
|  | 3037 |  | 
|  | 3038 | METHOD_TRACE("ips_removeq_scb", 1); | 
|  | 3039 |  | 
|  | 3040 | if (!item) | 
|  | 3041 | return (NULL); | 
|  | 3042 |  | 
|  | 3043 | if (item == queue->head) { | 
|  | 3044 | return (ips_removeq_scb_head(queue)); | 
|  | 3045 | } | 
|  | 3046 |  | 
|  | 3047 | p = queue->head; | 
|  | 3048 |  | 
|  | 3049 | while ((p) && (item != p->q_next)) | 
|  | 3050 | p = p->q_next; | 
|  | 3051 |  | 
|  | 3052 | if (p) { | 
|  | 3053 | /* found a match */ | 
|  | 3054 | p->q_next = item->q_next; | 
|  | 3055 |  | 
|  | 3056 | if (!item->q_next) | 
|  | 3057 | queue->tail = p; | 
|  | 3058 |  | 
|  | 3059 | item->q_next = NULL; | 
|  | 3060 | queue->count--; | 
|  | 3061 |  | 
|  | 3062 | return (item); | 
|  | 3063 | } | 
|  | 3064 |  | 
|  | 3065 | return (NULL); | 
|  | 3066 | } | 
|  | 3067 |  | 
|  | 3068 | /****************************************************************************/ | 
|  | 3069 | /*                                                                          */ | 
|  | 3070 | /* Routine Name: ips_putq_wait_tail                                         */ | 
|  | 3071 | /*                                                                          */ | 
|  | 3072 | /* Routine Description:                                                     */ | 
|  | 3073 | /*                                                                          */ | 
|  | 3074 | /*   Add an item to the tail of the queue                                   */ | 
|  | 3075 | /*                                                                          */ | 
|  | 3076 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3077 | /*                                                                          */ | 
|  | 3078 | /****************************************************************************/ | 
|  | 3079 | static void | 
|  | 3080 | ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) | 
|  | 3081 | { | 
|  | 3082 | METHOD_TRACE("ips_putq_wait_tail", 1); | 
|  | 3083 |  | 
|  | 3084 | if (!item) | 
|  | 3085 | return; | 
|  | 3086 |  | 
|  | 3087 | item->host_scribble = NULL; | 
|  | 3088 |  | 
|  | 3089 | if (queue->tail) | 
|  | 3090 | queue->tail->host_scribble = (char *) item; | 
|  | 3091 |  | 
|  | 3092 | queue->tail = item; | 
|  | 3093 |  | 
|  | 3094 | if (!queue->head) | 
|  | 3095 | queue->head = item; | 
|  | 3096 |  | 
|  | 3097 | queue->count++; | 
|  | 3098 | } | 
|  | 3099 |  | 
|  | 3100 | /****************************************************************************/ | 
|  | 3101 | /*                                                                          */ | 
|  | 3102 | /* Routine Name: ips_removeq_wait_head                                      */ | 
|  | 3103 | /*                                                                          */ | 
|  | 3104 | /* Routine Description:                                                     */ | 
|  | 3105 | /*                                                                          */ | 
|  | 3106 | /*   Remove the head of the queue                                           */ | 
|  | 3107 | /*                                                                          */ | 
|  | 3108 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3109 | /*                                                                          */ | 
|  | 3110 | /****************************************************************************/ | 
|  | 3111 | static Scsi_Cmnd * | 
|  | 3112 | ips_removeq_wait_head(ips_wait_queue_t * queue) | 
|  | 3113 | { | 
|  | 3114 | Scsi_Cmnd *item; | 
|  | 3115 |  | 
|  | 3116 | METHOD_TRACE("ips_removeq_wait_head", 1); | 
|  | 3117 |  | 
|  | 3118 | item = queue->head; | 
|  | 3119 |  | 
|  | 3120 | if (!item) { | 
|  | 3121 | return (NULL); | 
|  | 3122 | } | 
|  | 3123 |  | 
|  | 3124 | queue->head = (Scsi_Cmnd *) item->host_scribble; | 
|  | 3125 | item->host_scribble = NULL; | 
|  | 3126 |  | 
|  | 3127 | if (queue->tail == item) | 
|  | 3128 | queue->tail = NULL; | 
|  | 3129 |  | 
|  | 3130 | queue->count--; | 
|  | 3131 |  | 
|  | 3132 | return (item); | 
|  | 3133 | } | 
|  | 3134 |  | 
|  | 3135 | /****************************************************************************/ | 
|  | 3136 | /*                                                                          */ | 
|  | 3137 | /* Routine Name: ips_removeq_wait                                           */ | 
|  | 3138 | /*                                                                          */ | 
|  | 3139 | /* Routine Description:                                                     */ | 
|  | 3140 | /*                                                                          */ | 
|  | 3141 | /*   Remove an item from a queue                                            */ | 
|  | 3142 | /*                                                                          */ | 
|  | 3143 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3144 | /*                                                                          */ | 
|  | 3145 | /****************************************************************************/ | 
|  | 3146 | static Scsi_Cmnd * | 
|  | 3147 | ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) | 
|  | 3148 | { | 
|  | 3149 | Scsi_Cmnd *p; | 
|  | 3150 |  | 
|  | 3151 | METHOD_TRACE("ips_removeq_wait", 1); | 
|  | 3152 |  | 
|  | 3153 | if (!item) | 
|  | 3154 | return (NULL); | 
|  | 3155 |  | 
|  | 3156 | if (item == queue->head) { | 
|  | 3157 | return (ips_removeq_wait_head(queue)); | 
|  | 3158 | } | 
|  | 3159 |  | 
|  | 3160 | p = queue->head; | 
|  | 3161 |  | 
|  | 3162 | while ((p) && (item != (Scsi_Cmnd *) p->host_scribble)) | 
|  | 3163 | p = (Scsi_Cmnd *) p->host_scribble; | 
|  | 3164 |  | 
|  | 3165 | if (p) { | 
|  | 3166 | /* found a match */ | 
|  | 3167 | p->host_scribble = item->host_scribble; | 
|  | 3168 |  | 
|  | 3169 | if (!item->host_scribble) | 
|  | 3170 | queue->tail = p; | 
|  | 3171 |  | 
|  | 3172 | item->host_scribble = NULL; | 
|  | 3173 | queue->count--; | 
|  | 3174 |  | 
|  | 3175 | return (item); | 
|  | 3176 | } | 
|  | 3177 |  | 
|  | 3178 | return (NULL); | 
|  | 3179 | } | 
|  | 3180 |  | 
|  | 3181 | /****************************************************************************/ | 
|  | 3182 | /*                                                                          */ | 
|  | 3183 | /* Routine Name: ips_putq_copp_tail                                         */ | 
|  | 3184 | /*                                                                          */ | 
|  | 3185 | /* Routine Description:                                                     */ | 
|  | 3186 | /*                                                                          */ | 
|  | 3187 | /*   Add an item to the tail of the queue                                   */ | 
|  | 3188 | /*                                                                          */ | 
|  | 3189 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3190 | /*                                                                          */ | 
|  | 3191 | /****************************************************************************/ | 
|  | 3192 | static void | 
|  | 3193 | ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) | 
|  | 3194 | { | 
|  | 3195 | METHOD_TRACE("ips_putq_copp_tail", 1); | 
|  | 3196 |  | 
|  | 3197 | if (!item) | 
|  | 3198 | return; | 
|  | 3199 |  | 
|  | 3200 | item->next = NULL; | 
|  | 3201 |  | 
|  | 3202 | if (queue->tail) | 
|  | 3203 | queue->tail->next = item; | 
|  | 3204 |  | 
|  | 3205 | queue->tail = item; | 
|  | 3206 |  | 
|  | 3207 | if (!queue->head) | 
|  | 3208 | queue->head = item; | 
|  | 3209 |  | 
|  | 3210 | queue->count++; | 
|  | 3211 | } | 
|  | 3212 |  | 
|  | 3213 | /****************************************************************************/ | 
|  | 3214 | /*                                                                          */ | 
|  | 3215 | /* Routine Name: ips_removeq_copp_head                                      */ | 
|  | 3216 | /*                                                                          */ | 
|  | 3217 | /* Routine Description:                                                     */ | 
|  | 3218 | /*                                                                          */ | 
|  | 3219 | /*   Remove the head of the queue                                           */ | 
|  | 3220 | /*                                                                          */ | 
|  | 3221 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3222 | /*                                                                          */ | 
|  | 3223 | /****************************************************************************/ | 
|  | 3224 | static ips_copp_wait_item_t * | 
|  | 3225 | ips_removeq_copp_head(ips_copp_queue_t * queue) | 
|  | 3226 | { | 
|  | 3227 | ips_copp_wait_item_t *item; | 
|  | 3228 |  | 
|  | 3229 | METHOD_TRACE("ips_removeq_copp_head", 1); | 
|  | 3230 |  | 
|  | 3231 | item = queue->head; | 
|  | 3232 |  | 
|  | 3233 | if (!item) { | 
|  | 3234 | return (NULL); | 
|  | 3235 | } | 
|  | 3236 |  | 
|  | 3237 | queue->head = item->next; | 
|  | 3238 | item->next = NULL; | 
|  | 3239 |  | 
|  | 3240 | if (queue->tail == item) | 
|  | 3241 | queue->tail = NULL; | 
|  | 3242 |  | 
|  | 3243 | queue->count--; | 
|  | 3244 |  | 
|  | 3245 | return (item); | 
|  | 3246 | } | 
|  | 3247 |  | 
|  | 3248 | /****************************************************************************/ | 
|  | 3249 | /*                                                                          */ | 
|  | 3250 | /* Routine Name: ips_removeq_copp                                           */ | 
|  | 3251 | /*                                                                          */ | 
|  | 3252 | /* Routine Description:                                                     */ | 
|  | 3253 | /*                                                                          */ | 
|  | 3254 | /*   Remove an item from a queue                                            */ | 
|  | 3255 | /*                                                                          */ | 
|  | 3256 | /* ASSUMED to be called from within the HA lock                             */ | 
|  | 3257 | /*                                                                          */ | 
|  | 3258 | /****************************************************************************/ | 
|  | 3259 | static ips_copp_wait_item_t * | 
|  | 3260 | ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) | 
|  | 3261 | { | 
|  | 3262 | ips_copp_wait_item_t *p; | 
|  | 3263 |  | 
|  | 3264 | METHOD_TRACE("ips_removeq_copp", 1); | 
|  | 3265 |  | 
|  | 3266 | if (!item) | 
|  | 3267 | return (NULL); | 
|  | 3268 |  | 
|  | 3269 | if (item == queue->head) { | 
|  | 3270 | return (ips_removeq_copp_head(queue)); | 
|  | 3271 | } | 
|  | 3272 |  | 
|  | 3273 | p = queue->head; | 
|  | 3274 |  | 
|  | 3275 | while ((p) && (item != p->next)) | 
|  | 3276 | p = p->next; | 
|  | 3277 |  | 
|  | 3278 | if (p) { | 
|  | 3279 | /* found a match */ | 
|  | 3280 | p->next = item->next; | 
|  | 3281 |  | 
|  | 3282 | if (!item->next) | 
|  | 3283 | queue->tail = p; | 
|  | 3284 |  | 
|  | 3285 | item->next = NULL; | 
|  | 3286 | queue->count--; | 
|  | 3287 |  | 
|  | 3288 | return (item); | 
|  | 3289 | } | 
|  | 3290 |  | 
|  | 3291 | return (NULL); | 
|  | 3292 | } | 
|  | 3293 |  | 
|  | 3294 | /****************************************************************************/ | 
|  | 3295 | /*                                                                          */ | 
|  | 3296 | /* Routine Name: ipsintr_blocking                                           */ | 
|  | 3297 | /*                                                                          */ | 
|  | 3298 | /* Routine Description:                                                     */ | 
|  | 3299 | /*                                                                          */ | 
|  | 3300 | /*   Finalize an interrupt for internal commands                            */ | 
|  | 3301 | /*                                                                          */ | 
|  | 3302 | /****************************************************************************/ | 
|  | 3303 | static void | 
|  | 3304 | ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3305 | { | 
|  | 3306 | METHOD_TRACE("ipsintr_blocking", 2); | 
|  | 3307 |  | 
|  | 3308 | ips_freescb(ha, scb); | 
|  | 3309 | if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) { | 
|  | 3310 | ha->waitflag = FALSE; | 
|  | 3311 |  | 
|  | 3312 | return; | 
|  | 3313 | } | 
|  | 3314 | } | 
|  | 3315 |  | 
|  | 3316 | /****************************************************************************/ | 
|  | 3317 | /*                                                                          */ | 
|  | 3318 | /* Routine Name: ipsintr_done                                               */ | 
|  | 3319 | /*                                                                          */ | 
|  | 3320 | /* Routine Description:                                                     */ | 
|  | 3321 | /*                                                                          */ | 
|  | 3322 | /*   Finalize an interrupt for non-internal commands                        */ | 
|  | 3323 | /*                                                                          */ | 
|  | 3324 | /****************************************************************************/ | 
|  | 3325 | static void | 
|  | 3326 | ipsintr_done(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3327 | { | 
|  | 3328 | METHOD_TRACE("ipsintr_done", 2); | 
|  | 3329 |  | 
|  | 3330 | if (!scb) { | 
|  | 3331 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 3332 | "Spurious interrupt; scb NULL.\n"); | 
|  | 3333 |  | 
|  | 3334 | return; | 
|  | 3335 | } | 
|  | 3336 |  | 
|  | 3337 | if (scb->scsi_cmd == NULL) { | 
|  | 3338 | /* unexpected interrupt */ | 
|  | 3339 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 3340 | "Spurious interrupt; scsi_cmd not set.\n"); | 
|  | 3341 |  | 
|  | 3342 | return; | 
|  | 3343 | } | 
|  | 3344 |  | 
|  | 3345 | ips_done(ha, scb); | 
|  | 3346 | } | 
|  | 3347 |  | 
|  | 3348 | /****************************************************************************/ | 
|  | 3349 | /*                                                                          */ | 
|  | 3350 | /* Routine Name: ips_done                                                   */ | 
|  | 3351 | /*                                                                          */ | 
|  | 3352 | /* Routine Description:                                                     */ | 
|  | 3353 | /*                                                                          */ | 
|  | 3354 | /*   Do housekeeping on completed commands                                  */ | 
|  | 3355 | /*  ASSUMED to be called form within the request lock                       */ | 
|  | 3356 | /****************************************************************************/ | 
|  | 3357 | static void | 
|  | 3358 | ips_done(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3359 | { | 
|  | 3360 | int ret; | 
|  | 3361 |  | 
|  | 3362 | METHOD_TRACE("ips_done", 1); | 
|  | 3363 |  | 
|  | 3364 | if (!scb) | 
|  | 3365 | return; | 
|  | 3366 |  | 
|  | 3367 | if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) { | 
|  | 3368 | ips_cleanup_passthru(ha, scb); | 
|  | 3369 | ha->num_ioctl--; | 
|  | 3370 | } else { | 
|  | 3371 | /* | 
|  | 3372 | * Check to see if this command had too much | 
|  | 3373 | * data and had to be broke up.  If so, queue | 
|  | 3374 | * the rest of the data and continue. | 
|  | 3375 | */ | 
|  | 3376 | if ((scb->breakup) || (scb->sg_break)) { | 
|  | 3377 | /* we had a data breakup */ | 
|  | 3378 | scb->data_len = 0; | 
|  | 3379 |  | 
|  | 3380 | if (scb->sg_count) { | 
|  | 3381 | /* S/G request */ | 
|  | 3382 | struct scatterlist *sg; | 
|  | 3383 | int ips_sg_index = 0; | 
|  | 3384 | int sg_dma_index; | 
|  | 3385 |  | 
|  | 3386 | sg = scb->scsi_cmd->request_buffer; | 
|  | 3387 |  | 
|  | 3388 | /* Spin forward to last dma chunk */ | 
|  | 3389 | sg_dma_index = scb->breakup; | 
|  | 3390 |  | 
|  | 3391 | /* Take care of possible partial on last chunk */ | 
|  | 3392 | ips_fill_scb_sg_single(ha, | 
|  | 3393 | sg_dma_address(&sg | 
|  | 3394 | [sg_dma_index]), | 
|  | 3395 | scb, ips_sg_index++, | 
|  | 3396 | sg_dma_len(&sg | 
|  | 3397 | [sg_dma_index])); | 
|  | 3398 |  | 
|  | 3399 | for (; sg_dma_index < scb->sg_count; | 
|  | 3400 | sg_dma_index++) { | 
|  | 3401 | if (ips_fill_scb_sg_single | 
|  | 3402 | (ha, | 
|  | 3403 | sg_dma_address(&sg[sg_dma_index]), | 
|  | 3404 | scb, ips_sg_index++, | 
|  | 3405 | sg_dma_len(&sg[sg_dma_index])) < 0) | 
|  | 3406 | break; | 
|  | 3407 |  | 
|  | 3408 | } | 
|  | 3409 |  | 
|  | 3410 | } else { | 
|  | 3411 | /* Non S/G Request */ | 
|  | 3412 | (void) ips_fill_scb_sg_single(ha, | 
|  | 3413 | scb-> | 
|  | 3414 | data_busaddr + | 
|  | 3415 | (scb->sg_break * | 
|  | 3416 | ha->max_xfer), | 
|  | 3417 | scb, 0, | 
|  | 3418 | scb->scsi_cmd-> | 
|  | 3419 | request_bufflen - | 
|  | 3420 | (scb->sg_break * | 
|  | 3421 | ha->max_xfer)); | 
|  | 3422 | } | 
|  | 3423 |  | 
|  | 3424 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 3425 | scb->dcdb.cmd_attribute |= | 
|  | 3426 | ips_command_direction[scb->scsi_cmd->cmnd[0]]; | 
|  | 3427 |  | 
|  | 3428 | if (!(scb->dcdb.cmd_attribute & 0x3)) | 
|  | 3429 | scb->dcdb.transfer_length = 0; | 
|  | 3430 |  | 
|  | 3431 | if (scb->data_len >= IPS_MAX_XFER) { | 
|  | 3432 | scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; | 
|  | 3433 | scb->dcdb.transfer_length = 0; | 
|  | 3434 | } | 
|  | 3435 |  | 
|  | 3436 | ret = ips_send_cmd(ha, scb); | 
|  | 3437 |  | 
|  | 3438 | switch (ret) { | 
|  | 3439 | case IPS_FAILURE: | 
|  | 3440 | if (scb->scsi_cmd) { | 
|  | 3441 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 3442 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 3443 | } | 
|  | 3444 |  | 
|  | 3445 | ips_freescb(ha, scb); | 
|  | 3446 | break; | 
|  | 3447 | case IPS_SUCCESS_IMM: | 
|  | 3448 | if (scb->scsi_cmd) { | 
|  | 3449 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 3450 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 3451 | } | 
|  | 3452 |  | 
|  | 3453 | ips_freescb(ha, scb); | 
|  | 3454 | break; | 
|  | 3455 | default: | 
|  | 3456 | break; | 
|  | 3457 | }	/* end case */ | 
|  | 3458 |  | 
|  | 3459 | return; | 
|  | 3460 | } | 
|  | 3461 | }			/* end if passthru */ | 
|  | 3462 |  | 
|  | 3463 | if (scb->bus) { | 
|  | 3464 | ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id); | 
|  | 3465 | } | 
|  | 3466 |  | 
|  | 3467 | scb->scsi_cmd->scsi_done(scb->scsi_cmd); | 
|  | 3468 |  | 
|  | 3469 | ips_freescb(ha, scb); | 
|  | 3470 | } | 
|  | 3471 |  | 
|  | 3472 | /****************************************************************************/ | 
|  | 3473 | /*                                                                          */ | 
|  | 3474 | /* Routine Name: ips_map_status                                             */ | 
|  | 3475 | /*                                                                          */ | 
|  | 3476 | /* Routine Description:                                                     */ | 
|  | 3477 | /*                                                                          */ | 
|  | 3478 | /*   Map Controller Error codes to Linux Error Codes                        */ | 
|  | 3479 | /*                                                                          */ | 
|  | 3480 | /****************************************************************************/ | 
|  | 3481 | static int | 
|  | 3482 | ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) | 
|  | 3483 | { | 
|  | 3484 | int errcode; | 
|  | 3485 | int device_error; | 
|  | 3486 | uint32_t transfer_len; | 
|  | 3487 | IPS_DCDB_TABLE_TAPE *tapeDCDB; | 
|  | 3488 |  | 
|  | 3489 | METHOD_TRACE("ips_map_status", 1); | 
|  | 3490 |  | 
|  | 3491 | if (scb->bus) { | 
|  | 3492 | DEBUG_VAR(2, | 
|  | 3493 | "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x", | 
|  | 3494 | ips_name, ha->host_num, | 
|  | 3495 | scb->scsi_cmd->device->channel, | 
|  | 3496 | scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun, | 
|  | 3497 | scb->basic_status, scb->extended_status, | 
|  | 3498 | scb->extended_status == | 
|  | 3499 | IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0, | 
|  | 3500 | scb->extended_status == | 
|  | 3501 | IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0, | 
|  | 3502 | scb->extended_status == | 
|  | 3503 | IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0); | 
|  | 3504 | } | 
|  | 3505 |  | 
|  | 3506 | /* default driver error */ | 
|  | 3507 | errcode = DID_ERROR; | 
|  | 3508 | device_error = 0; | 
|  | 3509 |  | 
|  | 3510 | switch (scb->basic_status & IPS_GSC_STATUS_MASK) { | 
|  | 3511 | case IPS_CMD_TIMEOUT: | 
|  | 3512 | errcode = DID_TIME_OUT; | 
|  | 3513 | break; | 
|  | 3514 |  | 
|  | 3515 | case IPS_INVAL_OPCO: | 
|  | 3516 | case IPS_INVAL_CMD_BLK: | 
|  | 3517 | case IPS_INVAL_PARM_BLK: | 
|  | 3518 | case IPS_LD_ERROR: | 
|  | 3519 | case IPS_CMD_CMPLT_WERROR: | 
|  | 3520 | break; | 
|  | 3521 |  | 
|  | 3522 | case IPS_PHYS_DRV_ERROR: | 
|  | 3523 | switch (scb->extended_status) { | 
|  | 3524 | case IPS_ERR_SEL_TO: | 
|  | 3525 | if (scb->bus) | 
|  | 3526 | errcode = DID_NO_CONNECT; | 
|  | 3527 |  | 
|  | 3528 | break; | 
|  | 3529 |  | 
|  | 3530 | case IPS_ERR_OU_RUN: | 
|  | 3531 | if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) || | 
|  | 3532 | (scb->cmd.dcdb.op_code == | 
|  | 3533 | IPS_CMD_EXTENDED_DCDB_SG)) { | 
|  | 3534 | tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; | 
|  | 3535 | transfer_len = tapeDCDB->transfer_length; | 
|  | 3536 | } else { | 
|  | 3537 | transfer_len = | 
|  | 3538 | (uint32_t) scb->dcdb.transfer_length; | 
|  | 3539 | } | 
|  | 3540 |  | 
|  | 3541 | if ((scb->bus) && (transfer_len < scb->data_len)) { | 
|  | 3542 | /* Underrun - set default to no error */ | 
|  | 3543 | errcode = DID_OK; | 
|  | 3544 |  | 
|  | 3545 | /* Restrict access to physical DASD */ | 
|  | 3546 | if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && | 
|  | 3547 | ((((char *) scb->scsi_cmd-> | 
|  | 3548 | buffer)[0] & 0x1f) == TYPE_DISK)) { | 
|  | 3549 | /* underflow -- no error               */ | 
|  | 3550 | /* restrict access to physical DASD    */ | 
|  | 3551 | errcode = DID_TIME_OUT; | 
|  | 3552 | break; | 
|  | 3553 | } | 
|  | 3554 | } else | 
|  | 3555 | errcode = DID_ERROR; | 
|  | 3556 |  | 
|  | 3557 | break; | 
|  | 3558 |  | 
|  | 3559 | case IPS_ERR_RECOVERY: | 
|  | 3560 | /* don't fail recovered errors */ | 
|  | 3561 | if (scb->bus) | 
|  | 3562 | errcode = DID_OK; | 
|  | 3563 |  | 
|  | 3564 | break; | 
|  | 3565 |  | 
|  | 3566 | case IPS_ERR_HOST_RESET: | 
|  | 3567 | case IPS_ERR_DEV_RESET: | 
|  | 3568 | errcode = DID_RESET; | 
|  | 3569 | break; | 
|  | 3570 |  | 
|  | 3571 | case IPS_ERR_CKCOND: | 
|  | 3572 | if (scb->bus) { | 
|  | 3573 | if ((scb->cmd.dcdb.op_code == | 
|  | 3574 | IPS_CMD_EXTENDED_DCDB) | 
|  | 3575 | || (scb->cmd.dcdb.op_code == | 
|  | 3576 | IPS_CMD_EXTENDED_DCDB_SG)) { | 
|  | 3577 | tapeDCDB = | 
|  | 3578 | (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; | 
|  | 3579 | memcpy(scb->scsi_cmd->sense_buffer, | 
|  | 3580 | tapeDCDB->sense_info, | 
|  | 3581 | sizeof (scb->scsi_cmd-> | 
|  | 3582 | sense_buffer)); | 
|  | 3583 | } else { | 
|  | 3584 | memcpy(scb->scsi_cmd->sense_buffer, | 
|  | 3585 | scb->dcdb.sense_info, | 
|  | 3586 | sizeof (scb->scsi_cmd-> | 
|  | 3587 | sense_buffer)); | 
|  | 3588 | } | 
|  | 3589 | device_error = 2;	/* check condition */ | 
|  | 3590 | } | 
|  | 3591 |  | 
|  | 3592 | errcode = DID_OK; | 
|  | 3593 |  | 
|  | 3594 | break; | 
|  | 3595 |  | 
|  | 3596 | default: | 
|  | 3597 | errcode = DID_ERROR; | 
|  | 3598 | break; | 
|  | 3599 |  | 
|  | 3600 | }		/* end switch */ | 
|  | 3601 | }			/* end switch */ | 
|  | 3602 |  | 
|  | 3603 | scb->scsi_cmd->result = device_error | (errcode << 16); | 
|  | 3604 |  | 
|  | 3605 | return (1); | 
|  | 3606 | } | 
|  | 3607 |  | 
|  | 3608 | /****************************************************************************/ | 
|  | 3609 | /*                                                                          */ | 
|  | 3610 | /* Routine Name: ips_send_wait                                              */ | 
|  | 3611 | /*                                                                          */ | 
|  | 3612 | /* Routine Description:                                                     */ | 
|  | 3613 | /*                                                                          */ | 
|  | 3614 | /*   Send a command to the controller and wait for it to return             */ | 
|  | 3615 | /*                                                                          */ | 
|  | 3616 | /*   The FFDC Time Stamp use this function for the callback, but doesn't    */ | 
|  | 3617 | /*   actually need to wait.                                                 */ | 
|  | 3618 | /****************************************************************************/ | 
|  | 3619 | static int | 
|  | 3620 | ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) | 
|  | 3621 | { | 
|  | 3622 | int ret; | 
|  | 3623 |  | 
|  | 3624 | METHOD_TRACE("ips_send_wait", 1); | 
|  | 3625 |  | 
|  | 3626 | if (intr != IPS_FFDC) {	/* Won't be Waiting if this is a Time Stamp */ | 
|  | 3627 | ha->waitflag = TRUE; | 
|  | 3628 | ha->cmd_in_progress = scb->cdb[0]; | 
|  | 3629 | } | 
|  | 3630 | scb->callback = ipsintr_blocking; | 
|  | 3631 | ret = ips_send_cmd(ha, scb); | 
|  | 3632 |  | 
|  | 3633 | if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) | 
|  | 3634 | return (ret); | 
|  | 3635 |  | 
|  | 3636 | if (intr != IPS_FFDC)	/* Don't Wait around if this is a Time Stamp */ | 
|  | 3637 | ret = ips_wait(ha, timeout, intr); | 
|  | 3638 |  | 
|  | 3639 | return (ret); | 
|  | 3640 | } | 
|  | 3641 |  | 
|  | 3642 | /****************************************************************************/ | 
|  | 3643 | /*                                                                          */ | 
|  | 3644 | /* Routine Name: ips_scmd_buf_write                                         */ | 
|  | 3645 | /*                                                                          */ | 
|  | 3646 | /* Routine Description:                                                     */ | 
|  | 3647 | /*  Write data to Scsi_Cmnd request_buffer at proper offsets                */ | 
|  | 3648 | /****************************************************************************/ | 
|  | 3649 | static void | 
|  | 3650 | ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned | 
|  | 3651 | int count) | 
|  | 3652 | { | 
|  | 3653 | if (scmd->use_sg) { | 
|  | 3654 | int i; | 
|  | 3655 | unsigned int min_cnt, xfer_cnt; | 
|  | 3656 | char *cdata = (char *) data; | 
|  | 3657 | struct scatterlist *sg = scmd->request_buffer; | 
|  | 3658 | for (i = 0, xfer_cnt = 0; | 
|  | 3659 | (i < scmd->use_sg) && (xfer_cnt < count); i++) { | 
|  | 3660 | if (!IPS_SG_ADDRESS(&sg[i])) | 
|  | 3661 | return; | 
|  | 3662 | min_cnt = min(count - xfer_cnt, sg[i].length); | 
|  | 3663 | memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt], | 
|  | 3664 | min_cnt); | 
|  | 3665 | xfer_cnt += min_cnt; | 
|  | 3666 | } | 
|  | 3667 |  | 
|  | 3668 | } else { | 
|  | 3669 | unsigned int min_cnt = min(count, scmd->request_bufflen); | 
|  | 3670 | memcpy(scmd->request_buffer, data, min_cnt); | 
|  | 3671 | } | 
|  | 3672 | } | 
|  | 3673 |  | 
|  | 3674 | /****************************************************************************/ | 
|  | 3675 | /*                                                                          */ | 
|  | 3676 | /* Routine Name: ips_scmd_buf_read                                          */ | 
|  | 3677 | /*                                                                          */ | 
|  | 3678 | /* Routine Description:                                                     */ | 
|  | 3679 | /*  Copy data from a Scsi_Cmnd to a new, linear buffer                      */ | 
|  | 3680 | /****************************************************************************/ | 
|  | 3681 | static void | 
|  | 3682 | ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned | 
|  | 3683 | int count) | 
|  | 3684 | { | 
|  | 3685 | if (scmd->use_sg) { | 
|  | 3686 | int i; | 
|  | 3687 | unsigned int min_cnt, xfer_cnt; | 
|  | 3688 | char *cdata = (char *) data; | 
|  | 3689 | struct scatterlist *sg = scmd->request_buffer; | 
|  | 3690 | for (i = 0, xfer_cnt = 0; | 
|  | 3691 | (i < scmd->use_sg) && (xfer_cnt < count); i++) { | 
|  | 3692 | if (!IPS_SG_ADDRESS(&sg[i])) | 
|  | 3693 | return; | 
|  | 3694 | min_cnt = min(count - xfer_cnt, sg[i].length); | 
|  | 3695 | memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]), | 
|  | 3696 | min_cnt); | 
|  | 3697 | xfer_cnt += min_cnt; | 
|  | 3698 | } | 
|  | 3699 |  | 
|  | 3700 | } else { | 
|  | 3701 | unsigned int min_cnt = min(count, scmd->request_bufflen); | 
|  | 3702 | memcpy(data, scmd->request_buffer, min_cnt); | 
|  | 3703 | } | 
|  | 3704 | } | 
|  | 3705 |  | 
|  | 3706 | /****************************************************************************/ | 
|  | 3707 | /*                                                                          */ | 
|  | 3708 | /* Routine Name: ips_send_cmd                                               */ | 
|  | 3709 | /*                                                                          */ | 
|  | 3710 | /* Routine Description:                                                     */ | 
|  | 3711 | /*                                                                          */ | 
|  | 3712 | /*   Map SCSI commands to ServeRAID commands for logical drives             */ | 
|  | 3713 | /*                                                                          */ | 
|  | 3714 | /****************************************************************************/ | 
|  | 3715 | static int | 
|  | 3716 | ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 3717 | { | 
|  | 3718 | int ret; | 
|  | 3719 | char *sp; | 
|  | 3720 | int device_error; | 
|  | 3721 | IPS_DCDB_TABLE_TAPE *tapeDCDB; | 
|  | 3722 | int TimeOut; | 
|  | 3723 |  | 
|  | 3724 | METHOD_TRACE("ips_send_cmd", 1); | 
|  | 3725 |  | 
|  | 3726 | ret = IPS_SUCCESS; | 
|  | 3727 |  | 
|  | 3728 | if (!scb->scsi_cmd) { | 
|  | 3729 | /* internal command */ | 
|  | 3730 |  | 
|  | 3731 | if (scb->bus > 0) { | 
|  | 3732 | /* Controller commands can't be issued */ | 
|  | 3733 | /* to real devices -- fail them        */ | 
|  | 3734 | if ((ha->waitflag == TRUE) && | 
|  | 3735 | (ha->cmd_in_progress == scb->cdb[0])) { | 
|  | 3736 | ha->waitflag = FALSE; | 
|  | 3737 | } | 
|  | 3738 |  | 
|  | 3739 | return (1); | 
|  | 3740 | } | 
|  | 3741 | } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) { | 
|  | 3742 | /* command to logical bus -- interpret */ | 
|  | 3743 | ret = IPS_SUCCESS_IMM; | 
|  | 3744 |  | 
|  | 3745 | switch (scb->scsi_cmd->cmnd[0]) { | 
|  | 3746 | case ALLOW_MEDIUM_REMOVAL: | 
|  | 3747 | case REZERO_UNIT: | 
|  | 3748 | case ERASE: | 
|  | 3749 | case WRITE_FILEMARKS: | 
|  | 3750 | case SPACE: | 
|  | 3751 | scb->scsi_cmd->result = DID_ERROR << 16; | 
|  | 3752 | break; | 
|  | 3753 |  | 
|  | 3754 | case START_STOP: | 
|  | 3755 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3756 |  | 
|  | 3757 | case TEST_UNIT_READY: | 
|  | 3758 | case INQUIRY: | 
|  | 3759 | if (scb->target_id == IPS_ADAPTER_ID) { | 
|  | 3760 | /* | 
|  | 3761 | * Either we have a TUR | 
|  | 3762 | * or we have a SCSI inquiry | 
|  | 3763 | */ | 
|  | 3764 | if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY) | 
|  | 3765 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3766 |  | 
|  | 3767 | if (scb->scsi_cmd->cmnd[0] == INQUIRY) { | 
|  | 3768 | IPS_SCSI_INQ_DATA inquiry; | 
|  | 3769 |  | 
|  | 3770 | memset(&inquiry, 0, | 
|  | 3771 | sizeof (IPS_SCSI_INQ_DATA)); | 
|  | 3772 |  | 
|  | 3773 | inquiry.DeviceType = | 
|  | 3774 | IPS_SCSI_INQ_TYPE_PROCESSOR; | 
|  | 3775 | inquiry.DeviceTypeQualifier = | 
|  | 3776 | IPS_SCSI_INQ_LU_CONNECTED; | 
|  | 3777 | inquiry.Version = IPS_SCSI_INQ_REV2; | 
|  | 3778 | inquiry.ResponseDataFormat = | 
|  | 3779 | IPS_SCSI_INQ_RD_REV2; | 
|  | 3780 | inquiry.AdditionalLength = 31; | 
|  | 3781 | inquiry.Flags[0] = | 
|  | 3782 | IPS_SCSI_INQ_Address16; | 
|  | 3783 | inquiry.Flags[1] = | 
|  | 3784 | IPS_SCSI_INQ_WBus16 | | 
|  | 3785 | IPS_SCSI_INQ_Sync; | 
|  | 3786 | strncpy(inquiry.VendorId, "IBM     ", | 
|  | 3787 | 8); | 
|  | 3788 | strncpy(inquiry.ProductId, | 
|  | 3789 | "SERVERAID       ", 16); | 
|  | 3790 | strncpy(inquiry.ProductRevisionLevel, | 
|  | 3791 | "1.00", 4); | 
|  | 3792 |  | 
|  | 3793 | ips_scmd_buf_write(scb->scsi_cmd, | 
|  | 3794 | &inquiry, | 
|  | 3795 | sizeof (inquiry)); | 
|  | 3796 |  | 
|  | 3797 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3798 | } | 
|  | 3799 | } else { | 
|  | 3800 | scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; | 
|  | 3801 | scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3802 | scb->cmd.logical_info.reserved = 0; | 
|  | 3803 | scb->cmd.logical_info.reserved2 = 0; | 
|  | 3804 | scb->data_len = sizeof (IPS_LD_INFO); | 
|  | 3805 | scb->data_busaddr = ha->logical_drive_info_dma_addr; | 
|  | 3806 | scb->flags = 0; | 
|  | 3807 | scb->cmd.logical_info.buffer_addr = scb->data_busaddr; | 
|  | 3808 | ret = IPS_SUCCESS; | 
|  | 3809 | } | 
|  | 3810 |  | 
|  | 3811 | break; | 
|  | 3812 |  | 
|  | 3813 | case REQUEST_SENSE: | 
|  | 3814 | ips_reqsen(ha, scb); | 
|  | 3815 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3816 | break; | 
|  | 3817 |  | 
|  | 3818 | case READ_6: | 
|  | 3819 | case WRITE_6: | 
|  | 3820 | if (!scb->sg_len) { | 
|  | 3821 | scb->cmd.basic_io.op_code = | 
|  | 3822 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3823 | READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE; | 
|  | 3824 | scb->cmd.basic_io.enhanced_sg = 0; | 
|  | 3825 | scb->cmd.basic_io.sg_addr = | 
|  | 3826 | cpu_to_le32(scb->data_busaddr); | 
|  | 3827 | } else { | 
|  | 3828 | scb->cmd.basic_io.op_code = | 
|  | 3829 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3830 | READ_6) ? IPS_CMD_READ_SG : | 
|  | 3831 | IPS_CMD_WRITE_SG; | 
|  | 3832 | scb->cmd.basic_io.enhanced_sg = | 
|  | 3833 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 3834 | scb->cmd.basic_io.sg_addr = | 
|  | 3835 | cpu_to_le32(scb->sg_busaddr); | 
|  | 3836 | } | 
|  | 3837 |  | 
|  | 3838 | scb->cmd.basic_io.segment_4G = 0; | 
|  | 3839 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3840 | scb->cmd.basic_io.log_drv = scb->target_id; | 
|  | 3841 | scb->cmd.basic_io.sg_count = scb->sg_len; | 
|  | 3842 |  | 
|  | 3843 | if (scb->cmd.basic_io.lba) | 
|  | 3844 | scb->cmd.basic_io.lba = | 
|  | 3845 | cpu_to_le32(le32_to_cpu | 
|  | 3846 | (scb->cmd.basic_io.lba) + | 
|  | 3847 | le16_to_cpu(scb->cmd.basic_io. | 
|  | 3848 | sector_count)); | 
|  | 3849 | else | 
|  | 3850 | scb->cmd.basic_io.lba = | 
|  | 3851 | (((scb->scsi_cmd-> | 
|  | 3852 | cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd-> | 
|  | 3853 | cmnd[2] << 8) | | 
|  | 3854 | (scb->scsi_cmd->cmnd[3])); | 
|  | 3855 |  | 
|  | 3856 | scb->cmd.basic_io.sector_count = | 
|  | 3857 | cpu_to_le16(scb->data_len / IPS_BLKSIZE); | 
|  | 3858 |  | 
|  | 3859 | if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0) | 
|  | 3860 | scb->cmd.basic_io.sector_count = | 
|  | 3861 | cpu_to_le16(256); | 
|  | 3862 |  | 
|  | 3863 | ret = IPS_SUCCESS; | 
|  | 3864 | break; | 
|  | 3865 |  | 
|  | 3866 | case READ_10: | 
|  | 3867 | case WRITE_10: | 
|  | 3868 | if (!scb->sg_len) { | 
|  | 3869 | scb->cmd.basic_io.op_code = | 
|  | 3870 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3871 | READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE; | 
|  | 3872 | scb->cmd.basic_io.enhanced_sg = 0; | 
|  | 3873 | scb->cmd.basic_io.sg_addr = | 
|  | 3874 | cpu_to_le32(scb->data_busaddr); | 
|  | 3875 | } else { | 
|  | 3876 | scb->cmd.basic_io.op_code = | 
|  | 3877 | (scb->scsi_cmd->cmnd[0] == | 
|  | 3878 | READ_10) ? IPS_CMD_READ_SG : | 
|  | 3879 | IPS_CMD_WRITE_SG; | 
|  | 3880 | scb->cmd.basic_io.enhanced_sg = | 
|  | 3881 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 3882 | scb->cmd.basic_io.sg_addr = | 
|  | 3883 | cpu_to_le32(scb->sg_busaddr); | 
|  | 3884 | } | 
|  | 3885 |  | 
|  | 3886 | scb->cmd.basic_io.segment_4G = 0; | 
|  | 3887 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3888 | scb->cmd.basic_io.log_drv = scb->target_id; | 
|  | 3889 | scb->cmd.basic_io.sg_count = scb->sg_len; | 
|  | 3890 |  | 
|  | 3891 | if (scb->cmd.basic_io.lba) | 
|  | 3892 | scb->cmd.basic_io.lba = | 
|  | 3893 | cpu_to_le32(le32_to_cpu | 
|  | 3894 | (scb->cmd.basic_io.lba) + | 
|  | 3895 | le16_to_cpu(scb->cmd.basic_io. | 
|  | 3896 | sector_count)); | 
|  | 3897 | else | 
|  | 3898 | scb->cmd.basic_io.lba = | 
|  | 3899 | ((scb->scsi_cmd->cmnd[2] << 24) | (scb-> | 
|  | 3900 | scsi_cmd-> | 
|  | 3901 | cmnd[3] | 
|  | 3902 | << 16) | | 
|  | 3903 | (scb->scsi_cmd->cmnd[4] << 8) | scb-> | 
|  | 3904 | scsi_cmd->cmnd[5]); | 
|  | 3905 |  | 
|  | 3906 | scb->cmd.basic_io.sector_count = | 
|  | 3907 | cpu_to_le16(scb->data_len / IPS_BLKSIZE); | 
|  | 3908 |  | 
|  | 3909 | if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) { | 
|  | 3910 | /* | 
|  | 3911 | * This is a null condition | 
|  | 3912 | * we don't have to do anything | 
|  | 3913 | * so just return | 
|  | 3914 | */ | 
|  | 3915 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3916 | } else | 
|  | 3917 | ret = IPS_SUCCESS; | 
|  | 3918 |  | 
|  | 3919 | break; | 
|  | 3920 |  | 
|  | 3921 | case RESERVE: | 
|  | 3922 | case RELEASE: | 
|  | 3923 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3924 | break; | 
|  | 3925 |  | 
|  | 3926 | case MODE_SENSE: | 
|  | 3927 | scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; | 
|  | 3928 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3929 | scb->cmd.basic_io.segment_4G = 0; | 
|  | 3930 | scb->cmd.basic_io.enhanced_sg = 0; | 
|  | 3931 | scb->data_len = sizeof (*ha->enq); | 
|  | 3932 | scb->cmd.basic_io.sg_addr = ha->enq_busaddr; | 
|  | 3933 | ret = IPS_SUCCESS; | 
|  | 3934 | break; | 
|  | 3935 |  | 
|  | 3936 | case READ_CAPACITY: | 
|  | 3937 | scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; | 
|  | 3938 | scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3939 | scb->cmd.logical_info.reserved = 0; | 
|  | 3940 | scb->cmd.logical_info.reserved2 = 0; | 
|  | 3941 | scb->cmd.logical_info.reserved3 = 0; | 
|  | 3942 | scb->data_len = sizeof (IPS_LD_INFO); | 
|  | 3943 | scb->data_busaddr = ha->logical_drive_info_dma_addr; | 
|  | 3944 | scb->flags = 0; | 
|  | 3945 | scb->cmd.logical_info.buffer_addr = scb->data_busaddr; | 
|  | 3946 | ret = IPS_SUCCESS; | 
|  | 3947 | break; | 
|  | 3948 |  | 
|  | 3949 | case SEND_DIAGNOSTIC: | 
|  | 3950 | case REASSIGN_BLOCKS: | 
|  | 3951 | case FORMAT_UNIT: | 
|  | 3952 | case SEEK_10: | 
|  | 3953 | case VERIFY: | 
|  | 3954 | case READ_DEFECT_DATA: | 
|  | 3955 | case READ_BUFFER: | 
|  | 3956 | case WRITE_BUFFER: | 
|  | 3957 | scb->scsi_cmd->result = DID_OK << 16; | 
|  | 3958 | break; | 
|  | 3959 |  | 
|  | 3960 | default: | 
|  | 3961 | /* Set the Return Info to appear like the Command was */ | 
|  | 3962 | /* attempted, a Check Condition occurred, and Sense   */ | 
|  | 3963 | /* Data indicating an Invalid CDB OpCode is returned. */ | 
|  | 3964 | sp = (char *) scb->scsi_cmd->sense_buffer; | 
|  | 3965 | memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer)); | 
|  | 3966 |  | 
|  | 3967 | sp[0] = 0x70;	/* Error Code               */ | 
|  | 3968 | sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */ | 
|  | 3969 | sp[7] = 0x0A;	/* Additional Sense Length  */ | 
|  | 3970 | sp[12] = 0x20;	/* ASC = Invalid OpCode     */ | 
|  | 3971 | sp[13] = 0x00;	/* ASCQ                     */ | 
|  | 3972 |  | 
|  | 3973 | device_error = 2;	/* Indicate Check Condition */ | 
|  | 3974 | scb->scsi_cmd->result = device_error | (DID_OK << 16); | 
|  | 3975 | break; | 
|  | 3976 | }		/* end switch */ | 
|  | 3977 | } | 
|  | 3978 | /* end if */ | 
|  | 3979 | if (ret == IPS_SUCCESS_IMM) | 
|  | 3980 | return (ret); | 
|  | 3981 |  | 
|  | 3982 | /* setup DCDB */ | 
|  | 3983 | if (scb->bus > 0) { | 
|  | 3984 |  | 
|  | 3985 | /* If we already know the Device is Not there, no need to attempt a Command   */ | 
|  | 3986 | /* This also protects an NT FailOver Controller from getting CDB's sent to it */ | 
|  | 3987 | if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) { | 
|  | 3988 | scb->scsi_cmd->result = DID_NO_CONNECT << 16; | 
|  | 3989 | return (IPS_SUCCESS_IMM); | 
|  | 3990 | } | 
|  | 3991 |  | 
|  | 3992 | ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id); | 
|  | 3993 | scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 3994 | scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + | 
|  | 3995 | (unsigned long) &scb-> | 
|  | 3996 | dcdb - | 
|  | 3997 | (unsigned long) scb); | 
|  | 3998 | scb->cmd.dcdb.reserved = 0; | 
|  | 3999 | scb->cmd.dcdb.reserved2 = 0; | 
|  | 4000 | scb->cmd.dcdb.reserved3 = 0; | 
|  | 4001 | scb->cmd.dcdb.segment_4G = 0; | 
|  | 4002 | scb->cmd.dcdb.enhanced_sg = 0; | 
|  | 4003 |  | 
|  | 4004 | TimeOut = scb->scsi_cmd->timeout_per_command; | 
|  | 4005 |  | 
|  | 4006 | if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */ | 
|  | 4007 | if (!scb->sg_len) { | 
|  | 4008 | scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB; | 
|  | 4009 | } else { | 
|  | 4010 | scb->cmd.dcdb.op_code = | 
|  | 4011 | IPS_CMD_EXTENDED_DCDB_SG; | 
|  | 4012 | scb->cmd.dcdb.enhanced_sg = | 
|  | 4013 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 4014 | } | 
|  | 4015 |  | 
|  | 4016 | tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;	/* Use Same Data Area as Old DCDB Struct */ | 
|  | 4017 | tapeDCDB->device_address = | 
|  | 4018 | ((scb->bus - 1) << 4) | scb->target_id; | 
|  | 4019 | tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED; | 
|  | 4020 | tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;	/* Always Turn OFF 64K Size Flag */ | 
|  | 4021 |  | 
|  | 4022 | if (TimeOut) { | 
|  | 4023 | if (TimeOut < (10 * HZ)) | 
|  | 4024 | tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */ | 
|  | 4025 | else if (TimeOut < (60 * HZ)) | 
|  | 4026 | tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */ | 
|  | 4027 | else if (TimeOut < (1200 * HZ)) | 
|  | 4028 | tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */ | 
|  | 4029 | } | 
|  | 4030 |  | 
|  | 4031 | tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len; | 
|  | 4032 | tapeDCDB->reserved_for_LUN = 0; | 
|  | 4033 | tapeDCDB->transfer_length = scb->data_len; | 
|  | 4034 | if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG) | 
|  | 4035 | tapeDCDB->buffer_pointer = | 
|  | 4036 | cpu_to_le32(scb->sg_busaddr); | 
|  | 4037 | else | 
|  | 4038 | tapeDCDB->buffer_pointer = | 
|  | 4039 | cpu_to_le32(scb->data_busaddr); | 
|  | 4040 | tapeDCDB->sg_count = scb->sg_len; | 
|  | 4041 | tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info); | 
|  | 4042 | tapeDCDB->scsi_status = 0; | 
|  | 4043 | tapeDCDB->reserved = 0; | 
|  | 4044 | memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, | 
|  | 4045 | scb->scsi_cmd->cmd_len); | 
|  | 4046 | } else { | 
|  | 4047 | if (!scb->sg_len) { | 
|  | 4048 | scb->cmd.dcdb.op_code = IPS_CMD_DCDB; | 
|  | 4049 | } else { | 
|  | 4050 | scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG; | 
|  | 4051 | scb->cmd.dcdb.enhanced_sg = | 
|  | 4052 | IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; | 
|  | 4053 | } | 
|  | 4054 |  | 
|  | 4055 | scb->dcdb.device_address = | 
|  | 4056 | ((scb->bus - 1) << 4) | scb->target_id; | 
|  | 4057 | scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED; | 
|  | 4058 |  | 
|  | 4059 | if (TimeOut) { | 
|  | 4060 | if (TimeOut < (10 * HZ)) | 
|  | 4061 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */ | 
|  | 4062 | else if (TimeOut < (60 * HZ)) | 
|  | 4063 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */ | 
|  | 4064 | else if (TimeOut < (1200 * HZ)) | 
|  | 4065 | scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */ | 
|  | 4066 | } | 
|  | 4067 |  | 
|  | 4068 | scb->dcdb.transfer_length = scb->data_len; | 
|  | 4069 | if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K) | 
|  | 4070 | scb->dcdb.transfer_length = 0; | 
|  | 4071 | if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG) | 
|  | 4072 | scb->dcdb.buffer_pointer = | 
|  | 4073 | cpu_to_le32(scb->sg_busaddr); | 
|  | 4074 | else | 
|  | 4075 | scb->dcdb.buffer_pointer = | 
|  | 4076 | cpu_to_le32(scb->data_busaddr); | 
|  | 4077 | scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len; | 
|  | 4078 | scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info); | 
|  | 4079 | scb->dcdb.sg_count = scb->sg_len; | 
|  | 4080 | scb->dcdb.reserved = 0; | 
|  | 4081 | memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, | 
|  | 4082 | scb->scsi_cmd->cmd_len); | 
|  | 4083 | scb->dcdb.scsi_status = 0; | 
|  | 4084 | scb->dcdb.reserved2[0] = 0; | 
|  | 4085 | scb->dcdb.reserved2[1] = 0; | 
|  | 4086 | scb->dcdb.reserved2[2] = 0; | 
|  | 4087 | } | 
|  | 4088 | } | 
|  | 4089 |  | 
|  | 4090 | return ((*ha->func.issue) (ha, scb)); | 
|  | 4091 | } | 
|  | 4092 |  | 
|  | 4093 | /****************************************************************************/ | 
|  | 4094 | /*                                                                          */ | 
|  | 4095 | /* Routine Name: ips_chk_status                                             */ | 
|  | 4096 | /*                                                                          */ | 
|  | 4097 | /* Routine Description:                                                     */ | 
|  | 4098 | /*                                                                          */ | 
|  | 4099 | /*   Check the status of commands to logical drives                         */ | 
|  | 4100 | /*   Assumed to be called with the HA lock                                  */ | 
|  | 4101 | /****************************************************************************/ | 
|  | 4102 | static void | 
|  | 4103 | ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) | 
|  | 4104 | { | 
|  | 4105 | ips_scb_t *scb; | 
|  | 4106 | ips_stat_t *sp; | 
|  | 4107 | uint8_t basic_status; | 
|  | 4108 | uint8_t ext_status; | 
|  | 4109 | int errcode; | 
|  | 4110 |  | 
|  | 4111 | METHOD_TRACE("ips_chkstatus", 1); | 
|  | 4112 |  | 
|  | 4113 | scb = &ha->scbs[pstatus->fields.command_id]; | 
|  | 4114 | scb->basic_status = basic_status = | 
|  | 4115 | pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK; | 
|  | 4116 | scb->extended_status = ext_status = pstatus->fields.extended_status; | 
|  | 4117 |  | 
|  | 4118 | sp = &ha->sp; | 
|  | 4119 | sp->residue_len = 0; | 
|  | 4120 | sp->scb_addr = (void *) scb; | 
|  | 4121 |  | 
|  | 4122 | /* Remove the item from the active queue */ | 
|  | 4123 | ips_removeq_scb(&ha->scb_activelist, scb); | 
|  | 4124 |  | 
|  | 4125 | if (!scb->scsi_cmd) | 
|  | 4126 | /* internal commands are handled in do_ipsintr */ | 
|  | 4127 | return; | 
|  | 4128 |  | 
|  | 4129 | DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)", | 
|  | 4130 | ips_name, | 
|  | 4131 | ha->host_num, | 
|  | 4132 | scb->cdb[0], | 
|  | 4133 | scb->cmd.basic_io.command_id, | 
|  | 4134 | scb->bus, scb->target_id, scb->lun); | 
|  | 4135 |  | 
|  | 4136 | if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) | 
|  | 4137 | /* passthru - just returns the raw result */ | 
|  | 4138 | return; | 
|  | 4139 |  | 
|  | 4140 | errcode = DID_OK; | 
|  | 4141 |  | 
|  | 4142 | if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) || | 
|  | 4143 | ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) { | 
|  | 4144 |  | 
|  | 4145 | if (scb->bus == 0) { | 
|  | 4146 | if ((basic_status & IPS_GSC_STATUS_MASK) == | 
|  | 4147 | IPS_CMD_RECOVERED_ERROR) { | 
|  | 4148 | DEBUG_VAR(1, | 
|  | 4149 | "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", | 
|  | 4150 | ips_name, ha->host_num, | 
|  | 4151 | scb->cmd.basic_io.op_code, | 
|  | 4152 | basic_status, ext_status); | 
|  | 4153 | } | 
|  | 4154 |  | 
|  | 4155 | switch (scb->scsi_cmd->cmnd[0]) { | 
|  | 4156 | case ALLOW_MEDIUM_REMOVAL: | 
|  | 4157 | case REZERO_UNIT: | 
|  | 4158 | case ERASE: | 
|  | 4159 | case WRITE_FILEMARKS: | 
|  | 4160 | case SPACE: | 
|  | 4161 | errcode = DID_ERROR; | 
|  | 4162 | break; | 
|  | 4163 |  | 
|  | 4164 | case START_STOP: | 
|  | 4165 | break; | 
|  | 4166 |  | 
|  | 4167 | case TEST_UNIT_READY: | 
|  | 4168 | if (!ips_online(ha, scb)) { | 
|  | 4169 | errcode = DID_TIME_OUT; | 
|  | 4170 | } | 
|  | 4171 | break; | 
|  | 4172 |  | 
|  | 4173 | case INQUIRY: | 
|  | 4174 | if (ips_online(ha, scb)) { | 
|  | 4175 | ips_inquiry(ha, scb); | 
|  | 4176 | } else { | 
|  | 4177 | errcode = DID_TIME_OUT; | 
|  | 4178 | } | 
|  | 4179 | break; | 
|  | 4180 |  | 
|  | 4181 | case REQUEST_SENSE: | 
|  | 4182 | ips_reqsen(ha, scb); | 
|  | 4183 | break; | 
|  | 4184 |  | 
|  | 4185 | case READ_6: | 
|  | 4186 | case WRITE_6: | 
|  | 4187 | case READ_10: | 
|  | 4188 | case WRITE_10: | 
|  | 4189 | case RESERVE: | 
|  | 4190 | case RELEASE: | 
|  | 4191 | break; | 
|  | 4192 |  | 
|  | 4193 | case MODE_SENSE: | 
|  | 4194 | if (!ips_online(ha, scb) | 
|  | 4195 | || !ips_msense(ha, scb)) { | 
|  | 4196 | errcode = DID_ERROR; | 
|  | 4197 | } | 
|  | 4198 | break; | 
|  | 4199 |  | 
|  | 4200 | case READ_CAPACITY: | 
|  | 4201 | if (ips_online(ha, scb)) | 
|  | 4202 | ips_rdcap(ha, scb); | 
|  | 4203 | else { | 
|  | 4204 | errcode = DID_TIME_OUT; | 
|  | 4205 | } | 
|  | 4206 | break; | 
|  | 4207 |  | 
|  | 4208 | case SEND_DIAGNOSTIC: | 
|  | 4209 | case REASSIGN_BLOCKS: | 
|  | 4210 | break; | 
|  | 4211 |  | 
|  | 4212 | case FORMAT_UNIT: | 
|  | 4213 | errcode = DID_ERROR; | 
|  | 4214 | break; | 
|  | 4215 |  | 
|  | 4216 | case SEEK_10: | 
|  | 4217 | case VERIFY: | 
|  | 4218 | case READ_DEFECT_DATA: | 
|  | 4219 | case READ_BUFFER: | 
|  | 4220 | case WRITE_BUFFER: | 
|  | 4221 | break; | 
|  | 4222 |  | 
|  | 4223 | default: | 
|  | 4224 | errcode = DID_ERROR; | 
|  | 4225 | }	/* end switch */ | 
|  | 4226 |  | 
|  | 4227 | scb->scsi_cmd->result = errcode << 16; | 
|  | 4228 | } else {	/* bus == 0 */ | 
|  | 4229 | /* restrict access to physical drives */ | 
|  | 4230 | if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && | 
|  | 4231 | ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == | 
|  | 4232 | TYPE_DISK)) { | 
|  | 4233 |  | 
|  | 4234 | scb->scsi_cmd->result = DID_TIME_OUT << 16; | 
|  | 4235 | } | 
|  | 4236 | }		/* else */ | 
|  | 4237 | } else {		/* recovered error / success */ | 
|  | 4238 | if (scb->bus == 0) { | 
|  | 4239 | DEBUG_VAR(1, | 
|  | 4240 | "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", | 
|  | 4241 | ips_name, ha->host_num, | 
|  | 4242 | scb->cmd.basic_io.op_code, basic_status, | 
|  | 4243 | ext_status); | 
|  | 4244 | } | 
|  | 4245 |  | 
|  | 4246 | ips_map_status(ha, scb, sp); | 
|  | 4247 | }			/* else */ | 
|  | 4248 | } | 
|  | 4249 |  | 
|  | 4250 | /****************************************************************************/ | 
|  | 4251 | /*                                                                          */ | 
|  | 4252 | /* Routine Name: ips_online                                                 */ | 
|  | 4253 | /*                                                                          */ | 
|  | 4254 | /* Routine Description:                                                     */ | 
|  | 4255 | /*                                                                          */ | 
|  | 4256 | /*   Determine if a logical drive is online                                 */ | 
|  | 4257 | /*                                                                          */ | 
|  | 4258 | /****************************************************************************/ | 
|  | 4259 | static int | 
|  | 4260 | ips_online(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4261 | { | 
|  | 4262 | METHOD_TRACE("ips_online", 1); | 
|  | 4263 |  | 
|  | 4264 | if (scb->target_id >= IPS_MAX_LD) | 
|  | 4265 | return (0); | 
|  | 4266 |  | 
|  | 4267 | if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) { | 
|  | 4268 | memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO)); | 
|  | 4269 | return (0); | 
|  | 4270 | } | 
|  | 4271 |  | 
|  | 4272 | if (ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4273 | IPS_LD_OFFLINE | 
|  | 4274 | && ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4275 | IPS_LD_FREE | 
|  | 4276 | && ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4277 | IPS_LD_CRS | 
|  | 4278 | && ha->logical_drive_info->drive_info[scb->target_id].state != | 
|  | 4279 | IPS_LD_SYS) | 
|  | 4280 | return (1); | 
|  | 4281 | else | 
|  | 4282 | return (0); | 
|  | 4283 | } | 
|  | 4284 |  | 
|  | 4285 | /****************************************************************************/ | 
|  | 4286 | /*                                                                          */ | 
|  | 4287 | /* Routine Name: ips_inquiry                                                */ | 
|  | 4288 | /*                                                                          */ | 
|  | 4289 | /* Routine Description:                                                     */ | 
|  | 4290 | /*                                                                          */ | 
|  | 4291 | /*   Simulate an inquiry command to a logical drive                         */ | 
|  | 4292 | /*                                                                          */ | 
|  | 4293 | /****************************************************************************/ | 
|  | 4294 | static int | 
|  | 4295 | ips_inquiry(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4296 | { | 
|  | 4297 | IPS_SCSI_INQ_DATA inquiry; | 
|  | 4298 |  | 
|  | 4299 | METHOD_TRACE("ips_inquiry", 1); | 
|  | 4300 |  | 
|  | 4301 | memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA)); | 
|  | 4302 |  | 
|  | 4303 | inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD; | 
|  | 4304 | inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED; | 
|  | 4305 | inquiry.Version = IPS_SCSI_INQ_REV2; | 
|  | 4306 | inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2; | 
|  | 4307 | inquiry.AdditionalLength = 31; | 
|  | 4308 | inquiry.Flags[0] = IPS_SCSI_INQ_Address16; | 
|  | 4309 | inquiry.Flags[1] = | 
|  | 4310 | IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue; | 
|  | 4311 | strncpy(inquiry.VendorId, "IBM     ", 8); | 
|  | 4312 | strncpy(inquiry.ProductId, "SERVERAID       ", 16); | 
|  | 4313 | strncpy(inquiry.ProductRevisionLevel, "1.00", 4); | 
|  | 4314 |  | 
|  | 4315 | ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry)); | 
|  | 4316 |  | 
|  | 4317 | return (1); | 
|  | 4318 | } | 
|  | 4319 |  | 
|  | 4320 | /****************************************************************************/ | 
|  | 4321 | /*                                                                          */ | 
|  | 4322 | /* Routine Name: ips_rdcap                                                  */ | 
|  | 4323 | /*                                                                          */ | 
|  | 4324 | /* Routine Description:                                                     */ | 
|  | 4325 | /*                                                                          */ | 
|  | 4326 | /*   Simulate a read capacity command to a logical drive                    */ | 
|  | 4327 | /*                                                                          */ | 
|  | 4328 | /****************************************************************************/ | 
|  | 4329 | static int | 
|  | 4330 | ips_rdcap(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4331 | { | 
|  | 4332 | IPS_SCSI_CAPACITY cap; | 
|  | 4333 |  | 
|  | 4334 | METHOD_TRACE("ips_rdcap", 1); | 
|  | 4335 |  | 
|  | 4336 | if (scb->scsi_cmd->bufflen < 8) | 
|  | 4337 | return (0); | 
|  | 4338 |  | 
|  | 4339 | cap.lba = | 
|  | 4340 | cpu_to_be32(le32_to_cpu | 
|  | 4341 | (ha->logical_drive_info-> | 
|  | 4342 | drive_info[scb->target_id].sector_count) - 1); | 
|  | 4343 | cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE); | 
|  | 4344 |  | 
|  | 4345 | ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap)); | 
|  | 4346 |  | 
|  | 4347 | return (1); | 
|  | 4348 | } | 
|  | 4349 |  | 
|  | 4350 | /****************************************************************************/ | 
|  | 4351 | /*                                                                          */ | 
|  | 4352 | /* Routine Name: ips_msense                                                 */ | 
|  | 4353 | /*                                                                          */ | 
|  | 4354 | /* Routine Description:                                                     */ | 
|  | 4355 | /*                                                                          */ | 
|  | 4356 | /*   Simulate a mode sense command to a logical drive                       */ | 
|  | 4357 | /*                                                                          */ | 
|  | 4358 | /****************************************************************************/ | 
|  | 4359 | static int | 
|  | 4360 | ips_msense(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4361 | { | 
|  | 4362 | uint16_t heads; | 
|  | 4363 | uint16_t sectors; | 
|  | 4364 | uint32_t cylinders; | 
|  | 4365 | IPS_SCSI_MODE_PAGE_DATA mdata; | 
|  | 4366 |  | 
|  | 4367 | METHOD_TRACE("ips_msense", 1); | 
|  | 4368 |  | 
|  | 4369 | if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 && | 
|  | 4370 | (ha->enq->ucMiscFlag & 0x8) == 0) { | 
|  | 4371 | heads = IPS_NORM_HEADS; | 
|  | 4372 | sectors = IPS_NORM_SECTORS; | 
|  | 4373 | } else { | 
|  | 4374 | heads = IPS_COMP_HEADS; | 
|  | 4375 | sectors = IPS_COMP_SECTORS; | 
|  | 4376 | } | 
|  | 4377 |  | 
|  | 4378 | cylinders = | 
|  | 4379 | (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) - | 
|  | 4380 | 1) / (heads * sectors); | 
|  | 4381 |  | 
|  | 4382 | memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA)); | 
|  | 4383 |  | 
|  | 4384 | mdata.hdr.BlockDescLength = 8; | 
|  | 4385 |  | 
|  | 4386 | switch (scb->scsi_cmd->cmnd[2] & 0x3f) { | 
|  | 4387 | case 0x03:		/* page 3 */ | 
|  | 4388 | mdata.pdata.pg3.PageCode = 3; | 
|  | 4389 | mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3); | 
|  | 4390 | mdata.hdr.DataLength = | 
|  | 4391 | 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength; | 
|  | 4392 | mdata.pdata.pg3.TracksPerZone = 0; | 
|  | 4393 | mdata.pdata.pg3.AltSectorsPerZone = 0; | 
|  | 4394 | mdata.pdata.pg3.AltTracksPerZone = 0; | 
|  | 4395 | mdata.pdata.pg3.AltTracksPerVolume = 0; | 
|  | 4396 | mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors); | 
|  | 4397 | mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE); | 
|  | 4398 | mdata.pdata.pg3.Interleave = cpu_to_be16(1); | 
|  | 4399 | mdata.pdata.pg3.TrackSkew = 0; | 
|  | 4400 | mdata.pdata.pg3.CylinderSkew = 0; | 
|  | 4401 | mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector; | 
|  | 4402 | break; | 
|  | 4403 |  | 
|  | 4404 | case 0x4: | 
|  | 4405 | mdata.pdata.pg4.PageCode = 4; | 
|  | 4406 | mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4); | 
|  | 4407 | mdata.hdr.DataLength = | 
|  | 4408 | 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength; | 
|  | 4409 | mdata.pdata.pg4.CylindersHigh = | 
|  | 4410 | cpu_to_be16((cylinders >> 8) & 0xFFFF); | 
|  | 4411 | mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF); | 
|  | 4412 | mdata.pdata.pg4.Heads = heads; | 
|  | 4413 | mdata.pdata.pg4.WritePrecompHigh = 0; | 
|  | 4414 | mdata.pdata.pg4.WritePrecompLow = 0; | 
|  | 4415 | mdata.pdata.pg4.ReducedWriteCurrentHigh = 0; | 
|  | 4416 | mdata.pdata.pg4.ReducedWriteCurrentLow = 0; | 
|  | 4417 | mdata.pdata.pg4.StepRate = cpu_to_be16(1); | 
|  | 4418 | mdata.pdata.pg4.LandingZoneHigh = 0; | 
|  | 4419 | mdata.pdata.pg4.LandingZoneLow = 0; | 
|  | 4420 | mdata.pdata.pg4.flags = 0; | 
|  | 4421 | mdata.pdata.pg4.RotationalOffset = 0; | 
|  | 4422 | mdata.pdata.pg4.MediumRotationRate = 0; | 
|  | 4423 | break; | 
|  | 4424 | case 0x8: | 
|  | 4425 | mdata.pdata.pg8.PageCode = 8; | 
|  | 4426 | mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8); | 
|  | 4427 | mdata.hdr.DataLength = | 
|  | 4428 | 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength; | 
|  | 4429 | /* everything else is left set to 0 */ | 
|  | 4430 | break; | 
|  | 4431 |  | 
|  | 4432 | default: | 
|  | 4433 | return (0); | 
|  | 4434 | }			/* end switch */ | 
|  | 4435 |  | 
|  | 4436 | ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata)); | 
|  | 4437 |  | 
|  | 4438 | return (1); | 
|  | 4439 | } | 
|  | 4440 |  | 
|  | 4441 | /****************************************************************************/ | 
|  | 4442 | /*                                                                          */ | 
|  | 4443 | /* Routine Name: ips_reqsen                                                 */ | 
|  | 4444 | /*                                                                          */ | 
|  | 4445 | /* Routine Description:                                                     */ | 
|  | 4446 | /*                                                                          */ | 
|  | 4447 | /*   Simulate a request sense command to a logical drive                    */ | 
|  | 4448 | /*                                                                          */ | 
|  | 4449 | /****************************************************************************/ | 
|  | 4450 | static int | 
|  | 4451 | ips_reqsen(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4452 | { | 
|  | 4453 | IPS_SCSI_REQSEN reqsen; | 
|  | 4454 |  | 
|  | 4455 | METHOD_TRACE("ips_reqsen", 1); | 
|  | 4456 |  | 
|  | 4457 | memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN)); | 
|  | 4458 |  | 
|  | 4459 | reqsen.ResponseCode = | 
|  | 4460 | IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR; | 
|  | 4461 | reqsen.AdditionalLength = 10; | 
|  | 4462 | reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE; | 
|  | 4463 | reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE; | 
|  | 4464 |  | 
|  | 4465 | ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen)); | 
|  | 4466 |  | 
|  | 4467 | return (1); | 
|  | 4468 | } | 
|  | 4469 |  | 
|  | 4470 | /****************************************************************************/ | 
|  | 4471 | /*                                                                          */ | 
|  | 4472 | /* Routine Name: ips_free                                                   */ | 
|  | 4473 | /*                                                                          */ | 
|  | 4474 | /* Routine Description:                                                     */ | 
|  | 4475 | /*                                                                          */ | 
|  | 4476 | /*   Free any allocated space for this controller                           */ | 
|  | 4477 | /*                                                                          */ | 
|  | 4478 | /****************************************************************************/ | 
|  | 4479 | static void | 
|  | 4480 | ips_free(ips_ha_t * ha) | 
|  | 4481 | { | 
|  | 4482 |  | 
|  | 4483 | METHOD_TRACE("ips_free", 1); | 
|  | 4484 |  | 
|  | 4485 | if (ha) { | 
|  | 4486 | if (ha->enq) { | 
|  | 4487 | pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ), | 
|  | 4488 | ha->enq, ha->enq_busaddr); | 
|  | 4489 | ha->enq = NULL; | 
|  | 4490 | } | 
|  | 4491 |  | 
|  | 4492 | if (ha->conf) { | 
|  | 4493 | kfree(ha->conf); | 
|  | 4494 | ha->conf = NULL; | 
|  | 4495 | } | 
|  | 4496 |  | 
|  | 4497 | if (ha->adapt) { | 
|  | 4498 | pci_free_consistent(ha->pcidev, | 
|  | 4499 | sizeof (IPS_ADAPTER) + | 
|  | 4500 | sizeof (IPS_IO_CMD), ha->adapt, | 
|  | 4501 | ha->adapt->hw_status_start); | 
|  | 4502 | ha->adapt = NULL; | 
|  | 4503 | } | 
|  | 4504 |  | 
|  | 4505 | if (ha->logical_drive_info) { | 
|  | 4506 | pci_free_consistent(ha->pcidev, | 
|  | 4507 | sizeof (IPS_LD_INFO), | 
|  | 4508 | ha->logical_drive_info, | 
|  | 4509 | ha->logical_drive_info_dma_addr); | 
|  | 4510 | ha->logical_drive_info = NULL; | 
|  | 4511 | } | 
|  | 4512 |  | 
|  | 4513 | if (ha->nvram) { | 
|  | 4514 | kfree(ha->nvram); | 
|  | 4515 | ha->nvram = NULL; | 
|  | 4516 | } | 
|  | 4517 |  | 
|  | 4518 | if (ha->subsys) { | 
|  | 4519 | kfree(ha->subsys); | 
|  | 4520 | ha->subsys = NULL; | 
|  | 4521 | } | 
|  | 4522 |  | 
|  | 4523 | if (ha->ioctl_data) { | 
|  | 4524 | pci_free_consistent(ha->pcidev, ha->ioctl_len, | 
|  | 4525 | ha->ioctl_data, ha->ioctl_busaddr); | 
|  | 4526 | ha->ioctl_data = NULL; | 
|  | 4527 | ha->ioctl_datasize = 0; | 
|  | 4528 | ha->ioctl_len = 0; | 
|  | 4529 | } | 
|  | 4530 | ips_deallocatescbs(ha, ha->max_cmds); | 
|  | 4531 |  | 
|  | 4532 | /* free memory mapped (if applicable) */ | 
|  | 4533 | if (ha->mem_ptr) { | 
|  | 4534 | iounmap(ha->ioremap_ptr); | 
|  | 4535 | ha->ioremap_ptr = NULL; | 
|  | 4536 | ha->mem_ptr = NULL; | 
|  | 4537 | } | 
|  | 4538 |  | 
|  | 4539 | if (ha->mem_addr) | 
|  | 4540 | release_mem_region(ha->mem_addr, ha->mem_len); | 
|  | 4541 | ha->mem_addr = 0; | 
|  | 4542 |  | 
|  | 4543 | } | 
|  | 4544 | } | 
|  | 4545 |  | 
|  | 4546 | /****************************************************************************/ | 
|  | 4547 | /*                                                                          */ | 
|  | 4548 | /* Routine Name: ips_deallocatescbs                                         */ | 
|  | 4549 | /*                                                                          */ | 
|  | 4550 | /* Routine Description:                                                     */ | 
|  | 4551 | /*                                                                          */ | 
|  | 4552 | /*   Free the command blocks                                                */ | 
|  | 4553 | /*                                                                          */ | 
|  | 4554 | /****************************************************************************/ | 
|  | 4555 | static int | 
|  | 4556 | ips_deallocatescbs(ips_ha_t * ha, int cmds) | 
|  | 4557 | { | 
|  | 4558 | if (ha->scbs) { | 
|  | 4559 | pci_free_consistent(ha->pcidev, | 
|  | 4560 | IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds, | 
|  | 4561 | ha->scbs->sg_list.list, | 
|  | 4562 | ha->scbs->sg_busaddr); | 
|  | 4563 | pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds, | 
|  | 4564 | ha->scbs, ha->scbs->scb_busaddr); | 
|  | 4565 | ha->scbs = NULL; | 
|  | 4566 | }			/* end if */ | 
|  | 4567 | return 1; | 
|  | 4568 | } | 
|  | 4569 |  | 
|  | 4570 | /****************************************************************************/ | 
|  | 4571 | /*                                                                          */ | 
|  | 4572 | /* Routine Name: ips_allocatescbs                                           */ | 
|  | 4573 | /*                                                                          */ | 
|  | 4574 | /* Routine Description:                                                     */ | 
|  | 4575 | /*                                                                          */ | 
|  | 4576 | /*   Allocate the command blocks                                            */ | 
|  | 4577 | /*                                                                          */ | 
|  | 4578 | /****************************************************************************/ | 
|  | 4579 | static int | 
|  | 4580 | ips_allocatescbs(ips_ha_t * ha) | 
|  | 4581 | { | 
|  | 4582 | ips_scb_t *scb_p; | 
|  | 4583 | IPS_SG_LIST ips_sg; | 
|  | 4584 | int i; | 
|  | 4585 | dma_addr_t command_dma, sg_dma; | 
|  | 4586 |  | 
|  | 4587 | METHOD_TRACE("ips_allocatescbs", 1); | 
|  | 4588 |  | 
|  | 4589 | /* Allocate memory for the SCBs */ | 
|  | 4590 | ha->scbs = | 
|  | 4591 | pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t), | 
|  | 4592 | &command_dma); | 
|  | 4593 | if (ha->scbs == NULL) | 
|  | 4594 | return 0; | 
|  | 4595 | ips_sg.list = | 
|  | 4596 | pci_alloc_consistent(ha->pcidev, | 
|  | 4597 | IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * | 
|  | 4598 | ha->max_cmds, &sg_dma); | 
|  | 4599 | if (ips_sg.list == NULL) { | 
|  | 4600 | pci_free_consistent(ha->pcidev, | 
|  | 4601 | ha->max_cmds * sizeof (ips_scb_t), ha->scbs, | 
|  | 4602 | command_dma); | 
|  | 4603 | return 0; | 
|  | 4604 | } | 
|  | 4605 |  | 
|  | 4606 | memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t)); | 
|  | 4607 |  | 
|  | 4608 | for (i = 0; i < ha->max_cmds; i++) { | 
|  | 4609 | scb_p = &ha->scbs[i]; | 
|  | 4610 | scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i; | 
|  | 4611 | /* set up S/G list */ | 
|  | 4612 | if (IPS_USE_ENH_SGLIST(ha)) { | 
|  | 4613 | scb_p->sg_list.enh_list = | 
|  | 4614 | ips_sg.enh_list + i * IPS_MAX_SG; | 
|  | 4615 | scb_p->sg_busaddr = | 
|  | 4616 | sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; | 
|  | 4617 | } else { | 
|  | 4618 | scb_p->sg_list.std_list = | 
|  | 4619 | ips_sg.std_list + i * IPS_MAX_SG; | 
|  | 4620 | scb_p->sg_busaddr = | 
|  | 4621 | sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; | 
|  | 4622 | } | 
|  | 4623 |  | 
|  | 4624 | /* add to the free list */ | 
|  | 4625 | if (i < ha->max_cmds - 1) { | 
|  | 4626 | scb_p->q_next = ha->scb_freelist; | 
|  | 4627 | ha->scb_freelist = scb_p; | 
|  | 4628 | } | 
|  | 4629 | } | 
|  | 4630 |  | 
|  | 4631 | /* success */ | 
|  | 4632 | return (1); | 
|  | 4633 | } | 
|  | 4634 |  | 
|  | 4635 | /****************************************************************************/ | 
|  | 4636 | /*                                                                          */ | 
|  | 4637 | /* Routine Name: ips_init_scb                                               */ | 
|  | 4638 | /*                                                                          */ | 
|  | 4639 | /* Routine Description:                                                     */ | 
|  | 4640 | /*                                                                          */ | 
|  | 4641 | /*   Initialize a CCB to default values                                     */ | 
|  | 4642 | /*                                                                          */ | 
|  | 4643 | /****************************************************************************/ | 
|  | 4644 | static void | 
|  | 4645 | ips_init_scb(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4646 | { | 
|  | 4647 | IPS_SG_LIST sg_list; | 
|  | 4648 | uint32_t cmd_busaddr, sg_busaddr; | 
|  | 4649 | METHOD_TRACE("ips_init_scb", 1); | 
|  | 4650 |  | 
|  | 4651 | if (scb == NULL) | 
|  | 4652 | return; | 
|  | 4653 |  | 
|  | 4654 | sg_list.list = scb->sg_list.list; | 
|  | 4655 | cmd_busaddr = scb->scb_busaddr; | 
|  | 4656 | sg_busaddr = scb->sg_busaddr; | 
|  | 4657 | /* zero fill */ | 
|  | 4658 | memset(scb, 0, sizeof (ips_scb_t)); | 
|  | 4659 | memset(ha->dummy, 0, sizeof (IPS_IO_CMD)); | 
|  | 4660 |  | 
|  | 4661 | /* Initialize dummy command bucket */ | 
|  | 4662 | ha->dummy->op_code = 0xFF; | 
|  | 4663 | ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start | 
|  | 4664 | + sizeof (IPS_ADAPTER)); | 
|  | 4665 | ha->dummy->command_id = IPS_MAX_CMDS; | 
|  | 4666 |  | 
|  | 4667 | /* set bus address of scb */ | 
|  | 4668 | scb->scb_busaddr = cmd_busaddr; | 
|  | 4669 | scb->sg_busaddr = sg_busaddr; | 
|  | 4670 | scb->sg_list.list = sg_list.list; | 
|  | 4671 |  | 
|  | 4672 | /* Neptune Fix */ | 
|  | 4673 | scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE); | 
|  | 4674 | scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start | 
|  | 4675 | + sizeof (IPS_ADAPTER)); | 
|  | 4676 | } | 
|  | 4677 |  | 
|  | 4678 | /****************************************************************************/ | 
|  | 4679 | /*                                                                          */ | 
|  | 4680 | /* Routine Name: ips_get_scb                                                */ | 
|  | 4681 | /*                                                                          */ | 
|  | 4682 | /* Routine Description:                                                     */ | 
|  | 4683 | /*                                                                          */ | 
|  | 4684 | /*   Initialize a CCB to default values                                     */ | 
|  | 4685 | /*                                                                          */ | 
|  | 4686 | /* ASSUMED to be callled from within a lock                                 */ | 
|  | 4687 | /*                                                                          */ | 
|  | 4688 | /****************************************************************************/ | 
|  | 4689 | static ips_scb_t * | 
|  | 4690 | ips_getscb(ips_ha_t * ha) | 
|  | 4691 | { | 
|  | 4692 | ips_scb_t *scb; | 
|  | 4693 |  | 
|  | 4694 | METHOD_TRACE("ips_getscb", 1); | 
|  | 4695 |  | 
|  | 4696 | if ((scb = ha->scb_freelist) == NULL) { | 
|  | 4697 |  | 
|  | 4698 | return (NULL); | 
|  | 4699 | } | 
|  | 4700 |  | 
|  | 4701 | ha->scb_freelist = scb->q_next; | 
|  | 4702 | scb->flags = 0; | 
|  | 4703 | scb->q_next = NULL; | 
|  | 4704 |  | 
|  | 4705 | ips_init_scb(ha, scb); | 
|  | 4706 |  | 
|  | 4707 | return (scb); | 
|  | 4708 | } | 
|  | 4709 |  | 
|  | 4710 | /****************************************************************************/ | 
|  | 4711 | /*                                                                          */ | 
|  | 4712 | /* Routine Name: ips_free_scb                                               */ | 
|  | 4713 | /*                                                                          */ | 
|  | 4714 | /* Routine Description:                                                     */ | 
|  | 4715 | /*                                                                          */ | 
|  | 4716 | /*   Return an unused CCB back to the free list                             */ | 
|  | 4717 | /*                                                                          */ | 
|  | 4718 | /* ASSUMED to be called from within a lock                                  */ | 
|  | 4719 | /*                                                                          */ | 
|  | 4720 | /****************************************************************************/ | 
|  | 4721 | static void | 
|  | 4722 | ips_freescb(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 4723 | { | 
|  | 4724 |  | 
|  | 4725 | METHOD_TRACE("ips_freescb", 1); | 
|  | 4726 | if (scb->flags & IPS_SCB_MAP_SG) | 
|  | 4727 | pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer, | 
|  | 4728 | scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb)); | 
|  | 4729 | else if (scb->flags & IPS_SCB_MAP_SINGLE) | 
|  | 4730 | pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len, | 
|  | 4731 | IPS_DMA_DIR(scb)); | 
|  | 4732 |  | 
|  | 4733 | /* check to make sure this is not our "special" scb */ | 
|  | 4734 | if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { | 
|  | 4735 | scb->q_next = ha->scb_freelist; | 
|  | 4736 | ha->scb_freelist = scb; | 
|  | 4737 | } | 
|  | 4738 | } | 
|  | 4739 |  | 
|  | 4740 | /****************************************************************************/ | 
|  | 4741 | /*                                                                          */ | 
|  | 4742 | /* Routine Name: ips_isinit_copperhead                                      */ | 
|  | 4743 | /*                                                                          */ | 
|  | 4744 | /* Routine Description:                                                     */ | 
|  | 4745 | /*                                                                          */ | 
|  | 4746 | /*   Is controller initialized ?                                            */ | 
|  | 4747 | /*                                                                          */ | 
|  | 4748 | /****************************************************************************/ | 
|  | 4749 | static int | 
|  | 4750 | ips_isinit_copperhead(ips_ha_t * ha) | 
|  | 4751 | { | 
|  | 4752 | uint8_t scpr; | 
|  | 4753 | uint8_t isr; | 
|  | 4754 |  | 
|  | 4755 | METHOD_TRACE("ips_isinit_copperhead", 1); | 
|  | 4756 |  | 
|  | 4757 | isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 4758 | scpr = inb(ha->io_addr + IPS_REG_SCPR); | 
|  | 4759 |  | 
|  | 4760 | if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) | 
|  | 4761 | return (0); | 
|  | 4762 | else | 
|  | 4763 | return (1); | 
|  | 4764 | } | 
|  | 4765 |  | 
|  | 4766 | /****************************************************************************/ | 
|  | 4767 | /*                                                                          */ | 
|  | 4768 | /* Routine Name: ips_isinit_copperhead_memio                                */ | 
|  | 4769 | /*                                                                          */ | 
|  | 4770 | /* Routine Description:                                                     */ | 
|  | 4771 | /*                                                                          */ | 
|  | 4772 | /*   Is controller initialized ?                                            */ | 
|  | 4773 | /*                                                                          */ | 
|  | 4774 | /****************************************************************************/ | 
|  | 4775 | static int | 
|  | 4776 | ips_isinit_copperhead_memio(ips_ha_t * ha) | 
|  | 4777 | { | 
|  | 4778 | uint8_t isr = 0; | 
|  | 4779 | uint8_t scpr; | 
|  | 4780 |  | 
|  | 4781 | METHOD_TRACE("ips_is_init_copperhead_memio", 1); | 
|  | 4782 |  | 
|  | 4783 | isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 4784 | scpr = readb(ha->mem_ptr + IPS_REG_SCPR); | 
|  | 4785 |  | 
|  | 4786 | if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) | 
|  | 4787 | return (0); | 
|  | 4788 | else | 
|  | 4789 | return (1); | 
|  | 4790 | } | 
|  | 4791 |  | 
|  | 4792 | /****************************************************************************/ | 
|  | 4793 | /*                                                                          */ | 
|  | 4794 | /* Routine Name: ips_isinit_morpheus                                        */ | 
|  | 4795 | /*                                                                          */ | 
|  | 4796 | /* Routine Description:                                                     */ | 
|  | 4797 | /*                                                                          */ | 
|  | 4798 | /*   Is controller initialized ?                                            */ | 
|  | 4799 | /*                                                                          */ | 
|  | 4800 | /****************************************************************************/ | 
|  | 4801 | static int | 
|  | 4802 | ips_isinit_morpheus(ips_ha_t * ha) | 
|  | 4803 | { | 
|  | 4804 | uint32_t post; | 
|  | 4805 | uint32_t bits; | 
|  | 4806 |  | 
|  | 4807 | METHOD_TRACE("ips_is_init_morpheus", 1); | 
|  | 4808 |  | 
|  | 4809 | post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); | 
|  | 4810 | bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 4811 |  | 
|  | 4812 | if (post == 0) | 
|  | 4813 | return (0); | 
|  | 4814 | else if (bits & 0x3) | 
|  | 4815 | return (0); | 
|  | 4816 | else | 
|  | 4817 | return (1); | 
|  | 4818 | } | 
|  | 4819 |  | 
|  | 4820 | /****************************************************************************/ | 
|  | 4821 | /*                                                                          */ | 
|  | 4822 | /* Routine Name: ips_enable_int_copperhead                                  */ | 
|  | 4823 | /*                                                                          */ | 
|  | 4824 | /* Routine Description:                                                     */ | 
|  | 4825 | /*   Turn on interrupts                                                     */ | 
|  | 4826 | /*                                                                          */ | 
|  | 4827 | /****************************************************************************/ | 
|  | 4828 | static void | 
|  | 4829 | ips_enable_int_copperhead(ips_ha_t * ha) | 
|  | 4830 | { | 
|  | 4831 | METHOD_TRACE("ips_enable_int_copperhead", 1); | 
|  | 4832 |  | 
|  | 4833 | outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI); | 
|  | 4834 | inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/ | 
|  | 4835 | } | 
|  | 4836 |  | 
|  | 4837 | /****************************************************************************/ | 
|  | 4838 | /*                                                                          */ | 
|  | 4839 | /* Routine Name: ips_enable_int_copperhead_memio                            */ | 
|  | 4840 | /*                                                                          */ | 
|  | 4841 | /* Routine Description:                                                     */ | 
|  | 4842 | /*   Turn on interrupts                                                     */ | 
|  | 4843 | /*                                                                          */ | 
|  | 4844 | /****************************************************************************/ | 
|  | 4845 | static void | 
|  | 4846 | ips_enable_int_copperhead_memio(ips_ha_t * ha) | 
|  | 4847 | { | 
|  | 4848 | METHOD_TRACE("ips_enable_int_copperhead_memio", 1); | 
|  | 4849 |  | 
|  | 4850 | writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); | 
|  | 4851 | readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/ | 
|  | 4852 | } | 
|  | 4853 |  | 
|  | 4854 | /****************************************************************************/ | 
|  | 4855 | /*                                                                          */ | 
|  | 4856 | /* Routine Name: ips_enable_int_morpheus                                    */ | 
|  | 4857 | /*                                                                          */ | 
|  | 4858 | /* Routine Description:                                                     */ | 
|  | 4859 | /*   Turn on interrupts                                                     */ | 
|  | 4860 | /*                                                                          */ | 
|  | 4861 | /****************************************************************************/ | 
|  | 4862 | static void | 
|  | 4863 | ips_enable_int_morpheus(ips_ha_t * ha) | 
|  | 4864 | { | 
|  | 4865 | uint32_t Oimr; | 
|  | 4866 |  | 
|  | 4867 | METHOD_TRACE("ips_enable_int_morpheus", 1); | 
|  | 4868 |  | 
|  | 4869 | Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 4870 | Oimr &= ~0x08; | 
|  | 4871 | writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 4872 | readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/ | 
|  | 4873 | } | 
|  | 4874 |  | 
|  | 4875 | /****************************************************************************/ | 
|  | 4876 | /*                                                                          */ | 
|  | 4877 | /* Routine Name: ips_init_copperhead                                        */ | 
|  | 4878 | /*                                                                          */ | 
|  | 4879 | /* Routine Description:                                                     */ | 
|  | 4880 | /*                                                                          */ | 
|  | 4881 | /*   Initialize a copperhead controller                                     */ | 
|  | 4882 | /*                                                                          */ | 
|  | 4883 | /****************************************************************************/ | 
|  | 4884 | static int | 
|  | 4885 | ips_init_copperhead(ips_ha_t * ha) | 
|  | 4886 | { | 
|  | 4887 | uint8_t Isr; | 
|  | 4888 | uint8_t Cbsp; | 
|  | 4889 | uint8_t PostByte[IPS_MAX_POST_BYTES]; | 
|  | 4890 | uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; | 
|  | 4891 | int i, j; | 
|  | 4892 |  | 
|  | 4893 | METHOD_TRACE("ips_init_copperhead", 1); | 
|  | 4894 |  | 
|  | 4895 | for (i = 0; i < IPS_MAX_POST_BYTES; i++) { | 
|  | 4896 | for (j = 0; j < 45; j++) { | 
|  | 4897 | Isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 4898 | if (Isr & IPS_BIT_GHI) | 
|  | 4899 | break; | 
|  | 4900 |  | 
|  | 4901 | /* Delay for 1 Second */ | 
|  | 4902 | MDELAY(IPS_ONE_SEC); | 
|  | 4903 | } | 
|  | 4904 |  | 
|  | 4905 | if (j >= 45) | 
|  | 4906 | /* error occurred */ | 
|  | 4907 | return (0); | 
|  | 4908 |  | 
|  | 4909 | PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); | 
|  | 4910 | outb(Isr, ha->io_addr + IPS_REG_HISR); | 
|  | 4911 | } | 
|  | 4912 |  | 
|  | 4913 | if (PostByte[0] < IPS_GOOD_POST_STATUS) { | 
|  | 4914 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 4915 | "reset controller fails (post status %x %x).\n", | 
|  | 4916 | PostByte[0], PostByte[1]); | 
|  | 4917 |  | 
|  | 4918 | return (0); | 
|  | 4919 | } | 
|  | 4920 |  | 
|  | 4921 | for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { | 
|  | 4922 | for (j = 0; j < 240; j++) { | 
|  | 4923 | Isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 4924 | if (Isr & IPS_BIT_GHI) | 
|  | 4925 | break; | 
|  | 4926 |  | 
|  | 4927 | /* Delay for 1 Second */ | 
|  | 4928 | MDELAY(IPS_ONE_SEC); | 
|  | 4929 | } | 
|  | 4930 |  | 
|  | 4931 | if (j >= 240) | 
|  | 4932 | /* error occurred */ | 
|  | 4933 | return (0); | 
|  | 4934 |  | 
|  | 4935 | ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); | 
|  | 4936 | outb(Isr, ha->io_addr + IPS_REG_HISR); | 
|  | 4937 | } | 
|  | 4938 |  | 
|  | 4939 | for (i = 0; i < 240; i++) { | 
|  | 4940 | Cbsp = inb(ha->io_addr + IPS_REG_CBSP); | 
|  | 4941 |  | 
|  | 4942 | if ((Cbsp & IPS_BIT_OP) == 0) | 
|  | 4943 | break; | 
|  | 4944 |  | 
|  | 4945 | /* Delay for 1 Second */ | 
|  | 4946 | MDELAY(IPS_ONE_SEC); | 
|  | 4947 | } | 
|  | 4948 |  | 
|  | 4949 | if (i >= 240) | 
|  | 4950 | /* reset failed */ | 
|  | 4951 | return (0); | 
|  | 4952 |  | 
|  | 4953 | /* setup CCCR */ | 
|  | 4954 | outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR); | 
|  | 4955 |  | 
|  | 4956 | /* Enable busmastering */ | 
|  | 4957 | outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); | 
|  | 4958 |  | 
|  | 4959 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 4960 | /* fix for anaconda64 */ | 
|  | 4961 | outl(0, ha->io_addr + IPS_REG_NDAE); | 
|  | 4962 |  | 
|  | 4963 | /* Enable interrupts */ | 
|  | 4964 | outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); | 
|  | 4965 |  | 
|  | 4966 | return (1); | 
|  | 4967 | } | 
|  | 4968 |  | 
|  | 4969 | /****************************************************************************/ | 
|  | 4970 | /*                                                                          */ | 
|  | 4971 | /* Routine Name: ips_init_copperhead_memio                                  */ | 
|  | 4972 | /*                                                                          */ | 
|  | 4973 | /* Routine Description:                                                     */ | 
|  | 4974 | /*                                                                          */ | 
|  | 4975 | /*   Initialize a copperhead controller with memory mapped I/O              */ | 
|  | 4976 | /*                                                                          */ | 
|  | 4977 | /****************************************************************************/ | 
|  | 4978 | static int | 
|  | 4979 | ips_init_copperhead_memio(ips_ha_t * ha) | 
|  | 4980 | { | 
|  | 4981 | uint8_t Isr = 0; | 
|  | 4982 | uint8_t Cbsp; | 
|  | 4983 | uint8_t PostByte[IPS_MAX_POST_BYTES]; | 
|  | 4984 | uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; | 
|  | 4985 | int i, j; | 
|  | 4986 |  | 
|  | 4987 | METHOD_TRACE("ips_init_copperhead_memio", 1); | 
|  | 4988 |  | 
|  | 4989 | for (i = 0; i < IPS_MAX_POST_BYTES; i++) { | 
|  | 4990 | for (j = 0; j < 45; j++) { | 
|  | 4991 | Isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 4992 | if (Isr & IPS_BIT_GHI) | 
|  | 4993 | break; | 
|  | 4994 |  | 
|  | 4995 | /* Delay for 1 Second */ | 
|  | 4996 | MDELAY(IPS_ONE_SEC); | 
|  | 4997 | } | 
|  | 4998 |  | 
|  | 4999 | if (j >= 45) | 
|  | 5000 | /* error occurred */ | 
|  | 5001 | return (0); | 
|  | 5002 |  | 
|  | 5003 | PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); | 
|  | 5004 | writeb(Isr, ha->mem_ptr + IPS_REG_HISR); | 
|  | 5005 | } | 
|  | 5006 |  | 
|  | 5007 | if (PostByte[0] < IPS_GOOD_POST_STATUS) { | 
|  | 5008 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5009 | "reset controller fails (post status %x %x).\n", | 
|  | 5010 | PostByte[0], PostByte[1]); | 
|  | 5011 |  | 
|  | 5012 | return (0); | 
|  | 5013 | } | 
|  | 5014 |  | 
|  | 5015 | for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { | 
|  | 5016 | for (j = 0; j < 240; j++) { | 
|  | 5017 | Isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 5018 | if (Isr & IPS_BIT_GHI) | 
|  | 5019 | break; | 
|  | 5020 |  | 
|  | 5021 | /* Delay for 1 Second */ | 
|  | 5022 | MDELAY(IPS_ONE_SEC); | 
|  | 5023 | } | 
|  | 5024 |  | 
|  | 5025 | if (j >= 240) | 
|  | 5026 | /* error occurred */ | 
|  | 5027 | return (0); | 
|  | 5028 |  | 
|  | 5029 | ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); | 
|  | 5030 | writeb(Isr, ha->mem_ptr + IPS_REG_HISR); | 
|  | 5031 | } | 
|  | 5032 |  | 
|  | 5033 | for (i = 0; i < 240; i++) { | 
|  | 5034 | Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP); | 
|  | 5035 |  | 
|  | 5036 | if ((Cbsp & IPS_BIT_OP) == 0) | 
|  | 5037 | break; | 
|  | 5038 |  | 
|  | 5039 | /* Delay for 1 Second */ | 
|  | 5040 | MDELAY(IPS_ONE_SEC); | 
|  | 5041 | } | 
|  | 5042 |  | 
|  | 5043 | if (i >= 240) | 
|  | 5044 | /* error occurred */ | 
|  | 5045 | return (0); | 
|  | 5046 |  | 
|  | 5047 | /* setup CCCR */ | 
|  | 5048 | writel(0x1010, ha->mem_ptr + IPS_REG_CCCR); | 
|  | 5049 |  | 
|  | 5050 | /* Enable busmastering */ | 
|  | 5051 | writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); | 
|  | 5052 |  | 
|  | 5053 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 5054 | /* fix for anaconda64 */ | 
|  | 5055 | writel(0, ha->mem_ptr + IPS_REG_NDAE); | 
|  | 5056 |  | 
|  | 5057 | /* Enable interrupts */ | 
|  | 5058 | writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); | 
|  | 5059 |  | 
|  | 5060 | /* if we get here then everything went OK */ | 
|  | 5061 | return (1); | 
|  | 5062 | } | 
|  | 5063 |  | 
|  | 5064 | /****************************************************************************/ | 
|  | 5065 | /*                                                                          */ | 
|  | 5066 | /* Routine Name: ips_init_morpheus                                          */ | 
|  | 5067 | /*                                                                          */ | 
|  | 5068 | /* Routine Description:                                                     */ | 
|  | 5069 | /*                                                                          */ | 
|  | 5070 | /*   Initialize a morpheus controller                                       */ | 
|  | 5071 | /*                                                                          */ | 
|  | 5072 | /****************************************************************************/ | 
|  | 5073 | static int | 
|  | 5074 | ips_init_morpheus(ips_ha_t * ha) | 
|  | 5075 | { | 
|  | 5076 | uint32_t Post; | 
|  | 5077 | uint32_t Config; | 
|  | 5078 | uint32_t Isr; | 
|  | 5079 | uint32_t Oimr; | 
|  | 5080 | int i; | 
|  | 5081 |  | 
|  | 5082 | METHOD_TRACE("ips_init_morpheus", 1); | 
|  | 5083 |  | 
|  | 5084 | /* Wait up to 45 secs for Post */ | 
|  | 5085 | for (i = 0; i < 45; i++) { | 
|  | 5086 | Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5087 |  | 
|  | 5088 | if (Isr & IPS_BIT_I960_MSG0I) | 
|  | 5089 | break; | 
|  | 5090 |  | 
|  | 5091 | /* Delay for 1 Second */ | 
|  | 5092 | MDELAY(IPS_ONE_SEC); | 
|  | 5093 | } | 
|  | 5094 |  | 
|  | 5095 | if (i >= 45) { | 
|  | 5096 | /* error occurred */ | 
|  | 5097 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5098 | "timeout waiting for post.\n"); | 
|  | 5099 |  | 
|  | 5100 | return (0); | 
|  | 5101 | } | 
|  | 5102 |  | 
|  | 5103 | Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); | 
|  | 5104 |  | 
|  | 5105 | if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */ | 
|  | 5106 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5107 | "Flashing Battery PIC, Please wait ...\n"); | 
|  | 5108 |  | 
|  | 5109 | /* Clear the interrupt bit */ | 
|  | 5110 | Isr = (uint32_t) IPS_BIT_I960_MSG0I; | 
|  | 5111 | writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5112 |  | 
|  | 5113 | for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */ | 
|  | 5114 | Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); | 
|  | 5115 | if (Post != 0x4F00) | 
|  | 5116 | break; | 
|  | 5117 | /* Delay for 1 Second */ | 
|  | 5118 | MDELAY(IPS_ONE_SEC); | 
|  | 5119 | } | 
|  | 5120 |  | 
|  | 5121 | if (i >= 120) { | 
|  | 5122 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5123 | "timeout waiting for Battery PIC Flash\n"); | 
|  | 5124 | return (0); | 
|  | 5125 | } | 
|  | 5126 |  | 
|  | 5127 | } | 
|  | 5128 |  | 
|  | 5129 | /* Clear the interrupt bit */ | 
|  | 5130 | Isr = (uint32_t) IPS_BIT_I960_MSG0I; | 
|  | 5131 | writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5132 |  | 
|  | 5133 | if (Post < (IPS_GOOD_POST_STATUS << 8)) { | 
|  | 5134 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5135 | "reset controller fails (post status %x).\n", Post); | 
|  | 5136 |  | 
|  | 5137 | return (0); | 
|  | 5138 | } | 
|  | 5139 |  | 
|  | 5140 | /* Wait up to 240 secs for config bytes */ | 
|  | 5141 | for (i = 0; i < 240; i++) { | 
|  | 5142 | Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5143 |  | 
|  | 5144 | if (Isr & IPS_BIT_I960_MSG1I) | 
|  | 5145 | break; | 
|  | 5146 |  | 
|  | 5147 | /* Delay for 1 Second */ | 
|  | 5148 | MDELAY(IPS_ONE_SEC); | 
|  | 5149 | } | 
|  | 5150 |  | 
|  | 5151 | if (i >= 240) { | 
|  | 5152 | /* error occurred */ | 
|  | 5153 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5154 | "timeout waiting for config.\n"); | 
|  | 5155 |  | 
|  | 5156 | return (0); | 
|  | 5157 | } | 
|  | 5158 |  | 
|  | 5159 | Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1); | 
|  | 5160 |  | 
|  | 5161 | /* Clear interrupt bit */ | 
|  | 5162 | Isr = (uint32_t) IPS_BIT_I960_MSG1I; | 
|  | 5163 | writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5164 |  | 
|  | 5165 | /* Turn on the interrupts */ | 
|  | 5166 | Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 5167 | Oimr &= ~0x8; | 
|  | 5168 | writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); | 
|  | 5169 |  | 
|  | 5170 | /* if we get here then everything went OK */ | 
|  | 5171 |  | 
|  | 5172 | /* Since we did a RESET, an EraseStripeLock may be needed */ | 
|  | 5173 | if (Post == 0xEF10) { | 
|  | 5174 | if ((Config == 0x000F) || (Config == 0x0009)) | 
|  | 5175 | ha->requires_esl = 1; | 
|  | 5176 | } | 
|  | 5177 |  | 
|  | 5178 | return (1); | 
|  | 5179 | } | 
|  | 5180 |  | 
|  | 5181 | /****************************************************************************/ | 
|  | 5182 | /*                                                                          */ | 
|  | 5183 | /* Routine Name: ips_reset_copperhead                                       */ | 
|  | 5184 | /*                                                                          */ | 
|  | 5185 | /* Routine Description:                                                     */ | 
|  | 5186 | /*                                                                          */ | 
|  | 5187 | /*   Reset the controller                                                   */ | 
|  | 5188 | /*                                                                          */ | 
|  | 5189 | /****************************************************************************/ | 
|  | 5190 | static int | 
|  | 5191 | ips_reset_copperhead(ips_ha_t * ha) | 
|  | 5192 | { | 
|  | 5193 | int reset_counter; | 
|  | 5194 |  | 
|  | 5195 | METHOD_TRACE("ips_reset_copperhead", 1); | 
|  | 5196 |  | 
|  | 5197 | DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", | 
|  | 5198 | ips_name, ha->host_num, ha->io_addr, ha->irq); | 
|  | 5199 |  | 
|  | 5200 | reset_counter = 0; | 
|  | 5201 |  | 
|  | 5202 | while (reset_counter < 2) { | 
|  | 5203 | reset_counter++; | 
|  | 5204 |  | 
|  | 5205 | outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR); | 
|  | 5206 |  | 
|  | 5207 | /* Delay for 1 Second */ | 
|  | 5208 | MDELAY(IPS_ONE_SEC); | 
|  | 5209 |  | 
|  | 5210 | outb(0, ha->io_addr + IPS_REG_SCPR); | 
|  | 5211 |  | 
|  | 5212 | /* Delay for 1 Second */ | 
|  | 5213 | MDELAY(IPS_ONE_SEC); | 
|  | 5214 |  | 
|  | 5215 | if ((*ha->func.init) (ha)) | 
|  | 5216 | break; | 
|  | 5217 | else if (reset_counter >= 2) { | 
|  | 5218 |  | 
|  | 5219 | return (0); | 
|  | 5220 | } | 
|  | 5221 | } | 
|  | 5222 |  | 
|  | 5223 | return (1); | 
|  | 5224 | } | 
|  | 5225 |  | 
|  | 5226 | /****************************************************************************/ | 
|  | 5227 | /*                                                                          */ | 
|  | 5228 | /* Routine Name: ips_reset_copperhead_memio                                 */ | 
|  | 5229 | /*                                                                          */ | 
|  | 5230 | /* Routine Description:                                                     */ | 
|  | 5231 | /*                                                                          */ | 
|  | 5232 | /*   Reset the controller                                                   */ | 
|  | 5233 | /*                                                                          */ | 
|  | 5234 | /****************************************************************************/ | 
|  | 5235 | static int | 
|  | 5236 | ips_reset_copperhead_memio(ips_ha_t * ha) | 
|  | 5237 | { | 
|  | 5238 | int reset_counter; | 
|  | 5239 |  | 
|  | 5240 | METHOD_TRACE("ips_reset_copperhead_memio", 1); | 
|  | 5241 |  | 
|  | 5242 | DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", | 
|  | 5243 | ips_name, ha->host_num, ha->mem_addr, ha->irq); | 
|  | 5244 |  | 
|  | 5245 | reset_counter = 0; | 
|  | 5246 |  | 
|  | 5247 | while (reset_counter < 2) { | 
|  | 5248 | reset_counter++; | 
|  | 5249 |  | 
|  | 5250 | writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); | 
|  | 5251 |  | 
|  | 5252 | /* Delay for 1 Second */ | 
|  | 5253 | MDELAY(IPS_ONE_SEC); | 
|  | 5254 |  | 
|  | 5255 | writeb(0, ha->mem_ptr + IPS_REG_SCPR); | 
|  | 5256 |  | 
|  | 5257 | /* Delay for 1 Second */ | 
|  | 5258 | MDELAY(IPS_ONE_SEC); | 
|  | 5259 |  | 
|  | 5260 | if ((*ha->func.init) (ha)) | 
|  | 5261 | break; | 
|  | 5262 | else if (reset_counter >= 2) { | 
|  | 5263 |  | 
|  | 5264 | return (0); | 
|  | 5265 | } | 
|  | 5266 | } | 
|  | 5267 |  | 
|  | 5268 | return (1); | 
|  | 5269 | } | 
|  | 5270 |  | 
|  | 5271 | /****************************************************************************/ | 
|  | 5272 | /*                                                                          */ | 
|  | 5273 | /* Routine Name: ips_reset_morpheus                                         */ | 
|  | 5274 | /*                                                                          */ | 
|  | 5275 | /* Routine Description:                                                     */ | 
|  | 5276 | /*                                                                          */ | 
|  | 5277 | /*   Reset the controller                                                   */ | 
|  | 5278 | /*                                                                          */ | 
|  | 5279 | /****************************************************************************/ | 
|  | 5280 | static int | 
|  | 5281 | ips_reset_morpheus(ips_ha_t * ha) | 
|  | 5282 | { | 
|  | 5283 | int reset_counter; | 
|  | 5284 | uint8_t junk; | 
|  | 5285 |  | 
|  | 5286 | METHOD_TRACE("ips_reset_morpheus", 1); | 
|  | 5287 |  | 
|  | 5288 | DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", | 
|  | 5289 | ips_name, ha->host_num, ha->mem_addr, ha->irq); | 
|  | 5290 |  | 
|  | 5291 | reset_counter = 0; | 
|  | 5292 |  | 
|  | 5293 | while (reset_counter < 2) { | 
|  | 5294 | reset_counter++; | 
|  | 5295 |  | 
|  | 5296 | writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); | 
|  | 5297 |  | 
|  | 5298 | /* Delay for 5 Seconds */ | 
|  | 5299 | MDELAY(5 * IPS_ONE_SEC); | 
|  | 5300 |  | 
|  | 5301 | /* Do a PCI config read to wait for adapter */ | 
|  | 5302 | pci_read_config_byte(ha->pcidev, 4, &junk); | 
|  | 5303 |  | 
|  | 5304 | if ((*ha->func.init) (ha)) | 
|  | 5305 | break; | 
|  | 5306 | else if (reset_counter >= 2) { | 
|  | 5307 |  | 
|  | 5308 | return (0); | 
|  | 5309 | } | 
|  | 5310 | } | 
|  | 5311 |  | 
|  | 5312 | return (1); | 
|  | 5313 | } | 
|  | 5314 |  | 
|  | 5315 | /****************************************************************************/ | 
|  | 5316 | /*                                                                          */ | 
|  | 5317 | /* Routine Name: ips_statinit                                               */ | 
|  | 5318 | /*                                                                          */ | 
|  | 5319 | /* Routine Description:                                                     */ | 
|  | 5320 | /*                                                                          */ | 
|  | 5321 | /*   Initialize the status queues on the controller                         */ | 
|  | 5322 | /*                                                                          */ | 
|  | 5323 | /****************************************************************************/ | 
|  | 5324 | static void | 
|  | 5325 | ips_statinit(ips_ha_t * ha) | 
|  | 5326 | { | 
|  | 5327 | uint32_t phys_status_start; | 
|  | 5328 |  | 
|  | 5329 | METHOD_TRACE("ips_statinit", 1); | 
|  | 5330 |  | 
|  | 5331 | ha->adapt->p_status_start = ha->adapt->status; | 
|  | 5332 | ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; | 
|  | 5333 | ha->adapt->p_status_tail = ha->adapt->status; | 
|  | 5334 |  | 
|  | 5335 | phys_status_start = ha->adapt->hw_status_start; | 
|  | 5336 | outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR); | 
|  | 5337 | outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), | 
|  | 5338 | ha->io_addr + IPS_REG_SQER); | 
|  | 5339 | outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), | 
|  | 5340 | ha->io_addr + IPS_REG_SQHR); | 
|  | 5341 | outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR); | 
|  | 5342 |  | 
|  | 5343 | ha->adapt->hw_status_tail = phys_status_start; | 
|  | 5344 | } | 
|  | 5345 |  | 
|  | 5346 | /****************************************************************************/ | 
|  | 5347 | /*                                                                          */ | 
|  | 5348 | /* Routine Name: ips_statinit_memio                                         */ | 
|  | 5349 | /*                                                                          */ | 
|  | 5350 | /* Routine Description:                                                     */ | 
|  | 5351 | /*                                                                          */ | 
|  | 5352 | /*   Initialize the status queues on the controller                         */ | 
|  | 5353 | /*                                                                          */ | 
|  | 5354 | /****************************************************************************/ | 
|  | 5355 | static void | 
|  | 5356 | ips_statinit_memio(ips_ha_t * ha) | 
|  | 5357 | { | 
|  | 5358 | uint32_t phys_status_start; | 
|  | 5359 |  | 
|  | 5360 | METHOD_TRACE("ips_statinit_memio", 1); | 
|  | 5361 |  | 
|  | 5362 | ha->adapt->p_status_start = ha->adapt->status; | 
|  | 5363 | ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; | 
|  | 5364 | ha->adapt->p_status_tail = ha->adapt->status; | 
|  | 5365 |  | 
|  | 5366 | phys_status_start = ha->adapt->hw_status_start; | 
|  | 5367 | writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); | 
|  | 5368 | writel(phys_status_start + IPS_STATUS_Q_SIZE, | 
|  | 5369 | ha->mem_ptr + IPS_REG_SQER); | 
|  | 5370 | writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); | 
|  | 5371 | writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR); | 
|  | 5372 |  | 
|  | 5373 | ha->adapt->hw_status_tail = phys_status_start; | 
|  | 5374 | } | 
|  | 5375 |  | 
|  | 5376 | /****************************************************************************/ | 
|  | 5377 | /*                                                                          */ | 
|  | 5378 | /* Routine Name: ips_statupd_copperhead                                     */ | 
|  | 5379 | /*                                                                          */ | 
|  | 5380 | /* Routine Description:                                                     */ | 
|  | 5381 | /*                                                                          */ | 
|  | 5382 | /*   Remove an element from the status queue                                */ | 
|  | 5383 | /*                                                                          */ | 
|  | 5384 | /****************************************************************************/ | 
|  | 5385 | static uint32_t | 
|  | 5386 | ips_statupd_copperhead(ips_ha_t * ha) | 
|  | 5387 | { | 
|  | 5388 | METHOD_TRACE("ips_statupd_copperhead", 1); | 
|  | 5389 |  | 
|  | 5390 | if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { | 
|  | 5391 | ha->adapt->p_status_tail++; | 
|  | 5392 | ha->adapt->hw_status_tail += sizeof (IPS_STATUS); | 
|  | 5393 | } else { | 
|  | 5394 | ha->adapt->p_status_tail = ha->adapt->p_status_start; | 
|  | 5395 | ha->adapt->hw_status_tail = ha->adapt->hw_status_start; | 
|  | 5396 | } | 
|  | 5397 |  | 
|  | 5398 | outl(cpu_to_le32(ha->adapt->hw_status_tail), | 
|  | 5399 | ha->io_addr + IPS_REG_SQTR); | 
|  | 5400 |  | 
|  | 5401 | return (ha->adapt->p_status_tail->value); | 
|  | 5402 | } | 
|  | 5403 |  | 
|  | 5404 | /****************************************************************************/ | 
|  | 5405 | /*                                                                          */ | 
|  | 5406 | /* Routine Name: ips_statupd_copperhead_memio                               */ | 
|  | 5407 | /*                                                                          */ | 
|  | 5408 | /* Routine Description:                                                     */ | 
|  | 5409 | /*                                                                          */ | 
|  | 5410 | /*   Remove an element from the status queue                                */ | 
|  | 5411 | /*                                                                          */ | 
|  | 5412 | /****************************************************************************/ | 
|  | 5413 | static uint32_t | 
|  | 5414 | ips_statupd_copperhead_memio(ips_ha_t * ha) | 
|  | 5415 | { | 
|  | 5416 | METHOD_TRACE("ips_statupd_copperhead_memio", 1); | 
|  | 5417 |  | 
|  | 5418 | if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { | 
|  | 5419 | ha->adapt->p_status_tail++; | 
|  | 5420 | ha->adapt->hw_status_tail += sizeof (IPS_STATUS); | 
|  | 5421 | } else { | 
|  | 5422 | ha->adapt->p_status_tail = ha->adapt->p_status_start; | 
|  | 5423 | ha->adapt->hw_status_tail = ha->adapt->hw_status_start; | 
|  | 5424 | } | 
|  | 5425 |  | 
|  | 5426 | writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR); | 
|  | 5427 |  | 
|  | 5428 | return (ha->adapt->p_status_tail->value); | 
|  | 5429 | } | 
|  | 5430 |  | 
|  | 5431 | /****************************************************************************/ | 
|  | 5432 | /*                                                                          */ | 
|  | 5433 | /* Routine Name: ips_statupd_morpheus                                       */ | 
|  | 5434 | /*                                                                          */ | 
|  | 5435 | /* Routine Description:                                                     */ | 
|  | 5436 | /*                                                                          */ | 
|  | 5437 | /*   Remove an element from the status queue                                */ | 
|  | 5438 | /*                                                                          */ | 
|  | 5439 | /****************************************************************************/ | 
|  | 5440 | static uint32_t | 
|  | 5441 | ips_statupd_morpheus(ips_ha_t * ha) | 
|  | 5442 | { | 
|  | 5443 | uint32_t val; | 
|  | 5444 |  | 
|  | 5445 | METHOD_TRACE("ips_statupd_morpheus", 1); | 
|  | 5446 |  | 
|  | 5447 | val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ); | 
|  | 5448 |  | 
|  | 5449 | return (val); | 
|  | 5450 | } | 
|  | 5451 |  | 
|  | 5452 | /****************************************************************************/ | 
|  | 5453 | /*                                                                          */ | 
|  | 5454 | /* Routine Name: ips_issue_copperhead                                       */ | 
|  | 5455 | /*                                                                          */ | 
|  | 5456 | /* Routine Description:                                                     */ | 
|  | 5457 | /*                                                                          */ | 
|  | 5458 | /*   Send a command down to the controller                                  */ | 
|  | 5459 | /*                                                                          */ | 
|  | 5460 | /****************************************************************************/ | 
|  | 5461 | static int | 
|  | 5462 | ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5463 | { | 
|  | 5464 | uint32_t TimeOut; | 
|  | 5465 | uint32_t val; | 
|  | 5466 |  | 
|  | 5467 | METHOD_TRACE("ips_issue_copperhead", 1); | 
|  | 5468 |  | 
|  | 5469 | if (scb->scsi_cmd) { | 
|  | 5470 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5471 | ips_name, | 
|  | 5472 | ha->host_num, | 
|  | 5473 | scb->cdb[0], | 
|  | 5474 | scb->cmd.basic_io.command_id, | 
|  | 5475 | scb->bus, scb->target_id, scb->lun); | 
|  | 5476 | } else { | 
|  | 5477 | DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5478 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5479 | } | 
|  | 5480 |  | 
|  | 5481 | TimeOut = 0; | 
|  | 5482 |  | 
|  | 5483 | while ((val = | 
|  | 5484 | le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) { | 
|  | 5485 | udelay(1000); | 
|  | 5486 |  | 
|  | 5487 | if (++TimeOut >= IPS_SEM_TIMEOUT) { | 
|  | 5488 | if (!(val & IPS_BIT_START_STOP)) | 
|  | 5489 | break; | 
|  | 5490 |  | 
|  | 5491 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5492 | "ips_issue val [0x%x].\n", val); | 
|  | 5493 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5494 | "ips_issue semaphore chk timeout.\n"); | 
|  | 5495 |  | 
|  | 5496 | return (IPS_FAILURE); | 
|  | 5497 | }		/* end if */ | 
|  | 5498 | }			/* end while */ | 
|  | 5499 |  | 
|  | 5500 | outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR); | 
|  | 5501 | outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR); | 
|  | 5502 |  | 
|  | 5503 | return (IPS_SUCCESS); | 
|  | 5504 | } | 
|  | 5505 |  | 
|  | 5506 | /****************************************************************************/ | 
|  | 5507 | /*                                                                          */ | 
|  | 5508 | /* Routine Name: ips_issue_copperhead_memio                                 */ | 
|  | 5509 | /*                                                                          */ | 
|  | 5510 | /* Routine Description:                                                     */ | 
|  | 5511 | /*                                                                          */ | 
|  | 5512 | /*   Send a command down to the controller                                  */ | 
|  | 5513 | /*                                                                          */ | 
|  | 5514 | /****************************************************************************/ | 
|  | 5515 | static int | 
|  | 5516 | ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5517 | { | 
|  | 5518 | uint32_t TimeOut; | 
|  | 5519 | uint32_t val; | 
|  | 5520 |  | 
|  | 5521 | METHOD_TRACE("ips_issue_copperhead_memio", 1); | 
|  | 5522 |  | 
|  | 5523 | if (scb->scsi_cmd) { | 
|  | 5524 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5525 | ips_name, | 
|  | 5526 | ha->host_num, | 
|  | 5527 | scb->cdb[0], | 
|  | 5528 | scb->cmd.basic_io.command_id, | 
|  | 5529 | scb->bus, scb->target_id, scb->lun); | 
|  | 5530 | } else { | 
|  | 5531 | DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5532 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5533 | } | 
|  | 5534 |  | 
|  | 5535 | TimeOut = 0; | 
|  | 5536 |  | 
|  | 5537 | while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { | 
|  | 5538 | udelay(1000); | 
|  | 5539 |  | 
|  | 5540 | if (++TimeOut >= IPS_SEM_TIMEOUT) { | 
|  | 5541 | if (!(val & IPS_BIT_START_STOP)) | 
|  | 5542 | break; | 
|  | 5543 |  | 
|  | 5544 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5545 | "ips_issue val [0x%x].\n", val); | 
|  | 5546 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5547 | "ips_issue semaphore chk timeout.\n"); | 
|  | 5548 |  | 
|  | 5549 | return (IPS_FAILURE); | 
|  | 5550 | }		/* end if */ | 
|  | 5551 | }			/* end while */ | 
|  | 5552 |  | 
|  | 5553 | writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); | 
|  | 5554 | writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR); | 
|  | 5555 |  | 
|  | 5556 | return (IPS_SUCCESS); | 
|  | 5557 | } | 
|  | 5558 |  | 
|  | 5559 | /****************************************************************************/ | 
|  | 5560 | /*                                                                          */ | 
|  | 5561 | /* Routine Name: ips_issue_i2o                                              */ | 
|  | 5562 | /*                                                                          */ | 
|  | 5563 | /* Routine Description:                                                     */ | 
|  | 5564 | /*                                                                          */ | 
|  | 5565 | /*   Send a command down to the controller                                  */ | 
|  | 5566 | /*                                                                          */ | 
|  | 5567 | /****************************************************************************/ | 
|  | 5568 | static int | 
|  | 5569 | ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5570 | { | 
|  | 5571 |  | 
|  | 5572 | METHOD_TRACE("ips_issue_i2o", 1); | 
|  | 5573 |  | 
|  | 5574 | if (scb->scsi_cmd) { | 
|  | 5575 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5576 | ips_name, | 
|  | 5577 | ha->host_num, | 
|  | 5578 | scb->cdb[0], | 
|  | 5579 | scb->cmd.basic_io.command_id, | 
|  | 5580 | scb->bus, scb->target_id, scb->lun); | 
|  | 5581 | } else { | 
|  | 5582 | DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5583 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5584 | } | 
|  | 5585 |  | 
|  | 5586 | outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ); | 
|  | 5587 |  | 
|  | 5588 | return (IPS_SUCCESS); | 
|  | 5589 | } | 
|  | 5590 |  | 
|  | 5591 | /****************************************************************************/ | 
|  | 5592 | /*                                                                          */ | 
|  | 5593 | /* Routine Name: ips_issue_i2o_memio                                        */ | 
|  | 5594 | /*                                                                          */ | 
|  | 5595 | /* Routine Description:                                                     */ | 
|  | 5596 | /*                                                                          */ | 
|  | 5597 | /*   Send a command down to the controller                                  */ | 
|  | 5598 | /*                                                                          */ | 
|  | 5599 | /****************************************************************************/ | 
|  | 5600 | static int | 
|  | 5601 | ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) | 
|  | 5602 | { | 
|  | 5603 |  | 
|  | 5604 | METHOD_TRACE("ips_issue_i2o_memio", 1); | 
|  | 5605 |  | 
|  | 5606 | if (scb->scsi_cmd) { | 
|  | 5607 | DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", | 
|  | 5608 | ips_name, | 
|  | 5609 | ha->host_num, | 
|  | 5610 | scb->cdb[0], | 
|  | 5611 | scb->cmd.basic_io.command_id, | 
|  | 5612 | scb->bus, scb->target_id, scb->lun); | 
|  | 5613 | } else { | 
|  | 5614 | DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", | 
|  | 5615 | ips_name, ha->host_num, scb->cmd.basic_io.command_id); | 
|  | 5616 | } | 
|  | 5617 |  | 
|  | 5618 | writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ); | 
|  | 5619 |  | 
|  | 5620 | return (IPS_SUCCESS); | 
|  | 5621 | } | 
|  | 5622 |  | 
|  | 5623 | /****************************************************************************/ | 
|  | 5624 | /*                                                                          */ | 
|  | 5625 | /* Routine Name: ips_isintr_copperhead                                      */ | 
|  | 5626 | /*                                                                          */ | 
|  | 5627 | /* Routine Description:                                                     */ | 
|  | 5628 | /*                                                                          */ | 
|  | 5629 | /*   Test to see if an interrupt is for us                                  */ | 
|  | 5630 | /*                                                                          */ | 
|  | 5631 | /****************************************************************************/ | 
|  | 5632 | static int | 
|  | 5633 | ips_isintr_copperhead(ips_ha_t * ha) | 
|  | 5634 | { | 
|  | 5635 | uint8_t Isr; | 
|  | 5636 |  | 
|  | 5637 | METHOD_TRACE("ips_isintr_copperhead", 2); | 
|  | 5638 |  | 
|  | 5639 | Isr = inb(ha->io_addr + IPS_REG_HISR); | 
|  | 5640 |  | 
|  | 5641 | if (Isr == 0xFF) | 
|  | 5642 | /* ?!?! Nothing really there */ | 
|  | 5643 | return (0); | 
|  | 5644 |  | 
|  | 5645 | if (Isr & IPS_BIT_SCE) | 
|  | 5646 | return (1); | 
|  | 5647 | else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { | 
|  | 5648 | /* status queue overflow or GHI */ | 
|  | 5649 | /* just clear the interrupt */ | 
|  | 5650 | outb(Isr, ha->io_addr + IPS_REG_HISR); | 
|  | 5651 | } | 
|  | 5652 |  | 
|  | 5653 | return (0); | 
|  | 5654 | } | 
|  | 5655 |  | 
|  | 5656 | /****************************************************************************/ | 
|  | 5657 | /*                                                                          */ | 
|  | 5658 | /* Routine Name: ips_isintr_copperhead_memio                                */ | 
|  | 5659 | /*                                                                          */ | 
|  | 5660 | /* Routine Description:                                                     */ | 
|  | 5661 | /*                                                                          */ | 
|  | 5662 | /*   Test to see if an interrupt is for us                                  */ | 
|  | 5663 | /*                                                                          */ | 
|  | 5664 | /****************************************************************************/ | 
|  | 5665 | static int | 
|  | 5666 | ips_isintr_copperhead_memio(ips_ha_t * ha) | 
|  | 5667 | { | 
|  | 5668 | uint8_t Isr; | 
|  | 5669 |  | 
|  | 5670 | METHOD_TRACE("ips_isintr_memio", 2); | 
|  | 5671 |  | 
|  | 5672 | Isr = readb(ha->mem_ptr + IPS_REG_HISR); | 
|  | 5673 |  | 
|  | 5674 | if (Isr == 0xFF) | 
|  | 5675 | /* ?!?! Nothing really there */ | 
|  | 5676 | return (0); | 
|  | 5677 |  | 
|  | 5678 | if (Isr & IPS_BIT_SCE) | 
|  | 5679 | return (1); | 
|  | 5680 | else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { | 
|  | 5681 | /* status queue overflow or GHI */ | 
|  | 5682 | /* just clear the interrupt */ | 
|  | 5683 | writeb(Isr, ha->mem_ptr + IPS_REG_HISR); | 
|  | 5684 | } | 
|  | 5685 |  | 
|  | 5686 | return (0); | 
|  | 5687 | } | 
|  | 5688 |  | 
|  | 5689 | /****************************************************************************/ | 
|  | 5690 | /*                                                                          */ | 
|  | 5691 | /* Routine Name: ips_isintr_morpheus                                        */ | 
|  | 5692 | /*                                                                          */ | 
|  | 5693 | /* Routine Description:                                                     */ | 
|  | 5694 | /*                                                                          */ | 
|  | 5695 | /*   Test to see if an interrupt is for us                                  */ | 
|  | 5696 | /*                                                                          */ | 
|  | 5697 | /****************************************************************************/ | 
|  | 5698 | static int | 
|  | 5699 | ips_isintr_morpheus(ips_ha_t * ha) | 
|  | 5700 | { | 
|  | 5701 | uint32_t Isr; | 
|  | 5702 |  | 
|  | 5703 | METHOD_TRACE("ips_isintr_morpheus", 2); | 
|  | 5704 |  | 
|  | 5705 | Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); | 
|  | 5706 |  | 
|  | 5707 | if (Isr & IPS_BIT_I2O_OPQI) | 
|  | 5708 | return (1); | 
|  | 5709 | else | 
|  | 5710 | return (0); | 
|  | 5711 | } | 
|  | 5712 |  | 
|  | 5713 | /****************************************************************************/ | 
|  | 5714 | /*                                                                          */ | 
|  | 5715 | /* Routine Name: ips_wait                                                   */ | 
|  | 5716 | /*                                                                          */ | 
|  | 5717 | /* Routine Description:                                                     */ | 
|  | 5718 | /*                                                                          */ | 
|  | 5719 | /*   Wait for a command to complete                                         */ | 
|  | 5720 | /*                                                                          */ | 
|  | 5721 | /****************************************************************************/ | 
|  | 5722 | static int | 
|  | 5723 | ips_wait(ips_ha_t * ha, int time, int intr) | 
|  | 5724 | { | 
|  | 5725 | int ret; | 
|  | 5726 | int done; | 
|  | 5727 |  | 
|  | 5728 | METHOD_TRACE("ips_wait", 1); | 
|  | 5729 |  | 
|  | 5730 | ret = IPS_FAILURE; | 
|  | 5731 | done = FALSE; | 
|  | 5732 |  | 
|  | 5733 | time *= IPS_ONE_SEC;	/* convert seconds */ | 
|  | 5734 |  | 
|  | 5735 | while ((time > 0) && (!done)) { | 
|  | 5736 | if (intr == IPS_INTR_ON) { | 
|  | 5737 | if (ha->waitflag == FALSE) { | 
|  | 5738 | ret = IPS_SUCCESS; | 
|  | 5739 | done = TRUE; | 
|  | 5740 | break; | 
|  | 5741 | } | 
|  | 5742 | } else if (intr == IPS_INTR_IORL) { | 
|  | 5743 | if (ha->waitflag == FALSE) { | 
|  | 5744 | /* | 
|  | 5745 | * controller generated an interrupt to | 
|  | 5746 | * acknowledge completion of the command | 
|  | 5747 | * and ips_intr() has serviced the interrupt. | 
|  | 5748 | */ | 
|  | 5749 | ret = IPS_SUCCESS; | 
|  | 5750 | done = TRUE; | 
|  | 5751 | break; | 
|  | 5752 | } | 
|  | 5753 |  | 
|  | 5754 | /* | 
|  | 5755 | * NOTE: we already have the io_request_lock so | 
|  | 5756 | * even if we get an interrupt it won't get serviced | 
|  | 5757 | * until after we finish. | 
|  | 5758 | */ | 
|  | 5759 |  | 
|  | 5760 | (*ha->func.intr) (ha); | 
|  | 5761 | } | 
|  | 5762 |  | 
|  | 5763 | /* This looks like a very evil loop, but it only does this during start-up */ | 
|  | 5764 | udelay(1000); | 
|  | 5765 | time--; | 
|  | 5766 | } | 
|  | 5767 |  | 
|  | 5768 | return (ret); | 
|  | 5769 | } | 
|  | 5770 |  | 
|  | 5771 | /****************************************************************************/ | 
|  | 5772 | /*                                                                          */ | 
|  | 5773 | /* Routine Name: ips_write_driver_status                                    */ | 
|  | 5774 | /*                                                                          */ | 
|  | 5775 | /* Routine Description:                                                     */ | 
|  | 5776 | /*                                                                          */ | 
|  | 5777 | /*   Write OS/Driver version to Page 5 of the nvram on the controller       */ | 
|  | 5778 | /*                                                                          */ | 
|  | 5779 | /****************************************************************************/ | 
|  | 5780 | static int | 
|  | 5781 | ips_write_driver_status(ips_ha_t * ha, int intr) | 
|  | 5782 | { | 
|  | 5783 | METHOD_TRACE("ips_write_driver_status", 1); | 
|  | 5784 |  | 
|  | 5785 | if (!ips_readwrite_page5(ha, FALSE, intr)) { | 
|  | 5786 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5787 | "unable to read NVRAM page 5.\n"); | 
|  | 5788 |  | 
|  | 5789 | return (0); | 
|  | 5790 | } | 
|  | 5791 |  | 
|  | 5792 | /* check to make sure the page has a valid */ | 
|  | 5793 | /* signature */ | 
|  | 5794 | if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) { | 
|  | 5795 | DEBUG_VAR(1, | 
|  | 5796 | "(%s%d) NVRAM page 5 has an invalid signature: %X.", | 
|  | 5797 | ips_name, ha->host_num, ha->nvram->signature); | 
|  | 5798 | ha->nvram->signature = IPS_NVRAM_P5_SIG; | 
|  | 5799 | } | 
|  | 5800 |  | 
|  | 5801 | DEBUG_VAR(2, | 
|  | 5802 | "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", | 
|  | 5803 | ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type), | 
|  | 5804 | ha->nvram->adapter_slot, ha->nvram->bios_high[0], | 
|  | 5805 | ha->nvram->bios_high[1], ha->nvram->bios_high[2], | 
|  | 5806 | ha->nvram->bios_high[3], ha->nvram->bios_low[0], | 
|  | 5807 | ha->nvram->bios_low[1], ha->nvram->bios_low[2], | 
|  | 5808 | ha->nvram->bios_low[3]); | 
|  | 5809 |  | 
|  | 5810 | ips_get_bios_version(ha, intr); | 
|  | 5811 |  | 
|  | 5812 | /* change values (as needed) */ | 
|  | 5813 | ha->nvram->operating_system = IPS_OS_LINUX; | 
|  | 5814 | ha->nvram->adapter_type = ha->ad_type; | 
|  | 5815 | strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); | 
|  | 5816 | strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); | 
|  | 5817 | strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4); | 
|  | 5818 | strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4); | 
|  | 5819 |  | 
|  | 5820 | ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */ | 
|  | 5821 |  | 
|  | 5822 | /* now update the page */ | 
|  | 5823 | if (!ips_readwrite_page5(ha, TRUE, intr)) { | 
|  | 5824 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 5825 | "unable to write NVRAM page 5.\n"); | 
|  | 5826 |  | 
|  | 5827 | return (0); | 
|  | 5828 | } | 
|  | 5829 |  | 
|  | 5830 | /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ | 
|  | 5831 | ha->slot_num = ha->nvram->adapter_slot; | 
|  | 5832 |  | 
|  | 5833 | return (1); | 
|  | 5834 | } | 
|  | 5835 |  | 
|  | 5836 | /****************************************************************************/ | 
|  | 5837 | /*                                                                          */ | 
|  | 5838 | /* Routine Name: ips_read_adapter_status                                    */ | 
|  | 5839 | /*                                                                          */ | 
|  | 5840 | /* Routine Description:                                                     */ | 
|  | 5841 | /*                                                                          */ | 
|  | 5842 | /*   Do an Inquiry command to the adapter                                   */ | 
|  | 5843 | /*                                                                          */ | 
|  | 5844 | /****************************************************************************/ | 
|  | 5845 | static int | 
|  | 5846 | ips_read_adapter_status(ips_ha_t * ha, int intr) | 
|  | 5847 | { | 
|  | 5848 | ips_scb_t *scb; | 
|  | 5849 | int ret; | 
|  | 5850 |  | 
|  | 5851 | METHOD_TRACE("ips_read_adapter_status", 1); | 
|  | 5852 |  | 
|  | 5853 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5854 |  | 
|  | 5855 | ips_init_scb(ha, scb); | 
|  | 5856 |  | 
|  | 5857 | scb->timeout = ips_cmd_timeout; | 
|  | 5858 | scb->cdb[0] = IPS_CMD_ENQUIRY; | 
|  | 5859 |  | 
|  | 5860 | scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; | 
|  | 5861 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5862 | scb->cmd.basic_io.sg_count = 0; | 
|  | 5863 | scb->cmd.basic_io.lba = 0; | 
|  | 5864 | scb->cmd.basic_io.sector_count = 0; | 
|  | 5865 | scb->cmd.basic_io.log_drv = 0; | 
|  | 5866 | scb->data_len = sizeof (*ha->enq); | 
|  | 5867 | scb->cmd.basic_io.sg_addr = ha->enq_busaddr; | 
|  | 5868 |  | 
|  | 5869 | /* send command */ | 
|  | 5870 | if (((ret = | 
|  | 5871 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5872 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5873 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 5874 | return (0); | 
|  | 5875 |  | 
|  | 5876 | return (1); | 
|  | 5877 | } | 
|  | 5878 |  | 
|  | 5879 | /****************************************************************************/ | 
|  | 5880 | /*                                                                          */ | 
|  | 5881 | /* Routine Name: ips_read_subsystem_parameters                              */ | 
|  | 5882 | /*                                                                          */ | 
|  | 5883 | /* Routine Description:                                                     */ | 
|  | 5884 | /*                                                                          */ | 
|  | 5885 | /*   Read subsystem parameters from the adapter                             */ | 
|  | 5886 | /*                                                                          */ | 
|  | 5887 | /****************************************************************************/ | 
|  | 5888 | static int | 
|  | 5889 | ips_read_subsystem_parameters(ips_ha_t * ha, int intr) | 
|  | 5890 | { | 
|  | 5891 | ips_scb_t *scb; | 
|  | 5892 | int ret; | 
|  | 5893 |  | 
|  | 5894 | METHOD_TRACE("ips_read_subsystem_parameters", 1); | 
|  | 5895 |  | 
|  | 5896 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5897 |  | 
|  | 5898 | ips_init_scb(ha, scb); | 
|  | 5899 |  | 
|  | 5900 | scb->timeout = ips_cmd_timeout; | 
|  | 5901 | scb->cdb[0] = IPS_CMD_GET_SUBSYS; | 
|  | 5902 |  | 
|  | 5903 | scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS; | 
|  | 5904 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5905 | scb->cmd.basic_io.sg_count = 0; | 
|  | 5906 | scb->cmd.basic_io.lba = 0; | 
|  | 5907 | scb->cmd.basic_io.sector_count = 0; | 
|  | 5908 | scb->cmd.basic_io.log_drv = 0; | 
|  | 5909 | scb->data_len = sizeof (*ha->subsys); | 
|  | 5910 | scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; | 
|  | 5911 |  | 
|  | 5912 | /* send command */ | 
|  | 5913 | if (((ret = | 
|  | 5914 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5915 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5916 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 5917 | return (0); | 
|  | 5918 |  | 
|  | 5919 | memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys)); | 
|  | 5920 | return (1); | 
|  | 5921 | } | 
|  | 5922 |  | 
|  | 5923 | /****************************************************************************/ | 
|  | 5924 | /*                                                                          */ | 
|  | 5925 | /* Routine Name: ips_read_config                                            */ | 
|  | 5926 | /*                                                                          */ | 
|  | 5927 | /* Routine Description:                                                     */ | 
|  | 5928 | /*                                                                          */ | 
|  | 5929 | /*   Read the configuration on the adapter                                  */ | 
|  | 5930 | /*                                                                          */ | 
|  | 5931 | /****************************************************************************/ | 
|  | 5932 | static int | 
|  | 5933 | ips_read_config(ips_ha_t * ha, int intr) | 
|  | 5934 | { | 
|  | 5935 | ips_scb_t *scb; | 
|  | 5936 | int i; | 
|  | 5937 | int ret; | 
|  | 5938 |  | 
|  | 5939 | METHOD_TRACE("ips_read_config", 1); | 
|  | 5940 |  | 
|  | 5941 | /* set defaults for initiator IDs */ | 
|  | 5942 | for (i = 0; i < 4; i++) | 
|  | 5943 | ha->conf->init_id[i] = 7; | 
|  | 5944 |  | 
|  | 5945 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5946 |  | 
|  | 5947 | ips_init_scb(ha, scb); | 
|  | 5948 |  | 
|  | 5949 | scb->timeout = ips_cmd_timeout; | 
|  | 5950 | scb->cdb[0] = IPS_CMD_READ_CONF; | 
|  | 5951 |  | 
|  | 5952 | scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF; | 
|  | 5953 | scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 5954 | scb->data_len = sizeof (*ha->conf); | 
|  | 5955 | scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; | 
|  | 5956 |  | 
|  | 5957 | /* send command */ | 
|  | 5958 | if (((ret = | 
|  | 5959 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 5960 | || (ret == IPS_SUCCESS_IMM) | 
|  | 5961 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { | 
|  | 5962 |  | 
|  | 5963 | memset(ha->conf, 0, sizeof (IPS_CONF)); | 
|  | 5964 |  | 
|  | 5965 | /* reset initiator IDs */ | 
|  | 5966 | for (i = 0; i < 4; i++) | 
|  | 5967 | ha->conf->init_id[i] = 7; | 
|  | 5968 |  | 
|  | 5969 | /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */ | 
|  | 5970 | if ((scb->basic_status & IPS_GSC_STATUS_MASK) == | 
|  | 5971 | IPS_CMD_CMPLT_WERROR) | 
|  | 5972 | return (1); | 
|  | 5973 |  | 
|  | 5974 | return (0); | 
|  | 5975 | } | 
|  | 5976 |  | 
|  | 5977 | memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); | 
|  | 5978 | return (1); | 
|  | 5979 | } | 
|  | 5980 |  | 
|  | 5981 | /****************************************************************************/ | 
|  | 5982 | /*                                                                          */ | 
|  | 5983 | /* Routine Name: ips_readwrite_page5                                        */ | 
|  | 5984 | /*                                                                          */ | 
|  | 5985 | /* Routine Description:                                                     */ | 
|  | 5986 | /*                                                                          */ | 
|  | 5987 | /*   Read nvram page 5 from the adapter                                     */ | 
|  | 5988 | /*                                                                          */ | 
|  | 5989 | /****************************************************************************/ | 
|  | 5990 | static int | 
|  | 5991 | ips_readwrite_page5(ips_ha_t * ha, int write, int intr) | 
|  | 5992 | { | 
|  | 5993 | ips_scb_t *scb; | 
|  | 5994 | int ret; | 
|  | 5995 |  | 
|  | 5996 | METHOD_TRACE("ips_readwrite_page5", 1); | 
|  | 5997 |  | 
|  | 5998 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 5999 |  | 
|  | 6000 | ips_init_scb(ha, scb); | 
|  | 6001 |  | 
|  | 6002 | scb->timeout = ips_cmd_timeout; | 
|  | 6003 | scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE; | 
|  | 6004 |  | 
|  | 6005 | scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE; | 
|  | 6006 | scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6007 | scb->cmd.nvram.page = 5; | 
|  | 6008 | scb->cmd.nvram.write = write; | 
|  | 6009 | scb->cmd.nvram.reserved = 0; | 
|  | 6010 | scb->cmd.nvram.reserved2 = 0; | 
|  | 6011 | scb->data_len = sizeof (*ha->nvram); | 
|  | 6012 | scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; | 
|  | 6013 | if (write) | 
|  | 6014 | memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram)); | 
|  | 6015 |  | 
|  | 6016 | /* issue the command */ | 
|  | 6017 | if (((ret = | 
|  | 6018 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 6019 | || (ret == IPS_SUCCESS_IMM) | 
|  | 6020 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { | 
|  | 6021 |  | 
|  | 6022 | memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5)); | 
|  | 6023 |  | 
|  | 6024 | return (0); | 
|  | 6025 | } | 
|  | 6026 | if (!write) | 
|  | 6027 | memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram)); | 
|  | 6028 | return (1); | 
|  | 6029 | } | 
|  | 6030 |  | 
|  | 6031 | /****************************************************************************/ | 
|  | 6032 | /*                                                                          */ | 
|  | 6033 | /* Routine Name: ips_clear_adapter                                          */ | 
|  | 6034 | /*                                                                          */ | 
|  | 6035 | /* Routine Description:                                                     */ | 
|  | 6036 | /*                                                                          */ | 
|  | 6037 | /*   Clear the stripe lock tables                                           */ | 
|  | 6038 | /*                                                                          */ | 
|  | 6039 | /****************************************************************************/ | 
|  | 6040 | static int | 
|  | 6041 | ips_clear_adapter(ips_ha_t * ha, int intr) | 
|  | 6042 | { | 
|  | 6043 | ips_scb_t *scb; | 
|  | 6044 | int ret; | 
|  | 6045 |  | 
|  | 6046 | METHOD_TRACE("ips_clear_adapter", 1); | 
|  | 6047 |  | 
|  | 6048 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 6049 |  | 
|  | 6050 | ips_init_scb(ha, scb); | 
|  | 6051 |  | 
|  | 6052 | scb->timeout = ips_reset_timeout; | 
|  | 6053 | scb->cdb[0] = IPS_CMD_CONFIG_SYNC; | 
|  | 6054 |  | 
|  | 6055 | scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC; | 
|  | 6056 | scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6057 | scb->cmd.config_sync.channel = 0; | 
|  | 6058 | scb->cmd.config_sync.source_target = IPS_POCL; | 
|  | 6059 | scb->cmd.config_sync.reserved = 0; | 
|  | 6060 | scb->cmd.config_sync.reserved2 = 0; | 
|  | 6061 | scb->cmd.config_sync.reserved3 = 0; | 
|  | 6062 |  | 
|  | 6063 | /* issue command */ | 
|  | 6064 | if (((ret = | 
|  | 6065 | ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) | 
|  | 6066 | || (ret == IPS_SUCCESS_IMM) | 
|  | 6067 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 6068 | return (0); | 
|  | 6069 |  | 
|  | 6070 | /* send unlock stripe command */ | 
|  | 6071 | ips_init_scb(ha, scb); | 
|  | 6072 |  | 
|  | 6073 | scb->cdb[0] = IPS_CMD_ERROR_TABLE; | 
|  | 6074 | scb->timeout = ips_reset_timeout; | 
|  | 6075 |  | 
|  | 6076 | scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE; | 
|  | 6077 | scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6078 | scb->cmd.unlock_stripe.log_drv = 0; | 
|  | 6079 | scb->cmd.unlock_stripe.control = IPS_CSL; | 
|  | 6080 | scb->cmd.unlock_stripe.reserved = 0; | 
|  | 6081 | scb->cmd.unlock_stripe.reserved2 = 0; | 
|  | 6082 | scb->cmd.unlock_stripe.reserved3 = 0; | 
|  | 6083 |  | 
|  | 6084 | /* issue command */ | 
|  | 6085 | if (((ret = | 
|  | 6086 | ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) | 
|  | 6087 | || (ret == IPS_SUCCESS_IMM) | 
|  | 6088 | || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) | 
|  | 6089 | return (0); | 
|  | 6090 |  | 
|  | 6091 | return (1); | 
|  | 6092 | } | 
|  | 6093 |  | 
|  | 6094 | /****************************************************************************/ | 
|  | 6095 | /*                                                                          */ | 
|  | 6096 | /* Routine Name: ips_ffdc_reset                                             */ | 
|  | 6097 | /*                                                                          */ | 
|  | 6098 | /* Routine Description:                                                     */ | 
|  | 6099 | /*                                                                          */ | 
|  | 6100 | /*   FFDC: write reset info                                                 */ | 
|  | 6101 | /*                                                                          */ | 
|  | 6102 | /****************************************************************************/ | 
|  | 6103 | static void | 
|  | 6104 | ips_ffdc_reset(ips_ha_t * ha, int intr) | 
|  | 6105 | { | 
|  | 6106 | ips_scb_t *scb; | 
|  | 6107 |  | 
|  | 6108 | METHOD_TRACE("ips_ffdc_reset", 1); | 
|  | 6109 |  | 
|  | 6110 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 6111 |  | 
|  | 6112 | ips_init_scb(ha, scb); | 
|  | 6113 |  | 
|  | 6114 | scb->timeout = ips_cmd_timeout; | 
|  | 6115 | scb->cdb[0] = IPS_CMD_FFDC; | 
|  | 6116 | scb->cmd.ffdc.op_code = IPS_CMD_FFDC; | 
|  | 6117 | scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6118 | scb->cmd.ffdc.reset_count = ha->reset_count; | 
|  | 6119 | scb->cmd.ffdc.reset_type = 0x80; | 
|  | 6120 |  | 
|  | 6121 | /* convert time to what the card wants */ | 
|  | 6122 | ips_fix_ffdc_time(ha, scb, ha->last_ffdc); | 
|  | 6123 |  | 
|  | 6124 | /* issue command */ | 
|  | 6125 | ips_send_wait(ha, scb, ips_cmd_timeout, intr); | 
|  | 6126 | } | 
|  | 6127 |  | 
|  | 6128 | /****************************************************************************/ | 
|  | 6129 | /*                                                                          */ | 
|  | 6130 | /* Routine Name: ips_ffdc_time                                              */ | 
|  | 6131 | /*                                                                          */ | 
|  | 6132 | /* Routine Description:                                                     */ | 
|  | 6133 | /*                                                                          */ | 
|  | 6134 | /*   FFDC: write time info                                                  */ | 
|  | 6135 | /*                                                                          */ | 
|  | 6136 | /****************************************************************************/ | 
|  | 6137 | static void | 
|  | 6138 | ips_ffdc_time(ips_ha_t * ha) | 
|  | 6139 | { | 
|  | 6140 | ips_scb_t *scb; | 
|  | 6141 |  | 
|  | 6142 | METHOD_TRACE("ips_ffdc_time", 1); | 
|  | 6143 |  | 
|  | 6144 | DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num); | 
|  | 6145 |  | 
|  | 6146 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 6147 |  | 
|  | 6148 | ips_init_scb(ha, scb); | 
|  | 6149 |  | 
|  | 6150 | scb->timeout = ips_cmd_timeout; | 
|  | 6151 | scb->cdb[0] = IPS_CMD_FFDC; | 
|  | 6152 | scb->cmd.ffdc.op_code = IPS_CMD_FFDC; | 
|  | 6153 | scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6154 | scb->cmd.ffdc.reset_count = 0; | 
|  | 6155 | scb->cmd.ffdc.reset_type = 0; | 
|  | 6156 |  | 
|  | 6157 | /* convert time to what the card wants */ | 
|  | 6158 | ips_fix_ffdc_time(ha, scb, ha->last_ffdc); | 
|  | 6159 |  | 
|  | 6160 | /* issue command */ | 
|  | 6161 | ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC); | 
|  | 6162 | } | 
|  | 6163 |  | 
|  | 6164 | /****************************************************************************/ | 
|  | 6165 | /*                                                                          */ | 
|  | 6166 | /* Routine Name: ips_fix_ffdc_time                                          */ | 
|  | 6167 | /*                                                                          */ | 
|  | 6168 | /* Routine Description:                                                     */ | 
|  | 6169 | /*   Adjust time_t to what the card wants                                   */ | 
|  | 6170 | /*                                                                          */ | 
|  | 6171 | /****************************************************************************/ | 
|  | 6172 | static void | 
|  | 6173 | ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time) | 
|  | 6174 | { | 
|  | 6175 | long days; | 
|  | 6176 | long rem; | 
|  | 6177 | int i; | 
|  | 6178 | int year; | 
|  | 6179 | int yleap; | 
|  | 6180 | int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR }; | 
|  | 6181 | int month_lengths[12][2] = { {31, 31}, | 
|  | 6182 | {28, 29}, | 
|  | 6183 | {31, 31}, | 
|  | 6184 | {30, 30}, | 
|  | 6185 | {31, 31}, | 
|  | 6186 | {30, 30}, | 
|  | 6187 | {31, 31}, | 
|  | 6188 | {31, 31}, | 
|  | 6189 | {30, 30}, | 
|  | 6190 | {31, 31}, | 
|  | 6191 | {30, 30}, | 
|  | 6192 | {31, 31} | 
|  | 6193 | }; | 
|  | 6194 |  | 
|  | 6195 | METHOD_TRACE("ips_fix_ffdc_time", 1); | 
|  | 6196 |  | 
|  | 6197 | days = current_time / IPS_SECS_DAY; | 
|  | 6198 | rem = current_time % IPS_SECS_DAY; | 
|  | 6199 |  | 
|  | 6200 | scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR); | 
|  | 6201 | rem = rem % IPS_SECS_HOUR; | 
|  | 6202 | scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN); | 
|  | 6203 | scb->cmd.ffdc.second = (rem % IPS_SECS_MIN); | 
|  | 6204 |  | 
|  | 6205 | year = IPS_EPOCH_YEAR; | 
|  | 6206 | while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) { | 
|  | 6207 | int newy; | 
|  | 6208 |  | 
|  | 6209 | newy = year + (days / IPS_DAYS_NORMAL_YEAR); | 
|  | 6210 | if (days < 0) | 
|  | 6211 | --newy; | 
|  | 6212 | days -= (newy - year) * IPS_DAYS_NORMAL_YEAR + | 
|  | 6213 | IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) - | 
|  | 6214 | IPS_NUM_LEAP_YEARS_THROUGH(year - 1); | 
|  | 6215 | year = newy; | 
|  | 6216 | } | 
|  | 6217 |  | 
|  | 6218 | scb->cmd.ffdc.yearH = year / 100; | 
|  | 6219 | scb->cmd.ffdc.yearL = year % 100; | 
|  | 6220 |  | 
|  | 6221 | for (i = 0; days >= month_lengths[i][yleap]; ++i) | 
|  | 6222 | days -= month_lengths[i][yleap]; | 
|  | 6223 |  | 
|  | 6224 | scb->cmd.ffdc.month = i + 1; | 
|  | 6225 | scb->cmd.ffdc.day = days + 1; | 
|  | 6226 | } | 
|  | 6227 |  | 
|  | 6228 | /**************************************************************************** | 
|  | 6229 | * BIOS Flash Routines                                                      * | 
|  | 6230 | ****************************************************************************/ | 
|  | 6231 |  | 
|  | 6232 | /****************************************************************************/ | 
|  | 6233 | /*                                                                          */ | 
|  | 6234 | /* Routine Name: ips_erase_bios                                             */ | 
|  | 6235 | /*                                                                          */ | 
|  | 6236 | /* Routine Description:                                                     */ | 
|  | 6237 | /*   Erase the BIOS on the adapter                                          */ | 
|  | 6238 | /*                                                                          */ | 
|  | 6239 | /****************************************************************************/ | 
|  | 6240 | static int | 
|  | 6241 | ips_erase_bios(ips_ha_t * ha) | 
|  | 6242 | { | 
|  | 6243 | int timeout; | 
|  | 6244 | uint8_t status = 0; | 
|  | 6245 |  | 
|  | 6246 | METHOD_TRACE("ips_erase_bios", 1); | 
|  | 6247 |  | 
|  | 6248 | status = 0; | 
|  | 6249 |  | 
|  | 6250 | /* Clear the status register */ | 
|  | 6251 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6252 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6253 | udelay(25);	/* 25 us */ | 
|  | 6254 |  | 
|  | 6255 | outb(0x50, ha->io_addr + IPS_REG_FLDP); | 
|  | 6256 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6257 | udelay(25);	/* 25 us */ | 
|  | 6258 |  | 
|  | 6259 | /* Erase Setup */ | 
|  | 6260 | outb(0x20, ha->io_addr + IPS_REG_FLDP); | 
|  | 6261 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6262 | udelay(25);	/* 25 us */ | 
|  | 6263 |  | 
|  | 6264 | /* Erase Confirm */ | 
|  | 6265 | outb(0xD0, ha->io_addr + IPS_REG_FLDP); | 
|  | 6266 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6267 | udelay(25);	/* 25 us */ | 
|  | 6268 |  | 
|  | 6269 | /* Erase Status */ | 
|  | 6270 | outb(0x70, ha->io_addr + IPS_REG_FLDP); | 
|  | 6271 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6272 | udelay(25);	/* 25 us */ | 
|  | 6273 |  | 
|  | 6274 | timeout = 80000;	/* 80 seconds */ | 
|  | 6275 |  | 
|  | 6276 | while (timeout > 0) { | 
|  | 6277 | if (ha->revision_id == IPS_REVID_TROMBONE64) { | 
|  | 6278 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6279 | udelay(25);	/* 25 us */ | 
|  | 6280 | } | 
|  | 6281 |  | 
|  | 6282 | status = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6283 |  | 
|  | 6284 | if (status & 0x80) | 
|  | 6285 | break; | 
|  | 6286 |  | 
|  | 6287 | MDELAY(1); | 
|  | 6288 | timeout--; | 
|  | 6289 | } | 
|  | 6290 |  | 
|  | 6291 | /* check for timeout */ | 
|  | 6292 | if (timeout <= 0) { | 
|  | 6293 | /* timeout */ | 
|  | 6294 |  | 
|  | 6295 | /* try to suspend the erase */ | 
|  | 6296 | outb(0xB0, ha->io_addr + IPS_REG_FLDP); | 
|  | 6297 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6298 | udelay(25);	/* 25 us */ | 
|  | 6299 |  | 
|  | 6300 | /* wait for 10 seconds */ | 
|  | 6301 | timeout = 10000; | 
|  | 6302 | while (timeout > 0) { | 
|  | 6303 | if (ha->revision_id == IPS_REVID_TROMBONE64) { | 
|  | 6304 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6305 | udelay(25);	/* 25 us */ | 
|  | 6306 | } | 
|  | 6307 |  | 
|  | 6308 | status = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6309 |  | 
|  | 6310 | if (status & 0xC0) | 
|  | 6311 | break; | 
|  | 6312 |  | 
|  | 6313 | MDELAY(1); | 
|  | 6314 | timeout--; | 
|  | 6315 | } | 
|  | 6316 |  | 
|  | 6317 | return (1); | 
|  | 6318 | } | 
|  | 6319 |  | 
|  | 6320 | /* check for valid VPP */ | 
|  | 6321 | if (status & 0x08) | 
|  | 6322 | /* VPP failure */ | 
|  | 6323 | return (1); | 
|  | 6324 |  | 
|  | 6325 | /* check for succesful flash */ | 
|  | 6326 | if (status & 0x30) | 
|  | 6327 | /* sequence error */ | 
|  | 6328 | return (1); | 
|  | 6329 |  | 
|  | 6330 | /* Otherwise, we were successful */ | 
|  | 6331 | /* clear status */ | 
|  | 6332 | outb(0x50, ha->io_addr + IPS_REG_FLDP); | 
|  | 6333 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6334 | udelay(25);	/* 25 us */ | 
|  | 6335 |  | 
|  | 6336 | /* enable reads */ | 
|  | 6337 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
|  | 6338 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6339 | udelay(25);	/* 25 us */ | 
|  | 6340 |  | 
|  | 6341 | return (0); | 
|  | 6342 | } | 
|  | 6343 |  | 
|  | 6344 | /****************************************************************************/ | 
|  | 6345 | /*                                                                          */ | 
|  | 6346 | /* Routine Name: ips_erase_bios_memio                                       */ | 
|  | 6347 | /*                                                                          */ | 
|  | 6348 | /* Routine Description:                                                     */ | 
|  | 6349 | /*   Erase the BIOS on the adapter                                          */ | 
|  | 6350 | /*                                                                          */ | 
|  | 6351 | /****************************************************************************/ | 
|  | 6352 | static int | 
|  | 6353 | ips_erase_bios_memio(ips_ha_t * ha) | 
|  | 6354 | { | 
|  | 6355 | int timeout; | 
|  | 6356 | uint8_t status; | 
|  | 6357 |  | 
|  | 6358 | METHOD_TRACE("ips_erase_bios_memio", 1); | 
|  | 6359 |  | 
|  | 6360 | status = 0; | 
|  | 6361 |  | 
|  | 6362 | /* Clear the status register */ | 
|  | 6363 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6364 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6365 | udelay(25);	/* 25 us */ | 
|  | 6366 |  | 
|  | 6367 | writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6368 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6369 | udelay(25);	/* 25 us */ | 
|  | 6370 |  | 
|  | 6371 | /* Erase Setup */ | 
|  | 6372 | writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6373 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6374 | udelay(25);	/* 25 us */ | 
|  | 6375 |  | 
|  | 6376 | /* Erase Confirm */ | 
|  | 6377 | writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6378 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6379 | udelay(25);	/* 25 us */ | 
|  | 6380 |  | 
|  | 6381 | /* Erase Status */ | 
|  | 6382 | writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6383 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6384 | udelay(25);	/* 25 us */ | 
|  | 6385 |  | 
|  | 6386 | timeout = 80000;	/* 80 seconds */ | 
|  | 6387 |  | 
|  | 6388 | while (timeout > 0) { | 
|  | 6389 | if (ha->revision_id == IPS_REVID_TROMBONE64) { | 
|  | 6390 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6391 | udelay(25);	/* 25 us */ | 
|  | 6392 | } | 
|  | 6393 |  | 
|  | 6394 | status = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6395 |  | 
|  | 6396 | if (status & 0x80) | 
|  | 6397 | break; | 
|  | 6398 |  | 
|  | 6399 | MDELAY(1); | 
|  | 6400 | timeout--; | 
|  | 6401 | } | 
|  | 6402 |  | 
|  | 6403 | /* check for timeout */ | 
|  | 6404 | if (timeout <= 0) { | 
|  | 6405 | /* timeout */ | 
|  | 6406 |  | 
|  | 6407 | /* try to suspend the erase */ | 
|  | 6408 | writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6409 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6410 | udelay(25);	/* 25 us */ | 
|  | 6411 |  | 
|  | 6412 | /* wait for 10 seconds */ | 
|  | 6413 | timeout = 10000; | 
|  | 6414 | while (timeout > 0) { | 
|  | 6415 | if (ha->revision_id == IPS_REVID_TROMBONE64) { | 
|  | 6416 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6417 | udelay(25);	/* 25 us */ | 
|  | 6418 | } | 
|  | 6419 |  | 
|  | 6420 | status = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6421 |  | 
|  | 6422 | if (status & 0xC0) | 
|  | 6423 | break; | 
|  | 6424 |  | 
|  | 6425 | MDELAY(1); | 
|  | 6426 | timeout--; | 
|  | 6427 | } | 
|  | 6428 |  | 
|  | 6429 | return (1); | 
|  | 6430 | } | 
|  | 6431 |  | 
|  | 6432 | /* check for valid VPP */ | 
|  | 6433 | if (status & 0x08) | 
|  | 6434 | /* VPP failure */ | 
|  | 6435 | return (1); | 
|  | 6436 |  | 
|  | 6437 | /* check for succesful flash */ | 
|  | 6438 | if (status & 0x30) | 
|  | 6439 | /* sequence error */ | 
|  | 6440 | return (1); | 
|  | 6441 |  | 
|  | 6442 | /* Otherwise, we were successful */ | 
|  | 6443 | /* clear status */ | 
|  | 6444 | writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6445 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6446 | udelay(25);	/* 25 us */ | 
|  | 6447 |  | 
|  | 6448 | /* enable reads */ | 
|  | 6449 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6450 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6451 | udelay(25);	/* 25 us */ | 
|  | 6452 |  | 
|  | 6453 | return (0); | 
|  | 6454 | } | 
|  | 6455 |  | 
|  | 6456 | /****************************************************************************/ | 
|  | 6457 | /*                                                                          */ | 
|  | 6458 | /* Routine Name: ips_program_bios                                           */ | 
|  | 6459 | /*                                                                          */ | 
|  | 6460 | /* Routine Description:                                                     */ | 
|  | 6461 | /*   Program the BIOS on the adapter                                        */ | 
|  | 6462 | /*                                                                          */ | 
|  | 6463 | /****************************************************************************/ | 
|  | 6464 | static int | 
|  | 6465 | ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6466 | uint32_t offset) | 
|  | 6467 | { | 
|  | 6468 | int i; | 
|  | 6469 | int timeout; | 
|  | 6470 | uint8_t status = 0; | 
|  | 6471 |  | 
|  | 6472 | METHOD_TRACE("ips_program_bios", 1); | 
|  | 6473 |  | 
|  | 6474 | status = 0; | 
|  | 6475 |  | 
|  | 6476 | for (i = 0; i < buffersize; i++) { | 
|  | 6477 | /* write a byte */ | 
|  | 6478 | outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); | 
|  | 6479 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6480 | udelay(25);	/* 25 us */ | 
|  | 6481 |  | 
|  | 6482 | outb(0x40, ha->io_addr + IPS_REG_FLDP); | 
|  | 6483 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6484 | udelay(25);	/* 25 us */ | 
|  | 6485 |  | 
|  | 6486 | outb(buffer[i], ha->io_addr + IPS_REG_FLDP); | 
|  | 6487 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6488 | udelay(25);	/* 25 us */ | 
|  | 6489 |  | 
|  | 6490 | /* wait up to one second */ | 
|  | 6491 | timeout = 1000; | 
|  | 6492 | while (timeout > 0) { | 
|  | 6493 | if (ha->revision_id == IPS_REVID_TROMBONE64) { | 
|  | 6494 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6495 | udelay(25);	/* 25 us */ | 
|  | 6496 | } | 
|  | 6497 |  | 
|  | 6498 | status = inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6499 |  | 
|  | 6500 | if (status & 0x80) | 
|  | 6501 | break; | 
|  | 6502 |  | 
|  | 6503 | MDELAY(1); | 
|  | 6504 | timeout--; | 
|  | 6505 | } | 
|  | 6506 |  | 
|  | 6507 | if (timeout == 0) { | 
|  | 6508 | /* timeout error */ | 
|  | 6509 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6510 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6511 | udelay(25);	/* 25 us */ | 
|  | 6512 |  | 
|  | 6513 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
|  | 6514 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6515 | udelay(25);	/* 25 us */ | 
|  | 6516 |  | 
|  | 6517 | return (1); | 
|  | 6518 | } | 
|  | 6519 |  | 
|  | 6520 | /* check the status */ | 
|  | 6521 | if (status & 0x18) { | 
|  | 6522 | /* programming error */ | 
|  | 6523 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6524 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6525 | udelay(25);	/* 25 us */ | 
|  | 6526 |  | 
|  | 6527 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
|  | 6528 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6529 | udelay(25);	/* 25 us */ | 
|  | 6530 |  | 
|  | 6531 | return (1); | 
|  | 6532 | } | 
|  | 6533 | }			/* end for */ | 
|  | 6534 |  | 
|  | 6535 | /* Enable reading */ | 
|  | 6536 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6537 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6538 | udelay(25);	/* 25 us */ | 
|  | 6539 |  | 
|  | 6540 | outb(0xFF, ha->io_addr + IPS_REG_FLDP); | 
|  | 6541 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6542 | udelay(25);	/* 25 us */ | 
|  | 6543 |  | 
|  | 6544 | return (0); | 
|  | 6545 | } | 
|  | 6546 |  | 
|  | 6547 | /****************************************************************************/ | 
|  | 6548 | /*                                                                          */ | 
|  | 6549 | /* Routine Name: ips_program_bios_memio                                     */ | 
|  | 6550 | /*                                                                          */ | 
|  | 6551 | /* Routine Description:                                                     */ | 
|  | 6552 | /*   Program the BIOS on the adapter                                        */ | 
|  | 6553 | /*                                                                          */ | 
|  | 6554 | /****************************************************************************/ | 
|  | 6555 | static int | 
|  | 6556 | ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6557 | uint32_t offset) | 
|  | 6558 | { | 
|  | 6559 | int i; | 
|  | 6560 | int timeout; | 
|  | 6561 | uint8_t status = 0; | 
|  | 6562 |  | 
|  | 6563 | METHOD_TRACE("ips_program_bios_memio", 1); | 
|  | 6564 |  | 
|  | 6565 | status = 0; | 
|  | 6566 |  | 
|  | 6567 | for (i = 0; i < buffersize; i++) { | 
|  | 6568 | /* write a byte */ | 
|  | 6569 | writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6570 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6571 | udelay(25);	/* 25 us */ | 
|  | 6572 |  | 
|  | 6573 | writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6574 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6575 | udelay(25);	/* 25 us */ | 
|  | 6576 |  | 
|  | 6577 | writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6578 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6579 | udelay(25);	/* 25 us */ | 
|  | 6580 |  | 
|  | 6581 | /* wait up to one second */ | 
|  | 6582 | timeout = 1000; | 
|  | 6583 | while (timeout > 0) { | 
|  | 6584 | if (ha->revision_id == IPS_REVID_TROMBONE64) { | 
|  | 6585 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6586 | udelay(25);	/* 25 us */ | 
|  | 6587 | } | 
|  | 6588 |  | 
|  | 6589 | status = readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6590 |  | 
|  | 6591 | if (status & 0x80) | 
|  | 6592 | break; | 
|  | 6593 |  | 
|  | 6594 | MDELAY(1); | 
|  | 6595 | timeout--; | 
|  | 6596 | } | 
|  | 6597 |  | 
|  | 6598 | if (timeout == 0) { | 
|  | 6599 | /* timeout error */ | 
|  | 6600 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6601 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6602 | udelay(25);	/* 25 us */ | 
|  | 6603 |  | 
|  | 6604 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6605 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6606 | udelay(25);	/* 25 us */ | 
|  | 6607 |  | 
|  | 6608 | return (1); | 
|  | 6609 | } | 
|  | 6610 |  | 
|  | 6611 | /* check the status */ | 
|  | 6612 | if (status & 0x18) { | 
|  | 6613 | /* programming error */ | 
|  | 6614 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6615 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6616 | udelay(25);	/* 25 us */ | 
|  | 6617 |  | 
|  | 6618 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6619 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6620 | udelay(25);	/* 25 us */ | 
|  | 6621 |  | 
|  | 6622 | return (1); | 
|  | 6623 | } | 
|  | 6624 | }			/* end for */ | 
|  | 6625 |  | 
|  | 6626 | /* Enable reading */ | 
|  | 6627 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6628 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6629 | udelay(25);	/* 25 us */ | 
|  | 6630 |  | 
|  | 6631 | writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6632 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6633 | udelay(25);	/* 25 us */ | 
|  | 6634 |  | 
|  | 6635 | return (0); | 
|  | 6636 | } | 
|  | 6637 |  | 
|  | 6638 | /****************************************************************************/ | 
|  | 6639 | /*                                                                          */ | 
|  | 6640 | /* Routine Name: ips_verify_bios                                            */ | 
|  | 6641 | /*                                                                          */ | 
|  | 6642 | /* Routine Description:                                                     */ | 
|  | 6643 | /*   Verify the BIOS on the adapter                                         */ | 
|  | 6644 | /*                                                                          */ | 
|  | 6645 | /****************************************************************************/ | 
|  | 6646 | static int | 
|  | 6647 | ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6648 | uint32_t offset) | 
|  | 6649 | { | 
|  | 6650 | uint8_t checksum; | 
|  | 6651 | int i; | 
|  | 6652 |  | 
|  | 6653 | METHOD_TRACE("ips_verify_bios", 1); | 
|  | 6654 |  | 
|  | 6655 | /* test 1st byte */ | 
|  | 6656 | outl(0, ha->io_addr + IPS_REG_FLAP); | 
|  | 6657 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6658 | udelay(25);	/* 25 us */ | 
|  | 6659 |  | 
|  | 6660 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) | 
|  | 6661 | return (1); | 
|  | 6662 |  | 
|  | 6663 | outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); | 
|  | 6664 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6665 | udelay(25);	/* 25 us */ | 
|  | 6666 | if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) | 
|  | 6667 | return (1); | 
|  | 6668 |  | 
|  | 6669 | checksum = 0xff; | 
|  | 6670 | for (i = 2; i < buffersize; i++) { | 
|  | 6671 |  | 
|  | 6672 | outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); | 
|  | 6673 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6674 | udelay(25);	/* 25 us */ | 
|  | 6675 |  | 
|  | 6676 | checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); | 
|  | 6677 | } | 
|  | 6678 |  | 
|  | 6679 | if (checksum != 0) | 
|  | 6680 | /* failure */ | 
|  | 6681 | return (1); | 
|  | 6682 | else | 
|  | 6683 | /* success */ | 
|  | 6684 | return (0); | 
|  | 6685 | } | 
|  | 6686 |  | 
|  | 6687 | /****************************************************************************/ | 
|  | 6688 | /*                                                                          */ | 
|  | 6689 | /* Routine Name: ips_verify_bios_memio                                      */ | 
|  | 6690 | /*                                                                          */ | 
|  | 6691 | /* Routine Description:                                                     */ | 
|  | 6692 | /*   Verify the BIOS on the adapter                                         */ | 
|  | 6693 | /*                                                                          */ | 
|  | 6694 | /****************************************************************************/ | 
|  | 6695 | static int | 
|  | 6696 | ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, | 
|  | 6697 | uint32_t offset) | 
|  | 6698 | { | 
|  | 6699 | uint8_t checksum; | 
|  | 6700 | int i; | 
|  | 6701 |  | 
|  | 6702 | METHOD_TRACE("ips_verify_bios_memio", 1); | 
|  | 6703 |  | 
|  | 6704 | /* test 1st byte */ | 
|  | 6705 | writel(0, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6706 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6707 | udelay(25);	/* 25 us */ | 
|  | 6708 |  | 
|  | 6709 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) | 
|  | 6710 | return (1); | 
|  | 6711 |  | 
|  | 6712 | writel(1, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6713 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6714 | udelay(25);	/* 25 us */ | 
|  | 6715 | if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) | 
|  | 6716 | return (1); | 
|  | 6717 |  | 
|  | 6718 | checksum = 0xff; | 
|  | 6719 | for (i = 2; i < buffersize; i++) { | 
|  | 6720 |  | 
|  | 6721 | writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); | 
|  | 6722 | if (ha->revision_id == IPS_REVID_TROMBONE64) | 
|  | 6723 | udelay(25);	/* 25 us */ | 
|  | 6724 |  | 
|  | 6725 | checksum = | 
|  | 6726 | (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); | 
|  | 6727 | } | 
|  | 6728 |  | 
|  | 6729 | if (checksum != 0) | 
|  | 6730 | /* failure */ | 
|  | 6731 | return (1); | 
|  | 6732 | else | 
|  | 6733 | /* success */ | 
|  | 6734 | return (0); | 
|  | 6735 | } | 
|  | 6736 |  | 
|  | 6737 | /*---------------------------------------------------------------------------*/ | 
|  | 6738 | /*   Routine Name: ips_version_check                                         */ | 
|  | 6739 | /*                                                                           */ | 
|  | 6740 | /*   Dependencies:                                                           */ | 
|  | 6741 | /*     Assumes that ips_read_adapter_status() is called first filling in     */ | 
|  | 6742 | /*     the data for SubSystem Parameters.                                    */ | 
|  | 6743 | /*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */ | 
|  | 6744 | /*     Data is available.                                                    */ | 
|  | 6745 | /*                                                                           */ | 
|  | 6746 | /*---------------------------------------------------------------------------*/ | 
|  | 6747 | static void | 
|  | 6748 | ips_version_check(ips_ha_t * ha, int intr) | 
|  | 6749 | { | 
|  | 6750 | IPS_VERSION_DATA *VersionInfo; | 
|  | 6751 | uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1]; | 
|  | 6752 | uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1]; | 
|  | 6753 | int MatchError; | 
|  | 6754 | int rc; | 
|  | 6755 | char BiosString[10]; | 
|  | 6756 | char FirmwareString[10]; | 
|  | 6757 |  | 
|  | 6758 | METHOD_TRACE("ips_version_check", 1); | 
|  | 6759 |  | 
|  | 6760 | VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data; | 
|  | 6761 |  | 
|  | 6762 | memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1); | 
|  | 6763 | memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1); | 
|  | 6764 |  | 
|  | 6765 | /* Get the Compatible BIOS Version from NVRAM Page 5 */ | 
|  | 6766 | memcpy(BiosVersion, ha->nvram->BiosCompatibilityID, | 
|  | 6767 | IPS_COMPAT_ID_LENGTH); | 
|  | 6768 |  | 
|  | 6769 | rc = IPS_FAILURE; | 
|  | 6770 | if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */ | 
|  | 6771 | /* Get the Version Info with a Get Version Command */ | 
|  | 6772 | memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA)); | 
|  | 6773 | rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr); | 
|  | 6774 | if (rc == IPS_SUCCESS) | 
|  | 6775 | memcpy(FirmwareVersion, VersionInfo->compatibilityId, | 
|  | 6776 | IPS_COMPAT_ID_LENGTH); | 
|  | 6777 | } | 
|  | 6778 |  | 
|  | 6779 | if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */ | 
|  | 6780 | /* Get the Firmware Version from Enquiry Data */ | 
|  | 6781 | memcpy(FirmwareVersion, ha->enq->CodeBlkVersion, | 
|  | 6782 | IPS_COMPAT_ID_LENGTH); | 
|  | 6783 | } | 
|  | 6784 |  | 
|  | 6785 | /* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */ | 
|  | 6786 | /* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */ | 
|  | 6787 | /* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */ | 
|  | 6788 | /* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */ | 
|  | 6789 |  | 
|  | 6790 | MatchError = 0; | 
|  | 6791 |  | 
|  | 6792 | if (strncmp | 
|  | 6793 | (FirmwareVersion, Compatable[ha->nvram->adapter_type], | 
|  | 6794 | IPS_COMPAT_ID_LENGTH) != 0) | 
|  | 6795 | MatchError = 1; | 
|  | 6796 |  | 
|  | 6797 | if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0) | 
|  | 6798 | MatchError = 1; | 
|  | 6799 |  | 
|  | 6800 | ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */ | 
|  | 6801 |  | 
|  | 6802 | if (MatchError) { | 
|  | 6803 | ha->nvram->version_mismatch = 1; | 
|  | 6804 | if (ips_cd_boot == 0) { | 
|  | 6805 | strncpy(&BiosString[0], ha->nvram->bios_high, 4); | 
|  | 6806 | strncpy(&BiosString[4], ha->nvram->bios_low, 4); | 
|  | 6807 | BiosString[8] = 0; | 
|  | 6808 |  | 
|  | 6809 | strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8); | 
|  | 6810 | FirmwareString[8] = 0; | 
|  | 6811 |  | 
|  | 6812 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 6813 | "Warning ! ! ! ServeRAID Version Mismatch\n"); | 
|  | 6814 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 6815 | "Bios = %s, Firmware = %s, Device Driver = %s%s\n", | 
|  | 6816 | BiosString, FirmwareString, IPS_VERSION_HIGH, | 
|  | 6817 | IPS_VERSION_LOW); | 
|  | 6818 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 6819 | "These levels should match to avoid possible compatibility problems.\n"); | 
|  | 6820 | } | 
|  | 6821 | } else { | 
|  | 6822 | ha->nvram->version_mismatch = 0; | 
|  | 6823 | } | 
|  | 6824 |  | 
|  | 6825 | return; | 
|  | 6826 | } | 
|  | 6827 |  | 
|  | 6828 | /*---------------------------------------------------------------------------*/ | 
|  | 6829 | /*   Routine Name: ips_get_version_info                                      */ | 
|  | 6830 | /*                                                                           */ | 
|  | 6831 | /*   Routine Description:                                                    */ | 
|  | 6832 | /*     Issue an internal GETVERSION Command                                  */ | 
|  | 6833 | /*                                                                           */ | 
|  | 6834 | /*   Return Value:                                                           */ | 
|  | 6835 | /*     0 if Successful, else non-zero                                        */ | 
|  | 6836 | /*---------------------------------------------------------------------------*/ | 
|  | 6837 | static int | 
|  | 6838 | ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr) | 
|  | 6839 | { | 
|  | 6840 | ips_scb_t *scb; | 
|  | 6841 | int rc; | 
|  | 6842 |  | 
|  | 6843 | METHOD_TRACE("ips_get_version_info", 1); | 
|  | 6844 |  | 
|  | 6845 | scb = &ha->scbs[ha->max_cmds - 1]; | 
|  | 6846 |  | 
|  | 6847 | ips_init_scb(ha, scb); | 
|  | 6848 |  | 
|  | 6849 | scb->timeout = ips_cmd_timeout; | 
|  | 6850 | scb->cdb[0] = IPS_CMD_GET_VERSION_INFO; | 
|  | 6851 | scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO; | 
|  | 6852 | scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb); | 
|  | 6853 | scb->cmd.version_info.reserved = 0; | 
|  | 6854 | scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA); | 
|  | 6855 | scb->cmd.version_info.reserved2 = 0; | 
|  | 6856 | scb->data_len = sizeof (IPS_VERSION_DATA); | 
|  | 6857 | scb->data_busaddr = Buffer; | 
|  | 6858 | scb->cmd.version_info.buffer_addr = Buffer; | 
|  | 6859 | scb->flags = 0; | 
|  | 6860 |  | 
|  | 6861 | /* issue command */ | 
|  | 6862 | rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr); | 
|  | 6863 | return (rc); | 
|  | 6864 | } | 
|  | 6865 |  | 
|  | 6866 | /****************************************************************************/ | 
|  | 6867 | /*                                                                          */ | 
|  | 6868 | /* Routine Name: ips_abort_init                                             */ | 
|  | 6869 | /*                                                                          */ | 
|  | 6870 | /* Routine Description:                                                     */ | 
|  | 6871 | /*   cleanup routine for a failed adapter initialization                    */ | 
|  | 6872 | /****************************************************************************/ | 
|  | 6873 | static int | 
|  | 6874 | ips_abort_init(ips_ha_t * ha, int index) | 
|  | 6875 | { | 
|  | 6876 | ha->active = 0; | 
|  | 6877 | ips_free(ha); | 
|  | 6878 | ips_ha[index] = NULL; | 
|  | 6879 | ips_sh[index] = NULL; | 
|  | 6880 | return -1; | 
|  | 6881 | } | 
|  | 6882 |  | 
|  | 6883 | /****************************************************************************/ | 
|  | 6884 | /*                                                                          */ | 
|  | 6885 | /* Routine Name: ips_shift_controllers                                      */ | 
|  | 6886 | /*                                                                          */ | 
|  | 6887 | /* Routine Description:                                                     */ | 
|  | 6888 | /*   helper function for ordering adapters                                  */ | 
|  | 6889 | /****************************************************************************/ | 
|  | 6890 | static void | 
|  | 6891 | ips_shift_controllers(int lowindex, int highindex) | 
|  | 6892 | { | 
|  | 6893 | ips_ha_t *ha_sav = ips_ha[highindex]; | 
|  | 6894 | struct Scsi_Host *sh_sav = ips_sh[highindex]; | 
|  | 6895 | int i; | 
|  | 6896 |  | 
|  | 6897 | for (i = highindex; i > lowindex; i--) { | 
|  | 6898 | ips_ha[i] = ips_ha[i - 1]; | 
|  | 6899 | ips_sh[i] = ips_sh[i - 1]; | 
|  | 6900 | ips_ha[i]->host_num = i; | 
|  | 6901 | } | 
|  | 6902 | ha_sav->host_num = lowindex; | 
|  | 6903 | ips_ha[lowindex] = ha_sav; | 
|  | 6904 | ips_sh[lowindex] = sh_sav; | 
|  | 6905 | } | 
|  | 6906 |  | 
|  | 6907 | /****************************************************************************/ | 
|  | 6908 | /*                                                                          */ | 
|  | 6909 | /* Routine Name: ips_order_controllers                                      */ | 
|  | 6910 | /*                                                                          */ | 
|  | 6911 | /* Routine Description:                                                     */ | 
|  | 6912 | /*   place controllers is the "proper" boot order                           */ | 
|  | 6913 | /****************************************************************************/ | 
|  | 6914 | static void | 
|  | 6915 | ips_order_controllers(void) | 
|  | 6916 | { | 
|  | 6917 | int i, j, tmp, position = 0; | 
|  | 6918 | IPS_NVRAM_P5 *nvram; | 
|  | 6919 | if (!ips_ha[0]) | 
|  | 6920 | return; | 
|  | 6921 | nvram = ips_ha[0]->nvram; | 
|  | 6922 |  | 
|  | 6923 | if (nvram->adapter_order[0]) { | 
|  | 6924 | for (i = 1; i <= nvram->adapter_order[0]; i++) { | 
|  | 6925 | for (j = position; j < ips_num_controllers; j++) { | 
|  | 6926 | switch (ips_ha[j]->ad_type) { | 
|  | 6927 | case IPS_ADTYPE_SERVERAID6M: | 
|  | 6928 | case IPS_ADTYPE_SERVERAID7M: | 
|  | 6929 | if (nvram->adapter_order[i] == 'M') { | 
|  | 6930 | ips_shift_controllers(position, | 
|  | 6931 | j); | 
|  | 6932 | position++; | 
|  | 6933 | } | 
|  | 6934 | break; | 
|  | 6935 | case IPS_ADTYPE_SERVERAID4L: | 
|  | 6936 | case IPS_ADTYPE_SERVERAID4M: | 
|  | 6937 | case IPS_ADTYPE_SERVERAID4MX: | 
|  | 6938 | case IPS_ADTYPE_SERVERAID4LX: | 
|  | 6939 | if (nvram->adapter_order[i] == 'N') { | 
|  | 6940 | ips_shift_controllers(position, | 
|  | 6941 | j); | 
|  | 6942 | position++; | 
|  | 6943 | } | 
|  | 6944 | break; | 
|  | 6945 | case IPS_ADTYPE_SERVERAID6I: | 
|  | 6946 | case IPS_ADTYPE_SERVERAID5I2: | 
|  | 6947 | case IPS_ADTYPE_SERVERAID5I1: | 
|  | 6948 | case IPS_ADTYPE_SERVERAID7k: | 
|  | 6949 | if (nvram->adapter_order[i] == 'S') { | 
|  | 6950 | ips_shift_controllers(position, | 
|  | 6951 | j); | 
|  | 6952 | position++; | 
|  | 6953 | } | 
|  | 6954 | break; | 
|  | 6955 | case IPS_ADTYPE_SERVERAID: | 
|  | 6956 | case IPS_ADTYPE_SERVERAID2: | 
|  | 6957 | case IPS_ADTYPE_NAVAJO: | 
|  | 6958 | case IPS_ADTYPE_KIOWA: | 
|  | 6959 | case IPS_ADTYPE_SERVERAID3L: | 
|  | 6960 | case IPS_ADTYPE_SERVERAID3: | 
|  | 6961 | case IPS_ADTYPE_SERVERAID4H: | 
|  | 6962 | if (nvram->adapter_order[i] == 'A') { | 
|  | 6963 | ips_shift_controllers(position, | 
|  | 6964 | j); | 
|  | 6965 | position++; | 
|  | 6966 | } | 
|  | 6967 | break; | 
|  | 6968 | default: | 
|  | 6969 | break; | 
|  | 6970 | } | 
|  | 6971 | } | 
|  | 6972 | } | 
|  | 6973 | /* if adapter_order[0], then ordering is complete */ | 
|  | 6974 | return; | 
|  | 6975 | } | 
|  | 6976 | /* old bios, use older ordering */ | 
|  | 6977 | tmp = 0; | 
|  | 6978 | for (i = position; i < ips_num_controllers; i++) { | 
|  | 6979 | if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 || | 
|  | 6980 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) { | 
|  | 6981 | ips_shift_controllers(position, i); | 
|  | 6982 | position++; | 
|  | 6983 | tmp = 1; | 
|  | 6984 | } | 
|  | 6985 | } | 
|  | 6986 | /* if there were no 5I cards, then don't do any extra ordering */ | 
|  | 6987 | if (!tmp) | 
|  | 6988 | return; | 
|  | 6989 | for (i = position; i < ips_num_controllers; i++) { | 
|  | 6990 | if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L || | 
|  | 6991 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M || | 
|  | 6992 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX || | 
|  | 6993 | ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) { | 
|  | 6994 | ips_shift_controllers(position, i); | 
|  | 6995 | position++; | 
|  | 6996 | } | 
|  | 6997 | } | 
|  | 6998 |  | 
|  | 6999 | return; | 
|  | 7000 | } | 
|  | 7001 |  | 
|  | 7002 | /****************************************************************************/ | 
|  | 7003 | /*                                                                          */ | 
|  | 7004 | /* Routine Name: ips_register_scsi                                          */ | 
|  | 7005 | /*                                                                          */ | 
|  | 7006 | /* Routine Description:                                                     */ | 
|  | 7007 | /*   perform any registration and setup with the scsi layer                 */ | 
|  | 7008 | /****************************************************************************/ | 
|  | 7009 | static int | 
|  | 7010 | ips_register_scsi(int index) | 
|  | 7011 | { | 
|  | 7012 | struct Scsi_Host *sh; | 
|  | 7013 | ips_ha_t *ha, *oldha = ips_ha[index]; | 
|  | 7014 | sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t)); | 
|  | 7015 | if (!sh) { | 
|  | 7016 | IPS_PRINTK(KERN_WARNING, oldha->pcidev, | 
|  | 7017 | "Unable to register controller with SCSI subsystem\n"); | 
|  | 7018 | return -1; | 
|  | 7019 | } | 
|  | 7020 | ha = IPS_HA(sh); | 
|  | 7021 | memcpy(ha, oldha, sizeof (ips_ha_t)); | 
|  | 7022 | free_irq(oldha->irq, oldha); | 
|  | 7023 | /* Install the interrupt handler with the new ha */ | 
|  | 7024 | if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { | 
|  | 7025 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7026 | "Unable to install interrupt handler\n"); | 
|  | 7027 | scsi_host_put(sh); | 
|  | 7028 | return -1; | 
|  | 7029 | } | 
|  | 7030 |  | 
|  | 7031 | kfree(oldha); | 
|  | 7032 | ips_sh[index] = sh; | 
|  | 7033 | ips_ha[index] = ha; | 
|  | 7034 | IPS_SCSI_SET_DEVICE(sh, ha); | 
|  | 7035 |  | 
|  | 7036 | /* Store away needed values for later use */ | 
|  | 7037 | sh->io_port = ha->io_addr; | 
|  | 7038 | sh->n_io_port = ha->io_addr ? 255 : 0; | 
|  | 7039 | sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; | 
|  | 7040 | sh->irq = ha->irq; | 
|  | 7041 | sh->sg_tablesize = sh->hostt->sg_tablesize; | 
|  | 7042 | sh->can_queue = sh->hostt->can_queue; | 
|  | 7043 | sh->cmd_per_lun = sh->hostt->cmd_per_lun; | 
|  | 7044 | sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; | 
|  | 7045 | sh->use_clustering = sh->hostt->use_clustering; | 
|  | 7046 |  | 
|  | 7047 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) | 
|  | 7048 | sh->max_sectors = 128; | 
|  | 7049 | #endif | 
|  | 7050 |  | 
|  | 7051 | sh->max_id = ha->ntargets; | 
|  | 7052 | sh->max_lun = ha->nlun; | 
|  | 7053 | sh->max_channel = ha->nbus - 1; | 
|  | 7054 | sh->can_queue = ha->max_cmds - 1; | 
|  | 7055 |  | 
|  | 7056 | IPS_ADD_HOST(sh, NULL); | 
|  | 7057 | return 0; | 
|  | 7058 | } | 
|  | 7059 |  | 
|  | 7060 | /*---------------------------------------------------------------------------*/ | 
|  | 7061 | /*   Routine Name: ips_remove_device                                         */ | 
|  | 7062 | /*                                                                           */ | 
|  | 7063 | /*   Routine Description:                                                    */ | 
|  | 7064 | /*     Remove one Adapter ( Hot Plugging )                                   */ | 
|  | 7065 | /*---------------------------------------------------------------------------*/ | 
|  | 7066 | static void __devexit | 
|  | 7067 | ips_remove_device(struct pci_dev *pci_dev) | 
|  | 7068 | { | 
|  | 7069 | int i; | 
|  | 7070 | struct Scsi_Host *sh; | 
|  | 7071 | ips_ha_t *ha; | 
|  | 7072 |  | 
|  | 7073 | for (i = 0; i < IPS_MAX_ADAPTERS; i++) { | 
|  | 7074 | ha = ips_ha[i]; | 
|  | 7075 | if (ha) { | 
|  | 7076 | if ((pci_dev->bus->number == ha->pcidev->bus->number) && | 
|  | 7077 | (pci_dev->devfn == ha->pcidev->devfn)) { | 
|  | 7078 | sh = ips_sh[i]; | 
|  | 7079 | ips_release(sh); | 
|  | 7080 | } | 
|  | 7081 | } | 
|  | 7082 | } | 
|  | 7083 | } | 
|  | 7084 |  | 
|  | 7085 | /****************************************************************************/ | 
|  | 7086 | /*                                                                          */ | 
|  | 7087 | /* Routine Name: ips_module_init                                            */ | 
|  | 7088 | /*                                                                          */ | 
|  | 7089 | /* Routine Description:                                                     */ | 
|  | 7090 | /*   function called on module load                                         */ | 
|  | 7091 | /****************************************************************************/ | 
|  | 7092 | static int __init | 
|  | 7093 | ips_module_init(void) | 
|  | 7094 | { | 
|  | 7095 | if (pci_module_init(&ips_pci_driver) < 0) | 
|  | 7096 | return -ENODEV; | 
|  | 7097 | ips_driver_template.module = THIS_MODULE; | 
|  | 7098 | ips_order_controllers(); | 
|  | 7099 | if (IPS_REGISTER_HOSTS(&ips_driver_template)) { | 
|  | 7100 | pci_unregister_driver(&ips_pci_driver); | 
|  | 7101 | return -ENODEV; | 
|  | 7102 | } | 
|  | 7103 | register_reboot_notifier(&ips_notifier); | 
|  | 7104 | return 0; | 
|  | 7105 | } | 
|  | 7106 |  | 
|  | 7107 | /****************************************************************************/ | 
|  | 7108 | /*                                                                          */ | 
|  | 7109 | /* Routine Name: ips_module_exit                                            */ | 
|  | 7110 | /*                                                                          */ | 
|  | 7111 | /* Routine Description:                                                     */ | 
|  | 7112 | /*   function called on module unload                                       */ | 
|  | 7113 | /****************************************************************************/ | 
|  | 7114 | static void __exit | 
|  | 7115 | ips_module_exit(void) | 
|  | 7116 | { | 
|  | 7117 | IPS_UNREGISTER_HOSTS(&ips_driver_template); | 
|  | 7118 | pci_unregister_driver(&ips_pci_driver); | 
|  | 7119 | unregister_reboot_notifier(&ips_notifier); | 
|  | 7120 | } | 
|  | 7121 |  | 
|  | 7122 | module_init(ips_module_init); | 
|  | 7123 | module_exit(ips_module_exit); | 
|  | 7124 |  | 
|  | 7125 | /*---------------------------------------------------------------------------*/ | 
|  | 7126 | /*   Routine Name: ips_insert_device                                         */ | 
|  | 7127 | /*                                                                           */ | 
|  | 7128 | /*   Routine Description:                                                    */ | 
|  | 7129 | /*     Add One Adapter ( Hot Plug )                                          */ | 
|  | 7130 | /*                                                                           */ | 
|  | 7131 | /*   Return Value:                                                           */ | 
|  | 7132 | /*     0 if Successful, else non-zero                                        */ | 
|  | 7133 | /*---------------------------------------------------------------------------*/ | 
|  | 7134 | static int __devinit | 
|  | 7135 | ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) | 
|  | 7136 | { | 
|  | 7137 | int index; | 
|  | 7138 | int rc; | 
|  | 7139 |  | 
|  | 7140 | METHOD_TRACE("ips_insert_device", 1); | 
|  | 7141 | if (pci_enable_device(pci_dev)) | 
|  | 7142 | return -1; | 
|  | 7143 |  | 
|  | 7144 | rc = ips_init_phase1(pci_dev, &index); | 
|  | 7145 | if (rc == SUCCESS) | 
|  | 7146 | rc = ips_init_phase2(index); | 
|  | 7147 |  | 
|  | 7148 | if (ips_hotplug) | 
|  | 7149 | if (ips_register_scsi(index)) { | 
|  | 7150 | ips_free(ips_ha[index]); | 
|  | 7151 | rc = -1; | 
|  | 7152 | } | 
|  | 7153 |  | 
|  | 7154 | if (rc == SUCCESS) | 
|  | 7155 | ips_num_controllers++; | 
|  | 7156 |  | 
|  | 7157 | ips_next_controller = ips_num_controllers; | 
|  | 7158 | return rc; | 
|  | 7159 | } | 
|  | 7160 |  | 
|  | 7161 | /*---------------------------------------------------------------------------*/ | 
|  | 7162 | /*   Routine Name: ips_init_phase1                                           */ | 
|  | 7163 | /*                                                                           */ | 
|  | 7164 | /*   Routine Description:                                                    */ | 
|  | 7165 | /*     Adapter Initialization                                                */ | 
|  | 7166 | /*                                                                           */ | 
|  | 7167 | /*   Return Value:                                                           */ | 
|  | 7168 | /*     0 if Successful, else non-zero                                        */ | 
|  | 7169 | /*---------------------------------------------------------------------------*/ | 
|  | 7170 | static int | 
|  | 7171 | ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) | 
|  | 7172 | { | 
|  | 7173 | ips_ha_t *ha; | 
|  | 7174 | uint32_t io_addr; | 
|  | 7175 | uint32_t mem_addr; | 
|  | 7176 | uint32_t io_len; | 
|  | 7177 | uint32_t mem_len; | 
|  | 7178 | uint8_t revision_id; | 
|  | 7179 | uint8_t bus; | 
|  | 7180 | uint8_t func; | 
|  | 7181 | uint8_t irq; | 
|  | 7182 | uint16_t subdevice_id; | 
|  | 7183 | int j; | 
|  | 7184 | int index; | 
|  | 7185 | dma_addr_t dma_address; | 
|  | 7186 | char __iomem *ioremap_ptr; | 
|  | 7187 | char __iomem *mem_ptr; | 
|  | 7188 | uint32_t IsDead; | 
|  | 7189 |  | 
|  | 7190 | METHOD_TRACE("ips_init_phase1", 1); | 
|  | 7191 | index = IPS_MAX_ADAPTERS; | 
|  | 7192 | for (j = 0; j < IPS_MAX_ADAPTERS; j++) { | 
|  | 7193 | if (ips_ha[j] == 0) { | 
|  | 7194 | index = j; | 
|  | 7195 | break; | 
|  | 7196 | } | 
|  | 7197 | } | 
|  | 7198 |  | 
|  | 7199 | if (index >= IPS_MAX_ADAPTERS) | 
|  | 7200 | return -1; | 
|  | 7201 |  | 
|  | 7202 | /* stuff that we get in dev */ | 
|  | 7203 | irq = pci_dev->irq; | 
|  | 7204 | bus = pci_dev->bus->number; | 
|  | 7205 | func = pci_dev->devfn; | 
|  | 7206 |  | 
|  | 7207 | /* Init MEM/IO addresses to 0 */ | 
|  | 7208 | mem_addr = 0; | 
|  | 7209 | io_addr = 0; | 
|  | 7210 | mem_len = 0; | 
|  | 7211 | io_len = 0; | 
|  | 7212 |  | 
|  | 7213 | for (j = 0; j < 2; j++) { | 
|  | 7214 | if (!pci_resource_start(pci_dev, j)) | 
|  | 7215 | break; | 
|  | 7216 |  | 
|  | 7217 | if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) { | 
|  | 7218 | io_addr = pci_resource_start(pci_dev, j); | 
|  | 7219 | io_len = pci_resource_len(pci_dev, j); | 
|  | 7220 | } else { | 
|  | 7221 | mem_addr = pci_resource_start(pci_dev, j); | 
|  | 7222 | mem_len = pci_resource_len(pci_dev, j); | 
|  | 7223 | } | 
|  | 7224 | } | 
|  | 7225 |  | 
|  | 7226 | /* setup memory mapped area (if applicable) */ | 
|  | 7227 | if (mem_addr) { | 
|  | 7228 | uint32_t base; | 
|  | 7229 | uint32_t offs; | 
|  | 7230 |  | 
|  | 7231 | if (!request_mem_region(mem_addr, mem_len, "ips")) { | 
|  | 7232 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7233 | "Couldn't allocate IO Memory space %x len %d.\n", | 
|  | 7234 | mem_addr, mem_len); | 
|  | 7235 | return -1; | 
|  | 7236 | } | 
|  | 7237 |  | 
|  | 7238 | base = mem_addr & PAGE_MASK; | 
|  | 7239 | offs = mem_addr - base; | 
|  | 7240 | ioremap_ptr = ioremap(base, PAGE_SIZE); | 
|  | 7241 | mem_ptr = ioremap_ptr + offs; | 
|  | 7242 | } else { | 
|  | 7243 | ioremap_ptr = NULL; | 
|  | 7244 | mem_ptr = NULL; | 
|  | 7245 | } | 
|  | 7246 |  | 
|  | 7247 | /* setup I/O mapped area (if applicable) */ | 
|  | 7248 | if (io_addr) { | 
|  | 7249 | if (!request_region(io_addr, io_len, "ips")) { | 
|  | 7250 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7251 | "Couldn't allocate IO space %x len %d.\n", | 
|  | 7252 | io_addr, io_len); | 
|  | 7253 | return -1; | 
|  | 7254 | } | 
|  | 7255 | } | 
|  | 7256 |  | 
|  | 7257 | /* get the revision ID */ | 
|  | 7258 | if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) { | 
|  | 7259 | IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n"); | 
|  | 7260 | return -1; | 
|  | 7261 | } | 
|  | 7262 |  | 
|  | 7263 | subdevice_id = pci_dev->subsystem_device; | 
|  | 7264 |  | 
|  | 7265 | /* found a controller */ | 
|  | 7266 | ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL); | 
|  | 7267 | if (ha == NULL) { | 
|  | 7268 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7269 | "Unable to allocate temporary ha struct\n"); | 
|  | 7270 | return -1; | 
|  | 7271 | } | 
|  | 7272 |  | 
|  | 7273 | memset(ha, 0, sizeof (ips_ha_t)); | 
|  | 7274 |  | 
|  | 7275 | ips_sh[index] = NULL; | 
|  | 7276 | ips_ha[index] = ha; | 
|  | 7277 | ha->active = 1; | 
|  | 7278 |  | 
|  | 7279 | /* Store info in HA structure */ | 
|  | 7280 | ha->irq = irq; | 
|  | 7281 | ha->io_addr = io_addr; | 
|  | 7282 | ha->io_len = io_len; | 
|  | 7283 | ha->mem_addr = mem_addr; | 
|  | 7284 | ha->mem_len = mem_len; | 
|  | 7285 | ha->mem_ptr = mem_ptr; | 
|  | 7286 | ha->ioremap_ptr = ioremap_ptr; | 
|  | 7287 | ha->host_num = (uint32_t) index; | 
|  | 7288 | ha->revision_id = revision_id; | 
|  | 7289 | ha->slot_num = PCI_SLOT(pci_dev->devfn); | 
|  | 7290 | ha->device_id = pci_dev->device; | 
|  | 7291 | ha->subdevice_id = subdevice_id; | 
|  | 7292 | ha->pcidev = pci_dev; | 
|  | 7293 |  | 
|  | 7294 | /* | 
|  | 7295 | * Set the pci_dev's dma_mask.  Not all adapters support 64bit | 
|  | 7296 | * addressing so don't enable it if the adapter can't support | 
|  | 7297 | * it!  Also, don't use 64bit addressing if dma addresses | 
|  | 7298 | * are guaranteed to be < 4G. | 
|  | 7299 | */ | 
|  | 7300 | if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) && | 
|  | 7301 | !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) { | 
|  | 7302 | (ha)->flags |= IPS_HA_ENH_SG; | 
|  | 7303 | } else { | 
|  | 7304 | if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) { | 
|  | 7305 | printk(KERN_WARNING "Unable to set DMA Mask\n"); | 
|  | 7306 | return ips_abort_init(ha, index); | 
|  | 7307 | } | 
|  | 7308 | } | 
|  | 7309 | if(ips_cd_boot && !ips_FlashData){ | 
|  | 7310 | ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7, | 
|  | 7311 | &ips_flashbusaddr); | 
|  | 7312 | } | 
|  | 7313 |  | 
|  | 7314 | ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ), | 
|  | 7315 | &ha->enq_busaddr); | 
|  | 7316 | if (!ha->enq) { | 
|  | 7317 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7318 | "Unable to allocate host inquiry structure\n"); | 
|  | 7319 | return ips_abort_init(ha, index); | 
|  | 7320 | } | 
|  | 7321 |  | 
|  | 7322 | ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) + | 
|  | 7323 | sizeof (IPS_IO_CMD), &dma_address); | 
|  | 7324 | if (!ha->adapt) { | 
|  | 7325 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7326 | "Unable to allocate host adapt & dummy structures\n"); | 
|  | 7327 | return ips_abort_init(ha, index); | 
|  | 7328 | } | 
|  | 7329 | ha->adapt->hw_status_start = dma_address; | 
|  | 7330 | ha->dummy = (void *) (ha->adapt + 1); | 
|  | 7331 |  | 
|  | 7332 |  | 
|  | 7333 |  | 
|  | 7334 | ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address); | 
|  | 7335 | if (!ha->logical_drive_info) { | 
|  | 7336 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7337 | "Unable to allocate logical drive info structure\n"); | 
|  | 7338 | return ips_abort_init(ha, index); | 
|  | 7339 | } | 
|  | 7340 | ha->logical_drive_info_dma_addr = dma_address; | 
|  | 7341 |  | 
|  | 7342 |  | 
|  | 7343 | ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL); | 
|  | 7344 |  | 
|  | 7345 | if (!ha->conf) { | 
|  | 7346 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7347 | "Unable to allocate host conf structure\n"); | 
|  | 7348 | return ips_abort_init(ha, index); | 
|  | 7349 | } | 
|  | 7350 |  | 
|  | 7351 | ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL); | 
|  | 7352 |  | 
|  | 7353 | if (!ha->nvram) { | 
|  | 7354 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7355 | "Unable to allocate host NVRAM structure\n"); | 
|  | 7356 | return ips_abort_init(ha, index); | 
|  | 7357 | } | 
|  | 7358 |  | 
|  | 7359 | ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL); | 
|  | 7360 |  | 
|  | 7361 | if (!ha->subsys) { | 
|  | 7362 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7363 | "Unable to allocate host subsystem structure\n"); | 
|  | 7364 | return ips_abort_init(ha, index); | 
|  | 7365 | } | 
|  | 7366 |  | 
|  | 7367 | /* the ioctl buffer is now used during adapter initialization, so its | 
|  | 7368 | * successful allocation is now required */ | 
|  | 7369 | if (ips_ioctlsize < PAGE_SIZE) | 
|  | 7370 | ips_ioctlsize = PAGE_SIZE; | 
|  | 7371 |  | 
|  | 7372 | ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize, | 
|  | 7373 | &ha->ioctl_busaddr); | 
|  | 7374 | ha->ioctl_len = ips_ioctlsize; | 
|  | 7375 | if (!ha->ioctl_data) { | 
|  | 7376 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7377 | "Unable to allocate IOCTL data\n"); | 
|  | 7378 | return ips_abort_init(ha, index); | 
|  | 7379 | } | 
|  | 7380 |  | 
|  | 7381 | /* | 
|  | 7382 | * Setup Functions | 
|  | 7383 | */ | 
|  | 7384 | ips_setup_funclist(ha); | 
|  | 7385 |  | 
|  | 7386 | if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) { | 
|  | 7387 | /* If Morpheus appears dead, reset it */ | 
|  | 7388 | IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1); | 
|  | 7389 | if (IsDead == 0xDEADBEEF) { | 
|  | 7390 | ips_reset_morpheus(ha); | 
|  | 7391 | } | 
|  | 7392 | } | 
|  | 7393 |  | 
|  | 7394 | /* | 
|  | 7395 | * Initialize the card if it isn't already | 
|  | 7396 | */ | 
|  | 7397 |  | 
|  | 7398 | if (!(*ha->func.isinit) (ha)) { | 
|  | 7399 | if (!(*ha->func.init) (ha)) { | 
|  | 7400 | /* | 
|  | 7401 | * Initialization failed | 
|  | 7402 | */ | 
|  | 7403 | IPS_PRINTK(KERN_WARNING, pci_dev, | 
|  | 7404 | "Unable to initialize controller\n"); | 
|  | 7405 | return ips_abort_init(ha, index); | 
|  | 7406 | } | 
|  | 7407 | } | 
|  | 7408 |  | 
|  | 7409 | *indexPtr = index; | 
|  | 7410 | return SUCCESS; | 
|  | 7411 | } | 
|  | 7412 |  | 
|  | 7413 | /*---------------------------------------------------------------------------*/ | 
|  | 7414 | /*   Routine Name: ips_init_phase2                                           */ | 
|  | 7415 | /*                                                                           */ | 
|  | 7416 | /*   Routine Description:                                                    */ | 
|  | 7417 | /*     Adapter Initialization Phase 2                                        */ | 
|  | 7418 | /*                                                                           */ | 
|  | 7419 | /*   Return Value:                                                           */ | 
|  | 7420 | /*     0 if Successful, else non-zero                                        */ | 
|  | 7421 | /*---------------------------------------------------------------------------*/ | 
|  | 7422 | static int | 
|  | 7423 | ips_init_phase2(int index) | 
|  | 7424 | { | 
|  | 7425 | ips_ha_t *ha; | 
|  | 7426 |  | 
|  | 7427 | ha = ips_ha[index]; | 
|  | 7428 |  | 
|  | 7429 | METHOD_TRACE("ips_init_phase2", 1); | 
|  | 7430 | if (!ha->active) { | 
|  | 7431 | ips_ha[index] = NULL; | 
|  | 7432 | return -1; | 
|  | 7433 | } | 
|  | 7434 |  | 
|  | 7435 | /* Install the interrupt handler */ | 
|  | 7436 | if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { | 
|  | 7437 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7438 | "Unable to install interrupt handler\n"); | 
|  | 7439 | return ips_abort_init(ha, index); | 
|  | 7440 | } | 
|  | 7441 |  | 
|  | 7442 | /* | 
|  | 7443 | * Allocate a temporary SCB for initialization | 
|  | 7444 | */ | 
|  | 7445 | ha->max_cmds = 1; | 
|  | 7446 | if (!ips_allocatescbs(ha)) { | 
|  | 7447 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7448 | "Unable to allocate a CCB\n"); | 
|  | 7449 | free_irq(ha->irq, ha); | 
|  | 7450 | return ips_abort_init(ha, index); | 
|  | 7451 | } | 
|  | 7452 |  | 
|  | 7453 | if (!ips_hainit(ha)) { | 
|  | 7454 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7455 | "Unable to initialize controller\n"); | 
|  | 7456 | free_irq(ha->irq, ha); | 
|  | 7457 | return ips_abort_init(ha, index); | 
|  | 7458 | } | 
|  | 7459 | /* Free the temporary SCB */ | 
|  | 7460 | ips_deallocatescbs(ha, 1); | 
|  | 7461 |  | 
|  | 7462 | /* allocate CCBs */ | 
|  | 7463 | if (!ips_allocatescbs(ha)) { | 
|  | 7464 | IPS_PRINTK(KERN_WARNING, ha->pcidev, | 
|  | 7465 | "Unable to allocate CCBs\n"); | 
|  | 7466 | free_irq(ha->irq, ha); | 
|  | 7467 | return ips_abort_init(ha, index); | 
|  | 7468 | } | 
|  | 7469 |  | 
|  | 7470 | return SUCCESS; | 
|  | 7471 | } | 
|  | 7472 |  | 
|  | 7473 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9) | 
|  | 7474 | MODULE_LICENSE("GPL"); | 
|  | 7475 | #endif | 
|  | 7476 |  | 
|  | 7477 | MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING); | 
|  | 7478 |  | 
|  | 7479 | #ifdef MODULE_VERSION | 
|  | 7480 | MODULE_VERSION(IPS_VER_STRING); | 
|  | 7481 | #endif | 
|  | 7482 |  | 
|  | 7483 |  | 
|  | 7484 | /* | 
|  | 7485 | * Overrides for Emacs so that we almost follow Linus's tabbing style. | 
|  | 7486 | * Emacs will notice this stuff at the end of the file and automatically | 
|  | 7487 | * adjust the settings for this buffer only.  This must remain at the end | 
|  | 7488 | * of the file. | 
|  | 7489 | * --------------------------------------------------------------------------- | 
|  | 7490 | * Local variables: | 
|  | 7491 | * c-indent-level: 2 | 
|  | 7492 | * c-brace-imaginary-offset: 0 | 
|  | 7493 | * c-brace-offset: -2 | 
|  | 7494 | * c-argdecl-indent: 2 | 
|  | 7495 | * c-label-offset: -2 | 
|  | 7496 | * c-continued-statement-offset: 2 | 
|  | 7497 | * c-continued-brace-offset: 0 | 
|  | 7498 | * indent-tabs-mode: nil | 
|  | 7499 | * tab-width: 8 | 
|  | 7500 | * End: | 
|  | 7501 | */ |