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