xref: /openbmc/linux/drivers/scsi/ips.c (revision c1a15468d58e75debc5437b2e4e12d02a89bb3a2)
11da177e4SLinus Torvalds /*****************************************************************************/
21da177e4SLinus Torvalds /* ips.c -- driver for the Adaptec / IBM ServeRAID controller                */
31da177e4SLinus Torvalds /*                                                                           */
41da177e4SLinus Torvalds /* Written By: Keith Mitchell, IBM Corporation                               */
51da177e4SLinus Torvalds /*             Jack Hammer, Adaptec, Inc.                                    */
61da177e4SLinus Torvalds /*             David Jeffery, Adaptec, Inc.                                  */
71da177e4SLinus Torvalds /*                                                                           */
81da177e4SLinus Torvalds /* Copyright (C) 2000 IBM Corporation                                        */
91da177e4SLinus Torvalds /* Copyright (C) 2002,2003 Adaptec, Inc.                                     */
101da177e4SLinus Torvalds /*                                                                           */
111da177e4SLinus Torvalds /* This program is free software; you can redistribute it and/or modify      */
121da177e4SLinus Torvalds /* it under the terms of the GNU General Public License as published by      */
131da177e4SLinus Torvalds /* the Free Software Foundation; either version 2 of the License, or         */
141da177e4SLinus Torvalds /* (at your option) any later version.                                       */
151da177e4SLinus Torvalds /*                                                                           */
161da177e4SLinus Torvalds /* This program is distributed in the hope that it will be useful,           */
171da177e4SLinus Torvalds /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
181da177e4SLinus Torvalds /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
191da177e4SLinus Torvalds /* GNU General Public License for more details.                              */
201da177e4SLinus Torvalds /*                                                                           */
211da177e4SLinus Torvalds /* NO WARRANTY                                                               */
221da177e4SLinus Torvalds /* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        */
231da177e4SLinus Torvalds /* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      */
241da177e4SLinus Torvalds /* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      */
251da177e4SLinus Torvalds /* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    */
261da177e4SLinus Torvalds /* solely responsible for determining the appropriateness of using and       */
271da177e4SLinus Torvalds /* distributing the Program and assumes all risks associated with its        */
281da177e4SLinus Torvalds /* exercise of rights under this Agreement, including but not limited to     */
291da177e4SLinus Torvalds /* the risks and costs of program errors, damage to or loss of data,         */
301da177e4SLinus Torvalds /* programs or equipment, and unavailability or interruption of operations.  */
311da177e4SLinus Torvalds /*                                                                           */
321da177e4SLinus Torvalds /* DISCLAIMER OF LIABILITY                                                   */
331da177e4SLinus Torvalds /* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   */
341da177e4SLinus Torvalds /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
351da177e4SLinus Torvalds /* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   */
361da177e4SLinus Torvalds /* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     */
371da177e4SLinus Torvalds /* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    */
381da177e4SLinus Torvalds /* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  */
391da177e4SLinus Torvalds /* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             */
401da177e4SLinus Torvalds /*                                                                           */
411da177e4SLinus Torvalds /* You should have received a copy of the GNU General Public License         */
421da177e4SLinus Torvalds /* along with this program; if not, write to the Free Software               */
431da177e4SLinus Torvalds /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
441da177e4SLinus Torvalds /*                                                                           */
451da177e4SLinus Torvalds /* Bugs/Comments/Suggestions about this driver should be mailed to:          */
461da177e4SLinus Torvalds /*      ipslinux@adaptec.com        	                                     */
471da177e4SLinus Torvalds /*                                                                           */
481da177e4SLinus Torvalds /* For system support issues, contact your local IBM Customer support.       */
491da177e4SLinus Torvalds /* Directions to find IBM Customer Support for each country can be found at: */
501da177e4SLinus Torvalds /*      http://www.ibm.com/planetwide/                                       */
511da177e4SLinus Torvalds /*                                                                           */
521da177e4SLinus Torvalds /*****************************************************************************/
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds /*****************************************************************************/
551da177e4SLinus Torvalds /* Change Log                                                                */
561da177e4SLinus Torvalds /*                                                                           */
571da177e4SLinus Torvalds /* 0.99.02  - Breakup commands that are bigger than 8 * the stripe size      */
581da177e4SLinus Torvalds /* 0.99.03  - Make interrupt routine handle all completed request on the     */
591da177e4SLinus Torvalds /*            adapter not just the first one                                 */
601da177e4SLinus Torvalds /*          - Make sure passthru commands get woken up if we run out of      */
611da177e4SLinus Torvalds /*            SCBs                                                           */
621da177e4SLinus Torvalds /*          - Send all of the commands on the queue at once rather than      */
631da177e4SLinus Torvalds /*            one at a time since the card will support it.                  */
641da177e4SLinus Torvalds /* 0.99.04  - Fix race condition in the passthru mechanism -- this required  */
651da177e4SLinus Torvalds /*            the interface to the utilities to change                       */
661da177e4SLinus Torvalds /*          - Fix error recovery code                                        */
671da177e4SLinus Torvalds /* 0.99.05  - Fix an oops when we get certain passthru commands              */
681da177e4SLinus Torvalds /* 1.00.00  - Initial Public Release                                         */
691da177e4SLinus Torvalds /*            Functionally equivalent to 0.99.05                             */
701da177e4SLinus Torvalds /* 3.60.00  - Bump max commands to 128 for use with firmware 3.60            */
711da177e4SLinus Torvalds /*          - Change version to 3.60 to coincide with release numbering.     */
721da177e4SLinus Torvalds /* 3.60.01  - Remove bogus error check in passthru routine                   */
731da177e4SLinus Torvalds /* 3.60.02  - Make DCDB direction based on lookup table                      */
741da177e4SLinus Torvalds /*          - Only allow one DCDB command to a SCSI ID at a time             */
751da177e4SLinus Torvalds /* 4.00.00  - Add support for ServeRAID 4                                    */
761da177e4SLinus Torvalds /* 4.00.01  - Add support for First Failure Data Capture                     */
771da177e4SLinus Torvalds /* 4.00.02  - Fix problem with PT DCDB with no buffer                        */
781da177e4SLinus Torvalds /* 4.00.03  - Add alternative passthru interface                             */
791da177e4SLinus Torvalds /*          - Add ability to flash BIOS                                      */
801da177e4SLinus Torvalds /* 4.00.04  - Rename structures/constants to be prefixed with IPS_           */
811da177e4SLinus Torvalds /* 4.00.05  - Remove wish_block from init routine                            */
821da177e4SLinus Torvalds /*          - Use linux/spinlock.h instead of asm/spinlock.h for kernels     */
831da177e4SLinus Torvalds /*            2.3.18 and later                                               */
841da177e4SLinus Torvalds /*          - Sync with other changes from the 2.3 kernels                   */
851da177e4SLinus Torvalds /* 4.00.06  - Fix timeout with initial FFDC command                          */
861da177e4SLinus Torvalds /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */
871da177e4SLinus Torvalds /* 4.10.00  - Add support for ServeRAID 4M/4L                                */
881da177e4SLinus Torvalds /* 4.10.13  - Fix for dynamic unload and proc file system                    */
891da177e4SLinus Torvalds /* 4.20.03  - Rename version to coincide with new release schedules          */
901da177e4SLinus Torvalds /*            Performance fixes                                              */
911da177e4SLinus Torvalds /*            Fix truncation of /proc files with cat                         */
921da177e4SLinus Torvalds /*            Merge in changes through kernel 2.4.0test1ac21                 */
931da177e4SLinus Torvalds /* 4.20.13  - Fix some failure cases / reset code                            */
941da177e4SLinus Torvalds /*          - Hook into the reboot_notifier to flush the controller cache    */
951da177e4SLinus Torvalds /* 4.50.01  - Fix problem when there is a hole in logical drive numbering    */
961da177e4SLinus Torvalds /* 4.70.09  - Use a Common ( Large Buffer ) for Flashing from the JCRM CD    */
971da177e4SLinus Torvalds /*          - Add IPSSEND Flash Support                                      */
981da177e4SLinus Torvalds /*          - Set Sense Data for Unknown SCSI Command                        */
991da177e4SLinus Torvalds /*          - Use Slot Number from NVRAM Page 5                              */
1001da177e4SLinus Torvalds /*          - Restore caller's DCDB Structure                                */
1011da177e4SLinus Torvalds /* 4.70.12  - Corrective actions for bad controller ( during initialization )*/
1021da177e4SLinus Torvalds /* 4.70.13  - Don't Send CDB's if we already know the device is not present  */
1031da177e4SLinus Torvalds /*          - Don't release HA Lock in ips_next() until SC taken off queue   */
1041da177e4SLinus Torvalds /*          - Unregister SCSI device in ips_release()                        */
1051da177e4SLinus Torvalds /* 4.70.15  - Fix Breakup for very large ( non-SG ) requests in ips_done()   */
1061da177e4SLinus Torvalds /* 4.71.00  - Change all memory allocations to not use GFP_DMA flag          */
1071da177e4SLinus Torvalds /*            Code Clean-Up for 2.4.x kernel                                 */
1081da177e4SLinus Torvalds /* 4.72.00  - Allow for a Scatter-Gather Element to exceed MAX_XFER Size     */
1091da177e4SLinus Torvalds /* 4.72.01  - I/O Mapped Memory release ( so "insmod ips" does not Fail )    */
1101da177e4SLinus Torvalds /*          - Don't Issue Internal FFDC Command if there are Active Commands */
1111da177e4SLinus Torvalds /*          - Close Window for getting too many IOCTL's active               */
1121da177e4SLinus Torvalds /* 4.80.00  - Make ia64 Safe                                                 */
1131da177e4SLinus Torvalds /* 4.80.04  - Eliminate calls to strtok() if 2.4.x or greater                */
1141da177e4SLinus Torvalds /*          - Adjustments to Device Queue Depth                              */
1151da177e4SLinus Torvalds /* 4.80.14  - Take all semaphores off stack                                  */
1161da177e4SLinus Torvalds /*          - Clean Up New_IOCTL path                                        */
1171da177e4SLinus Torvalds /* 4.80.20  - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel )  */
1181da177e4SLinus Torvalds /*          - 5 second delay needed after resetting an i960 adapter          */
1191da177e4SLinus Torvalds /* 4.80.26  - Clean up potential code problems ( Arjan's recommendations )   */
1201da177e4SLinus Torvalds /* 4.90.01  - Version Matching for FirmWare, BIOS, and Driver                */
1211da177e4SLinus Torvalds /* 4.90.05  - Use New PCI Architecture to facilitate Hot Plug Development    */
1221da177e4SLinus Torvalds /* 4.90.08  - Increase Delays in Flashing ( Trombone Only - 4H )             */
1231da177e4SLinus Torvalds /* 4.90.08  - Data Corruption if First Scatter Gather Element is > 64K       */
1241da177e4SLinus Torvalds /* 4.90.11  - Don't actually RESET unless it's physically required           */
1251da177e4SLinus Torvalds /*          - Remove unused compile options                                  */
1261da177e4SLinus Torvalds /* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */
1271da177e4SLinus Torvalds /*          - Get rid on IOCTL_NEW_COMMAND code                              */
1281da177e4SLinus Torvalds /*          - Add Extended DCDB Commands for Tape Support in 5I              */
1291da177e4SLinus Torvalds /* 5.10.12  - use pci_dma interfaces, update for 2.5 kernel changes          */
1301da177e4SLinus Torvalds /* 5.10.15  - remove unused code (sem, macros, etc.)                         */
1311da177e4SLinus Torvalds /* 5.30.00  - use __devexit_p()                                              */
1321da177e4SLinus Torvalds /* 6.00.00  - Add 6x Adapters and Battery Flash                              */
1331da177e4SLinus Torvalds /* 6.10.00  - Remove 1G Addressing Limitations                               */
1341da177e4SLinus Torvalds /* 6.11.xx  - Get VersionInfo buffer off the stack !              DDTS 60401 */
1351da177e4SLinus Torvalds /* 6.11.xx  - Make Logical Drive Info structure safe for DMA      DDTS 60639 */
136*c1a15468SJack Hammer /* 7.10.18  - Add highmem_io flag in SCSI Templete for 2.4 kernels           */
1371da177e4SLinus Torvalds /*          - Fix path/name for scsi_hosts.h include for 2.6 kernels         */
1381da177e4SLinus Torvalds /*          - Fix sort order of 7k                                           */
1391da177e4SLinus Torvalds /*          - Remove 3 unused "inline" functions                             */
140*c1a15468SJack Hammer /* 7.12.xx  - Use STATIC functions whereever possible                        */
141*c1a15468SJack Hammer /*          - Clean up deprecated MODULE_PARM calls                          */
1421da177e4SLinus Torvalds /*****************************************************************************/
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /*
1451da177e4SLinus Torvalds  * Conditional Compilation directives for this driver:
1461da177e4SLinus Torvalds  *
1471da177e4SLinus Torvalds  * IPS_DEBUG            - Turn on debugging info
1481da177e4SLinus Torvalds  *
1491da177e4SLinus Torvalds  * Parameters:
1501da177e4SLinus Torvalds  *
1511da177e4SLinus Torvalds  * debug:<number>       - Set debug level to <number>
1521da177e4SLinus Torvalds  *                        NOTE: only works when IPS_DEBUG compile directive is used.
1531da177e4SLinus Torvalds  *       1              - Normal debug messages
1541da177e4SLinus Torvalds  *       2              - Verbose debug messages
1551da177e4SLinus Torvalds  *       11             - Method trace (non interrupt)
1561da177e4SLinus Torvalds  *       12             - Method trace (includes interrupt)
1571da177e4SLinus Torvalds  *
1581da177e4SLinus Torvalds  * noi2o                - Don't use I2O Queues (ServeRAID 4 only)
1591da177e4SLinus Torvalds  * nommap               - Don't use memory mapped I/O
1601da177e4SLinus Torvalds  * ioctlsize            - Initial size of the IOCTL buffer
1611da177e4SLinus Torvalds  */
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds #include <asm/io.h>
1641da177e4SLinus Torvalds #include <asm/byteorder.h>
1651da177e4SLinus Torvalds #include <asm/page.h>
1661da177e4SLinus Torvalds #include <linux/stddef.h>
1671da177e4SLinus Torvalds #include <linux/version.h>
1681da177e4SLinus Torvalds #include <linux/string.h>
1691da177e4SLinus Torvalds #include <linux/errno.h>
1701da177e4SLinus Torvalds #include <linux/kernel.h>
1711da177e4SLinus Torvalds #include <linux/ioport.h>
1721da177e4SLinus Torvalds #include <linux/slab.h>
1731da177e4SLinus Torvalds #include <linux/delay.h>
1741da177e4SLinus Torvalds #include <linux/pci.h>
1751da177e4SLinus Torvalds #include <linux/proc_fs.h>
1761da177e4SLinus Torvalds #include <linux/reboot.h>
1771da177e4SLinus Torvalds #include <linux/interrupt.h>
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds #include <linux/blkdev.h>
1801da177e4SLinus Torvalds #include <linux/types.h>
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds #include <scsi/sg.h>
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds #include "scsi.h"
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
1871da177e4SLinus Torvalds #include "hosts.h"
1881da177e4SLinus Torvalds #else
1891da177e4SLinus Torvalds #include <scsi/scsi_host.h>
1901da177e4SLinus Torvalds #endif
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds #include "ips.h"
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds #include <linux/module.h>
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds #include <linux/stat.h>
1971da177e4SLinus Torvalds #include <linux/config.h>
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds #include <linux/spinlock.h>
2001da177e4SLinus Torvalds #include <linux/init.h>
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds #include <linux/smp.h>
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds #ifdef MODULE
2051da177e4SLinus Torvalds static char *ips = NULL;
2061da177e4SLinus Torvalds module_param(ips, charp, 0);
2071da177e4SLinus Torvalds #endif
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /*
2101da177e4SLinus Torvalds  * DRIVER_VER
2111da177e4SLinus Torvalds  */
212*c1a15468SJack Hammer #define IPS_VERSION_HIGH        "7.12"
213*c1a15468SJack Hammer #define IPS_VERSION_LOW         ".02 "
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
2161da177e4SLinus Torvalds #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
2171da177e4SLinus Torvalds #endif
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
2201da177e4SLinus Torvalds #include <linux/blk.h>
2211da177e4SLinus Torvalds #include "sd.h"
2221da177e4SLinus Torvalds #define IPS_SG_ADDRESS(sg)       ((sg)->address)
2231da177e4SLinus Torvalds #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
2241da177e4SLinus Torvalds #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
2251da177e4SLinus Torvalds #ifndef __devexit_p
2261da177e4SLinus Torvalds #define __devexit_p(x) x
2271da177e4SLinus Torvalds #endif
2281da177e4SLinus Torvalds #else
2291da177e4SLinus Torvalds #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
2301da177e4SLinus Torvalds                                    page_address((sg)->page)+(sg)->offset : NULL)
2311da177e4SLinus Torvalds #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
2321da177e4SLinus Torvalds #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
2331da177e4SLinus Torvalds #endif
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
236be7db055S                          DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
2371da177e4SLinus Torvalds                          PCI_DMA_BIDIRECTIONAL : \
238be7db055S                          scb->scsi_cmd->sc_data_direction)
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds #ifdef IPS_DEBUG
2411da177e4SLinus Torvalds #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
2421da177e4SLinus Torvalds #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
2431da177e4SLinus Torvalds #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
2441da177e4SLinus Torvalds #else
2451da177e4SLinus Torvalds #define METHOD_TRACE(s, i)
2461da177e4SLinus Torvalds #define DEBUG(i, s)
2471da177e4SLinus Torvalds #define DEBUG_VAR(i, s, v...)
2481da177e4SLinus Torvalds #endif
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds /*
2511da177e4SLinus Torvalds  * Function prototypes
2521da177e4SLinus Torvalds  */
2531da177e4SLinus Torvalds static int ips_detect(Scsi_Host_Template *);
2541da177e4SLinus Torvalds static int ips_release(struct Scsi_Host *);
2551da177e4SLinus Torvalds static int ips_eh_abort(Scsi_Cmnd *);
2561da177e4SLinus Torvalds static int ips_eh_reset(Scsi_Cmnd *);
2571da177e4SLinus Torvalds static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
2581da177e4SLinus Torvalds static const char *ips_info(struct Scsi_Host *);
2591da177e4SLinus Torvalds static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
2601da177e4SLinus Torvalds static int ips_hainit(ips_ha_t *);
2611da177e4SLinus Torvalds static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
2621da177e4SLinus Torvalds static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
2631da177e4SLinus Torvalds static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
2641da177e4SLinus Torvalds static int ips_online(ips_ha_t *, ips_scb_t *);
2651da177e4SLinus Torvalds static int ips_inquiry(ips_ha_t *, ips_scb_t *);
2661da177e4SLinus Torvalds static int ips_rdcap(ips_ha_t *, ips_scb_t *);
2671da177e4SLinus Torvalds static int ips_msense(ips_ha_t *, ips_scb_t *);
2681da177e4SLinus Torvalds static int ips_reqsen(ips_ha_t *, ips_scb_t *);
2691da177e4SLinus Torvalds static int ips_deallocatescbs(ips_ha_t *, int);
2701da177e4SLinus Torvalds static int ips_allocatescbs(ips_ha_t *);
2711da177e4SLinus Torvalds static int ips_reset_copperhead(ips_ha_t *);
2721da177e4SLinus Torvalds static int ips_reset_copperhead_memio(ips_ha_t *);
2731da177e4SLinus Torvalds static int ips_reset_morpheus(ips_ha_t *);
2741da177e4SLinus Torvalds static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
2751da177e4SLinus Torvalds static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
2761da177e4SLinus Torvalds static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
2771da177e4SLinus Torvalds static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
2781da177e4SLinus Torvalds static int ips_isintr_copperhead(ips_ha_t *);
2791da177e4SLinus Torvalds static int ips_isintr_copperhead_memio(ips_ha_t *);
2801da177e4SLinus Torvalds static int ips_isintr_morpheus(ips_ha_t *);
2811da177e4SLinus Torvalds static int ips_wait(ips_ha_t *, int, int);
2821da177e4SLinus Torvalds static int ips_write_driver_status(ips_ha_t *, int);
2831da177e4SLinus Torvalds static int ips_read_adapter_status(ips_ha_t *, int);
2841da177e4SLinus Torvalds static int ips_read_subsystem_parameters(ips_ha_t *, int);
2851da177e4SLinus Torvalds static int ips_read_config(ips_ha_t *, int);
2861da177e4SLinus Torvalds static int ips_clear_adapter(ips_ha_t *, int);
2871da177e4SLinus Torvalds static int ips_readwrite_page5(ips_ha_t *, int, int);
2881da177e4SLinus Torvalds static int ips_init_copperhead(ips_ha_t *);
2891da177e4SLinus Torvalds static int ips_init_copperhead_memio(ips_ha_t *);
2901da177e4SLinus Torvalds static int ips_init_morpheus(ips_ha_t *);
2911da177e4SLinus Torvalds static int ips_isinit_copperhead(ips_ha_t *);
2921da177e4SLinus Torvalds static int ips_isinit_copperhead_memio(ips_ha_t *);
2931da177e4SLinus Torvalds static int ips_isinit_morpheus(ips_ha_t *);
2941da177e4SLinus Torvalds static int ips_erase_bios(ips_ha_t *);
2951da177e4SLinus Torvalds static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
2961da177e4SLinus Torvalds static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
2971da177e4SLinus Torvalds static int ips_erase_bios_memio(ips_ha_t *);
2981da177e4SLinus Torvalds static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
2991da177e4SLinus Torvalds static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
3001da177e4SLinus Torvalds static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
3011da177e4SLinus Torvalds static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
3021da177e4SLinus Torvalds static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
3031da177e4SLinus Torvalds static void ips_free_flash_copperhead(ips_ha_t * ha);
3041da177e4SLinus Torvalds static void ips_get_bios_version(ips_ha_t *, int);
3051da177e4SLinus Torvalds static void ips_identify_controller(ips_ha_t *);
3061da177e4SLinus Torvalds static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
3071da177e4SLinus Torvalds static void ips_enable_int_copperhead(ips_ha_t *);
3081da177e4SLinus Torvalds static void ips_enable_int_copperhead_memio(ips_ha_t *);
3091da177e4SLinus Torvalds static void ips_enable_int_morpheus(ips_ha_t *);
3101da177e4SLinus Torvalds static int ips_intr_copperhead(ips_ha_t *);
3111da177e4SLinus Torvalds static int ips_intr_morpheus(ips_ha_t *);
3121da177e4SLinus Torvalds static void ips_next(ips_ha_t *, int);
3131da177e4SLinus Torvalds static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
3141da177e4SLinus Torvalds static void ipsintr_done(ips_ha_t *, struct ips_scb *);
3151da177e4SLinus Torvalds static void ips_done(ips_ha_t *, ips_scb_t *);
3161da177e4SLinus Torvalds static void ips_free(ips_ha_t *);
3171da177e4SLinus Torvalds static void ips_init_scb(ips_ha_t *, ips_scb_t *);
3181da177e4SLinus Torvalds static void ips_freescb(ips_ha_t *, ips_scb_t *);
3191da177e4SLinus Torvalds static void ips_setup_funclist(ips_ha_t *);
3201da177e4SLinus Torvalds static void ips_statinit(ips_ha_t *);
3211da177e4SLinus Torvalds static void ips_statinit_memio(ips_ha_t *);
3221da177e4SLinus Torvalds static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
3231da177e4SLinus Torvalds static void ips_ffdc_reset(ips_ha_t *, int);
3241da177e4SLinus Torvalds static void ips_ffdc_time(ips_ha_t *);
3251da177e4SLinus Torvalds static uint32_t ips_statupd_copperhead(ips_ha_t *);
3261da177e4SLinus Torvalds static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
3271da177e4SLinus Torvalds static uint32_t ips_statupd_morpheus(ips_ha_t *);
3281da177e4SLinus Torvalds static ips_scb_t *ips_getscb(ips_ha_t *);
3291da177e4SLinus Torvalds static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
3301da177e4SLinus Torvalds static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
3311da177e4SLinus Torvalds static void ips_putq_copp_tail(ips_copp_queue_t *,
3321da177e4SLinus Torvalds 				      ips_copp_wait_item_t *);
3331da177e4SLinus Torvalds static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
3341da177e4SLinus Torvalds static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
3351da177e4SLinus Torvalds static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
3361da177e4SLinus Torvalds static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
3371da177e4SLinus Torvalds static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
3381da177e4SLinus Torvalds 						     ips_copp_wait_item_t *);
3391da177e4SLinus Torvalds static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds static int ips_is_passthru(Scsi_Cmnd *);
3421da177e4SLinus Torvalds static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
3431da177e4SLinus Torvalds static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
3441da177e4SLinus Torvalds static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
3451da177e4SLinus Torvalds static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
3461da177e4SLinus Torvalds 			       unsigned int count);
3471da177e4SLinus Torvalds static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
3501da177e4SLinus Torvalds static int ips_host_info(ips_ha_t *, char *, off_t, int);
3511da177e4SLinus Torvalds static void copy_mem_info(IPS_INFOSTR *, char *, int);
3521da177e4SLinus Torvalds static int copy_info(IPS_INFOSTR *, char *, ...);
3531da177e4SLinus Torvalds static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
3541da177e4SLinus Torvalds static void ips_version_check(ips_ha_t * ha, int intr);
3551da177e4SLinus Torvalds static int ips_abort_init(ips_ha_t * ha, int index);
3561da177e4SLinus Torvalds static int ips_init_phase2(int index);
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
3591da177e4SLinus Torvalds static int ips_register_scsi(int index);
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds /*
3621da177e4SLinus Torvalds  * global variables
3631da177e4SLinus Torvalds  */
3641da177e4SLinus Torvalds static const char ips_name[] = "ips";
3651da177e4SLinus Torvalds static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];	/* Array of host controller structures */
3661da177e4SLinus Torvalds static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS];	/* Array of HA structures */
3671da177e4SLinus Torvalds static unsigned int ips_next_controller;
3681da177e4SLinus Torvalds static unsigned int ips_num_controllers;
3691da177e4SLinus Torvalds static unsigned int ips_released_controllers;
3701da177e4SLinus Torvalds static int ips_hotplug;
3711da177e4SLinus Torvalds static int ips_cmd_timeout = 60;
3721da177e4SLinus Torvalds static int ips_reset_timeout = 60 * 5;
3731da177e4SLinus Torvalds static int ips_force_memio = 1;		/* Always use Memory Mapped I/O    */
3741da177e4SLinus Torvalds static int ips_force_i2o = 1;	/* Always use I2O command delivery */
3751da177e4SLinus Torvalds static int ips_ioctlsize = IPS_IOCTL_SIZE;	/* Size of the ioctl buffer        */
3761da177e4SLinus Torvalds static int ips_cd_boot;			/* Booting from Manager CD         */
3771da177e4SLinus Torvalds static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */
3781da177e4SLinus Torvalds static dma_addr_t ips_flashbusaddr;
3791da177e4SLinus Torvalds static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */
3801da177e4SLinus Torvalds static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
3811da177e4SLinus Torvalds static Scsi_Host_Template ips_driver_template = {
3821da177e4SLinus Torvalds 	.detect			= ips_detect,
3831da177e4SLinus Torvalds 	.release		= ips_release,
3841da177e4SLinus Torvalds 	.info			= ips_info,
3851da177e4SLinus Torvalds 	.queuecommand		= ips_queue,
3861da177e4SLinus Torvalds 	.eh_abort_handler	= ips_eh_abort,
3871da177e4SLinus Torvalds 	.eh_host_reset_handler	= ips_eh_reset,
3881da177e4SLinus Torvalds 	.proc_name		= "ips",
3891da177e4SLinus Torvalds #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
3901da177e4SLinus Torvalds 	.proc_info		= ips_proc_info,
3911da177e4SLinus Torvalds 	.slave_configure	= ips_slave_configure,
3921da177e4SLinus Torvalds #else
3931da177e4SLinus Torvalds 	.proc_info		= ips_proc24_info,
3941da177e4SLinus Torvalds 	.select_queue_depths	= ips_select_queue_depth,
3951da177e4SLinus Torvalds #endif
3961da177e4SLinus Torvalds 	.bios_param		= ips_biosparam,
3971da177e4SLinus Torvalds 	.this_id		= -1,
3981da177e4SLinus Torvalds 	.sg_tablesize		= IPS_MAX_SG,
3991da177e4SLinus Torvalds 	.cmd_per_lun		= 3,
4001da177e4SLinus Torvalds 	.use_clustering		= ENABLE_CLUSTERING,
4011da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4021da177e4SLinus Torvalds 	.use_new_eh_code	= 1,
4031da177e4SLinus Torvalds #endif
4041da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)  &&  LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4051da177e4SLinus Torvalds     .highmem_io          = 1,
4061da177e4SLinus Torvalds #endif
4071da177e4SLinus Torvalds };
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds static IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds /* This table describes all ServeRAID Adapters */
4131da177e4SLinus Torvalds static struct  pci_device_id  ips_pci_table[] = {
4141da177e4SLinus Torvalds 	{ 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
4151da177e4SLinus Torvalds 	{ 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
4161da177e4SLinus Torvalds 	{ 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
4171da177e4SLinus Torvalds 	{ 0, }
4181da177e4SLinus Torvalds };
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds MODULE_DEVICE_TABLE( pci, ips_pci_table );
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds static char ips_hot_plug_name[] = "ips";
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
4251da177e4SLinus Torvalds static void __devexit ips_remove_device(struct pci_dev *pci_dev);
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds static struct pci_driver ips_pci_driver = {
4281da177e4SLinus Torvalds 	.name		= ips_hot_plug_name,
4291da177e4SLinus Torvalds 	.id_table	= ips_pci_table,
4301da177e4SLinus Torvalds 	.probe		= ips_insert_device,
4311da177e4SLinus Torvalds 	.remove		= __devexit_p(ips_remove_device),
4321da177e4SLinus Torvalds };
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds /*
4361da177e4SLinus Torvalds  * Necessary forward function protoypes
4371da177e4SLinus Torvalds  */
4381da177e4SLinus Torvalds static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds #define MAX_ADAPTER_NAME 15
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds static char ips_adapter_name[][30] = {
4431da177e4SLinus Torvalds 	"ServeRAID",
4441da177e4SLinus Torvalds 	"ServeRAID II",
4451da177e4SLinus Torvalds 	"ServeRAID on motherboard",
4461da177e4SLinus Torvalds 	"ServeRAID on motherboard",
4471da177e4SLinus Torvalds 	"ServeRAID 3H",
4481da177e4SLinus Torvalds 	"ServeRAID 3L",
4491da177e4SLinus Torvalds 	"ServeRAID 4H",
4501da177e4SLinus Torvalds 	"ServeRAID 4M",
4511da177e4SLinus Torvalds 	"ServeRAID 4L",
4521da177e4SLinus Torvalds 	"ServeRAID 4Mx",
4531da177e4SLinus Torvalds 	"ServeRAID 4Lx",
4541da177e4SLinus Torvalds 	"ServeRAID 5i",
4551da177e4SLinus Torvalds 	"ServeRAID 5i",
4561da177e4SLinus Torvalds 	"ServeRAID 6M",
4571da177e4SLinus Torvalds 	"ServeRAID 6i",
4581da177e4SLinus Torvalds 	"ServeRAID 7t",
4591da177e4SLinus Torvalds 	"ServeRAID 7k",
4601da177e4SLinus Torvalds 	"ServeRAID 7M"
4611da177e4SLinus Torvalds };
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds static struct notifier_block ips_notifier = {
4641da177e4SLinus Torvalds 	ips_halt, NULL, 0
4651da177e4SLinus Torvalds };
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds /*
4681da177e4SLinus Torvalds  * Direction table
4691da177e4SLinus Torvalds  */
4701da177e4SLinus Torvalds static char ips_command_direction[] = {
4711da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
4721da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,
4731da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4741da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
4751da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
4761da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
4771da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,
4781da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
4791da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,
4801da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
4811da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,
4821da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
4831da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,
4841da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,
4851da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
4861da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
4871da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4881da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4891da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4901da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4911da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4921da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4931da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4941da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4951da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4961da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4971da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4981da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
4991da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5001da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5011da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5021da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5031da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5041da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,
5051da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,
5061da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,
5071da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,
5081da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5091da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5101da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5111da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5121da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5131da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5141da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5151da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5161da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5171da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,
5181da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5191da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5201da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
5211da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
5221da177e4SLinus Torvalds };
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds /****************************************************************************/
5261da177e4SLinus Torvalds /*                                                                          */
5271da177e4SLinus Torvalds /* Routine Name: ips_setup                                                  */
5281da177e4SLinus Torvalds /*                                                                          */
5291da177e4SLinus Torvalds /* Routine Description:                                                     */
5301da177e4SLinus Torvalds /*                                                                          */
5311da177e4SLinus Torvalds /*   setup parameters to the driver                                         */
5321da177e4SLinus Torvalds /*                                                                          */
5331da177e4SLinus Torvalds /****************************************************************************/
5341da177e4SLinus Torvalds static int
5351da177e4SLinus Torvalds ips_setup(char *ips_str)
5361da177e4SLinus Torvalds {
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	int i;
5391da177e4SLinus Torvalds 	char *key;
5401da177e4SLinus Torvalds 	char *value;
5411da177e4SLinus Torvalds 	IPS_OPTION options[] = {
5421da177e4SLinus Torvalds 		{"noi2o", &ips_force_i2o, 0},
5431da177e4SLinus Torvalds 		{"nommap", &ips_force_memio, 0},
5441da177e4SLinus Torvalds 		{"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
5451da177e4SLinus Torvalds 		{"cdboot", &ips_cd_boot, 0},
5461da177e4SLinus Torvalds 		{"maxcmds", &MaxLiteCmds, 32},
5471da177e4SLinus Torvalds 	};
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	/* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
5501da177e4SLinus Torvalds 	/* Search for value */
5511da177e4SLinus Torvalds 	while ((key = strsep(&ips_str, ",."))) {
5521da177e4SLinus Torvalds 		if (!*key)
5531da177e4SLinus Torvalds 			continue;
5541da177e4SLinus Torvalds 		value = strchr(key, ':');
5551da177e4SLinus Torvalds 		if (value)
5561da177e4SLinus Torvalds 			*value++ = '\0';
5571da177e4SLinus Torvalds 		/*
5581da177e4SLinus Torvalds 		 * We now have key/value pairs.
5591da177e4SLinus Torvalds 		 * Update the variables
5601da177e4SLinus Torvalds 		 */
5611da177e4SLinus Torvalds 		for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) {
5621da177e4SLinus Torvalds 			if (strnicmp
5631da177e4SLinus Torvalds 			    (key, options[i].option_name,
5641da177e4SLinus Torvalds 			     strlen(options[i].option_name)) == 0) {
5651da177e4SLinus Torvalds 				if (value)
5661da177e4SLinus Torvalds 					*options[i].option_flag =
5671da177e4SLinus Torvalds 					    simple_strtoul(value, NULL, 0);
5681da177e4SLinus Torvalds 				else
5691da177e4SLinus Torvalds 					*options[i].option_flag =
5701da177e4SLinus Torvalds 					    options[i].option_value;
5711da177e4SLinus Torvalds 				break;
5721da177e4SLinus Torvalds 			}
5731da177e4SLinus Torvalds 		}
5741da177e4SLinus Torvalds 	}
5751da177e4SLinus Torvalds 
5761da177e4SLinus Torvalds 	return (1);
5771da177e4SLinus Torvalds }
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds __setup("ips=", ips_setup);
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds /****************************************************************************/
5821da177e4SLinus Torvalds /*                                                                          */
5831da177e4SLinus Torvalds /* Routine Name: ips_detect                                                 */
5841da177e4SLinus Torvalds /*                                                                          */
5851da177e4SLinus Torvalds /* Routine Description:                                                     */
5861da177e4SLinus Torvalds /*                                                                          */
5871da177e4SLinus Torvalds /*   Detect and initialize the driver                                       */
5881da177e4SLinus Torvalds /*                                                                          */
5891da177e4SLinus Torvalds /* NOTE: this routine is called under the io_request_lock spinlock          */
5901da177e4SLinus Torvalds /*                                                                          */
5911da177e4SLinus Torvalds /****************************************************************************/
5921da177e4SLinus Torvalds static int
5931da177e4SLinus Torvalds ips_detect(Scsi_Host_Template * SHT)
5941da177e4SLinus Torvalds {
5951da177e4SLinus Torvalds 	int i;
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 	METHOD_TRACE("ips_detect", 1);
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds #ifdef MODULE
6001da177e4SLinus Torvalds 	if (ips)
6011da177e4SLinus Torvalds 		ips_setup(ips);
6021da177e4SLinus Torvalds #endif
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	for (i = 0; i < ips_num_controllers; i++) {
6051da177e4SLinus Torvalds 		if (ips_register_scsi(i))
6061da177e4SLinus Torvalds 			ips_free(ips_ha[i]);
6071da177e4SLinus Torvalds 		ips_released_controllers++;
6081da177e4SLinus Torvalds 	}
6091da177e4SLinus Torvalds 	ips_hotplug = 1;
6101da177e4SLinus Torvalds 	return (ips_num_controllers);
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds /****************************************************************************/
6141da177e4SLinus Torvalds /*   configure the function pointers to use the functions that will work    */
6151da177e4SLinus Torvalds /*   with the found version of the adapter                                  */
6161da177e4SLinus Torvalds /****************************************************************************/
6171da177e4SLinus Torvalds static void
6181da177e4SLinus Torvalds ips_setup_funclist(ips_ha_t * ha)
6191da177e4SLinus Torvalds {
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds 	/*
6221da177e4SLinus Torvalds 	 * Setup Functions
6231da177e4SLinus Torvalds 	 */
6241da177e4SLinus Torvalds 	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
6251da177e4SLinus Torvalds 		/* morpheus / marco / sebring */
6261da177e4SLinus Torvalds 		ha->func.isintr = ips_isintr_morpheus;
6271da177e4SLinus Torvalds 		ha->func.isinit = ips_isinit_morpheus;
6281da177e4SLinus Torvalds 		ha->func.issue = ips_issue_i2o_memio;
6291da177e4SLinus Torvalds 		ha->func.init = ips_init_morpheus;
6301da177e4SLinus Torvalds 		ha->func.statupd = ips_statupd_morpheus;
6311da177e4SLinus Torvalds 		ha->func.reset = ips_reset_morpheus;
6321da177e4SLinus Torvalds 		ha->func.intr = ips_intr_morpheus;
6331da177e4SLinus Torvalds 		ha->func.enableint = ips_enable_int_morpheus;
6341da177e4SLinus Torvalds 	} else if (IPS_USE_MEMIO(ha)) {
6351da177e4SLinus Torvalds 		/* copperhead w/MEMIO */
6361da177e4SLinus Torvalds 		ha->func.isintr = ips_isintr_copperhead_memio;
6371da177e4SLinus Torvalds 		ha->func.isinit = ips_isinit_copperhead_memio;
6381da177e4SLinus Torvalds 		ha->func.init = ips_init_copperhead_memio;
6391da177e4SLinus Torvalds 		ha->func.statupd = ips_statupd_copperhead_memio;
6401da177e4SLinus Torvalds 		ha->func.statinit = ips_statinit_memio;
6411da177e4SLinus Torvalds 		ha->func.reset = ips_reset_copperhead_memio;
6421da177e4SLinus Torvalds 		ha->func.intr = ips_intr_copperhead;
6431da177e4SLinus Torvalds 		ha->func.erasebios = ips_erase_bios_memio;
6441da177e4SLinus Torvalds 		ha->func.programbios = ips_program_bios_memio;
6451da177e4SLinus Torvalds 		ha->func.verifybios = ips_verify_bios_memio;
6461da177e4SLinus Torvalds 		ha->func.enableint = ips_enable_int_copperhead_memio;
6471da177e4SLinus Torvalds 		if (IPS_USE_I2O_DELIVER(ha))
6481da177e4SLinus Torvalds 			ha->func.issue = ips_issue_i2o_memio;
6491da177e4SLinus Torvalds 		else
6501da177e4SLinus Torvalds 			ha->func.issue = ips_issue_copperhead_memio;
6511da177e4SLinus Torvalds 	} else {
6521da177e4SLinus Torvalds 		/* copperhead */
6531da177e4SLinus Torvalds 		ha->func.isintr = ips_isintr_copperhead;
6541da177e4SLinus Torvalds 		ha->func.isinit = ips_isinit_copperhead;
6551da177e4SLinus Torvalds 		ha->func.init = ips_init_copperhead;
6561da177e4SLinus Torvalds 		ha->func.statupd = ips_statupd_copperhead;
6571da177e4SLinus Torvalds 		ha->func.statinit = ips_statinit;
6581da177e4SLinus Torvalds 		ha->func.reset = ips_reset_copperhead;
6591da177e4SLinus Torvalds 		ha->func.intr = ips_intr_copperhead;
6601da177e4SLinus Torvalds 		ha->func.erasebios = ips_erase_bios;
6611da177e4SLinus Torvalds 		ha->func.programbios = ips_program_bios;
6621da177e4SLinus Torvalds 		ha->func.verifybios = ips_verify_bios;
6631da177e4SLinus Torvalds 		ha->func.enableint = ips_enable_int_copperhead;
6641da177e4SLinus Torvalds 
6651da177e4SLinus Torvalds 		if (IPS_USE_I2O_DELIVER(ha))
6661da177e4SLinus Torvalds 			ha->func.issue = ips_issue_i2o;
6671da177e4SLinus Torvalds 		else
6681da177e4SLinus Torvalds 			ha->func.issue = ips_issue_copperhead;
6691da177e4SLinus Torvalds 	}
6701da177e4SLinus Torvalds }
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds /****************************************************************************/
6731da177e4SLinus Torvalds /*                                                                          */
6741da177e4SLinus Torvalds /* Routine Name: ips_release                                                */
6751da177e4SLinus Torvalds /*                                                                          */
6761da177e4SLinus Torvalds /* Routine Description:                                                     */
6771da177e4SLinus Torvalds /*                                                                          */
6781da177e4SLinus Torvalds /*   Remove a driver                                                        */
6791da177e4SLinus Torvalds /*                                                                          */
6801da177e4SLinus Torvalds /****************************************************************************/
6811da177e4SLinus Torvalds static int
6821da177e4SLinus Torvalds ips_release(struct Scsi_Host *sh)
6831da177e4SLinus Torvalds {
6841da177e4SLinus Torvalds 	ips_scb_t *scb;
6851da177e4SLinus Torvalds 	ips_ha_t *ha;
6861da177e4SLinus Torvalds 	int i;
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	METHOD_TRACE("ips_release", 1);
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	if (i == IPS_MAX_ADAPTERS) {
6931da177e4SLinus Torvalds 		printk(KERN_WARNING
6941da177e4SLinus Torvalds 		       "(%s) release, invalid Scsi_Host pointer.\n", ips_name);
6951da177e4SLinus Torvalds 		BUG();
6961da177e4SLinus Torvalds 		return (FALSE);
6971da177e4SLinus Torvalds 	}
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds 	ha = IPS_HA(sh);
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	if (!ha)
7021da177e4SLinus Torvalds 		return (FALSE);
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds 	/* flush the cache on the controller */
7051da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
7101da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_FLUSH;
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 	scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
7131da177e4SLinus Torvalds 	scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
7141da177e4SLinus Torvalds 	scb->cmd.flush_cache.state = IPS_NORM_STATE;
7151da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved = 0;
7161da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved2 = 0;
7171da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved3 = 0;
7181da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved4 = 0;
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	/* send command */
7231da177e4SLinus Torvalds 	if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
7241da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	ips_sh[i] = NULL;
7291da177e4SLinus Torvalds 	ips_ha[i] = NULL;
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	/* free extra memory */
7321da177e4SLinus Torvalds 	ips_free(ha);
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	/* Free I/O Region */
7351da177e4SLinus Torvalds 	if (ha->io_addr)
7361da177e4SLinus Torvalds 		release_region(ha->io_addr, ha->io_len);
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 	/* free IRQ */
7391da177e4SLinus Torvalds 	free_irq(ha->irq, ha);
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 	IPS_REMOVE_HOST(sh);
7421da177e4SLinus Torvalds 	scsi_host_put(sh);
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 	ips_released_controllers++;
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	return (FALSE);
7471da177e4SLinus Torvalds }
7481da177e4SLinus Torvalds 
7491da177e4SLinus Torvalds /****************************************************************************/
7501da177e4SLinus Torvalds /*                                                                          */
7511da177e4SLinus Torvalds /* Routine Name: ips_halt                                                   */
7521da177e4SLinus Torvalds /*                                                                          */
7531da177e4SLinus Torvalds /* Routine Description:                                                     */
7541da177e4SLinus Torvalds /*                                                                          */
7551da177e4SLinus Torvalds /*   Perform cleanup when the system reboots                                */
7561da177e4SLinus Torvalds /*                                                                          */
7571da177e4SLinus Torvalds /****************************************************************************/
7581da177e4SLinus Torvalds static int
7591da177e4SLinus Torvalds ips_halt(struct notifier_block *nb, ulong event, void *buf)
7601da177e4SLinus Torvalds {
7611da177e4SLinus Torvalds 	ips_scb_t *scb;
7621da177e4SLinus Torvalds 	ips_ha_t *ha;
7631da177e4SLinus Torvalds 	int i;
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 	if ((event != SYS_RESTART) && (event != SYS_HALT) &&
7661da177e4SLinus Torvalds 	    (event != SYS_POWER_OFF))
7671da177e4SLinus Torvalds 		return (NOTIFY_DONE);
7681da177e4SLinus Torvalds 
7691da177e4SLinus Torvalds 	for (i = 0; i < ips_next_controller; i++) {
7701da177e4SLinus Torvalds 		ha = (ips_ha_t *) ips_ha[i];
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 		if (!ha)
7731da177e4SLinus Torvalds 			continue;
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 		if (!ha->active)
7761da177e4SLinus Torvalds 			continue;
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 		/* flush the cache on the controller */
7791da177e4SLinus Torvalds 		scb = &ha->scbs[ha->max_cmds - 1];
7801da177e4SLinus Torvalds 
7811da177e4SLinus Torvalds 		ips_init_scb(ha, scb);
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
7841da177e4SLinus Torvalds 		scb->cdb[0] = IPS_CMD_FLUSH;
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
7871da177e4SLinus Torvalds 		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
7881da177e4SLinus Torvalds 		scb->cmd.flush_cache.state = IPS_NORM_STATE;
7891da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved = 0;
7901da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved2 = 0;
7911da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved3 = 0;
7921da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved4 = 0;
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 		/* send command */
7971da177e4SLinus Torvalds 		if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==
7981da177e4SLinus Torvalds 		    IPS_FAILURE)
7991da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
8001da177e4SLinus Torvalds 				   "Incomplete Flush.\n");
8011da177e4SLinus Torvalds 		else
8021da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
8031da177e4SLinus Torvalds 				   "Flushing Complete.\n");
8041da177e4SLinus Torvalds 	}
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds 	return (NOTIFY_OK);
8071da177e4SLinus Torvalds }
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds /****************************************************************************/
8101da177e4SLinus Torvalds /*                                                                          */
8111da177e4SLinus Torvalds /* Routine Name: ips_eh_abort                                               */
8121da177e4SLinus Torvalds /*                                                                          */
8131da177e4SLinus Torvalds /* Routine Description:                                                     */
8141da177e4SLinus Torvalds /*                                                                          */
8151da177e4SLinus Torvalds /*   Abort a command (using the new error code stuff)                       */
8161da177e4SLinus Torvalds /* Note: this routine is called under the io_request_lock                   */
8171da177e4SLinus Torvalds /****************************************************************************/
8181da177e4SLinus Torvalds int
8191da177e4SLinus Torvalds ips_eh_abort(Scsi_Cmnd * SC)
8201da177e4SLinus Torvalds {
8211da177e4SLinus Torvalds 	ips_ha_t *ha;
8221da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
8231da177e4SLinus Torvalds 	int ret;
8248fa728a2SJeff Garzik  	unsigned long cpu_flags;
8258fa728a2SJeff Garzik  	struct Scsi_Host *host;
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 	METHOD_TRACE("ips_eh_abort", 1);
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds 	if (!SC)
8301da177e4SLinus Torvalds 		return (FAILED);
8311da177e4SLinus Torvalds 
8328fa728a2SJeff Garzik  	host = SC->device->host;
8331da177e4SLinus Torvalds 	ha = (ips_ha_t *) SC->device->host->hostdata;
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 	if (!ha)
8361da177e4SLinus Torvalds 		return (FAILED);
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 	if (!ha->active)
8391da177e4SLinus Torvalds 		return (FAILED);
8401da177e4SLinus Torvalds 
8418fa728a2SJeff Garzik  	IPS_LOCK_SAVE(host->host_lock, cpu_flags);
8428fa728a2SJeff Garzik  
8431da177e4SLinus Torvalds 	/* See if the command is on the copp queue */
8441da177e4SLinus Torvalds 	item = ha->copp_waitlist.head;
8451da177e4SLinus Torvalds 	while ((item) && (item->scsi_cmd != SC))
8461da177e4SLinus Torvalds 		item = item->next;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (item) {
8491da177e4SLinus Torvalds 		/* Found it */
8501da177e4SLinus Torvalds 		ips_removeq_copp(&ha->copp_waitlist, item);
8511da177e4SLinus Torvalds 		ret = (SUCCESS);
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds 		/* See if the command is on the wait queue */
8541da177e4SLinus Torvalds 	} else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
8551da177e4SLinus Torvalds 		/* command not sent yet */
8561da177e4SLinus Torvalds 		ret = (SUCCESS);
8571da177e4SLinus Torvalds 	} else {
8581da177e4SLinus Torvalds 		/* command must have already been sent */
8591da177e4SLinus Torvalds 		ret = (FAILED);
8601da177e4SLinus Torvalds 	}
8618fa728a2SJeff Garzik  
8628fa728a2SJeff Garzik  	IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
8631da177e4SLinus Torvalds 	return ret;
8641da177e4SLinus Torvalds }
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds /****************************************************************************/
8671da177e4SLinus Torvalds /*                                                                          */
8681da177e4SLinus Torvalds /* Routine Name: ips_eh_reset                                               */
8691da177e4SLinus Torvalds /*                                                                          */
8701da177e4SLinus Torvalds /* Routine Description:                                                     */
8711da177e4SLinus Torvalds /*                                                                          */
8721da177e4SLinus Torvalds /*   Reset the controller (with new eh error code)                          */
8731da177e4SLinus Torvalds /*                                                                          */
8741da177e4SLinus Torvalds /* NOTE: this routine is called under the io_request_lock spinlock          */
8751da177e4SLinus Torvalds /*                                                                          */
8761da177e4SLinus Torvalds /****************************************************************************/
8771da177e4SLinus Torvalds static int
878df0ae249SJeff Garzik  __ips_eh_reset(Scsi_Cmnd * SC)
8791da177e4SLinus Torvalds {
8801da177e4SLinus Torvalds 	int ret;
8811da177e4SLinus Torvalds 	int i;
8821da177e4SLinus Torvalds 	ips_ha_t *ha;
8831da177e4SLinus Torvalds 	ips_scb_t *scb;
8841da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
8851da177e4SLinus Torvalds 
8861da177e4SLinus Torvalds 	METHOD_TRACE("ips_eh_reset", 1);
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds #ifdef NO_IPS_RESET
8891da177e4SLinus Torvalds 	return (FAILED);
8901da177e4SLinus Torvalds #else
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds 	if (!SC) {
8931da177e4SLinus Torvalds 		DEBUG(1, "Reset called with NULL scsi command");
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 		return (FAILED);
8961da177e4SLinus Torvalds 	}
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds 	ha = (ips_ha_t *) SC->device->host->hostdata;
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds 	if (!ha) {
9011da177e4SLinus Torvalds 		DEBUG(1, "Reset called with NULL ha struct");
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 		return (FAILED);
9041da177e4SLinus Torvalds 	}
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds 	if (!ha->active)
9071da177e4SLinus Torvalds 		return (FAILED);
9081da177e4SLinus Torvalds 
9091da177e4SLinus Torvalds 	/* See if the command is on the copp queue */
9101da177e4SLinus Torvalds 	item = ha->copp_waitlist.head;
9111da177e4SLinus Torvalds 	while ((item) && (item->scsi_cmd != SC))
9121da177e4SLinus Torvalds 		item = item->next;
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds 	if (item) {
9151da177e4SLinus Torvalds 		/* Found it */
9161da177e4SLinus Torvalds 		ips_removeq_copp(&ha->copp_waitlist, item);
9171da177e4SLinus Torvalds 		return (SUCCESS);
9181da177e4SLinus Torvalds 	}
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	/* See if the command is on the wait queue */
9211da177e4SLinus Torvalds 	if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
9221da177e4SLinus Torvalds 		/* command not sent yet */
9231da177e4SLinus Torvalds 		return (SUCCESS);
9241da177e4SLinus Torvalds 	}
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 	/* An explanation for the casual observer:                              */
9271da177e4SLinus Torvalds 	/* Part of the function of a RAID controller is automatic error         */
9281da177e4SLinus Torvalds 	/* detection and recovery.  As such, the only problem that physically   */
9291da177e4SLinus Torvalds 	/* resetting an adapter will ever fix is when, for some reason,         */
9301da177e4SLinus Torvalds 	/* the driver is not successfully communicating with the adapter.       */
9311da177e4SLinus Torvalds 	/* Therefore, we will attempt to flush this adapter.  If that succeeds, */
9321da177e4SLinus Torvalds 	/* then there's no real purpose in a physical reset. This will complete */
9331da177e4SLinus Torvalds 	/* much faster and avoids any problems that might be caused by a        */
9341da177e4SLinus Torvalds 	/* physical reset ( such as having to fail all the outstanding I/O's ). */
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */
9371da177e4SLinus Torvalds 		scb = &ha->scbs[ha->max_cmds - 1];
9381da177e4SLinus Torvalds 
9391da177e4SLinus Torvalds 		ips_init_scb(ha, scb);
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
9421da177e4SLinus Torvalds 		scb->cdb[0] = IPS_CMD_FLUSH;
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
9451da177e4SLinus Torvalds 		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
9461da177e4SLinus Torvalds 		scb->cmd.flush_cache.state = IPS_NORM_STATE;
9471da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved = 0;
9481da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved2 = 0;
9491da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved3 = 0;
9501da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved4 = 0;
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 		/* Attempt the flush command */
9531da177e4SLinus Torvalds 		ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
9541da177e4SLinus Torvalds 		if (ret == IPS_SUCCESS) {
9551da177e4SLinus Torvalds 			IPS_PRINTK(KERN_NOTICE, ha->pcidev,
9561da177e4SLinus Torvalds 				   "Reset Request - Flushed Cache\n");
9571da177e4SLinus Torvalds 			return (SUCCESS);
9581da177e4SLinus Torvalds 		}
9591da177e4SLinus Torvalds 	}
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 	/* Either we can't communicate with the adapter or it's an IOCTL request */
9621da177e4SLinus Torvalds 	/* from a utility.  A physical reset is needed at this point.            */
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 	ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds 	/*
9671da177e4SLinus Torvalds 	 * command must have already been sent
9681da177e4SLinus Torvalds 	 * reset the controller
9691da177e4SLinus Torvalds 	 */
9701da177e4SLinus Torvalds 	IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
9711da177e4SLinus Torvalds 	ret = (*ha->func.reset) (ha);
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds 	if (!ret) {
9741da177e4SLinus Torvalds 		Scsi_Cmnd *scsi_cmd;
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
9771da177e4SLinus Torvalds 			   "Controller reset failed - controller now offline.\n");
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 		/* Now fail all of the active commands */
9801da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing active commands",
9811da177e4SLinus Torvalds 			  ips_name, ha->host_num);
9821da177e4SLinus Torvalds 
9831da177e4SLinus Torvalds 		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
9841da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_ERROR << 16;
9851da177e4SLinus Torvalds 			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
9861da177e4SLinus Torvalds 			ips_freescb(ha, scb);
9871da177e4SLinus Torvalds 		}
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds 		/* Now fail all of the pending commands */
9901da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing pending commands",
9911da177e4SLinus Torvalds 			  ips_name, ha->host_num);
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds 		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
9941da177e4SLinus Torvalds 			scsi_cmd->result = DID_ERROR;
9951da177e4SLinus Torvalds 			scsi_cmd->scsi_done(scsi_cmd);
9961da177e4SLinus Torvalds 		}
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds 		ha->active = FALSE;
9991da177e4SLinus Torvalds 		return (FAILED);
10001da177e4SLinus Torvalds 	}
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds 	if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
10031da177e4SLinus Torvalds 		Scsi_Cmnd *scsi_cmd;
10041da177e4SLinus Torvalds 
10051da177e4SLinus Torvalds 		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
10061da177e4SLinus Torvalds 			   "Controller reset failed - controller now offline.\n");
10071da177e4SLinus Torvalds 
10081da177e4SLinus Torvalds 		/* Now fail all of the active commands */
10091da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing active commands",
10101da177e4SLinus Torvalds 			  ips_name, ha->host_num);
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
10131da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_ERROR << 16;
10141da177e4SLinus Torvalds 			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
10151da177e4SLinus Torvalds 			ips_freescb(ha, scb);
10161da177e4SLinus Torvalds 		}
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 		/* Now fail all of the pending commands */
10191da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing pending commands",
10201da177e4SLinus Torvalds 			  ips_name, ha->host_num);
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds 		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
10231da177e4SLinus Torvalds 			scsi_cmd->result = DID_ERROR << 16;
10241da177e4SLinus Torvalds 			scsi_cmd->scsi_done(scsi_cmd);
10251da177e4SLinus Torvalds 		}
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 		ha->active = FALSE;
10281da177e4SLinus Torvalds 		return (FAILED);
10291da177e4SLinus Torvalds 	}
10301da177e4SLinus Torvalds 
10311da177e4SLinus Torvalds 	/* FFDC */
10321da177e4SLinus Torvalds 	if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
10331da177e4SLinus Torvalds 		struct timeval tv;
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds 		do_gettimeofday(&tv);
10361da177e4SLinus Torvalds 		ha->last_ffdc = tv.tv_sec;
10371da177e4SLinus Torvalds 		ha->reset_count++;
10381da177e4SLinus Torvalds 		ips_ffdc_reset(ha, IPS_INTR_IORL);
10391da177e4SLinus Torvalds 	}
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds 	/* Now fail all of the active commands */
10421da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
10431da177e4SLinus Torvalds 
10441da177e4SLinus Torvalds 	while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
10451da177e4SLinus Torvalds 		scb->scsi_cmd->result =
10461da177e4SLinus Torvalds 		    (DID_RESET << 16) | (SUGGEST_RETRY << 24);
10471da177e4SLinus Torvalds 		scb->scsi_cmd->scsi_done(scb->scsi_cmd);
10481da177e4SLinus Torvalds 		ips_freescb(ha, scb);
10491da177e4SLinus Torvalds 	}
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds 	/* Reset DCDB active command bits */
10521da177e4SLinus Torvalds 	for (i = 1; i < ha->nbus; i++)
10531da177e4SLinus Torvalds 		ha->dcdb_active[i - 1] = 0;
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds 	/* Reset the number of active IOCTLs */
10561da177e4SLinus Torvalds 	ha->num_ioctl = 0;
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	ips_next(ha, IPS_INTR_IORL);
10591da177e4SLinus Torvalds 
10601da177e4SLinus Torvalds 	return (SUCCESS);
10611da177e4SLinus Torvalds #endif				/* NO_IPS_RESET */
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds }
10641da177e4SLinus Torvalds 
1065df0ae249SJeff Garzik  static int
1066df0ae249SJeff Garzik  ips_eh_reset(Scsi_Cmnd * SC)
1067df0ae249SJeff Garzik  {
1068df0ae249SJeff Garzik  	int rc;
1069df0ae249SJeff Garzik  
1070df0ae249SJeff Garzik  	spin_lock_irq(SC->device->host->host_lock);
1071df0ae249SJeff Garzik  	rc = __ips_eh_reset(SC);
1072df0ae249SJeff Garzik  	spin_unlock_irq(SC->device->host->host_lock);
1073df0ae249SJeff Garzik  
1074df0ae249SJeff Garzik  	return rc;
1075df0ae249SJeff Garzik  }
1076df0ae249SJeff Garzik  
10771da177e4SLinus Torvalds /****************************************************************************/
10781da177e4SLinus Torvalds /*                                                                          */
10791da177e4SLinus Torvalds /* Routine Name: ips_queue                                                  */
10801da177e4SLinus Torvalds /*                                                                          */
10811da177e4SLinus Torvalds /* Routine Description:                                                     */
10821da177e4SLinus Torvalds /*                                                                          */
10831da177e4SLinus Torvalds /*   Send a command to the controller                                       */
10841da177e4SLinus Torvalds /*                                                                          */
10851da177e4SLinus Torvalds /* NOTE:                                                                    */
10861da177e4SLinus Torvalds /*    Linux obtains io_request_lock before calling this function            */
10871da177e4SLinus Torvalds /*                                                                          */
10881da177e4SLinus Torvalds /****************************************************************************/
10891da177e4SLinus Torvalds static int
10901da177e4SLinus Torvalds ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
10911da177e4SLinus Torvalds {
10921da177e4SLinus Torvalds 	ips_ha_t *ha;
10931da177e4SLinus Torvalds 	ips_passthru_t *pt;
10941da177e4SLinus Torvalds 
10951da177e4SLinus Torvalds 	METHOD_TRACE("ips_queue", 1);
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 	ha = (ips_ha_t *) SC->device->host->hostdata;
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	if (!ha)
11001da177e4SLinus Torvalds 		return (1);
11011da177e4SLinus Torvalds 
11021da177e4SLinus Torvalds 	if (!ha->active)
11031da177e4SLinus Torvalds 		return (DID_ERROR);
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 	if (ips_is_passthru(SC)) {
11061da177e4SLinus Torvalds 		if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
11071da177e4SLinus Torvalds 			SC->result = DID_BUS_BUSY << 16;
11081da177e4SLinus Torvalds 			done(SC);
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 			return (0);
11111da177e4SLinus Torvalds 		}
11121da177e4SLinus Torvalds 	} else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
11131da177e4SLinus Torvalds 		SC->result = DID_BUS_BUSY << 16;
11141da177e4SLinus Torvalds 		done(SC);
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 		return (0);
11171da177e4SLinus Torvalds 	}
11181da177e4SLinus Torvalds 
11191da177e4SLinus Torvalds 	SC->scsi_done = done;
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds 	DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
11221da177e4SLinus Torvalds 		  ips_name,
11231da177e4SLinus Torvalds 		  ha->host_num,
11241da177e4SLinus Torvalds 		  SC->cmnd[0],
11251da177e4SLinus Torvalds 		  SC->device->channel, SC->device->id, SC->device->lun);
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 	/* Check for command to initiator IDs */
11281da177e4SLinus Torvalds 	if ((SC->device->channel > 0)
11291da177e4SLinus Torvalds 	    && (SC->device->id == ha->ha_id[SC->device->channel])) {
11301da177e4SLinus Torvalds 		SC->result = DID_NO_CONNECT << 16;
11311da177e4SLinus Torvalds 		done(SC);
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 		return (0);
11341da177e4SLinus Torvalds 	}
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds 	if (ips_is_passthru(SC)) {
11371da177e4SLinus Torvalds 
11381da177e4SLinus Torvalds 		ips_copp_wait_item_t *scratch;
11391da177e4SLinus Torvalds 
11401da177e4SLinus Torvalds 		/* A Reset IOCTL is only sent by the boot CD in extreme cases.           */
11411da177e4SLinus Torvalds 		/* There can never be any system activity ( network or disk ), but check */
11421da177e4SLinus Torvalds 		/* anyway just as a good practice.                                       */
11431da177e4SLinus Torvalds 		pt = (ips_passthru_t *) SC->request_buffer;
11441da177e4SLinus Torvalds 		if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
11451da177e4SLinus Torvalds 		    (pt->CoppCP.cmd.reset.adapter_flag == 1)) {
11461da177e4SLinus Torvalds 			if (ha->scb_activelist.count != 0) {
11471da177e4SLinus Torvalds 				SC->result = DID_BUS_BUSY << 16;
11481da177e4SLinus Torvalds 				done(SC);
11491da177e4SLinus Torvalds 				return (0);
11501da177e4SLinus Torvalds 			}
11511da177e4SLinus Torvalds 			ha->ioctl_reset = 1;	/* This reset request is from an IOCTL */
11521da177e4SLinus Torvalds 			ips_eh_reset(SC);
11531da177e4SLinus Torvalds 			SC->result = DID_OK << 16;
11541da177e4SLinus Torvalds 			SC->scsi_done(SC);
11551da177e4SLinus Torvalds 			return (0);
11561da177e4SLinus Torvalds 		}
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 		/* allocate space for the scribble */
11591da177e4SLinus Torvalds 		scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC);
11601da177e4SLinus Torvalds 
11611da177e4SLinus Torvalds 		if (!scratch) {
11621da177e4SLinus Torvalds 			SC->result = DID_ERROR << 16;
11631da177e4SLinus Torvalds 			done(SC);
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds 			return (0);
11661da177e4SLinus Torvalds 		}
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 		scratch->scsi_cmd = SC;
11691da177e4SLinus Torvalds 		scratch->next = NULL;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 		ips_putq_copp_tail(&ha->copp_waitlist, scratch);
11721da177e4SLinus Torvalds 	} else {
11731da177e4SLinus Torvalds 		ips_putq_wait_tail(&ha->scb_waitlist, SC);
11741da177e4SLinus Torvalds 	}
11751da177e4SLinus Torvalds 
11761da177e4SLinus Torvalds 	ips_next(ha, IPS_INTR_IORL);
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 	return (0);
11791da177e4SLinus Torvalds }
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds /****************************************************************************/
11821da177e4SLinus Torvalds /*                                                                          */
11831da177e4SLinus Torvalds /* Routine Name: ips_biosparam                                              */
11841da177e4SLinus Torvalds /*                                                                          */
11851da177e4SLinus Torvalds /* Routine Description:                                                     */
11861da177e4SLinus Torvalds /*                                                                          */
11871da177e4SLinus Torvalds /*   Set bios geometry for the controller                                   */
11881da177e4SLinus Torvalds /*                                                                          */
11891da177e4SLinus Torvalds /****************************************************************************/
11901da177e4SLinus Torvalds static int
11911da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
11921da177e4SLinus Torvalds ips_biosparam(Disk * disk, kdev_t dev, int geom[])
11931da177e4SLinus Torvalds {
11941da177e4SLinus Torvalds 	ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata;
11951da177e4SLinus Torvalds 	unsigned long capacity = disk->capacity;
11961da177e4SLinus Torvalds #else
11971da177e4SLinus Torvalds ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
11981da177e4SLinus Torvalds 	      sector_t capacity, int geom[])
11991da177e4SLinus Torvalds {
12001da177e4SLinus Torvalds 	ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
12011da177e4SLinus Torvalds #endif
12021da177e4SLinus Torvalds 	int heads;
12031da177e4SLinus Torvalds 	int sectors;
12041da177e4SLinus Torvalds 	int cylinders;
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 	METHOD_TRACE("ips_biosparam", 1);
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 	if (!ha)
12091da177e4SLinus Torvalds 		/* ?!?! host adater info invalid */
12101da177e4SLinus Torvalds 		return (0);
12111da177e4SLinus Torvalds 
12121da177e4SLinus Torvalds 	if (!ha->active)
12131da177e4SLinus Torvalds 		return (0);
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds 	if (!ips_read_adapter_status(ha, IPS_INTR_ON))
12161da177e4SLinus Torvalds 		/* ?!?! Enquiry command failed */
12171da177e4SLinus Torvalds 		return (0);
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
12201da177e4SLinus Torvalds 		heads = IPS_NORM_HEADS;
12211da177e4SLinus Torvalds 		sectors = IPS_NORM_SECTORS;
12221da177e4SLinus Torvalds 	} else {
12231da177e4SLinus Torvalds 		heads = IPS_COMP_HEADS;
12241da177e4SLinus Torvalds 		sectors = IPS_COMP_SECTORS;
12251da177e4SLinus Torvalds 	}
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 	cylinders = (unsigned long) capacity / (heads * sectors);
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
12301da177e4SLinus Torvalds 		  heads, sectors, cylinders);
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 	geom[0] = heads;
12331da177e4SLinus Torvalds 	geom[1] = sectors;
12341da177e4SLinus Torvalds 	geom[2] = cylinders;
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	return (0);
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds 
12391da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds /* ips_proc24_info is a wrapper around ips_proc_info *
12421da177e4SLinus Torvalds  * for compatibility with the 2.4 scsi parameters    */
12431da177e4SLinus Torvalds static int
12441da177e4SLinus Torvalds ips_proc24_info(char *buffer, char **start, off_t offset, int length,
12451da177e4SLinus Torvalds 		              int hostno, int func)
12461da177e4SLinus Torvalds {
12471da177e4SLinus Torvalds 	int i;
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds 	for (i = 0; i < ips_next_controller; i++) {
12501da177e4SLinus Torvalds 		if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
12511da177e4SLinus Torvalds 			return ips_proc_info(ips_sh[i], buffer, start,
12521da177e4SLinus Torvalds 					     offset, length, func);
12531da177e4SLinus Torvalds 		}
12541da177e4SLinus Torvalds 	}
12551da177e4SLinus Torvalds 	return -EINVAL;
12561da177e4SLinus Torvalds }
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds /****************************************************************************/
12591da177e4SLinus Torvalds /*                                                                          */
12601da177e4SLinus Torvalds /* Routine Name: ips_select_queue_depth                                     */
12611da177e4SLinus Torvalds /*                                                                          */
12621da177e4SLinus Torvalds /* Routine Description:                                                     */
12631da177e4SLinus Torvalds /*                                                                          */
12641da177e4SLinus Torvalds /*   Select queue depths for the devices on the contoller                   */
12651da177e4SLinus Torvalds /*                                                                          */
12661da177e4SLinus Torvalds /****************************************************************************/
12671da177e4SLinus Torvalds static void
12681da177e4SLinus Torvalds ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
12691da177e4SLinus Torvalds {
12701da177e4SLinus Torvalds 	Scsi_Device *device;
12711da177e4SLinus Torvalds 	ips_ha_t *ha;
12721da177e4SLinus Torvalds 	int count = 0;
12731da177e4SLinus Torvalds 	int min;
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 	ha = IPS_HA(host);
12761da177e4SLinus Torvalds 	min = ha->max_cmds / 4;
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds 	for (device = scsi_devs; device; device = device->next) {
12791da177e4SLinus Torvalds 		if (device->host == host) {
12801da177e4SLinus Torvalds 			if ((device->channel == 0) && (device->type == 0))
12811da177e4SLinus Torvalds 				count++;
12821da177e4SLinus Torvalds 		}
12831da177e4SLinus Torvalds 	}
12841da177e4SLinus Torvalds 
12851da177e4SLinus Torvalds 	for (device = scsi_devs; device; device = device->next) {
12861da177e4SLinus Torvalds 		if (device->host == host) {
12871da177e4SLinus Torvalds 			if ((device->channel == 0) && (device->type == 0)) {
12881da177e4SLinus Torvalds 				device->queue_depth =
12891da177e4SLinus Torvalds 				    (ha->max_cmds - 1) / count;
12901da177e4SLinus Torvalds 				if (device->queue_depth < min)
12911da177e4SLinus Torvalds 					device->queue_depth = min;
12921da177e4SLinus Torvalds 			} else {
12931da177e4SLinus Torvalds 				device->queue_depth = 2;
12941da177e4SLinus Torvalds 			}
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds 			if (device->queue_depth < 2)
12971da177e4SLinus Torvalds 				device->queue_depth = 2;
12981da177e4SLinus Torvalds 		}
12991da177e4SLinus Torvalds 	}
13001da177e4SLinus Torvalds }
13011da177e4SLinus Torvalds 
13021da177e4SLinus Torvalds #else
13031da177e4SLinus Torvalds /****************************************************************************/
13041da177e4SLinus Torvalds /*                                                                          */
13051da177e4SLinus Torvalds /* Routine Name: ips_slave_configure                                        */
13061da177e4SLinus Torvalds /*                                                                          */
13071da177e4SLinus Torvalds /* Routine Description:                                                     */
13081da177e4SLinus Torvalds /*                                                                          */
13091da177e4SLinus Torvalds /*   Set queue depths on devices once scan is complete                      */
13101da177e4SLinus Torvalds /*                                                                          */
13111da177e4SLinus Torvalds /****************************************************************************/
13121da177e4SLinus Torvalds static int
13131da177e4SLinus Torvalds ips_slave_configure(Scsi_Device * SDptr)
13141da177e4SLinus Torvalds {
13151da177e4SLinus Torvalds 	ips_ha_t *ha;
13161da177e4SLinus Torvalds 	int min;
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 	ha = IPS_HA(SDptr->host);
13191da177e4SLinus Torvalds 	if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) {
13201da177e4SLinus Torvalds 		min = ha->max_cmds / 2;
13211da177e4SLinus Torvalds 		if (ha->enq->ucLogDriveCount <= 2)
13221da177e4SLinus Torvalds 			min = ha->max_cmds - 1;
13231da177e4SLinus Torvalds 		scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
13241da177e4SLinus Torvalds 	}
13251da177e4SLinus Torvalds 	return 0;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds #endif
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds /****************************************************************************/
13301da177e4SLinus Torvalds /*                                                                          */
13311da177e4SLinus Torvalds /* Routine Name: do_ipsintr                                                 */
13321da177e4SLinus Torvalds /*                                                                          */
13331da177e4SLinus Torvalds /* Routine Description:                                                     */
13341da177e4SLinus Torvalds /*                                                                          */
13351da177e4SLinus Torvalds /*   Wrapper for the interrupt handler                                      */
13361da177e4SLinus Torvalds /*                                                                          */
13371da177e4SLinus Torvalds /****************************************************************************/
13381da177e4SLinus Torvalds static irqreturn_t
13391da177e4SLinus Torvalds do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
13401da177e4SLinus Torvalds {
13411da177e4SLinus Torvalds 	ips_ha_t *ha;
13421da177e4SLinus Torvalds 	unsigned long cpu_flags;
13431da177e4SLinus Torvalds 	struct Scsi_Host *host;
13441da177e4SLinus Torvalds 	int irqstatus;
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	METHOD_TRACE("do_ipsintr", 2);
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	ha = (ips_ha_t *) dev_id;
13491da177e4SLinus Torvalds 	if (!ha)
13501da177e4SLinus Torvalds 		return IRQ_NONE;
13511da177e4SLinus Torvalds 	host = ips_sh[ha->host_num];
13521da177e4SLinus Torvalds 	/* interrupt during initialization */
13531da177e4SLinus Torvalds 	if (!host) {
13541da177e4SLinus Torvalds 		(*ha->func.intr) (ha);
13551da177e4SLinus Torvalds 		return IRQ_HANDLED;
13561da177e4SLinus Torvalds 	}
13571da177e4SLinus Torvalds 
13581da177e4SLinus Torvalds 	IPS_LOCK_SAVE(host->host_lock, cpu_flags);
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 	if (!ha->active) {
13611da177e4SLinus Torvalds 		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
13621da177e4SLinus Torvalds 		return IRQ_HANDLED;
13631da177e4SLinus Torvalds 	}
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds 	irqstatus = (*ha->func.intr) (ha);
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 	IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 	/* start the next command */
13701da177e4SLinus Torvalds 	ips_next(ha, IPS_INTR_ON);
13711da177e4SLinus Torvalds 	return IRQ_RETVAL(irqstatus);
13721da177e4SLinus Torvalds }
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds /****************************************************************************/
13751da177e4SLinus Torvalds /*                                                                          */
13761da177e4SLinus Torvalds /* Routine Name: ips_intr_copperhead                                        */
13771da177e4SLinus Torvalds /*                                                                          */
13781da177e4SLinus Torvalds /* Routine Description:                                                     */
13791da177e4SLinus Torvalds /*                                                                          */
13801da177e4SLinus Torvalds /*   Polling interrupt handler                                              */
13811da177e4SLinus Torvalds /*                                                                          */
13821da177e4SLinus Torvalds /*   ASSUMES interrupts are disabled                                        */
13831da177e4SLinus Torvalds /*                                                                          */
13841da177e4SLinus Torvalds /****************************************************************************/
13851da177e4SLinus Torvalds int
13861da177e4SLinus Torvalds ips_intr_copperhead(ips_ha_t * ha)
13871da177e4SLinus Torvalds {
13881da177e4SLinus Torvalds 	ips_stat_t *sp;
13891da177e4SLinus Torvalds 	ips_scb_t *scb;
13901da177e4SLinus Torvalds 	IPS_STATUS cstatus;
13911da177e4SLinus Torvalds 	int intrstatus;
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds 	METHOD_TRACE("ips_intr", 2);
13941da177e4SLinus Torvalds 
13951da177e4SLinus Torvalds 	if (!ha)
13961da177e4SLinus Torvalds 		return 0;
13971da177e4SLinus Torvalds 
13981da177e4SLinus Torvalds 	if (!ha->active)
13991da177e4SLinus Torvalds 		return 0;
14001da177e4SLinus Torvalds 
14011da177e4SLinus Torvalds 	intrstatus = (*ha->func.isintr) (ha);
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 	if (!intrstatus) {
14041da177e4SLinus Torvalds 		/*
14051da177e4SLinus Torvalds 		 * Unexpected/Shared interrupt
14061da177e4SLinus Torvalds 		 */
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds 		return 0;
14091da177e4SLinus Torvalds 	}
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 	while (TRUE) {
14121da177e4SLinus Torvalds 		sp = &ha->sp;
14131da177e4SLinus Torvalds 
14141da177e4SLinus Torvalds 		intrstatus = (*ha->func.isintr) (ha);
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds 		if (!intrstatus)
14171da177e4SLinus Torvalds 			break;
14181da177e4SLinus Torvalds 		else
14191da177e4SLinus Torvalds 			cstatus.value = (*ha->func.statupd) (ha);
14201da177e4SLinus Torvalds 
14211da177e4SLinus Torvalds 		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
14221da177e4SLinus Torvalds 			/* Spurious Interupt ? */
14231da177e4SLinus Torvalds 			continue;
14241da177e4SLinus Torvalds 		}
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds 		ips_chkstatus(ha, &cstatus);
14271da177e4SLinus Torvalds 		scb = (ips_scb_t *) sp->scb_addr;
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 		/*
14301da177e4SLinus Torvalds 		 * use the callback function to finish things up
14311da177e4SLinus Torvalds 		 * NOTE: interrupts are OFF for this
14321da177e4SLinus Torvalds 		 */
14331da177e4SLinus Torvalds 		(*scb->callback) (ha, scb);
14341da177e4SLinus Torvalds 	}			/* end while */
14351da177e4SLinus Torvalds 	return 1;
14361da177e4SLinus Torvalds }
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds /****************************************************************************/
14391da177e4SLinus Torvalds /*                                                                          */
14401da177e4SLinus Torvalds /* Routine Name: ips_intr_morpheus                                          */
14411da177e4SLinus Torvalds /*                                                                          */
14421da177e4SLinus Torvalds /* Routine Description:                                                     */
14431da177e4SLinus Torvalds /*                                                                          */
14441da177e4SLinus Torvalds /*   Polling interrupt handler                                              */
14451da177e4SLinus Torvalds /*                                                                          */
14461da177e4SLinus Torvalds /*   ASSUMES interrupts are disabled                                        */
14471da177e4SLinus Torvalds /*                                                                          */
14481da177e4SLinus Torvalds /****************************************************************************/
14491da177e4SLinus Torvalds int
14501da177e4SLinus Torvalds ips_intr_morpheus(ips_ha_t * ha)
14511da177e4SLinus Torvalds {
14521da177e4SLinus Torvalds 	ips_stat_t *sp;
14531da177e4SLinus Torvalds 	ips_scb_t *scb;
14541da177e4SLinus Torvalds 	IPS_STATUS cstatus;
14551da177e4SLinus Torvalds 	int intrstatus;
14561da177e4SLinus Torvalds 
14571da177e4SLinus Torvalds 	METHOD_TRACE("ips_intr_morpheus", 2);
14581da177e4SLinus Torvalds 
14591da177e4SLinus Torvalds 	if (!ha)
14601da177e4SLinus Torvalds 		return 0;
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 	if (!ha->active)
14631da177e4SLinus Torvalds 		return 0;
14641da177e4SLinus Torvalds 
14651da177e4SLinus Torvalds 	intrstatus = (*ha->func.isintr) (ha);
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 	if (!intrstatus) {
14681da177e4SLinus Torvalds 		/*
14691da177e4SLinus Torvalds 		 * Unexpected/Shared interrupt
14701da177e4SLinus Torvalds 		 */
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 		return 0;
14731da177e4SLinus Torvalds 	}
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 	while (TRUE) {
14761da177e4SLinus Torvalds 		sp = &ha->sp;
14771da177e4SLinus Torvalds 
14781da177e4SLinus Torvalds 		intrstatus = (*ha->func.isintr) (ha);
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds 		if (!intrstatus)
14811da177e4SLinus Torvalds 			break;
14821da177e4SLinus Torvalds 		else
14831da177e4SLinus Torvalds 			cstatus.value = (*ha->func.statupd) (ha);
14841da177e4SLinus Torvalds 
14851da177e4SLinus Torvalds 		if (cstatus.value == 0xffffffff)
14861da177e4SLinus Torvalds 			/* No more to process */
14871da177e4SLinus Torvalds 			break;
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds 		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
14901da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
14911da177e4SLinus Torvalds 				   "Spurious interrupt; no ccb.\n");
14921da177e4SLinus Torvalds 
14931da177e4SLinus Torvalds 			continue;
14941da177e4SLinus Torvalds 		}
14951da177e4SLinus Torvalds 
14961da177e4SLinus Torvalds 		ips_chkstatus(ha, &cstatus);
14971da177e4SLinus Torvalds 		scb = (ips_scb_t *) sp->scb_addr;
14981da177e4SLinus Torvalds 
14991da177e4SLinus Torvalds 		/*
15001da177e4SLinus Torvalds 		 * use the callback function to finish things up
15011da177e4SLinus Torvalds 		 * NOTE: interrupts are OFF for this
15021da177e4SLinus Torvalds 		 */
15031da177e4SLinus Torvalds 		(*scb->callback) (ha, scb);
15041da177e4SLinus Torvalds 	}			/* end while */
15051da177e4SLinus Torvalds 	return 1;
15061da177e4SLinus Torvalds }
15071da177e4SLinus Torvalds 
15081da177e4SLinus Torvalds /****************************************************************************/
15091da177e4SLinus Torvalds /*                                                                          */
15101da177e4SLinus Torvalds /* Routine Name: ips_info                                                   */
15111da177e4SLinus Torvalds /*                                                                          */
15121da177e4SLinus Torvalds /* Routine Description:                                                     */
15131da177e4SLinus Torvalds /*                                                                          */
15141da177e4SLinus Torvalds /*   Return info about the driver                                           */
15151da177e4SLinus Torvalds /*                                                                          */
15161da177e4SLinus Torvalds /****************************************************************************/
15171da177e4SLinus Torvalds static const char *
15181da177e4SLinus Torvalds ips_info(struct Scsi_Host *SH)
15191da177e4SLinus Torvalds {
15201da177e4SLinus Torvalds 	static char buffer[256];
15211da177e4SLinus Torvalds 	char *bp;
15221da177e4SLinus Torvalds 	ips_ha_t *ha;
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds 	METHOD_TRACE("ips_info", 1);
15251da177e4SLinus Torvalds 
15261da177e4SLinus Torvalds 	ha = IPS_HA(SH);
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 	if (!ha)
15291da177e4SLinus Torvalds 		return (NULL);
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	bp = &buffer[0];
15321da177e4SLinus Torvalds 	memset(bp, 0, sizeof (buffer));
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ",
15351da177e4SLinus Torvalds 		IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT);
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds 	if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) {
15381da177e4SLinus Torvalds 		strcat(bp, " <");
15391da177e4SLinus Torvalds 		strcat(bp, ips_adapter_name[ha->ad_type - 1]);
15401da177e4SLinus Torvalds 		strcat(bp, ">");
15411da177e4SLinus Torvalds 	}
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds 	return (bp);
15441da177e4SLinus Torvalds }
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds /****************************************************************************/
15471da177e4SLinus Torvalds /*                                                                          */
15481da177e4SLinus Torvalds /* Routine Name: ips_proc_info                                              */
15491da177e4SLinus Torvalds /*                                                                          */
15501da177e4SLinus Torvalds /* Routine Description:                                                     */
15511da177e4SLinus Torvalds /*                                                                          */
15521da177e4SLinus Torvalds /*   The passthru interface for the driver                                  */
15531da177e4SLinus Torvalds /*                                                                          */
15541da177e4SLinus Torvalds /****************************************************************************/
15551da177e4SLinus Torvalds static int
15561da177e4SLinus Torvalds ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
15571da177e4SLinus Torvalds 	      int length, int func)
15581da177e4SLinus Torvalds {
15591da177e4SLinus Torvalds 	int i;
15601da177e4SLinus Torvalds 	int ret;
15611da177e4SLinus Torvalds 	ips_ha_t *ha = NULL;
15621da177e4SLinus Torvalds 
15631da177e4SLinus Torvalds 	METHOD_TRACE("ips_proc_info", 1);
15641da177e4SLinus Torvalds 
15651da177e4SLinus Torvalds 	/* Find our host structure */
15661da177e4SLinus Torvalds 	for (i = 0; i < ips_next_controller; i++) {
15671da177e4SLinus Torvalds 		if (ips_sh[i]) {
15681da177e4SLinus Torvalds 			if (ips_sh[i] == host) {
15691da177e4SLinus Torvalds 				ha = (ips_ha_t *) ips_sh[i]->hostdata;
15701da177e4SLinus Torvalds 				break;
15711da177e4SLinus Torvalds 			}
15721da177e4SLinus Torvalds 		}
15731da177e4SLinus Torvalds 	}
15741da177e4SLinus Torvalds 
15751da177e4SLinus Torvalds 	if (!ha)
15761da177e4SLinus Torvalds 		return (-EINVAL);
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds 	if (func) {
15791da177e4SLinus Torvalds 		/* write */
15801da177e4SLinus Torvalds 		return (0);
15811da177e4SLinus Torvalds 	} else {
15821da177e4SLinus Torvalds 		/* read */
15831da177e4SLinus Torvalds 		if (start)
15841da177e4SLinus Torvalds 			*start = buffer;
15851da177e4SLinus Torvalds 
15861da177e4SLinus Torvalds 		ret = ips_host_info(ha, buffer, offset, length);
15871da177e4SLinus Torvalds 
15881da177e4SLinus Torvalds 		return (ret);
15891da177e4SLinus Torvalds 	}
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds /*--------------------------------------------------------------------------*/
15931da177e4SLinus Torvalds /* Helper Functions                                                         */
15941da177e4SLinus Torvalds /*--------------------------------------------------------------------------*/
15951da177e4SLinus Torvalds 
15961da177e4SLinus Torvalds /****************************************************************************/
15971da177e4SLinus Torvalds /*                                                                          */
15981da177e4SLinus Torvalds /* Routine Name: ips_is_passthru                                            */
15991da177e4SLinus Torvalds /*                                                                          */
16001da177e4SLinus Torvalds /* Routine Description:                                                     */
16011da177e4SLinus Torvalds /*                                                                          */
16021da177e4SLinus Torvalds /*   Determine if the specified SCSI command is really a passthru command   */
16031da177e4SLinus Torvalds /*                                                                          */
16041da177e4SLinus Torvalds /****************************************************************************/
16051da177e4SLinus Torvalds static int
16061da177e4SLinus Torvalds ips_is_passthru(Scsi_Cmnd * SC)
16071da177e4SLinus Torvalds {
16081da177e4SLinus Torvalds 	METHOD_TRACE("ips_is_passthru", 1);
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 	if (!SC)
16111da177e4SLinus Torvalds 		return (0);
16121da177e4SLinus Torvalds 
16131da177e4SLinus Torvalds 	if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
16141da177e4SLinus Torvalds 	    (SC->device->channel == 0) &&
16151da177e4SLinus Torvalds 	    (SC->device->id == IPS_ADAPTER_ID) &&
16161da177e4SLinus Torvalds 	    (SC->device->lun == 0) && SC->request_buffer) {
16171da177e4SLinus Torvalds 		if ((!SC->use_sg) && SC->request_bufflen &&
16181da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[0] == 'C') &&
16191da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[1] == 'O') &&
16201da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[2] == 'P') &&
16211da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[3] == 'P'))
16221da177e4SLinus Torvalds 			return 1;
16231da177e4SLinus Torvalds 		else if (SC->use_sg) {
16241da177e4SLinus Torvalds 			struct scatterlist *sg = SC->request_buffer;
16251da177e4SLinus Torvalds 			char *buffer = IPS_SG_ADDRESS(sg);
16261da177e4SLinus Torvalds 			if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
16271da177e4SLinus Torvalds 			    buffer[2] == 'P' && buffer[3] == 'P')
16281da177e4SLinus Torvalds 				return 1;
16291da177e4SLinus Torvalds 		}
16301da177e4SLinus Torvalds 	}
16311da177e4SLinus Torvalds 	return 0;
16321da177e4SLinus Torvalds }
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds /****************************************************************************/
16351da177e4SLinus Torvalds /*                                                                          */
16361da177e4SLinus Torvalds /* Routine Name: ips_alloc_passthru_buffer                                  */
16371da177e4SLinus Torvalds /*                                                                          */
16381da177e4SLinus Torvalds /* Routine Description:                                                     */
16391da177e4SLinus Torvalds /*   allocate a buffer large enough for the ioctl data if the ioctl buffer  */
16401da177e4SLinus Torvalds /*   is too small or doesn't exist                                          */
16411da177e4SLinus Torvalds /****************************************************************************/
16421da177e4SLinus Torvalds static int
16431da177e4SLinus Torvalds ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
16441da177e4SLinus Torvalds {
16451da177e4SLinus Torvalds 	void *bigger_buf;
16461da177e4SLinus Torvalds 	dma_addr_t dma_busaddr;
16471da177e4SLinus Torvalds 
16481da177e4SLinus Torvalds 	if (ha->ioctl_data && length <= ha->ioctl_len)
16491da177e4SLinus Torvalds 		return 0;
16501da177e4SLinus Torvalds 	/* there is no buffer or it's not big enough, allocate a new one */
16511da177e4SLinus Torvalds 	bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr);
16521da177e4SLinus Torvalds 	if (bigger_buf) {
16531da177e4SLinus Torvalds 		/* free the old memory */
16541da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data,
16551da177e4SLinus Torvalds 				    ha->ioctl_busaddr);
16561da177e4SLinus Torvalds 		/* use the new memory */
16571da177e4SLinus Torvalds 		ha->ioctl_data = (char *) bigger_buf;
16581da177e4SLinus Torvalds 		ha->ioctl_len = length;
16591da177e4SLinus Torvalds 		ha->ioctl_busaddr = dma_busaddr;
16601da177e4SLinus Torvalds 	} else {
16611da177e4SLinus Torvalds 		return -1;
16621da177e4SLinus Torvalds 	}
16631da177e4SLinus Torvalds 	return 0;
16641da177e4SLinus Torvalds }
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds /****************************************************************************/
16671da177e4SLinus Torvalds /*                                                                          */
16681da177e4SLinus Torvalds /* Routine Name: ips_make_passthru                                          */
16691da177e4SLinus Torvalds /*                                                                          */
16701da177e4SLinus Torvalds /* Routine Description:                                                     */
16711da177e4SLinus Torvalds /*                                                                          */
16721da177e4SLinus Torvalds /*   Make a passthru command out of the info in the Scsi block              */
16731da177e4SLinus Torvalds /*                                                                          */
16741da177e4SLinus Torvalds /****************************************************************************/
16751da177e4SLinus Torvalds static int
16761da177e4SLinus Torvalds ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
16771da177e4SLinus Torvalds {
16781da177e4SLinus Torvalds 	ips_passthru_t *pt;
16791da177e4SLinus Torvalds 	int length = 0;
16801da177e4SLinus Torvalds 	int ret;
16811da177e4SLinus Torvalds 
16821da177e4SLinus Torvalds 	METHOD_TRACE("ips_make_passthru", 1);
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds 	if (!SC->use_sg) {
16851da177e4SLinus Torvalds 		length = SC->request_bufflen;
16861da177e4SLinus Torvalds 	} else {
16871da177e4SLinus Torvalds 		struct scatterlist *sg = SC->request_buffer;
16881da177e4SLinus Torvalds 		int i;
16891da177e4SLinus Torvalds 		for (i = 0; i < SC->use_sg; i++)
16901da177e4SLinus Torvalds 			length += sg[i].length;
16911da177e4SLinus Torvalds 	}
16921da177e4SLinus Torvalds 	if (length < sizeof (ips_passthru_t)) {
16931da177e4SLinus Torvalds 		/* wrong size */
16941da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
16951da177e4SLinus Torvalds 			  ips_name, ha->host_num);
16961da177e4SLinus Torvalds 		return (IPS_FAILURE);
16971da177e4SLinus Torvalds 	}
16981da177e4SLinus Torvalds 	if (ips_alloc_passthru_buffer(ha, length)) {
16991da177e4SLinus Torvalds 		/* allocation failure!  If ha->ioctl_data exists, use it to return
17001da177e4SLinus Torvalds 		   some error codes.  Return a failed command to the scsi layer. */
17011da177e4SLinus Torvalds 		if (ha->ioctl_data) {
17021da177e4SLinus Torvalds 			pt = (ips_passthru_t *) ha->ioctl_data;
17031da177e4SLinus Torvalds 			ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t));
17041da177e4SLinus Torvalds 			pt->BasicStatus = 0x0B;
17051da177e4SLinus Torvalds 			pt->ExtendedStatus = 0x00;
17061da177e4SLinus Torvalds 			ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t));
17071da177e4SLinus Torvalds 		}
17081da177e4SLinus Torvalds 		return IPS_FAILURE;
17091da177e4SLinus Torvalds 	}
17101da177e4SLinus Torvalds 	ha->ioctl_datasize = length;
17111da177e4SLinus Torvalds 
17121da177e4SLinus Torvalds 	ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize);
17131da177e4SLinus Torvalds 	pt = (ips_passthru_t *) ha->ioctl_data;
17141da177e4SLinus Torvalds 
17151da177e4SLinus Torvalds 	/*
17161da177e4SLinus Torvalds 	 * Some notes about the passthru interface used
17171da177e4SLinus Torvalds 	 *
17181da177e4SLinus Torvalds 	 * IF the scsi op_code == 0x0d then we assume
17191da177e4SLinus Torvalds 	 * that the data came along with/goes with the
17201da177e4SLinus Torvalds 	 * packet we received from the sg driver. In this
17211da177e4SLinus Torvalds 	 * case the CmdBSize field of the pt structure is
17221da177e4SLinus Torvalds 	 * used for the size of the buffer.
17231da177e4SLinus Torvalds 	 */
17241da177e4SLinus Torvalds 
17251da177e4SLinus Torvalds 	switch (pt->CoppCmd) {
17261da177e4SLinus Torvalds 	case IPS_NUMCTRLS:
17271da177e4SLinus Torvalds 		memcpy(ha->ioctl_data + sizeof (ips_passthru_t),
17281da177e4SLinus Torvalds 		       &ips_num_controllers, sizeof (int));
17291da177e4SLinus Torvalds 		ips_scmd_buf_write(SC, ha->ioctl_data,
17301da177e4SLinus Torvalds 				   sizeof (ips_passthru_t) + sizeof (int));
17311da177e4SLinus Torvalds 		SC->result = DID_OK << 16;
17321da177e4SLinus Torvalds 
17331da177e4SLinus Torvalds 		return (IPS_SUCCESS_IMM);
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 	case IPS_COPPUSRCMD:
17361da177e4SLinus Torvalds 	case IPS_COPPIOCCMD:
17371da177e4SLinus Torvalds 		if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
17381da177e4SLinus Torvalds 			if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) {
17391da177e4SLinus Torvalds 				/* wrong size */
17401da177e4SLinus Torvalds 				DEBUG_VAR(1,
17411da177e4SLinus Torvalds 					  "(%s%d) Passthru structure wrong size",
17421da177e4SLinus Torvalds 					  ips_name, ha->host_num);
17431da177e4SLinus Torvalds 
17441da177e4SLinus Torvalds 				return (IPS_FAILURE);
17451da177e4SLinus Torvalds 			}
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds 			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
17481da177e4SLinus Torvalds 			    pt->CoppCP.cmd.flashfw.op_code ==
17491da177e4SLinus Torvalds 			    IPS_CMD_RW_BIOSFW) {
17501da177e4SLinus Torvalds 				ret = ips_flash_copperhead(ha, pt, scb);
17511da177e4SLinus Torvalds 				ips_scmd_buf_write(SC, ha->ioctl_data,
17521da177e4SLinus Torvalds 						   sizeof (ips_passthru_t));
17531da177e4SLinus Torvalds 				return ret;
17541da177e4SLinus Torvalds 			}
17551da177e4SLinus Torvalds 			if (ips_usrcmd(ha, pt, scb))
17561da177e4SLinus Torvalds 				return (IPS_SUCCESS);
17571da177e4SLinus Torvalds 			else
17581da177e4SLinus Torvalds 				return (IPS_FAILURE);
17591da177e4SLinus Torvalds 		}
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds 		break;
17621da177e4SLinus Torvalds 
17631da177e4SLinus Torvalds 	}			/* end switch */
17641da177e4SLinus Torvalds 
17651da177e4SLinus Torvalds 	return (IPS_FAILURE);
17661da177e4SLinus Torvalds }
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds /****************************************************************************/
17691da177e4SLinus Torvalds /* Routine Name: ips_flash_copperhead                                       */
17701da177e4SLinus Torvalds /* Routine Description:                                                     */
17711da177e4SLinus Torvalds /*   Flash the BIOS/FW on a Copperhead style controller                     */
17721da177e4SLinus Torvalds /****************************************************************************/
17731da177e4SLinus Torvalds static int
17741da177e4SLinus Torvalds ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
17751da177e4SLinus Torvalds {
17761da177e4SLinus Torvalds 	int datasize;
17771da177e4SLinus Torvalds 
17781da177e4SLinus Torvalds 	/* Trombone is the only copperhead that can do packet flash, but only
17791da177e4SLinus Torvalds 	 * for firmware. No one said it had to make sence. */
17801da177e4SLinus Torvalds 	if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) {
17811da177e4SLinus Torvalds 		if (ips_usrcmd(ha, pt, scb))
17821da177e4SLinus Torvalds 			return IPS_SUCCESS;
17831da177e4SLinus Torvalds 		else
17841da177e4SLinus Torvalds 			return IPS_FAILURE;
17851da177e4SLinus Torvalds 	}
17861da177e4SLinus Torvalds 	pt->BasicStatus = 0x0B;
17871da177e4SLinus Torvalds 	pt->ExtendedStatus = 0;
17881da177e4SLinus Torvalds 	scb->scsi_cmd->result = DID_OK << 16;
17891da177e4SLinus Torvalds 	/* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
17901da177e4SLinus Torvalds 	/* avoid allocating a huge buffer per adapter ( which can fail ). */
17911da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
17921da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
17931da177e4SLinus Torvalds 		pt->BasicStatus = 0;
17941da177e4SLinus Torvalds 		return ips_flash_bios(ha, pt, scb);
17951da177e4SLinus Torvalds 	} else if (pt->CoppCP.cmd.flashfw.packet_num == 0) {
17961da177e4SLinus Torvalds 		if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){
17971da177e4SLinus Torvalds 			ha->flash_data = ips_FlashData;
17981da177e4SLinus Torvalds 			ha->flash_busaddr = ips_flashbusaddr;
17991da177e4SLinus Torvalds 			ha->flash_len = PAGE_SIZE << 7;
18001da177e4SLinus Torvalds 			ha->flash_datasize = 0;
18011da177e4SLinus Torvalds 		} else if (!ha->flash_data) {
18021da177e4SLinus Torvalds 			datasize = pt->CoppCP.cmd.flashfw.total_packets *
18031da177e4SLinus Torvalds 			    pt->CoppCP.cmd.flashfw.count;
18041da177e4SLinus Torvalds 			ha->flash_data = pci_alloc_consistent(ha->pcidev,
18051da177e4SLinus Torvalds 					                      datasize,
18061da177e4SLinus Torvalds 							      &ha->flash_busaddr);
18071da177e4SLinus Torvalds 			if (!ha->flash_data){
18081da177e4SLinus Torvalds 				printk(KERN_WARNING "Unable to allocate a flash buffer\n");
18091da177e4SLinus Torvalds 				return IPS_FAILURE;
18101da177e4SLinus Torvalds 			}
18111da177e4SLinus Torvalds 			ha->flash_datasize = 0;
18121da177e4SLinus Torvalds 			ha->flash_len = datasize;
18131da177e4SLinus Torvalds 		} else
18141da177e4SLinus Torvalds 			return IPS_FAILURE;
18151da177e4SLinus Torvalds 	} else {
18161da177e4SLinus Torvalds 		if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
18171da177e4SLinus Torvalds 		    ha->flash_len) {
18181da177e4SLinus Torvalds 			ips_free_flash_copperhead(ha);
18191da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
18201da177e4SLinus Torvalds 				   "failed size sanity check\n");
18211da177e4SLinus Torvalds 			return IPS_FAILURE;
18221da177e4SLinus Torvalds 		}
18231da177e4SLinus Torvalds 	}
18241da177e4SLinus Torvalds 	if (!ha->flash_data)
18251da177e4SLinus Torvalds 		return IPS_FAILURE;
18261da177e4SLinus Torvalds 	pt->BasicStatus = 0;
18271da177e4SLinus Torvalds 	memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
18281da177e4SLinus Torvalds 	       pt->CoppCP.cmd.flashfw.count);
18291da177e4SLinus Torvalds 	ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
18301da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.packet_num ==
18311da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.total_packets - 1) {
18321da177e4SLinus Torvalds 		if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
18331da177e4SLinus Torvalds 			return ips_flash_bios(ha, pt, scb);
18341da177e4SLinus Torvalds 		else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
18351da177e4SLinus Torvalds 			return ips_flash_firmware(ha, pt, scb);
18361da177e4SLinus Torvalds 	}
18371da177e4SLinus Torvalds 	return IPS_SUCCESS_IMM;
18381da177e4SLinus Torvalds }
18391da177e4SLinus Torvalds 
18401da177e4SLinus Torvalds /****************************************************************************/
18411da177e4SLinus Torvalds /* Routine Name: ips_flash_bios                                             */
18421da177e4SLinus Torvalds /* Routine Description:                                                     */
18431da177e4SLinus Torvalds /*   flashes the bios of a copperhead adapter                               */
18441da177e4SLinus Torvalds /****************************************************************************/
18451da177e4SLinus Torvalds static int
18461da177e4SLinus Torvalds ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
18471da177e4SLinus Torvalds {
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
18501da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) {
18511da177e4SLinus Torvalds 		if ((!ha->func.programbios) || (!ha->func.erasebios) ||
18521da177e4SLinus Torvalds 		    (!ha->func.verifybios))
18531da177e4SLinus Torvalds 			goto error;
18541da177e4SLinus Torvalds 		if ((*ha->func.erasebios) (ha)) {
18551da177e4SLinus Torvalds 			DEBUG_VAR(1,
18561da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to erase flash",
18571da177e4SLinus Torvalds 				  ips_name, ha->host_num);
18581da177e4SLinus Torvalds 			goto error;
18591da177e4SLinus Torvalds 		} else
18601da177e4SLinus Torvalds 		    if ((*ha->func.programbios) (ha,
18611da177e4SLinus Torvalds 						 ha->flash_data +
18621da177e4SLinus Torvalds 						 IPS_BIOS_HEADER,
18631da177e4SLinus Torvalds 						 ha->flash_datasize -
18641da177e4SLinus Torvalds 						 IPS_BIOS_HEADER, 0)) {
18651da177e4SLinus Torvalds 			DEBUG_VAR(1,
18661da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to flash",
18671da177e4SLinus Torvalds 				  ips_name, ha->host_num);
18681da177e4SLinus Torvalds 			goto error;
18691da177e4SLinus Torvalds 		} else
18701da177e4SLinus Torvalds 		    if ((*ha->func.verifybios) (ha,
18711da177e4SLinus Torvalds 						ha->flash_data +
18721da177e4SLinus Torvalds 						IPS_BIOS_HEADER,
18731da177e4SLinus Torvalds 						ha->flash_datasize -
18741da177e4SLinus Torvalds 						IPS_BIOS_HEADER, 0)) {
18751da177e4SLinus Torvalds 			DEBUG_VAR(1,
18761da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to verify flash",
18771da177e4SLinus Torvalds 				  ips_name, ha->host_num);
18781da177e4SLinus Torvalds 			goto error;
18791da177e4SLinus Torvalds 		}
18801da177e4SLinus Torvalds 		ips_free_flash_copperhead(ha);
18811da177e4SLinus Torvalds 		return IPS_SUCCESS_IMM;
18821da177e4SLinus Torvalds 	} else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
18831da177e4SLinus Torvalds 		   pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
18841da177e4SLinus Torvalds 		if (!ha->func.erasebios)
18851da177e4SLinus Torvalds 			goto error;
18861da177e4SLinus Torvalds 		if ((*ha->func.erasebios) (ha)) {
18871da177e4SLinus Torvalds 			DEBUG_VAR(1,
18881da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to erase flash",
18891da177e4SLinus Torvalds 				  ips_name, ha->host_num);
18901da177e4SLinus Torvalds 			goto error;
18911da177e4SLinus Torvalds 		}
18921da177e4SLinus Torvalds 		return IPS_SUCCESS_IMM;
18931da177e4SLinus Torvalds 	}
18941da177e4SLinus Torvalds       error:
18951da177e4SLinus Torvalds 	pt->BasicStatus = 0x0B;
18961da177e4SLinus Torvalds 	pt->ExtendedStatus = 0x00;
18971da177e4SLinus Torvalds 	ips_free_flash_copperhead(ha);
18981da177e4SLinus Torvalds 	return IPS_FAILURE;
18991da177e4SLinus Torvalds }
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds /****************************************************************************/
19021da177e4SLinus Torvalds /*                                                                          */
19031da177e4SLinus Torvalds /* Routine Name: ips_fill_scb_sg_single                                     */
19041da177e4SLinus Torvalds /*                                                                          */
19051da177e4SLinus Torvalds /* Routine Description:                                                     */
19061da177e4SLinus Torvalds /*   Fill in a single scb sg_list element from an address                   */
19071da177e4SLinus Torvalds /*   return a -1 if a breakup occurred                                      */
19081da177e4SLinus Torvalds /****************************************************************************/
19091da177e4SLinus Torvalds static int
19101da177e4SLinus Torvalds ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
19111da177e4SLinus Torvalds 		       ips_scb_t * scb, int indx, unsigned int e_len)
19121da177e4SLinus Torvalds {
19131da177e4SLinus Torvalds 
19141da177e4SLinus Torvalds 	int ret_val = 0;
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds 	if ((scb->data_len + e_len) > ha->max_xfer) {
19171da177e4SLinus Torvalds 		e_len = ha->max_xfer - scb->data_len;
19181da177e4SLinus Torvalds 		scb->breakup = indx;
19191da177e4SLinus Torvalds 		++scb->sg_break;
19201da177e4SLinus Torvalds 		ret_val = -1;
19211da177e4SLinus Torvalds 	} else {
19221da177e4SLinus Torvalds 		scb->breakup = 0;
19231da177e4SLinus Torvalds 		scb->sg_break = 0;
19241da177e4SLinus Torvalds 	}
19251da177e4SLinus Torvalds 	if (IPS_USE_ENH_SGLIST(ha)) {
19261da177e4SLinus Torvalds 		scb->sg_list.enh_list[indx].address_lo =
19271da177e4SLinus Torvalds 		    cpu_to_le32(pci_dma_lo32(busaddr));
19281da177e4SLinus Torvalds 		scb->sg_list.enh_list[indx].address_hi =
19291da177e4SLinus Torvalds 		    cpu_to_le32(pci_dma_hi32(busaddr));
19301da177e4SLinus Torvalds 		scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len);
19311da177e4SLinus Torvalds 	} else {
19321da177e4SLinus Torvalds 		scb->sg_list.std_list[indx].address =
19331da177e4SLinus Torvalds 		    cpu_to_le32(pci_dma_lo32(busaddr));
19341da177e4SLinus Torvalds 		scb->sg_list.std_list[indx].length = cpu_to_le32(e_len);
19351da177e4SLinus Torvalds 	}
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds 	++scb->sg_len;
19381da177e4SLinus Torvalds 	scb->data_len += e_len;
19391da177e4SLinus Torvalds 	return ret_val;
19401da177e4SLinus Torvalds }
19411da177e4SLinus Torvalds 
19421da177e4SLinus Torvalds /****************************************************************************/
19431da177e4SLinus Torvalds /* Routine Name: ips_flash_firmware                                         */
19441da177e4SLinus Torvalds /* Routine Description:                                                     */
19451da177e4SLinus Torvalds /*   flashes the firmware of a copperhead adapter                           */
19461da177e4SLinus Torvalds /****************************************************************************/
19471da177e4SLinus Torvalds static int
19481da177e4SLinus Torvalds ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
19491da177e4SLinus Torvalds {
19501da177e4SLinus Torvalds 	IPS_SG_LIST sg_list;
19511da177e4SLinus Torvalds 	uint32_t cmd_busaddr;
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
19541da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) {
19551da177e4SLinus Torvalds 		memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND));
19561da177e4SLinus Torvalds 		pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
19571da177e4SLinus Torvalds 		pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
19581da177e4SLinus Torvalds 	} else {
19591da177e4SLinus Torvalds 		pt->BasicStatus = 0x0B;
19601da177e4SLinus Torvalds 		pt->ExtendedStatus = 0x00;
19611da177e4SLinus Torvalds 		ips_free_flash_copperhead(ha);
19621da177e4SLinus Torvalds 		return IPS_FAILURE;
19631da177e4SLinus Torvalds 	}
19641da177e4SLinus Torvalds 	/* Save the S/G list pointer so it doesn't get clobbered */
19651da177e4SLinus Torvalds 	sg_list.list = scb->sg_list.list;
19661da177e4SLinus Torvalds 	cmd_busaddr = scb->scb_busaddr;
19671da177e4SLinus Torvalds 	/* copy in the CP */
19681da177e4SLinus Torvalds 	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
19691da177e4SLinus Torvalds 	/* FIX stuff that might be wrong */
19701da177e4SLinus Torvalds 	scb->sg_list.list = sg_list.list;
19711da177e4SLinus Torvalds 	scb->scb_busaddr = cmd_busaddr;
19721da177e4SLinus Torvalds 	scb->bus = scb->scsi_cmd->device->channel;
19731da177e4SLinus Torvalds 	scb->target_id = scb->scsi_cmd->device->id;
19741da177e4SLinus Torvalds 	scb->lun = scb->scsi_cmd->device->lun;
19751da177e4SLinus Torvalds 	scb->sg_len = 0;
19761da177e4SLinus Torvalds 	scb->data_len = 0;
19771da177e4SLinus Torvalds 	scb->flags = 0;
19781da177e4SLinus Torvalds 	scb->op_code = 0;
19791da177e4SLinus Torvalds 	scb->callback = ipsintr_done;
19801da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
19811da177e4SLinus Torvalds 
19821da177e4SLinus Torvalds 	scb->data_len = ha->flash_datasize;
19831da177e4SLinus Torvalds 	scb->data_busaddr =
19841da177e4SLinus Torvalds 	    pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
19851da177e4SLinus Torvalds 			   IPS_DMA_DIR(scb));
19861da177e4SLinus Torvalds 	scb->flags |= IPS_SCB_MAP_SINGLE;
19871da177e4SLinus Torvalds 	scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
19881da177e4SLinus Torvalds 	scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr);
19891da177e4SLinus Torvalds 	if (pt->TimeOut)
19901da177e4SLinus Torvalds 		scb->timeout = pt->TimeOut;
19911da177e4SLinus Torvalds 	scb->scsi_cmd->result = DID_OK << 16;
19921da177e4SLinus Torvalds 	return IPS_SUCCESS;
19931da177e4SLinus Torvalds }
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds /****************************************************************************/
19961da177e4SLinus Torvalds /* Routine Name: ips_free_flash_copperhead                                  */
19971da177e4SLinus Torvalds /* Routine Description:                                                     */
19981da177e4SLinus Torvalds /*   release the memory resources used to hold the flash image              */
19991da177e4SLinus Torvalds /****************************************************************************/
20001da177e4SLinus Torvalds static void
20011da177e4SLinus Torvalds ips_free_flash_copperhead(ips_ha_t * ha)
20021da177e4SLinus Torvalds {
20031da177e4SLinus Torvalds 	if (ha->flash_data == ips_FlashData)
20041da177e4SLinus Torvalds 		test_and_clear_bit(0, &ips_FlashDataInUse);
20051da177e4SLinus Torvalds 	else if (ha->flash_data)
20061da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data,
20071da177e4SLinus Torvalds 				    ha->flash_busaddr);
20081da177e4SLinus Torvalds 	ha->flash_data = NULL;
20091da177e4SLinus Torvalds }
20101da177e4SLinus Torvalds 
20111da177e4SLinus Torvalds /****************************************************************************/
20121da177e4SLinus Torvalds /*                                                                          */
20131da177e4SLinus Torvalds /* Routine Name: ips_usrcmd                                                 */
20141da177e4SLinus Torvalds /*                                                                          */
20151da177e4SLinus Torvalds /* Routine Description:                                                     */
20161da177e4SLinus Torvalds /*                                                                          */
20171da177e4SLinus Torvalds /*   Process a user command and make it ready to send                       */
20181da177e4SLinus Torvalds /*                                                                          */
20191da177e4SLinus Torvalds /****************************************************************************/
20201da177e4SLinus Torvalds static int
20211da177e4SLinus Torvalds ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
20221da177e4SLinus Torvalds {
20231da177e4SLinus Torvalds 	IPS_SG_LIST sg_list;
20241da177e4SLinus Torvalds 	uint32_t cmd_busaddr;
20251da177e4SLinus Torvalds 
20261da177e4SLinus Torvalds 	METHOD_TRACE("ips_usrcmd", 1);
20271da177e4SLinus Torvalds 
20281da177e4SLinus Torvalds 	if ((!scb) || (!pt) || (!ha))
20291da177e4SLinus Torvalds 		return (0);
20301da177e4SLinus Torvalds 
20311da177e4SLinus Torvalds 	/* Save the S/G list pointer so it doesn't get clobbered */
20321da177e4SLinus Torvalds 	sg_list.list = scb->sg_list.list;
20331da177e4SLinus Torvalds 	cmd_busaddr = scb->scb_busaddr;
20341da177e4SLinus Torvalds 	/* copy in the CP */
20351da177e4SLinus Torvalds 	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
20361da177e4SLinus Torvalds 	memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE));
20371da177e4SLinus Torvalds 
20381da177e4SLinus Torvalds 	/* FIX stuff that might be wrong */
20391da177e4SLinus Torvalds 	scb->sg_list.list = sg_list.list;
20401da177e4SLinus Torvalds 	scb->scb_busaddr = cmd_busaddr;
20411da177e4SLinus Torvalds 	scb->bus = scb->scsi_cmd->device->channel;
20421da177e4SLinus Torvalds 	scb->target_id = scb->scsi_cmd->device->id;
20431da177e4SLinus Torvalds 	scb->lun = scb->scsi_cmd->device->lun;
20441da177e4SLinus Torvalds 	scb->sg_len = 0;
20451da177e4SLinus Torvalds 	scb->data_len = 0;
20461da177e4SLinus Torvalds 	scb->flags = 0;
20471da177e4SLinus Torvalds 	scb->op_code = 0;
20481da177e4SLinus Torvalds 	scb->callback = ipsintr_done;
20491da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
20501da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds 	/* we don't support DCDB/READ/WRITE Scatter Gather */
20531da177e4SLinus Torvalds 	if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
20541da177e4SLinus Torvalds 	    (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
20551da177e4SLinus Torvalds 	    (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
20561da177e4SLinus Torvalds 		return (0);
20571da177e4SLinus Torvalds 
20581da177e4SLinus Torvalds 	if (pt->CmdBSize) {
20591da177e4SLinus Torvalds 		scb->data_len = pt->CmdBSize;
20601da177e4SLinus Torvalds 		scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t);
20611da177e4SLinus Torvalds 	} else {
20621da177e4SLinus Torvalds 		scb->data_busaddr = 0L;
20631da177e4SLinus Torvalds 	}
20641da177e4SLinus Torvalds 
20651da177e4SLinus Torvalds 	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
20661da177e4SLinus Torvalds 		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
20671da177e4SLinus Torvalds 							 (unsigned long) &scb->
20681da177e4SLinus Torvalds 							 dcdb -
20691da177e4SLinus Torvalds 							 (unsigned long) scb);
20701da177e4SLinus Torvalds 
20711da177e4SLinus Torvalds 	if (pt->CmdBSize) {
20721da177e4SLinus Torvalds 		if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
20731da177e4SLinus Torvalds 			scb->dcdb.buffer_pointer =
20741da177e4SLinus Torvalds 			    cpu_to_le32(scb->data_busaddr);
20751da177e4SLinus Torvalds 		else
20761da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_addr =
20771da177e4SLinus Torvalds 			    cpu_to_le32(scb->data_busaddr);
20781da177e4SLinus Torvalds 	}
20791da177e4SLinus Torvalds 
20801da177e4SLinus Torvalds 	/* set timeouts */
20811da177e4SLinus Torvalds 	if (pt->TimeOut) {
20821da177e4SLinus Torvalds 		scb->timeout = pt->TimeOut;
20831da177e4SLinus Torvalds 
20841da177e4SLinus Torvalds 		if (pt->TimeOut <= 10)
20851da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
20861da177e4SLinus Torvalds 		else if (pt->TimeOut <= 60)
20871da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
20881da177e4SLinus Torvalds 		else
20891da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
20901da177e4SLinus Torvalds 	}
20911da177e4SLinus Torvalds 
20921da177e4SLinus Torvalds 	/* assume success */
20931da177e4SLinus Torvalds 	scb->scsi_cmd->result = DID_OK << 16;
20941da177e4SLinus Torvalds 
20951da177e4SLinus Torvalds 	/* success */
20961da177e4SLinus Torvalds 	return (1);
20971da177e4SLinus Torvalds }
20981da177e4SLinus Torvalds 
20991da177e4SLinus Torvalds /****************************************************************************/
21001da177e4SLinus Torvalds /*                                                                          */
21011da177e4SLinus Torvalds /* Routine Name: ips_cleanup_passthru                                       */
21021da177e4SLinus Torvalds /*                                                                          */
21031da177e4SLinus Torvalds /* Routine Description:                                                     */
21041da177e4SLinus Torvalds /*                                                                          */
21051da177e4SLinus Torvalds /*   Cleanup after a passthru command                                       */
21061da177e4SLinus Torvalds /*                                                                          */
21071da177e4SLinus Torvalds /****************************************************************************/
21081da177e4SLinus Torvalds static void
21091da177e4SLinus Torvalds ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
21101da177e4SLinus Torvalds {
21111da177e4SLinus Torvalds 	ips_passthru_t *pt;
21121da177e4SLinus Torvalds 
21131da177e4SLinus Torvalds 	METHOD_TRACE("ips_cleanup_passthru", 1);
21141da177e4SLinus Torvalds 
21151da177e4SLinus Torvalds 	if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
21161da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
21171da177e4SLinus Torvalds 			  ips_name, ha->host_num);
21181da177e4SLinus Torvalds 
21191da177e4SLinus Torvalds 		return;
21201da177e4SLinus Torvalds 	}
21211da177e4SLinus Torvalds 	pt = (ips_passthru_t *) ha->ioctl_data;
21221da177e4SLinus Torvalds 
21231da177e4SLinus Torvalds 	/* Copy data back to the user */
21241da177e4SLinus Torvalds 	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)	/* Copy DCDB Back to Caller's Area */
21251da177e4SLinus Torvalds 		memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE));
21261da177e4SLinus Torvalds 
21271da177e4SLinus Torvalds 	pt->BasicStatus = scb->basic_status;
21281da177e4SLinus Torvalds 	pt->ExtendedStatus = scb->extended_status;
21291da177e4SLinus Torvalds 	pt->AdapterType = ha->ad_type;
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds 	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
21321da177e4SLinus Torvalds 	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
21331da177e4SLinus Torvalds 	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
21341da177e4SLinus Torvalds 		ips_free_flash_copperhead(ha);
21351da177e4SLinus Torvalds 
21361da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize);
21371da177e4SLinus Torvalds }
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds /****************************************************************************/
21401da177e4SLinus Torvalds /*                                                                          */
21411da177e4SLinus Torvalds /* Routine Name: ips_host_info                                              */
21421da177e4SLinus Torvalds /*                                                                          */
21431da177e4SLinus Torvalds /* Routine Description:                                                     */
21441da177e4SLinus Torvalds /*                                                                          */
21451da177e4SLinus Torvalds /*   The passthru interface for the driver                                  */
21461da177e4SLinus Torvalds /*                                                                          */
21471da177e4SLinus Torvalds /****************************************************************************/
21481da177e4SLinus Torvalds static int
21491da177e4SLinus Torvalds ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
21501da177e4SLinus Torvalds {
21511da177e4SLinus Torvalds 	IPS_INFOSTR info;
21521da177e4SLinus Torvalds 
21531da177e4SLinus Torvalds 	METHOD_TRACE("ips_host_info", 1);
21541da177e4SLinus Torvalds 
21551da177e4SLinus Torvalds 	info.buffer = ptr;
21561da177e4SLinus Torvalds 	info.length = len;
21571da177e4SLinus Torvalds 	info.offset = offset;
21581da177e4SLinus Torvalds 	info.pos = 0;
21591da177e4SLinus Torvalds 	info.localpos = 0;
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
21621da177e4SLinus Torvalds 
21631da177e4SLinus Torvalds 	if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
21641da177e4SLinus Torvalds 	    (le16_to_cpu(ha->nvram->adapter_type) != 0))
21651da177e4SLinus Torvalds 		copy_info(&info, "\tController Type                   : %s\n",
21661da177e4SLinus Torvalds 			  ips_adapter_name[ha->ad_type - 1]);
21671da177e4SLinus Torvalds 	else
21681da177e4SLinus Torvalds 		copy_info(&info,
21691da177e4SLinus Torvalds 			  "\tController Type                   : Unknown\n");
21701da177e4SLinus Torvalds 
21711da177e4SLinus Torvalds 	if (ha->io_addr)
21721da177e4SLinus Torvalds 		copy_info(&info,
21731da177e4SLinus Torvalds 			  "\tIO region                         : 0x%lx (%d bytes)\n",
21741da177e4SLinus Torvalds 			  ha->io_addr, ha->io_len);
21751da177e4SLinus Torvalds 
21761da177e4SLinus Torvalds 	if (ha->mem_addr) {
21771da177e4SLinus Torvalds 		copy_info(&info,
21781da177e4SLinus Torvalds 			  "\tMemory region                     : 0x%lx (%d bytes)\n",
21791da177e4SLinus Torvalds 			  ha->mem_addr, ha->mem_len);
21801da177e4SLinus Torvalds 		copy_info(&info,
21811da177e4SLinus Torvalds 			  "\tShared memory address             : 0x%lx\n",
21821da177e4SLinus Torvalds 			  ha->mem_ptr);
21831da177e4SLinus Torvalds 	}
21841da177e4SLinus Torvalds 
21851da177e4SLinus Torvalds 	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
21861da177e4SLinus Torvalds 
21871da177e4SLinus Torvalds     /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
21881da177e4SLinus Torvalds     /* That keeps everything happy for "text" operations on the proc file.                    */
21891da177e4SLinus Torvalds 
21901da177e4SLinus Torvalds 	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
21911da177e4SLinus Torvalds         if (ha->nvram->bios_low[3] == 0) {
21921da177e4SLinus Torvalds             copy_info(&info,
21931da177e4SLinus Torvalds 			          "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
21941da177e4SLinus Torvalds 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
21951da177e4SLinus Torvalds 			          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
21961da177e4SLinus Torvalds 			          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
21971da177e4SLinus Torvalds 			          ha->nvram->bios_low[2]);
21981da177e4SLinus Torvalds 
21991da177e4SLinus Torvalds         } else {
22001da177e4SLinus Torvalds 		    copy_info(&info,
22011da177e4SLinus Torvalds 			          "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n",
22021da177e4SLinus Torvalds 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
22031da177e4SLinus Torvalds 			          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
22041da177e4SLinus Torvalds 			          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
22051da177e4SLinus Torvalds 			          ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
22061da177e4SLinus Torvalds         }
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds     }
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds     if (ha->enq->CodeBlkVersion[7] == 0) {
22111da177e4SLinus Torvalds         copy_info(&info,
22121da177e4SLinus Torvalds 		          "\tFirmware Version                  : %c%c%c%c%c%c%c\n",
22131da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
22141da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
22151da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
22161da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[6]);
22171da177e4SLinus Torvalds     } else {
22181da177e4SLinus Torvalds         copy_info(&info,
22191da177e4SLinus Torvalds 		          "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n",
22201da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
22211da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
22221da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
22231da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
22241da177e4SLinus Torvalds     }
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds     if (ha->enq->BootBlkVersion[7] == 0) {
22271da177e4SLinus Torvalds         copy_info(&info,
22281da177e4SLinus Torvalds 		          "\tBoot Block Version                : %c%c%c%c%c%c%c\n",
22291da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
22301da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
22311da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
22321da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[6]);
22331da177e4SLinus Torvalds     } else {
22341da177e4SLinus Torvalds         copy_info(&info,
22351da177e4SLinus Torvalds 		          "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n",
22361da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
22371da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
22381da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
22391da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
22401da177e4SLinus Torvalds     }
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds 	copy_info(&info, "\tDriver Version                    : %s%s\n",
22431da177e4SLinus Torvalds 		  IPS_VERSION_HIGH, IPS_VERSION_LOW);
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 	copy_info(&info, "\tDriver Build                      : %d\n",
22461da177e4SLinus Torvalds 		  IPS_BUILD_IDENT);
22471da177e4SLinus Torvalds 
22481da177e4SLinus Torvalds 	copy_info(&info, "\tMax Physical Devices              : %d\n",
22491da177e4SLinus Torvalds 		  ha->enq->ucMaxPhysicalDevices);
22501da177e4SLinus Torvalds 	copy_info(&info, "\tMax Active Commands               : %d\n",
22511da177e4SLinus Torvalds 		  ha->max_cmds);
22521da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Queued Commands           : %d\n",
22531da177e4SLinus Torvalds 		  ha->scb_waitlist.count);
22541da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Active Commands           : %d\n",
22551da177e4SLinus Torvalds 		  ha->scb_activelist.count - ha->num_ioctl);
22561da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Queued PT Commands        : %d\n",
22571da177e4SLinus Torvalds 		  ha->copp_waitlist.count);
22581da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Active PT Commands        : %d\n",
22591da177e4SLinus Torvalds 		  ha->num_ioctl);
22601da177e4SLinus Torvalds 
22611da177e4SLinus Torvalds 	copy_info(&info, "\n");
22621da177e4SLinus Torvalds 
22631da177e4SLinus Torvalds 	return (info.localpos);
22641da177e4SLinus Torvalds }
22651da177e4SLinus Torvalds 
22661da177e4SLinus Torvalds /****************************************************************************/
22671da177e4SLinus Torvalds /*                                                                          */
22681da177e4SLinus Torvalds /* Routine Name: copy_mem_info                                              */
22691da177e4SLinus Torvalds /*                                                                          */
22701da177e4SLinus Torvalds /* Routine Description:                                                     */
22711da177e4SLinus Torvalds /*                                                                          */
22721da177e4SLinus Torvalds /*   Copy data into an IPS_INFOSTR structure                                */
22731da177e4SLinus Torvalds /*                                                                          */
22741da177e4SLinus Torvalds /****************************************************************************/
22751da177e4SLinus Torvalds static void
22761da177e4SLinus Torvalds copy_mem_info(IPS_INFOSTR * info, char *data, int len)
22771da177e4SLinus Torvalds {
22781da177e4SLinus Torvalds 	METHOD_TRACE("copy_mem_info", 1);
22791da177e4SLinus Torvalds 
22801da177e4SLinus Torvalds 	if (info->pos + len < info->offset) {
22811da177e4SLinus Torvalds 		info->pos += len;
22821da177e4SLinus Torvalds 		return;
22831da177e4SLinus Torvalds 	}
22841da177e4SLinus Torvalds 
22851da177e4SLinus Torvalds 	if (info->pos < info->offset) {
22861da177e4SLinus Torvalds 		data += (info->offset - info->pos);
22871da177e4SLinus Torvalds 		len -= (info->offset - info->pos);
22881da177e4SLinus Torvalds 		info->pos += (info->offset - info->pos);
22891da177e4SLinus Torvalds 	}
22901da177e4SLinus Torvalds 
22911da177e4SLinus Torvalds 	if (info->localpos + len > info->length)
22921da177e4SLinus Torvalds 		len = info->length - info->localpos;
22931da177e4SLinus Torvalds 
22941da177e4SLinus Torvalds 	if (len > 0) {
22951da177e4SLinus Torvalds 		memcpy(info->buffer + info->localpos, data, len);
22961da177e4SLinus Torvalds 		info->pos += len;
22971da177e4SLinus Torvalds 		info->localpos += len;
22981da177e4SLinus Torvalds 	}
22991da177e4SLinus Torvalds }
23001da177e4SLinus Torvalds 
23011da177e4SLinus Torvalds /****************************************************************************/
23021da177e4SLinus Torvalds /*                                                                          */
23031da177e4SLinus Torvalds /* Routine Name: copy_info                                                  */
23041da177e4SLinus Torvalds /*                                                                          */
23051da177e4SLinus Torvalds /* Routine Description:                                                     */
23061da177e4SLinus Torvalds /*                                                                          */
23071da177e4SLinus Torvalds /*   printf style wrapper for an info structure                             */
23081da177e4SLinus Torvalds /*                                                                          */
23091da177e4SLinus Torvalds /****************************************************************************/
23101da177e4SLinus Torvalds static int
23111da177e4SLinus Torvalds copy_info(IPS_INFOSTR * info, char *fmt, ...)
23121da177e4SLinus Torvalds {
23131da177e4SLinus Torvalds 	va_list args;
23141da177e4SLinus Torvalds 	char buf[128];
23151da177e4SLinus Torvalds 	int len;
23161da177e4SLinus Torvalds 
23171da177e4SLinus Torvalds 	METHOD_TRACE("copy_info", 1);
23181da177e4SLinus Torvalds 
23191da177e4SLinus Torvalds 	va_start(args, fmt);
23201da177e4SLinus Torvalds 	len = vsprintf(buf, fmt, args);
23211da177e4SLinus Torvalds 	va_end(args);
23221da177e4SLinus Torvalds 
23231da177e4SLinus Torvalds 	copy_mem_info(info, buf, len);
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds 	return (len);
23261da177e4SLinus Torvalds }
23271da177e4SLinus Torvalds 
23281da177e4SLinus Torvalds /****************************************************************************/
23291da177e4SLinus Torvalds /*                                                                          */
23301da177e4SLinus Torvalds /* Routine Name: ips_identify_controller                                    */
23311da177e4SLinus Torvalds /*                                                                          */
23321da177e4SLinus Torvalds /* Routine Description:                                                     */
23331da177e4SLinus Torvalds /*                                                                          */
23341da177e4SLinus Torvalds /*   Identify this controller                                               */
23351da177e4SLinus Torvalds /*                                                                          */
23361da177e4SLinus Torvalds /****************************************************************************/
23371da177e4SLinus Torvalds static void
23381da177e4SLinus Torvalds ips_identify_controller(ips_ha_t * ha)
23391da177e4SLinus Torvalds {
23401da177e4SLinus Torvalds 	METHOD_TRACE("ips_identify_controller", 1);
23411da177e4SLinus Torvalds 
23421da177e4SLinus Torvalds 	switch (ha->device_id) {
23431da177e4SLinus Torvalds 	case IPS_DEVICEID_COPPERHEAD:
23441da177e4SLinus Torvalds 		if (ha->revision_id <= IPS_REVID_SERVERAID) {
23451da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID;
23461da177e4SLinus Torvalds 		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
23471da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID2;
23481da177e4SLinus Torvalds 		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
23491da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_NAVAJO;
23501da177e4SLinus Torvalds 		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
23511da177e4SLinus Torvalds 			   && (ha->slot_num == 0)) {
23521da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_KIOWA;
23531da177e4SLinus Torvalds 		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
23541da177e4SLinus Torvalds 			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
23551da177e4SLinus Torvalds 			if (ha->enq->ucMaxPhysicalDevices == 15)
23561da177e4SLinus Torvalds 				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
23571da177e4SLinus Torvalds 			else
23581da177e4SLinus Torvalds 				ha->ad_type = IPS_ADTYPE_SERVERAID3;
23591da177e4SLinus Torvalds 		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
23601da177e4SLinus Torvalds 			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
23611da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
23621da177e4SLinus Torvalds 		}
23631da177e4SLinus Torvalds 		break;
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds 	case IPS_DEVICEID_MORPHEUS:
23661da177e4SLinus Torvalds 		switch (ha->subdevice_id) {
23671da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4L:
23681da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
23691da177e4SLinus Torvalds 			break;
23701da177e4SLinus Torvalds 
23711da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4M:
23721da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4M;
23731da177e4SLinus Torvalds 			break;
23741da177e4SLinus Torvalds 
23751da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4MX:
23761da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
23771da177e4SLinus Torvalds 			break;
23781da177e4SLinus Torvalds 
23791da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4LX:
23801da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
23811da177e4SLinus Torvalds 			break;
23821da177e4SLinus Torvalds 
23831da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_5I2:
23841da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
23851da177e4SLinus Torvalds 			break;
23861da177e4SLinus Torvalds 
23871da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_5I1:
23881da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
23891da177e4SLinus Torvalds 			break;
23901da177e4SLinus Torvalds 		}
23911da177e4SLinus Torvalds 
23921da177e4SLinus Torvalds 		break;
23931da177e4SLinus Torvalds 
23941da177e4SLinus Torvalds 	case IPS_DEVICEID_MARCO:
23951da177e4SLinus Torvalds 		switch (ha->subdevice_id) {
23961da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_6M:
23971da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
23981da177e4SLinus Torvalds 			break;
23991da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_6I:
24001da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID6I;
24011da177e4SLinus Torvalds 			break;
24021da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_7k:
24031da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID7k;
24041da177e4SLinus Torvalds 			break;
24051da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_7M:
24061da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID7M;
24071da177e4SLinus Torvalds 			break;
24081da177e4SLinus Torvalds 		}
24091da177e4SLinus Torvalds 		break;
24101da177e4SLinus Torvalds 	}
24111da177e4SLinus Torvalds }
24121da177e4SLinus Torvalds 
24131da177e4SLinus Torvalds /****************************************************************************/
24141da177e4SLinus Torvalds /*                                                                          */
24151da177e4SLinus Torvalds /* Routine Name: ips_get_bios_version                                       */
24161da177e4SLinus Torvalds /*                                                                          */
24171da177e4SLinus Torvalds /* Routine Description:                                                     */
24181da177e4SLinus Torvalds /*                                                                          */
24191da177e4SLinus Torvalds /*   Get the BIOS revision number                                           */
24201da177e4SLinus Torvalds /*                                                                          */
24211da177e4SLinus Torvalds /****************************************************************************/
24221da177e4SLinus Torvalds static void
24231da177e4SLinus Torvalds ips_get_bios_version(ips_ha_t * ha, int intr)
24241da177e4SLinus Torvalds {
24251da177e4SLinus Torvalds 	ips_scb_t *scb;
24261da177e4SLinus Torvalds 	int ret;
24271da177e4SLinus Torvalds 	uint8_t major;
24281da177e4SLinus Torvalds 	uint8_t minor;
24291da177e4SLinus Torvalds 	uint8_t subminor;
24301da177e4SLinus Torvalds 	uint8_t *buffer;
24311da177e4SLinus Torvalds 	char hexDigits[] =
24321da177e4SLinus Torvalds 	    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
24331da177e4SLinus Torvalds      'D', 'E', 'F' };
24341da177e4SLinus Torvalds 
24351da177e4SLinus Torvalds 	METHOD_TRACE("ips_get_bios_version", 1);
24361da177e4SLinus Torvalds 
24371da177e4SLinus Torvalds 	major = 0;
24381da177e4SLinus Torvalds 	minor = 0;
24391da177e4SLinus Torvalds 
24401da177e4SLinus Torvalds 	strncpy(ha->bios_version, "       ?", 8);
24411da177e4SLinus Torvalds 
24421da177e4SLinus Torvalds 	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
24431da177e4SLinus Torvalds 		if (IPS_USE_MEMIO(ha)) {
24441da177e4SLinus Torvalds 			/* Memory Mapped I/O */
24451da177e4SLinus Torvalds 
24461da177e4SLinus Torvalds 			/* test 1st byte */
24471da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
24481da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24491da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24501da177e4SLinus Torvalds 
24511da177e4SLinus Torvalds 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
24521da177e4SLinus Torvalds 				return;
24531da177e4SLinus Torvalds 
24541da177e4SLinus Torvalds 			writel(1, ha->mem_ptr + IPS_REG_FLAP);
24551da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24561da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24571da177e4SLinus Torvalds 
24581da177e4SLinus Torvalds 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
24591da177e4SLinus Torvalds 				return;
24601da177e4SLinus Torvalds 
24611da177e4SLinus Torvalds 			/* Get Major version */
24621da177e4SLinus Torvalds 			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
24631da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24641da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24651da177e4SLinus Torvalds 
24661da177e4SLinus Torvalds 			major = readb(ha->mem_ptr + IPS_REG_FLDP);
24671da177e4SLinus Torvalds 
24681da177e4SLinus Torvalds 			/* Get Minor version */
24691da177e4SLinus Torvalds 			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
24701da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24711da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24721da177e4SLinus Torvalds 			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds 			/* Get SubMinor version */
24751da177e4SLinus Torvalds 			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
24761da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24771da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24781da177e4SLinus Torvalds 			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
24791da177e4SLinus Torvalds 
24801da177e4SLinus Torvalds 		} else {
24811da177e4SLinus Torvalds 			/* Programmed I/O */
24821da177e4SLinus Torvalds 
24831da177e4SLinus Torvalds 			/* test 1st byte */
24841da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
24851da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24861da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24871da177e4SLinus Torvalds 
24881da177e4SLinus Torvalds 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
24891da177e4SLinus Torvalds 				return;
24901da177e4SLinus Torvalds 
24911da177e4SLinus Torvalds 			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
24921da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
24931da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
24941da177e4SLinus Torvalds 
24951da177e4SLinus Torvalds 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
24961da177e4SLinus Torvalds 				return;
24971da177e4SLinus Torvalds 
24981da177e4SLinus Torvalds 			/* Get Major version */
24991da177e4SLinus Torvalds 			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
25001da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
25011da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
25021da177e4SLinus Torvalds 
25031da177e4SLinus Torvalds 			major = inb(ha->io_addr + IPS_REG_FLDP);
25041da177e4SLinus Torvalds 
25051da177e4SLinus Torvalds 			/* Get Minor version */
25061da177e4SLinus Torvalds 			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
25071da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
25081da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
25091da177e4SLinus Torvalds 
25101da177e4SLinus Torvalds 			minor = inb(ha->io_addr + IPS_REG_FLDP);
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds 			/* Get SubMinor version */
25131da177e4SLinus Torvalds 			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
25141da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
25151da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
25161da177e4SLinus Torvalds 
25171da177e4SLinus Torvalds 			subminor = inb(ha->io_addr + IPS_REG_FLDP);
25181da177e4SLinus Torvalds 
25191da177e4SLinus Torvalds 		}
25201da177e4SLinus Torvalds 	} else {
25211da177e4SLinus Torvalds 		/* Morpheus Family - Send Command to the card */
25221da177e4SLinus Torvalds 
25231da177e4SLinus Torvalds 		buffer = ha->ioctl_data;
25241da177e4SLinus Torvalds 
25251da177e4SLinus Torvalds 		memset(buffer, 0, 0x1000);
25261da177e4SLinus Torvalds 
25271da177e4SLinus Torvalds 		scb = &ha->scbs[ha->max_cmds - 1];
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds 		ips_init_scb(ha, scb);
25301da177e4SLinus Torvalds 
25311da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
25321da177e4SLinus Torvalds 		scb->cdb[0] = IPS_CMD_RW_BIOSFW;
25331da177e4SLinus Torvalds 
25341da177e4SLinus Torvalds 		scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
25351da177e4SLinus Torvalds 		scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
25361da177e4SLinus Torvalds 		scb->cmd.flashfw.type = 1;
25371da177e4SLinus Torvalds 		scb->cmd.flashfw.direction = 0;
25381da177e4SLinus Torvalds 		scb->cmd.flashfw.count = cpu_to_le32(0x800);
25391da177e4SLinus Torvalds 		scb->cmd.flashfw.total_packets = 1;
25401da177e4SLinus Torvalds 		scb->cmd.flashfw.packet_num = 0;
25411da177e4SLinus Torvalds 		scb->data_len = 0x1000;
25421da177e4SLinus Torvalds 		scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr;
25431da177e4SLinus Torvalds 
25441da177e4SLinus Torvalds 		/* issue the command */
25451da177e4SLinus Torvalds 		if (((ret =
25461da177e4SLinus Torvalds 		      ips_send_wait(ha, scb, ips_cmd_timeout,
25471da177e4SLinus Torvalds 				    intr)) == IPS_FAILURE)
25481da177e4SLinus Torvalds 		    || (ret == IPS_SUCCESS_IMM)
25491da177e4SLinus Torvalds 		    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
25501da177e4SLinus Torvalds 			/* Error occurred */
25511da177e4SLinus Torvalds 
25521da177e4SLinus Torvalds 			return;
25531da177e4SLinus Torvalds 		}
25541da177e4SLinus Torvalds 
25551da177e4SLinus Torvalds 		if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
25561da177e4SLinus Torvalds 			major = buffer[0x1ff + 0xC0];	/* Offset 0x1ff after the header (0xc0) */
25571da177e4SLinus Torvalds 			minor = buffer[0x1fe + 0xC0];	/* Offset 0x1fe after the header (0xc0) */
25581da177e4SLinus Torvalds 			subminor = buffer[0x1fd + 0xC0];	/* Offset 0x1fd after the header (0xc0) */
25591da177e4SLinus Torvalds 		} else {
25601da177e4SLinus Torvalds 			return;
25611da177e4SLinus Torvalds 		}
25621da177e4SLinus Torvalds 	}
25631da177e4SLinus Torvalds 
25641da177e4SLinus Torvalds 	ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
25651da177e4SLinus Torvalds 	ha->bios_version[1] = '.';
25661da177e4SLinus Torvalds 	ha->bios_version[2] = hexDigits[major & 0x0F];
25671da177e4SLinus Torvalds 	ha->bios_version[3] = hexDigits[subminor];
25681da177e4SLinus Torvalds 	ha->bios_version[4] = '.';
25691da177e4SLinus Torvalds 	ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
25701da177e4SLinus Torvalds 	ha->bios_version[6] = hexDigits[minor & 0x0F];
25711da177e4SLinus Torvalds 	ha->bios_version[7] = 0;
25721da177e4SLinus Torvalds }
25731da177e4SLinus Torvalds 
25741da177e4SLinus Torvalds /****************************************************************************/
25751da177e4SLinus Torvalds /*                                                                          */
25761da177e4SLinus Torvalds /* Routine Name: ips_hainit                                                 */
25771da177e4SLinus Torvalds /*                                                                          */
25781da177e4SLinus Torvalds /* Routine Description:                                                     */
25791da177e4SLinus Torvalds /*                                                                          */
25801da177e4SLinus Torvalds /*   Initialize the controller                                              */
25811da177e4SLinus Torvalds /*                                                                          */
25821da177e4SLinus Torvalds /* NOTE: Assumes to be called from with a lock                              */
25831da177e4SLinus Torvalds /*                                                                          */
25841da177e4SLinus Torvalds /****************************************************************************/
25851da177e4SLinus Torvalds static int
25861da177e4SLinus Torvalds ips_hainit(ips_ha_t * ha)
25871da177e4SLinus Torvalds {
25881da177e4SLinus Torvalds 	int i;
25891da177e4SLinus Torvalds 	struct timeval tv;
25901da177e4SLinus Torvalds 
25911da177e4SLinus Torvalds 	METHOD_TRACE("ips_hainit", 1);
25921da177e4SLinus Torvalds 
25931da177e4SLinus Torvalds 	if (!ha)
25941da177e4SLinus Torvalds 		return (0);
25951da177e4SLinus Torvalds 
25961da177e4SLinus Torvalds 	if (ha->func.statinit)
25971da177e4SLinus Torvalds 		(*ha->func.statinit) (ha);
25981da177e4SLinus Torvalds 
25991da177e4SLinus Torvalds 	if (ha->func.enableint)
26001da177e4SLinus Torvalds 		(*ha->func.enableint) (ha);
26011da177e4SLinus Torvalds 
26021da177e4SLinus Torvalds 	/* Send FFDC */
26031da177e4SLinus Torvalds 	ha->reset_count = 1;
26041da177e4SLinus Torvalds 	do_gettimeofday(&tv);
26051da177e4SLinus Torvalds 	ha->last_ffdc = tv.tv_sec;
26061da177e4SLinus Torvalds 	ips_ffdc_reset(ha, IPS_INTR_IORL);
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds 	if (!ips_read_config(ha, IPS_INTR_IORL)) {
26091da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
26101da177e4SLinus Torvalds 			   "unable to read config from controller.\n");
26111da177e4SLinus Torvalds 
26121da177e4SLinus Torvalds 		return (0);
26131da177e4SLinus Torvalds 	}
26141da177e4SLinus Torvalds 	/* end if */
26151da177e4SLinus Torvalds 	if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
26161da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
26171da177e4SLinus Torvalds 			   "unable to read controller status.\n");
26181da177e4SLinus Torvalds 
26191da177e4SLinus Torvalds 		return (0);
26201da177e4SLinus Torvalds 	}
26211da177e4SLinus Torvalds 
26221da177e4SLinus Torvalds 	/* Identify this controller */
26231da177e4SLinus Torvalds 	ips_identify_controller(ha);
26241da177e4SLinus Torvalds 
26251da177e4SLinus Torvalds 	if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
26261da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
26271da177e4SLinus Torvalds 			   "unable to read subsystem parameters.\n");
26281da177e4SLinus Torvalds 
26291da177e4SLinus Torvalds 		return (0);
26301da177e4SLinus Torvalds 	}
26311da177e4SLinus Torvalds 
26321da177e4SLinus Torvalds 	/* write nvram user page 5 */
26331da177e4SLinus Torvalds 	if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
26341da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
26351da177e4SLinus Torvalds 			   "unable to write driver info to controller.\n");
26361da177e4SLinus Torvalds 
26371da177e4SLinus Torvalds 		return (0);
26381da177e4SLinus Torvalds 	}
26391da177e4SLinus Torvalds 
26401da177e4SLinus Torvalds 	/* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
26411da177e4SLinus Torvalds 	if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1))
26421da177e4SLinus Torvalds 		ips_clear_adapter(ha, IPS_INTR_IORL);
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds 	/* set limits on SID, LUN, BUS */
26451da177e4SLinus Torvalds 	ha->ntargets = IPS_MAX_TARGETS + 1;
26461da177e4SLinus Torvalds 	ha->nlun = 1;
26471da177e4SLinus Torvalds 	ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
26481da177e4SLinus Torvalds 
26491da177e4SLinus Torvalds 	switch (ha->conf->logical_drive[0].ucStripeSize) {
26501da177e4SLinus Torvalds 	case 4:
26511da177e4SLinus Torvalds 		ha->max_xfer = 0x10000;
26521da177e4SLinus Torvalds 		break;
26531da177e4SLinus Torvalds 
26541da177e4SLinus Torvalds 	case 5:
26551da177e4SLinus Torvalds 		ha->max_xfer = 0x20000;
26561da177e4SLinus Torvalds 		break;
26571da177e4SLinus Torvalds 
26581da177e4SLinus Torvalds 	case 6:
26591da177e4SLinus Torvalds 		ha->max_xfer = 0x40000;
26601da177e4SLinus Torvalds 		break;
26611da177e4SLinus Torvalds 
26621da177e4SLinus Torvalds 	case 7:
26631da177e4SLinus Torvalds 	default:
26641da177e4SLinus Torvalds 		ha->max_xfer = 0x80000;
26651da177e4SLinus Torvalds 		break;
26661da177e4SLinus Torvalds 	}
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 	/* setup max concurrent commands */
26691da177e4SLinus Torvalds 	if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
26701da177e4SLinus Torvalds 		/* Use the new method */
26711da177e4SLinus Torvalds 		ha->max_cmds = ha->enq->ucConcurrentCmdCount;
26721da177e4SLinus Torvalds 	} else {
26731da177e4SLinus Torvalds 		/* use the old method */
26741da177e4SLinus Torvalds 		switch (ha->conf->logical_drive[0].ucStripeSize) {
26751da177e4SLinus Torvalds 		case 4:
26761da177e4SLinus Torvalds 			ha->max_cmds = 32;
26771da177e4SLinus Torvalds 			break;
26781da177e4SLinus Torvalds 
26791da177e4SLinus Torvalds 		case 5:
26801da177e4SLinus Torvalds 			ha->max_cmds = 16;
26811da177e4SLinus Torvalds 			break;
26821da177e4SLinus Torvalds 
26831da177e4SLinus Torvalds 		case 6:
26841da177e4SLinus Torvalds 			ha->max_cmds = 8;
26851da177e4SLinus Torvalds 			break;
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds 		case 7:
26881da177e4SLinus Torvalds 		default:
26891da177e4SLinus Torvalds 			ha->max_cmds = 4;
26901da177e4SLinus Torvalds 			break;
26911da177e4SLinus Torvalds 		}
26921da177e4SLinus Torvalds 	}
26931da177e4SLinus Torvalds 
26941da177e4SLinus Torvalds 	/* Limit the Active Commands on a Lite Adapter */
26951da177e4SLinus Torvalds 	if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
26961da177e4SLinus Torvalds 	    (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
26971da177e4SLinus Torvalds 	    (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
26981da177e4SLinus Torvalds 		if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds))
26991da177e4SLinus Torvalds 			ha->max_cmds = MaxLiteCmds;
27001da177e4SLinus Torvalds 	}
27011da177e4SLinus Torvalds 
27021da177e4SLinus Torvalds 	/* set controller IDs */
27031da177e4SLinus Torvalds 	ha->ha_id[0] = IPS_ADAPTER_ID;
27041da177e4SLinus Torvalds 	for (i = 1; i < ha->nbus; i++) {
27051da177e4SLinus Torvalds 		ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f;
27061da177e4SLinus Torvalds 		ha->dcdb_active[i - 1] = 0;
27071da177e4SLinus Torvalds 	}
27081da177e4SLinus Torvalds 
27091da177e4SLinus Torvalds 	return (1);
27101da177e4SLinus Torvalds }
27111da177e4SLinus Torvalds 
27121da177e4SLinus Torvalds /****************************************************************************/
27131da177e4SLinus Torvalds /*                                                                          */
27141da177e4SLinus Torvalds /* Routine Name: ips_next                                                   */
27151da177e4SLinus Torvalds /*                                                                          */
27161da177e4SLinus Torvalds /* Routine Description:                                                     */
27171da177e4SLinus Torvalds /*                                                                          */
27181da177e4SLinus Torvalds /*   Take the next command off the queue and send it to the controller      */
27191da177e4SLinus Torvalds /*                                                                          */
27201da177e4SLinus Torvalds /****************************************************************************/
27211da177e4SLinus Torvalds static void
27221da177e4SLinus Torvalds ips_next(ips_ha_t * ha, int intr)
27231da177e4SLinus Torvalds {
27241da177e4SLinus Torvalds 	ips_scb_t *scb;
27251da177e4SLinus Torvalds 	Scsi_Cmnd *SC;
27261da177e4SLinus Torvalds 	Scsi_Cmnd *p;
27271da177e4SLinus Torvalds 	Scsi_Cmnd *q;
27281da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
27291da177e4SLinus Torvalds 	int ret;
27301da177e4SLinus Torvalds 	unsigned long cpu_flags = 0;
27311da177e4SLinus Torvalds 	struct Scsi_Host *host;
27321da177e4SLinus Torvalds 	METHOD_TRACE("ips_next", 1);
27331da177e4SLinus Torvalds 
27341da177e4SLinus Torvalds 	if (!ha)
27351da177e4SLinus Torvalds 		return;
27361da177e4SLinus Torvalds 	host = ips_sh[ha->host_num];
27371da177e4SLinus Torvalds 	/*
27381da177e4SLinus Torvalds 	 * Block access to the queue function so
27391da177e4SLinus Torvalds 	 * this command won't time out
27401da177e4SLinus Torvalds 	 */
27411da177e4SLinus Torvalds 	if (intr == IPS_INTR_ON)
27421da177e4SLinus Torvalds 		IPS_LOCK_SAVE(host->host_lock, cpu_flags);
27431da177e4SLinus Torvalds 
27441da177e4SLinus Torvalds 	if ((ha->subsys->param[3] & 0x300000)
27451da177e4SLinus Torvalds 	    && (ha->scb_activelist.count == 0)) {
27461da177e4SLinus Torvalds 		struct timeval tv;
27471da177e4SLinus Torvalds 
27481da177e4SLinus Torvalds 		do_gettimeofday(&tv);
27491da177e4SLinus Torvalds 
27501da177e4SLinus Torvalds 		if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
27511da177e4SLinus Torvalds 			ha->last_ffdc = tv.tv_sec;
27521da177e4SLinus Torvalds 			ips_ffdc_time(ha);
27531da177e4SLinus Torvalds 		}
27541da177e4SLinus Torvalds 	}
27551da177e4SLinus Torvalds 
27561da177e4SLinus Torvalds 	/*
27571da177e4SLinus Torvalds 	 * Send passthru commands
27581da177e4SLinus Torvalds 	 * These have priority over normal I/O
27591da177e4SLinus Torvalds 	 * but shouldn't affect performance too much
27601da177e4SLinus Torvalds 	 * since we limit the number that can be active
27611da177e4SLinus Torvalds 	 * on the card at any one time
27621da177e4SLinus Torvalds 	 */
27631da177e4SLinus Torvalds 	while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
27641da177e4SLinus Torvalds 	       (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) {
27651da177e4SLinus Torvalds 
27661da177e4SLinus Torvalds 		item = ips_removeq_copp_head(&ha->copp_waitlist);
27671da177e4SLinus Torvalds 		ha->num_ioctl++;
27681da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
27691da177e4SLinus Torvalds 			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
27701da177e4SLinus Torvalds 		scb->scsi_cmd = item->scsi_cmd;
27711da177e4SLinus Torvalds 		kfree(item);
27721da177e4SLinus Torvalds 
27731da177e4SLinus Torvalds 		ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
27741da177e4SLinus Torvalds 
27751da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
27761da177e4SLinus Torvalds 			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
27771da177e4SLinus Torvalds 		switch (ret) {
27781da177e4SLinus Torvalds 		case IPS_FAILURE:
27791da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
27801da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_ERROR << 16;
27811da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
27821da177e4SLinus Torvalds 			}
27831da177e4SLinus Torvalds 
27841da177e4SLinus Torvalds 			ips_freescb(ha, scb);
27851da177e4SLinus Torvalds 			break;
27861da177e4SLinus Torvalds 		case IPS_SUCCESS_IMM:
27871da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
27881da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_OK << 16;
27891da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
27901da177e4SLinus Torvalds 			}
27911da177e4SLinus Torvalds 
27921da177e4SLinus Torvalds 			ips_freescb(ha, scb);
27931da177e4SLinus Torvalds 			break;
27941da177e4SLinus Torvalds 		default:
27951da177e4SLinus Torvalds 			break;
27961da177e4SLinus Torvalds 		}		/* end case */
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds 		if (ret != IPS_SUCCESS) {
27991da177e4SLinus Torvalds 			ha->num_ioctl--;
28001da177e4SLinus Torvalds 			continue;
28011da177e4SLinus Torvalds 		}
28021da177e4SLinus Torvalds 
28031da177e4SLinus Torvalds 		ret = ips_send_cmd(ha, scb);
28041da177e4SLinus Torvalds 
28051da177e4SLinus Torvalds 		if (ret == IPS_SUCCESS)
28061da177e4SLinus Torvalds 			ips_putq_scb_head(&ha->scb_activelist, scb);
28071da177e4SLinus Torvalds 		else
28081da177e4SLinus Torvalds 			ha->num_ioctl--;
28091da177e4SLinus Torvalds 
28101da177e4SLinus Torvalds 		switch (ret) {
28111da177e4SLinus Torvalds 		case IPS_FAILURE:
28121da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
28131da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_ERROR << 16;
28141da177e4SLinus Torvalds 			}
28151da177e4SLinus Torvalds 
28161da177e4SLinus Torvalds 			ips_freescb(ha, scb);
28171da177e4SLinus Torvalds 			break;
28181da177e4SLinus Torvalds 		case IPS_SUCCESS_IMM:
28191da177e4SLinus Torvalds 			ips_freescb(ha, scb);
28201da177e4SLinus Torvalds 			break;
28211da177e4SLinus Torvalds 		default:
28221da177e4SLinus Torvalds 			break;
28231da177e4SLinus Torvalds 		}		/* end case */
28241da177e4SLinus Torvalds 
28251da177e4SLinus Torvalds 	}
28261da177e4SLinus Torvalds 
28271da177e4SLinus Torvalds 	/*
28281da177e4SLinus Torvalds 	 * Send "Normal" I/O commands
28291da177e4SLinus Torvalds 	 */
28301da177e4SLinus Torvalds 
28311da177e4SLinus Torvalds 	p = ha->scb_waitlist.head;
28321da177e4SLinus Torvalds 	while ((p) && (scb = ips_getscb(ha))) {
28331da177e4SLinus Torvalds 		if ((p->device->channel > 0)
28341da177e4SLinus Torvalds 		    && (ha->
28351da177e4SLinus Torvalds 			dcdb_active[p->device->channel -
28361da177e4SLinus Torvalds 				    1] & (1 << p->device->id))) {
28371da177e4SLinus Torvalds 			ips_freescb(ha, scb);
28381da177e4SLinus Torvalds 			p = (Scsi_Cmnd *) p->host_scribble;
28391da177e4SLinus Torvalds 			continue;
28401da177e4SLinus Torvalds 		}
28411da177e4SLinus Torvalds 
28421da177e4SLinus Torvalds 		q = p;
28431da177e4SLinus Torvalds 		SC = ips_removeq_wait(&ha->scb_waitlist, q);
28441da177e4SLinus Torvalds 
28451da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
28461da177e4SLinus Torvalds 			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);	/* Unlock HA after command is taken off queue */
28471da177e4SLinus Torvalds 
28481da177e4SLinus Torvalds 		SC->result = DID_OK;
28491da177e4SLinus Torvalds 		SC->host_scribble = NULL;
28501da177e4SLinus Torvalds 
28511da177e4SLinus Torvalds 		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
28521da177e4SLinus Torvalds 
28531da177e4SLinus Torvalds 		scb->target_id = SC->device->id;
28541da177e4SLinus Torvalds 		scb->lun = SC->device->lun;
28551da177e4SLinus Torvalds 		scb->bus = SC->device->channel;
28561da177e4SLinus Torvalds 		scb->scsi_cmd = SC;
28571da177e4SLinus Torvalds 		scb->breakup = 0;
28581da177e4SLinus Torvalds 		scb->data_len = 0;
28591da177e4SLinus Torvalds 		scb->callback = ipsintr_done;
28601da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
28611da177e4SLinus Torvalds 		memset(&scb->cmd, 0, 16);
28621da177e4SLinus Torvalds 
28631da177e4SLinus Torvalds 		/* copy in the CDB */
28641da177e4SLinus Torvalds 		memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
28651da177e4SLinus Torvalds 
28661da177e4SLinus Torvalds 		/* Now handle the data buffer */
28671da177e4SLinus Torvalds 		if (SC->use_sg) {
28681da177e4SLinus Torvalds 			struct scatterlist *sg;
28691da177e4SLinus Torvalds 			int i;
28701da177e4SLinus Torvalds 
28711da177e4SLinus Torvalds 			sg = SC->request_buffer;
28721da177e4SLinus Torvalds 			scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
2873be7db055S 						   SC->sc_data_direction);
28741da177e4SLinus Torvalds 			scb->flags |= IPS_SCB_MAP_SG;
28751da177e4SLinus Torvalds 			for (i = 0; i < scb->sg_count; i++) {
28761da177e4SLinus Torvalds 				if (ips_fill_scb_sg_single
28771da177e4SLinus Torvalds 				    (ha, sg_dma_address(&sg[i]), scb, i,
28781da177e4SLinus Torvalds 				     sg_dma_len(&sg[i])) < 0)
28791da177e4SLinus Torvalds 					break;
28801da177e4SLinus Torvalds 			}
28811da177e4SLinus Torvalds 			scb->dcdb.transfer_length = scb->data_len;
28821da177e4SLinus Torvalds 		} else {
28831da177e4SLinus Torvalds 			if (SC->request_bufflen) {
28841da177e4SLinus Torvalds 				scb->data_busaddr =
28851da177e4SLinus Torvalds 				    pci_map_single(ha->pcidev,
28861da177e4SLinus Torvalds 						   SC->request_buffer,
28871da177e4SLinus Torvalds 						   SC->request_bufflen,
2888be7db055S 						   SC->sc_data_direction);
28891da177e4SLinus Torvalds 				scb->flags |= IPS_SCB_MAP_SINGLE;
28901da177e4SLinus Torvalds 				ips_fill_scb_sg_single(ha, scb->data_busaddr,
28911da177e4SLinus Torvalds 						       scb, 0,
28921da177e4SLinus Torvalds 						       SC->request_bufflen);
28931da177e4SLinus Torvalds 				scb->dcdb.transfer_length = scb->data_len;
28941da177e4SLinus Torvalds 			} else {
28951da177e4SLinus Torvalds 				scb->data_busaddr = 0L;
28961da177e4SLinus Torvalds 				scb->sg_len = 0;
28971da177e4SLinus Torvalds 				scb->data_len = 0;
28981da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
28991da177e4SLinus Torvalds 			}
29001da177e4SLinus Torvalds 
29011da177e4SLinus Torvalds 		}
29021da177e4SLinus Torvalds 
29031da177e4SLinus Torvalds 		scb->dcdb.cmd_attribute =
29041da177e4SLinus Torvalds 		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
29051da177e4SLinus Torvalds 
29061da177e4SLinus Torvalds         /* Allow a WRITE BUFFER Command to Have no Data */
29071da177e4SLinus Torvalds         /* This is Used by Tape Flash Utilites          */
29081da177e4SLinus Torvalds         if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0))
29091da177e4SLinus Torvalds             scb->dcdb.cmd_attribute = 0;
29101da177e4SLinus Torvalds 
29111da177e4SLinus Torvalds 		if (!(scb->dcdb.cmd_attribute & 0x3))
29121da177e4SLinus Torvalds 			scb->dcdb.transfer_length = 0;
29131da177e4SLinus Torvalds 
29141da177e4SLinus Torvalds 		if (scb->data_len >= IPS_MAX_XFER) {
29151da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
29161da177e4SLinus Torvalds 			scb->dcdb.transfer_length = 0;
29171da177e4SLinus Torvalds 		}
29181da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
29191da177e4SLinus Torvalds 			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
29201da177e4SLinus Torvalds 
29211da177e4SLinus Torvalds 		ret = ips_send_cmd(ha, scb);
29221da177e4SLinus Torvalds 
29231da177e4SLinus Torvalds 		switch (ret) {
29241da177e4SLinus Torvalds 		case IPS_SUCCESS:
29251da177e4SLinus Torvalds 			ips_putq_scb_head(&ha->scb_activelist, scb);
29261da177e4SLinus Torvalds 			break;
29271da177e4SLinus Torvalds 		case IPS_FAILURE:
29281da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
29291da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_ERROR << 16;
29301da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
29311da177e4SLinus Torvalds 			}
29321da177e4SLinus Torvalds 
29331da177e4SLinus Torvalds 			if (scb->bus)
29341da177e4SLinus Torvalds 				ha->dcdb_active[scb->bus - 1] &=
29351da177e4SLinus Torvalds 				    ~(1 << scb->target_id);
29361da177e4SLinus Torvalds 
29371da177e4SLinus Torvalds 			ips_freescb(ha, scb);
29381da177e4SLinus Torvalds 			break;
29391da177e4SLinus Torvalds 		case IPS_SUCCESS_IMM:
29401da177e4SLinus Torvalds 			if (scb->scsi_cmd)
29411da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
29421da177e4SLinus Torvalds 
29431da177e4SLinus Torvalds 			if (scb->bus)
29441da177e4SLinus Torvalds 				ha->dcdb_active[scb->bus - 1] &=
29451da177e4SLinus Torvalds 				    ~(1 << scb->target_id);
29461da177e4SLinus Torvalds 
29471da177e4SLinus Torvalds 			ips_freescb(ha, scb);
29481da177e4SLinus Torvalds 			break;
29491da177e4SLinus Torvalds 		default:
29501da177e4SLinus Torvalds 			break;
29511da177e4SLinus Torvalds 		}		/* end case */
29521da177e4SLinus Torvalds 
29531da177e4SLinus Torvalds 		p = (Scsi_Cmnd *) p->host_scribble;
29541da177e4SLinus Torvalds 
29551da177e4SLinus Torvalds 	}			/* end while */
29561da177e4SLinus Torvalds 
29571da177e4SLinus Torvalds 	if (intr == IPS_INTR_ON)
29581da177e4SLinus Torvalds 		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
29591da177e4SLinus Torvalds }
29601da177e4SLinus Torvalds 
29611da177e4SLinus Torvalds /****************************************************************************/
29621da177e4SLinus Torvalds /*                                                                          */
29631da177e4SLinus Torvalds /* Routine Name: ips_putq_scb_head                                          */
29641da177e4SLinus Torvalds /*                                                                          */
29651da177e4SLinus Torvalds /* Routine Description:                                                     */
29661da177e4SLinus Torvalds /*                                                                          */
29671da177e4SLinus Torvalds /*   Add an item to the head of the queue                                   */
29681da177e4SLinus Torvalds /*                                                                          */
29691da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
29701da177e4SLinus Torvalds /*                                                                          */
29711da177e4SLinus Torvalds /****************************************************************************/
29721da177e4SLinus Torvalds static void
29731da177e4SLinus Torvalds ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
29741da177e4SLinus Torvalds {
29751da177e4SLinus Torvalds 	METHOD_TRACE("ips_putq_scb_head", 1);
29761da177e4SLinus Torvalds 
29771da177e4SLinus Torvalds 	if (!item)
29781da177e4SLinus Torvalds 		return;
29791da177e4SLinus Torvalds 
29801da177e4SLinus Torvalds 	item->q_next = queue->head;
29811da177e4SLinus Torvalds 	queue->head = item;
29821da177e4SLinus Torvalds 
29831da177e4SLinus Torvalds 	if (!queue->tail)
29841da177e4SLinus Torvalds 		queue->tail = item;
29851da177e4SLinus Torvalds 
29861da177e4SLinus Torvalds 	queue->count++;
29871da177e4SLinus Torvalds }
29881da177e4SLinus Torvalds 
29891da177e4SLinus Torvalds /****************************************************************************/
29901da177e4SLinus Torvalds /*                                                                          */
29911da177e4SLinus Torvalds /* Routine Name: ips_removeq_scb_head                                       */
29921da177e4SLinus Torvalds /*                                                                          */
29931da177e4SLinus Torvalds /* Routine Description:                                                     */
29941da177e4SLinus Torvalds /*                                                                          */
29951da177e4SLinus Torvalds /*   Remove the head of the queue                                           */
29961da177e4SLinus Torvalds /*                                                                          */
29971da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
29981da177e4SLinus Torvalds /*                                                                          */
29991da177e4SLinus Torvalds /****************************************************************************/
30001da177e4SLinus Torvalds static ips_scb_t *
30011da177e4SLinus Torvalds ips_removeq_scb_head(ips_scb_queue_t * queue)
30021da177e4SLinus Torvalds {
30031da177e4SLinus Torvalds 	ips_scb_t *item;
30041da177e4SLinus Torvalds 
30051da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_scb_head", 1);
30061da177e4SLinus Torvalds 
30071da177e4SLinus Torvalds 	item = queue->head;
30081da177e4SLinus Torvalds 
30091da177e4SLinus Torvalds 	if (!item) {
30101da177e4SLinus Torvalds 		return (NULL);
30111da177e4SLinus Torvalds 	}
30121da177e4SLinus Torvalds 
30131da177e4SLinus Torvalds 	queue->head = item->q_next;
30141da177e4SLinus Torvalds 	item->q_next = NULL;
30151da177e4SLinus Torvalds 
30161da177e4SLinus Torvalds 	if (queue->tail == item)
30171da177e4SLinus Torvalds 		queue->tail = NULL;
30181da177e4SLinus Torvalds 
30191da177e4SLinus Torvalds 	queue->count--;
30201da177e4SLinus Torvalds 
30211da177e4SLinus Torvalds 	return (item);
30221da177e4SLinus Torvalds }
30231da177e4SLinus Torvalds 
30241da177e4SLinus Torvalds /****************************************************************************/
30251da177e4SLinus Torvalds /*                                                                          */
30261da177e4SLinus Torvalds /* Routine Name: ips_removeq_scb                                            */
30271da177e4SLinus Torvalds /*                                                                          */
30281da177e4SLinus Torvalds /* Routine Description:                                                     */
30291da177e4SLinus Torvalds /*                                                                          */
30301da177e4SLinus Torvalds /*   Remove an item from a queue                                            */
30311da177e4SLinus Torvalds /*                                                                          */
30321da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
30331da177e4SLinus Torvalds /*                                                                          */
30341da177e4SLinus Torvalds /****************************************************************************/
30351da177e4SLinus Torvalds static ips_scb_t *
30361da177e4SLinus Torvalds ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
30371da177e4SLinus Torvalds {
30381da177e4SLinus Torvalds 	ips_scb_t *p;
30391da177e4SLinus Torvalds 
30401da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_scb", 1);
30411da177e4SLinus Torvalds 
30421da177e4SLinus Torvalds 	if (!item)
30431da177e4SLinus Torvalds 		return (NULL);
30441da177e4SLinus Torvalds 
30451da177e4SLinus Torvalds 	if (item == queue->head) {
30461da177e4SLinus Torvalds 		return (ips_removeq_scb_head(queue));
30471da177e4SLinus Torvalds 	}
30481da177e4SLinus Torvalds 
30491da177e4SLinus Torvalds 	p = queue->head;
30501da177e4SLinus Torvalds 
30511da177e4SLinus Torvalds 	while ((p) && (item != p->q_next))
30521da177e4SLinus Torvalds 		p = p->q_next;
30531da177e4SLinus Torvalds 
30541da177e4SLinus Torvalds 	if (p) {
30551da177e4SLinus Torvalds 		/* found a match */
30561da177e4SLinus Torvalds 		p->q_next = item->q_next;
30571da177e4SLinus Torvalds 
30581da177e4SLinus Torvalds 		if (!item->q_next)
30591da177e4SLinus Torvalds 			queue->tail = p;
30601da177e4SLinus Torvalds 
30611da177e4SLinus Torvalds 		item->q_next = NULL;
30621da177e4SLinus Torvalds 		queue->count--;
30631da177e4SLinus Torvalds 
30641da177e4SLinus Torvalds 		return (item);
30651da177e4SLinus Torvalds 	}
30661da177e4SLinus Torvalds 
30671da177e4SLinus Torvalds 	return (NULL);
30681da177e4SLinus Torvalds }
30691da177e4SLinus Torvalds 
30701da177e4SLinus Torvalds /****************************************************************************/
30711da177e4SLinus Torvalds /*                                                                          */
30721da177e4SLinus Torvalds /* Routine Name: ips_putq_wait_tail                                         */
30731da177e4SLinus Torvalds /*                                                                          */
30741da177e4SLinus Torvalds /* Routine Description:                                                     */
30751da177e4SLinus Torvalds /*                                                                          */
30761da177e4SLinus Torvalds /*   Add an item to the tail of the queue                                   */
30771da177e4SLinus Torvalds /*                                                                          */
30781da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
30791da177e4SLinus Torvalds /*                                                                          */
30801da177e4SLinus Torvalds /****************************************************************************/
30811da177e4SLinus Torvalds static void
30821da177e4SLinus Torvalds ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
30831da177e4SLinus Torvalds {
30841da177e4SLinus Torvalds 	METHOD_TRACE("ips_putq_wait_tail", 1);
30851da177e4SLinus Torvalds 
30861da177e4SLinus Torvalds 	if (!item)
30871da177e4SLinus Torvalds 		return;
30881da177e4SLinus Torvalds 
30891da177e4SLinus Torvalds 	item->host_scribble = NULL;
30901da177e4SLinus Torvalds 
30911da177e4SLinus Torvalds 	if (queue->tail)
30921da177e4SLinus Torvalds 		queue->tail->host_scribble = (char *) item;
30931da177e4SLinus Torvalds 
30941da177e4SLinus Torvalds 	queue->tail = item;
30951da177e4SLinus Torvalds 
30961da177e4SLinus Torvalds 	if (!queue->head)
30971da177e4SLinus Torvalds 		queue->head = item;
30981da177e4SLinus Torvalds 
30991da177e4SLinus Torvalds 	queue->count++;
31001da177e4SLinus Torvalds }
31011da177e4SLinus Torvalds 
31021da177e4SLinus Torvalds /****************************************************************************/
31031da177e4SLinus Torvalds /*                                                                          */
31041da177e4SLinus Torvalds /* Routine Name: ips_removeq_wait_head                                      */
31051da177e4SLinus Torvalds /*                                                                          */
31061da177e4SLinus Torvalds /* Routine Description:                                                     */
31071da177e4SLinus Torvalds /*                                                                          */
31081da177e4SLinus Torvalds /*   Remove the head of the queue                                           */
31091da177e4SLinus Torvalds /*                                                                          */
31101da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
31111da177e4SLinus Torvalds /*                                                                          */
31121da177e4SLinus Torvalds /****************************************************************************/
31131da177e4SLinus Torvalds static Scsi_Cmnd *
31141da177e4SLinus Torvalds ips_removeq_wait_head(ips_wait_queue_t * queue)
31151da177e4SLinus Torvalds {
31161da177e4SLinus Torvalds 	Scsi_Cmnd *item;
31171da177e4SLinus Torvalds 
31181da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_wait_head", 1);
31191da177e4SLinus Torvalds 
31201da177e4SLinus Torvalds 	item = queue->head;
31211da177e4SLinus Torvalds 
31221da177e4SLinus Torvalds 	if (!item) {
31231da177e4SLinus Torvalds 		return (NULL);
31241da177e4SLinus Torvalds 	}
31251da177e4SLinus Torvalds 
31261da177e4SLinus Torvalds 	queue->head = (Scsi_Cmnd *) item->host_scribble;
31271da177e4SLinus Torvalds 	item->host_scribble = NULL;
31281da177e4SLinus Torvalds 
31291da177e4SLinus Torvalds 	if (queue->tail == item)
31301da177e4SLinus Torvalds 		queue->tail = NULL;
31311da177e4SLinus Torvalds 
31321da177e4SLinus Torvalds 	queue->count--;
31331da177e4SLinus Torvalds 
31341da177e4SLinus Torvalds 	return (item);
31351da177e4SLinus Torvalds }
31361da177e4SLinus Torvalds 
31371da177e4SLinus Torvalds /****************************************************************************/
31381da177e4SLinus Torvalds /*                                                                          */
31391da177e4SLinus Torvalds /* Routine Name: ips_removeq_wait                                           */
31401da177e4SLinus Torvalds /*                                                                          */
31411da177e4SLinus Torvalds /* Routine Description:                                                     */
31421da177e4SLinus Torvalds /*                                                                          */
31431da177e4SLinus Torvalds /*   Remove an item from a queue                                            */
31441da177e4SLinus Torvalds /*                                                                          */
31451da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
31461da177e4SLinus Torvalds /*                                                                          */
31471da177e4SLinus Torvalds /****************************************************************************/
31481da177e4SLinus Torvalds static Scsi_Cmnd *
31491da177e4SLinus Torvalds ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
31501da177e4SLinus Torvalds {
31511da177e4SLinus Torvalds 	Scsi_Cmnd *p;
31521da177e4SLinus Torvalds 
31531da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_wait", 1);
31541da177e4SLinus Torvalds 
31551da177e4SLinus Torvalds 	if (!item)
31561da177e4SLinus Torvalds 		return (NULL);
31571da177e4SLinus Torvalds 
31581da177e4SLinus Torvalds 	if (item == queue->head) {
31591da177e4SLinus Torvalds 		return (ips_removeq_wait_head(queue));
31601da177e4SLinus Torvalds 	}
31611da177e4SLinus Torvalds 
31621da177e4SLinus Torvalds 	p = queue->head;
31631da177e4SLinus Torvalds 
31641da177e4SLinus Torvalds 	while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
31651da177e4SLinus Torvalds 		p = (Scsi_Cmnd *) p->host_scribble;
31661da177e4SLinus Torvalds 
31671da177e4SLinus Torvalds 	if (p) {
31681da177e4SLinus Torvalds 		/* found a match */
31691da177e4SLinus Torvalds 		p->host_scribble = item->host_scribble;
31701da177e4SLinus Torvalds 
31711da177e4SLinus Torvalds 		if (!item->host_scribble)
31721da177e4SLinus Torvalds 			queue->tail = p;
31731da177e4SLinus Torvalds 
31741da177e4SLinus Torvalds 		item->host_scribble = NULL;
31751da177e4SLinus Torvalds 		queue->count--;
31761da177e4SLinus Torvalds 
31771da177e4SLinus Torvalds 		return (item);
31781da177e4SLinus Torvalds 	}
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 	return (NULL);
31811da177e4SLinus Torvalds }
31821da177e4SLinus Torvalds 
31831da177e4SLinus Torvalds /****************************************************************************/
31841da177e4SLinus Torvalds /*                                                                          */
31851da177e4SLinus Torvalds /* Routine Name: ips_putq_copp_tail                                         */
31861da177e4SLinus Torvalds /*                                                                          */
31871da177e4SLinus Torvalds /* Routine Description:                                                     */
31881da177e4SLinus Torvalds /*                                                                          */
31891da177e4SLinus Torvalds /*   Add an item to the tail of the queue                                   */
31901da177e4SLinus Torvalds /*                                                                          */
31911da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
31921da177e4SLinus Torvalds /*                                                                          */
31931da177e4SLinus Torvalds /****************************************************************************/
31941da177e4SLinus Torvalds static void
31951da177e4SLinus Torvalds ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
31961da177e4SLinus Torvalds {
31971da177e4SLinus Torvalds 	METHOD_TRACE("ips_putq_copp_tail", 1);
31981da177e4SLinus Torvalds 
31991da177e4SLinus Torvalds 	if (!item)
32001da177e4SLinus Torvalds 		return;
32011da177e4SLinus Torvalds 
32021da177e4SLinus Torvalds 	item->next = NULL;
32031da177e4SLinus Torvalds 
32041da177e4SLinus Torvalds 	if (queue->tail)
32051da177e4SLinus Torvalds 		queue->tail->next = item;
32061da177e4SLinus Torvalds 
32071da177e4SLinus Torvalds 	queue->tail = item;
32081da177e4SLinus Torvalds 
32091da177e4SLinus Torvalds 	if (!queue->head)
32101da177e4SLinus Torvalds 		queue->head = item;
32111da177e4SLinus Torvalds 
32121da177e4SLinus Torvalds 	queue->count++;
32131da177e4SLinus Torvalds }
32141da177e4SLinus Torvalds 
32151da177e4SLinus Torvalds /****************************************************************************/
32161da177e4SLinus Torvalds /*                                                                          */
32171da177e4SLinus Torvalds /* Routine Name: ips_removeq_copp_head                                      */
32181da177e4SLinus Torvalds /*                                                                          */
32191da177e4SLinus Torvalds /* Routine Description:                                                     */
32201da177e4SLinus Torvalds /*                                                                          */
32211da177e4SLinus Torvalds /*   Remove the head of the queue                                           */
32221da177e4SLinus Torvalds /*                                                                          */
32231da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
32241da177e4SLinus Torvalds /*                                                                          */
32251da177e4SLinus Torvalds /****************************************************************************/
32261da177e4SLinus Torvalds static ips_copp_wait_item_t *
32271da177e4SLinus Torvalds ips_removeq_copp_head(ips_copp_queue_t * queue)
32281da177e4SLinus Torvalds {
32291da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
32301da177e4SLinus Torvalds 
32311da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_copp_head", 1);
32321da177e4SLinus Torvalds 
32331da177e4SLinus Torvalds 	item = queue->head;
32341da177e4SLinus Torvalds 
32351da177e4SLinus Torvalds 	if (!item) {
32361da177e4SLinus Torvalds 		return (NULL);
32371da177e4SLinus Torvalds 	}
32381da177e4SLinus Torvalds 
32391da177e4SLinus Torvalds 	queue->head = item->next;
32401da177e4SLinus Torvalds 	item->next = NULL;
32411da177e4SLinus Torvalds 
32421da177e4SLinus Torvalds 	if (queue->tail == item)
32431da177e4SLinus Torvalds 		queue->tail = NULL;
32441da177e4SLinus Torvalds 
32451da177e4SLinus Torvalds 	queue->count--;
32461da177e4SLinus Torvalds 
32471da177e4SLinus Torvalds 	return (item);
32481da177e4SLinus Torvalds }
32491da177e4SLinus Torvalds 
32501da177e4SLinus Torvalds /****************************************************************************/
32511da177e4SLinus Torvalds /*                                                                          */
32521da177e4SLinus Torvalds /* Routine Name: ips_removeq_copp                                           */
32531da177e4SLinus Torvalds /*                                                                          */
32541da177e4SLinus Torvalds /* Routine Description:                                                     */
32551da177e4SLinus Torvalds /*                                                                          */
32561da177e4SLinus Torvalds /*   Remove an item from a queue                                            */
32571da177e4SLinus Torvalds /*                                                                          */
32581da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
32591da177e4SLinus Torvalds /*                                                                          */
32601da177e4SLinus Torvalds /****************************************************************************/
32611da177e4SLinus Torvalds static ips_copp_wait_item_t *
32621da177e4SLinus Torvalds ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
32631da177e4SLinus Torvalds {
32641da177e4SLinus Torvalds 	ips_copp_wait_item_t *p;
32651da177e4SLinus Torvalds 
32661da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_copp", 1);
32671da177e4SLinus Torvalds 
32681da177e4SLinus Torvalds 	if (!item)
32691da177e4SLinus Torvalds 		return (NULL);
32701da177e4SLinus Torvalds 
32711da177e4SLinus Torvalds 	if (item == queue->head) {
32721da177e4SLinus Torvalds 		return (ips_removeq_copp_head(queue));
32731da177e4SLinus Torvalds 	}
32741da177e4SLinus Torvalds 
32751da177e4SLinus Torvalds 	p = queue->head;
32761da177e4SLinus Torvalds 
32771da177e4SLinus Torvalds 	while ((p) && (item != p->next))
32781da177e4SLinus Torvalds 		p = p->next;
32791da177e4SLinus Torvalds 
32801da177e4SLinus Torvalds 	if (p) {
32811da177e4SLinus Torvalds 		/* found a match */
32821da177e4SLinus Torvalds 		p->next = item->next;
32831da177e4SLinus Torvalds 
32841da177e4SLinus Torvalds 		if (!item->next)
32851da177e4SLinus Torvalds 			queue->tail = p;
32861da177e4SLinus Torvalds 
32871da177e4SLinus Torvalds 		item->next = NULL;
32881da177e4SLinus Torvalds 		queue->count--;
32891da177e4SLinus Torvalds 
32901da177e4SLinus Torvalds 		return (item);
32911da177e4SLinus Torvalds 	}
32921da177e4SLinus Torvalds 
32931da177e4SLinus Torvalds 	return (NULL);
32941da177e4SLinus Torvalds }
32951da177e4SLinus Torvalds 
32961da177e4SLinus Torvalds /****************************************************************************/
32971da177e4SLinus Torvalds /*                                                                          */
32981da177e4SLinus Torvalds /* Routine Name: ipsintr_blocking                                           */
32991da177e4SLinus Torvalds /*                                                                          */
33001da177e4SLinus Torvalds /* Routine Description:                                                     */
33011da177e4SLinus Torvalds /*                                                                          */
33021da177e4SLinus Torvalds /*   Finalize an interrupt for internal commands                            */
33031da177e4SLinus Torvalds /*                                                                          */
33041da177e4SLinus Torvalds /****************************************************************************/
33051da177e4SLinus Torvalds static void
33061da177e4SLinus Torvalds ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb)
33071da177e4SLinus Torvalds {
33081da177e4SLinus Torvalds 	METHOD_TRACE("ipsintr_blocking", 2);
33091da177e4SLinus Torvalds 
33101da177e4SLinus Torvalds 	ips_freescb(ha, scb);
33111da177e4SLinus Torvalds 	if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) {
33121da177e4SLinus Torvalds 		ha->waitflag = FALSE;
33131da177e4SLinus Torvalds 
33141da177e4SLinus Torvalds 		return;
33151da177e4SLinus Torvalds 	}
33161da177e4SLinus Torvalds }
33171da177e4SLinus Torvalds 
33181da177e4SLinus Torvalds /****************************************************************************/
33191da177e4SLinus Torvalds /*                                                                          */
33201da177e4SLinus Torvalds /* Routine Name: ipsintr_done                                               */
33211da177e4SLinus Torvalds /*                                                                          */
33221da177e4SLinus Torvalds /* Routine Description:                                                     */
33231da177e4SLinus Torvalds /*                                                                          */
33241da177e4SLinus Torvalds /*   Finalize an interrupt for non-internal commands                        */
33251da177e4SLinus Torvalds /*                                                                          */
33261da177e4SLinus Torvalds /****************************************************************************/
33271da177e4SLinus Torvalds static void
33281da177e4SLinus Torvalds ipsintr_done(ips_ha_t * ha, ips_scb_t * scb)
33291da177e4SLinus Torvalds {
33301da177e4SLinus Torvalds 	METHOD_TRACE("ipsintr_done", 2);
33311da177e4SLinus Torvalds 
33321da177e4SLinus Torvalds 	if (!scb) {
33331da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
33341da177e4SLinus Torvalds 			   "Spurious interrupt; scb NULL.\n");
33351da177e4SLinus Torvalds 
33361da177e4SLinus Torvalds 		return;
33371da177e4SLinus Torvalds 	}
33381da177e4SLinus Torvalds 
33391da177e4SLinus Torvalds 	if (scb->scsi_cmd == NULL) {
33401da177e4SLinus Torvalds 		/* unexpected interrupt */
33411da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
33421da177e4SLinus Torvalds 			   "Spurious interrupt; scsi_cmd not set.\n");
33431da177e4SLinus Torvalds 
33441da177e4SLinus Torvalds 		return;
33451da177e4SLinus Torvalds 	}
33461da177e4SLinus Torvalds 
33471da177e4SLinus Torvalds 	ips_done(ha, scb);
33481da177e4SLinus Torvalds }
33491da177e4SLinus Torvalds 
33501da177e4SLinus Torvalds /****************************************************************************/
33511da177e4SLinus Torvalds /*                                                                          */
33521da177e4SLinus Torvalds /* Routine Name: ips_done                                                   */
33531da177e4SLinus Torvalds /*                                                                          */
33541da177e4SLinus Torvalds /* Routine Description:                                                     */
33551da177e4SLinus Torvalds /*                                                                          */
33561da177e4SLinus Torvalds /*   Do housekeeping on completed commands                                  */
33571da177e4SLinus Torvalds /*  ASSUMED to be called form within the request lock                       */
33581da177e4SLinus Torvalds /****************************************************************************/
33591da177e4SLinus Torvalds static void
33601da177e4SLinus Torvalds ips_done(ips_ha_t * ha, ips_scb_t * scb)
33611da177e4SLinus Torvalds {
33621da177e4SLinus Torvalds 	int ret;
33631da177e4SLinus Torvalds 
33641da177e4SLinus Torvalds 	METHOD_TRACE("ips_done", 1);
33651da177e4SLinus Torvalds 
33661da177e4SLinus Torvalds 	if (!scb)
33671da177e4SLinus Torvalds 		return;
33681da177e4SLinus Torvalds 
33691da177e4SLinus Torvalds 	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
33701da177e4SLinus Torvalds 		ips_cleanup_passthru(ha, scb);
33711da177e4SLinus Torvalds 		ha->num_ioctl--;
33721da177e4SLinus Torvalds 	} else {
33731da177e4SLinus Torvalds 		/*
33741da177e4SLinus Torvalds 		 * Check to see if this command had too much
33751da177e4SLinus Torvalds 		 * data and had to be broke up.  If so, queue
33761da177e4SLinus Torvalds 		 * the rest of the data and continue.
33771da177e4SLinus Torvalds 		 */
33781da177e4SLinus Torvalds 		if ((scb->breakup) || (scb->sg_break)) {
33791da177e4SLinus Torvalds 			/* we had a data breakup */
33801da177e4SLinus Torvalds 			scb->data_len = 0;
33811da177e4SLinus Torvalds 
33821da177e4SLinus Torvalds 			if (scb->sg_count) {
33831da177e4SLinus Torvalds 				/* S/G request */
33841da177e4SLinus Torvalds 				struct scatterlist *sg;
33851da177e4SLinus Torvalds 				int ips_sg_index = 0;
33861da177e4SLinus Torvalds 				int sg_dma_index;
33871da177e4SLinus Torvalds 
33881da177e4SLinus Torvalds 				sg = scb->scsi_cmd->request_buffer;
33891da177e4SLinus Torvalds 
33901da177e4SLinus Torvalds 				/* Spin forward to last dma chunk */
33911da177e4SLinus Torvalds 				sg_dma_index = scb->breakup;
33921da177e4SLinus Torvalds 
33931da177e4SLinus Torvalds 				/* Take care of possible partial on last chunk */
33941da177e4SLinus Torvalds 				ips_fill_scb_sg_single(ha,
33951da177e4SLinus Torvalds 						       sg_dma_address(&sg
33961da177e4SLinus Torvalds 								      [sg_dma_index]),
33971da177e4SLinus Torvalds 						       scb, ips_sg_index++,
33981da177e4SLinus Torvalds 						       sg_dma_len(&sg
33991da177e4SLinus Torvalds 								  [sg_dma_index]));
34001da177e4SLinus Torvalds 
34011da177e4SLinus Torvalds 				for (; sg_dma_index < scb->sg_count;
34021da177e4SLinus Torvalds 				     sg_dma_index++) {
34031da177e4SLinus Torvalds 					if (ips_fill_scb_sg_single
34041da177e4SLinus Torvalds 					    (ha,
34051da177e4SLinus Torvalds 					     sg_dma_address(&sg[sg_dma_index]),
34061da177e4SLinus Torvalds 					     scb, ips_sg_index++,
34071da177e4SLinus Torvalds 					     sg_dma_len(&sg[sg_dma_index])) < 0)
34081da177e4SLinus Torvalds 						break;
34091da177e4SLinus Torvalds 
34101da177e4SLinus Torvalds 				}
34111da177e4SLinus Torvalds 
34121da177e4SLinus Torvalds 			} else {
34131da177e4SLinus Torvalds 				/* Non S/G Request */
34141da177e4SLinus Torvalds 				(void) ips_fill_scb_sg_single(ha,
34151da177e4SLinus Torvalds 							      scb->
34161da177e4SLinus Torvalds 							      data_busaddr +
34171da177e4SLinus Torvalds 							      (scb->sg_break *
34181da177e4SLinus Torvalds 							       ha->max_xfer),
34191da177e4SLinus Torvalds 							      scb, 0,
34201da177e4SLinus Torvalds 							      scb->scsi_cmd->
34211da177e4SLinus Torvalds 							      request_bufflen -
34221da177e4SLinus Torvalds 							      (scb->sg_break *
34231da177e4SLinus Torvalds 							       ha->max_xfer));
34241da177e4SLinus Torvalds 			}
34251da177e4SLinus Torvalds 
34261da177e4SLinus Torvalds 			scb->dcdb.transfer_length = scb->data_len;
34271da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |=
34281da177e4SLinus Torvalds 			    ips_command_direction[scb->scsi_cmd->cmnd[0]];
34291da177e4SLinus Torvalds 
34301da177e4SLinus Torvalds 			if (!(scb->dcdb.cmd_attribute & 0x3))
34311da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
34321da177e4SLinus Torvalds 
34331da177e4SLinus Torvalds 			if (scb->data_len >= IPS_MAX_XFER) {
34341da177e4SLinus Torvalds 				scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
34351da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
34361da177e4SLinus Torvalds 			}
34371da177e4SLinus Torvalds 
34381da177e4SLinus Torvalds 			ret = ips_send_cmd(ha, scb);
34391da177e4SLinus Torvalds 
34401da177e4SLinus Torvalds 			switch (ret) {
34411da177e4SLinus Torvalds 			case IPS_FAILURE:
34421da177e4SLinus Torvalds 				if (scb->scsi_cmd) {
34431da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_ERROR << 16;
34441da177e4SLinus Torvalds 					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
34451da177e4SLinus Torvalds 				}
34461da177e4SLinus Torvalds 
34471da177e4SLinus Torvalds 				ips_freescb(ha, scb);
34481da177e4SLinus Torvalds 				break;
34491da177e4SLinus Torvalds 			case IPS_SUCCESS_IMM:
34501da177e4SLinus Torvalds 				if (scb->scsi_cmd) {
34511da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_ERROR << 16;
34521da177e4SLinus Torvalds 					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
34531da177e4SLinus Torvalds 				}
34541da177e4SLinus Torvalds 
34551da177e4SLinus Torvalds 				ips_freescb(ha, scb);
34561da177e4SLinus Torvalds 				break;
34571da177e4SLinus Torvalds 			default:
34581da177e4SLinus Torvalds 				break;
34591da177e4SLinus Torvalds 			}	/* end case */
34601da177e4SLinus Torvalds 
34611da177e4SLinus Torvalds 			return;
34621da177e4SLinus Torvalds 		}
34631da177e4SLinus Torvalds 	}			/* end if passthru */
34641da177e4SLinus Torvalds 
34651da177e4SLinus Torvalds 	if (scb->bus) {
34661da177e4SLinus Torvalds 		ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id);
34671da177e4SLinus Torvalds 	}
34681da177e4SLinus Torvalds 
34691da177e4SLinus Torvalds 	scb->scsi_cmd->scsi_done(scb->scsi_cmd);
34701da177e4SLinus Torvalds 
34711da177e4SLinus Torvalds 	ips_freescb(ha, scb);
34721da177e4SLinus Torvalds }
34731da177e4SLinus Torvalds 
34741da177e4SLinus Torvalds /****************************************************************************/
34751da177e4SLinus Torvalds /*                                                                          */
34761da177e4SLinus Torvalds /* Routine Name: ips_map_status                                             */
34771da177e4SLinus Torvalds /*                                                                          */
34781da177e4SLinus Torvalds /* Routine Description:                                                     */
34791da177e4SLinus Torvalds /*                                                                          */
34801da177e4SLinus Torvalds /*   Map Controller Error codes to Linux Error Codes                        */
34811da177e4SLinus Torvalds /*                                                                          */
34821da177e4SLinus Torvalds /****************************************************************************/
34831da177e4SLinus Torvalds static int
34841da177e4SLinus Torvalds ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
34851da177e4SLinus Torvalds {
34861da177e4SLinus Torvalds 	int errcode;
34871da177e4SLinus Torvalds 	int device_error;
34881da177e4SLinus Torvalds 	uint32_t transfer_len;
34891da177e4SLinus Torvalds 	IPS_DCDB_TABLE_TAPE *tapeDCDB;
34901da177e4SLinus Torvalds 
34911da177e4SLinus Torvalds 	METHOD_TRACE("ips_map_status", 1);
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds 	if (scb->bus) {
34941da177e4SLinus Torvalds 		DEBUG_VAR(2,
34951da177e4SLinus Torvalds 			  "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
34961da177e4SLinus Torvalds 			  ips_name, ha->host_num,
34971da177e4SLinus Torvalds 			  scb->scsi_cmd->device->channel,
34981da177e4SLinus Torvalds 			  scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun,
34991da177e4SLinus Torvalds 			  scb->basic_status, scb->extended_status,
35001da177e4SLinus Torvalds 			  scb->extended_status ==
35011da177e4SLinus Torvalds 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
35021da177e4SLinus Torvalds 			  scb->extended_status ==
35031da177e4SLinus Torvalds 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
35041da177e4SLinus Torvalds 			  scb->extended_status ==
35051da177e4SLinus Torvalds 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
35061da177e4SLinus Torvalds 	}
35071da177e4SLinus Torvalds 
35081da177e4SLinus Torvalds 	/* default driver error */
35091da177e4SLinus Torvalds 	errcode = DID_ERROR;
35101da177e4SLinus Torvalds 	device_error = 0;
35111da177e4SLinus Torvalds 
35121da177e4SLinus Torvalds 	switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
35131da177e4SLinus Torvalds 	case IPS_CMD_TIMEOUT:
35141da177e4SLinus Torvalds 		errcode = DID_TIME_OUT;
35151da177e4SLinus Torvalds 		break;
35161da177e4SLinus Torvalds 
35171da177e4SLinus Torvalds 	case IPS_INVAL_OPCO:
35181da177e4SLinus Torvalds 	case IPS_INVAL_CMD_BLK:
35191da177e4SLinus Torvalds 	case IPS_INVAL_PARM_BLK:
35201da177e4SLinus Torvalds 	case IPS_LD_ERROR:
35211da177e4SLinus Torvalds 	case IPS_CMD_CMPLT_WERROR:
35221da177e4SLinus Torvalds 		break;
35231da177e4SLinus Torvalds 
35241da177e4SLinus Torvalds 	case IPS_PHYS_DRV_ERROR:
35251da177e4SLinus Torvalds 		switch (scb->extended_status) {
35261da177e4SLinus Torvalds 		case IPS_ERR_SEL_TO:
35271da177e4SLinus Torvalds 			if (scb->bus)
35281da177e4SLinus Torvalds 				errcode = DID_NO_CONNECT;
35291da177e4SLinus Torvalds 
35301da177e4SLinus Torvalds 			break;
35311da177e4SLinus Torvalds 
35321da177e4SLinus Torvalds 		case IPS_ERR_OU_RUN:
35331da177e4SLinus Torvalds 			if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
35341da177e4SLinus Torvalds 			    (scb->cmd.dcdb.op_code ==
35351da177e4SLinus Torvalds 			     IPS_CMD_EXTENDED_DCDB_SG)) {
35361da177e4SLinus Torvalds 				tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
35371da177e4SLinus Torvalds 				transfer_len = tapeDCDB->transfer_length;
35381da177e4SLinus Torvalds 			} else {
35391da177e4SLinus Torvalds 				transfer_len =
35401da177e4SLinus Torvalds 				    (uint32_t) scb->dcdb.transfer_length;
35411da177e4SLinus Torvalds 			}
35421da177e4SLinus Torvalds 
35431da177e4SLinus Torvalds 			if ((scb->bus) && (transfer_len < scb->data_len)) {
35441da177e4SLinus Torvalds 				/* Underrun - set default to no error */
35451da177e4SLinus Torvalds 				errcode = DID_OK;
35461da177e4SLinus Torvalds 
35471da177e4SLinus Torvalds 				/* Restrict access to physical DASD */
35481da177e4SLinus Torvalds 				if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
35491da177e4SLinus Torvalds 				    ((((char *) scb->scsi_cmd->
35501da177e4SLinus Torvalds 				       buffer)[0] & 0x1f) == TYPE_DISK)) {
35511da177e4SLinus Torvalds 					/* underflow -- no error               */
35521da177e4SLinus Torvalds 					/* restrict access to physical DASD    */
35531da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
35541da177e4SLinus Torvalds 					break;
35551da177e4SLinus Torvalds 				}
35561da177e4SLinus Torvalds 			} else
35571da177e4SLinus Torvalds 				errcode = DID_ERROR;
35581da177e4SLinus Torvalds 
35591da177e4SLinus Torvalds 			break;
35601da177e4SLinus Torvalds 
35611da177e4SLinus Torvalds 		case IPS_ERR_RECOVERY:
35621da177e4SLinus Torvalds 			/* don't fail recovered errors */
35631da177e4SLinus Torvalds 			if (scb->bus)
35641da177e4SLinus Torvalds 				errcode = DID_OK;
35651da177e4SLinus Torvalds 
35661da177e4SLinus Torvalds 			break;
35671da177e4SLinus Torvalds 
35681da177e4SLinus Torvalds 		case IPS_ERR_HOST_RESET:
35691da177e4SLinus Torvalds 		case IPS_ERR_DEV_RESET:
35701da177e4SLinus Torvalds 			errcode = DID_RESET;
35711da177e4SLinus Torvalds 			break;
35721da177e4SLinus Torvalds 
35731da177e4SLinus Torvalds 		case IPS_ERR_CKCOND:
35741da177e4SLinus Torvalds 			if (scb->bus) {
35751da177e4SLinus Torvalds 				if ((scb->cmd.dcdb.op_code ==
35761da177e4SLinus Torvalds 				     IPS_CMD_EXTENDED_DCDB)
35771da177e4SLinus Torvalds 				    || (scb->cmd.dcdb.op_code ==
35781da177e4SLinus Torvalds 					IPS_CMD_EXTENDED_DCDB_SG)) {
35791da177e4SLinus Torvalds 					tapeDCDB =
35801da177e4SLinus Torvalds 					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
35811da177e4SLinus Torvalds 					memcpy(scb->scsi_cmd->sense_buffer,
35821da177e4SLinus Torvalds 					       tapeDCDB->sense_info,
35831da177e4SLinus Torvalds 					       sizeof (scb->scsi_cmd->
35841da177e4SLinus Torvalds 						       sense_buffer));
35851da177e4SLinus Torvalds 				} else {
35861da177e4SLinus Torvalds 					memcpy(scb->scsi_cmd->sense_buffer,
35871da177e4SLinus Torvalds 					       scb->dcdb.sense_info,
35881da177e4SLinus Torvalds 					       sizeof (scb->scsi_cmd->
35891da177e4SLinus Torvalds 						       sense_buffer));
35901da177e4SLinus Torvalds 				}
35911da177e4SLinus Torvalds 				device_error = 2;	/* check condition */
35921da177e4SLinus Torvalds 			}
35931da177e4SLinus Torvalds 
35941da177e4SLinus Torvalds 			errcode = DID_OK;
35951da177e4SLinus Torvalds 
35961da177e4SLinus Torvalds 			break;
35971da177e4SLinus Torvalds 
35981da177e4SLinus Torvalds 		default:
35991da177e4SLinus Torvalds 			errcode = DID_ERROR;
36001da177e4SLinus Torvalds 			break;
36011da177e4SLinus Torvalds 
36021da177e4SLinus Torvalds 		}		/* end switch */
36031da177e4SLinus Torvalds 	}			/* end switch */
36041da177e4SLinus Torvalds 
36051da177e4SLinus Torvalds 	scb->scsi_cmd->result = device_error | (errcode << 16);
36061da177e4SLinus Torvalds 
36071da177e4SLinus Torvalds 	return (1);
36081da177e4SLinus Torvalds }
36091da177e4SLinus Torvalds 
36101da177e4SLinus Torvalds /****************************************************************************/
36111da177e4SLinus Torvalds /*                                                                          */
36121da177e4SLinus Torvalds /* Routine Name: ips_send_wait                                              */
36131da177e4SLinus Torvalds /*                                                                          */
36141da177e4SLinus Torvalds /* Routine Description:                                                     */
36151da177e4SLinus Torvalds /*                                                                          */
36161da177e4SLinus Torvalds /*   Send a command to the controller and wait for it to return             */
36171da177e4SLinus Torvalds /*                                                                          */
36181da177e4SLinus Torvalds /*   The FFDC Time Stamp use this function for the callback, but doesn't    */
36191da177e4SLinus Torvalds /*   actually need to wait.                                                 */
36201da177e4SLinus Torvalds /****************************************************************************/
36211da177e4SLinus Torvalds static int
36221da177e4SLinus Torvalds ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
36231da177e4SLinus Torvalds {
36241da177e4SLinus Torvalds 	int ret;
36251da177e4SLinus Torvalds 
36261da177e4SLinus Torvalds 	METHOD_TRACE("ips_send_wait", 1);
36271da177e4SLinus Torvalds 
36281da177e4SLinus Torvalds 	if (intr != IPS_FFDC) {	/* Won't be Waiting if this is a Time Stamp */
36291da177e4SLinus Torvalds 		ha->waitflag = TRUE;
36301da177e4SLinus Torvalds 		ha->cmd_in_progress = scb->cdb[0];
36311da177e4SLinus Torvalds 	}
36321da177e4SLinus Torvalds 	scb->callback = ipsintr_blocking;
36331da177e4SLinus Torvalds 	ret = ips_send_cmd(ha, scb);
36341da177e4SLinus Torvalds 
36351da177e4SLinus Torvalds 	if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
36361da177e4SLinus Torvalds 		return (ret);
36371da177e4SLinus Torvalds 
36381da177e4SLinus Torvalds 	if (intr != IPS_FFDC)	/* Don't Wait around if this is a Time Stamp */
36391da177e4SLinus Torvalds 		ret = ips_wait(ha, timeout, intr);
36401da177e4SLinus Torvalds 
36411da177e4SLinus Torvalds 	return (ret);
36421da177e4SLinus Torvalds }
36431da177e4SLinus Torvalds 
36441da177e4SLinus Torvalds /****************************************************************************/
36451da177e4SLinus Torvalds /*                                                                          */
36461da177e4SLinus Torvalds /* Routine Name: ips_scmd_buf_write                                         */
36471da177e4SLinus Torvalds /*                                                                          */
36481da177e4SLinus Torvalds /* Routine Description:                                                     */
36491da177e4SLinus Torvalds /*  Write data to Scsi_Cmnd request_buffer at proper offsets                */
36501da177e4SLinus Torvalds /****************************************************************************/
36511da177e4SLinus Torvalds static void
36521da177e4SLinus Torvalds ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
36531da177e4SLinus Torvalds 		   int count)
36541da177e4SLinus Torvalds {
36551da177e4SLinus Torvalds 	if (scmd->use_sg) {
36561da177e4SLinus Torvalds 		int i;
36571da177e4SLinus Torvalds 		unsigned int min_cnt, xfer_cnt;
36581da177e4SLinus Torvalds 		char *cdata = (char *) data;
36591da177e4SLinus Torvalds 		struct scatterlist *sg = scmd->request_buffer;
36601da177e4SLinus Torvalds 		for (i = 0, xfer_cnt = 0;
36611da177e4SLinus Torvalds 		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
36621da177e4SLinus Torvalds 			if (!IPS_SG_ADDRESS(&sg[i]))
36631da177e4SLinus Torvalds 				return;
36641da177e4SLinus Torvalds 			min_cnt = min(count - xfer_cnt, sg[i].length);
36651da177e4SLinus Torvalds 			memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt],
36661da177e4SLinus Torvalds 			       min_cnt);
36671da177e4SLinus Torvalds 			xfer_cnt += min_cnt;
36681da177e4SLinus Torvalds 		}
36691da177e4SLinus Torvalds 
36701da177e4SLinus Torvalds 	} else {
36711da177e4SLinus Torvalds 		unsigned int min_cnt = min(count, scmd->request_bufflen);
36721da177e4SLinus Torvalds 		memcpy(scmd->request_buffer, data, min_cnt);
36731da177e4SLinus Torvalds 	}
36741da177e4SLinus Torvalds }
36751da177e4SLinus Torvalds 
36761da177e4SLinus Torvalds /****************************************************************************/
36771da177e4SLinus Torvalds /*                                                                          */
36781da177e4SLinus Torvalds /* Routine Name: ips_scmd_buf_read                                          */
36791da177e4SLinus Torvalds /*                                                                          */
36801da177e4SLinus Torvalds /* Routine Description:                                                     */
36811da177e4SLinus Torvalds /*  Copy data from a Scsi_Cmnd to a new, linear buffer                      */
36821da177e4SLinus Torvalds /****************************************************************************/
36831da177e4SLinus Torvalds static void
36841da177e4SLinus Torvalds ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
36851da177e4SLinus Torvalds 		  int count)
36861da177e4SLinus Torvalds {
36871da177e4SLinus Torvalds 	if (scmd->use_sg) {
36881da177e4SLinus Torvalds 		int i;
36891da177e4SLinus Torvalds 		unsigned int min_cnt, xfer_cnt;
36901da177e4SLinus Torvalds 		char *cdata = (char *) data;
36911da177e4SLinus Torvalds 		struct scatterlist *sg = scmd->request_buffer;
36921da177e4SLinus Torvalds 		for (i = 0, xfer_cnt = 0;
36931da177e4SLinus Torvalds 		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
36941da177e4SLinus Torvalds 			if (!IPS_SG_ADDRESS(&sg[i]))
36951da177e4SLinus Torvalds 				return;
36961da177e4SLinus Torvalds 			min_cnt = min(count - xfer_cnt, sg[i].length);
36971da177e4SLinus Torvalds 			memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]),
36981da177e4SLinus Torvalds 			       min_cnt);
36991da177e4SLinus Torvalds 			xfer_cnt += min_cnt;
37001da177e4SLinus Torvalds 		}
37011da177e4SLinus Torvalds 
37021da177e4SLinus Torvalds 	} else {
37031da177e4SLinus Torvalds 		unsigned int min_cnt = min(count, scmd->request_bufflen);
37041da177e4SLinus Torvalds 		memcpy(data, scmd->request_buffer, min_cnt);
37051da177e4SLinus Torvalds 	}
37061da177e4SLinus Torvalds }
37071da177e4SLinus Torvalds 
37081da177e4SLinus Torvalds /****************************************************************************/
37091da177e4SLinus Torvalds /*                                                                          */
37101da177e4SLinus Torvalds /* Routine Name: ips_send_cmd                                               */
37111da177e4SLinus Torvalds /*                                                                          */
37121da177e4SLinus Torvalds /* Routine Description:                                                     */
37131da177e4SLinus Torvalds /*                                                                          */
37141da177e4SLinus Torvalds /*   Map SCSI commands to ServeRAID commands for logical drives             */
37151da177e4SLinus Torvalds /*                                                                          */
37161da177e4SLinus Torvalds /****************************************************************************/
37171da177e4SLinus Torvalds static int
37181da177e4SLinus Torvalds ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
37191da177e4SLinus Torvalds {
37201da177e4SLinus Torvalds 	int ret;
37211da177e4SLinus Torvalds 	char *sp;
37221da177e4SLinus Torvalds 	int device_error;
37231da177e4SLinus Torvalds 	IPS_DCDB_TABLE_TAPE *tapeDCDB;
37241da177e4SLinus Torvalds 	int TimeOut;
37251da177e4SLinus Torvalds 
37261da177e4SLinus Torvalds 	METHOD_TRACE("ips_send_cmd", 1);
37271da177e4SLinus Torvalds 
37281da177e4SLinus Torvalds 	ret = IPS_SUCCESS;
37291da177e4SLinus Torvalds 
37301da177e4SLinus Torvalds 	if (!scb->scsi_cmd) {
37311da177e4SLinus Torvalds 		/* internal command */
37321da177e4SLinus Torvalds 
37331da177e4SLinus Torvalds 		if (scb->bus > 0) {
37341da177e4SLinus Torvalds 			/* Controller commands can't be issued */
37351da177e4SLinus Torvalds 			/* to real devices -- fail them        */
37361da177e4SLinus Torvalds 			if ((ha->waitflag == TRUE) &&
37371da177e4SLinus Torvalds 			    (ha->cmd_in_progress == scb->cdb[0])) {
37381da177e4SLinus Torvalds 				ha->waitflag = FALSE;
37391da177e4SLinus Torvalds 			}
37401da177e4SLinus Torvalds 
37411da177e4SLinus Torvalds 			return (1);
37421da177e4SLinus Torvalds 		}
37431da177e4SLinus Torvalds 	} else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
37441da177e4SLinus Torvalds 		/* command to logical bus -- interpret */
37451da177e4SLinus Torvalds 		ret = IPS_SUCCESS_IMM;
37461da177e4SLinus Torvalds 
37471da177e4SLinus Torvalds 		switch (scb->scsi_cmd->cmnd[0]) {
37481da177e4SLinus Torvalds 		case ALLOW_MEDIUM_REMOVAL:
37491da177e4SLinus Torvalds 		case REZERO_UNIT:
37501da177e4SLinus Torvalds 		case ERASE:
37511da177e4SLinus Torvalds 		case WRITE_FILEMARKS:
37521da177e4SLinus Torvalds 		case SPACE:
37531da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_ERROR << 16;
37541da177e4SLinus Torvalds 			break;
37551da177e4SLinus Torvalds 
37561da177e4SLinus Torvalds 		case START_STOP:
37571da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
37581da177e4SLinus Torvalds 
37591da177e4SLinus Torvalds 		case TEST_UNIT_READY:
37601da177e4SLinus Torvalds 		case INQUIRY:
37611da177e4SLinus Torvalds 			if (scb->target_id == IPS_ADAPTER_ID) {
37621da177e4SLinus Torvalds 				/*
37631da177e4SLinus Torvalds 				 * Either we have a TUR
37641da177e4SLinus Torvalds 				 * or we have a SCSI inquiry
37651da177e4SLinus Torvalds 				 */
37661da177e4SLinus Torvalds 				if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
37671da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_OK << 16;
37681da177e4SLinus Torvalds 
37691da177e4SLinus Torvalds 				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
37701da177e4SLinus Torvalds 					IPS_SCSI_INQ_DATA inquiry;
37711da177e4SLinus Torvalds 
37721da177e4SLinus Torvalds 					memset(&inquiry, 0,
37731da177e4SLinus Torvalds 					       sizeof (IPS_SCSI_INQ_DATA));
37741da177e4SLinus Torvalds 
37751da177e4SLinus Torvalds 					inquiry.DeviceType =
37761da177e4SLinus Torvalds 					    IPS_SCSI_INQ_TYPE_PROCESSOR;
37771da177e4SLinus Torvalds 					inquiry.DeviceTypeQualifier =
37781da177e4SLinus Torvalds 					    IPS_SCSI_INQ_LU_CONNECTED;
37791da177e4SLinus Torvalds 					inquiry.Version = IPS_SCSI_INQ_REV2;
37801da177e4SLinus Torvalds 					inquiry.ResponseDataFormat =
37811da177e4SLinus Torvalds 					    IPS_SCSI_INQ_RD_REV2;
37821da177e4SLinus Torvalds 					inquiry.AdditionalLength = 31;
37831da177e4SLinus Torvalds 					inquiry.Flags[0] =
37841da177e4SLinus Torvalds 					    IPS_SCSI_INQ_Address16;
37851da177e4SLinus Torvalds 					inquiry.Flags[1] =
37861da177e4SLinus Torvalds 					    IPS_SCSI_INQ_WBus16 |
37871da177e4SLinus Torvalds 					    IPS_SCSI_INQ_Sync;
37881da177e4SLinus Torvalds 					strncpy(inquiry.VendorId, "IBM     ",
37891da177e4SLinus Torvalds 						8);
37901da177e4SLinus Torvalds 					strncpy(inquiry.ProductId,
37911da177e4SLinus Torvalds 						"SERVERAID       ", 16);
37921da177e4SLinus Torvalds 					strncpy(inquiry.ProductRevisionLevel,
37931da177e4SLinus Torvalds 						"1.00", 4);
37941da177e4SLinus Torvalds 
37951da177e4SLinus Torvalds 					ips_scmd_buf_write(scb->scsi_cmd,
37961da177e4SLinus Torvalds 							   &inquiry,
37971da177e4SLinus Torvalds 							   sizeof (inquiry));
37981da177e4SLinus Torvalds 
37991da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_OK << 16;
38001da177e4SLinus Torvalds 				}
38011da177e4SLinus Torvalds 			} else {
38021da177e4SLinus Torvalds 				scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
38031da177e4SLinus Torvalds 				scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
38041da177e4SLinus Torvalds 				scb->cmd.logical_info.reserved = 0;
38051da177e4SLinus Torvalds 				scb->cmd.logical_info.reserved2 = 0;
38061da177e4SLinus Torvalds 				scb->data_len = sizeof (IPS_LD_INFO);
38071da177e4SLinus Torvalds 				scb->data_busaddr = ha->logical_drive_info_dma_addr;
38081da177e4SLinus Torvalds 				scb->flags = 0;
38091da177e4SLinus Torvalds 				scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
38101da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
38111da177e4SLinus Torvalds 			}
38121da177e4SLinus Torvalds 
38131da177e4SLinus Torvalds 			break;
38141da177e4SLinus Torvalds 
38151da177e4SLinus Torvalds 		case REQUEST_SENSE:
38161da177e4SLinus Torvalds 			ips_reqsen(ha, scb);
38171da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
38181da177e4SLinus Torvalds 			break;
38191da177e4SLinus Torvalds 
38201da177e4SLinus Torvalds 		case READ_6:
38211da177e4SLinus Torvalds 		case WRITE_6:
38221da177e4SLinus Torvalds 			if (!scb->sg_len) {
38231da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
38241da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
38251da177e4SLinus Torvalds 				     READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
38261da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg = 0;
38271da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
38281da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
38291da177e4SLinus Torvalds 			} else {
38301da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
38311da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
38321da177e4SLinus Torvalds 				     READ_6) ? IPS_CMD_READ_SG :
38331da177e4SLinus Torvalds 				    IPS_CMD_WRITE_SG;
38341da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg =
38351da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
38361da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
38371da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
38381da177e4SLinus Torvalds 			}
38391da177e4SLinus Torvalds 
38401da177e4SLinus Torvalds 			scb->cmd.basic_io.segment_4G = 0;
38411da177e4SLinus Torvalds 			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
38421da177e4SLinus Torvalds 			scb->cmd.basic_io.log_drv = scb->target_id;
38431da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_count = scb->sg_len;
38441da177e4SLinus Torvalds 
38451da177e4SLinus Torvalds 			if (scb->cmd.basic_io.lba)
38461da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
38471da177e4SLinus Torvalds 				    cpu_to_le32(le32_to_cpu
38481da177e4SLinus Torvalds 						(scb->cmd.basic_io.lba) +
38491da177e4SLinus Torvalds 						le16_to_cpu(scb->cmd.basic_io.
38501da177e4SLinus Torvalds 							    sector_count));
38511da177e4SLinus Torvalds 			else
38521da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
38531da177e4SLinus Torvalds 				    (((scb->scsi_cmd->
38541da177e4SLinus Torvalds 				       cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd->
38551da177e4SLinus Torvalds 								 cmnd[2] << 8) |
38561da177e4SLinus Torvalds 				     (scb->scsi_cmd->cmnd[3]));
38571da177e4SLinus Torvalds 
38581da177e4SLinus Torvalds 			scb->cmd.basic_io.sector_count =
38591da177e4SLinus Torvalds 			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
38601da177e4SLinus Torvalds 
38611da177e4SLinus Torvalds 			if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
38621da177e4SLinus Torvalds 				scb->cmd.basic_io.sector_count =
38631da177e4SLinus Torvalds 				    cpu_to_le16(256);
38641da177e4SLinus Torvalds 
38651da177e4SLinus Torvalds 			ret = IPS_SUCCESS;
38661da177e4SLinus Torvalds 			break;
38671da177e4SLinus Torvalds 
38681da177e4SLinus Torvalds 		case READ_10:
38691da177e4SLinus Torvalds 		case WRITE_10:
38701da177e4SLinus Torvalds 			if (!scb->sg_len) {
38711da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
38721da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
38731da177e4SLinus Torvalds 				     READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
38741da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg = 0;
38751da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
38761da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
38771da177e4SLinus Torvalds 			} else {
38781da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
38791da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
38801da177e4SLinus Torvalds 				     READ_10) ? IPS_CMD_READ_SG :
38811da177e4SLinus Torvalds 				    IPS_CMD_WRITE_SG;
38821da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg =
38831da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
38841da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
38851da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
38861da177e4SLinus Torvalds 			}
38871da177e4SLinus Torvalds 
38881da177e4SLinus Torvalds 			scb->cmd.basic_io.segment_4G = 0;
38891da177e4SLinus Torvalds 			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
38901da177e4SLinus Torvalds 			scb->cmd.basic_io.log_drv = scb->target_id;
38911da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_count = scb->sg_len;
38921da177e4SLinus Torvalds 
38931da177e4SLinus Torvalds 			if (scb->cmd.basic_io.lba)
38941da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
38951da177e4SLinus Torvalds 				    cpu_to_le32(le32_to_cpu
38961da177e4SLinus Torvalds 						(scb->cmd.basic_io.lba) +
38971da177e4SLinus Torvalds 						le16_to_cpu(scb->cmd.basic_io.
38981da177e4SLinus Torvalds 							    sector_count));
38991da177e4SLinus Torvalds 			else
39001da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
39011da177e4SLinus Torvalds 				    ((scb->scsi_cmd->cmnd[2] << 24) | (scb->
39021da177e4SLinus Torvalds 								       scsi_cmd->
39031da177e4SLinus Torvalds 								       cmnd[3]
39041da177e4SLinus Torvalds 								       << 16) |
39051da177e4SLinus Torvalds 				     (scb->scsi_cmd->cmnd[4] << 8) | scb->
39061da177e4SLinus Torvalds 				     scsi_cmd->cmnd[5]);
39071da177e4SLinus Torvalds 
39081da177e4SLinus Torvalds 			scb->cmd.basic_io.sector_count =
39091da177e4SLinus Torvalds 			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
39101da177e4SLinus Torvalds 
39111da177e4SLinus Torvalds 			if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
39121da177e4SLinus Torvalds 				/*
39131da177e4SLinus Torvalds 				 * This is a null condition
39141da177e4SLinus Torvalds 				 * we don't have to do anything
39151da177e4SLinus Torvalds 				 * so just return
39161da177e4SLinus Torvalds 				 */
39171da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_OK << 16;
39181da177e4SLinus Torvalds 			} else
39191da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
39201da177e4SLinus Torvalds 
39211da177e4SLinus Torvalds 			break;
39221da177e4SLinus Torvalds 
39231da177e4SLinus Torvalds 		case RESERVE:
39241da177e4SLinus Torvalds 		case RELEASE:
39251da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
39261da177e4SLinus Torvalds 			break;
39271da177e4SLinus Torvalds 
39281da177e4SLinus Torvalds 		case MODE_SENSE:
39291da177e4SLinus Torvalds 			scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
39301da177e4SLinus Torvalds 			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
39311da177e4SLinus Torvalds 			scb->cmd.basic_io.segment_4G = 0;
39321da177e4SLinus Torvalds 			scb->cmd.basic_io.enhanced_sg = 0;
39331da177e4SLinus Torvalds 			scb->data_len = sizeof (*ha->enq);
39341da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
39351da177e4SLinus Torvalds 			ret = IPS_SUCCESS;
39361da177e4SLinus Torvalds 			break;
39371da177e4SLinus Torvalds 
39381da177e4SLinus Torvalds 		case READ_CAPACITY:
39391da177e4SLinus Torvalds 			scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
39401da177e4SLinus Torvalds 			scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
39411da177e4SLinus Torvalds 			scb->cmd.logical_info.reserved = 0;
39421da177e4SLinus Torvalds 			scb->cmd.logical_info.reserved2 = 0;
39431da177e4SLinus Torvalds 			scb->cmd.logical_info.reserved3 = 0;
39441da177e4SLinus Torvalds 			scb->data_len = sizeof (IPS_LD_INFO);
39451da177e4SLinus Torvalds 			scb->data_busaddr = ha->logical_drive_info_dma_addr;
39461da177e4SLinus Torvalds 			scb->flags = 0;
39471da177e4SLinus Torvalds 			scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
39481da177e4SLinus Torvalds 			ret = IPS_SUCCESS;
39491da177e4SLinus Torvalds 			break;
39501da177e4SLinus Torvalds 
39511da177e4SLinus Torvalds 		case SEND_DIAGNOSTIC:
39521da177e4SLinus Torvalds 		case REASSIGN_BLOCKS:
39531da177e4SLinus Torvalds 		case FORMAT_UNIT:
39541da177e4SLinus Torvalds 		case SEEK_10:
39551da177e4SLinus Torvalds 		case VERIFY:
39561da177e4SLinus Torvalds 		case READ_DEFECT_DATA:
39571da177e4SLinus Torvalds 		case READ_BUFFER:
39581da177e4SLinus Torvalds 		case WRITE_BUFFER:
39591da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
39601da177e4SLinus Torvalds 			break;
39611da177e4SLinus Torvalds 
39621da177e4SLinus Torvalds 		default:
39631da177e4SLinus Torvalds 			/* Set the Return Info to appear like the Command was */
39641da177e4SLinus Torvalds 			/* attempted, a Check Condition occurred, and Sense   */
39651da177e4SLinus Torvalds 			/* Data indicating an Invalid CDB OpCode is returned. */
39661da177e4SLinus Torvalds 			sp = (char *) scb->scsi_cmd->sense_buffer;
39671da177e4SLinus Torvalds 			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
39681da177e4SLinus Torvalds 
39691da177e4SLinus Torvalds 			sp[0] = 0x70;	/* Error Code               */
39701da177e4SLinus Torvalds 			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
39711da177e4SLinus Torvalds 			sp[7] = 0x0A;	/* Additional Sense Length  */
39721da177e4SLinus Torvalds 			sp[12] = 0x20;	/* ASC = Invalid OpCode     */
39731da177e4SLinus Torvalds 			sp[13] = 0x00;	/* ASCQ                     */
39741da177e4SLinus Torvalds 
39751da177e4SLinus Torvalds 			device_error = 2;	/* Indicate Check Condition */
39761da177e4SLinus Torvalds 			scb->scsi_cmd->result = device_error | (DID_OK << 16);
39771da177e4SLinus Torvalds 			break;
39781da177e4SLinus Torvalds 		}		/* end switch */
39791da177e4SLinus Torvalds 	}
39801da177e4SLinus Torvalds 	/* end if */
39811da177e4SLinus Torvalds 	if (ret == IPS_SUCCESS_IMM)
39821da177e4SLinus Torvalds 		return (ret);
39831da177e4SLinus Torvalds 
39841da177e4SLinus Torvalds 	/* setup DCDB */
39851da177e4SLinus Torvalds 	if (scb->bus > 0) {
39861da177e4SLinus Torvalds 
39871da177e4SLinus Torvalds 		/* If we already know the Device is Not there, no need to attempt a Command   */
39881da177e4SLinus Torvalds 		/* This also protects an NT FailOver Controller from getting CDB's sent to it */
39891da177e4SLinus Torvalds 		if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) {
39901da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_NO_CONNECT << 16;
39911da177e4SLinus Torvalds 			return (IPS_SUCCESS_IMM);
39921da177e4SLinus Torvalds 		}
39931da177e4SLinus Torvalds 
39941da177e4SLinus Torvalds 		ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id);
39951da177e4SLinus Torvalds 		scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
39961da177e4SLinus Torvalds 		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
39971da177e4SLinus Torvalds 							 (unsigned long) &scb->
39981da177e4SLinus Torvalds 							 dcdb -
39991da177e4SLinus Torvalds 							 (unsigned long) scb);
40001da177e4SLinus Torvalds 		scb->cmd.dcdb.reserved = 0;
40011da177e4SLinus Torvalds 		scb->cmd.dcdb.reserved2 = 0;
40021da177e4SLinus Torvalds 		scb->cmd.dcdb.reserved3 = 0;
40031da177e4SLinus Torvalds 		scb->cmd.dcdb.segment_4G = 0;
40041da177e4SLinus Torvalds 		scb->cmd.dcdb.enhanced_sg = 0;
40051da177e4SLinus Torvalds 
40061da177e4SLinus Torvalds 		TimeOut = scb->scsi_cmd->timeout_per_command;
40071da177e4SLinus Torvalds 
40081da177e4SLinus Torvalds 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
40091da177e4SLinus Torvalds 			if (!scb->sg_len) {
40101da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
40111da177e4SLinus Torvalds 			} else {
40121da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code =
40131da177e4SLinus Torvalds 				    IPS_CMD_EXTENDED_DCDB_SG;
40141da177e4SLinus Torvalds 				scb->cmd.dcdb.enhanced_sg =
40151da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
40161da177e4SLinus Torvalds 			}
40171da177e4SLinus Torvalds 
40181da177e4SLinus Torvalds 			tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;	/* Use Same Data Area as Old DCDB Struct */
40191da177e4SLinus Torvalds 			tapeDCDB->device_address =
40201da177e4SLinus Torvalds 			    ((scb->bus - 1) << 4) | scb->target_id;
40211da177e4SLinus Torvalds 			tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
40221da177e4SLinus Torvalds 			tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;	/* Always Turn OFF 64K Size Flag */
40231da177e4SLinus Torvalds 
40241da177e4SLinus Torvalds 			if (TimeOut) {
40251da177e4SLinus Torvalds 				if (TimeOut < (10 * HZ))
40261da177e4SLinus Torvalds 					tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
40271da177e4SLinus Torvalds 				else if (TimeOut < (60 * HZ))
40281da177e4SLinus Torvalds 					tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
40291da177e4SLinus Torvalds 				else if (TimeOut < (1200 * HZ))
40301da177e4SLinus Torvalds 					tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
40311da177e4SLinus Torvalds 			}
40321da177e4SLinus Torvalds 
40331da177e4SLinus Torvalds 			tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
40341da177e4SLinus Torvalds 			tapeDCDB->reserved_for_LUN = 0;
40351da177e4SLinus Torvalds 			tapeDCDB->transfer_length = scb->data_len;
40361da177e4SLinus Torvalds 			if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)
40371da177e4SLinus Torvalds 				tapeDCDB->buffer_pointer =
40381da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
40391da177e4SLinus Torvalds 			else
40401da177e4SLinus Torvalds 				tapeDCDB->buffer_pointer =
40411da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
40421da177e4SLinus Torvalds 			tapeDCDB->sg_count = scb->sg_len;
40431da177e4SLinus Torvalds 			tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info);
40441da177e4SLinus Torvalds 			tapeDCDB->scsi_status = 0;
40451da177e4SLinus Torvalds 			tapeDCDB->reserved = 0;
40461da177e4SLinus Torvalds 			memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd,
40471da177e4SLinus Torvalds 			       scb->scsi_cmd->cmd_len);
40481da177e4SLinus Torvalds 		} else {
40491da177e4SLinus Torvalds 			if (!scb->sg_len) {
40501da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
40511da177e4SLinus Torvalds 			} else {
40521da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
40531da177e4SLinus Torvalds 				scb->cmd.dcdb.enhanced_sg =
40541da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
40551da177e4SLinus Torvalds 			}
40561da177e4SLinus Torvalds 
40571da177e4SLinus Torvalds 			scb->dcdb.device_address =
40581da177e4SLinus Torvalds 			    ((scb->bus - 1) << 4) | scb->target_id;
40591da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
40601da177e4SLinus Torvalds 
40611da177e4SLinus Torvalds 			if (TimeOut) {
40621da177e4SLinus Torvalds 				if (TimeOut < (10 * HZ))
40631da177e4SLinus Torvalds 					scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
40641da177e4SLinus Torvalds 				else if (TimeOut < (60 * HZ))
40651da177e4SLinus Torvalds 					scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
40661da177e4SLinus Torvalds 				else if (TimeOut < (1200 * HZ))
40671da177e4SLinus Torvalds 					scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
40681da177e4SLinus Torvalds 			}
40691da177e4SLinus Torvalds 
40701da177e4SLinus Torvalds 			scb->dcdb.transfer_length = scb->data_len;
40711da177e4SLinus Torvalds 			if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K)
40721da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
40731da177e4SLinus Torvalds 			if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG)
40741da177e4SLinus Torvalds 				scb->dcdb.buffer_pointer =
40751da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
40761da177e4SLinus Torvalds 			else
40771da177e4SLinus Torvalds 				scb->dcdb.buffer_pointer =
40781da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
40791da177e4SLinus Torvalds 			scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
40801da177e4SLinus Torvalds 			scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info);
40811da177e4SLinus Torvalds 			scb->dcdb.sg_count = scb->sg_len;
40821da177e4SLinus Torvalds 			scb->dcdb.reserved = 0;
40831da177e4SLinus Torvalds 			memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd,
40841da177e4SLinus Torvalds 			       scb->scsi_cmd->cmd_len);
40851da177e4SLinus Torvalds 			scb->dcdb.scsi_status = 0;
40861da177e4SLinus Torvalds 			scb->dcdb.reserved2[0] = 0;
40871da177e4SLinus Torvalds 			scb->dcdb.reserved2[1] = 0;
40881da177e4SLinus Torvalds 			scb->dcdb.reserved2[2] = 0;
40891da177e4SLinus Torvalds 		}
40901da177e4SLinus Torvalds 	}
40911da177e4SLinus Torvalds 
40921da177e4SLinus Torvalds 	return ((*ha->func.issue) (ha, scb));
40931da177e4SLinus Torvalds }
40941da177e4SLinus Torvalds 
40951da177e4SLinus Torvalds /****************************************************************************/
40961da177e4SLinus Torvalds /*                                                                          */
40971da177e4SLinus Torvalds /* Routine Name: ips_chk_status                                             */
40981da177e4SLinus Torvalds /*                                                                          */
40991da177e4SLinus Torvalds /* Routine Description:                                                     */
41001da177e4SLinus Torvalds /*                                                                          */
41011da177e4SLinus Torvalds /*   Check the status of commands to logical drives                         */
41021da177e4SLinus Torvalds /*   Assumed to be called with the HA lock                                  */
41031da177e4SLinus Torvalds /****************************************************************************/
41041da177e4SLinus Torvalds static void
41051da177e4SLinus Torvalds ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
41061da177e4SLinus Torvalds {
41071da177e4SLinus Torvalds 	ips_scb_t *scb;
41081da177e4SLinus Torvalds 	ips_stat_t *sp;
41091da177e4SLinus Torvalds 	uint8_t basic_status;
41101da177e4SLinus Torvalds 	uint8_t ext_status;
41111da177e4SLinus Torvalds 	int errcode;
41121da177e4SLinus Torvalds 
41131da177e4SLinus Torvalds 	METHOD_TRACE("ips_chkstatus", 1);
41141da177e4SLinus Torvalds 
41151da177e4SLinus Torvalds 	scb = &ha->scbs[pstatus->fields.command_id];
41161da177e4SLinus Torvalds 	scb->basic_status = basic_status =
41171da177e4SLinus Torvalds 	    pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
41181da177e4SLinus Torvalds 	scb->extended_status = ext_status = pstatus->fields.extended_status;
41191da177e4SLinus Torvalds 
41201da177e4SLinus Torvalds 	sp = &ha->sp;
41211da177e4SLinus Torvalds 	sp->residue_len = 0;
41221da177e4SLinus Torvalds 	sp->scb_addr = (void *) scb;
41231da177e4SLinus Torvalds 
41241da177e4SLinus Torvalds 	/* Remove the item from the active queue */
41251da177e4SLinus Torvalds 	ips_removeq_scb(&ha->scb_activelist, scb);
41261da177e4SLinus Torvalds 
41271da177e4SLinus Torvalds 	if (!scb->scsi_cmd)
41281da177e4SLinus Torvalds 		/* internal commands are handled in do_ipsintr */
41291da177e4SLinus Torvalds 		return;
41301da177e4SLinus Torvalds 
41311da177e4SLinus Torvalds 	DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
41321da177e4SLinus Torvalds 		  ips_name,
41331da177e4SLinus Torvalds 		  ha->host_num,
41341da177e4SLinus Torvalds 		  scb->cdb[0],
41351da177e4SLinus Torvalds 		  scb->cmd.basic_io.command_id,
41361da177e4SLinus Torvalds 		  scb->bus, scb->target_id, scb->lun);
41371da177e4SLinus Torvalds 
41381da177e4SLinus Torvalds 	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
41391da177e4SLinus Torvalds 		/* passthru - just returns the raw result */
41401da177e4SLinus Torvalds 		return;
41411da177e4SLinus Torvalds 
41421da177e4SLinus Torvalds 	errcode = DID_OK;
41431da177e4SLinus Torvalds 
41441da177e4SLinus Torvalds 	if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
41451da177e4SLinus Torvalds 	    ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
41461da177e4SLinus Torvalds 
41471da177e4SLinus Torvalds 		if (scb->bus == 0) {
41481da177e4SLinus Torvalds 			if ((basic_status & IPS_GSC_STATUS_MASK) ==
41491da177e4SLinus Torvalds 			    IPS_CMD_RECOVERED_ERROR) {
41501da177e4SLinus Torvalds 				DEBUG_VAR(1,
41511da177e4SLinus Torvalds 					  "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
41521da177e4SLinus Torvalds 					  ips_name, ha->host_num,
41531da177e4SLinus Torvalds 					  scb->cmd.basic_io.op_code,
41541da177e4SLinus Torvalds 					  basic_status, ext_status);
41551da177e4SLinus Torvalds 			}
41561da177e4SLinus Torvalds 
41571da177e4SLinus Torvalds 			switch (scb->scsi_cmd->cmnd[0]) {
41581da177e4SLinus Torvalds 			case ALLOW_MEDIUM_REMOVAL:
41591da177e4SLinus Torvalds 			case REZERO_UNIT:
41601da177e4SLinus Torvalds 			case ERASE:
41611da177e4SLinus Torvalds 			case WRITE_FILEMARKS:
41621da177e4SLinus Torvalds 			case SPACE:
41631da177e4SLinus Torvalds 				errcode = DID_ERROR;
41641da177e4SLinus Torvalds 				break;
41651da177e4SLinus Torvalds 
41661da177e4SLinus Torvalds 			case START_STOP:
41671da177e4SLinus Torvalds 				break;
41681da177e4SLinus Torvalds 
41691da177e4SLinus Torvalds 			case TEST_UNIT_READY:
41701da177e4SLinus Torvalds 				if (!ips_online(ha, scb)) {
41711da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
41721da177e4SLinus Torvalds 				}
41731da177e4SLinus Torvalds 				break;
41741da177e4SLinus Torvalds 
41751da177e4SLinus Torvalds 			case INQUIRY:
41761da177e4SLinus Torvalds 				if (ips_online(ha, scb)) {
41771da177e4SLinus Torvalds 					ips_inquiry(ha, scb);
41781da177e4SLinus Torvalds 				} else {
41791da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
41801da177e4SLinus Torvalds 				}
41811da177e4SLinus Torvalds 				break;
41821da177e4SLinus Torvalds 
41831da177e4SLinus Torvalds 			case REQUEST_SENSE:
41841da177e4SLinus Torvalds 				ips_reqsen(ha, scb);
41851da177e4SLinus Torvalds 				break;
41861da177e4SLinus Torvalds 
41871da177e4SLinus Torvalds 			case READ_6:
41881da177e4SLinus Torvalds 			case WRITE_6:
41891da177e4SLinus Torvalds 			case READ_10:
41901da177e4SLinus Torvalds 			case WRITE_10:
41911da177e4SLinus Torvalds 			case RESERVE:
41921da177e4SLinus Torvalds 			case RELEASE:
41931da177e4SLinus Torvalds 				break;
41941da177e4SLinus Torvalds 
41951da177e4SLinus Torvalds 			case MODE_SENSE:
41961da177e4SLinus Torvalds 				if (!ips_online(ha, scb)
41971da177e4SLinus Torvalds 				    || !ips_msense(ha, scb)) {
41981da177e4SLinus Torvalds 					errcode = DID_ERROR;
41991da177e4SLinus Torvalds 				}
42001da177e4SLinus Torvalds 				break;
42011da177e4SLinus Torvalds 
42021da177e4SLinus Torvalds 			case READ_CAPACITY:
42031da177e4SLinus Torvalds 				if (ips_online(ha, scb))
42041da177e4SLinus Torvalds 					ips_rdcap(ha, scb);
42051da177e4SLinus Torvalds 				else {
42061da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
42071da177e4SLinus Torvalds 				}
42081da177e4SLinus Torvalds 				break;
42091da177e4SLinus Torvalds 
42101da177e4SLinus Torvalds 			case SEND_DIAGNOSTIC:
42111da177e4SLinus Torvalds 			case REASSIGN_BLOCKS:
42121da177e4SLinus Torvalds 				break;
42131da177e4SLinus Torvalds 
42141da177e4SLinus Torvalds 			case FORMAT_UNIT:
42151da177e4SLinus Torvalds 				errcode = DID_ERROR;
42161da177e4SLinus Torvalds 				break;
42171da177e4SLinus Torvalds 
42181da177e4SLinus Torvalds 			case SEEK_10:
42191da177e4SLinus Torvalds 			case VERIFY:
42201da177e4SLinus Torvalds 			case READ_DEFECT_DATA:
42211da177e4SLinus Torvalds 			case READ_BUFFER:
42221da177e4SLinus Torvalds 			case WRITE_BUFFER:
42231da177e4SLinus Torvalds 				break;
42241da177e4SLinus Torvalds 
42251da177e4SLinus Torvalds 			default:
42261da177e4SLinus Torvalds 				errcode = DID_ERROR;
42271da177e4SLinus Torvalds 			}	/* end switch */
42281da177e4SLinus Torvalds 
42291da177e4SLinus Torvalds 			scb->scsi_cmd->result = errcode << 16;
42301da177e4SLinus Torvalds 		} else {	/* bus == 0 */
42311da177e4SLinus Torvalds 			/* restrict access to physical drives */
42321da177e4SLinus Torvalds 			if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
42331da177e4SLinus Torvalds 			    ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) ==
42341da177e4SLinus Torvalds 			     TYPE_DISK)) {
42351da177e4SLinus Torvalds 
42361da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_TIME_OUT << 16;
42371da177e4SLinus Torvalds 			}
42381da177e4SLinus Torvalds 		}		/* else */
42391da177e4SLinus Torvalds 	} else {		/* recovered error / success */
42401da177e4SLinus Torvalds 		if (scb->bus == 0) {
42411da177e4SLinus Torvalds 			DEBUG_VAR(1,
42421da177e4SLinus Torvalds 				  "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
42431da177e4SLinus Torvalds 				  ips_name, ha->host_num,
42441da177e4SLinus Torvalds 				  scb->cmd.basic_io.op_code, basic_status,
42451da177e4SLinus Torvalds 				  ext_status);
42461da177e4SLinus Torvalds 		}
42471da177e4SLinus Torvalds 
42481da177e4SLinus Torvalds 		ips_map_status(ha, scb, sp);
42491da177e4SLinus Torvalds 	}			/* else */
42501da177e4SLinus Torvalds }
42511da177e4SLinus Torvalds 
42521da177e4SLinus Torvalds /****************************************************************************/
42531da177e4SLinus Torvalds /*                                                                          */
42541da177e4SLinus Torvalds /* Routine Name: ips_online                                                 */
42551da177e4SLinus Torvalds /*                                                                          */
42561da177e4SLinus Torvalds /* Routine Description:                                                     */
42571da177e4SLinus Torvalds /*                                                                          */
42581da177e4SLinus Torvalds /*   Determine if a logical drive is online                                 */
42591da177e4SLinus Torvalds /*                                                                          */
42601da177e4SLinus Torvalds /****************************************************************************/
42611da177e4SLinus Torvalds static int
42621da177e4SLinus Torvalds ips_online(ips_ha_t * ha, ips_scb_t * scb)
42631da177e4SLinus Torvalds {
42641da177e4SLinus Torvalds 	METHOD_TRACE("ips_online", 1);
42651da177e4SLinus Torvalds 
42661da177e4SLinus Torvalds 	if (scb->target_id >= IPS_MAX_LD)
42671da177e4SLinus Torvalds 		return (0);
42681da177e4SLinus Torvalds 
42691da177e4SLinus Torvalds 	if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) {
42701da177e4SLinus Torvalds 		memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO));
42711da177e4SLinus Torvalds 		return (0);
42721da177e4SLinus Torvalds 	}
42731da177e4SLinus Torvalds 
42741da177e4SLinus Torvalds 	if (ha->logical_drive_info->drive_info[scb->target_id].state !=
42751da177e4SLinus Torvalds 	    IPS_LD_OFFLINE
42761da177e4SLinus Torvalds 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
42771da177e4SLinus Torvalds 	    IPS_LD_FREE
42781da177e4SLinus Torvalds 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
42791da177e4SLinus Torvalds 	    IPS_LD_CRS
42801da177e4SLinus Torvalds 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
42811da177e4SLinus Torvalds 	    IPS_LD_SYS)
42821da177e4SLinus Torvalds 		return (1);
42831da177e4SLinus Torvalds 	else
42841da177e4SLinus Torvalds 		return (0);
42851da177e4SLinus Torvalds }
42861da177e4SLinus Torvalds 
42871da177e4SLinus Torvalds /****************************************************************************/
42881da177e4SLinus Torvalds /*                                                                          */
42891da177e4SLinus Torvalds /* Routine Name: ips_inquiry                                                */
42901da177e4SLinus Torvalds /*                                                                          */
42911da177e4SLinus Torvalds /* Routine Description:                                                     */
42921da177e4SLinus Torvalds /*                                                                          */
42931da177e4SLinus Torvalds /*   Simulate an inquiry command to a logical drive                         */
42941da177e4SLinus Torvalds /*                                                                          */
42951da177e4SLinus Torvalds /****************************************************************************/
42961da177e4SLinus Torvalds static int
42971da177e4SLinus Torvalds ips_inquiry(ips_ha_t * ha, ips_scb_t * scb)
42981da177e4SLinus Torvalds {
42991da177e4SLinus Torvalds 	IPS_SCSI_INQ_DATA inquiry;
43001da177e4SLinus Torvalds 
43011da177e4SLinus Torvalds 	METHOD_TRACE("ips_inquiry", 1);
43021da177e4SLinus Torvalds 
43031da177e4SLinus Torvalds 	memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA));
43041da177e4SLinus Torvalds 
43051da177e4SLinus Torvalds 	inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD;
43061da177e4SLinus Torvalds 	inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
43071da177e4SLinus Torvalds 	inquiry.Version = IPS_SCSI_INQ_REV2;
43081da177e4SLinus Torvalds 	inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
43091da177e4SLinus Torvalds 	inquiry.AdditionalLength = 31;
43101da177e4SLinus Torvalds 	inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
43111da177e4SLinus Torvalds 	inquiry.Flags[1] =
43121da177e4SLinus Torvalds 	    IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue;
43131da177e4SLinus Torvalds 	strncpy(inquiry.VendorId, "IBM     ", 8);
43141da177e4SLinus Torvalds 	strncpy(inquiry.ProductId, "SERVERAID       ", 16);
43151da177e4SLinus Torvalds 	strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
43161da177e4SLinus Torvalds 
43171da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry));
43181da177e4SLinus Torvalds 
43191da177e4SLinus Torvalds 	return (1);
43201da177e4SLinus Torvalds }
43211da177e4SLinus Torvalds 
43221da177e4SLinus Torvalds /****************************************************************************/
43231da177e4SLinus Torvalds /*                                                                          */
43241da177e4SLinus Torvalds /* Routine Name: ips_rdcap                                                  */
43251da177e4SLinus Torvalds /*                                                                          */
43261da177e4SLinus Torvalds /* Routine Description:                                                     */
43271da177e4SLinus Torvalds /*                                                                          */
43281da177e4SLinus Torvalds /*   Simulate a read capacity command to a logical drive                    */
43291da177e4SLinus Torvalds /*                                                                          */
43301da177e4SLinus Torvalds /****************************************************************************/
43311da177e4SLinus Torvalds static int
43321da177e4SLinus Torvalds ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
43331da177e4SLinus Torvalds {
43341da177e4SLinus Torvalds 	IPS_SCSI_CAPACITY cap;
43351da177e4SLinus Torvalds 
43361da177e4SLinus Torvalds 	METHOD_TRACE("ips_rdcap", 1);
43371da177e4SLinus Torvalds 
43381da177e4SLinus Torvalds 	if (scb->scsi_cmd->bufflen < 8)
43391da177e4SLinus Torvalds 		return (0);
43401da177e4SLinus Torvalds 
43411da177e4SLinus Torvalds 	cap.lba =
43421da177e4SLinus Torvalds 	    cpu_to_be32(le32_to_cpu
43431da177e4SLinus Torvalds 			(ha->logical_drive_info->
43441da177e4SLinus Torvalds 			 drive_info[scb->target_id].sector_count) - 1);
43451da177e4SLinus Torvalds 	cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
43461da177e4SLinus Torvalds 
43471da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap));
43481da177e4SLinus Torvalds 
43491da177e4SLinus Torvalds 	return (1);
43501da177e4SLinus Torvalds }
43511da177e4SLinus Torvalds 
43521da177e4SLinus Torvalds /****************************************************************************/
43531da177e4SLinus Torvalds /*                                                                          */
43541da177e4SLinus Torvalds /* Routine Name: ips_msense                                                 */
43551da177e4SLinus Torvalds /*                                                                          */
43561da177e4SLinus Torvalds /* Routine Description:                                                     */
43571da177e4SLinus Torvalds /*                                                                          */
43581da177e4SLinus Torvalds /*   Simulate a mode sense command to a logical drive                       */
43591da177e4SLinus Torvalds /*                                                                          */
43601da177e4SLinus Torvalds /****************************************************************************/
43611da177e4SLinus Torvalds static int
43621da177e4SLinus Torvalds ips_msense(ips_ha_t * ha, ips_scb_t * scb)
43631da177e4SLinus Torvalds {
43641da177e4SLinus Torvalds 	uint16_t heads;
43651da177e4SLinus Torvalds 	uint16_t sectors;
43661da177e4SLinus Torvalds 	uint32_t cylinders;
43671da177e4SLinus Torvalds 	IPS_SCSI_MODE_PAGE_DATA mdata;
43681da177e4SLinus Torvalds 
43691da177e4SLinus Torvalds 	METHOD_TRACE("ips_msense", 1);
43701da177e4SLinus Torvalds 
43711da177e4SLinus Torvalds 	if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 &&
43721da177e4SLinus Torvalds 	    (ha->enq->ucMiscFlag & 0x8) == 0) {
43731da177e4SLinus Torvalds 		heads = IPS_NORM_HEADS;
43741da177e4SLinus Torvalds 		sectors = IPS_NORM_SECTORS;
43751da177e4SLinus Torvalds 	} else {
43761da177e4SLinus Torvalds 		heads = IPS_COMP_HEADS;
43771da177e4SLinus Torvalds 		sectors = IPS_COMP_SECTORS;
43781da177e4SLinus Torvalds 	}
43791da177e4SLinus Torvalds 
43801da177e4SLinus Torvalds 	cylinders =
43811da177e4SLinus Torvalds 	    (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) -
43821da177e4SLinus Torvalds 	     1) / (heads * sectors);
43831da177e4SLinus Torvalds 
43841da177e4SLinus Torvalds 	memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA));
43851da177e4SLinus Torvalds 
43861da177e4SLinus Torvalds 	mdata.hdr.BlockDescLength = 8;
43871da177e4SLinus Torvalds 
43881da177e4SLinus Torvalds 	switch (scb->scsi_cmd->cmnd[2] & 0x3f) {
43891da177e4SLinus Torvalds 	case 0x03:		/* page 3 */
43901da177e4SLinus Torvalds 		mdata.pdata.pg3.PageCode = 3;
43911da177e4SLinus Torvalds 		mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3);
43921da177e4SLinus Torvalds 		mdata.hdr.DataLength =
43931da177e4SLinus Torvalds 		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength;
43941da177e4SLinus Torvalds 		mdata.pdata.pg3.TracksPerZone = 0;
43951da177e4SLinus Torvalds 		mdata.pdata.pg3.AltSectorsPerZone = 0;
43961da177e4SLinus Torvalds 		mdata.pdata.pg3.AltTracksPerZone = 0;
43971da177e4SLinus Torvalds 		mdata.pdata.pg3.AltTracksPerVolume = 0;
43981da177e4SLinus Torvalds 		mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors);
43991da177e4SLinus Torvalds 		mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE);
44001da177e4SLinus Torvalds 		mdata.pdata.pg3.Interleave = cpu_to_be16(1);
44011da177e4SLinus Torvalds 		mdata.pdata.pg3.TrackSkew = 0;
44021da177e4SLinus Torvalds 		mdata.pdata.pg3.CylinderSkew = 0;
44031da177e4SLinus Torvalds 		mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector;
44041da177e4SLinus Torvalds 		break;
44051da177e4SLinus Torvalds 
44061da177e4SLinus Torvalds 	case 0x4:
44071da177e4SLinus Torvalds 		mdata.pdata.pg4.PageCode = 4;
44081da177e4SLinus Torvalds 		mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4);
44091da177e4SLinus Torvalds 		mdata.hdr.DataLength =
44101da177e4SLinus Torvalds 		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength;
44111da177e4SLinus Torvalds 		mdata.pdata.pg4.CylindersHigh =
44121da177e4SLinus Torvalds 		    cpu_to_be16((cylinders >> 8) & 0xFFFF);
44131da177e4SLinus Torvalds 		mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF);
44141da177e4SLinus Torvalds 		mdata.pdata.pg4.Heads = heads;
44151da177e4SLinus Torvalds 		mdata.pdata.pg4.WritePrecompHigh = 0;
44161da177e4SLinus Torvalds 		mdata.pdata.pg4.WritePrecompLow = 0;
44171da177e4SLinus Torvalds 		mdata.pdata.pg4.ReducedWriteCurrentHigh = 0;
44181da177e4SLinus Torvalds 		mdata.pdata.pg4.ReducedWriteCurrentLow = 0;
44191da177e4SLinus Torvalds 		mdata.pdata.pg4.StepRate = cpu_to_be16(1);
44201da177e4SLinus Torvalds 		mdata.pdata.pg4.LandingZoneHigh = 0;
44211da177e4SLinus Torvalds 		mdata.pdata.pg4.LandingZoneLow = 0;
44221da177e4SLinus Torvalds 		mdata.pdata.pg4.flags = 0;
44231da177e4SLinus Torvalds 		mdata.pdata.pg4.RotationalOffset = 0;
44241da177e4SLinus Torvalds 		mdata.pdata.pg4.MediumRotationRate = 0;
44251da177e4SLinus Torvalds 		break;
44261da177e4SLinus Torvalds 	case 0x8:
44271da177e4SLinus Torvalds 		mdata.pdata.pg8.PageCode = 8;
44281da177e4SLinus Torvalds 		mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8);
44291da177e4SLinus Torvalds 		mdata.hdr.DataLength =
44301da177e4SLinus Torvalds 		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength;
44311da177e4SLinus Torvalds 		/* everything else is left set to 0 */
44321da177e4SLinus Torvalds 		break;
44331da177e4SLinus Torvalds 
44341da177e4SLinus Torvalds 	default:
44351da177e4SLinus Torvalds 		return (0);
44361da177e4SLinus Torvalds 	}			/* end switch */
44371da177e4SLinus Torvalds 
44381da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata));
44391da177e4SLinus Torvalds 
44401da177e4SLinus Torvalds 	return (1);
44411da177e4SLinus Torvalds }
44421da177e4SLinus Torvalds 
44431da177e4SLinus Torvalds /****************************************************************************/
44441da177e4SLinus Torvalds /*                                                                          */
44451da177e4SLinus Torvalds /* Routine Name: ips_reqsen                                                 */
44461da177e4SLinus Torvalds /*                                                                          */
44471da177e4SLinus Torvalds /* Routine Description:                                                     */
44481da177e4SLinus Torvalds /*                                                                          */
44491da177e4SLinus Torvalds /*   Simulate a request sense command to a logical drive                    */
44501da177e4SLinus Torvalds /*                                                                          */
44511da177e4SLinus Torvalds /****************************************************************************/
44521da177e4SLinus Torvalds static int
44531da177e4SLinus Torvalds ips_reqsen(ips_ha_t * ha, ips_scb_t * scb)
44541da177e4SLinus Torvalds {
44551da177e4SLinus Torvalds 	IPS_SCSI_REQSEN reqsen;
44561da177e4SLinus Torvalds 
44571da177e4SLinus Torvalds 	METHOD_TRACE("ips_reqsen", 1);
44581da177e4SLinus Torvalds 
44591da177e4SLinus Torvalds 	memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN));
44601da177e4SLinus Torvalds 
44611da177e4SLinus Torvalds 	reqsen.ResponseCode =
44621da177e4SLinus Torvalds 	    IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR;
44631da177e4SLinus Torvalds 	reqsen.AdditionalLength = 10;
44641da177e4SLinus Torvalds 	reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE;
44651da177e4SLinus Torvalds 	reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE;
44661da177e4SLinus Torvalds 
44671da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen));
44681da177e4SLinus Torvalds 
44691da177e4SLinus Torvalds 	return (1);
44701da177e4SLinus Torvalds }
44711da177e4SLinus Torvalds 
44721da177e4SLinus Torvalds /****************************************************************************/
44731da177e4SLinus Torvalds /*                                                                          */
44741da177e4SLinus Torvalds /* Routine Name: ips_free                                                   */
44751da177e4SLinus Torvalds /*                                                                          */
44761da177e4SLinus Torvalds /* Routine Description:                                                     */
44771da177e4SLinus Torvalds /*                                                                          */
44781da177e4SLinus Torvalds /*   Free any allocated space for this controller                           */
44791da177e4SLinus Torvalds /*                                                                          */
44801da177e4SLinus Torvalds /****************************************************************************/
44811da177e4SLinus Torvalds static void
44821da177e4SLinus Torvalds ips_free(ips_ha_t * ha)
44831da177e4SLinus Torvalds {
44841da177e4SLinus Torvalds 
44851da177e4SLinus Torvalds 	METHOD_TRACE("ips_free", 1);
44861da177e4SLinus Torvalds 
44871da177e4SLinus Torvalds 	if (ha) {
44881da177e4SLinus Torvalds 		if (ha->enq) {
44891da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ),
44901da177e4SLinus Torvalds 					    ha->enq, ha->enq_busaddr);
44911da177e4SLinus Torvalds 			ha->enq = NULL;
44921da177e4SLinus Torvalds 		}
44931da177e4SLinus Torvalds 
44941da177e4SLinus Torvalds 		if (ha->conf) {
44951da177e4SLinus Torvalds 			kfree(ha->conf);
44961da177e4SLinus Torvalds 			ha->conf = NULL;
44971da177e4SLinus Torvalds 		}
44981da177e4SLinus Torvalds 
44991da177e4SLinus Torvalds 		if (ha->adapt) {
45001da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev,
45011da177e4SLinus Torvalds 					    sizeof (IPS_ADAPTER) +
45021da177e4SLinus Torvalds 					    sizeof (IPS_IO_CMD), ha->adapt,
45031da177e4SLinus Torvalds 					    ha->adapt->hw_status_start);
45041da177e4SLinus Torvalds 			ha->adapt = NULL;
45051da177e4SLinus Torvalds 		}
45061da177e4SLinus Torvalds 
45071da177e4SLinus Torvalds 		if (ha->logical_drive_info) {
45081da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev,
45091da177e4SLinus Torvalds 					    sizeof (IPS_LD_INFO),
45101da177e4SLinus Torvalds 					    ha->logical_drive_info,
45111da177e4SLinus Torvalds 					    ha->logical_drive_info_dma_addr);
45121da177e4SLinus Torvalds 			ha->logical_drive_info = NULL;
45131da177e4SLinus Torvalds 		}
45141da177e4SLinus Torvalds 
45151da177e4SLinus Torvalds 		if (ha->nvram) {
45161da177e4SLinus Torvalds 			kfree(ha->nvram);
45171da177e4SLinus Torvalds 			ha->nvram = NULL;
45181da177e4SLinus Torvalds 		}
45191da177e4SLinus Torvalds 
45201da177e4SLinus Torvalds 		if (ha->subsys) {
45211da177e4SLinus Torvalds 			kfree(ha->subsys);
45221da177e4SLinus Torvalds 			ha->subsys = NULL;
45231da177e4SLinus Torvalds 		}
45241da177e4SLinus Torvalds 
45251da177e4SLinus Torvalds 		if (ha->ioctl_data) {
45261da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev, ha->ioctl_len,
45271da177e4SLinus Torvalds 					    ha->ioctl_data, ha->ioctl_busaddr);
45281da177e4SLinus Torvalds 			ha->ioctl_data = NULL;
45291da177e4SLinus Torvalds 			ha->ioctl_datasize = 0;
45301da177e4SLinus Torvalds 			ha->ioctl_len = 0;
45311da177e4SLinus Torvalds 		}
45321da177e4SLinus Torvalds 		ips_deallocatescbs(ha, ha->max_cmds);
45331da177e4SLinus Torvalds 
45341da177e4SLinus Torvalds 		/* free memory mapped (if applicable) */
45351da177e4SLinus Torvalds 		if (ha->mem_ptr) {
45361da177e4SLinus Torvalds 			iounmap(ha->ioremap_ptr);
45371da177e4SLinus Torvalds 			ha->ioremap_ptr = NULL;
45381da177e4SLinus Torvalds 			ha->mem_ptr = NULL;
45391da177e4SLinus Torvalds 		}
45401da177e4SLinus Torvalds 
45411da177e4SLinus Torvalds 		if (ha->mem_addr)
45421da177e4SLinus Torvalds 			release_mem_region(ha->mem_addr, ha->mem_len);
45431da177e4SLinus Torvalds 		ha->mem_addr = 0;
45441da177e4SLinus Torvalds 
45451da177e4SLinus Torvalds 	}
45461da177e4SLinus Torvalds }
45471da177e4SLinus Torvalds 
45481da177e4SLinus Torvalds /****************************************************************************/
45491da177e4SLinus Torvalds /*                                                                          */
45501da177e4SLinus Torvalds /* Routine Name: ips_deallocatescbs                                         */
45511da177e4SLinus Torvalds /*                                                                          */
45521da177e4SLinus Torvalds /* Routine Description:                                                     */
45531da177e4SLinus Torvalds /*                                                                          */
45541da177e4SLinus Torvalds /*   Free the command blocks                                                */
45551da177e4SLinus Torvalds /*                                                                          */
45561da177e4SLinus Torvalds /****************************************************************************/
45571da177e4SLinus Torvalds static int
45581da177e4SLinus Torvalds ips_deallocatescbs(ips_ha_t * ha, int cmds)
45591da177e4SLinus Torvalds {
45601da177e4SLinus Torvalds 	if (ha->scbs) {
45611da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev,
45621da177e4SLinus Torvalds 				    IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds,
45631da177e4SLinus Torvalds 				    ha->scbs->sg_list.list,
45641da177e4SLinus Torvalds 				    ha->scbs->sg_busaddr);
45651da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds,
45661da177e4SLinus Torvalds 				    ha->scbs, ha->scbs->scb_busaddr);
45671da177e4SLinus Torvalds 		ha->scbs = NULL;
45681da177e4SLinus Torvalds 	}			/* end if */
45691da177e4SLinus Torvalds 	return 1;
45701da177e4SLinus Torvalds }
45711da177e4SLinus Torvalds 
45721da177e4SLinus Torvalds /****************************************************************************/
45731da177e4SLinus Torvalds /*                                                                          */
45741da177e4SLinus Torvalds /* Routine Name: ips_allocatescbs                                           */
45751da177e4SLinus Torvalds /*                                                                          */
45761da177e4SLinus Torvalds /* Routine Description:                                                     */
45771da177e4SLinus Torvalds /*                                                                          */
45781da177e4SLinus Torvalds /*   Allocate the command blocks                                            */
45791da177e4SLinus Torvalds /*                                                                          */
45801da177e4SLinus Torvalds /****************************************************************************/
45811da177e4SLinus Torvalds static int
45821da177e4SLinus Torvalds ips_allocatescbs(ips_ha_t * ha)
45831da177e4SLinus Torvalds {
45841da177e4SLinus Torvalds 	ips_scb_t *scb_p;
45851da177e4SLinus Torvalds 	IPS_SG_LIST ips_sg;
45861da177e4SLinus Torvalds 	int i;
45871da177e4SLinus Torvalds 	dma_addr_t command_dma, sg_dma;
45881da177e4SLinus Torvalds 
45891da177e4SLinus Torvalds 	METHOD_TRACE("ips_allocatescbs", 1);
45901da177e4SLinus Torvalds 
45911da177e4SLinus Torvalds 	/* Allocate memory for the SCBs */
45921da177e4SLinus Torvalds 	ha->scbs =
45931da177e4SLinus Torvalds 	    pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t),
45941da177e4SLinus Torvalds 				 &command_dma);
45951da177e4SLinus Torvalds 	if (ha->scbs == NULL)
45961da177e4SLinus Torvalds 		return 0;
45971da177e4SLinus Torvalds 	ips_sg.list =
45981da177e4SLinus Torvalds 	    pci_alloc_consistent(ha->pcidev,
45991da177e4SLinus Torvalds 				 IPS_SGLIST_SIZE(ha) * IPS_MAX_SG *
46001da177e4SLinus Torvalds 				 ha->max_cmds, &sg_dma);
46011da177e4SLinus Torvalds 	if (ips_sg.list == NULL) {
46021da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev,
46031da177e4SLinus Torvalds 				    ha->max_cmds * sizeof (ips_scb_t), ha->scbs,
46041da177e4SLinus Torvalds 				    command_dma);
46051da177e4SLinus Torvalds 		return 0;
46061da177e4SLinus Torvalds 	}
46071da177e4SLinus Torvalds 
46081da177e4SLinus Torvalds 	memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t));
46091da177e4SLinus Torvalds 
46101da177e4SLinus Torvalds 	for (i = 0; i < ha->max_cmds; i++) {
46111da177e4SLinus Torvalds 		scb_p = &ha->scbs[i];
46121da177e4SLinus Torvalds 		scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i;
46131da177e4SLinus Torvalds 		/* set up S/G list */
46141da177e4SLinus Torvalds 		if (IPS_USE_ENH_SGLIST(ha)) {
46151da177e4SLinus Torvalds 			scb_p->sg_list.enh_list =
46161da177e4SLinus Torvalds 			    ips_sg.enh_list + i * IPS_MAX_SG;
46171da177e4SLinus Torvalds 			scb_p->sg_busaddr =
46181da177e4SLinus Torvalds 			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
46191da177e4SLinus Torvalds 		} else {
46201da177e4SLinus Torvalds 			scb_p->sg_list.std_list =
46211da177e4SLinus Torvalds 			    ips_sg.std_list + i * IPS_MAX_SG;
46221da177e4SLinus Torvalds 			scb_p->sg_busaddr =
46231da177e4SLinus Torvalds 			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
46241da177e4SLinus Torvalds 		}
46251da177e4SLinus Torvalds 
46261da177e4SLinus Torvalds 		/* add to the free list */
46271da177e4SLinus Torvalds 		if (i < ha->max_cmds - 1) {
46281da177e4SLinus Torvalds 			scb_p->q_next = ha->scb_freelist;
46291da177e4SLinus Torvalds 			ha->scb_freelist = scb_p;
46301da177e4SLinus Torvalds 		}
46311da177e4SLinus Torvalds 	}
46321da177e4SLinus Torvalds 
46331da177e4SLinus Torvalds 	/* success */
46341da177e4SLinus Torvalds 	return (1);
46351da177e4SLinus Torvalds }
46361da177e4SLinus Torvalds 
46371da177e4SLinus Torvalds /****************************************************************************/
46381da177e4SLinus Torvalds /*                                                                          */
46391da177e4SLinus Torvalds /* Routine Name: ips_init_scb                                               */
46401da177e4SLinus Torvalds /*                                                                          */
46411da177e4SLinus Torvalds /* Routine Description:                                                     */
46421da177e4SLinus Torvalds /*                                                                          */
46431da177e4SLinus Torvalds /*   Initialize a CCB to default values                                     */
46441da177e4SLinus Torvalds /*                                                                          */
46451da177e4SLinus Torvalds /****************************************************************************/
46461da177e4SLinus Torvalds static void
46471da177e4SLinus Torvalds ips_init_scb(ips_ha_t * ha, ips_scb_t * scb)
46481da177e4SLinus Torvalds {
46491da177e4SLinus Torvalds 	IPS_SG_LIST sg_list;
46501da177e4SLinus Torvalds 	uint32_t cmd_busaddr, sg_busaddr;
46511da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_scb", 1);
46521da177e4SLinus Torvalds 
46531da177e4SLinus Torvalds 	if (scb == NULL)
46541da177e4SLinus Torvalds 		return;
46551da177e4SLinus Torvalds 
46561da177e4SLinus Torvalds 	sg_list.list = scb->sg_list.list;
46571da177e4SLinus Torvalds 	cmd_busaddr = scb->scb_busaddr;
46581da177e4SLinus Torvalds 	sg_busaddr = scb->sg_busaddr;
46591da177e4SLinus Torvalds 	/* zero fill */
46601da177e4SLinus Torvalds 	memset(scb, 0, sizeof (ips_scb_t));
46611da177e4SLinus Torvalds 	memset(ha->dummy, 0, sizeof (IPS_IO_CMD));
46621da177e4SLinus Torvalds 
46631da177e4SLinus Torvalds 	/* Initialize dummy command bucket */
46641da177e4SLinus Torvalds 	ha->dummy->op_code = 0xFF;
46651da177e4SLinus Torvalds 	ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
46661da177e4SLinus Torvalds 				       + sizeof (IPS_ADAPTER));
46671da177e4SLinus Torvalds 	ha->dummy->command_id = IPS_MAX_CMDS;
46681da177e4SLinus Torvalds 
46691da177e4SLinus Torvalds 	/* set bus address of scb */
46701da177e4SLinus Torvalds 	scb->scb_busaddr = cmd_busaddr;
46711da177e4SLinus Torvalds 	scb->sg_busaddr = sg_busaddr;
46721da177e4SLinus Torvalds 	scb->sg_list.list = sg_list.list;
46731da177e4SLinus Torvalds 
46741da177e4SLinus Torvalds 	/* Neptune Fix */
46751da177e4SLinus Torvalds 	scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
46761da177e4SLinus Torvalds 	scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
46771da177e4SLinus Torvalds 					      + sizeof (IPS_ADAPTER));
46781da177e4SLinus Torvalds }
46791da177e4SLinus Torvalds 
46801da177e4SLinus Torvalds /****************************************************************************/
46811da177e4SLinus Torvalds /*                                                                          */
46821da177e4SLinus Torvalds /* Routine Name: ips_get_scb                                                */
46831da177e4SLinus Torvalds /*                                                                          */
46841da177e4SLinus Torvalds /* Routine Description:                                                     */
46851da177e4SLinus Torvalds /*                                                                          */
46861da177e4SLinus Torvalds /*   Initialize a CCB to default values                                     */
46871da177e4SLinus Torvalds /*                                                                          */
46881da177e4SLinus Torvalds /* ASSUMED to be callled from within a lock                                 */
46891da177e4SLinus Torvalds /*                                                                          */
46901da177e4SLinus Torvalds /****************************************************************************/
46911da177e4SLinus Torvalds static ips_scb_t *
46921da177e4SLinus Torvalds ips_getscb(ips_ha_t * ha)
46931da177e4SLinus Torvalds {
46941da177e4SLinus Torvalds 	ips_scb_t *scb;
46951da177e4SLinus Torvalds 
46961da177e4SLinus Torvalds 	METHOD_TRACE("ips_getscb", 1);
46971da177e4SLinus Torvalds 
46981da177e4SLinus Torvalds 	if ((scb = ha->scb_freelist) == NULL) {
46991da177e4SLinus Torvalds 
47001da177e4SLinus Torvalds 		return (NULL);
47011da177e4SLinus Torvalds 	}
47021da177e4SLinus Torvalds 
47031da177e4SLinus Torvalds 	ha->scb_freelist = scb->q_next;
47041da177e4SLinus Torvalds 	scb->flags = 0;
47051da177e4SLinus Torvalds 	scb->q_next = NULL;
47061da177e4SLinus Torvalds 
47071da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
47081da177e4SLinus Torvalds 
47091da177e4SLinus Torvalds 	return (scb);
47101da177e4SLinus Torvalds }
47111da177e4SLinus Torvalds 
47121da177e4SLinus Torvalds /****************************************************************************/
47131da177e4SLinus Torvalds /*                                                                          */
47141da177e4SLinus Torvalds /* Routine Name: ips_free_scb                                               */
47151da177e4SLinus Torvalds /*                                                                          */
47161da177e4SLinus Torvalds /* Routine Description:                                                     */
47171da177e4SLinus Torvalds /*                                                                          */
47181da177e4SLinus Torvalds /*   Return an unused CCB back to the free list                             */
47191da177e4SLinus Torvalds /*                                                                          */
47201da177e4SLinus Torvalds /* ASSUMED to be called from within a lock                                  */
47211da177e4SLinus Torvalds /*                                                                          */
47221da177e4SLinus Torvalds /****************************************************************************/
47231da177e4SLinus Torvalds static void
47241da177e4SLinus Torvalds ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
47251da177e4SLinus Torvalds {
47261da177e4SLinus Torvalds 
47271da177e4SLinus Torvalds 	METHOD_TRACE("ips_freescb", 1);
47281da177e4SLinus Torvalds 	if (scb->flags & IPS_SCB_MAP_SG)
47291da177e4SLinus Torvalds 		pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
47301da177e4SLinus Torvalds 			     scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb));
47311da177e4SLinus Torvalds 	else if (scb->flags & IPS_SCB_MAP_SINGLE)
47321da177e4SLinus Torvalds 		pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
47331da177e4SLinus Torvalds 				 IPS_DMA_DIR(scb));
47341da177e4SLinus Torvalds 
47351da177e4SLinus Torvalds 	/* check to make sure this is not our "special" scb */
47361da177e4SLinus Torvalds 	if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
47371da177e4SLinus Torvalds 		scb->q_next = ha->scb_freelist;
47381da177e4SLinus Torvalds 		ha->scb_freelist = scb;
47391da177e4SLinus Torvalds 	}
47401da177e4SLinus Torvalds }
47411da177e4SLinus Torvalds 
47421da177e4SLinus Torvalds /****************************************************************************/
47431da177e4SLinus Torvalds /*                                                                          */
47441da177e4SLinus Torvalds /* Routine Name: ips_isinit_copperhead                                      */
47451da177e4SLinus Torvalds /*                                                                          */
47461da177e4SLinus Torvalds /* Routine Description:                                                     */
47471da177e4SLinus Torvalds /*                                                                          */
47481da177e4SLinus Torvalds /*   Is controller initialized ?                                            */
47491da177e4SLinus Torvalds /*                                                                          */
47501da177e4SLinus Torvalds /****************************************************************************/
47511da177e4SLinus Torvalds static int
47521da177e4SLinus Torvalds ips_isinit_copperhead(ips_ha_t * ha)
47531da177e4SLinus Torvalds {
47541da177e4SLinus Torvalds 	uint8_t scpr;
47551da177e4SLinus Torvalds 	uint8_t isr;
47561da177e4SLinus Torvalds 
47571da177e4SLinus Torvalds 	METHOD_TRACE("ips_isinit_copperhead", 1);
47581da177e4SLinus Torvalds 
47591da177e4SLinus Torvalds 	isr = inb(ha->io_addr + IPS_REG_HISR);
47601da177e4SLinus Torvalds 	scpr = inb(ha->io_addr + IPS_REG_SCPR);
47611da177e4SLinus Torvalds 
47621da177e4SLinus Torvalds 	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
47631da177e4SLinus Torvalds 		return (0);
47641da177e4SLinus Torvalds 	else
47651da177e4SLinus Torvalds 		return (1);
47661da177e4SLinus Torvalds }
47671da177e4SLinus Torvalds 
47681da177e4SLinus Torvalds /****************************************************************************/
47691da177e4SLinus Torvalds /*                                                                          */
47701da177e4SLinus Torvalds /* Routine Name: ips_isinit_copperhead_memio                                */
47711da177e4SLinus Torvalds /*                                                                          */
47721da177e4SLinus Torvalds /* Routine Description:                                                     */
47731da177e4SLinus Torvalds /*                                                                          */
47741da177e4SLinus Torvalds /*   Is controller initialized ?                                            */
47751da177e4SLinus Torvalds /*                                                                          */
47761da177e4SLinus Torvalds /****************************************************************************/
47771da177e4SLinus Torvalds static int
47781da177e4SLinus Torvalds ips_isinit_copperhead_memio(ips_ha_t * ha)
47791da177e4SLinus Torvalds {
47801da177e4SLinus Torvalds 	uint8_t isr = 0;
47811da177e4SLinus Torvalds 	uint8_t scpr;
47821da177e4SLinus Torvalds 
47831da177e4SLinus Torvalds 	METHOD_TRACE("ips_is_init_copperhead_memio", 1);
47841da177e4SLinus Torvalds 
47851da177e4SLinus Torvalds 	isr = readb(ha->mem_ptr + IPS_REG_HISR);
47861da177e4SLinus Torvalds 	scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
47871da177e4SLinus Torvalds 
47881da177e4SLinus Torvalds 	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
47891da177e4SLinus Torvalds 		return (0);
47901da177e4SLinus Torvalds 	else
47911da177e4SLinus Torvalds 		return (1);
47921da177e4SLinus Torvalds }
47931da177e4SLinus Torvalds 
47941da177e4SLinus Torvalds /****************************************************************************/
47951da177e4SLinus Torvalds /*                                                                          */
47961da177e4SLinus Torvalds /* Routine Name: ips_isinit_morpheus                                        */
47971da177e4SLinus Torvalds /*                                                                          */
47981da177e4SLinus Torvalds /* Routine Description:                                                     */
47991da177e4SLinus Torvalds /*                                                                          */
48001da177e4SLinus Torvalds /*   Is controller initialized ?                                            */
48011da177e4SLinus Torvalds /*                                                                          */
48021da177e4SLinus Torvalds /****************************************************************************/
48031da177e4SLinus Torvalds static int
48041da177e4SLinus Torvalds ips_isinit_morpheus(ips_ha_t * ha)
48051da177e4SLinus Torvalds {
48061da177e4SLinus Torvalds 	uint32_t post;
48071da177e4SLinus Torvalds 	uint32_t bits;
48081da177e4SLinus Torvalds 
48091da177e4SLinus Torvalds 	METHOD_TRACE("ips_is_init_morpheus", 1);
48101da177e4SLinus Torvalds 
48111da177e4SLinus Torvalds 	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
48121da177e4SLinus Torvalds 	bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
48131da177e4SLinus Torvalds 
48141da177e4SLinus Torvalds 	if (post == 0)
48151da177e4SLinus Torvalds 		return (0);
48161da177e4SLinus Torvalds 	else if (bits & 0x3)
48171da177e4SLinus Torvalds 		return (0);
48181da177e4SLinus Torvalds 	else
48191da177e4SLinus Torvalds 		return (1);
48201da177e4SLinus Torvalds }
48211da177e4SLinus Torvalds 
48221da177e4SLinus Torvalds /****************************************************************************/
48231da177e4SLinus Torvalds /*                                                                          */
48241da177e4SLinus Torvalds /* Routine Name: ips_enable_int_copperhead                                  */
48251da177e4SLinus Torvalds /*                                                                          */
48261da177e4SLinus Torvalds /* Routine Description:                                                     */
48271da177e4SLinus Torvalds /*   Turn on interrupts                                                     */
48281da177e4SLinus Torvalds /*                                                                          */
48291da177e4SLinus Torvalds /****************************************************************************/
48301da177e4SLinus Torvalds static void
48311da177e4SLinus Torvalds ips_enable_int_copperhead(ips_ha_t * ha)
48321da177e4SLinus Torvalds {
48331da177e4SLinus Torvalds 	METHOD_TRACE("ips_enable_int_copperhead", 1);
48341da177e4SLinus Torvalds 
48351da177e4SLinus Torvalds 	outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
48361da177e4SLinus Torvalds 	inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
48371da177e4SLinus Torvalds }
48381da177e4SLinus Torvalds 
48391da177e4SLinus Torvalds /****************************************************************************/
48401da177e4SLinus Torvalds /*                                                                          */
48411da177e4SLinus Torvalds /* Routine Name: ips_enable_int_copperhead_memio                            */
48421da177e4SLinus Torvalds /*                                                                          */
48431da177e4SLinus Torvalds /* Routine Description:                                                     */
48441da177e4SLinus Torvalds /*   Turn on interrupts                                                     */
48451da177e4SLinus Torvalds /*                                                                          */
48461da177e4SLinus Torvalds /****************************************************************************/
48471da177e4SLinus Torvalds static void
48481da177e4SLinus Torvalds ips_enable_int_copperhead_memio(ips_ha_t * ha)
48491da177e4SLinus Torvalds {
48501da177e4SLinus Torvalds 	METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
48511da177e4SLinus Torvalds 
48521da177e4SLinus Torvalds 	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
48531da177e4SLinus Torvalds 	readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
48541da177e4SLinus Torvalds }
48551da177e4SLinus Torvalds 
48561da177e4SLinus Torvalds /****************************************************************************/
48571da177e4SLinus Torvalds /*                                                                          */
48581da177e4SLinus Torvalds /* Routine Name: ips_enable_int_morpheus                                    */
48591da177e4SLinus Torvalds /*                                                                          */
48601da177e4SLinus Torvalds /* Routine Description:                                                     */
48611da177e4SLinus Torvalds /*   Turn on interrupts                                                     */
48621da177e4SLinus Torvalds /*                                                                          */
48631da177e4SLinus Torvalds /****************************************************************************/
48641da177e4SLinus Torvalds static void
48651da177e4SLinus Torvalds ips_enable_int_morpheus(ips_ha_t * ha)
48661da177e4SLinus Torvalds {
48671da177e4SLinus Torvalds 	uint32_t Oimr;
48681da177e4SLinus Torvalds 
48691da177e4SLinus Torvalds 	METHOD_TRACE("ips_enable_int_morpheus", 1);
48701da177e4SLinus Torvalds 
48711da177e4SLinus Torvalds 	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
48721da177e4SLinus Torvalds 	Oimr &= ~0x08;
48731da177e4SLinus Torvalds 	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
48741da177e4SLinus Torvalds 	readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/
48751da177e4SLinus Torvalds }
48761da177e4SLinus Torvalds 
48771da177e4SLinus Torvalds /****************************************************************************/
48781da177e4SLinus Torvalds /*                                                                          */
48791da177e4SLinus Torvalds /* Routine Name: ips_init_copperhead                                        */
48801da177e4SLinus Torvalds /*                                                                          */
48811da177e4SLinus Torvalds /* Routine Description:                                                     */
48821da177e4SLinus Torvalds /*                                                                          */
48831da177e4SLinus Torvalds /*   Initialize a copperhead controller                                     */
48841da177e4SLinus Torvalds /*                                                                          */
48851da177e4SLinus Torvalds /****************************************************************************/
48861da177e4SLinus Torvalds static int
48871da177e4SLinus Torvalds ips_init_copperhead(ips_ha_t * ha)
48881da177e4SLinus Torvalds {
48891da177e4SLinus Torvalds 	uint8_t Isr;
48901da177e4SLinus Torvalds 	uint8_t Cbsp;
48911da177e4SLinus Torvalds 	uint8_t PostByte[IPS_MAX_POST_BYTES];
48921da177e4SLinus Torvalds 	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
48931da177e4SLinus Torvalds 	int i, j;
48941da177e4SLinus Torvalds 
48951da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_copperhead", 1);
48961da177e4SLinus Torvalds 
48971da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
48981da177e4SLinus Torvalds 		for (j = 0; j < 45; j++) {
48991da177e4SLinus Torvalds 			Isr = inb(ha->io_addr + IPS_REG_HISR);
49001da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
49011da177e4SLinus Torvalds 				break;
49021da177e4SLinus Torvalds 
49031da177e4SLinus Torvalds 			/* Delay for 1 Second */
49041da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
49051da177e4SLinus Torvalds 		}
49061da177e4SLinus Torvalds 
49071da177e4SLinus Torvalds 		if (j >= 45)
49081da177e4SLinus Torvalds 			/* error occurred */
49091da177e4SLinus Torvalds 			return (0);
49101da177e4SLinus Torvalds 
49111da177e4SLinus Torvalds 		PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
49121da177e4SLinus Torvalds 		outb(Isr, ha->io_addr + IPS_REG_HISR);
49131da177e4SLinus Torvalds 	}
49141da177e4SLinus Torvalds 
49151da177e4SLinus Torvalds 	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
49161da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
49171da177e4SLinus Torvalds 			   "reset controller fails (post status %x %x).\n",
49181da177e4SLinus Torvalds 			   PostByte[0], PostByte[1]);
49191da177e4SLinus Torvalds 
49201da177e4SLinus Torvalds 		return (0);
49211da177e4SLinus Torvalds 	}
49221da177e4SLinus Torvalds 
49231da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
49241da177e4SLinus Torvalds 		for (j = 0; j < 240; j++) {
49251da177e4SLinus Torvalds 			Isr = inb(ha->io_addr + IPS_REG_HISR);
49261da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
49271da177e4SLinus Torvalds 				break;
49281da177e4SLinus Torvalds 
49291da177e4SLinus Torvalds 			/* Delay for 1 Second */
49301da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
49311da177e4SLinus Torvalds 		}
49321da177e4SLinus Torvalds 
49331da177e4SLinus Torvalds 		if (j >= 240)
49341da177e4SLinus Torvalds 			/* error occurred */
49351da177e4SLinus Torvalds 			return (0);
49361da177e4SLinus Torvalds 
49371da177e4SLinus Torvalds 		ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
49381da177e4SLinus Torvalds 		outb(Isr, ha->io_addr + IPS_REG_HISR);
49391da177e4SLinus Torvalds 	}
49401da177e4SLinus Torvalds 
49411da177e4SLinus Torvalds 	for (i = 0; i < 240; i++) {
49421da177e4SLinus Torvalds 		Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
49431da177e4SLinus Torvalds 
49441da177e4SLinus Torvalds 		if ((Cbsp & IPS_BIT_OP) == 0)
49451da177e4SLinus Torvalds 			break;
49461da177e4SLinus Torvalds 
49471da177e4SLinus Torvalds 		/* Delay for 1 Second */
49481da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
49491da177e4SLinus Torvalds 	}
49501da177e4SLinus Torvalds 
49511da177e4SLinus Torvalds 	if (i >= 240)
49521da177e4SLinus Torvalds 		/* reset failed */
49531da177e4SLinus Torvalds 		return (0);
49541da177e4SLinus Torvalds 
49551da177e4SLinus Torvalds 	/* setup CCCR */
49561da177e4SLinus Torvalds 	outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);
49571da177e4SLinus Torvalds 
49581da177e4SLinus Torvalds 	/* Enable busmastering */
49591da177e4SLinus Torvalds 	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
49601da177e4SLinus Torvalds 
49611da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
49621da177e4SLinus Torvalds 		/* fix for anaconda64 */
49631da177e4SLinus Torvalds 		outl(0, ha->io_addr + IPS_REG_NDAE);
49641da177e4SLinus Torvalds 
49651da177e4SLinus Torvalds 	/* Enable interrupts */
49661da177e4SLinus Torvalds 	outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
49671da177e4SLinus Torvalds 
49681da177e4SLinus Torvalds 	return (1);
49691da177e4SLinus Torvalds }
49701da177e4SLinus Torvalds 
49711da177e4SLinus Torvalds /****************************************************************************/
49721da177e4SLinus Torvalds /*                                                                          */
49731da177e4SLinus Torvalds /* Routine Name: ips_init_copperhead_memio                                  */
49741da177e4SLinus Torvalds /*                                                                          */
49751da177e4SLinus Torvalds /* Routine Description:                                                     */
49761da177e4SLinus Torvalds /*                                                                          */
49771da177e4SLinus Torvalds /*   Initialize a copperhead controller with memory mapped I/O              */
49781da177e4SLinus Torvalds /*                                                                          */
49791da177e4SLinus Torvalds /****************************************************************************/
49801da177e4SLinus Torvalds static int
49811da177e4SLinus Torvalds ips_init_copperhead_memio(ips_ha_t * ha)
49821da177e4SLinus Torvalds {
49831da177e4SLinus Torvalds 	uint8_t Isr = 0;
49841da177e4SLinus Torvalds 	uint8_t Cbsp;
49851da177e4SLinus Torvalds 	uint8_t PostByte[IPS_MAX_POST_BYTES];
49861da177e4SLinus Torvalds 	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
49871da177e4SLinus Torvalds 	int i, j;
49881da177e4SLinus Torvalds 
49891da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_copperhead_memio", 1);
49901da177e4SLinus Torvalds 
49911da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
49921da177e4SLinus Torvalds 		for (j = 0; j < 45; j++) {
49931da177e4SLinus Torvalds 			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
49941da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
49951da177e4SLinus Torvalds 				break;
49961da177e4SLinus Torvalds 
49971da177e4SLinus Torvalds 			/* Delay for 1 Second */
49981da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
49991da177e4SLinus Torvalds 		}
50001da177e4SLinus Torvalds 
50011da177e4SLinus Torvalds 		if (j >= 45)
50021da177e4SLinus Torvalds 			/* error occurred */
50031da177e4SLinus Torvalds 			return (0);
50041da177e4SLinus Torvalds 
50051da177e4SLinus Torvalds 		PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
50061da177e4SLinus Torvalds 		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
50071da177e4SLinus Torvalds 	}
50081da177e4SLinus Torvalds 
50091da177e4SLinus Torvalds 	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
50101da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
50111da177e4SLinus Torvalds 			   "reset controller fails (post status %x %x).\n",
50121da177e4SLinus Torvalds 			   PostByte[0], PostByte[1]);
50131da177e4SLinus Torvalds 
50141da177e4SLinus Torvalds 		return (0);
50151da177e4SLinus Torvalds 	}
50161da177e4SLinus Torvalds 
50171da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
50181da177e4SLinus Torvalds 		for (j = 0; j < 240; j++) {
50191da177e4SLinus Torvalds 			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
50201da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
50211da177e4SLinus Torvalds 				break;
50221da177e4SLinus Torvalds 
50231da177e4SLinus Torvalds 			/* Delay for 1 Second */
50241da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
50251da177e4SLinus Torvalds 		}
50261da177e4SLinus Torvalds 
50271da177e4SLinus Torvalds 		if (j >= 240)
50281da177e4SLinus Torvalds 			/* error occurred */
50291da177e4SLinus Torvalds 			return (0);
50301da177e4SLinus Torvalds 
50311da177e4SLinus Torvalds 		ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
50321da177e4SLinus Torvalds 		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
50331da177e4SLinus Torvalds 	}
50341da177e4SLinus Torvalds 
50351da177e4SLinus Torvalds 	for (i = 0; i < 240; i++) {
50361da177e4SLinus Torvalds 		Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
50371da177e4SLinus Torvalds 
50381da177e4SLinus Torvalds 		if ((Cbsp & IPS_BIT_OP) == 0)
50391da177e4SLinus Torvalds 			break;
50401da177e4SLinus Torvalds 
50411da177e4SLinus Torvalds 		/* Delay for 1 Second */
50421da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
50431da177e4SLinus Torvalds 	}
50441da177e4SLinus Torvalds 
50451da177e4SLinus Torvalds 	if (i >= 240)
50461da177e4SLinus Torvalds 		/* error occurred */
50471da177e4SLinus Torvalds 		return (0);
50481da177e4SLinus Torvalds 
50491da177e4SLinus Torvalds 	/* setup CCCR */
50501da177e4SLinus Torvalds 	writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
50511da177e4SLinus Torvalds 
50521da177e4SLinus Torvalds 	/* Enable busmastering */
50531da177e4SLinus Torvalds 	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
50541da177e4SLinus Torvalds 
50551da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
50561da177e4SLinus Torvalds 		/* fix for anaconda64 */
50571da177e4SLinus Torvalds 		writel(0, ha->mem_ptr + IPS_REG_NDAE);
50581da177e4SLinus Torvalds 
50591da177e4SLinus Torvalds 	/* Enable interrupts */
50601da177e4SLinus Torvalds 	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
50611da177e4SLinus Torvalds 
50621da177e4SLinus Torvalds 	/* if we get here then everything went OK */
50631da177e4SLinus Torvalds 	return (1);
50641da177e4SLinus Torvalds }
50651da177e4SLinus Torvalds 
50661da177e4SLinus Torvalds /****************************************************************************/
50671da177e4SLinus Torvalds /*                                                                          */
50681da177e4SLinus Torvalds /* Routine Name: ips_init_morpheus                                          */
50691da177e4SLinus Torvalds /*                                                                          */
50701da177e4SLinus Torvalds /* Routine Description:                                                     */
50711da177e4SLinus Torvalds /*                                                                          */
50721da177e4SLinus Torvalds /*   Initialize a morpheus controller                                       */
50731da177e4SLinus Torvalds /*                                                                          */
50741da177e4SLinus Torvalds /****************************************************************************/
50751da177e4SLinus Torvalds static int
50761da177e4SLinus Torvalds ips_init_morpheus(ips_ha_t * ha)
50771da177e4SLinus Torvalds {
50781da177e4SLinus Torvalds 	uint32_t Post;
50791da177e4SLinus Torvalds 	uint32_t Config;
50801da177e4SLinus Torvalds 	uint32_t Isr;
50811da177e4SLinus Torvalds 	uint32_t Oimr;
50821da177e4SLinus Torvalds 	int i;
50831da177e4SLinus Torvalds 
50841da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_morpheus", 1);
50851da177e4SLinus Torvalds 
50861da177e4SLinus Torvalds 	/* Wait up to 45 secs for Post */
50871da177e4SLinus Torvalds 	for (i = 0; i < 45; i++) {
50881da177e4SLinus Torvalds 		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
50891da177e4SLinus Torvalds 
50901da177e4SLinus Torvalds 		if (Isr & IPS_BIT_I960_MSG0I)
50911da177e4SLinus Torvalds 			break;
50921da177e4SLinus Torvalds 
50931da177e4SLinus Torvalds 		/* Delay for 1 Second */
50941da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
50951da177e4SLinus Torvalds 	}
50961da177e4SLinus Torvalds 
50971da177e4SLinus Torvalds 	if (i >= 45) {
50981da177e4SLinus Torvalds 		/* error occurred */
50991da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
51001da177e4SLinus Torvalds 			   "timeout waiting for post.\n");
51011da177e4SLinus Torvalds 
51021da177e4SLinus Torvalds 		return (0);
51031da177e4SLinus Torvalds 	}
51041da177e4SLinus Torvalds 
51051da177e4SLinus Torvalds 	Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
51061da177e4SLinus Torvalds 
51071da177e4SLinus Torvalds 	if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */
51081da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
51091da177e4SLinus Torvalds 			   "Flashing Battery PIC, Please wait ...\n");
51101da177e4SLinus Torvalds 
51111da177e4SLinus Torvalds 		/* Clear the interrupt bit */
51121da177e4SLinus Torvalds 		Isr = (uint32_t) IPS_BIT_I960_MSG0I;
51131da177e4SLinus Torvalds 		writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
51141da177e4SLinus Torvalds 
51151da177e4SLinus Torvalds 		for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */
51161da177e4SLinus Torvalds 			Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
51171da177e4SLinus Torvalds 			if (Post != 0x4F00)
51181da177e4SLinus Torvalds 				break;
51191da177e4SLinus Torvalds 			/* Delay for 1 Second */
51201da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
51211da177e4SLinus Torvalds 		}
51221da177e4SLinus Torvalds 
51231da177e4SLinus Torvalds 		if (i >= 120) {
51241da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
51251da177e4SLinus Torvalds 				   "timeout waiting for Battery PIC Flash\n");
51261da177e4SLinus Torvalds 			return (0);
51271da177e4SLinus Torvalds 		}
51281da177e4SLinus Torvalds 
51291da177e4SLinus Torvalds 	}
51301da177e4SLinus Torvalds 
51311da177e4SLinus Torvalds 	/* Clear the interrupt bit */
51321da177e4SLinus Torvalds 	Isr = (uint32_t) IPS_BIT_I960_MSG0I;
51331da177e4SLinus Torvalds 	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
51341da177e4SLinus Torvalds 
51351da177e4SLinus Torvalds 	if (Post < (IPS_GOOD_POST_STATUS << 8)) {
51361da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
51371da177e4SLinus Torvalds 			   "reset controller fails (post status %x).\n", Post);
51381da177e4SLinus Torvalds 
51391da177e4SLinus Torvalds 		return (0);
51401da177e4SLinus Torvalds 	}
51411da177e4SLinus Torvalds 
51421da177e4SLinus Torvalds 	/* Wait up to 240 secs for config bytes */
51431da177e4SLinus Torvalds 	for (i = 0; i < 240; i++) {
51441da177e4SLinus Torvalds 		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
51451da177e4SLinus Torvalds 
51461da177e4SLinus Torvalds 		if (Isr & IPS_BIT_I960_MSG1I)
51471da177e4SLinus Torvalds 			break;
51481da177e4SLinus Torvalds 
51491da177e4SLinus Torvalds 		/* Delay for 1 Second */
51501da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
51511da177e4SLinus Torvalds 	}
51521da177e4SLinus Torvalds 
51531da177e4SLinus Torvalds 	if (i >= 240) {
51541da177e4SLinus Torvalds 		/* error occurred */
51551da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
51561da177e4SLinus Torvalds 			   "timeout waiting for config.\n");
51571da177e4SLinus Torvalds 
51581da177e4SLinus Torvalds 		return (0);
51591da177e4SLinus Torvalds 	}
51601da177e4SLinus Torvalds 
51611da177e4SLinus Torvalds 	Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
51621da177e4SLinus Torvalds 
51631da177e4SLinus Torvalds 	/* Clear interrupt bit */
51641da177e4SLinus Torvalds 	Isr = (uint32_t) IPS_BIT_I960_MSG1I;
51651da177e4SLinus Torvalds 	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
51661da177e4SLinus Torvalds 
51671da177e4SLinus Torvalds 	/* Turn on the interrupts */
51681da177e4SLinus Torvalds 	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
51691da177e4SLinus Torvalds 	Oimr &= ~0x8;
51701da177e4SLinus Torvalds 	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
51711da177e4SLinus Torvalds 
51721da177e4SLinus Torvalds 	/* if we get here then everything went OK */
51731da177e4SLinus Torvalds 
51741da177e4SLinus Torvalds 	/* Since we did a RESET, an EraseStripeLock may be needed */
51751da177e4SLinus Torvalds 	if (Post == 0xEF10) {
51761da177e4SLinus Torvalds 		if ((Config == 0x000F) || (Config == 0x0009))
51771da177e4SLinus Torvalds 			ha->requires_esl = 1;
51781da177e4SLinus Torvalds 	}
51791da177e4SLinus Torvalds 
51801da177e4SLinus Torvalds 	return (1);
51811da177e4SLinus Torvalds }
51821da177e4SLinus Torvalds 
51831da177e4SLinus Torvalds /****************************************************************************/
51841da177e4SLinus Torvalds /*                                                                          */
51851da177e4SLinus Torvalds /* Routine Name: ips_reset_copperhead                                       */
51861da177e4SLinus Torvalds /*                                                                          */
51871da177e4SLinus Torvalds /* Routine Description:                                                     */
51881da177e4SLinus Torvalds /*                                                                          */
51891da177e4SLinus Torvalds /*   Reset the controller                                                   */
51901da177e4SLinus Torvalds /*                                                                          */
51911da177e4SLinus Torvalds /****************************************************************************/
51921da177e4SLinus Torvalds static int
51931da177e4SLinus Torvalds ips_reset_copperhead(ips_ha_t * ha)
51941da177e4SLinus Torvalds {
51951da177e4SLinus Torvalds 	int reset_counter;
51961da177e4SLinus Torvalds 
51971da177e4SLinus Torvalds 	METHOD_TRACE("ips_reset_copperhead", 1);
51981da177e4SLinus Torvalds 
51991da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
52001da177e4SLinus Torvalds 		  ips_name, ha->host_num, ha->io_addr, ha->irq);
52011da177e4SLinus Torvalds 
52021da177e4SLinus Torvalds 	reset_counter = 0;
52031da177e4SLinus Torvalds 
52041da177e4SLinus Torvalds 	while (reset_counter < 2) {
52051da177e4SLinus Torvalds 		reset_counter++;
52061da177e4SLinus Torvalds 
52071da177e4SLinus Torvalds 		outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
52081da177e4SLinus Torvalds 
52091da177e4SLinus Torvalds 		/* Delay for 1 Second */
52101da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
52111da177e4SLinus Torvalds 
52121da177e4SLinus Torvalds 		outb(0, ha->io_addr + IPS_REG_SCPR);
52131da177e4SLinus Torvalds 
52141da177e4SLinus Torvalds 		/* Delay for 1 Second */
52151da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
52161da177e4SLinus Torvalds 
52171da177e4SLinus Torvalds 		if ((*ha->func.init) (ha))
52181da177e4SLinus Torvalds 			break;
52191da177e4SLinus Torvalds 		else if (reset_counter >= 2) {
52201da177e4SLinus Torvalds 
52211da177e4SLinus Torvalds 			return (0);
52221da177e4SLinus Torvalds 		}
52231da177e4SLinus Torvalds 	}
52241da177e4SLinus Torvalds 
52251da177e4SLinus Torvalds 	return (1);
52261da177e4SLinus Torvalds }
52271da177e4SLinus Torvalds 
52281da177e4SLinus Torvalds /****************************************************************************/
52291da177e4SLinus Torvalds /*                                                                          */
52301da177e4SLinus Torvalds /* Routine Name: ips_reset_copperhead_memio                                 */
52311da177e4SLinus Torvalds /*                                                                          */
52321da177e4SLinus Torvalds /* Routine Description:                                                     */
52331da177e4SLinus Torvalds /*                                                                          */
52341da177e4SLinus Torvalds /*   Reset the controller                                                   */
52351da177e4SLinus Torvalds /*                                                                          */
52361da177e4SLinus Torvalds /****************************************************************************/
52371da177e4SLinus Torvalds static int
52381da177e4SLinus Torvalds ips_reset_copperhead_memio(ips_ha_t * ha)
52391da177e4SLinus Torvalds {
52401da177e4SLinus Torvalds 	int reset_counter;
52411da177e4SLinus Torvalds 
52421da177e4SLinus Torvalds 	METHOD_TRACE("ips_reset_copperhead_memio", 1);
52431da177e4SLinus Torvalds 
52441da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
52451da177e4SLinus Torvalds 		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
52461da177e4SLinus Torvalds 
52471da177e4SLinus Torvalds 	reset_counter = 0;
52481da177e4SLinus Torvalds 
52491da177e4SLinus Torvalds 	while (reset_counter < 2) {
52501da177e4SLinus Torvalds 		reset_counter++;
52511da177e4SLinus Torvalds 
52521da177e4SLinus Torvalds 		writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
52531da177e4SLinus Torvalds 
52541da177e4SLinus Torvalds 		/* Delay for 1 Second */
52551da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
52561da177e4SLinus Torvalds 
52571da177e4SLinus Torvalds 		writeb(0, ha->mem_ptr + IPS_REG_SCPR);
52581da177e4SLinus Torvalds 
52591da177e4SLinus Torvalds 		/* Delay for 1 Second */
52601da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
52611da177e4SLinus Torvalds 
52621da177e4SLinus Torvalds 		if ((*ha->func.init) (ha))
52631da177e4SLinus Torvalds 			break;
52641da177e4SLinus Torvalds 		else if (reset_counter >= 2) {
52651da177e4SLinus Torvalds 
52661da177e4SLinus Torvalds 			return (0);
52671da177e4SLinus Torvalds 		}
52681da177e4SLinus Torvalds 	}
52691da177e4SLinus Torvalds 
52701da177e4SLinus Torvalds 	return (1);
52711da177e4SLinus Torvalds }
52721da177e4SLinus Torvalds 
52731da177e4SLinus Torvalds /****************************************************************************/
52741da177e4SLinus Torvalds /*                                                                          */
52751da177e4SLinus Torvalds /* Routine Name: ips_reset_morpheus                                         */
52761da177e4SLinus Torvalds /*                                                                          */
52771da177e4SLinus Torvalds /* Routine Description:                                                     */
52781da177e4SLinus Torvalds /*                                                                          */
52791da177e4SLinus Torvalds /*   Reset the controller                                                   */
52801da177e4SLinus Torvalds /*                                                                          */
52811da177e4SLinus Torvalds /****************************************************************************/
52821da177e4SLinus Torvalds static int
52831da177e4SLinus Torvalds ips_reset_morpheus(ips_ha_t * ha)
52841da177e4SLinus Torvalds {
52851da177e4SLinus Torvalds 	int reset_counter;
52861da177e4SLinus Torvalds 	uint8_t junk;
52871da177e4SLinus Torvalds 
52881da177e4SLinus Torvalds 	METHOD_TRACE("ips_reset_morpheus", 1);
52891da177e4SLinus Torvalds 
52901da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
52911da177e4SLinus Torvalds 		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
52921da177e4SLinus Torvalds 
52931da177e4SLinus Torvalds 	reset_counter = 0;
52941da177e4SLinus Torvalds 
52951da177e4SLinus Torvalds 	while (reset_counter < 2) {
52961da177e4SLinus Torvalds 		reset_counter++;
52971da177e4SLinus Torvalds 
52981da177e4SLinus Torvalds 		writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
52991da177e4SLinus Torvalds 
53001da177e4SLinus Torvalds 		/* Delay for 5 Seconds */
53011da177e4SLinus Torvalds 		MDELAY(5 * IPS_ONE_SEC);
53021da177e4SLinus Torvalds 
53031da177e4SLinus Torvalds 		/* Do a PCI config read to wait for adapter */
53041da177e4SLinus Torvalds 		pci_read_config_byte(ha->pcidev, 4, &junk);
53051da177e4SLinus Torvalds 
53061da177e4SLinus Torvalds 		if ((*ha->func.init) (ha))
53071da177e4SLinus Torvalds 			break;
53081da177e4SLinus Torvalds 		else if (reset_counter >= 2) {
53091da177e4SLinus Torvalds 
53101da177e4SLinus Torvalds 			return (0);
53111da177e4SLinus Torvalds 		}
53121da177e4SLinus Torvalds 	}
53131da177e4SLinus Torvalds 
53141da177e4SLinus Torvalds 	return (1);
53151da177e4SLinus Torvalds }
53161da177e4SLinus Torvalds 
53171da177e4SLinus Torvalds /****************************************************************************/
53181da177e4SLinus Torvalds /*                                                                          */
53191da177e4SLinus Torvalds /* Routine Name: ips_statinit                                               */
53201da177e4SLinus Torvalds /*                                                                          */
53211da177e4SLinus Torvalds /* Routine Description:                                                     */
53221da177e4SLinus Torvalds /*                                                                          */
53231da177e4SLinus Torvalds /*   Initialize the status queues on the controller                         */
53241da177e4SLinus Torvalds /*                                                                          */
53251da177e4SLinus Torvalds /****************************************************************************/
53261da177e4SLinus Torvalds static void
53271da177e4SLinus Torvalds ips_statinit(ips_ha_t * ha)
53281da177e4SLinus Torvalds {
53291da177e4SLinus Torvalds 	uint32_t phys_status_start;
53301da177e4SLinus Torvalds 
53311da177e4SLinus Torvalds 	METHOD_TRACE("ips_statinit", 1);
53321da177e4SLinus Torvalds 
53331da177e4SLinus Torvalds 	ha->adapt->p_status_start = ha->adapt->status;
53341da177e4SLinus Torvalds 	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
53351da177e4SLinus Torvalds 	ha->adapt->p_status_tail = ha->adapt->status;
53361da177e4SLinus Torvalds 
53371da177e4SLinus Torvalds 	phys_status_start = ha->adapt->hw_status_start;
53381da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);
53391da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE),
53401da177e4SLinus Torvalds 	     ha->io_addr + IPS_REG_SQER);
53411da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE),
53421da177e4SLinus Torvalds 	     ha->io_addr + IPS_REG_SQHR);
53431da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);
53441da177e4SLinus Torvalds 
53451da177e4SLinus Torvalds 	ha->adapt->hw_status_tail = phys_status_start;
53461da177e4SLinus Torvalds }
53471da177e4SLinus Torvalds 
53481da177e4SLinus Torvalds /****************************************************************************/
53491da177e4SLinus Torvalds /*                                                                          */
53501da177e4SLinus Torvalds /* Routine Name: ips_statinit_memio                                         */
53511da177e4SLinus Torvalds /*                                                                          */
53521da177e4SLinus Torvalds /* Routine Description:                                                     */
53531da177e4SLinus Torvalds /*                                                                          */
53541da177e4SLinus Torvalds /*   Initialize the status queues on the controller                         */
53551da177e4SLinus Torvalds /*                                                                          */
53561da177e4SLinus Torvalds /****************************************************************************/
53571da177e4SLinus Torvalds static void
53581da177e4SLinus Torvalds ips_statinit_memio(ips_ha_t * ha)
53591da177e4SLinus Torvalds {
53601da177e4SLinus Torvalds 	uint32_t phys_status_start;
53611da177e4SLinus Torvalds 
53621da177e4SLinus Torvalds 	METHOD_TRACE("ips_statinit_memio", 1);
53631da177e4SLinus Torvalds 
53641da177e4SLinus Torvalds 	ha->adapt->p_status_start = ha->adapt->status;
53651da177e4SLinus Torvalds 	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
53661da177e4SLinus Torvalds 	ha->adapt->p_status_tail = ha->adapt->status;
53671da177e4SLinus Torvalds 
53681da177e4SLinus Torvalds 	phys_status_start = ha->adapt->hw_status_start;
53691da177e4SLinus Torvalds 	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
53701da177e4SLinus Torvalds 	writel(phys_status_start + IPS_STATUS_Q_SIZE,
53711da177e4SLinus Torvalds 	       ha->mem_ptr + IPS_REG_SQER);
53721da177e4SLinus Torvalds 	writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
53731da177e4SLinus Torvalds 	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
53741da177e4SLinus Torvalds 
53751da177e4SLinus Torvalds 	ha->adapt->hw_status_tail = phys_status_start;
53761da177e4SLinus Torvalds }
53771da177e4SLinus Torvalds 
53781da177e4SLinus Torvalds /****************************************************************************/
53791da177e4SLinus Torvalds /*                                                                          */
53801da177e4SLinus Torvalds /* Routine Name: ips_statupd_copperhead                                     */
53811da177e4SLinus Torvalds /*                                                                          */
53821da177e4SLinus Torvalds /* Routine Description:                                                     */
53831da177e4SLinus Torvalds /*                                                                          */
53841da177e4SLinus Torvalds /*   Remove an element from the status queue                                */
53851da177e4SLinus Torvalds /*                                                                          */
53861da177e4SLinus Torvalds /****************************************************************************/
53871da177e4SLinus Torvalds static uint32_t
53881da177e4SLinus Torvalds ips_statupd_copperhead(ips_ha_t * ha)
53891da177e4SLinus Torvalds {
53901da177e4SLinus Torvalds 	METHOD_TRACE("ips_statupd_copperhead", 1);
53911da177e4SLinus Torvalds 
53921da177e4SLinus Torvalds 	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
53931da177e4SLinus Torvalds 		ha->adapt->p_status_tail++;
53941da177e4SLinus Torvalds 		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
53951da177e4SLinus Torvalds 	} else {
53961da177e4SLinus Torvalds 		ha->adapt->p_status_tail = ha->adapt->p_status_start;
53971da177e4SLinus Torvalds 		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
53981da177e4SLinus Torvalds 	}
53991da177e4SLinus Torvalds 
54001da177e4SLinus Torvalds 	outl(cpu_to_le32(ha->adapt->hw_status_tail),
54011da177e4SLinus Torvalds 	     ha->io_addr + IPS_REG_SQTR);
54021da177e4SLinus Torvalds 
54031da177e4SLinus Torvalds 	return (ha->adapt->p_status_tail->value);
54041da177e4SLinus Torvalds }
54051da177e4SLinus Torvalds 
54061da177e4SLinus Torvalds /****************************************************************************/
54071da177e4SLinus Torvalds /*                                                                          */
54081da177e4SLinus Torvalds /* Routine Name: ips_statupd_copperhead_memio                               */
54091da177e4SLinus Torvalds /*                                                                          */
54101da177e4SLinus Torvalds /* Routine Description:                                                     */
54111da177e4SLinus Torvalds /*                                                                          */
54121da177e4SLinus Torvalds /*   Remove an element from the status queue                                */
54131da177e4SLinus Torvalds /*                                                                          */
54141da177e4SLinus Torvalds /****************************************************************************/
54151da177e4SLinus Torvalds static uint32_t
54161da177e4SLinus Torvalds ips_statupd_copperhead_memio(ips_ha_t * ha)
54171da177e4SLinus Torvalds {
54181da177e4SLinus Torvalds 	METHOD_TRACE("ips_statupd_copperhead_memio", 1);
54191da177e4SLinus Torvalds 
54201da177e4SLinus Torvalds 	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
54211da177e4SLinus Torvalds 		ha->adapt->p_status_tail++;
54221da177e4SLinus Torvalds 		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
54231da177e4SLinus Torvalds 	} else {
54241da177e4SLinus Torvalds 		ha->adapt->p_status_tail = ha->adapt->p_status_start;
54251da177e4SLinus Torvalds 		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
54261da177e4SLinus Torvalds 	}
54271da177e4SLinus Torvalds 
54281da177e4SLinus Torvalds 	writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
54291da177e4SLinus Torvalds 
54301da177e4SLinus Torvalds 	return (ha->adapt->p_status_tail->value);
54311da177e4SLinus Torvalds }
54321da177e4SLinus Torvalds 
54331da177e4SLinus Torvalds /****************************************************************************/
54341da177e4SLinus Torvalds /*                                                                          */
54351da177e4SLinus Torvalds /* Routine Name: ips_statupd_morpheus                                       */
54361da177e4SLinus Torvalds /*                                                                          */
54371da177e4SLinus Torvalds /* Routine Description:                                                     */
54381da177e4SLinus Torvalds /*                                                                          */
54391da177e4SLinus Torvalds /*   Remove an element from the status queue                                */
54401da177e4SLinus Torvalds /*                                                                          */
54411da177e4SLinus Torvalds /****************************************************************************/
54421da177e4SLinus Torvalds static uint32_t
54431da177e4SLinus Torvalds ips_statupd_morpheus(ips_ha_t * ha)
54441da177e4SLinus Torvalds {
54451da177e4SLinus Torvalds 	uint32_t val;
54461da177e4SLinus Torvalds 
54471da177e4SLinus Torvalds 	METHOD_TRACE("ips_statupd_morpheus", 1);
54481da177e4SLinus Torvalds 
54491da177e4SLinus Torvalds 	val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
54501da177e4SLinus Torvalds 
54511da177e4SLinus Torvalds 	return (val);
54521da177e4SLinus Torvalds }
54531da177e4SLinus Torvalds 
54541da177e4SLinus Torvalds /****************************************************************************/
54551da177e4SLinus Torvalds /*                                                                          */
54561da177e4SLinus Torvalds /* Routine Name: ips_issue_copperhead                                       */
54571da177e4SLinus Torvalds /*                                                                          */
54581da177e4SLinus Torvalds /* Routine Description:                                                     */
54591da177e4SLinus Torvalds /*                                                                          */
54601da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
54611da177e4SLinus Torvalds /*                                                                          */
54621da177e4SLinus Torvalds /****************************************************************************/
54631da177e4SLinus Torvalds static int
54641da177e4SLinus Torvalds ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb)
54651da177e4SLinus Torvalds {
54661da177e4SLinus Torvalds 	uint32_t TimeOut;
54671da177e4SLinus Torvalds 	uint32_t val;
54681da177e4SLinus Torvalds 
54691da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_copperhead", 1);
54701da177e4SLinus Torvalds 
54711da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
54721da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
54731da177e4SLinus Torvalds 			  ips_name,
54741da177e4SLinus Torvalds 			  ha->host_num,
54751da177e4SLinus Torvalds 			  scb->cdb[0],
54761da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
54771da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
54781da177e4SLinus Torvalds 	} else {
54791da177e4SLinus Torvalds 		DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
54801da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
54811da177e4SLinus Torvalds 	}
54821da177e4SLinus Torvalds 
54831da177e4SLinus Torvalds 	TimeOut = 0;
54841da177e4SLinus Torvalds 
54851da177e4SLinus Torvalds 	while ((val =
54861da177e4SLinus Torvalds 		le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
54871da177e4SLinus Torvalds 		udelay(1000);
54881da177e4SLinus Torvalds 
54891da177e4SLinus Torvalds 		if (++TimeOut >= IPS_SEM_TIMEOUT) {
54901da177e4SLinus Torvalds 			if (!(val & IPS_BIT_START_STOP))
54911da177e4SLinus Torvalds 				break;
54921da177e4SLinus Torvalds 
54931da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
54941da177e4SLinus Torvalds 				   "ips_issue val [0x%x].\n", val);
54951da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
54961da177e4SLinus Torvalds 				   "ips_issue semaphore chk timeout.\n");
54971da177e4SLinus Torvalds 
54981da177e4SLinus Torvalds 			return (IPS_FAILURE);
54991da177e4SLinus Torvalds 		}		/* end if */
55001da177e4SLinus Torvalds 	}			/* end while */
55011da177e4SLinus Torvalds 
55021da177e4SLinus Torvalds 	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
55031da177e4SLinus Torvalds 	outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
55041da177e4SLinus Torvalds 
55051da177e4SLinus Torvalds 	return (IPS_SUCCESS);
55061da177e4SLinus Torvalds }
55071da177e4SLinus Torvalds 
55081da177e4SLinus Torvalds /****************************************************************************/
55091da177e4SLinus Torvalds /*                                                                          */
55101da177e4SLinus Torvalds /* Routine Name: ips_issue_copperhead_memio                                 */
55111da177e4SLinus Torvalds /*                                                                          */
55121da177e4SLinus Torvalds /* Routine Description:                                                     */
55131da177e4SLinus Torvalds /*                                                                          */
55141da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
55151da177e4SLinus Torvalds /*                                                                          */
55161da177e4SLinus Torvalds /****************************************************************************/
55171da177e4SLinus Torvalds static int
55181da177e4SLinus Torvalds ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb)
55191da177e4SLinus Torvalds {
55201da177e4SLinus Torvalds 	uint32_t TimeOut;
55211da177e4SLinus Torvalds 	uint32_t val;
55221da177e4SLinus Torvalds 
55231da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_copperhead_memio", 1);
55241da177e4SLinus Torvalds 
55251da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
55261da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
55271da177e4SLinus Torvalds 			  ips_name,
55281da177e4SLinus Torvalds 			  ha->host_num,
55291da177e4SLinus Torvalds 			  scb->cdb[0],
55301da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
55311da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
55321da177e4SLinus Torvalds 	} else {
55331da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
55341da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
55351da177e4SLinus Torvalds 	}
55361da177e4SLinus Torvalds 
55371da177e4SLinus Torvalds 	TimeOut = 0;
55381da177e4SLinus Torvalds 
55391da177e4SLinus Torvalds 	while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
55401da177e4SLinus Torvalds 		udelay(1000);
55411da177e4SLinus Torvalds 
55421da177e4SLinus Torvalds 		if (++TimeOut >= IPS_SEM_TIMEOUT) {
55431da177e4SLinus Torvalds 			if (!(val & IPS_BIT_START_STOP))
55441da177e4SLinus Torvalds 				break;
55451da177e4SLinus Torvalds 
55461da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
55471da177e4SLinus Torvalds 				   "ips_issue val [0x%x].\n", val);
55481da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
55491da177e4SLinus Torvalds 				   "ips_issue semaphore chk timeout.\n");
55501da177e4SLinus Torvalds 
55511da177e4SLinus Torvalds 			return (IPS_FAILURE);
55521da177e4SLinus Torvalds 		}		/* end if */
55531da177e4SLinus Torvalds 	}			/* end while */
55541da177e4SLinus Torvalds 
55551da177e4SLinus Torvalds 	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
55561da177e4SLinus Torvalds 	writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
55571da177e4SLinus Torvalds 
55581da177e4SLinus Torvalds 	return (IPS_SUCCESS);
55591da177e4SLinus Torvalds }
55601da177e4SLinus Torvalds 
55611da177e4SLinus Torvalds /****************************************************************************/
55621da177e4SLinus Torvalds /*                                                                          */
55631da177e4SLinus Torvalds /* Routine Name: ips_issue_i2o                                              */
55641da177e4SLinus Torvalds /*                                                                          */
55651da177e4SLinus Torvalds /* Routine Description:                                                     */
55661da177e4SLinus Torvalds /*                                                                          */
55671da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
55681da177e4SLinus Torvalds /*                                                                          */
55691da177e4SLinus Torvalds /****************************************************************************/
55701da177e4SLinus Torvalds static int
55711da177e4SLinus Torvalds ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb)
55721da177e4SLinus Torvalds {
55731da177e4SLinus Torvalds 
55741da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_i2o", 1);
55751da177e4SLinus Torvalds 
55761da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
55771da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
55781da177e4SLinus Torvalds 			  ips_name,
55791da177e4SLinus Torvalds 			  ha->host_num,
55801da177e4SLinus Torvalds 			  scb->cdb[0],
55811da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
55821da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
55831da177e4SLinus Torvalds 	} else {
55841da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
55851da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
55861da177e4SLinus Torvalds 	}
55871da177e4SLinus Torvalds 
55881da177e4SLinus Torvalds 	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
55891da177e4SLinus Torvalds 
55901da177e4SLinus Torvalds 	return (IPS_SUCCESS);
55911da177e4SLinus Torvalds }
55921da177e4SLinus Torvalds 
55931da177e4SLinus Torvalds /****************************************************************************/
55941da177e4SLinus Torvalds /*                                                                          */
55951da177e4SLinus Torvalds /* Routine Name: ips_issue_i2o_memio                                        */
55961da177e4SLinus Torvalds /*                                                                          */
55971da177e4SLinus Torvalds /* Routine Description:                                                     */
55981da177e4SLinus Torvalds /*                                                                          */
55991da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
56001da177e4SLinus Torvalds /*                                                                          */
56011da177e4SLinus Torvalds /****************************************************************************/
56021da177e4SLinus Torvalds static int
56031da177e4SLinus Torvalds ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb)
56041da177e4SLinus Torvalds {
56051da177e4SLinus Torvalds 
56061da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_i2o_memio", 1);
56071da177e4SLinus Torvalds 
56081da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
56091da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
56101da177e4SLinus Torvalds 			  ips_name,
56111da177e4SLinus Torvalds 			  ha->host_num,
56121da177e4SLinus Torvalds 			  scb->cdb[0],
56131da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
56141da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
56151da177e4SLinus Torvalds 	} else {
56161da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
56171da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
56181da177e4SLinus Torvalds 	}
56191da177e4SLinus Torvalds 
56201da177e4SLinus Torvalds 	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
56211da177e4SLinus Torvalds 
56221da177e4SLinus Torvalds 	return (IPS_SUCCESS);
56231da177e4SLinus Torvalds }
56241da177e4SLinus Torvalds 
56251da177e4SLinus Torvalds /****************************************************************************/
56261da177e4SLinus Torvalds /*                                                                          */
56271da177e4SLinus Torvalds /* Routine Name: ips_isintr_copperhead                                      */
56281da177e4SLinus Torvalds /*                                                                          */
56291da177e4SLinus Torvalds /* Routine Description:                                                     */
56301da177e4SLinus Torvalds /*                                                                          */
56311da177e4SLinus Torvalds /*   Test to see if an interrupt is for us                                  */
56321da177e4SLinus Torvalds /*                                                                          */
56331da177e4SLinus Torvalds /****************************************************************************/
56341da177e4SLinus Torvalds static int
56351da177e4SLinus Torvalds ips_isintr_copperhead(ips_ha_t * ha)
56361da177e4SLinus Torvalds {
56371da177e4SLinus Torvalds 	uint8_t Isr;
56381da177e4SLinus Torvalds 
56391da177e4SLinus Torvalds 	METHOD_TRACE("ips_isintr_copperhead", 2);
56401da177e4SLinus Torvalds 
56411da177e4SLinus Torvalds 	Isr = inb(ha->io_addr + IPS_REG_HISR);
56421da177e4SLinus Torvalds 
56431da177e4SLinus Torvalds 	if (Isr == 0xFF)
56441da177e4SLinus Torvalds 		/* ?!?! Nothing really there */
56451da177e4SLinus Torvalds 		return (0);
56461da177e4SLinus Torvalds 
56471da177e4SLinus Torvalds 	if (Isr & IPS_BIT_SCE)
56481da177e4SLinus Torvalds 		return (1);
56491da177e4SLinus Torvalds 	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
56501da177e4SLinus Torvalds 		/* status queue overflow or GHI */
56511da177e4SLinus Torvalds 		/* just clear the interrupt */
56521da177e4SLinus Torvalds 		outb(Isr, ha->io_addr + IPS_REG_HISR);
56531da177e4SLinus Torvalds 	}
56541da177e4SLinus Torvalds 
56551da177e4SLinus Torvalds 	return (0);
56561da177e4SLinus Torvalds }
56571da177e4SLinus Torvalds 
56581da177e4SLinus Torvalds /****************************************************************************/
56591da177e4SLinus Torvalds /*                                                                          */
56601da177e4SLinus Torvalds /* Routine Name: ips_isintr_copperhead_memio                                */
56611da177e4SLinus Torvalds /*                                                                          */
56621da177e4SLinus Torvalds /* Routine Description:                                                     */
56631da177e4SLinus Torvalds /*                                                                          */
56641da177e4SLinus Torvalds /*   Test to see if an interrupt is for us                                  */
56651da177e4SLinus Torvalds /*                                                                          */
56661da177e4SLinus Torvalds /****************************************************************************/
56671da177e4SLinus Torvalds static int
56681da177e4SLinus Torvalds ips_isintr_copperhead_memio(ips_ha_t * ha)
56691da177e4SLinus Torvalds {
56701da177e4SLinus Torvalds 	uint8_t Isr;
56711da177e4SLinus Torvalds 
56721da177e4SLinus Torvalds 	METHOD_TRACE("ips_isintr_memio", 2);
56731da177e4SLinus Torvalds 
56741da177e4SLinus Torvalds 	Isr = readb(ha->mem_ptr + IPS_REG_HISR);
56751da177e4SLinus Torvalds 
56761da177e4SLinus Torvalds 	if (Isr == 0xFF)
56771da177e4SLinus Torvalds 		/* ?!?! Nothing really there */
56781da177e4SLinus Torvalds 		return (0);
56791da177e4SLinus Torvalds 
56801da177e4SLinus Torvalds 	if (Isr & IPS_BIT_SCE)
56811da177e4SLinus Torvalds 		return (1);
56821da177e4SLinus Torvalds 	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
56831da177e4SLinus Torvalds 		/* status queue overflow or GHI */
56841da177e4SLinus Torvalds 		/* just clear the interrupt */
56851da177e4SLinus Torvalds 		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
56861da177e4SLinus Torvalds 	}
56871da177e4SLinus Torvalds 
56881da177e4SLinus Torvalds 	return (0);
56891da177e4SLinus Torvalds }
56901da177e4SLinus Torvalds 
56911da177e4SLinus Torvalds /****************************************************************************/
56921da177e4SLinus Torvalds /*                                                                          */
56931da177e4SLinus Torvalds /* Routine Name: ips_isintr_morpheus                                        */
56941da177e4SLinus Torvalds /*                                                                          */
56951da177e4SLinus Torvalds /* Routine Description:                                                     */
56961da177e4SLinus Torvalds /*                                                                          */
56971da177e4SLinus Torvalds /*   Test to see if an interrupt is for us                                  */
56981da177e4SLinus Torvalds /*                                                                          */
56991da177e4SLinus Torvalds /****************************************************************************/
57001da177e4SLinus Torvalds static int
57011da177e4SLinus Torvalds ips_isintr_morpheus(ips_ha_t * ha)
57021da177e4SLinus Torvalds {
57031da177e4SLinus Torvalds 	uint32_t Isr;
57041da177e4SLinus Torvalds 
57051da177e4SLinus Torvalds 	METHOD_TRACE("ips_isintr_morpheus", 2);
57061da177e4SLinus Torvalds 
57071da177e4SLinus Torvalds 	Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
57081da177e4SLinus Torvalds 
57091da177e4SLinus Torvalds 	if (Isr & IPS_BIT_I2O_OPQI)
57101da177e4SLinus Torvalds 		return (1);
57111da177e4SLinus Torvalds 	else
57121da177e4SLinus Torvalds 		return (0);
57131da177e4SLinus Torvalds }
57141da177e4SLinus Torvalds 
57151da177e4SLinus Torvalds /****************************************************************************/
57161da177e4SLinus Torvalds /*                                                                          */
57171da177e4SLinus Torvalds /* Routine Name: ips_wait                                                   */
57181da177e4SLinus Torvalds /*                                                                          */
57191da177e4SLinus Torvalds /* Routine Description:                                                     */
57201da177e4SLinus Torvalds /*                                                                          */
57211da177e4SLinus Torvalds /*   Wait for a command to complete                                         */
57221da177e4SLinus Torvalds /*                                                                          */
57231da177e4SLinus Torvalds /****************************************************************************/
57241da177e4SLinus Torvalds static int
57251da177e4SLinus Torvalds ips_wait(ips_ha_t * ha, int time, int intr)
57261da177e4SLinus Torvalds {
57271da177e4SLinus Torvalds 	int ret;
57281da177e4SLinus Torvalds 	int done;
57291da177e4SLinus Torvalds 
57301da177e4SLinus Torvalds 	METHOD_TRACE("ips_wait", 1);
57311da177e4SLinus Torvalds 
57321da177e4SLinus Torvalds 	ret = IPS_FAILURE;
57331da177e4SLinus Torvalds 	done = FALSE;
57341da177e4SLinus Torvalds 
57351da177e4SLinus Torvalds 	time *= IPS_ONE_SEC;	/* convert seconds */
57361da177e4SLinus Torvalds 
57371da177e4SLinus Torvalds 	while ((time > 0) && (!done)) {
57381da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON) {
57391da177e4SLinus Torvalds 			if (ha->waitflag == FALSE) {
57401da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
57411da177e4SLinus Torvalds 				done = TRUE;
57421da177e4SLinus Torvalds 				break;
57431da177e4SLinus Torvalds 			}
57441da177e4SLinus Torvalds 		} else if (intr == IPS_INTR_IORL) {
57451da177e4SLinus Torvalds 			if (ha->waitflag == FALSE) {
57461da177e4SLinus Torvalds 				/*
57471da177e4SLinus Torvalds 				 * controller generated an interrupt to
57481da177e4SLinus Torvalds 				 * acknowledge completion of the command
57491da177e4SLinus Torvalds 				 * and ips_intr() has serviced the interrupt.
57501da177e4SLinus Torvalds 				 */
57511da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
57521da177e4SLinus Torvalds 				done = TRUE;
57531da177e4SLinus Torvalds 				break;
57541da177e4SLinus Torvalds 			}
57551da177e4SLinus Torvalds 
57561da177e4SLinus Torvalds 			/*
57571da177e4SLinus Torvalds 			 * NOTE: we already have the io_request_lock so
57581da177e4SLinus Torvalds 			 * even if we get an interrupt it won't get serviced
57591da177e4SLinus Torvalds 			 * until after we finish.
57601da177e4SLinus Torvalds 			 */
57611da177e4SLinus Torvalds 
57621da177e4SLinus Torvalds 			(*ha->func.intr) (ha);
57631da177e4SLinus Torvalds 		}
57641da177e4SLinus Torvalds 
57651da177e4SLinus Torvalds 		/* This looks like a very evil loop, but it only does this during start-up */
57661da177e4SLinus Torvalds 		udelay(1000);
57671da177e4SLinus Torvalds 		time--;
57681da177e4SLinus Torvalds 	}
57691da177e4SLinus Torvalds 
57701da177e4SLinus Torvalds 	return (ret);
57711da177e4SLinus Torvalds }
57721da177e4SLinus Torvalds 
57731da177e4SLinus Torvalds /****************************************************************************/
57741da177e4SLinus Torvalds /*                                                                          */
57751da177e4SLinus Torvalds /* Routine Name: ips_write_driver_status                                    */
57761da177e4SLinus Torvalds /*                                                                          */
57771da177e4SLinus Torvalds /* Routine Description:                                                     */
57781da177e4SLinus Torvalds /*                                                                          */
57791da177e4SLinus Torvalds /*   Write OS/Driver version to Page 5 of the nvram on the controller       */
57801da177e4SLinus Torvalds /*                                                                          */
57811da177e4SLinus Torvalds /****************************************************************************/
57821da177e4SLinus Torvalds static int
57831da177e4SLinus Torvalds ips_write_driver_status(ips_ha_t * ha, int intr)
57841da177e4SLinus Torvalds {
57851da177e4SLinus Torvalds 	METHOD_TRACE("ips_write_driver_status", 1);
57861da177e4SLinus Torvalds 
57871da177e4SLinus Torvalds 	if (!ips_readwrite_page5(ha, FALSE, intr)) {
57881da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
57891da177e4SLinus Torvalds 			   "unable to read NVRAM page 5.\n");
57901da177e4SLinus Torvalds 
57911da177e4SLinus Torvalds 		return (0);
57921da177e4SLinus Torvalds 	}
57931da177e4SLinus Torvalds 
57941da177e4SLinus Torvalds 	/* check to make sure the page has a valid */
57951da177e4SLinus Torvalds 	/* signature */
57961da177e4SLinus Torvalds 	if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
57971da177e4SLinus Torvalds 		DEBUG_VAR(1,
57981da177e4SLinus Torvalds 			  "(%s%d) NVRAM page 5 has an invalid signature: %X.",
57991da177e4SLinus Torvalds 			  ips_name, ha->host_num, ha->nvram->signature);
58001da177e4SLinus Torvalds 		ha->nvram->signature = IPS_NVRAM_P5_SIG;
58011da177e4SLinus Torvalds 	}
58021da177e4SLinus Torvalds 
58031da177e4SLinus Torvalds 	DEBUG_VAR(2,
58041da177e4SLinus Torvalds 		  "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
58051da177e4SLinus Torvalds 		  ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),
58061da177e4SLinus Torvalds 		  ha->nvram->adapter_slot, ha->nvram->bios_high[0],
58071da177e4SLinus Torvalds 		  ha->nvram->bios_high[1], ha->nvram->bios_high[2],
58081da177e4SLinus Torvalds 		  ha->nvram->bios_high[3], ha->nvram->bios_low[0],
58091da177e4SLinus Torvalds 		  ha->nvram->bios_low[1], ha->nvram->bios_low[2],
58101da177e4SLinus Torvalds 		  ha->nvram->bios_low[3]);
58111da177e4SLinus Torvalds 
58121da177e4SLinus Torvalds 	ips_get_bios_version(ha, intr);
58131da177e4SLinus Torvalds 
58141da177e4SLinus Torvalds 	/* change values (as needed) */
58151da177e4SLinus Torvalds 	ha->nvram->operating_system = IPS_OS_LINUX;
58161da177e4SLinus Torvalds 	ha->nvram->adapter_type = ha->ad_type;
58171da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
58181da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);
58191da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
58201da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
58211da177e4SLinus Torvalds 
58221da177e4SLinus Torvalds 	ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */
58231da177e4SLinus Torvalds 
58241da177e4SLinus Torvalds 	/* now update the page */
58251da177e4SLinus Torvalds 	if (!ips_readwrite_page5(ha, TRUE, intr)) {
58261da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
58271da177e4SLinus Torvalds 			   "unable to write NVRAM page 5.\n");
58281da177e4SLinus Torvalds 
58291da177e4SLinus Torvalds 		return (0);
58301da177e4SLinus Torvalds 	}
58311da177e4SLinus Torvalds 
58321da177e4SLinus Torvalds 	/* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
58331da177e4SLinus Torvalds 	ha->slot_num = ha->nvram->adapter_slot;
58341da177e4SLinus Torvalds 
58351da177e4SLinus Torvalds 	return (1);
58361da177e4SLinus Torvalds }
58371da177e4SLinus Torvalds 
58381da177e4SLinus Torvalds /****************************************************************************/
58391da177e4SLinus Torvalds /*                                                                          */
58401da177e4SLinus Torvalds /* Routine Name: ips_read_adapter_status                                    */
58411da177e4SLinus Torvalds /*                                                                          */
58421da177e4SLinus Torvalds /* Routine Description:                                                     */
58431da177e4SLinus Torvalds /*                                                                          */
58441da177e4SLinus Torvalds /*   Do an Inquiry command to the adapter                                   */
58451da177e4SLinus Torvalds /*                                                                          */
58461da177e4SLinus Torvalds /****************************************************************************/
58471da177e4SLinus Torvalds static int
58481da177e4SLinus Torvalds ips_read_adapter_status(ips_ha_t * ha, int intr)
58491da177e4SLinus Torvalds {
58501da177e4SLinus Torvalds 	ips_scb_t *scb;
58511da177e4SLinus Torvalds 	int ret;
58521da177e4SLinus Torvalds 
58531da177e4SLinus Torvalds 	METHOD_TRACE("ips_read_adapter_status", 1);
58541da177e4SLinus Torvalds 
58551da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
58561da177e4SLinus Torvalds 
58571da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
58581da177e4SLinus Torvalds 
58591da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
58601da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_ENQUIRY;
58611da177e4SLinus Torvalds 
58621da177e4SLinus Torvalds 	scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
58631da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
58641da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_count = 0;
58651da177e4SLinus Torvalds 	scb->cmd.basic_io.lba = 0;
58661da177e4SLinus Torvalds 	scb->cmd.basic_io.sector_count = 0;
58671da177e4SLinus Torvalds 	scb->cmd.basic_io.log_drv = 0;
58681da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->enq);
58691da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
58701da177e4SLinus Torvalds 
58711da177e4SLinus Torvalds 	/* send command */
58721da177e4SLinus Torvalds 	if (((ret =
58731da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
58741da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
58751da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
58761da177e4SLinus Torvalds 		return (0);
58771da177e4SLinus Torvalds 
58781da177e4SLinus Torvalds 	return (1);
58791da177e4SLinus Torvalds }
58801da177e4SLinus Torvalds 
58811da177e4SLinus Torvalds /****************************************************************************/
58821da177e4SLinus Torvalds /*                                                                          */
58831da177e4SLinus Torvalds /* Routine Name: ips_read_subsystem_parameters                              */
58841da177e4SLinus Torvalds /*                                                                          */
58851da177e4SLinus Torvalds /* Routine Description:                                                     */
58861da177e4SLinus Torvalds /*                                                                          */
58871da177e4SLinus Torvalds /*   Read subsystem parameters from the adapter                             */
58881da177e4SLinus Torvalds /*                                                                          */
58891da177e4SLinus Torvalds /****************************************************************************/
58901da177e4SLinus Torvalds static int
58911da177e4SLinus Torvalds ips_read_subsystem_parameters(ips_ha_t * ha, int intr)
58921da177e4SLinus Torvalds {
58931da177e4SLinus Torvalds 	ips_scb_t *scb;
58941da177e4SLinus Torvalds 	int ret;
58951da177e4SLinus Torvalds 
58961da177e4SLinus Torvalds 	METHOD_TRACE("ips_read_subsystem_parameters", 1);
58971da177e4SLinus Torvalds 
58981da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
58991da177e4SLinus Torvalds 
59001da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
59011da177e4SLinus Torvalds 
59021da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
59031da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_GET_SUBSYS;
59041da177e4SLinus Torvalds 
59051da177e4SLinus Torvalds 	scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
59061da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
59071da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_count = 0;
59081da177e4SLinus Torvalds 	scb->cmd.basic_io.lba = 0;
59091da177e4SLinus Torvalds 	scb->cmd.basic_io.sector_count = 0;
59101da177e4SLinus Torvalds 	scb->cmd.basic_io.log_drv = 0;
59111da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->subsys);
59121da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
59131da177e4SLinus Torvalds 
59141da177e4SLinus Torvalds 	/* send command */
59151da177e4SLinus Torvalds 	if (((ret =
59161da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
59171da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
59181da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
59191da177e4SLinus Torvalds 		return (0);
59201da177e4SLinus Torvalds 
59211da177e4SLinus Torvalds 	memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys));
59221da177e4SLinus Torvalds 	return (1);
59231da177e4SLinus Torvalds }
59241da177e4SLinus Torvalds 
59251da177e4SLinus Torvalds /****************************************************************************/
59261da177e4SLinus Torvalds /*                                                                          */
59271da177e4SLinus Torvalds /* Routine Name: ips_read_config                                            */
59281da177e4SLinus Torvalds /*                                                                          */
59291da177e4SLinus Torvalds /* Routine Description:                                                     */
59301da177e4SLinus Torvalds /*                                                                          */
59311da177e4SLinus Torvalds /*   Read the configuration on the adapter                                  */
59321da177e4SLinus Torvalds /*                                                                          */
59331da177e4SLinus Torvalds /****************************************************************************/
59341da177e4SLinus Torvalds static int
59351da177e4SLinus Torvalds ips_read_config(ips_ha_t * ha, int intr)
59361da177e4SLinus Torvalds {
59371da177e4SLinus Torvalds 	ips_scb_t *scb;
59381da177e4SLinus Torvalds 	int i;
59391da177e4SLinus Torvalds 	int ret;
59401da177e4SLinus Torvalds 
59411da177e4SLinus Torvalds 	METHOD_TRACE("ips_read_config", 1);
59421da177e4SLinus Torvalds 
59431da177e4SLinus Torvalds 	/* set defaults for initiator IDs */
59441da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
59451da177e4SLinus Torvalds 		ha->conf->init_id[i] = 7;
59461da177e4SLinus Torvalds 
59471da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
59481da177e4SLinus Torvalds 
59491da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
59501da177e4SLinus Torvalds 
59511da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
59521da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_READ_CONF;
59531da177e4SLinus Torvalds 
59541da177e4SLinus Torvalds 	scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
59551da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
59561da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->conf);
59571da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
59581da177e4SLinus Torvalds 
59591da177e4SLinus Torvalds 	/* send command */
59601da177e4SLinus Torvalds 	if (((ret =
59611da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
59621da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
59631da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
59641da177e4SLinus Torvalds 
59651da177e4SLinus Torvalds 		memset(ha->conf, 0, sizeof (IPS_CONF));
59661da177e4SLinus Torvalds 
59671da177e4SLinus Torvalds 		/* reset initiator IDs */
59681da177e4SLinus Torvalds 		for (i = 0; i < 4; i++)
59691da177e4SLinus Torvalds 			ha->conf->init_id[i] = 7;
59701da177e4SLinus Torvalds 
59711da177e4SLinus Torvalds 		/* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
59721da177e4SLinus Torvalds 		if ((scb->basic_status & IPS_GSC_STATUS_MASK) ==
59731da177e4SLinus Torvalds 		    IPS_CMD_CMPLT_WERROR)
59741da177e4SLinus Torvalds 			return (1);
59751da177e4SLinus Torvalds 
59761da177e4SLinus Torvalds 		return (0);
59771da177e4SLinus Torvalds 	}
59781da177e4SLinus Torvalds 
59791da177e4SLinus Torvalds 	memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
59801da177e4SLinus Torvalds 	return (1);
59811da177e4SLinus Torvalds }
59821da177e4SLinus Torvalds 
59831da177e4SLinus Torvalds /****************************************************************************/
59841da177e4SLinus Torvalds /*                                                                          */
59851da177e4SLinus Torvalds /* Routine Name: ips_readwrite_page5                                        */
59861da177e4SLinus Torvalds /*                                                                          */
59871da177e4SLinus Torvalds /* Routine Description:                                                     */
59881da177e4SLinus Torvalds /*                                                                          */
59891da177e4SLinus Torvalds /*   Read nvram page 5 from the adapter                                     */
59901da177e4SLinus Torvalds /*                                                                          */
59911da177e4SLinus Torvalds /****************************************************************************/
59921da177e4SLinus Torvalds static int
59931da177e4SLinus Torvalds ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
59941da177e4SLinus Torvalds {
59951da177e4SLinus Torvalds 	ips_scb_t *scb;
59961da177e4SLinus Torvalds 	int ret;
59971da177e4SLinus Torvalds 
59981da177e4SLinus Torvalds 	METHOD_TRACE("ips_readwrite_page5", 1);
59991da177e4SLinus Torvalds 
60001da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
60011da177e4SLinus Torvalds 
60021da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
60031da177e4SLinus Torvalds 
60041da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
60051da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;
60061da177e4SLinus Torvalds 
60071da177e4SLinus Torvalds 	scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;
60081da177e4SLinus Torvalds 	scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
60091da177e4SLinus Torvalds 	scb->cmd.nvram.page = 5;
60101da177e4SLinus Torvalds 	scb->cmd.nvram.write = write;
60111da177e4SLinus Torvalds 	scb->cmd.nvram.reserved = 0;
60121da177e4SLinus Torvalds 	scb->cmd.nvram.reserved2 = 0;
60131da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->nvram);
60141da177e4SLinus Torvalds 	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
60151da177e4SLinus Torvalds 	if (write)
60161da177e4SLinus Torvalds 		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
60171da177e4SLinus Torvalds 
60181da177e4SLinus Torvalds 	/* issue the command */
60191da177e4SLinus Torvalds 	if (((ret =
60201da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
60211da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
60221da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
60231da177e4SLinus Torvalds 
60241da177e4SLinus Torvalds 		memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));
60251da177e4SLinus Torvalds 
60261da177e4SLinus Torvalds 		return (0);
60271da177e4SLinus Torvalds 	}
60281da177e4SLinus Torvalds 	if (!write)
60291da177e4SLinus Torvalds 		memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram));
60301da177e4SLinus Torvalds 	return (1);
60311da177e4SLinus Torvalds }
60321da177e4SLinus Torvalds 
60331da177e4SLinus Torvalds /****************************************************************************/
60341da177e4SLinus Torvalds /*                                                                          */
60351da177e4SLinus Torvalds /* Routine Name: ips_clear_adapter                                          */
60361da177e4SLinus Torvalds /*                                                                          */
60371da177e4SLinus Torvalds /* Routine Description:                                                     */
60381da177e4SLinus Torvalds /*                                                                          */
60391da177e4SLinus Torvalds /*   Clear the stripe lock tables                                           */
60401da177e4SLinus Torvalds /*                                                                          */
60411da177e4SLinus Torvalds /****************************************************************************/
60421da177e4SLinus Torvalds static int
60431da177e4SLinus Torvalds ips_clear_adapter(ips_ha_t * ha, int intr)
60441da177e4SLinus Torvalds {
60451da177e4SLinus Torvalds 	ips_scb_t *scb;
60461da177e4SLinus Torvalds 	int ret;
60471da177e4SLinus Torvalds 
60481da177e4SLinus Torvalds 	METHOD_TRACE("ips_clear_adapter", 1);
60491da177e4SLinus Torvalds 
60501da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
60511da177e4SLinus Torvalds 
60521da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
60531da177e4SLinus Torvalds 
60541da177e4SLinus Torvalds 	scb->timeout = ips_reset_timeout;
60551da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_CONFIG_SYNC;
60561da177e4SLinus Torvalds 
60571da177e4SLinus Torvalds 	scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;
60581da177e4SLinus Torvalds 	scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);
60591da177e4SLinus Torvalds 	scb->cmd.config_sync.channel = 0;
60601da177e4SLinus Torvalds 	scb->cmd.config_sync.source_target = IPS_POCL;
60611da177e4SLinus Torvalds 	scb->cmd.config_sync.reserved = 0;
60621da177e4SLinus Torvalds 	scb->cmd.config_sync.reserved2 = 0;
60631da177e4SLinus Torvalds 	scb->cmd.config_sync.reserved3 = 0;
60641da177e4SLinus Torvalds 
60651da177e4SLinus Torvalds 	/* issue command */
60661da177e4SLinus Torvalds 	if (((ret =
60671da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE)
60681da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
60691da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
60701da177e4SLinus Torvalds 		return (0);
60711da177e4SLinus Torvalds 
60721da177e4SLinus Torvalds 	/* send unlock stripe command */
60731da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
60741da177e4SLinus Torvalds 
60751da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_ERROR_TABLE;
60761da177e4SLinus Torvalds 	scb->timeout = ips_reset_timeout;
60771da177e4SLinus Torvalds 
60781da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;
60791da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);
60801da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.log_drv = 0;
60811da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.control = IPS_CSL;
60821da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.reserved = 0;
60831da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.reserved2 = 0;
60841da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.reserved3 = 0;
60851da177e4SLinus Torvalds 
60861da177e4SLinus Torvalds 	/* issue command */
60871da177e4SLinus Torvalds 	if (((ret =
60881da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
60891da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
60901da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
60911da177e4SLinus Torvalds 		return (0);
60921da177e4SLinus Torvalds 
60931da177e4SLinus Torvalds 	return (1);
60941da177e4SLinus Torvalds }
60951da177e4SLinus Torvalds 
60961da177e4SLinus Torvalds /****************************************************************************/
60971da177e4SLinus Torvalds /*                                                                          */
60981da177e4SLinus Torvalds /* Routine Name: ips_ffdc_reset                                             */
60991da177e4SLinus Torvalds /*                                                                          */
61001da177e4SLinus Torvalds /* Routine Description:                                                     */
61011da177e4SLinus Torvalds /*                                                                          */
61021da177e4SLinus Torvalds /*   FFDC: write reset info                                                 */
61031da177e4SLinus Torvalds /*                                                                          */
61041da177e4SLinus Torvalds /****************************************************************************/
61051da177e4SLinus Torvalds static void
61061da177e4SLinus Torvalds ips_ffdc_reset(ips_ha_t * ha, int intr)
61071da177e4SLinus Torvalds {
61081da177e4SLinus Torvalds 	ips_scb_t *scb;
61091da177e4SLinus Torvalds 
61101da177e4SLinus Torvalds 	METHOD_TRACE("ips_ffdc_reset", 1);
61111da177e4SLinus Torvalds 
61121da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
61131da177e4SLinus Torvalds 
61141da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
61151da177e4SLinus Torvalds 
61161da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
61171da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_FFDC;
61181da177e4SLinus Torvalds 	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
61191da177e4SLinus Torvalds 	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
61201da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_count = ha->reset_count;
61211da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_type = 0x80;
61221da177e4SLinus Torvalds 
61231da177e4SLinus Torvalds 	/* convert time to what the card wants */
61241da177e4SLinus Torvalds 	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
61251da177e4SLinus Torvalds 
61261da177e4SLinus Torvalds 	/* issue command */
61271da177e4SLinus Torvalds 	ips_send_wait(ha, scb, ips_cmd_timeout, intr);
61281da177e4SLinus Torvalds }
61291da177e4SLinus Torvalds 
61301da177e4SLinus Torvalds /****************************************************************************/
61311da177e4SLinus Torvalds /*                                                                          */
61321da177e4SLinus Torvalds /* Routine Name: ips_ffdc_time                                              */
61331da177e4SLinus Torvalds /*                                                                          */
61341da177e4SLinus Torvalds /* Routine Description:                                                     */
61351da177e4SLinus Torvalds /*                                                                          */
61361da177e4SLinus Torvalds /*   FFDC: write time info                                                  */
61371da177e4SLinus Torvalds /*                                                                          */
61381da177e4SLinus Torvalds /****************************************************************************/
61391da177e4SLinus Torvalds static void
61401da177e4SLinus Torvalds ips_ffdc_time(ips_ha_t * ha)
61411da177e4SLinus Torvalds {
61421da177e4SLinus Torvalds 	ips_scb_t *scb;
61431da177e4SLinus Torvalds 
61441da177e4SLinus Torvalds 	METHOD_TRACE("ips_ffdc_time", 1);
61451da177e4SLinus Torvalds 
61461da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);
61471da177e4SLinus Torvalds 
61481da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
61491da177e4SLinus Torvalds 
61501da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
61511da177e4SLinus Torvalds 
61521da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
61531da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_FFDC;
61541da177e4SLinus Torvalds 	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
61551da177e4SLinus Torvalds 	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
61561da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_count = 0;
61571da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_type = 0;
61581da177e4SLinus Torvalds 
61591da177e4SLinus Torvalds 	/* convert time to what the card wants */
61601da177e4SLinus Torvalds 	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
61611da177e4SLinus Torvalds 
61621da177e4SLinus Torvalds 	/* issue command */
61631da177e4SLinus Torvalds 	ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
61641da177e4SLinus Torvalds }
61651da177e4SLinus Torvalds 
61661da177e4SLinus Torvalds /****************************************************************************/
61671da177e4SLinus Torvalds /*                                                                          */
61681da177e4SLinus Torvalds /* Routine Name: ips_fix_ffdc_time                                          */
61691da177e4SLinus Torvalds /*                                                                          */
61701da177e4SLinus Torvalds /* Routine Description:                                                     */
61711da177e4SLinus Torvalds /*   Adjust time_t to what the card wants                                   */
61721da177e4SLinus Torvalds /*                                                                          */
61731da177e4SLinus Torvalds /****************************************************************************/
61741da177e4SLinus Torvalds static void
61751da177e4SLinus Torvalds ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time)
61761da177e4SLinus Torvalds {
61771da177e4SLinus Torvalds 	long days;
61781da177e4SLinus Torvalds 	long rem;
61791da177e4SLinus Torvalds 	int i;
61801da177e4SLinus Torvalds 	int year;
61811da177e4SLinus Torvalds 	int yleap;
61821da177e4SLinus Torvalds 	int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };
61831da177e4SLinus Torvalds 	int month_lengths[12][2] = { {31, 31},
61841da177e4SLinus Torvalds 	{28, 29},
61851da177e4SLinus Torvalds 	{31, 31},
61861da177e4SLinus Torvalds 	{30, 30},
61871da177e4SLinus Torvalds 	{31, 31},
61881da177e4SLinus Torvalds 	{30, 30},
61891da177e4SLinus Torvalds 	{31, 31},
61901da177e4SLinus Torvalds 	{31, 31},
61911da177e4SLinus Torvalds 	{30, 30},
61921da177e4SLinus Torvalds 	{31, 31},
61931da177e4SLinus Torvalds 	{30, 30},
61941da177e4SLinus Torvalds 	{31, 31}
61951da177e4SLinus Torvalds 	};
61961da177e4SLinus Torvalds 
61971da177e4SLinus Torvalds 	METHOD_TRACE("ips_fix_ffdc_time", 1);
61981da177e4SLinus Torvalds 
61991da177e4SLinus Torvalds 	days = current_time / IPS_SECS_DAY;
62001da177e4SLinus Torvalds 	rem = current_time % IPS_SECS_DAY;
62011da177e4SLinus Torvalds 
62021da177e4SLinus Torvalds 	scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);
62031da177e4SLinus Torvalds 	rem = rem % IPS_SECS_HOUR;
62041da177e4SLinus Torvalds 	scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);
62051da177e4SLinus Torvalds 	scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);
62061da177e4SLinus Torvalds 
62071da177e4SLinus Torvalds 	year = IPS_EPOCH_YEAR;
62081da177e4SLinus Torvalds 	while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {
62091da177e4SLinus Torvalds 		int newy;
62101da177e4SLinus Torvalds 
62111da177e4SLinus Torvalds 		newy = year + (days / IPS_DAYS_NORMAL_YEAR);
62121da177e4SLinus Torvalds 		if (days < 0)
62131da177e4SLinus Torvalds 			--newy;
62141da177e4SLinus Torvalds 		days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +
62151da177e4SLinus Torvalds 		    IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -
62161da177e4SLinus Torvalds 		    IPS_NUM_LEAP_YEARS_THROUGH(year - 1);
62171da177e4SLinus Torvalds 		year = newy;
62181da177e4SLinus Torvalds 	}
62191da177e4SLinus Torvalds 
62201da177e4SLinus Torvalds 	scb->cmd.ffdc.yearH = year / 100;
62211da177e4SLinus Torvalds 	scb->cmd.ffdc.yearL = year % 100;
62221da177e4SLinus Torvalds 
62231da177e4SLinus Torvalds 	for (i = 0; days >= month_lengths[i][yleap]; ++i)
62241da177e4SLinus Torvalds 		days -= month_lengths[i][yleap];
62251da177e4SLinus Torvalds 
62261da177e4SLinus Torvalds 	scb->cmd.ffdc.month = i + 1;
62271da177e4SLinus Torvalds 	scb->cmd.ffdc.day = days + 1;
62281da177e4SLinus Torvalds }
62291da177e4SLinus Torvalds 
62301da177e4SLinus Torvalds /****************************************************************************
62311da177e4SLinus Torvalds  * BIOS Flash Routines                                                      *
62321da177e4SLinus Torvalds  ****************************************************************************/
62331da177e4SLinus Torvalds 
62341da177e4SLinus Torvalds /****************************************************************************/
62351da177e4SLinus Torvalds /*                                                                          */
62361da177e4SLinus Torvalds /* Routine Name: ips_erase_bios                                             */
62371da177e4SLinus Torvalds /*                                                                          */
62381da177e4SLinus Torvalds /* Routine Description:                                                     */
62391da177e4SLinus Torvalds /*   Erase the BIOS on the adapter                                          */
62401da177e4SLinus Torvalds /*                                                                          */
62411da177e4SLinus Torvalds /****************************************************************************/
62421da177e4SLinus Torvalds static int
62431da177e4SLinus Torvalds ips_erase_bios(ips_ha_t * ha)
62441da177e4SLinus Torvalds {
62451da177e4SLinus Torvalds 	int timeout;
62461da177e4SLinus Torvalds 	uint8_t status = 0;
62471da177e4SLinus Torvalds 
62481da177e4SLinus Torvalds 	METHOD_TRACE("ips_erase_bios", 1);
62491da177e4SLinus Torvalds 
62501da177e4SLinus Torvalds 	status = 0;
62511da177e4SLinus Torvalds 
62521da177e4SLinus Torvalds 	/* Clear the status register */
62531da177e4SLinus Torvalds 	outl(0, ha->io_addr + IPS_REG_FLAP);
62541da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
62551da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
62561da177e4SLinus Torvalds 
62571da177e4SLinus Torvalds 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
62581da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
62591da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
62601da177e4SLinus Torvalds 
62611da177e4SLinus Torvalds 	/* Erase Setup */
62621da177e4SLinus Torvalds 	outb(0x20, ha->io_addr + IPS_REG_FLDP);
62631da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
62641da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
62651da177e4SLinus Torvalds 
62661da177e4SLinus Torvalds 	/* Erase Confirm */
62671da177e4SLinus Torvalds 	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
62681da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
62691da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
62701da177e4SLinus Torvalds 
62711da177e4SLinus Torvalds 	/* Erase Status */
62721da177e4SLinus Torvalds 	outb(0x70, ha->io_addr + IPS_REG_FLDP);
62731da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
62741da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
62751da177e4SLinus Torvalds 
62761da177e4SLinus Torvalds 	timeout = 80000;	/* 80 seconds */
62771da177e4SLinus Torvalds 
62781da177e4SLinus Torvalds 	while (timeout > 0) {
62791da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64) {
62801da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
62811da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
62821da177e4SLinus Torvalds 		}
62831da177e4SLinus Torvalds 
62841da177e4SLinus Torvalds 		status = inb(ha->io_addr + IPS_REG_FLDP);
62851da177e4SLinus Torvalds 
62861da177e4SLinus Torvalds 		if (status & 0x80)
62871da177e4SLinus Torvalds 			break;
62881da177e4SLinus Torvalds 
62891da177e4SLinus Torvalds 		MDELAY(1);
62901da177e4SLinus Torvalds 		timeout--;
62911da177e4SLinus Torvalds 	}
62921da177e4SLinus Torvalds 
62931da177e4SLinus Torvalds 	/* check for timeout */
62941da177e4SLinus Torvalds 	if (timeout <= 0) {
62951da177e4SLinus Torvalds 		/* timeout */
62961da177e4SLinus Torvalds 
62971da177e4SLinus Torvalds 		/* try to suspend the erase */
62981da177e4SLinus Torvalds 		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
62991da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
63001da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
63011da177e4SLinus Torvalds 
63021da177e4SLinus Torvalds 		/* wait for 10 seconds */
63031da177e4SLinus Torvalds 		timeout = 10000;
63041da177e4SLinus Torvalds 		while (timeout > 0) {
63051da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
63061da177e4SLinus Torvalds 				outl(0, ha->io_addr + IPS_REG_FLAP);
63071da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
63081da177e4SLinus Torvalds 			}
63091da177e4SLinus Torvalds 
63101da177e4SLinus Torvalds 			status = inb(ha->io_addr + IPS_REG_FLDP);
63111da177e4SLinus Torvalds 
63121da177e4SLinus Torvalds 			if (status & 0xC0)
63131da177e4SLinus Torvalds 				break;
63141da177e4SLinus Torvalds 
63151da177e4SLinus Torvalds 			MDELAY(1);
63161da177e4SLinus Torvalds 			timeout--;
63171da177e4SLinus Torvalds 		}
63181da177e4SLinus Torvalds 
63191da177e4SLinus Torvalds 		return (1);
63201da177e4SLinus Torvalds 	}
63211da177e4SLinus Torvalds 
63221da177e4SLinus Torvalds 	/* check for valid VPP */
63231da177e4SLinus Torvalds 	if (status & 0x08)
63241da177e4SLinus Torvalds 		/* VPP failure */
63251da177e4SLinus Torvalds 		return (1);
63261da177e4SLinus Torvalds 
63271da177e4SLinus Torvalds 	/* check for succesful flash */
63281da177e4SLinus Torvalds 	if (status & 0x30)
63291da177e4SLinus Torvalds 		/* sequence error */
63301da177e4SLinus Torvalds 		return (1);
63311da177e4SLinus Torvalds 
63321da177e4SLinus Torvalds 	/* Otherwise, we were successful */
63331da177e4SLinus Torvalds 	/* clear status */
63341da177e4SLinus Torvalds 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
63351da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63361da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63371da177e4SLinus Torvalds 
63381da177e4SLinus Torvalds 	/* enable reads */
63391da177e4SLinus Torvalds 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
63401da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63411da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63421da177e4SLinus Torvalds 
63431da177e4SLinus Torvalds 	return (0);
63441da177e4SLinus Torvalds }
63451da177e4SLinus Torvalds 
63461da177e4SLinus Torvalds /****************************************************************************/
63471da177e4SLinus Torvalds /*                                                                          */
63481da177e4SLinus Torvalds /* Routine Name: ips_erase_bios_memio                                       */
63491da177e4SLinus Torvalds /*                                                                          */
63501da177e4SLinus Torvalds /* Routine Description:                                                     */
63511da177e4SLinus Torvalds /*   Erase the BIOS on the adapter                                          */
63521da177e4SLinus Torvalds /*                                                                          */
63531da177e4SLinus Torvalds /****************************************************************************/
63541da177e4SLinus Torvalds static int
63551da177e4SLinus Torvalds ips_erase_bios_memio(ips_ha_t * ha)
63561da177e4SLinus Torvalds {
63571da177e4SLinus Torvalds 	int timeout;
63581da177e4SLinus Torvalds 	uint8_t status;
63591da177e4SLinus Torvalds 
63601da177e4SLinus Torvalds 	METHOD_TRACE("ips_erase_bios_memio", 1);
63611da177e4SLinus Torvalds 
63621da177e4SLinus Torvalds 	status = 0;
63631da177e4SLinus Torvalds 
63641da177e4SLinus Torvalds 	/* Clear the status register */
63651da177e4SLinus Torvalds 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
63661da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63671da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63681da177e4SLinus Torvalds 
63691da177e4SLinus Torvalds 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
63701da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63711da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63721da177e4SLinus Torvalds 
63731da177e4SLinus Torvalds 	/* Erase Setup */
63741da177e4SLinus Torvalds 	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
63751da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63761da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63771da177e4SLinus Torvalds 
63781da177e4SLinus Torvalds 	/* Erase Confirm */
63791da177e4SLinus Torvalds 	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
63801da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63811da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63821da177e4SLinus Torvalds 
63831da177e4SLinus Torvalds 	/* Erase Status */
63841da177e4SLinus Torvalds 	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
63851da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
63861da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
63871da177e4SLinus Torvalds 
63881da177e4SLinus Torvalds 	timeout = 80000;	/* 80 seconds */
63891da177e4SLinus Torvalds 
63901da177e4SLinus Torvalds 	while (timeout > 0) {
63911da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64) {
63921da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
63931da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
63941da177e4SLinus Torvalds 		}
63951da177e4SLinus Torvalds 
63961da177e4SLinus Torvalds 		status = readb(ha->mem_ptr + IPS_REG_FLDP);
63971da177e4SLinus Torvalds 
63981da177e4SLinus Torvalds 		if (status & 0x80)
63991da177e4SLinus Torvalds 			break;
64001da177e4SLinus Torvalds 
64011da177e4SLinus Torvalds 		MDELAY(1);
64021da177e4SLinus Torvalds 		timeout--;
64031da177e4SLinus Torvalds 	}
64041da177e4SLinus Torvalds 
64051da177e4SLinus Torvalds 	/* check for timeout */
64061da177e4SLinus Torvalds 	if (timeout <= 0) {
64071da177e4SLinus Torvalds 		/* timeout */
64081da177e4SLinus Torvalds 
64091da177e4SLinus Torvalds 		/* try to suspend the erase */
64101da177e4SLinus Torvalds 		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
64111da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
64121da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
64131da177e4SLinus Torvalds 
64141da177e4SLinus Torvalds 		/* wait for 10 seconds */
64151da177e4SLinus Torvalds 		timeout = 10000;
64161da177e4SLinus Torvalds 		while (timeout > 0) {
64171da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
64181da177e4SLinus Torvalds 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
64191da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
64201da177e4SLinus Torvalds 			}
64211da177e4SLinus Torvalds 
64221da177e4SLinus Torvalds 			status = readb(ha->mem_ptr + IPS_REG_FLDP);
64231da177e4SLinus Torvalds 
64241da177e4SLinus Torvalds 			if (status & 0xC0)
64251da177e4SLinus Torvalds 				break;
64261da177e4SLinus Torvalds 
64271da177e4SLinus Torvalds 			MDELAY(1);
64281da177e4SLinus Torvalds 			timeout--;
64291da177e4SLinus Torvalds 		}
64301da177e4SLinus Torvalds 
64311da177e4SLinus Torvalds 		return (1);
64321da177e4SLinus Torvalds 	}
64331da177e4SLinus Torvalds 
64341da177e4SLinus Torvalds 	/* check for valid VPP */
64351da177e4SLinus Torvalds 	if (status & 0x08)
64361da177e4SLinus Torvalds 		/* VPP failure */
64371da177e4SLinus Torvalds 		return (1);
64381da177e4SLinus Torvalds 
64391da177e4SLinus Torvalds 	/* check for succesful flash */
64401da177e4SLinus Torvalds 	if (status & 0x30)
64411da177e4SLinus Torvalds 		/* sequence error */
64421da177e4SLinus Torvalds 		return (1);
64431da177e4SLinus Torvalds 
64441da177e4SLinus Torvalds 	/* Otherwise, we were successful */
64451da177e4SLinus Torvalds 	/* clear status */
64461da177e4SLinus Torvalds 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
64471da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
64481da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
64491da177e4SLinus Torvalds 
64501da177e4SLinus Torvalds 	/* enable reads */
64511da177e4SLinus Torvalds 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
64521da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
64531da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
64541da177e4SLinus Torvalds 
64551da177e4SLinus Torvalds 	return (0);
64561da177e4SLinus Torvalds }
64571da177e4SLinus Torvalds 
64581da177e4SLinus Torvalds /****************************************************************************/
64591da177e4SLinus Torvalds /*                                                                          */
64601da177e4SLinus Torvalds /* Routine Name: ips_program_bios                                           */
64611da177e4SLinus Torvalds /*                                                                          */
64621da177e4SLinus Torvalds /* Routine Description:                                                     */
64631da177e4SLinus Torvalds /*   Program the BIOS on the adapter                                        */
64641da177e4SLinus Torvalds /*                                                                          */
64651da177e4SLinus Torvalds /****************************************************************************/
64661da177e4SLinus Torvalds static int
64671da177e4SLinus Torvalds ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
64681da177e4SLinus Torvalds 		 uint32_t offset)
64691da177e4SLinus Torvalds {
64701da177e4SLinus Torvalds 	int i;
64711da177e4SLinus Torvalds 	int timeout;
64721da177e4SLinus Torvalds 	uint8_t status = 0;
64731da177e4SLinus Torvalds 
64741da177e4SLinus Torvalds 	METHOD_TRACE("ips_program_bios", 1);
64751da177e4SLinus Torvalds 
64761da177e4SLinus Torvalds 	status = 0;
64771da177e4SLinus Torvalds 
64781da177e4SLinus Torvalds 	for (i = 0; i < buffersize; i++) {
64791da177e4SLinus Torvalds 		/* write a byte */
64801da177e4SLinus Torvalds 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
64811da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
64821da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
64831da177e4SLinus Torvalds 
64841da177e4SLinus Torvalds 		outb(0x40, ha->io_addr + IPS_REG_FLDP);
64851da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
64861da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
64871da177e4SLinus Torvalds 
64881da177e4SLinus Torvalds 		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
64891da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
64901da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
64911da177e4SLinus Torvalds 
64921da177e4SLinus Torvalds 		/* wait up to one second */
64931da177e4SLinus Torvalds 		timeout = 1000;
64941da177e4SLinus Torvalds 		while (timeout > 0) {
64951da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
64961da177e4SLinus Torvalds 				outl(0, ha->io_addr + IPS_REG_FLAP);
64971da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
64981da177e4SLinus Torvalds 			}
64991da177e4SLinus Torvalds 
65001da177e4SLinus Torvalds 			status = inb(ha->io_addr + IPS_REG_FLDP);
65011da177e4SLinus Torvalds 
65021da177e4SLinus Torvalds 			if (status & 0x80)
65031da177e4SLinus Torvalds 				break;
65041da177e4SLinus Torvalds 
65051da177e4SLinus Torvalds 			MDELAY(1);
65061da177e4SLinus Torvalds 			timeout--;
65071da177e4SLinus Torvalds 		}
65081da177e4SLinus Torvalds 
65091da177e4SLinus Torvalds 		if (timeout == 0) {
65101da177e4SLinus Torvalds 			/* timeout error */
65111da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
65121da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
65131da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
65141da177e4SLinus Torvalds 
65151da177e4SLinus Torvalds 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
65161da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
65171da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
65181da177e4SLinus Torvalds 
65191da177e4SLinus Torvalds 			return (1);
65201da177e4SLinus Torvalds 		}
65211da177e4SLinus Torvalds 
65221da177e4SLinus Torvalds 		/* check the status */
65231da177e4SLinus Torvalds 		if (status & 0x18) {
65241da177e4SLinus Torvalds 			/* programming error */
65251da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
65261da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
65271da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
65281da177e4SLinus Torvalds 
65291da177e4SLinus Torvalds 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
65301da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
65311da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
65321da177e4SLinus Torvalds 
65331da177e4SLinus Torvalds 			return (1);
65341da177e4SLinus Torvalds 		}
65351da177e4SLinus Torvalds 	}			/* end for */
65361da177e4SLinus Torvalds 
65371da177e4SLinus Torvalds 	/* Enable reading */
65381da177e4SLinus Torvalds 	outl(0, ha->io_addr + IPS_REG_FLAP);
65391da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
65401da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
65411da177e4SLinus Torvalds 
65421da177e4SLinus Torvalds 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
65431da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
65441da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
65451da177e4SLinus Torvalds 
65461da177e4SLinus Torvalds 	return (0);
65471da177e4SLinus Torvalds }
65481da177e4SLinus Torvalds 
65491da177e4SLinus Torvalds /****************************************************************************/
65501da177e4SLinus Torvalds /*                                                                          */
65511da177e4SLinus Torvalds /* Routine Name: ips_program_bios_memio                                     */
65521da177e4SLinus Torvalds /*                                                                          */
65531da177e4SLinus Torvalds /* Routine Description:                                                     */
65541da177e4SLinus Torvalds /*   Program the BIOS on the adapter                                        */
65551da177e4SLinus Torvalds /*                                                                          */
65561da177e4SLinus Torvalds /****************************************************************************/
65571da177e4SLinus Torvalds static int
65581da177e4SLinus Torvalds ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
65591da177e4SLinus Torvalds 		       uint32_t offset)
65601da177e4SLinus Torvalds {
65611da177e4SLinus Torvalds 	int i;
65621da177e4SLinus Torvalds 	int timeout;
65631da177e4SLinus Torvalds 	uint8_t status = 0;
65641da177e4SLinus Torvalds 
65651da177e4SLinus Torvalds 	METHOD_TRACE("ips_program_bios_memio", 1);
65661da177e4SLinus Torvalds 
65671da177e4SLinus Torvalds 	status = 0;
65681da177e4SLinus Torvalds 
65691da177e4SLinus Torvalds 	for (i = 0; i < buffersize; i++) {
65701da177e4SLinus Torvalds 		/* write a byte */
65711da177e4SLinus Torvalds 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
65721da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
65731da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
65741da177e4SLinus Torvalds 
65751da177e4SLinus Torvalds 		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
65761da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
65771da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
65781da177e4SLinus Torvalds 
65791da177e4SLinus Torvalds 		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
65801da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
65811da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
65821da177e4SLinus Torvalds 
65831da177e4SLinus Torvalds 		/* wait up to one second */
65841da177e4SLinus Torvalds 		timeout = 1000;
65851da177e4SLinus Torvalds 		while (timeout > 0) {
65861da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
65871da177e4SLinus Torvalds 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
65881da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
65891da177e4SLinus Torvalds 			}
65901da177e4SLinus Torvalds 
65911da177e4SLinus Torvalds 			status = readb(ha->mem_ptr + IPS_REG_FLDP);
65921da177e4SLinus Torvalds 
65931da177e4SLinus Torvalds 			if (status & 0x80)
65941da177e4SLinus Torvalds 				break;
65951da177e4SLinus Torvalds 
65961da177e4SLinus Torvalds 			MDELAY(1);
65971da177e4SLinus Torvalds 			timeout--;
65981da177e4SLinus Torvalds 		}
65991da177e4SLinus Torvalds 
66001da177e4SLinus Torvalds 		if (timeout == 0) {
66011da177e4SLinus Torvalds 			/* timeout error */
66021da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
66031da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
66041da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
66051da177e4SLinus Torvalds 
66061da177e4SLinus Torvalds 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
66071da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
66081da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
66091da177e4SLinus Torvalds 
66101da177e4SLinus Torvalds 			return (1);
66111da177e4SLinus Torvalds 		}
66121da177e4SLinus Torvalds 
66131da177e4SLinus Torvalds 		/* check the status */
66141da177e4SLinus Torvalds 		if (status & 0x18) {
66151da177e4SLinus Torvalds 			/* programming error */
66161da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
66171da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
66181da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
66191da177e4SLinus Torvalds 
66201da177e4SLinus Torvalds 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
66211da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
66221da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
66231da177e4SLinus Torvalds 
66241da177e4SLinus Torvalds 			return (1);
66251da177e4SLinus Torvalds 		}
66261da177e4SLinus Torvalds 	}			/* end for */
66271da177e4SLinus Torvalds 
66281da177e4SLinus Torvalds 	/* Enable reading */
66291da177e4SLinus Torvalds 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
66301da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
66311da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
66321da177e4SLinus Torvalds 
66331da177e4SLinus Torvalds 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
66341da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
66351da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
66361da177e4SLinus Torvalds 
66371da177e4SLinus Torvalds 	return (0);
66381da177e4SLinus Torvalds }
66391da177e4SLinus Torvalds 
66401da177e4SLinus Torvalds /****************************************************************************/
66411da177e4SLinus Torvalds /*                                                                          */
66421da177e4SLinus Torvalds /* Routine Name: ips_verify_bios                                            */
66431da177e4SLinus Torvalds /*                                                                          */
66441da177e4SLinus Torvalds /* Routine Description:                                                     */
66451da177e4SLinus Torvalds /*   Verify the BIOS on the adapter                                         */
66461da177e4SLinus Torvalds /*                                                                          */
66471da177e4SLinus Torvalds /****************************************************************************/
66481da177e4SLinus Torvalds static int
66491da177e4SLinus Torvalds ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
66501da177e4SLinus Torvalds 		uint32_t offset)
66511da177e4SLinus Torvalds {
66521da177e4SLinus Torvalds 	uint8_t checksum;
66531da177e4SLinus Torvalds 	int i;
66541da177e4SLinus Torvalds 
66551da177e4SLinus Torvalds 	METHOD_TRACE("ips_verify_bios", 1);
66561da177e4SLinus Torvalds 
66571da177e4SLinus Torvalds 	/* test 1st byte */
66581da177e4SLinus Torvalds 	outl(0, ha->io_addr + IPS_REG_FLAP);
66591da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
66601da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
66611da177e4SLinus Torvalds 
66621da177e4SLinus Torvalds 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
66631da177e4SLinus Torvalds 		return (1);
66641da177e4SLinus Torvalds 
66651da177e4SLinus Torvalds 	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
66661da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
66671da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
66681da177e4SLinus Torvalds 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
66691da177e4SLinus Torvalds 		return (1);
66701da177e4SLinus Torvalds 
66711da177e4SLinus Torvalds 	checksum = 0xff;
66721da177e4SLinus Torvalds 	for (i = 2; i < buffersize; i++) {
66731da177e4SLinus Torvalds 
66741da177e4SLinus Torvalds 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
66751da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
66761da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
66771da177e4SLinus Torvalds 
66781da177e4SLinus Torvalds 		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
66791da177e4SLinus Torvalds 	}
66801da177e4SLinus Torvalds 
66811da177e4SLinus Torvalds 	if (checksum != 0)
66821da177e4SLinus Torvalds 		/* failure */
66831da177e4SLinus Torvalds 		return (1);
66841da177e4SLinus Torvalds 	else
66851da177e4SLinus Torvalds 		/* success */
66861da177e4SLinus Torvalds 		return (0);
66871da177e4SLinus Torvalds }
66881da177e4SLinus Torvalds 
66891da177e4SLinus Torvalds /****************************************************************************/
66901da177e4SLinus Torvalds /*                                                                          */
66911da177e4SLinus Torvalds /* Routine Name: ips_verify_bios_memio                                      */
66921da177e4SLinus Torvalds /*                                                                          */
66931da177e4SLinus Torvalds /* Routine Description:                                                     */
66941da177e4SLinus Torvalds /*   Verify the BIOS on the adapter                                         */
66951da177e4SLinus Torvalds /*                                                                          */
66961da177e4SLinus Torvalds /****************************************************************************/
66971da177e4SLinus Torvalds static int
66981da177e4SLinus Torvalds ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
66991da177e4SLinus Torvalds 		      uint32_t offset)
67001da177e4SLinus Torvalds {
67011da177e4SLinus Torvalds 	uint8_t checksum;
67021da177e4SLinus Torvalds 	int i;
67031da177e4SLinus Torvalds 
67041da177e4SLinus Torvalds 	METHOD_TRACE("ips_verify_bios_memio", 1);
67051da177e4SLinus Torvalds 
67061da177e4SLinus Torvalds 	/* test 1st byte */
67071da177e4SLinus Torvalds 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
67081da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
67091da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
67101da177e4SLinus Torvalds 
67111da177e4SLinus Torvalds 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
67121da177e4SLinus Torvalds 		return (1);
67131da177e4SLinus Torvalds 
67141da177e4SLinus Torvalds 	writel(1, ha->mem_ptr + IPS_REG_FLAP);
67151da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
67161da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
67171da177e4SLinus Torvalds 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
67181da177e4SLinus Torvalds 		return (1);
67191da177e4SLinus Torvalds 
67201da177e4SLinus Torvalds 	checksum = 0xff;
67211da177e4SLinus Torvalds 	for (i = 2; i < buffersize; i++) {
67221da177e4SLinus Torvalds 
67231da177e4SLinus Torvalds 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
67241da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
67251da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
67261da177e4SLinus Torvalds 
67271da177e4SLinus Torvalds 		checksum =
67281da177e4SLinus Torvalds 		    (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
67291da177e4SLinus Torvalds 	}
67301da177e4SLinus Torvalds 
67311da177e4SLinus Torvalds 	if (checksum != 0)
67321da177e4SLinus Torvalds 		/* failure */
67331da177e4SLinus Torvalds 		return (1);
67341da177e4SLinus Torvalds 	else
67351da177e4SLinus Torvalds 		/* success */
67361da177e4SLinus Torvalds 		return (0);
67371da177e4SLinus Torvalds }
67381da177e4SLinus Torvalds 
67391da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
67401da177e4SLinus Torvalds /*   Routine Name: ips_version_check                                         */
67411da177e4SLinus Torvalds /*                                                                           */
67421da177e4SLinus Torvalds /*   Dependencies:                                                           */
67431da177e4SLinus Torvalds /*     Assumes that ips_read_adapter_status() is called first filling in     */
67441da177e4SLinus Torvalds /*     the data for SubSystem Parameters.                                    */
67451da177e4SLinus Torvalds /*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */
67461da177e4SLinus Torvalds /*     Data is available.                                                    */
67471da177e4SLinus Torvalds /*                                                                           */
67481da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
67491da177e4SLinus Torvalds static void
67501da177e4SLinus Torvalds ips_version_check(ips_ha_t * ha, int intr)
67511da177e4SLinus Torvalds {
67521da177e4SLinus Torvalds 	IPS_VERSION_DATA *VersionInfo;
67531da177e4SLinus Torvalds 	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
67541da177e4SLinus Torvalds 	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
67551da177e4SLinus Torvalds 	int MatchError;
67561da177e4SLinus Torvalds 	int rc;
67571da177e4SLinus Torvalds 	char BiosString[10];
67581da177e4SLinus Torvalds 	char FirmwareString[10];
67591da177e4SLinus Torvalds 
67601da177e4SLinus Torvalds 	METHOD_TRACE("ips_version_check", 1);
67611da177e4SLinus Torvalds 
67621da177e4SLinus Torvalds 	VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;
67631da177e4SLinus Torvalds 
67641da177e4SLinus Torvalds 	memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
67651da177e4SLinus Torvalds 	memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
67661da177e4SLinus Torvalds 
67671da177e4SLinus Torvalds 	/* Get the Compatible BIOS Version from NVRAM Page 5 */
67681da177e4SLinus Torvalds 	memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,
67691da177e4SLinus Torvalds 	       IPS_COMPAT_ID_LENGTH);
67701da177e4SLinus Torvalds 
67711da177e4SLinus Torvalds 	rc = IPS_FAILURE;
67721da177e4SLinus Torvalds 	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */
67731da177e4SLinus Torvalds 		/* Get the Version Info with a Get Version Command */
67741da177e4SLinus Torvalds 		memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
67751da177e4SLinus Torvalds 		rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);
67761da177e4SLinus Torvalds 		if (rc == IPS_SUCCESS)
67771da177e4SLinus Torvalds 			memcpy(FirmwareVersion, VersionInfo->compatibilityId,
67781da177e4SLinus Torvalds 			       IPS_COMPAT_ID_LENGTH);
67791da177e4SLinus Torvalds 	}
67801da177e4SLinus Torvalds 
67811da177e4SLinus Torvalds 	if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */
67821da177e4SLinus Torvalds 		/* Get the Firmware Version from Enquiry Data */
67831da177e4SLinus Torvalds 		memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,
67841da177e4SLinus Torvalds 		       IPS_COMPAT_ID_LENGTH);
67851da177e4SLinus Torvalds 	}
67861da177e4SLinus Torvalds 
67871da177e4SLinus Torvalds 	/* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
67881da177e4SLinus Torvalds 	/* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
67891da177e4SLinus Torvalds 	/* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
67901da177e4SLinus Torvalds 	/* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
67911da177e4SLinus Torvalds 
67921da177e4SLinus Torvalds 	MatchError = 0;
67931da177e4SLinus Torvalds 
67941da177e4SLinus Torvalds 	if (strncmp
67951da177e4SLinus Torvalds 	    (FirmwareVersion, Compatable[ha->nvram->adapter_type],
67961da177e4SLinus Torvalds 	     IPS_COMPAT_ID_LENGTH) != 0)
67971da177e4SLinus Torvalds 		MatchError = 1;
67981da177e4SLinus Torvalds 
67991da177e4SLinus Torvalds 	if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
68001da177e4SLinus Torvalds 		MatchError = 1;
68011da177e4SLinus Torvalds 
68021da177e4SLinus Torvalds 	ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */
68031da177e4SLinus Torvalds 
68041da177e4SLinus Torvalds 	if (MatchError) {
68051da177e4SLinus Torvalds 		ha->nvram->version_mismatch = 1;
68061da177e4SLinus Torvalds 		if (ips_cd_boot == 0) {
68071da177e4SLinus Torvalds 			strncpy(&BiosString[0], ha->nvram->bios_high, 4);
68081da177e4SLinus Torvalds 			strncpy(&BiosString[4], ha->nvram->bios_low, 4);
68091da177e4SLinus Torvalds 			BiosString[8] = 0;
68101da177e4SLinus Torvalds 
68111da177e4SLinus Torvalds 			strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
68121da177e4SLinus Torvalds 			FirmwareString[8] = 0;
68131da177e4SLinus Torvalds 
68141da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
68151da177e4SLinus Torvalds 				   "Warning ! ! ! ServeRAID Version Mismatch\n");
68161da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
68171da177e4SLinus Torvalds 				   "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
68181da177e4SLinus Torvalds 				   BiosString, FirmwareString, IPS_VERSION_HIGH,
68191da177e4SLinus Torvalds 				   IPS_VERSION_LOW);
68201da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
68211da177e4SLinus Torvalds 				   "These levels should match to avoid possible compatibility problems.\n");
68221da177e4SLinus Torvalds 		}
68231da177e4SLinus Torvalds 	} else {
68241da177e4SLinus Torvalds 		ha->nvram->version_mismatch = 0;
68251da177e4SLinus Torvalds 	}
68261da177e4SLinus Torvalds 
68271da177e4SLinus Torvalds 	return;
68281da177e4SLinus Torvalds }
68291da177e4SLinus Torvalds 
68301da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
68311da177e4SLinus Torvalds /*   Routine Name: ips_get_version_info                                      */
68321da177e4SLinus Torvalds /*                                                                           */
68331da177e4SLinus Torvalds /*   Routine Description:                                                    */
68341da177e4SLinus Torvalds /*     Issue an internal GETVERSION Command                                  */
68351da177e4SLinus Torvalds /*                                                                           */
68361da177e4SLinus Torvalds /*   Return Value:                                                           */
68371da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
68381da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
68391da177e4SLinus Torvalds static int
68401da177e4SLinus Torvalds ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr)
68411da177e4SLinus Torvalds {
68421da177e4SLinus Torvalds 	ips_scb_t *scb;
68431da177e4SLinus Torvalds 	int rc;
68441da177e4SLinus Torvalds 
68451da177e4SLinus Torvalds 	METHOD_TRACE("ips_get_version_info", 1);
68461da177e4SLinus Torvalds 
68471da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
68481da177e4SLinus Torvalds 
68491da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
68501da177e4SLinus Torvalds 
68511da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
68521da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
68531da177e4SLinus Torvalds 	scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
68541da177e4SLinus Torvalds 	scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
68551da177e4SLinus Torvalds 	scb->cmd.version_info.reserved = 0;
68561da177e4SLinus Torvalds 	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
68571da177e4SLinus Torvalds 	scb->cmd.version_info.reserved2 = 0;
68581da177e4SLinus Torvalds 	scb->data_len = sizeof (IPS_VERSION_DATA);
68591da177e4SLinus Torvalds 	scb->data_busaddr = Buffer;
68601da177e4SLinus Torvalds 	scb->cmd.version_info.buffer_addr = Buffer;
68611da177e4SLinus Torvalds 	scb->flags = 0;
68621da177e4SLinus Torvalds 
68631da177e4SLinus Torvalds 	/* issue command */
68641da177e4SLinus Torvalds 	rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
68651da177e4SLinus Torvalds 	return (rc);
68661da177e4SLinus Torvalds }
68671da177e4SLinus Torvalds 
68681da177e4SLinus Torvalds /****************************************************************************/
68691da177e4SLinus Torvalds /*                                                                          */
68701da177e4SLinus Torvalds /* Routine Name: ips_abort_init                                             */
68711da177e4SLinus Torvalds /*                                                                          */
68721da177e4SLinus Torvalds /* Routine Description:                                                     */
68731da177e4SLinus Torvalds /*   cleanup routine for a failed adapter initialization                    */
68741da177e4SLinus Torvalds /****************************************************************************/
68751da177e4SLinus Torvalds static int
68761da177e4SLinus Torvalds ips_abort_init(ips_ha_t * ha, int index)
68771da177e4SLinus Torvalds {
68781da177e4SLinus Torvalds 	ha->active = 0;
68791da177e4SLinus Torvalds 	ips_free(ha);
68801da177e4SLinus Torvalds 	ips_ha[index] = NULL;
68811da177e4SLinus Torvalds 	ips_sh[index] = NULL;
68821da177e4SLinus Torvalds 	return -1;
68831da177e4SLinus Torvalds }
68841da177e4SLinus Torvalds 
68851da177e4SLinus Torvalds /****************************************************************************/
68861da177e4SLinus Torvalds /*                                                                          */
68871da177e4SLinus Torvalds /* Routine Name: ips_shift_controllers                                      */
68881da177e4SLinus Torvalds /*                                                                          */
68891da177e4SLinus Torvalds /* Routine Description:                                                     */
68901da177e4SLinus Torvalds /*   helper function for ordering adapters                                  */
68911da177e4SLinus Torvalds /****************************************************************************/
68921da177e4SLinus Torvalds static void
68931da177e4SLinus Torvalds ips_shift_controllers(int lowindex, int highindex)
68941da177e4SLinus Torvalds {
68951da177e4SLinus Torvalds 	ips_ha_t *ha_sav = ips_ha[highindex];
68961da177e4SLinus Torvalds 	struct Scsi_Host *sh_sav = ips_sh[highindex];
68971da177e4SLinus Torvalds 	int i;
68981da177e4SLinus Torvalds 
68991da177e4SLinus Torvalds 	for (i = highindex; i > lowindex; i--) {
69001da177e4SLinus Torvalds 		ips_ha[i] = ips_ha[i - 1];
69011da177e4SLinus Torvalds 		ips_sh[i] = ips_sh[i - 1];
69021da177e4SLinus Torvalds 		ips_ha[i]->host_num = i;
69031da177e4SLinus Torvalds 	}
69041da177e4SLinus Torvalds 	ha_sav->host_num = lowindex;
69051da177e4SLinus Torvalds 	ips_ha[lowindex] = ha_sav;
69061da177e4SLinus Torvalds 	ips_sh[lowindex] = sh_sav;
69071da177e4SLinus Torvalds }
69081da177e4SLinus Torvalds 
69091da177e4SLinus Torvalds /****************************************************************************/
69101da177e4SLinus Torvalds /*                                                                          */
69111da177e4SLinus Torvalds /* Routine Name: ips_order_controllers                                      */
69121da177e4SLinus Torvalds /*                                                                          */
69131da177e4SLinus Torvalds /* Routine Description:                                                     */
69141da177e4SLinus Torvalds /*   place controllers is the "proper" boot order                           */
69151da177e4SLinus Torvalds /****************************************************************************/
69161da177e4SLinus Torvalds static void
69171da177e4SLinus Torvalds ips_order_controllers(void)
69181da177e4SLinus Torvalds {
69191da177e4SLinus Torvalds 	int i, j, tmp, position = 0;
69201da177e4SLinus Torvalds 	IPS_NVRAM_P5 *nvram;
69211da177e4SLinus Torvalds 	if (!ips_ha[0])
69221da177e4SLinus Torvalds 		return;
69231da177e4SLinus Torvalds 	nvram = ips_ha[0]->nvram;
69241da177e4SLinus Torvalds 
69251da177e4SLinus Torvalds 	if (nvram->adapter_order[0]) {
69261da177e4SLinus Torvalds 		for (i = 1; i <= nvram->adapter_order[0]; i++) {
69271da177e4SLinus Torvalds 			for (j = position; j < ips_num_controllers; j++) {
69281da177e4SLinus Torvalds 				switch (ips_ha[j]->ad_type) {
69291da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID6M:
69301da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID7M:
69311da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'M') {
69321da177e4SLinus Torvalds 						ips_shift_controllers(position,
69331da177e4SLinus Torvalds 								      j);
69341da177e4SLinus Torvalds 						position++;
69351da177e4SLinus Torvalds 					}
69361da177e4SLinus Torvalds 					break;
69371da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4L:
69381da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4M:
69391da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4MX:
69401da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4LX:
69411da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'N') {
69421da177e4SLinus Torvalds 						ips_shift_controllers(position,
69431da177e4SLinus Torvalds 								      j);
69441da177e4SLinus Torvalds 						position++;
69451da177e4SLinus Torvalds 					}
69461da177e4SLinus Torvalds 					break;
69471da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID6I:
69481da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID5I2:
69491da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID5I1:
69501da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID7k:
69511da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'S') {
69521da177e4SLinus Torvalds 						ips_shift_controllers(position,
69531da177e4SLinus Torvalds 								      j);
69541da177e4SLinus Torvalds 						position++;
69551da177e4SLinus Torvalds 					}
69561da177e4SLinus Torvalds 					break;
69571da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID:
69581da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID2:
69591da177e4SLinus Torvalds 				case IPS_ADTYPE_NAVAJO:
69601da177e4SLinus Torvalds 				case IPS_ADTYPE_KIOWA:
69611da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID3L:
69621da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID3:
69631da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4H:
69641da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'A') {
69651da177e4SLinus Torvalds 						ips_shift_controllers(position,
69661da177e4SLinus Torvalds 								      j);
69671da177e4SLinus Torvalds 						position++;
69681da177e4SLinus Torvalds 					}
69691da177e4SLinus Torvalds 					break;
69701da177e4SLinus Torvalds 				default:
69711da177e4SLinus Torvalds 					break;
69721da177e4SLinus Torvalds 				}
69731da177e4SLinus Torvalds 			}
69741da177e4SLinus Torvalds 		}
69751da177e4SLinus Torvalds 		/* if adapter_order[0], then ordering is complete */
69761da177e4SLinus Torvalds 		return;
69771da177e4SLinus Torvalds 	}
69781da177e4SLinus Torvalds 	/* old bios, use older ordering */
69791da177e4SLinus Torvalds 	tmp = 0;
69801da177e4SLinus Torvalds 	for (i = position; i < ips_num_controllers; i++) {
69811da177e4SLinus Torvalds 		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 ||
69821da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) {
69831da177e4SLinus Torvalds 			ips_shift_controllers(position, i);
69841da177e4SLinus Torvalds 			position++;
69851da177e4SLinus Torvalds 			tmp = 1;
69861da177e4SLinus Torvalds 		}
69871da177e4SLinus Torvalds 	}
69881da177e4SLinus Torvalds 	/* if there were no 5I cards, then don't do any extra ordering */
69891da177e4SLinus Torvalds 	if (!tmp)
69901da177e4SLinus Torvalds 		return;
69911da177e4SLinus Torvalds 	for (i = position; i < ips_num_controllers; i++) {
69921da177e4SLinus Torvalds 		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L ||
69931da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M ||
69941da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX ||
69951da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) {
69961da177e4SLinus Torvalds 			ips_shift_controllers(position, i);
69971da177e4SLinus Torvalds 			position++;
69981da177e4SLinus Torvalds 		}
69991da177e4SLinus Torvalds 	}
70001da177e4SLinus Torvalds 
70011da177e4SLinus Torvalds 	return;
70021da177e4SLinus Torvalds }
70031da177e4SLinus Torvalds 
70041da177e4SLinus Torvalds /****************************************************************************/
70051da177e4SLinus Torvalds /*                                                                          */
70061da177e4SLinus Torvalds /* Routine Name: ips_register_scsi                                          */
70071da177e4SLinus Torvalds /*                                                                          */
70081da177e4SLinus Torvalds /* Routine Description:                                                     */
70091da177e4SLinus Torvalds /*   perform any registration and setup with the scsi layer                 */
70101da177e4SLinus Torvalds /****************************************************************************/
70111da177e4SLinus Torvalds static int
70121da177e4SLinus Torvalds ips_register_scsi(int index)
70131da177e4SLinus Torvalds {
70141da177e4SLinus Torvalds 	struct Scsi_Host *sh;
70151da177e4SLinus Torvalds 	ips_ha_t *ha, *oldha = ips_ha[index];
70161da177e4SLinus Torvalds 	sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t));
70171da177e4SLinus Torvalds 	if (!sh) {
70181da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, oldha->pcidev,
70191da177e4SLinus Torvalds 			   "Unable to register controller with SCSI subsystem\n");
70201da177e4SLinus Torvalds 		return -1;
70211da177e4SLinus Torvalds 	}
70221da177e4SLinus Torvalds 	ha = IPS_HA(sh);
70231da177e4SLinus Torvalds 	memcpy(ha, oldha, sizeof (ips_ha_t));
70241da177e4SLinus Torvalds 	free_irq(oldha->irq, oldha);
70251da177e4SLinus Torvalds 	/* Install the interrupt handler with the new ha */
70261da177e4SLinus Torvalds 	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
70271da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
70281da177e4SLinus Torvalds 			   "Unable to install interrupt handler\n");
70291da177e4SLinus Torvalds 		scsi_host_put(sh);
70301da177e4SLinus Torvalds 		return -1;
70311da177e4SLinus Torvalds 	}
70321da177e4SLinus Torvalds 
70331da177e4SLinus Torvalds 	kfree(oldha);
70341da177e4SLinus Torvalds 	ips_sh[index] = sh;
70351da177e4SLinus Torvalds 	ips_ha[index] = ha;
70361da177e4SLinus Torvalds 	IPS_SCSI_SET_DEVICE(sh, ha);
70371da177e4SLinus Torvalds 
70381da177e4SLinus Torvalds 	/* Store away needed values for later use */
70391da177e4SLinus Torvalds 	sh->io_port = ha->io_addr;
70401da177e4SLinus Torvalds 	sh->n_io_port = ha->io_addr ? 255 : 0;
70411da177e4SLinus Torvalds 	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
70421da177e4SLinus Torvalds 	sh->irq = ha->irq;
70431da177e4SLinus Torvalds 	sh->sg_tablesize = sh->hostt->sg_tablesize;
70441da177e4SLinus Torvalds 	sh->can_queue = sh->hostt->can_queue;
70451da177e4SLinus Torvalds 	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
70461da177e4SLinus Torvalds 	sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
70471da177e4SLinus Torvalds 	sh->use_clustering = sh->hostt->use_clustering;
70481da177e4SLinus Torvalds 
70491da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
70501da177e4SLinus Torvalds 	sh->max_sectors = 128;
70511da177e4SLinus Torvalds #endif
70521da177e4SLinus Torvalds 
70531da177e4SLinus Torvalds 	sh->max_id = ha->ntargets;
70541da177e4SLinus Torvalds 	sh->max_lun = ha->nlun;
70551da177e4SLinus Torvalds 	sh->max_channel = ha->nbus - 1;
70561da177e4SLinus Torvalds 	sh->can_queue = ha->max_cmds - 1;
70571da177e4SLinus Torvalds 
70581da177e4SLinus Torvalds 	IPS_ADD_HOST(sh, NULL);
70591da177e4SLinus Torvalds 	return 0;
70601da177e4SLinus Torvalds }
70611da177e4SLinus Torvalds 
70621da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
70631da177e4SLinus Torvalds /*   Routine Name: ips_remove_device                                         */
70641da177e4SLinus Torvalds /*                                                                           */
70651da177e4SLinus Torvalds /*   Routine Description:                                                    */
70661da177e4SLinus Torvalds /*     Remove one Adapter ( Hot Plugging )                                   */
70671da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
70681da177e4SLinus Torvalds static void __devexit
70691da177e4SLinus Torvalds ips_remove_device(struct pci_dev *pci_dev)
70701da177e4SLinus Torvalds {
70711da177e4SLinus Torvalds 	int i;
70721da177e4SLinus Torvalds 	struct Scsi_Host *sh;
70731da177e4SLinus Torvalds 	ips_ha_t *ha;
70741da177e4SLinus Torvalds 
70751da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
70761da177e4SLinus Torvalds 		ha = ips_ha[i];
70771da177e4SLinus Torvalds 		if (ha) {
70781da177e4SLinus Torvalds 			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
70791da177e4SLinus Torvalds 			    (pci_dev->devfn == ha->pcidev->devfn)) {
70801da177e4SLinus Torvalds 				sh = ips_sh[i];
70811da177e4SLinus Torvalds 				ips_release(sh);
70821da177e4SLinus Torvalds 			}
70831da177e4SLinus Torvalds 		}
70841da177e4SLinus Torvalds 	}
70851da177e4SLinus Torvalds }
70861da177e4SLinus Torvalds 
70871da177e4SLinus Torvalds /****************************************************************************/
70881da177e4SLinus Torvalds /*                                                                          */
70891da177e4SLinus Torvalds /* Routine Name: ips_module_init                                            */
70901da177e4SLinus Torvalds /*                                                                          */
70911da177e4SLinus Torvalds /* Routine Description:                                                     */
70921da177e4SLinus Torvalds /*   function called on module load                                         */
70931da177e4SLinus Torvalds /****************************************************************************/
70941da177e4SLinus Torvalds static int __init
70951da177e4SLinus Torvalds ips_module_init(void)
70961da177e4SLinus Torvalds {
70971da177e4SLinus Torvalds 	if (pci_module_init(&ips_pci_driver) < 0)
70981da177e4SLinus Torvalds 		return -ENODEV;
70991da177e4SLinus Torvalds 	ips_driver_template.module = THIS_MODULE;
71001da177e4SLinus Torvalds 	ips_order_controllers();
71011da177e4SLinus Torvalds 	if (IPS_REGISTER_HOSTS(&ips_driver_template)) {
71021da177e4SLinus Torvalds 		pci_unregister_driver(&ips_pci_driver);
71031da177e4SLinus Torvalds 		return -ENODEV;
71041da177e4SLinus Torvalds 	}
71051da177e4SLinus Torvalds 	register_reboot_notifier(&ips_notifier);
71061da177e4SLinus Torvalds 	return 0;
71071da177e4SLinus Torvalds }
71081da177e4SLinus Torvalds 
71091da177e4SLinus Torvalds /****************************************************************************/
71101da177e4SLinus Torvalds /*                                                                          */
71111da177e4SLinus Torvalds /* Routine Name: ips_module_exit                                            */
71121da177e4SLinus Torvalds /*                                                                          */
71131da177e4SLinus Torvalds /* Routine Description:                                                     */
71141da177e4SLinus Torvalds /*   function called on module unload                                       */
71151da177e4SLinus Torvalds /****************************************************************************/
71161da177e4SLinus Torvalds static void __exit
71171da177e4SLinus Torvalds ips_module_exit(void)
71181da177e4SLinus Torvalds {
71191da177e4SLinus Torvalds 	IPS_UNREGISTER_HOSTS(&ips_driver_template);
71201da177e4SLinus Torvalds 	pci_unregister_driver(&ips_pci_driver);
71211da177e4SLinus Torvalds 	unregister_reboot_notifier(&ips_notifier);
71221da177e4SLinus Torvalds }
71231da177e4SLinus Torvalds 
71241da177e4SLinus Torvalds module_init(ips_module_init);
71251da177e4SLinus Torvalds module_exit(ips_module_exit);
71261da177e4SLinus Torvalds 
71271da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
71281da177e4SLinus Torvalds /*   Routine Name: ips_insert_device                                         */
71291da177e4SLinus Torvalds /*                                                                           */
71301da177e4SLinus Torvalds /*   Routine Description:                                                    */
71311da177e4SLinus Torvalds /*     Add One Adapter ( Hot Plug )                                          */
71321da177e4SLinus Torvalds /*                                                                           */
71331da177e4SLinus Torvalds /*   Return Value:                                                           */
71341da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
71351da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
71361da177e4SLinus Torvalds static int __devinit
71371da177e4SLinus Torvalds ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
71381da177e4SLinus Torvalds {
71391da177e4SLinus Torvalds 	int index;
71401da177e4SLinus Torvalds 	int rc;
71411da177e4SLinus Torvalds 
71421da177e4SLinus Torvalds 	METHOD_TRACE("ips_insert_device", 1);
71431da177e4SLinus Torvalds 	if (pci_enable_device(pci_dev))
71441da177e4SLinus Torvalds 		return -1;
71451da177e4SLinus Torvalds 
71461da177e4SLinus Torvalds 	rc = ips_init_phase1(pci_dev, &index);
71471da177e4SLinus Torvalds 	if (rc == SUCCESS)
71481da177e4SLinus Torvalds 		rc = ips_init_phase2(index);
71491da177e4SLinus Torvalds 
71501da177e4SLinus Torvalds 	if (ips_hotplug)
71511da177e4SLinus Torvalds 		if (ips_register_scsi(index)) {
71521da177e4SLinus Torvalds 			ips_free(ips_ha[index]);
71531da177e4SLinus Torvalds 			rc = -1;
71541da177e4SLinus Torvalds 		}
71551da177e4SLinus Torvalds 
71561da177e4SLinus Torvalds 	if (rc == SUCCESS)
71571da177e4SLinus Torvalds 		ips_num_controllers++;
71581da177e4SLinus Torvalds 
71591da177e4SLinus Torvalds 	ips_next_controller = ips_num_controllers;
71601da177e4SLinus Torvalds 	return rc;
71611da177e4SLinus Torvalds }
71621da177e4SLinus Torvalds 
71631da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
71641da177e4SLinus Torvalds /*   Routine Name: ips_init_phase1                                           */
71651da177e4SLinus Torvalds /*                                                                           */
71661da177e4SLinus Torvalds /*   Routine Description:                                                    */
71671da177e4SLinus Torvalds /*     Adapter Initialization                                                */
71681da177e4SLinus Torvalds /*                                                                           */
71691da177e4SLinus Torvalds /*   Return Value:                                                           */
71701da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
71711da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
71721da177e4SLinus Torvalds static int
71731da177e4SLinus Torvalds ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
71741da177e4SLinus Torvalds {
71751da177e4SLinus Torvalds 	ips_ha_t *ha;
71761da177e4SLinus Torvalds 	uint32_t io_addr;
71771da177e4SLinus Torvalds 	uint32_t mem_addr;
71781da177e4SLinus Torvalds 	uint32_t io_len;
71791da177e4SLinus Torvalds 	uint32_t mem_len;
71801da177e4SLinus Torvalds 	uint8_t revision_id;
71811da177e4SLinus Torvalds 	uint8_t bus;
71821da177e4SLinus Torvalds 	uint8_t func;
71831da177e4SLinus Torvalds 	uint8_t irq;
71841da177e4SLinus Torvalds 	uint16_t subdevice_id;
71851da177e4SLinus Torvalds 	int j;
71861da177e4SLinus Torvalds 	int index;
71871da177e4SLinus Torvalds 	dma_addr_t dma_address;
71881da177e4SLinus Torvalds 	char __iomem *ioremap_ptr;
71891da177e4SLinus Torvalds 	char __iomem *mem_ptr;
71901da177e4SLinus Torvalds 	uint32_t IsDead;
71911da177e4SLinus Torvalds 
71921da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_phase1", 1);
71931da177e4SLinus Torvalds 	index = IPS_MAX_ADAPTERS;
71941da177e4SLinus Torvalds 	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
71951da177e4SLinus Torvalds 		if (ips_ha[j] == 0) {
71961da177e4SLinus Torvalds 			index = j;
71971da177e4SLinus Torvalds 			break;
71981da177e4SLinus Torvalds 		}
71991da177e4SLinus Torvalds 	}
72001da177e4SLinus Torvalds 
72011da177e4SLinus Torvalds 	if (index >= IPS_MAX_ADAPTERS)
72021da177e4SLinus Torvalds 		return -1;
72031da177e4SLinus Torvalds 
72041da177e4SLinus Torvalds 	/* stuff that we get in dev */
72051da177e4SLinus Torvalds 	irq = pci_dev->irq;
72061da177e4SLinus Torvalds 	bus = pci_dev->bus->number;
72071da177e4SLinus Torvalds 	func = pci_dev->devfn;
72081da177e4SLinus Torvalds 
72091da177e4SLinus Torvalds 	/* Init MEM/IO addresses to 0 */
72101da177e4SLinus Torvalds 	mem_addr = 0;
72111da177e4SLinus Torvalds 	io_addr = 0;
72121da177e4SLinus Torvalds 	mem_len = 0;
72131da177e4SLinus Torvalds 	io_len = 0;
72141da177e4SLinus Torvalds 
72151da177e4SLinus Torvalds 	for (j = 0; j < 2; j++) {
72161da177e4SLinus Torvalds 		if (!pci_resource_start(pci_dev, j))
72171da177e4SLinus Torvalds 			break;
72181da177e4SLinus Torvalds 
72191da177e4SLinus Torvalds 		if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
72201da177e4SLinus Torvalds 			io_addr = pci_resource_start(pci_dev, j);
72211da177e4SLinus Torvalds 			io_len = pci_resource_len(pci_dev, j);
72221da177e4SLinus Torvalds 		} else {
72231da177e4SLinus Torvalds 			mem_addr = pci_resource_start(pci_dev, j);
72241da177e4SLinus Torvalds 			mem_len = pci_resource_len(pci_dev, j);
72251da177e4SLinus Torvalds 		}
72261da177e4SLinus Torvalds 	}
72271da177e4SLinus Torvalds 
72281da177e4SLinus Torvalds 	/* setup memory mapped area (if applicable) */
72291da177e4SLinus Torvalds 	if (mem_addr) {
72301da177e4SLinus Torvalds 		uint32_t base;
72311da177e4SLinus Torvalds 		uint32_t offs;
72321da177e4SLinus Torvalds 
72331da177e4SLinus Torvalds 		if (!request_mem_region(mem_addr, mem_len, "ips")) {
72341da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, pci_dev,
72351da177e4SLinus Torvalds 				   "Couldn't allocate IO Memory space %x len %d.\n",
72361da177e4SLinus Torvalds 				   mem_addr, mem_len);
72371da177e4SLinus Torvalds 			return -1;
72381da177e4SLinus Torvalds 		}
72391da177e4SLinus Torvalds 
72401da177e4SLinus Torvalds 		base = mem_addr & PAGE_MASK;
72411da177e4SLinus Torvalds 		offs = mem_addr - base;
72421da177e4SLinus Torvalds 		ioremap_ptr = ioremap(base, PAGE_SIZE);
72431da177e4SLinus Torvalds 		mem_ptr = ioremap_ptr + offs;
72441da177e4SLinus Torvalds 	} else {
72451da177e4SLinus Torvalds 		ioremap_ptr = NULL;
72461da177e4SLinus Torvalds 		mem_ptr = NULL;
72471da177e4SLinus Torvalds 	}
72481da177e4SLinus Torvalds 
72491da177e4SLinus Torvalds 	/* setup I/O mapped area (if applicable) */
72501da177e4SLinus Torvalds 	if (io_addr) {
72511da177e4SLinus Torvalds 		if (!request_region(io_addr, io_len, "ips")) {
72521da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, pci_dev,
72531da177e4SLinus Torvalds 				   "Couldn't allocate IO space %x len %d.\n",
72541da177e4SLinus Torvalds 				   io_addr, io_len);
72551da177e4SLinus Torvalds 			return -1;
72561da177e4SLinus Torvalds 		}
72571da177e4SLinus Torvalds 	}
72581da177e4SLinus Torvalds 
72591da177e4SLinus Torvalds 	/* get the revision ID */
72601da177e4SLinus Torvalds 	if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
72611da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");
72621da177e4SLinus Torvalds 		return -1;
72631da177e4SLinus Torvalds 	}
72641da177e4SLinus Torvalds 
72651da177e4SLinus Torvalds 	subdevice_id = pci_dev->subsystem_device;
72661da177e4SLinus Torvalds 
72671da177e4SLinus Torvalds 	/* found a controller */
72681da177e4SLinus Torvalds 	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
72691da177e4SLinus Torvalds 	if (ha == NULL) {
72701da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
72711da177e4SLinus Torvalds 			   "Unable to allocate temporary ha struct\n");
72721da177e4SLinus Torvalds 		return -1;
72731da177e4SLinus Torvalds 	}
72741da177e4SLinus Torvalds 
72751da177e4SLinus Torvalds 	memset(ha, 0, sizeof (ips_ha_t));
72761da177e4SLinus Torvalds 
72771da177e4SLinus Torvalds 	ips_sh[index] = NULL;
72781da177e4SLinus Torvalds 	ips_ha[index] = ha;
72791da177e4SLinus Torvalds 	ha->active = 1;
72801da177e4SLinus Torvalds 
72811da177e4SLinus Torvalds 	/* Store info in HA structure */
72821da177e4SLinus Torvalds 	ha->irq = irq;
72831da177e4SLinus Torvalds 	ha->io_addr = io_addr;
72841da177e4SLinus Torvalds 	ha->io_len = io_len;
72851da177e4SLinus Torvalds 	ha->mem_addr = mem_addr;
72861da177e4SLinus Torvalds 	ha->mem_len = mem_len;
72871da177e4SLinus Torvalds 	ha->mem_ptr = mem_ptr;
72881da177e4SLinus Torvalds 	ha->ioremap_ptr = ioremap_ptr;
72891da177e4SLinus Torvalds 	ha->host_num = (uint32_t) index;
72901da177e4SLinus Torvalds 	ha->revision_id = revision_id;
72911da177e4SLinus Torvalds 	ha->slot_num = PCI_SLOT(pci_dev->devfn);
72921da177e4SLinus Torvalds 	ha->device_id = pci_dev->device;
72931da177e4SLinus Torvalds 	ha->subdevice_id = subdevice_id;
72941da177e4SLinus Torvalds 	ha->pcidev = pci_dev;
72951da177e4SLinus Torvalds 
72961da177e4SLinus Torvalds 	/*
72971da177e4SLinus Torvalds 	 * Set the pci_dev's dma_mask.  Not all adapters support 64bit
72981da177e4SLinus Torvalds 	 * addressing so don't enable it if the adapter can't support
72991da177e4SLinus Torvalds 	 * it!  Also, don't use 64bit addressing if dma addresses
73001da177e4SLinus Torvalds 	 * are guaranteed to be < 4G.
73011da177e4SLinus Torvalds 	 */
73021da177e4SLinus Torvalds 	if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
73031da177e4SLinus Torvalds 	    !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) {
73041da177e4SLinus Torvalds 		(ha)->flags |= IPS_HA_ENH_SG;
73051da177e4SLinus Torvalds 	} else {
73061da177e4SLinus Torvalds 		if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) {
73071da177e4SLinus Torvalds 			printk(KERN_WARNING "Unable to set DMA Mask\n");
73081da177e4SLinus Torvalds 			return ips_abort_init(ha, index);
73091da177e4SLinus Torvalds 		}
73101da177e4SLinus Torvalds 	}
73111da177e4SLinus Torvalds 	if(ips_cd_boot && !ips_FlashData){
73121da177e4SLinus Torvalds 		ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7,
73131da177e4SLinus Torvalds 						     &ips_flashbusaddr);
73141da177e4SLinus Torvalds 	}
73151da177e4SLinus Torvalds 
73161da177e4SLinus Torvalds 	ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ),
73171da177e4SLinus Torvalds 				       &ha->enq_busaddr);
73181da177e4SLinus Torvalds 	if (!ha->enq) {
73191da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73201da177e4SLinus Torvalds 			   "Unable to allocate host inquiry structure\n");
73211da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73221da177e4SLinus Torvalds 	}
73231da177e4SLinus Torvalds 
73241da177e4SLinus Torvalds 	ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) +
73251da177e4SLinus Torvalds 					 sizeof (IPS_IO_CMD), &dma_address);
73261da177e4SLinus Torvalds 	if (!ha->adapt) {
73271da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73281da177e4SLinus Torvalds 			   "Unable to allocate host adapt & dummy structures\n");
73291da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73301da177e4SLinus Torvalds 	}
73311da177e4SLinus Torvalds 	ha->adapt->hw_status_start = dma_address;
73321da177e4SLinus Torvalds 	ha->dummy = (void *) (ha->adapt + 1);
73331da177e4SLinus Torvalds 
73341da177e4SLinus Torvalds 
73351da177e4SLinus Torvalds 
73361da177e4SLinus Torvalds 	ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address);
73371da177e4SLinus Torvalds 	if (!ha->logical_drive_info) {
73381da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73391da177e4SLinus Torvalds 			   "Unable to allocate logical drive info structure\n");
73401da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73411da177e4SLinus Torvalds 	}
73421da177e4SLinus Torvalds 	ha->logical_drive_info_dma_addr = dma_address;
73431da177e4SLinus Torvalds 
73441da177e4SLinus Torvalds 
73451da177e4SLinus Torvalds 	ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);
73461da177e4SLinus Torvalds 
73471da177e4SLinus Torvalds 	if (!ha->conf) {
73481da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73491da177e4SLinus Torvalds 			   "Unable to allocate host conf structure\n");
73501da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73511da177e4SLinus Torvalds 	}
73521da177e4SLinus Torvalds 
73531da177e4SLinus Torvalds 	ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);
73541da177e4SLinus Torvalds 
73551da177e4SLinus Torvalds 	if (!ha->nvram) {
73561da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73571da177e4SLinus Torvalds 			   "Unable to allocate host NVRAM structure\n");
73581da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73591da177e4SLinus Torvalds 	}
73601da177e4SLinus Torvalds 
73611da177e4SLinus Torvalds 	ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);
73621da177e4SLinus Torvalds 
73631da177e4SLinus Torvalds 	if (!ha->subsys) {
73641da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73651da177e4SLinus Torvalds 			   "Unable to allocate host subsystem structure\n");
73661da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73671da177e4SLinus Torvalds 	}
73681da177e4SLinus Torvalds 
73691da177e4SLinus Torvalds 	/* the ioctl buffer is now used during adapter initialization, so its
73701da177e4SLinus Torvalds 	 * successful allocation is now required */
73711da177e4SLinus Torvalds 	if (ips_ioctlsize < PAGE_SIZE)
73721da177e4SLinus Torvalds 		ips_ioctlsize = PAGE_SIZE;
73731da177e4SLinus Torvalds 
73741da177e4SLinus Torvalds 	ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize,
73751da177e4SLinus Torvalds 					      &ha->ioctl_busaddr);
73761da177e4SLinus Torvalds 	ha->ioctl_len = ips_ioctlsize;
73771da177e4SLinus Torvalds 	if (!ha->ioctl_data) {
73781da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
73791da177e4SLinus Torvalds 			   "Unable to allocate IOCTL data\n");
73801da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
73811da177e4SLinus Torvalds 	}
73821da177e4SLinus Torvalds 
73831da177e4SLinus Torvalds 	/*
73841da177e4SLinus Torvalds 	 * Setup Functions
73851da177e4SLinus Torvalds 	 */
73861da177e4SLinus Torvalds 	ips_setup_funclist(ha);
73871da177e4SLinus Torvalds 
73881da177e4SLinus Torvalds 	if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) {
73891da177e4SLinus Torvalds 		/* If Morpheus appears dead, reset it */
73901da177e4SLinus Torvalds 		IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
73911da177e4SLinus Torvalds 		if (IsDead == 0xDEADBEEF) {
73921da177e4SLinus Torvalds 			ips_reset_morpheus(ha);
73931da177e4SLinus Torvalds 		}
73941da177e4SLinus Torvalds 	}
73951da177e4SLinus Torvalds 
73961da177e4SLinus Torvalds 	/*
73971da177e4SLinus Torvalds 	 * Initialize the card if it isn't already
73981da177e4SLinus Torvalds 	 */
73991da177e4SLinus Torvalds 
74001da177e4SLinus Torvalds 	if (!(*ha->func.isinit) (ha)) {
74011da177e4SLinus Torvalds 		if (!(*ha->func.init) (ha)) {
74021da177e4SLinus Torvalds 			/*
74031da177e4SLinus Torvalds 			 * Initialization failed
74041da177e4SLinus Torvalds 			 */
74051da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, pci_dev,
74061da177e4SLinus Torvalds 				   "Unable to initialize controller\n");
74071da177e4SLinus Torvalds 			return ips_abort_init(ha, index);
74081da177e4SLinus Torvalds 		}
74091da177e4SLinus Torvalds 	}
74101da177e4SLinus Torvalds 
74111da177e4SLinus Torvalds 	*indexPtr = index;
74121da177e4SLinus Torvalds 	return SUCCESS;
74131da177e4SLinus Torvalds }
74141da177e4SLinus Torvalds 
74151da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
74161da177e4SLinus Torvalds /*   Routine Name: ips_init_phase2                                           */
74171da177e4SLinus Torvalds /*                                                                           */
74181da177e4SLinus Torvalds /*   Routine Description:                                                    */
74191da177e4SLinus Torvalds /*     Adapter Initialization Phase 2                                        */
74201da177e4SLinus Torvalds /*                                                                           */
74211da177e4SLinus Torvalds /*   Return Value:                                                           */
74221da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
74231da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
74241da177e4SLinus Torvalds static int
74251da177e4SLinus Torvalds ips_init_phase2(int index)
74261da177e4SLinus Torvalds {
74271da177e4SLinus Torvalds 	ips_ha_t *ha;
74281da177e4SLinus Torvalds 
74291da177e4SLinus Torvalds 	ha = ips_ha[index];
74301da177e4SLinus Torvalds 
74311da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_phase2", 1);
74321da177e4SLinus Torvalds 	if (!ha->active) {
74331da177e4SLinus Torvalds 		ips_ha[index] = NULL;
74341da177e4SLinus Torvalds 		return -1;
74351da177e4SLinus Torvalds 	}
74361da177e4SLinus Torvalds 
74371da177e4SLinus Torvalds 	/* Install the interrupt handler */
74381da177e4SLinus Torvalds 	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
74391da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
74401da177e4SLinus Torvalds 			   "Unable to install interrupt handler\n");
74411da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
74421da177e4SLinus Torvalds 	}
74431da177e4SLinus Torvalds 
74441da177e4SLinus Torvalds 	/*
74451da177e4SLinus Torvalds 	 * Allocate a temporary SCB for initialization
74461da177e4SLinus Torvalds 	 */
74471da177e4SLinus Torvalds 	ha->max_cmds = 1;
74481da177e4SLinus Torvalds 	if (!ips_allocatescbs(ha)) {
74491da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
74501da177e4SLinus Torvalds 			   "Unable to allocate a CCB\n");
74511da177e4SLinus Torvalds 		free_irq(ha->irq, ha);
74521da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
74531da177e4SLinus Torvalds 	}
74541da177e4SLinus Torvalds 
74551da177e4SLinus Torvalds 	if (!ips_hainit(ha)) {
74561da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
74571da177e4SLinus Torvalds 			   "Unable to initialize controller\n");
74581da177e4SLinus Torvalds 		free_irq(ha->irq, ha);
74591da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
74601da177e4SLinus Torvalds 	}
74611da177e4SLinus Torvalds 	/* Free the temporary SCB */
74621da177e4SLinus Torvalds 	ips_deallocatescbs(ha, 1);
74631da177e4SLinus Torvalds 
74641da177e4SLinus Torvalds 	/* allocate CCBs */
74651da177e4SLinus Torvalds 	if (!ips_allocatescbs(ha)) {
74661da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
74671da177e4SLinus Torvalds 			   "Unable to allocate CCBs\n");
74681da177e4SLinus Torvalds 		free_irq(ha->irq, ha);
74691da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
74701da177e4SLinus Torvalds 	}
74711da177e4SLinus Torvalds 
74721da177e4SLinus Torvalds 	return SUCCESS;
74731da177e4SLinus Torvalds }
74741da177e4SLinus Torvalds 
74751da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
74761da177e4SLinus Torvalds MODULE_LICENSE("GPL");
74771da177e4SLinus Torvalds #endif
74781da177e4SLinus Torvalds 
74791da177e4SLinus Torvalds MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
74801da177e4SLinus Torvalds 
74811da177e4SLinus Torvalds #ifdef MODULE_VERSION
74821da177e4SLinus Torvalds MODULE_VERSION(IPS_VER_STRING);
74831da177e4SLinus Torvalds #endif
74841da177e4SLinus Torvalds 
74851da177e4SLinus Torvalds 
74861da177e4SLinus Torvalds /*
74871da177e4SLinus Torvalds  * Overrides for Emacs so that we almost follow Linus's tabbing style.
74881da177e4SLinus Torvalds  * Emacs will notice this stuff at the end of the file and automatically
74891da177e4SLinus Torvalds  * adjust the settings for this buffer only.  This must remain at the end
74901da177e4SLinus Torvalds  * of the file.
74911da177e4SLinus Torvalds  * ---------------------------------------------------------------------------
74921da177e4SLinus Torvalds  * Local variables:
74931da177e4SLinus Torvalds  * c-indent-level: 2
74941da177e4SLinus Torvalds  * c-brace-imaginary-offset: 0
74951da177e4SLinus Torvalds  * c-brace-offset: -2
74961da177e4SLinus Torvalds  * c-argdecl-indent: 2
74971da177e4SLinus Torvalds  * c-label-offset: -2
74981da177e4SLinus Torvalds  * c-continued-statement-offset: 2
74991da177e4SLinus Torvalds  * c-continued-brace-offset: 0
75001da177e4SLinus Torvalds  * indent-tabs-mode: nil
75011da177e4SLinus Torvalds  * tab-width: 8
75021da177e4SLinus Torvalds  * End:
75031da177e4SLinus Torvalds  */
7504