xref: /openbmc/linux/drivers/scsi/ips.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*****************************************************************************/
2*1da177e4SLinus Torvalds /* ips.c -- driver for the Adaptec / IBM ServeRAID controller                */
3*1da177e4SLinus Torvalds /*                                                                           */
4*1da177e4SLinus Torvalds /* Written By: Keith Mitchell, IBM Corporation                               */
5*1da177e4SLinus Torvalds /*             Jack Hammer, Adaptec, Inc.                                    */
6*1da177e4SLinus Torvalds /*             David Jeffery, Adaptec, Inc.                                  */
7*1da177e4SLinus Torvalds /*                                                                           */
8*1da177e4SLinus Torvalds /* Copyright (C) 2000 IBM Corporation                                        */
9*1da177e4SLinus Torvalds /* Copyright (C) 2002,2003 Adaptec, Inc.                                     */
10*1da177e4SLinus Torvalds /*                                                                           */
11*1da177e4SLinus Torvalds /* This program is free software; you can redistribute it and/or modify      */
12*1da177e4SLinus Torvalds /* it under the terms of the GNU General Public License as published by      */
13*1da177e4SLinus Torvalds /* the Free Software Foundation; either version 2 of the License, or         */
14*1da177e4SLinus Torvalds /* (at your option) any later version.                                       */
15*1da177e4SLinus Torvalds /*                                                                           */
16*1da177e4SLinus Torvalds /* This program is distributed in the hope that it will be useful,           */
17*1da177e4SLinus Torvalds /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
18*1da177e4SLinus Torvalds /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
19*1da177e4SLinus Torvalds /* GNU General Public License for more details.                              */
20*1da177e4SLinus Torvalds /*                                                                           */
21*1da177e4SLinus Torvalds /* NO WARRANTY                                                               */
22*1da177e4SLinus Torvalds /* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        */
23*1da177e4SLinus Torvalds /* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      */
24*1da177e4SLinus Torvalds /* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      */
25*1da177e4SLinus Torvalds /* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    */
26*1da177e4SLinus Torvalds /* solely responsible for determining the appropriateness of using and       */
27*1da177e4SLinus Torvalds /* distributing the Program and assumes all risks associated with its        */
28*1da177e4SLinus Torvalds /* exercise of rights under this Agreement, including but not limited to     */
29*1da177e4SLinus Torvalds /* the risks and costs of program errors, damage to or loss of data,         */
30*1da177e4SLinus Torvalds /* programs or equipment, and unavailability or interruption of operations.  */
31*1da177e4SLinus Torvalds /*                                                                           */
32*1da177e4SLinus Torvalds /* DISCLAIMER OF LIABILITY                                                   */
33*1da177e4SLinus Torvalds /* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   */
34*1da177e4SLinus Torvalds /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
35*1da177e4SLinus Torvalds /* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   */
36*1da177e4SLinus Torvalds /* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     */
37*1da177e4SLinus Torvalds /* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    */
38*1da177e4SLinus Torvalds /* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  */
39*1da177e4SLinus Torvalds /* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             */
40*1da177e4SLinus Torvalds /*                                                                           */
41*1da177e4SLinus Torvalds /* You should have received a copy of the GNU General Public License         */
42*1da177e4SLinus Torvalds /* along with this program; if not, write to the Free Software               */
43*1da177e4SLinus Torvalds /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
44*1da177e4SLinus Torvalds /*                                                                           */
45*1da177e4SLinus Torvalds /* Bugs/Comments/Suggestions about this driver should be mailed to:          */
46*1da177e4SLinus Torvalds /*      ipslinux@adaptec.com        	                                     */
47*1da177e4SLinus Torvalds /*                                                                           */
48*1da177e4SLinus Torvalds /* For system support issues, contact your local IBM Customer support.       */
49*1da177e4SLinus Torvalds /* Directions to find IBM Customer Support for each country can be found at: */
50*1da177e4SLinus Torvalds /*      http://www.ibm.com/planetwide/                                       */
51*1da177e4SLinus Torvalds /*                                                                           */
52*1da177e4SLinus Torvalds /*****************************************************************************/
53*1da177e4SLinus Torvalds 
54*1da177e4SLinus Torvalds /*****************************************************************************/
55*1da177e4SLinus Torvalds /* Change Log                                                                */
56*1da177e4SLinus Torvalds /*                                                                           */
57*1da177e4SLinus Torvalds /* 0.99.02  - Breakup commands that are bigger than 8 * the stripe size      */
58*1da177e4SLinus Torvalds /* 0.99.03  - Make interrupt routine handle all completed request on the     */
59*1da177e4SLinus Torvalds /*            adapter not just the first one                                 */
60*1da177e4SLinus Torvalds /*          - Make sure passthru commands get woken up if we run out of      */
61*1da177e4SLinus Torvalds /*            SCBs                                                           */
62*1da177e4SLinus Torvalds /*          - Send all of the commands on the queue at once rather than      */
63*1da177e4SLinus Torvalds /*            one at a time since the card will support it.                  */
64*1da177e4SLinus Torvalds /* 0.99.04  - Fix race condition in the passthru mechanism -- this required  */
65*1da177e4SLinus Torvalds /*            the interface to the utilities to change                       */
66*1da177e4SLinus Torvalds /*          - Fix error recovery code                                        */
67*1da177e4SLinus Torvalds /* 0.99.05  - Fix an oops when we get certain passthru commands              */
68*1da177e4SLinus Torvalds /* 1.00.00  - Initial Public Release                                         */
69*1da177e4SLinus Torvalds /*            Functionally equivalent to 0.99.05                             */
70*1da177e4SLinus Torvalds /* 3.60.00  - Bump max commands to 128 for use with firmware 3.60            */
71*1da177e4SLinus Torvalds /*          - Change version to 3.60 to coincide with release numbering.     */
72*1da177e4SLinus Torvalds /* 3.60.01  - Remove bogus error check in passthru routine                   */
73*1da177e4SLinus Torvalds /* 3.60.02  - Make DCDB direction based on lookup table                      */
74*1da177e4SLinus Torvalds /*          - Only allow one DCDB command to a SCSI ID at a time             */
75*1da177e4SLinus Torvalds /* 4.00.00  - Add support for ServeRAID 4                                    */
76*1da177e4SLinus Torvalds /* 4.00.01  - Add support for First Failure Data Capture                     */
77*1da177e4SLinus Torvalds /* 4.00.02  - Fix problem with PT DCDB with no buffer                        */
78*1da177e4SLinus Torvalds /* 4.00.03  - Add alternative passthru interface                             */
79*1da177e4SLinus Torvalds /*          - Add ability to flash BIOS                                      */
80*1da177e4SLinus Torvalds /* 4.00.04  - Rename structures/constants to be prefixed with IPS_           */
81*1da177e4SLinus Torvalds /* 4.00.05  - Remove wish_block from init routine                            */
82*1da177e4SLinus Torvalds /*          - Use linux/spinlock.h instead of asm/spinlock.h for kernels     */
83*1da177e4SLinus Torvalds /*            2.3.18 and later                                               */
84*1da177e4SLinus Torvalds /*          - Sync with other changes from the 2.3 kernels                   */
85*1da177e4SLinus Torvalds /* 4.00.06  - Fix timeout with initial FFDC command                          */
86*1da177e4SLinus Torvalds /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */
87*1da177e4SLinus Torvalds /* 4.10.00  - Add support for ServeRAID 4M/4L                                */
88*1da177e4SLinus Torvalds /* 4.10.13  - Fix for dynamic unload and proc file system                    */
89*1da177e4SLinus Torvalds /* 4.20.03  - Rename version to coincide with new release schedules          */
90*1da177e4SLinus Torvalds /*            Performance fixes                                              */
91*1da177e4SLinus Torvalds /*            Fix truncation of /proc files with cat                         */
92*1da177e4SLinus Torvalds /*            Merge in changes through kernel 2.4.0test1ac21                 */
93*1da177e4SLinus Torvalds /* 4.20.13  - Fix some failure cases / reset code                            */
94*1da177e4SLinus Torvalds /*          - Hook into the reboot_notifier to flush the controller cache    */
95*1da177e4SLinus Torvalds /* 4.50.01  - Fix problem when there is a hole in logical drive numbering    */
96*1da177e4SLinus Torvalds /* 4.70.09  - Use a Common ( Large Buffer ) for Flashing from the JCRM CD    */
97*1da177e4SLinus Torvalds /*          - Add IPSSEND Flash Support                                      */
98*1da177e4SLinus Torvalds /*          - Set Sense Data for Unknown SCSI Command                        */
99*1da177e4SLinus Torvalds /*          - Use Slot Number from NVRAM Page 5                              */
100*1da177e4SLinus Torvalds /*          - Restore caller's DCDB Structure                                */
101*1da177e4SLinus Torvalds /* 4.70.12  - Corrective actions for bad controller ( during initialization )*/
102*1da177e4SLinus Torvalds /* 4.70.13  - Don't Send CDB's if we already know the device is not present  */
103*1da177e4SLinus Torvalds /*          - Don't release HA Lock in ips_next() until SC taken off queue   */
104*1da177e4SLinus Torvalds /*          - Unregister SCSI device in ips_release()                        */
105*1da177e4SLinus Torvalds /* 4.70.15  - Fix Breakup for very large ( non-SG ) requests in ips_done()   */
106*1da177e4SLinus Torvalds /* 4.71.00  - Change all memory allocations to not use GFP_DMA flag          */
107*1da177e4SLinus Torvalds /*            Code Clean-Up for 2.4.x kernel                                 */
108*1da177e4SLinus Torvalds /* 4.72.00  - Allow for a Scatter-Gather Element to exceed MAX_XFER Size     */
109*1da177e4SLinus Torvalds /* 4.72.01  - I/O Mapped Memory release ( so "insmod ips" does not Fail )    */
110*1da177e4SLinus Torvalds /*          - Don't Issue Internal FFDC Command if there are Active Commands */
111*1da177e4SLinus Torvalds /*          - Close Window for getting too many IOCTL's active               */
112*1da177e4SLinus Torvalds /* 4.80.00  - Make ia64 Safe                                                 */
113*1da177e4SLinus Torvalds /* 4.80.04  - Eliminate calls to strtok() if 2.4.x or greater                */
114*1da177e4SLinus Torvalds /*          - Adjustments to Device Queue Depth                              */
115*1da177e4SLinus Torvalds /* 4.80.14  - Take all semaphores off stack                                  */
116*1da177e4SLinus Torvalds /*          - Clean Up New_IOCTL path                                        */
117*1da177e4SLinus Torvalds /* 4.80.20  - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel )  */
118*1da177e4SLinus Torvalds /*          - 5 second delay needed after resetting an i960 adapter          */
119*1da177e4SLinus Torvalds /* 4.80.26  - Clean up potential code problems ( Arjan's recommendations )   */
120*1da177e4SLinus Torvalds /* 4.90.01  - Version Matching for FirmWare, BIOS, and Driver                */
121*1da177e4SLinus Torvalds /* 4.90.05  - Use New PCI Architecture to facilitate Hot Plug Development    */
122*1da177e4SLinus Torvalds /* 4.90.08  - Increase Delays in Flashing ( Trombone Only - 4H )             */
123*1da177e4SLinus Torvalds /* 4.90.08  - Data Corruption if First Scatter Gather Element is > 64K       */
124*1da177e4SLinus Torvalds /* 4.90.11  - Don't actually RESET unless it's physically required           */
125*1da177e4SLinus Torvalds /*          - Remove unused compile options                                  */
126*1da177e4SLinus Torvalds /* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */
127*1da177e4SLinus Torvalds /*          - Get rid on IOCTL_NEW_COMMAND code                              */
128*1da177e4SLinus Torvalds /*          - Add Extended DCDB Commands for Tape Support in 5I              */
129*1da177e4SLinus Torvalds /* 5.10.12  - use pci_dma interfaces, update for 2.5 kernel changes          */
130*1da177e4SLinus Torvalds /* 5.10.15  - remove unused code (sem, macros, etc.)                         */
131*1da177e4SLinus Torvalds /* 5.30.00  - use __devexit_p()                                              */
132*1da177e4SLinus Torvalds /* 6.00.00  - Add 6x Adapters and Battery Flash                              */
133*1da177e4SLinus Torvalds /* 6.10.00  - Remove 1G Addressing Limitations                               */
134*1da177e4SLinus Torvalds /* 6.11.xx  - Get VersionInfo buffer off the stack !              DDTS 60401 */
135*1da177e4SLinus Torvalds /* 6.11.xx  - Make Logical Drive Info structure safe for DMA      DDTS 60639 */
136*1da177e4SLinus Torvalds /* 7.10.xx  - Add highmem_io flag in SCSI Templete for 2.4 kernels           */
137*1da177e4SLinus Torvalds /*          - Fix path/name for scsi_hosts.h include for 2.6 kernels         */
138*1da177e4SLinus Torvalds /*          - Fix sort order of 7k                                           */
139*1da177e4SLinus Torvalds /*          - Remove 3 unused "inline" functions                             */
140*1da177e4SLinus Torvalds /*****************************************************************************/
141*1da177e4SLinus Torvalds 
142*1da177e4SLinus Torvalds /*
143*1da177e4SLinus Torvalds  * Conditional Compilation directives for this driver:
144*1da177e4SLinus Torvalds  *
145*1da177e4SLinus Torvalds  * IPS_DEBUG            - Turn on debugging info
146*1da177e4SLinus Torvalds  *
147*1da177e4SLinus Torvalds  * Parameters:
148*1da177e4SLinus Torvalds  *
149*1da177e4SLinus Torvalds  * debug:<number>       - Set debug level to <number>
150*1da177e4SLinus Torvalds  *                        NOTE: only works when IPS_DEBUG compile directive is used.
151*1da177e4SLinus Torvalds  *       1              - Normal debug messages
152*1da177e4SLinus Torvalds  *       2              - Verbose debug messages
153*1da177e4SLinus Torvalds  *       11             - Method trace (non interrupt)
154*1da177e4SLinus Torvalds  *       12             - Method trace (includes interrupt)
155*1da177e4SLinus Torvalds  *
156*1da177e4SLinus Torvalds  * noi2o                - Don't use I2O Queues (ServeRAID 4 only)
157*1da177e4SLinus Torvalds  * nommap               - Don't use memory mapped I/O
158*1da177e4SLinus Torvalds  * ioctlsize            - Initial size of the IOCTL buffer
159*1da177e4SLinus Torvalds  */
160*1da177e4SLinus Torvalds 
161*1da177e4SLinus Torvalds #include <asm/io.h>
162*1da177e4SLinus Torvalds #include <asm/byteorder.h>
163*1da177e4SLinus Torvalds #include <asm/page.h>
164*1da177e4SLinus Torvalds #include <linux/stddef.h>
165*1da177e4SLinus Torvalds #include <linux/version.h>
166*1da177e4SLinus Torvalds #include <linux/string.h>
167*1da177e4SLinus Torvalds #include <linux/errno.h>
168*1da177e4SLinus Torvalds #include <linux/kernel.h>
169*1da177e4SLinus Torvalds #include <linux/ioport.h>
170*1da177e4SLinus Torvalds #include <linux/slab.h>
171*1da177e4SLinus Torvalds #include <linux/delay.h>
172*1da177e4SLinus Torvalds #include <linux/pci.h>
173*1da177e4SLinus Torvalds #include <linux/proc_fs.h>
174*1da177e4SLinus Torvalds #include <linux/reboot.h>
175*1da177e4SLinus Torvalds #include <linux/interrupt.h>
176*1da177e4SLinus Torvalds 
177*1da177e4SLinus Torvalds #include <linux/blkdev.h>
178*1da177e4SLinus Torvalds #include <linux/types.h>
179*1da177e4SLinus Torvalds 
180*1da177e4SLinus Torvalds #include <scsi/sg.h>
181*1da177e4SLinus Torvalds 
182*1da177e4SLinus Torvalds #include "scsi.h"
183*1da177e4SLinus Torvalds 
184*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
185*1da177e4SLinus Torvalds #include "hosts.h"
186*1da177e4SLinus Torvalds #else
187*1da177e4SLinus Torvalds #include <scsi/scsi_host.h>
188*1da177e4SLinus Torvalds #endif
189*1da177e4SLinus Torvalds 
190*1da177e4SLinus Torvalds #include "ips.h"
191*1da177e4SLinus Torvalds 
192*1da177e4SLinus Torvalds #include <linux/module.h>
193*1da177e4SLinus Torvalds 
194*1da177e4SLinus Torvalds #include <linux/stat.h>
195*1da177e4SLinus Torvalds #include <linux/config.h>
196*1da177e4SLinus Torvalds 
197*1da177e4SLinus Torvalds #include <linux/spinlock.h>
198*1da177e4SLinus Torvalds #include <linux/init.h>
199*1da177e4SLinus Torvalds 
200*1da177e4SLinus Torvalds #include <linux/smp.h>
201*1da177e4SLinus Torvalds 
202*1da177e4SLinus Torvalds #ifdef MODULE
203*1da177e4SLinus Torvalds static char *ips = NULL;
204*1da177e4SLinus Torvalds module_param(ips, charp, 0);
205*1da177e4SLinus Torvalds #endif
206*1da177e4SLinus Torvalds 
207*1da177e4SLinus Torvalds /*
208*1da177e4SLinus Torvalds  * DRIVER_VER
209*1da177e4SLinus Torvalds  */
210*1da177e4SLinus Torvalds #define IPS_VERSION_HIGH        "7.10"
211*1da177e4SLinus Torvalds #define IPS_VERSION_LOW         ".18 "
212*1da177e4SLinus Torvalds 
213*1da177e4SLinus Torvalds #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
214*1da177e4SLinus Torvalds #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
215*1da177e4SLinus Torvalds #endif
216*1da177e4SLinus Torvalds 
217*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
218*1da177e4SLinus Torvalds #include <linux/blk.h>
219*1da177e4SLinus Torvalds #include "sd.h"
220*1da177e4SLinus Torvalds #define IPS_SG_ADDRESS(sg)       ((sg)->address)
221*1da177e4SLinus Torvalds #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
222*1da177e4SLinus Torvalds #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
223*1da177e4SLinus Torvalds #ifndef __devexit_p
224*1da177e4SLinus Torvalds #define __devexit_p(x) x
225*1da177e4SLinus Torvalds #endif
226*1da177e4SLinus Torvalds #else
227*1da177e4SLinus Torvalds #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
228*1da177e4SLinus Torvalds                                    page_address((sg)->page)+(sg)->offset : NULL)
229*1da177e4SLinus Torvalds #define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
230*1da177e4SLinus Torvalds #define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
231*1da177e4SLinus Torvalds #endif
232*1da177e4SLinus Torvalds 
233*1da177e4SLinus Torvalds #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
234*1da177e4SLinus Torvalds                          SCSI_DATA_NONE == scb->scsi_cmd->sc_data_direction) ? \
235*1da177e4SLinus Torvalds                          PCI_DMA_BIDIRECTIONAL : \
236*1da177e4SLinus Torvalds                          scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction))
237*1da177e4SLinus Torvalds 
238*1da177e4SLinus Torvalds #ifdef IPS_DEBUG
239*1da177e4SLinus Torvalds #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
240*1da177e4SLinus Torvalds #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
241*1da177e4SLinus Torvalds #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
242*1da177e4SLinus Torvalds #else
243*1da177e4SLinus Torvalds #define METHOD_TRACE(s, i)
244*1da177e4SLinus Torvalds #define DEBUG(i, s)
245*1da177e4SLinus Torvalds #define DEBUG_VAR(i, s, v...)
246*1da177e4SLinus Torvalds #endif
247*1da177e4SLinus Torvalds 
248*1da177e4SLinus Torvalds /*
249*1da177e4SLinus Torvalds  * Function prototypes
250*1da177e4SLinus Torvalds  */
251*1da177e4SLinus Torvalds static int ips_detect(Scsi_Host_Template *);
252*1da177e4SLinus Torvalds static int ips_release(struct Scsi_Host *);
253*1da177e4SLinus Torvalds static int ips_eh_abort(Scsi_Cmnd *);
254*1da177e4SLinus Torvalds static int ips_eh_reset(Scsi_Cmnd *);
255*1da177e4SLinus Torvalds static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
256*1da177e4SLinus Torvalds static const char *ips_info(struct Scsi_Host *);
257*1da177e4SLinus Torvalds static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
258*1da177e4SLinus Torvalds static int ips_hainit(ips_ha_t *);
259*1da177e4SLinus Torvalds static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
260*1da177e4SLinus Torvalds static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
261*1da177e4SLinus Torvalds static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
262*1da177e4SLinus Torvalds static int ips_online(ips_ha_t *, ips_scb_t *);
263*1da177e4SLinus Torvalds static int ips_inquiry(ips_ha_t *, ips_scb_t *);
264*1da177e4SLinus Torvalds static int ips_rdcap(ips_ha_t *, ips_scb_t *);
265*1da177e4SLinus Torvalds static int ips_msense(ips_ha_t *, ips_scb_t *);
266*1da177e4SLinus Torvalds static int ips_reqsen(ips_ha_t *, ips_scb_t *);
267*1da177e4SLinus Torvalds static int ips_deallocatescbs(ips_ha_t *, int);
268*1da177e4SLinus Torvalds static int ips_allocatescbs(ips_ha_t *);
269*1da177e4SLinus Torvalds static int ips_reset_copperhead(ips_ha_t *);
270*1da177e4SLinus Torvalds static int ips_reset_copperhead_memio(ips_ha_t *);
271*1da177e4SLinus Torvalds static int ips_reset_morpheus(ips_ha_t *);
272*1da177e4SLinus Torvalds static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
273*1da177e4SLinus Torvalds static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
274*1da177e4SLinus Torvalds static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
275*1da177e4SLinus Torvalds static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
276*1da177e4SLinus Torvalds static int ips_isintr_copperhead(ips_ha_t *);
277*1da177e4SLinus Torvalds static int ips_isintr_copperhead_memio(ips_ha_t *);
278*1da177e4SLinus Torvalds static int ips_isintr_morpheus(ips_ha_t *);
279*1da177e4SLinus Torvalds static int ips_wait(ips_ha_t *, int, int);
280*1da177e4SLinus Torvalds static int ips_write_driver_status(ips_ha_t *, int);
281*1da177e4SLinus Torvalds static int ips_read_adapter_status(ips_ha_t *, int);
282*1da177e4SLinus Torvalds static int ips_read_subsystem_parameters(ips_ha_t *, int);
283*1da177e4SLinus Torvalds static int ips_read_config(ips_ha_t *, int);
284*1da177e4SLinus Torvalds static int ips_clear_adapter(ips_ha_t *, int);
285*1da177e4SLinus Torvalds static int ips_readwrite_page5(ips_ha_t *, int, int);
286*1da177e4SLinus Torvalds static int ips_init_copperhead(ips_ha_t *);
287*1da177e4SLinus Torvalds static int ips_init_copperhead_memio(ips_ha_t *);
288*1da177e4SLinus Torvalds static int ips_init_morpheus(ips_ha_t *);
289*1da177e4SLinus Torvalds static int ips_isinit_copperhead(ips_ha_t *);
290*1da177e4SLinus Torvalds static int ips_isinit_copperhead_memio(ips_ha_t *);
291*1da177e4SLinus Torvalds static int ips_isinit_morpheus(ips_ha_t *);
292*1da177e4SLinus Torvalds static int ips_erase_bios(ips_ha_t *);
293*1da177e4SLinus Torvalds static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
294*1da177e4SLinus Torvalds static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
295*1da177e4SLinus Torvalds static int ips_erase_bios_memio(ips_ha_t *);
296*1da177e4SLinus Torvalds static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
297*1da177e4SLinus Torvalds static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
298*1da177e4SLinus Torvalds static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
299*1da177e4SLinus Torvalds static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
300*1da177e4SLinus Torvalds static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
301*1da177e4SLinus Torvalds static void ips_free_flash_copperhead(ips_ha_t * ha);
302*1da177e4SLinus Torvalds static void ips_get_bios_version(ips_ha_t *, int);
303*1da177e4SLinus Torvalds static void ips_identify_controller(ips_ha_t *);
304*1da177e4SLinus Torvalds static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
305*1da177e4SLinus Torvalds static void ips_enable_int_copperhead(ips_ha_t *);
306*1da177e4SLinus Torvalds static void ips_enable_int_copperhead_memio(ips_ha_t *);
307*1da177e4SLinus Torvalds static void ips_enable_int_morpheus(ips_ha_t *);
308*1da177e4SLinus Torvalds static int ips_intr_copperhead(ips_ha_t *);
309*1da177e4SLinus Torvalds static int ips_intr_morpheus(ips_ha_t *);
310*1da177e4SLinus Torvalds static void ips_next(ips_ha_t *, int);
311*1da177e4SLinus Torvalds static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
312*1da177e4SLinus Torvalds static void ipsintr_done(ips_ha_t *, struct ips_scb *);
313*1da177e4SLinus Torvalds static void ips_done(ips_ha_t *, ips_scb_t *);
314*1da177e4SLinus Torvalds static void ips_free(ips_ha_t *);
315*1da177e4SLinus Torvalds static void ips_init_scb(ips_ha_t *, ips_scb_t *);
316*1da177e4SLinus Torvalds static void ips_freescb(ips_ha_t *, ips_scb_t *);
317*1da177e4SLinus Torvalds static void ips_setup_funclist(ips_ha_t *);
318*1da177e4SLinus Torvalds static void ips_statinit(ips_ha_t *);
319*1da177e4SLinus Torvalds static void ips_statinit_memio(ips_ha_t *);
320*1da177e4SLinus Torvalds static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
321*1da177e4SLinus Torvalds static void ips_ffdc_reset(ips_ha_t *, int);
322*1da177e4SLinus Torvalds static void ips_ffdc_time(ips_ha_t *);
323*1da177e4SLinus Torvalds static uint32_t ips_statupd_copperhead(ips_ha_t *);
324*1da177e4SLinus Torvalds static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
325*1da177e4SLinus Torvalds static uint32_t ips_statupd_morpheus(ips_ha_t *);
326*1da177e4SLinus Torvalds static ips_scb_t *ips_getscb(ips_ha_t *);
327*1da177e4SLinus Torvalds static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
328*1da177e4SLinus Torvalds static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
329*1da177e4SLinus Torvalds static void ips_putq_copp_tail(ips_copp_queue_t *,
330*1da177e4SLinus Torvalds 				      ips_copp_wait_item_t *);
331*1da177e4SLinus Torvalds static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
332*1da177e4SLinus Torvalds static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
333*1da177e4SLinus Torvalds static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
334*1da177e4SLinus Torvalds static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
335*1da177e4SLinus Torvalds static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
336*1da177e4SLinus Torvalds 						     ips_copp_wait_item_t *);
337*1da177e4SLinus Torvalds static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
338*1da177e4SLinus Torvalds 
339*1da177e4SLinus Torvalds static int ips_is_passthru(Scsi_Cmnd *);
340*1da177e4SLinus Torvalds static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
341*1da177e4SLinus Torvalds static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
342*1da177e4SLinus Torvalds static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
343*1da177e4SLinus Torvalds static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
344*1da177e4SLinus Torvalds 			       unsigned int count);
345*1da177e4SLinus Torvalds static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
346*1da177e4SLinus Torvalds 
347*1da177e4SLinus Torvalds static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
348*1da177e4SLinus Torvalds static int ips_host_info(ips_ha_t *, char *, off_t, int);
349*1da177e4SLinus Torvalds static void copy_mem_info(IPS_INFOSTR *, char *, int);
350*1da177e4SLinus Torvalds static int copy_info(IPS_INFOSTR *, char *, ...);
351*1da177e4SLinus Torvalds static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
352*1da177e4SLinus Torvalds static void ips_version_check(ips_ha_t * ha, int intr);
353*1da177e4SLinus Torvalds static int ips_abort_init(ips_ha_t * ha, int index);
354*1da177e4SLinus Torvalds static int ips_init_phase2(int index);
355*1da177e4SLinus Torvalds 
356*1da177e4SLinus Torvalds static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
357*1da177e4SLinus Torvalds static int ips_register_scsi(int index);
358*1da177e4SLinus Torvalds 
359*1da177e4SLinus Torvalds /*
360*1da177e4SLinus Torvalds  * global variables
361*1da177e4SLinus Torvalds  */
362*1da177e4SLinus Torvalds static const char ips_name[] = "ips";
363*1da177e4SLinus Torvalds static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];	/* Array of host controller structures */
364*1da177e4SLinus Torvalds static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS];	/* Array of HA structures */
365*1da177e4SLinus Torvalds static unsigned int ips_next_controller;
366*1da177e4SLinus Torvalds static unsigned int ips_num_controllers;
367*1da177e4SLinus Torvalds static unsigned int ips_released_controllers;
368*1da177e4SLinus Torvalds static int ips_hotplug;
369*1da177e4SLinus Torvalds static int ips_cmd_timeout = 60;
370*1da177e4SLinus Torvalds static int ips_reset_timeout = 60 * 5;
371*1da177e4SLinus Torvalds static int ips_force_memio = 1;		/* Always use Memory Mapped I/O    */
372*1da177e4SLinus Torvalds static int ips_force_i2o = 1;	/* Always use I2O command delivery */
373*1da177e4SLinus Torvalds static int ips_ioctlsize = IPS_IOCTL_SIZE;	/* Size of the ioctl buffer        */
374*1da177e4SLinus Torvalds static int ips_cd_boot;			/* Booting from Manager CD         */
375*1da177e4SLinus Torvalds static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */
376*1da177e4SLinus Torvalds static dma_addr_t ips_flashbusaddr;
377*1da177e4SLinus Torvalds static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */
378*1da177e4SLinus Torvalds static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
379*1da177e4SLinus Torvalds static Scsi_Host_Template ips_driver_template = {
380*1da177e4SLinus Torvalds 	.detect			= ips_detect,
381*1da177e4SLinus Torvalds 	.release		= ips_release,
382*1da177e4SLinus Torvalds 	.info			= ips_info,
383*1da177e4SLinus Torvalds 	.queuecommand		= ips_queue,
384*1da177e4SLinus Torvalds 	.eh_abort_handler	= ips_eh_abort,
385*1da177e4SLinus Torvalds 	.eh_host_reset_handler	= ips_eh_reset,
386*1da177e4SLinus Torvalds 	.proc_name		= "ips",
387*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
388*1da177e4SLinus Torvalds 	.proc_info		= ips_proc_info,
389*1da177e4SLinus Torvalds 	.slave_configure	= ips_slave_configure,
390*1da177e4SLinus Torvalds #else
391*1da177e4SLinus Torvalds 	.proc_info		= ips_proc24_info,
392*1da177e4SLinus Torvalds 	.select_queue_depths	= ips_select_queue_depth,
393*1da177e4SLinus Torvalds #endif
394*1da177e4SLinus Torvalds 	.bios_param		= ips_biosparam,
395*1da177e4SLinus Torvalds 	.this_id		= -1,
396*1da177e4SLinus Torvalds 	.sg_tablesize		= IPS_MAX_SG,
397*1da177e4SLinus Torvalds 	.cmd_per_lun		= 3,
398*1da177e4SLinus Torvalds 	.use_clustering		= ENABLE_CLUSTERING,
399*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
400*1da177e4SLinus Torvalds 	.use_new_eh_code	= 1,
401*1da177e4SLinus Torvalds #endif
402*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)  &&  LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
403*1da177e4SLinus Torvalds     .highmem_io          = 1,
404*1da177e4SLinus Torvalds #endif
405*1da177e4SLinus Torvalds };
406*1da177e4SLinus Torvalds 
407*1da177e4SLinus Torvalds static IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
408*1da177e4SLinus Torvalds 
409*1da177e4SLinus Torvalds 
410*1da177e4SLinus Torvalds /* This table describes all ServeRAID Adapters */
411*1da177e4SLinus Torvalds static struct  pci_device_id  ips_pci_table[] = {
412*1da177e4SLinus Torvalds 	{ 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
413*1da177e4SLinus Torvalds 	{ 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
414*1da177e4SLinus Torvalds 	{ 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
415*1da177e4SLinus Torvalds 	{ 0, }
416*1da177e4SLinus Torvalds };
417*1da177e4SLinus Torvalds 
418*1da177e4SLinus Torvalds MODULE_DEVICE_TABLE( pci, ips_pci_table );
419*1da177e4SLinus Torvalds 
420*1da177e4SLinus Torvalds static char ips_hot_plug_name[] = "ips";
421*1da177e4SLinus Torvalds 
422*1da177e4SLinus Torvalds static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
423*1da177e4SLinus Torvalds static void __devexit ips_remove_device(struct pci_dev *pci_dev);
424*1da177e4SLinus Torvalds 
425*1da177e4SLinus Torvalds static struct pci_driver ips_pci_driver = {
426*1da177e4SLinus Torvalds 	.name		= ips_hot_plug_name,
427*1da177e4SLinus Torvalds 	.id_table	= ips_pci_table,
428*1da177e4SLinus Torvalds 	.probe		= ips_insert_device,
429*1da177e4SLinus Torvalds 	.remove		= __devexit_p(ips_remove_device),
430*1da177e4SLinus Torvalds };
431*1da177e4SLinus Torvalds 
432*1da177e4SLinus Torvalds 
433*1da177e4SLinus Torvalds /*
434*1da177e4SLinus Torvalds  * Necessary forward function protoypes
435*1da177e4SLinus Torvalds  */
436*1da177e4SLinus Torvalds static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
437*1da177e4SLinus Torvalds 
438*1da177e4SLinus Torvalds #define MAX_ADAPTER_NAME 15
439*1da177e4SLinus Torvalds 
440*1da177e4SLinus Torvalds static char ips_adapter_name[][30] = {
441*1da177e4SLinus Torvalds 	"ServeRAID",
442*1da177e4SLinus Torvalds 	"ServeRAID II",
443*1da177e4SLinus Torvalds 	"ServeRAID on motherboard",
444*1da177e4SLinus Torvalds 	"ServeRAID on motherboard",
445*1da177e4SLinus Torvalds 	"ServeRAID 3H",
446*1da177e4SLinus Torvalds 	"ServeRAID 3L",
447*1da177e4SLinus Torvalds 	"ServeRAID 4H",
448*1da177e4SLinus Torvalds 	"ServeRAID 4M",
449*1da177e4SLinus Torvalds 	"ServeRAID 4L",
450*1da177e4SLinus Torvalds 	"ServeRAID 4Mx",
451*1da177e4SLinus Torvalds 	"ServeRAID 4Lx",
452*1da177e4SLinus Torvalds 	"ServeRAID 5i",
453*1da177e4SLinus Torvalds 	"ServeRAID 5i",
454*1da177e4SLinus Torvalds 	"ServeRAID 6M",
455*1da177e4SLinus Torvalds 	"ServeRAID 6i",
456*1da177e4SLinus Torvalds 	"ServeRAID 7t",
457*1da177e4SLinus Torvalds 	"ServeRAID 7k",
458*1da177e4SLinus Torvalds 	"ServeRAID 7M"
459*1da177e4SLinus Torvalds };
460*1da177e4SLinus Torvalds 
461*1da177e4SLinus Torvalds static struct notifier_block ips_notifier = {
462*1da177e4SLinus Torvalds 	ips_halt, NULL, 0
463*1da177e4SLinus Torvalds };
464*1da177e4SLinus Torvalds 
465*1da177e4SLinus Torvalds /*
466*1da177e4SLinus Torvalds  * Direction table
467*1da177e4SLinus Torvalds  */
468*1da177e4SLinus Torvalds static char ips_command_direction[] = {
469*1da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
470*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,
471*1da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
472*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
473*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
474*1da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
475*1da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,
476*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
477*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,
478*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
479*1da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,
480*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
481*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,
482*1da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,
483*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
484*1da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
485*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
486*1da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
487*1da177e4SLinus Torvalds 	IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
488*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
489*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
490*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
491*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
492*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
493*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
494*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
495*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
496*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
497*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
498*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
499*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
500*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
501*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
502*1da177e4SLinus Torvalds 	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,
503*1da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,
504*1da177e4SLinus Torvalds 	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,
505*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,
506*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
507*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
508*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
509*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
510*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
511*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
512*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
513*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
514*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
515*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,
516*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
517*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
518*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
519*1da177e4SLinus Torvalds 	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
520*1da177e4SLinus Torvalds };
521*1da177e4SLinus Torvalds 
522*1da177e4SLinus Torvalds 
523*1da177e4SLinus Torvalds /****************************************************************************/
524*1da177e4SLinus Torvalds /*                                                                          */
525*1da177e4SLinus Torvalds /* Routine Name: ips_setup                                                  */
526*1da177e4SLinus Torvalds /*                                                                          */
527*1da177e4SLinus Torvalds /* Routine Description:                                                     */
528*1da177e4SLinus Torvalds /*                                                                          */
529*1da177e4SLinus Torvalds /*   setup parameters to the driver                                         */
530*1da177e4SLinus Torvalds /*                                                                          */
531*1da177e4SLinus Torvalds /****************************************************************************/
532*1da177e4SLinus Torvalds static int
533*1da177e4SLinus Torvalds ips_setup(char *ips_str)
534*1da177e4SLinus Torvalds {
535*1da177e4SLinus Torvalds 
536*1da177e4SLinus Torvalds 	int i;
537*1da177e4SLinus Torvalds 	char *key;
538*1da177e4SLinus Torvalds 	char *value;
539*1da177e4SLinus Torvalds 	IPS_OPTION options[] = {
540*1da177e4SLinus Torvalds 		{"noi2o", &ips_force_i2o, 0},
541*1da177e4SLinus Torvalds 		{"nommap", &ips_force_memio, 0},
542*1da177e4SLinus Torvalds 		{"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
543*1da177e4SLinus Torvalds 		{"cdboot", &ips_cd_boot, 0},
544*1da177e4SLinus Torvalds 		{"maxcmds", &MaxLiteCmds, 32},
545*1da177e4SLinus Torvalds 	};
546*1da177e4SLinus Torvalds 
547*1da177e4SLinus Torvalds 	/* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
548*1da177e4SLinus Torvalds 	/* Search for value */
549*1da177e4SLinus Torvalds 	while ((key = strsep(&ips_str, ",."))) {
550*1da177e4SLinus Torvalds 		if (!*key)
551*1da177e4SLinus Torvalds 			continue;
552*1da177e4SLinus Torvalds 		value = strchr(key, ':');
553*1da177e4SLinus Torvalds 		if (value)
554*1da177e4SLinus Torvalds 			*value++ = '\0';
555*1da177e4SLinus Torvalds 		/*
556*1da177e4SLinus Torvalds 		 * We now have key/value pairs.
557*1da177e4SLinus Torvalds 		 * Update the variables
558*1da177e4SLinus Torvalds 		 */
559*1da177e4SLinus Torvalds 		for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) {
560*1da177e4SLinus Torvalds 			if (strnicmp
561*1da177e4SLinus Torvalds 			    (key, options[i].option_name,
562*1da177e4SLinus Torvalds 			     strlen(options[i].option_name)) == 0) {
563*1da177e4SLinus Torvalds 				if (value)
564*1da177e4SLinus Torvalds 					*options[i].option_flag =
565*1da177e4SLinus Torvalds 					    simple_strtoul(value, NULL, 0);
566*1da177e4SLinus Torvalds 				else
567*1da177e4SLinus Torvalds 					*options[i].option_flag =
568*1da177e4SLinus Torvalds 					    options[i].option_value;
569*1da177e4SLinus Torvalds 				break;
570*1da177e4SLinus Torvalds 			}
571*1da177e4SLinus Torvalds 		}
572*1da177e4SLinus Torvalds 	}
573*1da177e4SLinus Torvalds 
574*1da177e4SLinus Torvalds 	return (1);
575*1da177e4SLinus Torvalds }
576*1da177e4SLinus Torvalds 
577*1da177e4SLinus Torvalds __setup("ips=", ips_setup);
578*1da177e4SLinus Torvalds 
579*1da177e4SLinus Torvalds /****************************************************************************/
580*1da177e4SLinus Torvalds /*                                                                          */
581*1da177e4SLinus Torvalds /* Routine Name: ips_detect                                                 */
582*1da177e4SLinus Torvalds /*                                                                          */
583*1da177e4SLinus Torvalds /* Routine Description:                                                     */
584*1da177e4SLinus Torvalds /*                                                                          */
585*1da177e4SLinus Torvalds /*   Detect and initialize the driver                                       */
586*1da177e4SLinus Torvalds /*                                                                          */
587*1da177e4SLinus Torvalds /* NOTE: this routine is called under the io_request_lock spinlock          */
588*1da177e4SLinus Torvalds /*                                                                          */
589*1da177e4SLinus Torvalds /****************************************************************************/
590*1da177e4SLinus Torvalds static int
591*1da177e4SLinus Torvalds ips_detect(Scsi_Host_Template * SHT)
592*1da177e4SLinus Torvalds {
593*1da177e4SLinus Torvalds 	int i;
594*1da177e4SLinus Torvalds 
595*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_detect", 1);
596*1da177e4SLinus Torvalds 
597*1da177e4SLinus Torvalds #ifdef MODULE
598*1da177e4SLinus Torvalds 	if (ips)
599*1da177e4SLinus Torvalds 		ips_setup(ips);
600*1da177e4SLinus Torvalds #endif
601*1da177e4SLinus Torvalds 
602*1da177e4SLinus Torvalds 	for (i = 0; i < ips_num_controllers; i++) {
603*1da177e4SLinus Torvalds 		if (ips_register_scsi(i))
604*1da177e4SLinus Torvalds 			ips_free(ips_ha[i]);
605*1da177e4SLinus Torvalds 		ips_released_controllers++;
606*1da177e4SLinus Torvalds 	}
607*1da177e4SLinus Torvalds 	ips_hotplug = 1;
608*1da177e4SLinus Torvalds 	return (ips_num_controllers);
609*1da177e4SLinus Torvalds }
610*1da177e4SLinus Torvalds 
611*1da177e4SLinus Torvalds /****************************************************************************/
612*1da177e4SLinus Torvalds /*   configure the function pointers to use the functions that will work    */
613*1da177e4SLinus Torvalds /*   with the found version of the adapter                                  */
614*1da177e4SLinus Torvalds /****************************************************************************/
615*1da177e4SLinus Torvalds static void
616*1da177e4SLinus Torvalds ips_setup_funclist(ips_ha_t * ha)
617*1da177e4SLinus Torvalds {
618*1da177e4SLinus Torvalds 
619*1da177e4SLinus Torvalds 	/*
620*1da177e4SLinus Torvalds 	 * Setup Functions
621*1da177e4SLinus Torvalds 	 */
622*1da177e4SLinus Torvalds 	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
623*1da177e4SLinus Torvalds 		/* morpheus / marco / sebring */
624*1da177e4SLinus Torvalds 		ha->func.isintr = ips_isintr_morpheus;
625*1da177e4SLinus Torvalds 		ha->func.isinit = ips_isinit_morpheus;
626*1da177e4SLinus Torvalds 		ha->func.issue = ips_issue_i2o_memio;
627*1da177e4SLinus Torvalds 		ha->func.init = ips_init_morpheus;
628*1da177e4SLinus Torvalds 		ha->func.statupd = ips_statupd_morpheus;
629*1da177e4SLinus Torvalds 		ha->func.reset = ips_reset_morpheus;
630*1da177e4SLinus Torvalds 		ha->func.intr = ips_intr_morpheus;
631*1da177e4SLinus Torvalds 		ha->func.enableint = ips_enable_int_morpheus;
632*1da177e4SLinus Torvalds 	} else if (IPS_USE_MEMIO(ha)) {
633*1da177e4SLinus Torvalds 		/* copperhead w/MEMIO */
634*1da177e4SLinus Torvalds 		ha->func.isintr = ips_isintr_copperhead_memio;
635*1da177e4SLinus Torvalds 		ha->func.isinit = ips_isinit_copperhead_memio;
636*1da177e4SLinus Torvalds 		ha->func.init = ips_init_copperhead_memio;
637*1da177e4SLinus Torvalds 		ha->func.statupd = ips_statupd_copperhead_memio;
638*1da177e4SLinus Torvalds 		ha->func.statinit = ips_statinit_memio;
639*1da177e4SLinus Torvalds 		ha->func.reset = ips_reset_copperhead_memio;
640*1da177e4SLinus Torvalds 		ha->func.intr = ips_intr_copperhead;
641*1da177e4SLinus Torvalds 		ha->func.erasebios = ips_erase_bios_memio;
642*1da177e4SLinus Torvalds 		ha->func.programbios = ips_program_bios_memio;
643*1da177e4SLinus Torvalds 		ha->func.verifybios = ips_verify_bios_memio;
644*1da177e4SLinus Torvalds 		ha->func.enableint = ips_enable_int_copperhead_memio;
645*1da177e4SLinus Torvalds 		if (IPS_USE_I2O_DELIVER(ha))
646*1da177e4SLinus Torvalds 			ha->func.issue = ips_issue_i2o_memio;
647*1da177e4SLinus Torvalds 		else
648*1da177e4SLinus Torvalds 			ha->func.issue = ips_issue_copperhead_memio;
649*1da177e4SLinus Torvalds 	} else {
650*1da177e4SLinus Torvalds 		/* copperhead */
651*1da177e4SLinus Torvalds 		ha->func.isintr = ips_isintr_copperhead;
652*1da177e4SLinus Torvalds 		ha->func.isinit = ips_isinit_copperhead;
653*1da177e4SLinus Torvalds 		ha->func.init = ips_init_copperhead;
654*1da177e4SLinus Torvalds 		ha->func.statupd = ips_statupd_copperhead;
655*1da177e4SLinus Torvalds 		ha->func.statinit = ips_statinit;
656*1da177e4SLinus Torvalds 		ha->func.reset = ips_reset_copperhead;
657*1da177e4SLinus Torvalds 		ha->func.intr = ips_intr_copperhead;
658*1da177e4SLinus Torvalds 		ha->func.erasebios = ips_erase_bios;
659*1da177e4SLinus Torvalds 		ha->func.programbios = ips_program_bios;
660*1da177e4SLinus Torvalds 		ha->func.verifybios = ips_verify_bios;
661*1da177e4SLinus Torvalds 		ha->func.enableint = ips_enable_int_copperhead;
662*1da177e4SLinus Torvalds 
663*1da177e4SLinus Torvalds 		if (IPS_USE_I2O_DELIVER(ha))
664*1da177e4SLinus Torvalds 			ha->func.issue = ips_issue_i2o;
665*1da177e4SLinus Torvalds 		else
666*1da177e4SLinus Torvalds 			ha->func.issue = ips_issue_copperhead;
667*1da177e4SLinus Torvalds 	}
668*1da177e4SLinus Torvalds }
669*1da177e4SLinus Torvalds 
670*1da177e4SLinus Torvalds /****************************************************************************/
671*1da177e4SLinus Torvalds /*                                                                          */
672*1da177e4SLinus Torvalds /* Routine Name: ips_release                                                */
673*1da177e4SLinus Torvalds /*                                                                          */
674*1da177e4SLinus Torvalds /* Routine Description:                                                     */
675*1da177e4SLinus Torvalds /*                                                                          */
676*1da177e4SLinus Torvalds /*   Remove a driver                                                        */
677*1da177e4SLinus Torvalds /*                                                                          */
678*1da177e4SLinus Torvalds /****************************************************************************/
679*1da177e4SLinus Torvalds static int
680*1da177e4SLinus Torvalds ips_release(struct Scsi_Host *sh)
681*1da177e4SLinus Torvalds {
682*1da177e4SLinus Torvalds 	ips_scb_t *scb;
683*1da177e4SLinus Torvalds 	ips_ha_t *ha;
684*1da177e4SLinus Torvalds 	int i;
685*1da177e4SLinus Torvalds 
686*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_release", 1);
687*1da177e4SLinus Torvalds 
688*1da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
689*1da177e4SLinus Torvalds 
690*1da177e4SLinus Torvalds 	if (i == IPS_MAX_ADAPTERS) {
691*1da177e4SLinus Torvalds 		printk(KERN_WARNING
692*1da177e4SLinus Torvalds 		       "(%s) release, invalid Scsi_Host pointer.\n", ips_name);
693*1da177e4SLinus Torvalds 		BUG();
694*1da177e4SLinus Torvalds 		return (FALSE);
695*1da177e4SLinus Torvalds 	}
696*1da177e4SLinus Torvalds 
697*1da177e4SLinus Torvalds 	ha = IPS_HA(sh);
698*1da177e4SLinus Torvalds 
699*1da177e4SLinus Torvalds 	if (!ha)
700*1da177e4SLinus Torvalds 		return (FALSE);
701*1da177e4SLinus Torvalds 
702*1da177e4SLinus Torvalds 	/* flush the cache on the controller */
703*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
704*1da177e4SLinus Torvalds 
705*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
706*1da177e4SLinus Torvalds 
707*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
708*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_FLUSH;
709*1da177e4SLinus Torvalds 
710*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
711*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
712*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.state = IPS_NORM_STATE;
713*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved = 0;
714*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved2 = 0;
715*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved3 = 0;
716*1da177e4SLinus Torvalds 	scb->cmd.flush_cache.reserved4 = 0;
717*1da177e4SLinus Torvalds 
718*1da177e4SLinus Torvalds 	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
719*1da177e4SLinus Torvalds 
720*1da177e4SLinus Torvalds 	/* send command */
721*1da177e4SLinus Torvalds 	if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
722*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
723*1da177e4SLinus Torvalds 
724*1da177e4SLinus Torvalds 	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
725*1da177e4SLinus Torvalds 
726*1da177e4SLinus Torvalds 	ips_sh[i] = NULL;
727*1da177e4SLinus Torvalds 	ips_ha[i] = NULL;
728*1da177e4SLinus Torvalds 
729*1da177e4SLinus Torvalds 	/* free extra memory */
730*1da177e4SLinus Torvalds 	ips_free(ha);
731*1da177e4SLinus Torvalds 
732*1da177e4SLinus Torvalds 	/* Free I/O Region */
733*1da177e4SLinus Torvalds 	if (ha->io_addr)
734*1da177e4SLinus Torvalds 		release_region(ha->io_addr, ha->io_len);
735*1da177e4SLinus Torvalds 
736*1da177e4SLinus Torvalds 	/* free IRQ */
737*1da177e4SLinus Torvalds 	free_irq(ha->irq, ha);
738*1da177e4SLinus Torvalds 
739*1da177e4SLinus Torvalds 	IPS_REMOVE_HOST(sh);
740*1da177e4SLinus Torvalds 	scsi_host_put(sh);
741*1da177e4SLinus Torvalds 
742*1da177e4SLinus Torvalds 	ips_released_controllers++;
743*1da177e4SLinus Torvalds 
744*1da177e4SLinus Torvalds 	return (FALSE);
745*1da177e4SLinus Torvalds }
746*1da177e4SLinus Torvalds 
747*1da177e4SLinus Torvalds /****************************************************************************/
748*1da177e4SLinus Torvalds /*                                                                          */
749*1da177e4SLinus Torvalds /* Routine Name: ips_halt                                                   */
750*1da177e4SLinus Torvalds /*                                                                          */
751*1da177e4SLinus Torvalds /* Routine Description:                                                     */
752*1da177e4SLinus Torvalds /*                                                                          */
753*1da177e4SLinus Torvalds /*   Perform cleanup when the system reboots                                */
754*1da177e4SLinus Torvalds /*                                                                          */
755*1da177e4SLinus Torvalds /****************************************************************************/
756*1da177e4SLinus Torvalds static int
757*1da177e4SLinus Torvalds ips_halt(struct notifier_block *nb, ulong event, void *buf)
758*1da177e4SLinus Torvalds {
759*1da177e4SLinus Torvalds 	ips_scb_t *scb;
760*1da177e4SLinus Torvalds 	ips_ha_t *ha;
761*1da177e4SLinus Torvalds 	int i;
762*1da177e4SLinus Torvalds 
763*1da177e4SLinus Torvalds 	if ((event != SYS_RESTART) && (event != SYS_HALT) &&
764*1da177e4SLinus Torvalds 	    (event != SYS_POWER_OFF))
765*1da177e4SLinus Torvalds 		return (NOTIFY_DONE);
766*1da177e4SLinus Torvalds 
767*1da177e4SLinus Torvalds 	for (i = 0; i < ips_next_controller; i++) {
768*1da177e4SLinus Torvalds 		ha = (ips_ha_t *) ips_ha[i];
769*1da177e4SLinus Torvalds 
770*1da177e4SLinus Torvalds 		if (!ha)
771*1da177e4SLinus Torvalds 			continue;
772*1da177e4SLinus Torvalds 
773*1da177e4SLinus Torvalds 		if (!ha->active)
774*1da177e4SLinus Torvalds 			continue;
775*1da177e4SLinus Torvalds 
776*1da177e4SLinus Torvalds 		/* flush the cache on the controller */
777*1da177e4SLinus Torvalds 		scb = &ha->scbs[ha->max_cmds - 1];
778*1da177e4SLinus Torvalds 
779*1da177e4SLinus Torvalds 		ips_init_scb(ha, scb);
780*1da177e4SLinus Torvalds 
781*1da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
782*1da177e4SLinus Torvalds 		scb->cdb[0] = IPS_CMD_FLUSH;
783*1da177e4SLinus Torvalds 
784*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
785*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
786*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.state = IPS_NORM_STATE;
787*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved = 0;
788*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved2 = 0;
789*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved3 = 0;
790*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved4 = 0;
791*1da177e4SLinus Torvalds 
792*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
793*1da177e4SLinus Torvalds 
794*1da177e4SLinus Torvalds 		/* send command */
795*1da177e4SLinus Torvalds 		if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==
796*1da177e4SLinus Torvalds 		    IPS_FAILURE)
797*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
798*1da177e4SLinus Torvalds 				   "Incomplete Flush.\n");
799*1da177e4SLinus Torvalds 		else
800*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
801*1da177e4SLinus Torvalds 				   "Flushing Complete.\n");
802*1da177e4SLinus Torvalds 	}
803*1da177e4SLinus Torvalds 
804*1da177e4SLinus Torvalds 	return (NOTIFY_OK);
805*1da177e4SLinus Torvalds }
806*1da177e4SLinus Torvalds 
807*1da177e4SLinus Torvalds /****************************************************************************/
808*1da177e4SLinus Torvalds /*                                                                          */
809*1da177e4SLinus Torvalds /* Routine Name: ips_eh_abort                                               */
810*1da177e4SLinus Torvalds /*                                                                          */
811*1da177e4SLinus Torvalds /* Routine Description:                                                     */
812*1da177e4SLinus Torvalds /*                                                                          */
813*1da177e4SLinus Torvalds /*   Abort a command (using the new error code stuff)                       */
814*1da177e4SLinus Torvalds /* Note: this routine is called under the io_request_lock                   */
815*1da177e4SLinus Torvalds /****************************************************************************/
816*1da177e4SLinus Torvalds int
817*1da177e4SLinus Torvalds ips_eh_abort(Scsi_Cmnd * SC)
818*1da177e4SLinus Torvalds {
819*1da177e4SLinus Torvalds 	ips_ha_t *ha;
820*1da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
821*1da177e4SLinus Torvalds 	int ret;
822*1da177e4SLinus Torvalds 
823*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_eh_abort", 1);
824*1da177e4SLinus Torvalds 
825*1da177e4SLinus Torvalds 	if (!SC)
826*1da177e4SLinus Torvalds 		return (FAILED);
827*1da177e4SLinus Torvalds 
828*1da177e4SLinus Torvalds 	ha = (ips_ha_t *) SC->device->host->hostdata;
829*1da177e4SLinus Torvalds 
830*1da177e4SLinus Torvalds 	if (!ha)
831*1da177e4SLinus Torvalds 		return (FAILED);
832*1da177e4SLinus Torvalds 
833*1da177e4SLinus Torvalds 	if (!ha->active)
834*1da177e4SLinus Torvalds 		return (FAILED);
835*1da177e4SLinus Torvalds 
836*1da177e4SLinus Torvalds 	if (SC->serial_number != SC->serial_number_at_timeout) {
837*1da177e4SLinus Torvalds 		/* HMM, looks like a bogus command */
838*1da177e4SLinus Torvalds 		DEBUG(1, "Abort called with bogus scsi command");
839*1da177e4SLinus Torvalds 
840*1da177e4SLinus Torvalds 		return (FAILED);
841*1da177e4SLinus Torvalds 	}
842*1da177e4SLinus Torvalds 
843*1da177e4SLinus Torvalds 	/* See if the command is on the copp queue */
844*1da177e4SLinus Torvalds 	item = ha->copp_waitlist.head;
845*1da177e4SLinus Torvalds 	while ((item) && (item->scsi_cmd != SC))
846*1da177e4SLinus Torvalds 		item = item->next;
847*1da177e4SLinus Torvalds 
848*1da177e4SLinus Torvalds 	if (item) {
849*1da177e4SLinus Torvalds 		/* Found it */
850*1da177e4SLinus Torvalds 		ips_removeq_copp(&ha->copp_waitlist, item);
851*1da177e4SLinus Torvalds 		ret = (SUCCESS);
852*1da177e4SLinus Torvalds 
853*1da177e4SLinus Torvalds 		/* See if the command is on the wait queue */
854*1da177e4SLinus Torvalds 	} else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
855*1da177e4SLinus Torvalds 		/* command not sent yet */
856*1da177e4SLinus Torvalds 		ret = (SUCCESS);
857*1da177e4SLinus Torvalds 	} else {
858*1da177e4SLinus Torvalds 		/* command must have already been sent */
859*1da177e4SLinus Torvalds 		ret = (FAILED);
860*1da177e4SLinus Torvalds 	}
861*1da177e4SLinus Torvalds 	return ret;
862*1da177e4SLinus Torvalds }
863*1da177e4SLinus Torvalds 
864*1da177e4SLinus Torvalds /****************************************************************************/
865*1da177e4SLinus Torvalds /*                                                                          */
866*1da177e4SLinus Torvalds /* Routine Name: ips_eh_reset                                               */
867*1da177e4SLinus Torvalds /*                                                                          */
868*1da177e4SLinus Torvalds /* Routine Description:                                                     */
869*1da177e4SLinus Torvalds /*                                                                          */
870*1da177e4SLinus Torvalds /*   Reset the controller (with new eh error code)                          */
871*1da177e4SLinus Torvalds /*                                                                          */
872*1da177e4SLinus Torvalds /* NOTE: this routine is called under the io_request_lock spinlock          */
873*1da177e4SLinus Torvalds /*                                                                          */
874*1da177e4SLinus Torvalds /****************************************************************************/
875*1da177e4SLinus Torvalds static int
876*1da177e4SLinus Torvalds ips_eh_reset(Scsi_Cmnd * SC)
877*1da177e4SLinus Torvalds {
878*1da177e4SLinus Torvalds 	int ret;
879*1da177e4SLinus Torvalds 	int i;
880*1da177e4SLinus Torvalds 	ips_ha_t *ha;
881*1da177e4SLinus Torvalds 	ips_scb_t *scb;
882*1da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
883*1da177e4SLinus Torvalds 
884*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_eh_reset", 1);
885*1da177e4SLinus Torvalds 
886*1da177e4SLinus Torvalds #ifdef NO_IPS_RESET
887*1da177e4SLinus Torvalds 	return (FAILED);
888*1da177e4SLinus Torvalds #else
889*1da177e4SLinus Torvalds 
890*1da177e4SLinus Torvalds 	if (!SC) {
891*1da177e4SLinus Torvalds 		DEBUG(1, "Reset called with NULL scsi command");
892*1da177e4SLinus Torvalds 
893*1da177e4SLinus Torvalds 		return (FAILED);
894*1da177e4SLinus Torvalds 	}
895*1da177e4SLinus Torvalds 
896*1da177e4SLinus Torvalds 	ha = (ips_ha_t *) SC->device->host->hostdata;
897*1da177e4SLinus Torvalds 
898*1da177e4SLinus Torvalds 	if (!ha) {
899*1da177e4SLinus Torvalds 		DEBUG(1, "Reset called with NULL ha struct");
900*1da177e4SLinus Torvalds 
901*1da177e4SLinus Torvalds 		return (FAILED);
902*1da177e4SLinus Torvalds 	}
903*1da177e4SLinus Torvalds 
904*1da177e4SLinus Torvalds 	if (!ha->active)
905*1da177e4SLinus Torvalds 		return (FAILED);
906*1da177e4SLinus Torvalds 
907*1da177e4SLinus Torvalds 	/* See if the command is on the copp queue */
908*1da177e4SLinus Torvalds 	item = ha->copp_waitlist.head;
909*1da177e4SLinus Torvalds 	while ((item) && (item->scsi_cmd != SC))
910*1da177e4SLinus Torvalds 		item = item->next;
911*1da177e4SLinus Torvalds 
912*1da177e4SLinus Torvalds 	if (item) {
913*1da177e4SLinus Torvalds 		/* Found it */
914*1da177e4SLinus Torvalds 		ips_removeq_copp(&ha->copp_waitlist, item);
915*1da177e4SLinus Torvalds 		return (SUCCESS);
916*1da177e4SLinus Torvalds 	}
917*1da177e4SLinus Torvalds 
918*1da177e4SLinus Torvalds 	/* See if the command is on the wait queue */
919*1da177e4SLinus Torvalds 	if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
920*1da177e4SLinus Torvalds 		/* command not sent yet */
921*1da177e4SLinus Torvalds 		return (SUCCESS);
922*1da177e4SLinus Torvalds 	}
923*1da177e4SLinus Torvalds 
924*1da177e4SLinus Torvalds 	/* An explanation for the casual observer:                              */
925*1da177e4SLinus Torvalds 	/* Part of the function of a RAID controller is automatic error         */
926*1da177e4SLinus Torvalds 	/* detection and recovery.  As such, the only problem that physically   */
927*1da177e4SLinus Torvalds 	/* resetting an adapter will ever fix is when, for some reason,         */
928*1da177e4SLinus Torvalds 	/* the driver is not successfully communicating with the adapter.       */
929*1da177e4SLinus Torvalds 	/* Therefore, we will attempt to flush this adapter.  If that succeeds, */
930*1da177e4SLinus Torvalds 	/* then there's no real purpose in a physical reset. This will complete */
931*1da177e4SLinus Torvalds 	/* much faster and avoids any problems that might be caused by a        */
932*1da177e4SLinus Torvalds 	/* physical reset ( such as having to fail all the outstanding I/O's ). */
933*1da177e4SLinus Torvalds 
934*1da177e4SLinus Torvalds 	if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */
935*1da177e4SLinus Torvalds 		scb = &ha->scbs[ha->max_cmds - 1];
936*1da177e4SLinus Torvalds 
937*1da177e4SLinus Torvalds 		ips_init_scb(ha, scb);
938*1da177e4SLinus Torvalds 
939*1da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
940*1da177e4SLinus Torvalds 		scb->cdb[0] = IPS_CMD_FLUSH;
941*1da177e4SLinus Torvalds 
942*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
943*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
944*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.state = IPS_NORM_STATE;
945*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved = 0;
946*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved2 = 0;
947*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved3 = 0;
948*1da177e4SLinus Torvalds 		scb->cmd.flush_cache.reserved4 = 0;
949*1da177e4SLinus Torvalds 
950*1da177e4SLinus Torvalds 		/* Attempt the flush command */
951*1da177e4SLinus Torvalds 		ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
952*1da177e4SLinus Torvalds 		if (ret == IPS_SUCCESS) {
953*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_NOTICE, ha->pcidev,
954*1da177e4SLinus Torvalds 				   "Reset Request - Flushed Cache\n");
955*1da177e4SLinus Torvalds 			return (SUCCESS);
956*1da177e4SLinus Torvalds 		}
957*1da177e4SLinus Torvalds 	}
958*1da177e4SLinus Torvalds 
959*1da177e4SLinus Torvalds 	/* Either we can't communicate with the adapter or it's an IOCTL request */
960*1da177e4SLinus Torvalds 	/* from a utility.  A physical reset is needed at this point.            */
961*1da177e4SLinus Torvalds 
962*1da177e4SLinus Torvalds 	ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */
963*1da177e4SLinus Torvalds 
964*1da177e4SLinus Torvalds 	/*
965*1da177e4SLinus Torvalds 	 * command must have already been sent
966*1da177e4SLinus Torvalds 	 * reset the controller
967*1da177e4SLinus Torvalds 	 */
968*1da177e4SLinus Torvalds 	IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
969*1da177e4SLinus Torvalds 	ret = (*ha->func.reset) (ha);
970*1da177e4SLinus Torvalds 
971*1da177e4SLinus Torvalds 	if (!ret) {
972*1da177e4SLinus Torvalds 		Scsi_Cmnd *scsi_cmd;
973*1da177e4SLinus Torvalds 
974*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
975*1da177e4SLinus Torvalds 			   "Controller reset failed - controller now offline.\n");
976*1da177e4SLinus Torvalds 
977*1da177e4SLinus Torvalds 		/* Now fail all of the active commands */
978*1da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing active commands",
979*1da177e4SLinus Torvalds 			  ips_name, ha->host_num);
980*1da177e4SLinus Torvalds 
981*1da177e4SLinus Torvalds 		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
982*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_ERROR << 16;
983*1da177e4SLinus Torvalds 			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
984*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
985*1da177e4SLinus Torvalds 		}
986*1da177e4SLinus Torvalds 
987*1da177e4SLinus Torvalds 		/* Now fail all of the pending commands */
988*1da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing pending commands",
989*1da177e4SLinus Torvalds 			  ips_name, ha->host_num);
990*1da177e4SLinus Torvalds 
991*1da177e4SLinus Torvalds 		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
992*1da177e4SLinus Torvalds 			scsi_cmd->result = DID_ERROR;
993*1da177e4SLinus Torvalds 			scsi_cmd->scsi_done(scsi_cmd);
994*1da177e4SLinus Torvalds 		}
995*1da177e4SLinus Torvalds 
996*1da177e4SLinus Torvalds 		ha->active = FALSE;
997*1da177e4SLinus Torvalds 		return (FAILED);
998*1da177e4SLinus Torvalds 	}
999*1da177e4SLinus Torvalds 
1000*1da177e4SLinus Torvalds 	if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
1001*1da177e4SLinus Torvalds 		Scsi_Cmnd *scsi_cmd;
1002*1da177e4SLinus Torvalds 
1003*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
1004*1da177e4SLinus Torvalds 			   "Controller reset failed - controller now offline.\n");
1005*1da177e4SLinus Torvalds 
1006*1da177e4SLinus Torvalds 		/* Now fail all of the active commands */
1007*1da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing active commands",
1008*1da177e4SLinus Torvalds 			  ips_name, ha->host_num);
1009*1da177e4SLinus Torvalds 
1010*1da177e4SLinus Torvalds 		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
1011*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_ERROR << 16;
1012*1da177e4SLinus Torvalds 			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
1013*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
1014*1da177e4SLinus Torvalds 		}
1015*1da177e4SLinus Torvalds 
1016*1da177e4SLinus Torvalds 		/* Now fail all of the pending commands */
1017*1da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Failing pending commands",
1018*1da177e4SLinus Torvalds 			  ips_name, ha->host_num);
1019*1da177e4SLinus Torvalds 
1020*1da177e4SLinus Torvalds 		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
1021*1da177e4SLinus Torvalds 			scsi_cmd->result = DID_ERROR << 16;
1022*1da177e4SLinus Torvalds 			scsi_cmd->scsi_done(scsi_cmd);
1023*1da177e4SLinus Torvalds 		}
1024*1da177e4SLinus Torvalds 
1025*1da177e4SLinus Torvalds 		ha->active = FALSE;
1026*1da177e4SLinus Torvalds 		return (FAILED);
1027*1da177e4SLinus Torvalds 	}
1028*1da177e4SLinus Torvalds 
1029*1da177e4SLinus Torvalds 	/* FFDC */
1030*1da177e4SLinus Torvalds 	if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
1031*1da177e4SLinus Torvalds 		struct timeval tv;
1032*1da177e4SLinus Torvalds 
1033*1da177e4SLinus Torvalds 		do_gettimeofday(&tv);
1034*1da177e4SLinus Torvalds 		ha->last_ffdc = tv.tv_sec;
1035*1da177e4SLinus Torvalds 		ha->reset_count++;
1036*1da177e4SLinus Torvalds 		ips_ffdc_reset(ha, IPS_INTR_IORL);
1037*1da177e4SLinus Torvalds 	}
1038*1da177e4SLinus Torvalds 
1039*1da177e4SLinus Torvalds 	/* Now fail all of the active commands */
1040*1da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
1041*1da177e4SLinus Torvalds 
1042*1da177e4SLinus Torvalds 	while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
1043*1da177e4SLinus Torvalds 		scb->scsi_cmd->result =
1044*1da177e4SLinus Torvalds 		    (DID_RESET << 16) | (SUGGEST_RETRY << 24);
1045*1da177e4SLinus Torvalds 		scb->scsi_cmd->scsi_done(scb->scsi_cmd);
1046*1da177e4SLinus Torvalds 		ips_freescb(ha, scb);
1047*1da177e4SLinus Torvalds 	}
1048*1da177e4SLinus Torvalds 
1049*1da177e4SLinus Torvalds 	/* Reset DCDB active command bits */
1050*1da177e4SLinus Torvalds 	for (i = 1; i < ha->nbus; i++)
1051*1da177e4SLinus Torvalds 		ha->dcdb_active[i - 1] = 0;
1052*1da177e4SLinus Torvalds 
1053*1da177e4SLinus Torvalds 	/* Reset the number of active IOCTLs */
1054*1da177e4SLinus Torvalds 	ha->num_ioctl = 0;
1055*1da177e4SLinus Torvalds 
1056*1da177e4SLinus Torvalds 	ips_next(ha, IPS_INTR_IORL);
1057*1da177e4SLinus Torvalds 
1058*1da177e4SLinus Torvalds 	return (SUCCESS);
1059*1da177e4SLinus Torvalds #endif				/* NO_IPS_RESET */
1060*1da177e4SLinus Torvalds 
1061*1da177e4SLinus Torvalds }
1062*1da177e4SLinus Torvalds 
1063*1da177e4SLinus Torvalds /****************************************************************************/
1064*1da177e4SLinus Torvalds /*                                                                          */
1065*1da177e4SLinus Torvalds /* Routine Name: ips_queue                                                  */
1066*1da177e4SLinus Torvalds /*                                                                          */
1067*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1068*1da177e4SLinus Torvalds /*                                                                          */
1069*1da177e4SLinus Torvalds /*   Send a command to the controller                                       */
1070*1da177e4SLinus Torvalds /*                                                                          */
1071*1da177e4SLinus Torvalds /* NOTE:                                                                    */
1072*1da177e4SLinus Torvalds /*    Linux obtains io_request_lock before calling this function            */
1073*1da177e4SLinus Torvalds /*                                                                          */
1074*1da177e4SLinus Torvalds /****************************************************************************/
1075*1da177e4SLinus Torvalds static int
1076*1da177e4SLinus Torvalds ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
1077*1da177e4SLinus Torvalds {
1078*1da177e4SLinus Torvalds 	ips_ha_t *ha;
1079*1da177e4SLinus Torvalds 	ips_passthru_t *pt;
1080*1da177e4SLinus Torvalds 
1081*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_queue", 1);
1082*1da177e4SLinus Torvalds 
1083*1da177e4SLinus Torvalds 	ha = (ips_ha_t *) SC->device->host->hostdata;
1084*1da177e4SLinus Torvalds 
1085*1da177e4SLinus Torvalds 	if (!ha)
1086*1da177e4SLinus Torvalds 		return (1);
1087*1da177e4SLinus Torvalds 
1088*1da177e4SLinus Torvalds 	if (!ha->active)
1089*1da177e4SLinus Torvalds 		return (DID_ERROR);
1090*1da177e4SLinus Torvalds 
1091*1da177e4SLinus Torvalds 	if (ips_is_passthru(SC)) {
1092*1da177e4SLinus Torvalds 		if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
1093*1da177e4SLinus Torvalds 			SC->result = DID_BUS_BUSY << 16;
1094*1da177e4SLinus Torvalds 			done(SC);
1095*1da177e4SLinus Torvalds 
1096*1da177e4SLinus Torvalds 			return (0);
1097*1da177e4SLinus Torvalds 		}
1098*1da177e4SLinus Torvalds 	} else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
1099*1da177e4SLinus Torvalds 		SC->result = DID_BUS_BUSY << 16;
1100*1da177e4SLinus Torvalds 		done(SC);
1101*1da177e4SLinus Torvalds 
1102*1da177e4SLinus Torvalds 		return (0);
1103*1da177e4SLinus Torvalds 	}
1104*1da177e4SLinus Torvalds 
1105*1da177e4SLinus Torvalds 	SC->scsi_done = done;
1106*1da177e4SLinus Torvalds 
1107*1da177e4SLinus Torvalds 	DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
1108*1da177e4SLinus Torvalds 		  ips_name,
1109*1da177e4SLinus Torvalds 		  ha->host_num,
1110*1da177e4SLinus Torvalds 		  SC->cmnd[0],
1111*1da177e4SLinus Torvalds 		  SC->device->channel, SC->device->id, SC->device->lun);
1112*1da177e4SLinus Torvalds 
1113*1da177e4SLinus Torvalds 	/* Check for command to initiator IDs */
1114*1da177e4SLinus Torvalds 	if ((SC->device->channel > 0)
1115*1da177e4SLinus Torvalds 	    && (SC->device->id == ha->ha_id[SC->device->channel])) {
1116*1da177e4SLinus Torvalds 		SC->result = DID_NO_CONNECT << 16;
1117*1da177e4SLinus Torvalds 		done(SC);
1118*1da177e4SLinus Torvalds 
1119*1da177e4SLinus Torvalds 		return (0);
1120*1da177e4SLinus Torvalds 	}
1121*1da177e4SLinus Torvalds 
1122*1da177e4SLinus Torvalds 	if (ips_is_passthru(SC)) {
1123*1da177e4SLinus Torvalds 
1124*1da177e4SLinus Torvalds 		ips_copp_wait_item_t *scratch;
1125*1da177e4SLinus Torvalds 
1126*1da177e4SLinus Torvalds 		/* A Reset IOCTL is only sent by the boot CD in extreme cases.           */
1127*1da177e4SLinus Torvalds 		/* There can never be any system activity ( network or disk ), but check */
1128*1da177e4SLinus Torvalds 		/* anyway just as a good practice.                                       */
1129*1da177e4SLinus Torvalds 		pt = (ips_passthru_t *) SC->request_buffer;
1130*1da177e4SLinus Torvalds 		if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
1131*1da177e4SLinus Torvalds 		    (pt->CoppCP.cmd.reset.adapter_flag == 1)) {
1132*1da177e4SLinus Torvalds 			if (ha->scb_activelist.count != 0) {
1133*1da177e4SLinus Torvalds 				SC->result = DID_BUS_BUSY << 16;
1134*1da177e4SLinus Torvalds 				done(SC);
1135*1da177e4SLinus Torvalds 				return (0);
1136*1da177e4SLinus Torvalds 			}
1137*1da177e4SLinus Torvalds 			ha->ioctl_reset = 1;	/* This reset request is from an IOCTL */
1138*1da177e4SLinus Torvalds 			ips_eh_reset(SC);
1139*1da177e4SLinus Torvalds 			SC->result = DID_OK << 16;
1140*1da177e4SLinus Torvalds 			SC->scsi_done(SC);
1141*1da177e4SLinus Torvalds 			return (0);
1142*1da177e4SLinus Torvalds 		}
1143*1da177e4SLinus Torvalds 
1144*1da177e4SLinus Torvalds 		/* allocate space for the scribble */
1145*1da177e4SLinus Torvalds 		scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC);
1146*1da177e4SLinus Torvalds 
1147*1da177e4SLinus Torvalds 		if (!scratch) {
1148*1da177e4SLinus Torvalds 			SC->result = DID_ERROR << 16;
1149*1da177e4SLinus Torvalds 			done(SC);
1150*1da177e4SLinus Torvalds 
1151*1da177e4SLinus Torvalds 			return (0);
1152*1da177e4SLinus Torvalds 		}
1153*1da177e4SLinus Torvalds 
1154*1da177e4SLinus Torvalds 		scratch->scsi_cmd = SC;
1155*1da177e4SLinus Torvalds 		scratch->next = NULL;
1156*1da177e4SLinus Torvalds 
1157*1da177e4SLinus Torvalds 		ips_putq_copp_tail(&ha->copp_waitlist, scratch);
1158*1da177e4SLinus Torvalds 	} else {
1159*1da177e4SLinus Torvalds 		ips_putq_wait_tail(&ha->scb_waitlist, SC);
1160*1da177e4SLinus Torvalds 	}
1161*1da177e4SLinus Torvalds 
1162*1da177e4SLinus Torvalds 	ips_next(ha, IPS_INTR_IORL);
1163*1da177e4SLinus Torvalds 
1164*1da177e4SLinus Torvalds 	return (0);
1165*1da177e4SLinus Torvalds }
1166*1da177e4SLinus Torvalds 
1167*1da177e4SLinus Torvalds /****************************************************************************/
1168*1da177e4SLinus Torvalds /*                                                                          */
1169*1da177e4SLinus Torvalds /* Routine Name: ips_biosparam                                              */
1170*1da177e4SLinus Torvalds /*                                                                          */
1171*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1172*1da177e4SLinus Torvalds /*                                                                          */
1173*1da177e4SLinus Torvalds /*   Set bios geometry for the controller                                   */
1174*1da177e4SLinus Torvalds /*                                                                          */
1175*1da177e4SLinus Torvalds /****************************************************************************/
1176*1da177e4SLinus Torvalds static int
1177*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1178*1da177e4SLinus Torvalds ips_biosparam(Disk * disk, kdev_t dev, int geom[])
1179*1da177e4SLinus Torvalds {
1180*1da177e4SLinus Torvalds 	ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata;
1181*1da177e4SLinus Torvalds 	unsigned long capacity = disk->capacity;
1182*1da177e4SLinus Torvalds #else
1183*1da177e4SLinus Torvalds ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
1184*1da177e4SLinus Torvalds 	      sector_t capacity, int geom[])
1185*1da177e4SLinus Torvalds {
1186*1da177e4SLinus Torvalds 	ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
1187*1da177e4SLinus Torvalds #endif
1188*1da177e4SLinus Torvalds 	int heads;
1189*1da177e4SLinus Torvalds 	int sectors;
1190*1da177e4SLinus Torvalds 	int cylinders;
1191*1da177e4SLinus Torvalds 
1192*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_biosparam", 1);
1193*1da177e4SLinus Torvalds 
1194*1da177e4SLinus Torvalds 	if (!ha)
1195*1da177e4SLinus Torvalds 		/* ?!?! host adater info invalid */
1196*1da177e4SLinus Torvalds 		return (0);
1197*1da177e4SLinus Torvalds 
1198*1da177e4SLinus Torvalds 	if (!ha->active)
1199*1da177e4SLinus Torvalds 		return (0);
1200*1da177e4SLinus Torvalds 
1201*1da177e4SLinus Torvalds 	if (!ips_read_adapter_status(ha, IPS_INTR_ON))
1202*1da177e4SLinus Torvalds 		/* ?!?! Enquiry command failed */
1203*1da177e4SLinus Torvalds 		return (0);
1204*1da177e4SLinus Torvalds 
1205*1da177e4SLinus Torvalds 	if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
1206*1da177e4SLinus Torvalds 		heads = IPS_NORM_HEADS;
1207*1da177e4SLinus Torvalds 		sectors = IPS_NORM_SECTORS;
1208*1da177e4SLinus Torvalds 	} else {
1209*1da177e4SLinus Torvalds 		heads = IPS_COMP_HEADS;
1210*1da177e4SLinus Torvalds 		sectors = IPS_COMP_SECTORS;
1211*1da177e4SLinus Torvalds 	}
1212*1da177e4SLinus Torvalds 
1213*1da177e4SLinus Torvalds 	cylinders = (unsigned long) capacity / (heads * sectors);
1214*1da177e4SLinus Torvalds 
1215*1da177e4SLinus Torvalds 	DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
1216*1da177e4SLinus Torvalds 		  heads, sectors, cylinders);
1217*1da177e4SLinus Torvalds 
1218*1da177e4SLinus Torvalds 	geom[0] = heads;
1219*1da177e4SLinus Torvalds 	geom[1] = sectors;
1220*1da177e4SLinus Torvalds 	geom[2] = cylinders;
1221*1da177e4SLinus Torvalds 
1222*1da177e4SLinus Torvalds 	return (0);
1223*1da177e4SLinus Torvalds }
1224*1da177e4SLinus Torvalds 
1225*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1226*1da177e4SLinus Torvalds 
1227*1da177e4SLinus Torvalds /* ips_proc24_info is a wrapper around ips_proc_info *
1228*1da177e4SLinus Torvalds  * for compatibility with the 2.4 scsi parameters    */
1229*1da177e4SLinus Torvalds static int
1230*1da177e4SLinus Torvalds ips_proc24_info(char *buffer, char **start, off_t offset, int length,
1231*1da177e4SLinus Torvalds 		              int hostno, int func)
1232*1da177e4SLinus Torvalds {
1233*1da177e4SLinus Torvalds 	int i;
1234*1da177e4SLinus Torvalds 
1235*1da177e4SLinus Torvalds 	for (i = 0; i < ips_next_controller; i++) {
1236*1da177e4SLinus Torvalds 		if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
1237*1da177e4SLinus Torvalds 			return ips_proc_info(ips_sh[i], buffer, start,
1238*1da177e4SLinus Torvalds 					     offset, length, func);
1239*1da177e4SLinus Torvalds 		}
1240*1da177e4SLinus Torvalds 	}
1241*1da177e4SLinus Torvalds 	return -EINVAL;
1242*1da177e4SLinus Torvalds }
1243*1da177e4SLinus Torvalds 
1244*1da177e4SLinus Torvalds /****************************************************************************/
1245*1da177e4SLinus Torvalds /*                                                                          */
1246*1da177e4SLinus Torvalds /* Routine Name: ips_select_queue_depth                                     */
1247*1da177e4SLinus Torvalds /*                                                                          */
1248*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1249*1da177e4SLinus Torvalds /*                                                                          */
1250*1da177e4SLinus Torvalds /*   Select queue depths for the devices on the contoller                   */
1251*1da177e4SLinus Torvalds /*                                                                          */
1252*1da177e4SLinus Torvalds /****************************************************************************/
1253*1da177e4SLinus Torvalds static void
1254*1da177e4SLinus Torvalds ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
1255*1da177e4SLinus Torvalds {
1256*1da177e4SLinus Torvalds 	Scsi_Device *device;
1257*1da177e4SLinus Torvalds 	ips_ha_t *ha;
1258*1da177e4SLinus Torvalds 	int count = 0;
1259*1da177e4SLinus Torvalds 	int min;
1260*1da177e4SLinus Torvalds 
1261*1da177e4SLinus Torvalds 	ha = IPS_HA(host);
1262*1da177e4SLinus Torvalds 	min = ha->max_cmds / 4;
1263*1da177e4SLinus Torvalds 
1264*1da177e4SLinus Torvalds 	for (device = scsi_devs; device; device = device->next) {
1265*1da177e4SLinus Torvalds 		if (device->host == host) {
1266*1da177e4SLinus Torvalds 			if ((device->channel == 0) && (device->type == 0))
1267*1da177e4SLinus Torvalds 				count++;
1268*1da177e4SLinus Torvalds 		}
1269*1da177e4SLinus Torvalds 	}
1270*1da177e4SLinus Torvalds 
1271*1da177e4SLinus Torvalds 	for (device = scsi_devs; device; device = device->next) {
1272*1da177e4SLinus Torvalds 		if (device->host == host) {
1273*1da177e4SLinus Torvalds 			if ((device->channel == 0) && (device->type == 0)) {
1274*1da177e4SLinus Torvalds 				device->queue_depth =
1275*1da177e4SLinus Torvalds 				    (ha->max_cmds - 1) / count;
1276*1da177e4SLinus Torvalds 				if (device->queue_depth < min)
1277*1da177e4SLinus Torvalds 					device->queue_depth = min;
1278*1da177e4SLinus Torvalds 			} else {
1279*1da177e4SLinus Torvalds 				device->queue_depth = 2;
1280*1da177e4SLinus Torvalds 			}
1281*1da177e4SLinus Torvalds 
1282*1da177e4SLinus Torvalds 			if (device->queue_depth < 2)
1283*1da177e4SLinus Torvalds 				device->queue_depth = 2;
1284*1da177e4SLinus Torvalds 		}
1285*1da177e4SLinus Torvalds 	}
1286*1da177e4SLinus Torvalds }
1287*1da177e4SLinus Torvalds 
1288*1da177e4SLinus Torvalds #else
1289*1da177e4SLinus Torvalds /****************************************************************************/
1290*1da177e4SLinus Torvalds /*                                                                          */
1291*1da177e4SLinus Torvalds /* Routine Name: ips_slave_configure                                        */
1292*1da177e4SLinus Torvalds /*                                                                          */
1293*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1294*1da177e4SLinus Torvalds /*                                                                          */
1295*1da177e4SLinus Torvalds /*   Set queue depths on devices once scan is complete                      */
1296*1da177e4SLinus Torvalds /*                                                                          */
1297*1da177e4SLinus Torvalds /****************************************************************************/
1298*1da177e4SLinus Torvalds static int
1299*1da177e4SLinus Torvalds ips_slave_configure(Scsi_Device * SDptr)
1300*1da177e4SLinus Torvalds {
1301*1da177e4SLinus Torvalds 	ips_ha_t *ha;
1302*1da177e4SLinus Torvalds 	int min;
1303*1da177e4SLinus Torvalds 
1304*1da177e4SLinus Torvalds 	ha = IPS_HA(SDptr->host);
1305*1da177e4SLinus Torvalds 	if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) {
1306*1da177e4SLinus Torvalds 		min = ha->max_cmds / 2;
1307*1da177e4SLinus Torvalds 		if (ha->enq->ucLogDriveCount <= 2)
1308*1da177e4SLinus Torvalds 			min = ha->max_cmds - 1;
1309*1da177e4SLinus Torvalds 		scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
1310*1da177e4SLinus Torvalds 	}
1311*1da177e4SLinus Torvalds 	return 0;
1312*1da177e4SLinus Torvalds }
1313*1da177e4SLinus Torvalds #endif
1314*1da177e4SLinus Torvalds 
1315*1da177e4SLinus Torvalds /****************************************************************************/
1316*1da177e4SLinus Torvalds /*                                                                          */
1317*1da177e4SLinus Torvalds /* Routine Name: do_ipsintr                                                 */
1318*1da177e4SLinus Torvalds /*                                                                          */
1319*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1320*1da177e4SLinus Torvalds /*                                                                          */
1321*1da177e4SLinus Torvalds /*   Wrapper for the interrupt handler                                      */
1322*1da177e4SLinus Torvalds /*                                                                          */
1323*1da177e4SLinus Torvalds /****************************************************************************/
1324*1da177e4SLinus Torvalds static irqreturn_t
1325*1da177e4SLinus Torvalds do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
1326*1da177e4SLinus Torvalds {
1327*1da177e4SLinus Torvalds 	ips_ha_t *ha;
1328*1da177e4SLinus Torvalds 	unsigned long cpu_flags;
1329*1da177e4SLinus Torvalds 	struct Scsi_Host *host;
1330*1da177e4SLinus Torvalds 	int irqstatus;
1331*1da177e4SLinus Torvalds 
1332*1da177e4SLinus Torvalds 	METHOD_TRACE("do_ipsintr", 2);
1333*1da177e4SLinus Torvalds 
1334*1da177e4SLinus Torvalds 	ha = (ips_ha_t *) dev_id;
1335*1da177e4SLinus Torvalds 	if (!ha)
1336*1da177e4SLinus Torvalds 		return IRQ_NONE;
1337*1da177e4SLinus Torvalds 	host = ips_sh[ha->host_num];
1338*1da177e4SLinus Torvalds 	/* interrupt during initialization */
1339*1da177e4SLinus Torvalds 	if (!host) {
1340*1da177e4SLinus Torvalds 		(*ha->func.intr) (ha);
1341*1da177e4SLinus Torvalds 		return IRQ_HANDLED;
1342*1da177e4SLinus Torvalds 	}
1343*1da177e4SLinus Torvalds 
1344*1da177e4SLinus Torvalds 	IPS_LOCK_SAVE(host->host_lock, cpu_flags);
1345*1da177e4SLinus Torvalds 
1346*1da177e4SLinus Torvalds 	if (!ha->active) {
1347*1da177e4SLinus Torvalds 		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
1348*1da177e4SLinus Torvalds 		return IRQ_HANDLED;
1349*1da177e4SLinus Torvalds 	}
1350*1da177e4SLinus Torvalds 
1351*1da177e4SLinus Torvalds 	irqstatus = (*ha->func.intr) (ha);
1352*1da177e4SLinus Torvalds 
1353*1da177e4SLinus Torvalds 	IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
1354*1da177e4SLinus Torvalds 
1355*1da177e4SLinus Torvalds 	/* start the next command */
1356*1da177e4SLinus Torvalds 	ips_next(ha, IPS_INTR_ON);
1357*1da177e4SLinus Torvalds 	return IRQ_RETVAL(irqstatus);
1358*1da177e4SLinus Torvalds }
1359*1da177e4SLinus Torvalds 
1360*1da177e4SLinus Torvalds /****************************************************************************/
1361*1da177e4SLinus Torvalds /*                                                                          */
1362*1da177e4SLinus Torvalds /* Routine Name: ips_intr_copperhead                                        */
1363*1da177e4SLinus Torvalds /*                                                                          */
1364*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1365*1da177e4SLinus Torvalds /*                                                                          */
1366*1da177e4SLinus Torvalds /*   Polling interrupt handler                                              */
1367*1da177e4SLinus Torvalds /*                                                                          */
1368*1da177e4SLinus Torvalds /*   ASSUMES interrupts are disabled                                        */
1369*1da177e4SLinus Torvalds /*                                                                          */
1370*1da177e4SLinus Torvalds /****************************************************************************/
1371*1da177e4SLinus Torvalds int
1372*1da177e4SLinus Torvalds ips_intr_copperhead(ips_ha_t * ha)
1373*1da177e4SLinus Torvalds {
1374*1da177e4SLinus Torvalds 	ips_stat_t *sp;
1375*1da177e4SLinus Torvalds 	ips_scb_t *scb;
1376*1da177e4SLinus Torvalds 	IPS_STATUS cstatus;
1377*1da177e4SLinus Torvalds 	int intrstatus;
1378*1da177e4SLinus Torvalds 
1379*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_intr", 2);
1380*1da177e4SLinus Torvalds 
1381*1da177e4SLinus Torvalds 	if (!ha)
1382*1da177e4SLinus Torvalds 		return 0;
1383*1da177e4SLinus Torvalds 
1384*1da177e4SLinus Torvalds 	if (!ha->active)
1385*1da177e4SLinus Torvalds 		return 0;
1386*1da177e4SLinus Torvalds 
1387*1da177e4SLinus Torvalds 	intrstatus = (*ha->func.isintr) (ha);
1388*1da177e4SLinus Torvalds 
1389*1da177e4SLinus Torvalds 	if (!intrstatus) {
1390*1da177e4SLinus Torvalds 		/*
1391*1da177e4SLinus Torvalds 		 * Unexpected/Shared interrupt
1392*1da177e4SLinus Torvalds 		 */
1393*1da177e4SLinus Torvalds 
1394*1da177e4SLinus Torvalds 		return 0;
1395*1da177e4SLinus Torvalds 	}
1396*1da177e4SLinus Torvalds 
1397*1da177e4SLinus Torvalds 	while (TRUE) {
1398*1da177e4SLinus Torvalds 		sp = &ha->sp;
1399*1da177e4SLinus Torvalds 
1400*1da177e4SLinus Torvalds 		intrstatus = (*ha->func.isintr) (ha);
1401*1da177e4SLinus Torvalds 
1402*1da177e4SLinus Torvalds 		if (!intrstatus)
1403*1da177e4SLinus Torvalds 			break;
1404*1da177e4SLinus Torvalds 		else
1405*1da177e4SLinus Torvalds 			cstatus.value = (*ha->func.statupd) (ha);
1406*1da177e4SLinus Torvalds 
1407*1da177e4SLinus Torvalds 		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
1408*1da177e4SLinus Torvalds 			/* Spurious Interupt ? */
1409*1da177e4SLinus Torvalds 			continue;
1410*1da177e4SLinus Torvalds 		}
1411*1da177e4SLinus Torvalds 
1412*1da177e4SLinus Torvalds 		ips_chkstatus(ha, &cstatus);
1413*1da177e4SLinus Torvalds 		scb = (ips_scb_t *) sp->scb_addr;
1414*1da177e4SLinus Torvalds 
1415*1da177e4SLinus Torvalds 		/*
1416*1da177e4SLinus Torvalds 		 * use the callback function to finish things up
1417*1da177e4SLinus Torvalds 		 * NOTE: interrupts are OFF for this
1418*1da177e4SLinus Torvalds 		 */
1419*1da177e4SLinus Torvalds 		(*scb->callback) (ha, scb);
1420*1da177e4SLinus Torvalds 	}			/* end while */
1421*1da177e4SLinus Torvalds 	return 1;
1422*1da177e4SLinus Torvalds }
1423*1da177e4SLinus Torvalds 
1424*1da177e4SLinus Torvalds /****************************************************************************/
1425*1da177e4SLinus Torvalds /*                                                                          */
1426*1da177e4SLinus Torvalds /* Routine Name: ips_intr_morpheus                                          */
1427*1da177e4SLinus Torvalds /*                                                                          */
1428*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1429*1da177e4SLinus Torvalds /*                                                                          */
1430*1da177e4SLinus Torvalds /*   Polling interrupt handler                                              */
1431*1da177e4SLinus Torvalds /*                                                                          */
1432*1da177e4SLinus Torvalds /*   ASSUMES interrupts are disabled                                        */
1433*1da177e4SLinus Torvalds /*                                                                          */
1434*1da177e4SLinus Torvalds /****************************************************************************/
1435*1da177e4SLinus Torvalds int
1436*1da177e4SLinus Torvalds ips_intr_morpheus(ips_ha_t * ha)
1437*1da177e4SLinus Torvalds {
1438*1da177e4SLinus Torvalds 	ips_stat_t *sp;
1439*1da177e4SLinus Torvalds 	ips_scb_t *scb;
1440*1da177e4SLinus Torvalds 	IPS_STATUS cstatus;
1441*1da177e4SLinus Torvalds 	int intrstatus;
1442*1da177e4SLinus Torvalds 
1443*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_intr_morpheus", 2);
1444*1da177e4SLinus Torvalds 
1445*1da177e4SLinus Torvalds 	if (!ha)
1446*1da177e4SLinus Torvalds 		return 0;
1447*1da177e4SLinus Torvalds 
1448*1da177e4SLinus Torvalds 	if (!ha->active)
1449*1da177e4SLinus Torvalds 		return 0;
1450*1da177e4SLinus Torvalds 
1451*1da177e4SLinus Torvalds 	intrstatus = (*ha->func.isintr) (ha);
1452*1da177e4SLinus Torvalds 
1453*1da177e4SLinus Torvalds 	if (!intrstatus) {
1454*1da177e4SLinus Torvalds 		/*
1455*1da177e4SLinus Torvalds 		 * Unexpected/Shared interrupt
1456*1da177e4SLinus Torvalds 		 */
1457*1da177e4SLinus Torvalds 
1458*1da177e4SLinus Torvalds 		return 0;
1459*1da177e4SLinus Torvalds 	}
1460*1da177e4SLinus Torvalds 
1461*1da177e4SLinus Torvalds 	while (TRUE) {
1462*1da177e4SLinus Torvalds 		sp = &ha->sp;
1463*1da177e4SLinus Torvalds 
1464*1da177e4SLinus Torvalds 		intrstatus = (*ha->func.isintr) (ha);
1465*1da177e4SLinus Torvalds 
1466*1da177e4SLinus Torvalds 		if (!intrstatus)
1467*1da177e4SLinus Torvalds 			break;
1468*1da177e4SLinus Torvalds 		else
1469*1da177e4SLinus Torvalds 			cstatus.value = (*ha->func.statupd) (ha);
1470*1da177e4SLinus Torvalds 
1471*1da177e4SLinus Torvalds 		if (cstatus.value == 0xffffffff)
1472*1da177e4SLinus Torvalds 			/* No more to process */
1473*1da177e4SLinus Torvalds 			break;
1474*1da177e4SLinus Torvalds 
1475*1da177e4SLinus Torvalds 		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
1476*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
1477*1da177e4SLinus Torvalds 				   "Spurious interrupt; no ccb.\n");
1478*1da177e4SLinus Torvalds 
1479*1da177e4SLinus Torvalds 			continue;
1480*1da177e4SLinus Torvalds 		}
1481*1da177e4SLinus Torvalds 
1482*1da177e4SLinus Torvalds 		ips_chkstatus(ha, &cstatus);
1483*1da177e4SLinus Torvalds 		scb = (ips_scb_t *) sp->scb_addr;
1484*1da177e4SLinus Torvalds 
1485*1da177e4SLinus Torvalds 		/*
1486*1da177e4SLinus Torvalds 		 * use the callback function to finish things up
1487*1da177e4SLinus Torvalds 		 * NOTE: interrupts are OFF for this
1488*1da177e4SLinus Torvalds 		 */
1489*1da177e4SLinus Torvalds 		(*scb->callback) (ha, scb);
1490*1da177e4SLinus Torvalds 	}			/* end while */
1491*1da177e4SLinus Torvalds 	return 1;
1492*1da177e4SLinus Torvalds }
1493*1da177e4SLinus Torvalds 
1494*1da177e4SLinus Torvalds /****************************************************************************/
1495*1da177e4SLinus Torvalds /*                                                                          */
1496*1da177e4SLinus Torvalds /* Routine Name: ips_info                                                   */
1497*1da177e4SLinus Torvalds /*                                                                          */
1498*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1499*1da177e4SLinus Torvalds /*                                                                          */
1500*1da177e4SLinus Torvalds /*   Return info about the driver                                           */
1501*1da177e4SLinus Torvalds /*                                                                          */
1502*1da177e4SLinus Torvalds /****************************************************************************/
1503*1da177e4SLinus Torvalds static const char *
1504*1da177e4SLinus Torvalds ips_info(struct Scsi_Host *SH)
1505*1da177e4SLinus Torvalds {
1506*1da177e4SLinus Torvalds 	static char buffer[256];
1507*1da177e4SLinus Torvalds 	char *bp;
1508*1da177e4SLinus Torvalds 	ips_ha_t *ha;
1509*1da177e4SLinus Torvalds 
1510*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_info", 1);
1511*1da177e4SLinus Torvalds 
1512*1da177e4SLinus Torvalds 	ha = IPS_HA(SH);
1513*1da177e4SLinus Torvalds 
1514*1da177e4SLinus Torvalds 	if (!ha)
1515*1da177e4SLinus Torvalds 		return (NULL);
1516*1da177e4SLinus Torvalds 
1517*1da177e4SLinus Torvalds 	bp = &buffer[0];
1518*1da177e4SLinus Torvalds 	memset(bp, 0, sizeof (buffer));
1519*1da177e4SLinus Torvalds 
1520*1da177e4SLinus Torvalds 	sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ",
1521*1da177e4SLinus Torvalds 		IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT);
1522*1da177e4SLinus Torvalds 
1523*1da177e4SLinus Torvalds 	if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) {
1524*1da177e4SLinus Torvalds 		strcat(bp, " <");
1525*1da177e4SLinus Torvalds 		strcat(bp, ips_adapter_name[ha->ad_type - 1]);
1526*1da177e4SLinus Torvalds 		strcat(bp, ">");
1527*1da177e4SLinus Torvalds 	}
1528*1da177e4SLinus Torvalds 
1529*1da177e4SLinus Torvalds 	return (bp);
1530*1da177e4SLinus Torvalds }
1531*1da177e4SLinus Torvalds 
1532*1da177e4SLinus Torvalds /****************************************************************************/
1533*1da177e4SLinus Torvalds /*                                                                          */
1534*1da177e4SLinus Torvalds /* Routine Name: ips_proc_info                                              */
1535*1da177e4SLinus Torvalds /*                                                                          */
1536*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1537*1da177e4SLinus Torvalds /*                                                                          */
1538*1da177e4SLinus Torvalds /*   The passthru interface for the driver                                  */
1539*1da177e4SLinus Torvalds /*                                                                          */
1540*1da177e4SLinus Torvalds /****************************************************************************/
1541*1da177e4SLinus Torvalds static int
1542*1da177e4SLinus Torvalds ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1543*1da177e4SLinus Torvalds 	      int length, int func)
1544*1da177e4SLinus Torvalds {
1545*1da177e4SLinus Torvalds 	int i;
1546*1da177e4SLinus Torvalds 	int ret;
1547*1da177e4SLinus Torvalds 	ips_ha_t *ha = NULL;
1548*1da177e4SLinus Torvalds 
1549*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_proc_info", 1);
1550*1da177e4SLinus Torvalds 
1551*1da177e4SLinus Torvalds 	/* Find our host structure */
1552*1da177e4SLinus Torvalds 	for (i = 0; i < ips_next_controller; i++) {
1553*1da177e4SLinus Torvalds 		if (ips_sh[i]) {
1554*1da177e4SLinus Torvalds 			if (ips_sh[i] == host) {
1555*1da177e4SLinus Torvalds 				ha = (ips_ha_t *) ips_sh[i]->hostdata;
1556*1da177e4SLinus Torvalds 				break;
1557*1da177e4SLinus Torvalds 			}
1558*1da177e4SLinus Torvalds 		}
1559*1da177e4SLinus Torvalds 	}
1560*1da177e4SLinus Torvalds 
1561*1da177e4SLinus Torvalds 	if (!ha)
1562*1da177e4SLinus Torvalds 		return (-EINVAL);
1563*1da177e4SLinus Torvalds 
1564*1da177e4SLinus Torvalds 	if (func) {
1565*1da177e4SLinus Torvalds 		/* write */
1566*1da177e4SLinus Torvalds 		return (0);
1567*1da177e4SLinus Torvalds 	} else {
1568*1da177e4SLinus Torvalds 		/* read */
1569*1da177e4SLinus Torvalds 		if (start)
1570*1da177e4SLinus Torvalds 			*start = buffer;
1571*1da177e4SLinus Torvalds 
1572*1da177e4SLinus Torvalds 		ret = ips_host_info(ha, buffer, offset, length);
1573*1da177e4SLinus Torvalds 
1574*1da177e4SLinus Torvalds 		return (ret);
1575*1da177e4SLinus Torvalds 	}
1576*1da177e4SLinus Torvalds }
1577*1da177e4SLinus Torvalds 
1578*1da177e4SLinus Torvalds /*--------------------------------------------------------------------------*/
1579*1da177e4SLinus Torvalds /* Helper Functions                                                         */
1580*1da177e4SLinus Torvalds /*--------------------------------------------------------------------------*/
1581*1da177e4SLinus Torvalds 
1582*1da177e4SLinus Torvalds /****************************************************************************/
1583*1da177e4SLinus Torvalds /*                                                                          */
1584*1da177e4SLinus Torvalds /* Routine Name: ips_is_passthru                                            */
1585*1da177e4SLinus Torvalds /*                                                                          */
1586*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1587*1da177e4SLinus Torvalds /*                                                                          */
1588*1da177e4SLinus Torvalds /*   Determine if the specified SCSI command is really a passthru command   */
1589*1da177e4SLinus Torvalds /*                                                                          */
1590*1da177e4SLinus Torvalds /****************************************************************************/
1591*1da177e4SLinus Torvalds static int
1592*1da177e4SLinus Torvalds ips_is_passthru(Scsi_Cmnd * SC)
1593*1da177e4SLinus Torvalds {
1594*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_is_passthru", 1);
1595*1da177e4SLinus Torvalds 
1596*1da177e4SLinus Torvalds 	if (!SC)
1597*1da177e4SLinus Torvalds 		return (0);
1598*1da177e4SLinus Torvalds 
1599*1da177e4SLinus Torvalds 	if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
1600*1da177e4SLinus Torvalds 	    (SC->device->channel == 0) &&
1601*1da177e4SLinus Torvalds 	    (SC->device->id == IPS_ADAPTER_ID) &&
1602*1da177e4SLinus Torvalds 	    (SC->device->lun == 0) && SC->request_buffer) {
1603*1da177e4SLinus Torvalds 		if ((!SC->use_sg) && SC->request_bufflen &&
1604*1da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[0] == 'C') &&
1605*1da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[1] == 'O') &&
1606*1da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[2] == 'P') &&
1607*1da177e4SLinus Torvalds 		    (((char *) SC->request_buffer)[3] == 'P'))
1608*1da177e4SLinus Torvalds 			return 1;
1609*1da177e4SLinus Torvalds 		else if (SC->use_sg) {
1610*1da177e4SLinus Torvalds 			struct scatterlist *sg = SC->request_buffer;
1611*1da177e4SLinus Torvalds 			char *buffer = IPS_SG_ADDRESS(sg);
1612*1da177e4SLinus Torvalds 			if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
1613*1da177e4SLinus Torvalds 			    buffer[2] == 'P' && buffer[3] == 'P')
1614*1da177e4SLinus Torvalds 				return 1;
1615*1da177e4SLinus Torvalds 		}
1616*1da177e4SLinus Torvalds 	}
1617*1da177e4SLinus Torvalds 	return 0;
1618*1da177e4SLinus Torvalds }
1619*1da177e4SLinus Torvalds 
1620*1da177e4SLinus Torvalds /****************************************************************************/
1621*1da177e4SLinus Torvalds /*                                                                          */
1622*1da177e4SLinus Torvalds /* Routine Name: ips_alloc_passthru_buffer                                  */
1623*1da177e4SLinus Torvalds /*                                                                          */
1624*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1625*1da177e4SLinus Torvalds /*   allocate a buffer large enough for the ioctl data if the ioctl buffer  */
1626*1da177e4SLinus Torvalds /*   is too small or doesn't exist                                          */
1627*1da177e4SLinus Torvalds /****************************************************************************/
1628*1da177e4SLinus Torvalds static int
1629*1da177e4SLinus Torvalds ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
1630*1da177e4SLinus Torvalds {
1631*1da177e4SLinus Torvalds 	void *bigger_buf;
1632*1da177e4SLinus Torvalds 	dma_addr_t dma_busaddr;
1633*1da177e4SLinus Torvalds 
1634*1da177e4SLinus Torvalds 	if (ha->ioctl_data && length <= ha->ioctl_len)
1635*1da177e4SLinus Torvalds 		return 0;
1636*1da177e4SLinus Torvalds 	/* there is no buffer or it's not big enough, allocate a new one */
1637*1da177e4SLinus Torvalds 	bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr);
1638*1da177e4SLinus Torvalds 	if (bigger_buf) {
1639*1da177e4SLinus Torvalds 		/* free the old memory */
1640*1da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data,
1641*1da177e4SLinus Torvalds 				    ha->ioctl_busaddr);
1642*1da177e4SLinus Torvalds 		/* use the new memory */
1643*1da177e4SLinus Torvalds 		ha->ioctl_data = (char *) bigger_buf;
1644*1da177e4SLinus Torvalds 		ha->ioctl_len = length;
1645*1da177e4SLinus Torvalds 		ha->ioctl_busaddr = dma_busaddr;
1646*1da177e4SLinus Torvalds 	} else {
1647*1da177e4SLinus Torvalds 		return -1;
1648*1da177e4SLinus Torvalds 	}
1649*1da177e4SLinus Torvalds 	return 0;
1650*1da177e4SLinus Torvalds }
1651*1da177e4SLinus Torvalds 
1652*1da177e4SLinus Torvalds /****************************************************************************/
1653*1da177e4SLinus Torvalds /*                                                                          */
1654*1da177e4SLinus Torvalds /* Routine Name: ips_make_passthru                                          */
1655*1da177e4SLinus Torvalds /*                                                                          */
1656*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1657*1da177e4SLinus Torvalds /*                                                                          */
1658*1da177e4SLinus Torvalds /*   Make a passthru command out of the info in the Scsi block              */
1659*1da177e4SLinus Torvalds /*                                                                          */
1660*1da177e4SLinus Torvalds /****************************************************************************/
1661*1da177e4SLinus Torvalds static int
1662*1da177e4SLinus Torvalds ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
1663*1da177e4SLinus Torvalds {
1664*1da177e4SLinus Torvalds 	ips_passthru_t *pt;
1665*1da177e4SLinus Torvalds 	int length = 0;
1666*1da177e4SLinus Torvalds 	int ret;
1667*1da177e4SLinus Torvalds 
1668*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_make_passthru", 1);
1669*1da177e4SLinus Torvalds 
1670*1da177e4SLinus Torvalds 	if (!SC->use_sg) {
1671*1da177e4SLinus Torvalds 		length = SC->request_bufflen;
1672*1da177e4SLinus Torvalds 	} else {
1673*1da177e4SLinus Torvalds 		struct scatterlist *sg = SC->request_buffer;
1674*1da177e4SLinus Torvalds 		int i;
1675*1da177e4SLinus Torvalds 		for (i = 0; i < SC->use_sg; i++)
1676*1da177e4SLinus Torvalds 			length += sg[i].length;
1677*1da177e4SLinus Torvalds 	}
1678*1da177e4SLinus Torvalds 	if (length < sizeof (ips_passthru_t)) {
1679*1da177e4SLinus Torvalds 		/* wrong size */
1680*1da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
1681*1da177e4SLinus Torvalds 			  ips_name, ha->host_num);
1682*1da177e4SLinus Torvalds 		return (IPS_FAILURE);
1683*1da177e4SLinus Torvalds 	}
1684*1da177e4SLinus Torvalds 	if (ips_alloc_passthru_buffer(ha, length)) {
1685*1da177e4SLinus Torvalds 		/* allocation failure!  If ha->ioctl_data exists, use it to return
1686*1da177e4SLinus Torvalds 		   some error codes.  Return a failed command to the scsi layer. */
1687*1da177e4SLinus Torvalds 		if (ha->ioctl_data) {
1688*1da177e4SLinus Torvalds 			pt = (ips_passthru_t *) ha->ioctl_data;
1689*1da177e4SLinus Torvalds 			ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t));
1690*1da177e4SLinus Torvalds 			pt->BasicStatus = 0x0B;
1691*1da177e4SLinus Torvalds 			pt->ExtendedStatus = 0x00;
1692*1da177e4SLinus Torvalds 			ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t));
1693*1da177e4SLinus Torvalds 		}
1694*1da177e4SLinus Torvalds 		return IPS_FAILURE;
1695*1da177e4SLinus Torvalds 	}
1696*1da177e4SLinus Torvalds 	ha->ioctl_datasize = length;
1697*1da177e4SLinus Torvalds 
1698*1da177e4SLinus Torvalds 	ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize);
1699*1da177e4SLinus Torvalds 	pt = (ips_passthru_t *) ha->ioctl_data;
1700*1da177e4SLinus Torvalds 
1701*1da177e4SLinus Torvalds 	/*
1702*1da177e4SLinus Torvalds 	 * Some notes about the passthru interface used
1703*1da177e4SLinus Torvalds 	 *
1704*1da177e4SLinus Torvalds 	 * IF the scsi op_code == 0x0d then we assume
1705*1da177e4SLinus Torvalds 	 * that the data came along with/goes with the
1706*1da177e4SLinus Torvalds 	 * packet we received from the sg driver. In this
1707*1da177e4SLinus Torvalds 	 * case the CmdBSize field of the pt structure is
1708*1da177e4SLinus Torvalds 	 * used for the size of the buffer.
1709*1da177e4SLinus Torvalds 	 */
1710*1da177e4SLinus Torvalds 
1711*1da177e4SLinus Torvalds 	switch (pt->CoppCmd) {
1712*1da177e4SLinus Torvalds 	case IPS_NUMCTRLS:
1713*1da177e4SLinus Torvalds 		memcpy(ha->ioctl_data + sizeof (ips_passthru_t),
1714*1da177e4SLinus Torvalds 		       &ips_num_controllers, sizeof (int));
1715*1da177e4SLinus Torvalds 		ips_scmd_buf_write(SC, ha->ioctl_data,
1716*1da177e4SLinus Torvalds 				   sizeof (ips_passthru_t) + sizeof (int));
1717*1da177e4SLinus Torvalds 		SC->result = DID_OK << 16;
1718*1da177e4SLinus Torvalds 
1719*1da177e4SLinus Torvalds 		return (IPS_SUCCESS_IMM);
1720*1da177e4SLinus Torvalds 
1721*1da177e4SLinus Torvalds 	case IPS_COPPUSRCMD:
1722*1da177e4SLinus Torvalds 	case IPS_COPPIOCCMD:
1723*1da177e4SLinus Torvalds 		if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
1724*1da177e4SLinus Torvalds 			if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) {
1725*1da177e4SLinus Torvalds 				/* wrong size */
1726*1da177e4SLinus Torvalds 				DEBUG_VAR(1,
1727*1da177e4SLinus Torvalds 					  "(%s%d) Passthru structure wrong size",
1728*1da177e4SLinus Torvalds 					  ips_name, ha->host_num);
1729*1da177e4SLinus Torvalds 
1730*1da177e4SLinus Torvalds 				return (IPS_FAILURE);
1731*1da177e4SLinus Torvalds 			}
1732*1da177e4SLinus Torvalds 
1733*1da177e4SLinus Torvalds 			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
1734*1da177e4SLinus Torvalds 			    pt->CoppCP.cmd.flashfw.op_code ==
1735*1da177e4SLinus Torvalds 			    IPS_CMD_RW_BIOSFW) {
1736*1da177e4SLinus Torvalds 				ret = ips_flash_copperhead(ha, pt, scb);
1737*1da177e4SLinus Torvalds 				ips_scmd_buf_write(SC, ha->ioctl_data,
1738*1da177e4SLinus Torvalds 						   sizeof (ips_passthru_t));
1739*1da177e4SLinus Torvalds 				return ret;
1740*1da177e4SLinus Torvalds 			}
1741*1da177e4SLinus Torvalds 			if (ips_usrcmd(ha, pt, scb))
1742*1da177e4SLinus Torvalds 				return (IPS_SUCCESS);
1743*1da177e4SLinus Torvalds 			else
1744*1da177e4SLinus Torvalds 				return (IPS_FAILURE);
1745*1da177e4SLinus Torvalds 		}
1746*1da177e4SLinus Torvalds 
1747*1da177e4SLinus Torvalds 		break;
1748*1da177e4SLinus Torvalds 
1749*1da177e4SLinus Torvalds 	}			/* end switch */
1750*1da177e4SLinus Torvalds 
1751*1da177e4SLinus Torvalds 	return (IPS_FAILURE);
1752*1da177e4SLinus Torvalds }
1753*1da177e4SLinus Torvalds 
1754*1da177e4SLinus Torvalds /****************************************************************************/
1755*1da177e4SLinus Torvalds /* Routine Name: ips_flash_copperhead                                       */
1756*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1757*1da177e4SLinus Torvalds /*   Flash the BIOS/FW on a Copperhead style controller                     */
1758*1da177e4SLinus Torvalds /****************************************************************************/
1759*1da177e4SLinus Torvalds static int
1760*1da177e4SLinus Torvalds ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1761*1da177e4SLinus Torvalds {
1762*1da177e4SLinus Torvalds 	int datasize;
1763*1da177e4SLinus Torvalds 
1764*1da177e4SLinus Torvalds 	/* Trombone is the only copperhead that can do packet flash, but only
1765*1da177e4SLinus Torvalds 	 * for firmware. No one said it had to make sence. */
1766*1da177e4SLinus Torvalds 	if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) {
1767*1da177e4SLinus Torvalds 		if (ips_usrcmd(ha, pt, scb))
1768*1da177e4SLinus Torvalds 			return IPS_SUCCESS;
1769*1da177e4SLinus Torvalds 		else
1770*1da177e4SLinus Torvalds 			return IPS_FAILURE;
1771*1da177e4SLinus Torvalds 	}
1772*1da177e4SLinus Torvalds 	pt->BasicStatus = 0x0B;
1773*1da177e4SLinus Torvalds 	pt->ExtendedStatus = 0;
1774*1da177e4SLinus Torvalds 	scb->scsi_cmd->result = DID_OK << 16;
1775*1da177e4SLinus Torvalds 	/* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
1776*1da177e4SLinus Torvalds 	/* avoid allocating a huge buffer per adapter ( which can fail ). */
1777*1da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
1778*1da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
1779*1da177e4SLinus Torvalds 		pt->BasicStatus = 0;
1780*1da177e4SLinus Torvalds 		return ips_flash_bios(ha, pt, scb);
1781*1da177e4SLinus Torvalds 	} else if (pt->CoppCP.cmd.flashfw.packet_num == 0) {
1782*1da177e4SLinus Torvalds 		if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){
1783*1da177e4SLinus Torvalds 			ha->flash_data = ips_FlashData;
1784*1da177e4SLinus Torvalds 			ha->flash_busaddr = ips_flashbusaddr;
1785*1da177e4SLinus Torvalds 			ha->flash_len = PAGE_SIZE << 7;
1786*1da177e4SLinus Torvalds 			ha->flash_datasize = 0;
1787*1da177e4SLinus Torvalds 		} else if (!ha->flash_data) {
1788*1da177e4SLinus Torvalds 			datasize = pt->CoppCP.cmd.flashfw.total_packets *
1789*1da177e4SLinus Torvalds 			    pt->CoppCP.cmd.flashfw.count;
1790*1da177e4SLinus Torvalds 			ha->flash_data = pci_alloc_consistent(ha->pcidev,
1791*1da177e4SLinus Torvalds 					                      datasize,
1792*1da177e4SLinus Torvalds 							      &ha->flash_busaddr);
1793*1da177e4SLinus Torvalds 			if (!ha->flash_data){
1794*1da177e4SLinus Torvalds 				printk(KERN_WARNING "Unable to allocate a flash buffer\n");
1795*1da177e4SLinus Torvalds 				return IPS_FAILURE;
1796*1da177e4SLinus Torvalds 			}
1797*1da177e4SLinus Torvalds 			ha->flash_datasize = 0;
1798*1da177e4SLinus Torvalds 			ha->flash_len = datasize;
1799*1da177e4SLinus Torvalds 		} else
1800*1da177e4SLinus Torvalds 			return IPS_FAILURE;
1801*1da177e4SLinus Torvalds 	} else {
1802*1da177e4SLinus Torvalds 		if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
1803*1da177e4SLinus Torvalds 		    ha->flash_len) {
1804*1da177e4SLinus Torvalds 			ips_free_flash_copperhead(ha);
1805*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
1806*1da177e4SLinus Torvalds 				   "failed size sanity check\n");
1807*1da177e4SLinus Torvalds 			return IPS_FAILURE;
1808*1da177e4SLinus Torvalds 		}
1809*1da177e4SLinus Torvalds 	}
1810*1da177e4SLinus Torvalds 	if (!ha->flash_data)
1811*1da177e4SLinus Torvalds 		return IPS_FAILURE;
1812*1da177e4SLinus Torvalds 	pt->BasicStatus = 0;
1813*1da177e4SLinus Torvalds 	memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
1814*1da177e4SLinus Torvalds 	       pt->CoppCP.cmd.flashfw.count);
1815*1da177e4SLinus Torvalds 	ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
1816*1da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.packet_num ==
1817*1da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.total_packets - 1) {
1818*1da177e4SLinus Torvalds 		if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
1819*1da177e4SLinus Torvalds 			return ips_flash_bios(ha, pt, scb);
1820*1da177e4SLinus Torvalds 		else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
1821*1da177e4SLinus Torvalds 			return ips_flash_firmware(ha, pt, scb);
1822*1da177e4SLinus Torvalds 	}
1823*1da177e4SLinus Torvalds 	return IPS_SUCCESS_IMM;
1824*1da177e4SLinus Torvalds }
1825*1da177e4SLinus Torvalds 
1826*1da177e4SLinus Torvalds /****************************************************************************/
1827*1da177e4SLinus Torvalds /* Routine Name: ips_flash_bios                                             */
1828*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1829*1da177e4SLinus Torvalds /*   flashes the bios of a copperhead adapter                               */
1830*1da177e4SLinus Torvalds /****************************************************************************/
1831*1da177e4SLinus Torvalds static int
1832*1da177e4SLinus Torvalds ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1833*1da177e4SLinus Torvalds {
1834*1da177e4SLinus Torvalds 
1835*1da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
1836*1da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) {
1837*1da177e4SLinus Torvalds 		if ((!ha->func.programbios) || (!ha->func.erasebios) ||
1838*1da177e4SLinus Torvalds 		    (!ha->func.verifybios))
1839*1da177e4SLinus Torvalds 			goto error;
1840*1da177e4SLinus Torvalds 		if ((*ha->func.erasebios) (ha)) {
1841*1da177e4SLinus Torvalds 			DEBUG_VAR(1,
1842*1da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to erase flash",
1843*1da177e4SLinus Torvalds 				  ips_name, ha->host_num);
1844*1da177e4SLinus Torvalds 			goto error;
1845*1da177e4SLinus Torvalds 		} else
1846*1da177e4SLinus Torvalds 		    if ((*ha->func.programbios) (ha,
1847*1da177e4SLinus Torvalds 						 ha->flash_data +
1848*1da177e4SLinus Torvalds 						 IPS_BIOS_HEADER,
1849*1da177e4SLinus Torvalds 						 ha->flash_datasize -
1850*1da177e4SLinus Torvalds 						 IPS_BIOS_HEADER, 0)) {
1851*1da177e4SLinus Torvalds 			DEBUG_VAR(1,
1852*1da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to flash",
1853*1da177e4SLinus Torvalds 				  ips_name, ha->host_num);
1854*1da177e4SLinus Torvalds 			goto error;
1855*1da177e4SLinus Torvalds 		} else
1856*1da177e4SLinus Torvalds 		    if ((*ha->func.verifybios) (ha,
1857*1da177e4SLinus Torvalds 						ha->flash_data +
1858*1da177e4SLinus Torvalds 						IPS_BIOS_HEADER,
1859*1da177e4SLinus Torvalds 						ha->flash_datasize -
1860*1da177e4SLinus Torvalds 						IPS_BIOS_HEADER, 0)) {
1861*1da177e4SLinus Torvalds 			DEBUG_VAR(1,
1862*1da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to verify flash",
1863*1da177e4SLinus Torvalds 				  ips_name, ha->host_num);
1864*1da177e4SLinus Torvalds 			goto error;
1865*1da177e4SLinus Torvalds 		}
1866*1da177e4SLinus Torvalds 		ips_free_flash_copperhead(ha);
1867*1da177e4SLinus Torvalds 		return IPS_SUCCESS_IMM;
1868*1da177e4SLinus Torvalds 	} else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
1869*1da177e4SLinus Torvalds 		   pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
1870*1da177e4SLinus Torvalds 		if (!ha->func.erasebios)
1871*1da177e4SLinus Torvalds 			goto error;
1872*1da177e4SLinus Torvalds 		if ((*ha->func.erasebios) (ha)) {
1873*1da177e4SLinus Torvalds 			DEBUG_VAR(1,
1874*1da177e4SLinus Torvalds 				  "(%s%d) flash bios failed - unable to erase flash",
1875*1da177e4SLinus Torvalds 				  ips_name, ha->host_num);
1876*1da177e4SLinus Torvalds 			goto error;
1877*1da177e4SLinus Torvalds 		}
1878*1da177e4SLinus Torvalds 		return IPS_SUCCESS_IMM;
1879*1da177e4SLinus Torvalds 	}
1880*1da177e4SLinus Torvalds       error:
1881*1da177e4SLinus Torvalds 	pt->BasicStatus = 0x0B;
1882*1da177e4SLinus Torvalds 	pt->ExtendedStatus = 0x00;
1883*1da177e4SLinus Torvalds 	ips_free_flash_copperhead(ha);
1884*1da177e4SLinus Torvalds 	return IPS_FAILURE;
1885*1da177e4SLinus Torvalds }
1886*1da177e4SLinus Torvalds 
1887*1da177e4SLinus Torvalds /****************************************************************************/
1888*1da177e4SLinus Torvalds /*                                                                          */
1889*1da177e4SLinus Torvalds /* Routine Name: ips_fill_scb_sg_single                                     */
1890*1da177e4SLinus Torvalds /*                                                                          */
1891*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1892*1da177e4SLinus Torvalds /*   Fill in a single scb sg_list element from an address                   */
1893*1da177e4SLinus Torvalds /*   return a -1 if a breakup occurred                                      */
1894*1da177e4SLinus Torvalds /****************************************************************************/
1895*1da177e4SLinus Torvalds static int
1896*1da177e4SLinus Torvalds ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
1897*1da177e4SLinus Torvalds 		       ips_scb_t * scb, int indx, unsigned int e_len)
1898*1da177e4SLinus Torvalds {
1899*1da177e4SLinus Torvalds 
1900*1da177e4SLinus Torvalds 	int ret_val = 0;
1901*1da177e4SLinus Torvalds 
1902*1da177e4SLinus Torvalds 	if ((scb->data_len + e_len) > ha->max_xfer) {
1903*1da177e4SLinus Torvalds 		e_len = ha->max_xfer - scb->data_len;
1904*1da177e4SLinus Torvalds 		scb->breakup = indx;
1905*1da177e4SLinus Torvalds 		++scb->sg_break;
1906*1da177e4SLinus Torvalds 		ret_val = -1;
1907*1da177e4SLinus Torvalds 	} else {
1908*1da177e4SLinus Torvalds 		scb->breakup = 0;
1909*1da177e4SLinus Torvalds 		scb->sg_break = 0;
1910*1da177e4SLinus Torvalds 	}
1911*1da177e4SLinus Torvalds 	if (IPS_USE_ENH_SGLIST(ha)) {
1912*1da177e4SLinus Torvalds 		scb->sg_list.enh_list[indx].address_lo =
1913*1da177e4SLinus Torvalds 		    cpu_to_le32(pci_dma_lo32(busaddr));
1914*1da177e4SLinus Torvalds 		scb->sg_list.enh_list[indx].address_hi =
1915*1da177e4SLinus Torvalds 		    cpu_to_le32(pci_dma_hi32(busaddr));
1916*1da177e4SLinus Torvalds 		scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len);
1917*1da177e4SLinus Torvalds 	} else {
1918*1da177e4SLinus Torvalds 		scb->sg_list.std_list[indx].address =
1919*1da177e4SLinus Torvalds 		    cpu_to_le32(pci_dma_lo32(busaddr));
1920*1da177e4SLinus Torvalds 		scb->sg_list.std_list[indx].length = cpu_to_le32(e_len);
1921*1da177e4SLinus Torvalds 	}
1922*1da177e4SLinus Torvalds 
1923*1da177e4SLinus Torvalds 	++scb->sg_len;
1924*1da177e4SLinus Torvalds 	scb->data_len += e_len;
1925*1da177e4SLinus Torvalds 	return ret_val;
1926*1da177e4SLinus Torvalds }
1927*1da177e4SLinus Torvalds 
1928*1da177e4SLinus Torvalds /****************************************************************************/
1929*1da177e4SLinus Torvalds /* Routine Name: ips_flash_firmware                                         */
1930*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1931*1da177e4SLinus Torvalds /*   flashes the firmware of a copperhead adapter                           */
1932*1da177e4SLinus Torvalds /****************************************************************************/
1933*1da177e4SLinus Torvalds static int
1934*1da177e4SLinus Torvalds ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1935*1da177e4SLinus Torvalds {
1936*1da177e4SLinus Torvalds 	IPS_SG_LIST sg_list;
1937*1da177e4SLinus Torvalds 	uint32_t cmd_busaddr;
1938*1da177e4SLinus Torvalds 
1939*1da177e4SLinus Torvalds 	if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
1940*1da177e4SLinus Torvalds 	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) {
1941*1da177e4SLinus Torvalds 		memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND));
1942*1da177e4SLinus Torvalds 		pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
1943*1da177e4SLinus Torvalds 		pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
1944*1da177e4SLinus Torvalds 	} else {
1945*1da177e4SLinus Torvalds 		pt->BasicStatus = 0x0B;
1946*1da177e4SLinus Torvalds 		pt->ExtendedStatus = 0x00;
1947*1da177e4SLinus Torvalds 		ips_free_flash_copperhead(ha);
1948*1da177e4SLinus Torvalds 		return IPS_FAILURE;
1949*1da177e4SLinus Torvalds 	}
1950*1da177e4SLinus Torvalds 	/* Save the S/G list pointer so it doesn't get clobbered */
1951*1da177e4SLinus Torvalds 	sg_list.list = scb->sg_list.list;
1952*1da177e4SLinus Torvalds 	cmd_busaddr = scb->scb_busaddr;
1953*1da177e4SLinus Torvalds 	/* copy in the CP */
1954*1da177e4SLinus Torvalds 	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
1955*1da177e4SLinus Torvalds 	/* FIX stuff that might be wrong */
1956*1da177e4SLinus Torvalds 	scb->sg_list.list = sg_list.list;
1957*1da177e4SLinus Torvalds 	scb->scb_busaddr = cmd_busaddr;
1958*1da177e4SLinus Torvalds 	scb->bus = scb->scsi_cmd->device->channel;
1959*1da177e4SLinus Torvalds 	scb->target_id = scb->scsi_cmd->device->id;
1960*1da177e4SLinus Torvalds 	scb->lun = scb->scsi_cmd->device->lun;
1961*1da177e4SLinus Torvalds 	scb->sg_len = 0;
1962*1da177e4SLinus Torvalds 	scb->data_len = 0;
1963*1da177e4SLinus Torvalds 	scb->flags = 0;
1964*1da177e4SLinus Torvalds 	scb->op_code = 0;
1965*1da177e4SLinus Torvalds 	scb->callback = ipsintr_done;
1966*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
1967*1da177e4SLinus Torvalds 
1968*1da177e4SLinus Torvalds 	scb->data_len = ha->flash_datasize;
1969*1da177e4SLinus Torvalds 	scb->data_busaddr =
1970*1da177e4SLinus Torvalds 	    pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
1971*1da177e4SLinus Torvalds 			   IPS_DMA_DIR(scb));
1972*1da177e4SLinus Torvalds 	scb->flags |= IPS_SCB_MAP_SINGLE;
1973*1da177e4SLinus Torvalds 	scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
1974*1da177e4SLinus Torvalds 	scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr);
1975*1da177e4SLinus Torvalds 	if (pt->TimeOut)
1976*1da177e4SLinus Torvalds 		scb->timeout = pt->TimeOut;
1977*1da177e4SLinus Torvalds 	scb->scsi_cmd->result = DID_OK << 16;
1978*1da177e4SLinus Torvalds 	return IPS_SUCCESS;
1979*1da177e4SLinus Torvalds }
1980*1da177e4SLinus Torvalds 
1981*1da177e4SLinus Torvalds /****************************************************************************/
1982*1da177e4SLinus Torvalds /* Routine Name: ips_free_flash_copperhead                                  */
1983*1da177e4SLinus Torvalds /* Routine Description:                                                     */
1984*1da177e4SLinus Torvalds /*   release the memory resources used to hold the flash image              */
1985*1da177e4SLinus Torvalds /****************************************************************************/
1986*1da177e4SLinus Torvalds static void
1987*1da177e4SLinus Torvalds ips_free_flash_copperhead(ips_ha_t * ha)
1988*1da177e4SLinus Torvalds {
1989*1da177e4SLinus Torvalds 	if (ha->flash_data == ips_FlashData)
1990*1da177e4SLinus Torvalds 		test_and_clear_bit(0, &ips_FlashDataInUse);
1991*1da177e4SLinus Torvalds 	else if (ha->flash_data)
1992*1da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data,
1993*1da177e4SLinus Torvalds 				    ha->flash_busaddr);
1994*1da177e4SLinus Torvalds 	ha->flash_data = NULL;
1995*1da177e4SLinus Torvalds }
1996*1da177e4SLinus Torvalds 
1997*1da177e4SLinus Torvalds /****************************************************************************/
1998*1da177e4SLinus Torvalds /*                                                                          */
1999*1da177e4SLinus Torvalds /* Routine Name: ips_usrcmd                                                 */
2000*1da177e4SLinus Torvalds /*                                                                          */
2001*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2002*1da177e4SLinus Torvalds /*                                                                          */
2003*1da177e4SLinus Torvalds /*   Process a user command and make it ready to send                       */
2004*1da177e4SLinus Torvalds /*                                                                          */
2005*1da177e4SLinus Torvalds /****************************************************************************/
2006*1da177e4SLinus Torvalds static int
2007*1da177e4SLinus Torvalds ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
2008*1da177e4SLinus Torvalds {
2009*1da177e4SLinus Torvalds 	IPS_SG_LIST sg_list;
2010*1da177e4SLinus Torvalds 	uint32_t cmd_busaddr;
2011*1da177e4SLinus Torvalds 
2012*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_usrcmd", 1);
2013*1da177e4SLinus Torvalds 
2014*1da177e4SLinus Torvalds 	if ((!scb) || (!pt) || (!ha))
2015*1da177e4SLinus Torvalds 		return (0);
2016*1da177e4SLinus Torvalds 
2017*1da177e4SLinus Torvalds 	/* Save the S/G list pointer so it doesn't get clobbered */
2018*1da177e4SLinus Torvalds 	sg_list.list = scb->sg_list.list;
2019*1da177e4SLinus Torvalds 	cmd_busaddr = scb->scb_busaddr;
2020*1da177e4SLinus Torvalds 	/* copy in the CP */
2021*1da177e4SLinus Torvalds 	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
2022*1da177e4SLinus Torvalds 	memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE));
2023*1da177e4SLinus Torvalds 
2024*1da177e4SLinus Torvalds 	/* FIX stuff that might be wrong */
2025*1da177e4SLinus Torvalds 	scb->sg_list.list = sg_list.list;
2026*1da177e4SLinus Torvalds 	scb->scb_busaddr = cmd_busaddr;
2027*1da177e4SLinus Torvalds 	scb->bus = scb->scsi_cmd->device->channel;
2028*1da177e4SLinus Torvalds 	scb->target_id = scb->scsi_cmd->device->id;
2029*1da177e4SLinus Torvalds 	scb->lun = scb->scsi_cmd->device->lun;
2030*1da177e4SLinus Torvalds 	scb->sg_len = 0;
2031*1da177e4SLinus Torvalds 	scb->data_len = 0;
2032*1da177e4SLinus Torvalds 	scb->flags = 0;
2033*1da177e4SLinus Torvalds 	scb->op_code = 0;
2034*1da177e4SLinus Torvalds 	scb->callback = ipsintr_done;
2035*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
2036*1da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
2037*1da177e4SLinus Torvalds 
2038*1da177e4SLinus Torvalds 	/* we don't support DCDB/READ/WRITE Scatter Gather */
2039*1da177e4SLinus Torvalds 	if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
2040*1da177e4SLinus Torvalds 	    (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
2041*1da177e4SLinus Torvalds 	    (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
2042*1da177e4SLinus Torvalds 		return (0);
2043*1da177e4SLinus Torvalds 
2044*1da177e4SLinus Torvalds 	if (pt->CmdBSize) {
2045*1da177e4SLinus Torvalds 		scb->data_len = pt->CmdBSize;
2046*1da177e4SLinus Torvalds 		scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t);
2047*1da177e4SLinus Torvalds 	} else {
2048*1da177e4SLinus Torvalds 		scb->data_busaddr = 0L;
2049*1da177e4SLinus Torvalds 	}
2050*1da177e4SLinus Torvalds 
2051*1da177e4SLinus Torvalds 	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
2052*1da177e4SLinus Torvalds 		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
2053*1da177e4SLinus Torvalds 							 (unsigned long) &scb->
2054*1da177e4SLinus Torvalds 							 dcdb -
2055*1da177e4SLinus Torvalds 							 (unsigned long) scb);
2056*1da177e4SLinus Torvalds 
2057*1da177e4SLinus Torvalds 	if (pt->CmdBSize) {
2058*1da177e4SLinus Torvalds 		if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
2059*1da177e4SLinus Torvalds 			scb->dcdb.buffer_pointer =
2060*1da177e4SLinus Torvalds 			    cpu_to_le32(scb->data_busaddr);
2061*1da177e4SLinus Torvalds 		else
2062*1da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_addr =
2063*1da177e4SLinus Torvalds 			    cpu_to_le32(scb->data_busaddr);
2064*1da177e4SLinus Torvalds 	}
2065*1da177e4SLinus Torvalds 
2066*1da177e4SLinus Torvalds 	/* set timeouts */
2067*1da177e4SLinus Torvalds 	if (pt->TimeOut) {
2068*1da177e4SLinus Torvalds 		scb->timeout = pt->TimeOut;
2069*1da177e4SLinus Torvalds 
2070*1da177e4SLinus Torvalds 		if (pt->TimeOut <= 10)
2071*1da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
2072*1da177e4SLinus Torvalds 		else if (pt->TimeOut <= 60)
2073*1da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
2074*1da177e4SLinus Torvalds 		else
2075*1da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
2076*1da177e4SLinus Torvalds 	}
2077*1da177e4SLinus Torvalds 
2078*1da177e4SLinus Torvalds 	/* assume success */
2079*1da177e4SLinus Torvalds 	scb->scsi_cmd->result = DID_OK << 16;
2080*1da177e4SLinus Torvalds 
2081*1da177e4SLinus Torvalds 	/* success */
2082*1da177e4SLinus Torvalds 	return (1);
2083*1da177e4SLinus Torvalds }
2084*1da177e4SLinus Torvalds 
2085*1da177e4SLinus Torvalds /****************************************************************************/
2086*1da177e4SLinus Torvalds /*                                                                          */
2087*1da177e4SLinus Torvalds /* Routine Name: ips_cleanup_passthru                                       */
2088*1da177e4SLinus Torvalds /*                                                                          */
2089*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2090*1da177e4SLinus Torvalds /*                                                                          */
2091*1da177e4SLinus Torvalds /*   Cleanup after a passthru command                                       */
2092*1da177e4SLinus Torvalds /*                                                                          */
2093*1da177e4SLinus Torvalds /****************************************************************************/
2094*1da177e4SLinus Torvalds static void
2095*1da177e4SLinus Torvalds ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
2096*1da177e4SLinus Torvalds {
2097*1da177e4SLinus Torvalds 	ips_passthru_t *pt;
2098*1da177e4SLinus Torvalds 
2099*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_cleanup_passthru", 1);
2100*1da177e4SLinus Torvalds 
2101*1da177e4SLinus Torvalds 	if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
2102*1da177e4SLinus Torvalds 		DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
2103*1da177e4SLinus Torvalds 			  ips_name, ha->host_num);
2104*1da177e4SLinus Torvalds 
2105*1da177e4SLinus Torvalds 		return;
2106*1da177e4SLinus Torvalds 	}
2107*1da177e4SLinus Torvalds 	pt = (ips_passthru_t *) ha->ioctl_data;
2108*1da177e4SLinus Torvalds 
2109*1da177e4SLinus Torvalds 	/* Copy data back to the user */
2110*1da177e4SLinus Torvalds 	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)	/* Copy DCDB Back to Caller's Area */
2111*1da177e4SLinus Torvalds 		memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE));
2112*1da177e4SLinus Torvalds 
2113*1da177e4SLinus Torvalds 	pt->BasicStatus = scb->basic_status;
2114*1da177e4SLinus Torvalds 	pt->ExtendedStatus = scb->extended_status;
2115*1da177e4SLinus Torvalds 	pt->AdapterType = ha->ad_type;
2116*1da177e4SLinus Torvalds 
2117*1da177e4SLinus Torvalds 	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
2118*1da177e4SLinus Torvalds 	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
2119*1da177e4SLinus Torvalds 	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
2120*1da177e4SLinus Torvalds 		ips_free_flash_copperhead(ha);
2121*1da177e4SLinus Torvalds 
2122*1da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize);
2123*1da177e4SLinus Torvalds }
2124*1da177e4SLinus Torvalds 
2125*1da177e4SLinus Torvalds /****************************************************************************/
2126*1da177e4SLinus Torvalds /*                                                                          */
2127*1da177e4SLinus Torvalds /* Routine Name: ips_host_info                                              */
2128*1da177e4SLinus Torvalds /*                                                                          */
2129*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2130*1da177e4SLinus Torvalds /*                                                                          */
2131*1da177e4SLinus Torvalds /*   The passthru interface for the driver                                  */
2132*1da177e4SLinus Torvalds /*                                                                          */
2133*1da177e4SLinus Torvalds /****************************************************************************/
2134*1da177e4SLinus Torvalds static int
2135*1da177e4SLinus Torvalds ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
2136*1da177e4SLinus Torvalds {
2137*1da177e4SLinus Torvalds 	IPS_INFOSTR info;
2138*1da177e4SLinus Torvalds 
2139*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_host_info", 1);
2140*1da177e4SLinus Torvalds 
2141*1da177e4SLinus Torvalds 	info.buffer = ptr;
2142*1da177e4SLinus Torvalds 	info.length = len;
2143*1da177e4SLinus Torvalds 	info.offset = offset;
2144*1da177e4SLinus Torvalds 	info.pos = 0;
2145*1da177e4SLinus Torvalds 	info.localpos = 0;
2146*1da177e4SLinus Torvalds 
2147*1da177e4SLinus Torvalds 	copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
2148*1da177e4SLinus Torvalds 
2149*1da177e4SLinus Torvalds 	if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
2150*1da177e4SLinus Torvalds 	    (le16_to_cpu(ha->nvram->adapter_type) != 0))
2151*1da177e4SLinus Torvalds 		copy_info(&info, "\tController Type                   : %s\n",
2152*1da177e4SLinus Torvalds 			  ips_adapter_name[ha->ad_type - 1]);
2153*1da177e4SLinus Torvalds 	else
2154*1da177e4SLinus Torvalds 		copy_info(&info,
2155*1da177e4SLinus Torvalds 			  "\tController Type                   : Unknown\n");
2156*1da177e4SLinus Torvalds 
2157*1da177e4SLinus Torvalds 	if (ha->io_addr)
2158*1da177e4SLinus Torvalds 		copy_info(&info,
2159*1da177e4SLinus Torvalds 			  "\tIO region                         : 0x%lx (%d bytes)\n",
2160*1da177e4SLinus Torvalds 			  ha->io_addr, ha->io_len);
2161*1da177e4SLinus Torvalds 
2162*1da177e4SLinus Torvalds 	if (ha->mem_addr) {
2163*1da177e4SLinus Torvalds 		copy_info(&info,
2164*1da177e4SLinus Torvalds 			  "\tMemory region                     : 0x%lx (%d bytes)\n",
2165*1da177e4SLinus Torvalds 			  ha->mem_addr, ha->mem_len);
2166*1da177e4SLinus Torvalds 		copy_info(&info,
2167*1da177e4SLinus Torvalds 			  "\tShared memory address             : 0x%lx\n",
2168*1da177e4SLinus Torvalds 			  ha->mem_ptr);
2169*1da177e4SLinus Torvalds 	}
2170*1da177e4SLinus Torvalds 
2171*1da177e4SLinus Torvalds 	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
2172*1da177e4SLinus Torvalds 
2173*1da177e4SLinus Torvalds     /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
2174*1da177e4SLinus Torvalds     /* That keeps everything happy for "text" operations on the proc file.                    */
2175*1da177e4SLinus Torvalds 
2176*1da177e4SLinus Torvalds 	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
2177*1da177e4SLinus Torvalds         if (ha->nvram->bios_low[3] == 0) {
2178*1da177e4SLinus Torvalds             copy_info(&info,
2179*1da177e4SLinus Torvalds 			          "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
2180*1da177e4SLinus Torvalds 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
2181*1da177e4SLinus Torvalds 			          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
2182*1da177e4SLinus Torvalds 			          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
2183*1da177e4SLinus Torvalds 			          ha->nvram->bios_low[2]);
2184*1da177e4SLinus Torvalds 
2185*1da177e4SLinus Torvalds         } else {
2186*1da177e4SLinus Torvalds 		    copy_info(&info,
2187*1da177e4SLinus Torvalds 			          "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n",
2188*1da177e4SLinus Torvalds 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
2189*1da177e4SLinus Torvalds 			          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
2190*1da177e4SLinus Torvalds 			          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
2191*1da177e4SLinus Torvalds 			          ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
2192*1da177e4SLinus Torvalds         }
2193*1da177e4SLinus Torvalds 
2194*1da177e4SLinus Torvalds     }
2195*1da177e4SLinus Torvalds 
2196*1da177e4SLinus Torvalds     if (ha->enq->CodeBlkVersion[7] == 0) {
2197*1da177e4SLinus Torvalds         copy_info(&info,
2198*1da177e4SLinus Torvalds 		          "\tFirmware Version                  : %c%c%c%c%c%c%c\n",
2199*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
2200*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
2201*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
2202*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[6]);
2203*1da177e4SLinus Torvalds     } else {
2204*1da177e4SLinus Torvalds         copy_info(&info,
2205*1da177e4SLinus Torvalds 		          "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n",
2206*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
2207*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
2208*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
2209*1da177e4SLinus Torvalds 		          ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
2210*1da177e4SLinus Torvalds     }
2211*1da177e4SLinus Torvalds 
2212*1da177e4SLinus Torvalds     if (ha->enq->BootBlkVersion[7] == 0) {
2213*1da177e4SLinus Torvalds         copy_info(&info,
2214*1da177e4SLinus Torvalds 		          "\tBoot Block Version                : %c%c%c%c%c%c%c\n",
2215*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
2216*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
2217*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
2218*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[6]);
2219*1da177e4SLinus Torvalds     } else {
2220*1da177e4SLinus Torvalds         copy_info(&info,
2221*1da177e4SLinus Torvalds 		          "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n",
2222*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
2223*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
2224*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
2225*1da177e4SLinus Torvalds 		          ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
2226*1da177e4SLinus Torvalds     }
2227*1da177e4SLinus Torvalds 
2228*1da177e4SLinus Torvalds 	copy_info(&info, "\tDriver Version                    : %s%s\n",
2229*1da177e4SLinus Torvalds 		  IPS_VERSION_HIGH, IPS_VERSION_LOW);
2230*1da177e4SLinus Torvalds 
2231*1da177e4SLinus Torvalds 	copy_info(&info, "\tDriver Build                      : %d\n",
2232*1da177e4SLinus Torvalds 		  IPS_BUILD_IDENT);
2233*1da177e4SLinus Torvalds 
2234*1da177e4SLinus Torvalds 	copy_info(&info, "\tMax Physical Devices              : %d\n",
2235*1da177e4SLinus Torvalds 		  ha->enq->ucMaxPhysicalDevices);
2236*1da177e4SLinus Torvalds 	copy_info(&info, "\tMax Active Commands               : %d\n",
2237*1da177e4SLinus Torvalds 		  ha->max_cmds);
2238*1da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Queued Commands           : %d\n",
2239*1da177e4SLinus Torvalds 		  ha->scb_waitlist.count);
2240*1da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Active Commands           : %d\n",
2241*1da177e4SLinus Torvalds 		  ha->scb_activelist.count - ha->num_ioctl);
2242*1da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Queued PT Commands        : %d\n",
2243*1da177e4SLinus Torvalds 		  ha->copp_waitlist.count);
2244*1da177e4SLinus Torvalds 	copy_info(&info, "\tCurrent Active PT Commands        : %d\n",
2245*1da177e4SLinus Torvalds 		  ha->num_ioctl);
2246*1da177e4SLinus Torvalds 
2247*1da177e4SLinus Torvalds 	copy_info(&info, "\n");
2248*1da177e4SLinus Torvalds 
2249*1da177e4SLinus Torvalds 	return (info.localpos);
2250*1da177e4SLinus Torvalds }
2251*1da177e4SLinus Torvalds 
2252*1da177e4SLinus Torvalds /****************************************************************************/
2253*1da177e4SLinus Torvalds /*                                                                          */
2254*1da177e4SLinus Torvalds /* Routine Name: copy_mem_info                                              */
2255*1da177e4SLinus Torvalds /*                                                                          */
2256*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2257*1da177e4SLinus Torvalds /*                                                                          */
2258*1da177e4SLinus Torvalds /*   Copy data into an IPS_INFOSTR structure                                */
2259*1da177e4SLinus Torvalds /*                                                                          */
2260*1da177e4SLinus Torvalds /****************************************************************************/
2261*1da177e4SLinus Torvalds static void
2262*1da177e4SLinus Torvalds copy_mem_info(IPS_INFOSTR * info, char *data, int len)
2263*1da177e4SLinus Torvalds {
2264*1da177e4SLinus Torvalds 	METHOD_TRACE("copy_mem_info", 1);
2265*1da177e4SLinus Torvalds 
2266*1da177e4SLinus Torvalds 	if (info->pos + len < info->offset) {
2267*1da177e4SLinus Torvalds 		info->pos += len;
2268*1da177e4SLinus Torvalds 		return;
2269*1da177e4SLinus Torvalds 	}
2270*1da177e4SLinus Torvalds 
2271*1da177e4SLinus Torvalds 	if (info->pos < info->offset) {
2272*1da177e4SLinus Torvalds 		data += (info->offset - info->pos);
2273*1da177e4SLinus Torvalds 		len -= (info->offset - info->pos);
2274*1da177e4SLinus Torvalds 		info->pos += (info->offset - info->pos);
2275*1da177e4SLinus Torvalds 	}
2276*1da177e4SLinus Torvalds 
2277*1da177e4SLinus Torvalds 	if (info->localpos + len > info->length)
2278*1da177e4SLinus Torvalds 		len = info->length - info->localpos;
2279*1da177e4SLinus Torvalds 
2280*1da177e4SLinus Torvalds 	if (len > 0) {
2281*1da177e4SLinus Torvalds 		memcpy(info->buffer + info->localpos, data, len);
2282*1da177e4SLinus Torvalds 		info->pos += len;
2283*1da177e4SLinus Torvalds 		info->localpos += len;
2284*1da177e4SLinus Torvalds 	}
2285*1da177e4SLinus Torvalds }
2286*1da177e4SLinus Torvalds 
2287*1da177e4SLinus Torvalds /****************************************************************************/
2288*1da177e4SLinus Torvalds /*                                                                          */
2289*1da177e4SLinus Torvalds /* Routine Name: copy_info                                                  */
2290*1da177e4SLinus Torvalds /*                                                                          */
2291*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2292*1da177e4SLinus Torvalds /*                                                                          */
2293*1da177e4SLinus Torvalds /*   printf style wrapper for an info structure                             */
2294*1da177e4SLinus Torvalds /*                                                                          */
2295*1da177e4SLinus Torvalds /****************************************************************************/
2296*1da177e4SLinus Torvalds static int
2297*1da177e4SLinus Torvalds copy_info(IPS_INFOSTR * info, char *fmt, ...)
2298*1da177e4SLinus Torvalds {
2299*1da177e4SLinus Torvalds 	va_list args;
2300*1da177e4SLinus Torvalds 	char buf[128];
2301*1da177e4SLinus Torvalds 	int len;
2302*1da177e4SLinus Torvalds 
2303*1da177e4SLinus Torvalds 	METHOD_TRACE("copy_info", 1);
2304*1da177e4SLinus Torvalds 
2305*1da177e4SLinus Torvalds 	va_start(args, fmt);
2306*1da177e4SLinus Torvalds 	len = vsprintf(buf, fmt, args);
2307*1da177e4SLinus Torvalds 	va_end(args);
2308*1da177e4SLinus Torvalds 
2309*1da177e4SLinus Torvalds 	copy_mem_info(info, buf, len);
2310*1da177e4SLinus Torvalds 
2311*1da177e4SLinus Torvalds 	return (len);
2312*1da177e4SLinus Torvalds }
2313*1da177e4SLinus Torvalds 
2314*1da177e4SLinus Torvalds /****************************************************************************/
2315*1da177e4SLinus Torvalds /*                                                                          */
2316*1da177e4SLinus Torvalds /* Routine Name: ips_identify_controller                                    */
2317*1da177e4SLinus Torvalds /*                                                                          */
2318*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2319*1da177e4SLinus Torvalds /*                                                                          */
2320*1da177e4SLinus Torvalds /*   Identify this controller                                               */
2321*1da177e4SLinus Torvalds /*                                                                          */
2322*1da177e4SLinus Torvalds /****************************************************************************/
2323*1da177e4SLinus Torvalds static void
2324*1da177e4SLinus Torvalds ips_identify_controller(ips_ha_t * ha)
2325*1da177e4SLinus Torvalds {
2326*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_identify_controller", 1);
2327*1da177e4SLinus Torvalds 
2328*1da177e4SLinus Torvalds 	switch (ha->device_id) {
2329*1da177e4SLinus Torvalds 	case IPS_DEVICEID_COPPERHEAD:
2330*1da177e4SLinus Torvalds 		if (ha->revision_id <= IPS_REVID_SERVERAID) {
2331*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID;
2332*1da177e4SLinus Torvalds 		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
2333*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID2;
2334*1da177e4SLinus Torvalds 		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
2335*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_NAVAJO;
2336*1da177e4SLinus Torvalds 		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
2337*1da177e4SLinus Torvalds 			   && (ha->slot_num == 0)) {
2338*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_KIOWA;
2339*1da177e4SLinus Torvalds 		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
2340*1da177e4SLinus Torvalds 			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
2341*1da177e4SLinus Torvalds 			if (ha->enq->ucMaxPhysicalDevices == 15)
2342*1da177e4SLinus Torvalds 				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
2343*1da177e4SLinus Torvalds 			else
2344*1da177e4SLinus Torvalds 				ha->ad_type = IPS_ADTYPE_SERVERAID3;
2345*1da177e4SLinus Torvalds 		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
2346*1da177e4SLinus Torvalds 			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
2347*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
2348*1da177e4SLinus Torvalds 		}
2349*1da177e4SLinus Torvalds 		break;
2350*1da177e4SLinus Torvalds 
2351*1da177e4SLinus Torvalds 	case IPS_DEVICEID_MORPHEUS:
2352*1da177e4SLinus Torvalds 		switch (ha->subdevice_id) {
2353*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4L:
2354*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
2355*1da177e4SLinus Torvalds 			break;
2356*1da177e4SLinus Torvalds 
2357*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4M:
2358*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4M;
2359*1da177e4SLinus Torvalds 			break;
2360*1da177e4SLinus Torvalds 
2361*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4MX:
2362*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
2363*1da177e4SLinus Torvalds 			break;
2364*1da177e4SLinus Torvalds 
2365*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_4LX:
2366*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
2367*1da177e4SLinus Torvalds 			break;
2368*1da177e4SLinus Torvalds 
2369*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_5I2:
2370*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
2371*1da177e4SLinus Torvalds 			break;
2372*1da177e4SLinus Torvalds 
2373*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_5I1:
2374*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
2375*1da177e4SLinus Torvalds 			break;
2376*1da177e4SLinus Torvalds 		}
2377*1da177e4SLinus Torvalds 
2378*1da177e4SLinus Torvalds 		break;
2379*1da177e4SLinus Torvalds 
2380*1da177e4SLinus Torvalds 	case IPS_DEVICEID_MARCO:
2381*1da177e4SLinus Torvalds 		switch (ha->subdevice_id) {
2382*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_6M:
2383*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
2384*1da177e4SLinus Torvalds 			break;
2385*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_6I:
2386*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID6I;
2387*1da177e4SLinus Torvalds 			break;
2388*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_7k:
2389*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID7k;
2390*1da177e4SLinus Torvalds 			break;
2391*1da177e4SLinus Torvalds 		case IPS_SUBDEVICEID_7M:
2392*1da177e4SLinus Torvalds 			ha->ad_type = IPS_ADTYPE_SERVERAID7M;
2393*1da177e4SLinus Torvalds 			break;
2394*1da177e4SLinus Torvalds 		}
2395*1da177e4SLinus Torvalds 		break;
2396*1da177e4SLinus Torvalds 	}
2397*1da177e4SLinus Torvalds }
2398*1da177e4SLinus Torvalds 
2399*1da177e4SLinus Torvalds /****************************************************************************/
2400*1da177e4SLinus Torvalds /*                                                                          */
2401*1da177e4SLinus Torvalds /* Routine Name: ips_get_bios_version                                       */
2402*1da177e4SLinus Torvalds /*                                                                          */
2403*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2404*1da177e4SLinus Torvalds /*                                                                          */
2405*1da177e4SLinus Torvalds /*   Get the BIOS revision number                                           */
2406*1da177e4SLinus Torvalds /*                                                                          */
2407*1da177e4SLinus Torvalds /****************************************************************************/
2408*1da177e4SLinus Torvalds static void
2409*1da177e4SLinus Torvalds ips_get_bios_version(ips_ha_t * ha, int intr)
2410*1da177e4SLinus Torvalds {
2411*1da177e4SLinus Torvalds 	ips_scb_t *scb;
2412*1da177e4SLinus Torvalds 	int ret;
2413*1da177e4SLinus Torvalds 	uint8_t major;
2414*1da177e4SLinus Torvalds 	uint8_t minor;
2415*1da177e4SLinus Torvalds 	uint8_t subminor;
2416*1da177e4SLinus Torvalds 	uint8_t *buffer;
2417*1da177e4SLinus Torvalds 	char hexDigits[] =
2418*1da177e4SLinus Torvalds 	    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
2419*1da177e4SLinus Torvalds      'D', 'E', 'F' };
2420*1da177e4SLinus Torvalds 
2421*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_get_bios_version", 1);
2422*1da177e4SLinus Torvalds 
2423*1da177e4SLinus Torvalds 	major = 0;
2424*1da177e4SLinus Torvalds 	minor = 0;
2425*1da177e4SLinus Torvalds 
2426*1da177e4SLinus Torvalds 	strncpy(ha->bios_version, "       ?", 8);
2427*1da177e4SLinus Torvalds 
2428*1da177e4SLinus Torvalds 	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
2429*1da177e4SLinus Torvalds 		if (IPS_USE_MEMIO(ha)) {
2430*1da177e4SLinus Torvalds 			/* Memory Mapped I/O */
2431*1da177e4SLinus Torvalds 
2432*1da177e4SLinus Torvalds 			/* test 1st byte */
2433*1da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
2434*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2435*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2436*1da177e4SLinus Torvalds 
2437*1da177e4SLinus Torvalds 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
2438*1da177e4SLinus Torvalds 				return;
2439*1da177e4SLinus Torvalds 
2440*1da177e4SLinus Torvalds 			writel(1, ha->mem_ptr + IPS_REG_FLAP);
2441*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2442*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2443*1da177e4SLinus Torvalds 
2444*1da177e4SLinus Torvalds 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
2445*1da177e4SLinus Torvalds 				return;
2446*1da177e4SLinus Torvalds 
2447*1da177e4SLinus Torvalds 			/* Get Major version */
2448*1da177e4SLinus Torvalds 			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
2449*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2450*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2451*1da177e4SLinus Torvalds 
2452*1da177e4SLinus Torvalds 			major = readb(ha->mem_ptr + IPS_REG_FLDP);
2453*1da177e4SLinus Torvalds 
2454*1da177e4SLinus Torvalds 			/* Get Minor version */
2455*1da177e4SLinus Torvalds 			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
2456*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2457*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2458*1da177e4SLinus Torvalds 			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
2459*1da177e4SLinus Torvalds 
2460*1da177e4SLinus Torvalds 			/* Get SubMinor version */
2461*1da177e4SLinus Torvalds 			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
2462*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2463*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2464*1da177e4SLinus Torvalds 			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
2465*1da177e4SLinus Torvalds 
2466*1da177e4SLinus Torvalds 		} else {
2467*1da177e4SLinus Torvalds 			/* Programmed I/O */
2468*1da177e4SLinus Torvalds 
2469*1da177e4SLinus Torvalds 			/* test 1st byte */
2470*1da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
2471*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2472*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2473*1da177e4SLinus Torvalds 
2474*1da177e4SLinus Torvalds 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
2475*1da177e4SLinus Torvalds 				return;
2476*1da177e4SLinus Torvalds 
2477*1da177e4SLinus Torvalds 			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
2478*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2479*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2480*1da177e4SLinus Torvalds 
2481*1da177e4SLinus Torvalds 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
2482*1da177e4SLinus Torvalds 				return;
2483*1da177e4SLinus Torvalds 
2484*1da177e4SLinus Torvalds 			/* Get Major version */
2485*1da177e4SLinus Torvalds 			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
2486*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2487*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2488*1da177e4SLinus Torvalds 
2489*1da177e4SLinus Torvalds 			major = inb(ha->io_addr + IPS_REG_FLDP);
2490*1da177e4SLinus Torvalds 
2491*1da177e4SLinus Torvalds 			/* Get Minor version */
2492*1da177e4SLinus Torvalds 			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
2493*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2494*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2495*1da177e4SLinus Torvalds 
2496*1da177e4SLinus Torvalds 			minor = inb(ha->io_addr + IPS_REG_FLDP);
2497*1da177e4SLinus Torvalds 
2498*1da177e4SLinus Torvalds 			/* Get SubMinor version */
2499*1da177e4SLinus Torvalds 			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
2500*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
2501*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
2502*1da177e4SLinus Torvalds 
2503*1da177e4SLinus Torvalds 			subminor = inb(ha->io_addr + IPS_REG_FLDP);
2504*1da177e4SLinus Torvalds 
2505*1da177e4SLinus Torvalds 		}
2506*1da177e4SLinus Torvalds 	} else {
2507*1da177e4SLinus Torvalds 		/* Morpheus Family - Send Command to the card */
2508*1da177e4SLinus Torvalds 
2509*1da177e4SLinus Torvalds 		buffer = ha->ioctl_data;
2510*1da177e4SLinus Torvalds 
2511*1da177e4SLinus Torvalds 		memset(buffer, 0, 0x1000);
2512*1da177e4SLinus Torvalds 
2513*1da177e4SLinus Torvalds 		scb = &ha->scbs[ha->max_cmds - 1];
2514*1da177e4SLinus Torvalds 
2515*1da177e4SLinus Torvalds 		ips_init_scb(ha, scb);
2516*1da177e4SLinus Torvalds 
2517*1da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
2518*1da177e4SLinus Torvalds 		scb->cdb[0] = IPS_CMD_RW_BIOSFW;
2519*1da177e4SLinus Torvalds 
2520*1da177e4SLinus Torvalds 		scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
2521*1da177e4SLinus Torvalds 		scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
2522*1da177e4SLinus Torvalds 		scb->cmd.flashfw.type = 1;
2523*1da177e4SLinus Torvalds 		scb->cmd.flashfw.direction = 0;
2524*1da177e4SLinus Torvalds 		scb->cmd.flashfw.count = cpu_to_le32(0x800);
2525*1da177e4SLinus Torvalds 		scb->cmd.flashfw.total_packets = 1;
2526*1da177e4SLinus Torvalds 		scb->cmd.flashfw.packet_num = 0;
2527*1da177e4SLinus Torvalds 		scb->data_len = 0x1000;
2528*1da177e4SLinus Torvalds 		scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr;
2529*1da177e4SLinus Torvalds 
2530*1da177e4SLinus Torvalds 		/* issue the command */
2531*1da177e4SLinus Torvalds 		if (((ret =
2532*1da177e4SLinus Torvalds 		      ips_send_wait(ha, scb, ips_cmd_timeout,
2533*1da177e4SLinus Torvalds 				    intr)) == IPS_FAILURE)
2534*1da177e4SLinus Torvalds 		    || (ret == IPS_SUCCESS_IMM)
2535*1da177e4SLinus Torvalds 		    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
2536*1da177e4SLinus Torvalds 			/* Error occurred */
2537*1da177e4SLinus Torvalds 
2538*1da177e4SLinus Torvalds 			return;
2539*1da177e4SLinus Torvalds 		}
2540*1da177e4SLinus Torvalds 
2541*1da177e4SLinus Torvalds 		if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
2542*1da177e4SLinus Torvalds 			major = buffer[0x1ff + 0xC0];	/* Offset 0x1ff after the header (0xc0) */
2543*1da177e4SLinus Torvalds 			minor = buffer[0x1fe + 0xC0];	/* Offset 0x1fe after the header (0xc0) */
2544*1da177e4SLinus Torvalds 			subminor = buffer[0x1fd + 0xC0];	/* Offset 0x1fd after the header (0xc0) */
2545*1da177e4SLinus Torvalds 		} else {
2546*1da177e4SLinus Torvalds 			return;
2547*1da177e4SLinus Torvalds 		}
2548*1da177e4SLinus Torvalds 	}
2549*1da177e4SLinus Torvalds 
2550*1da177e4SLinus Torvalds 	ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
2551*1da177e4SLinus Torvalds 	ha->bios_version[1] = '.';
2552*1da177e4SLinus Torvalds 	ha->bios_version[2] = hexDigits[major & 0x0F];
2553*1da177e4SLinus Torvalds 	ha->bios_version[3] = hexDigits[subminor];
2554*1da177e4SLinus Torvalds 	ha->bios_version[4] = '.';
2555*1da177e4SLinus Torvalds 	ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
2556*1da177e4SLinus Torvalds 	ha->bios_version[6] = hexDigits[minor & 0x0F];
2557*1da177e4SLinus Torvalds 	ha->bios_version[7] = 0;
2558*1da177e4SLinus Torvalds }
2559*1da177e4SLinus Torvalds 
2560*1da177e4SLinus Torvalds /****************************************************************************/
2561*1da177e4SLinus Torvalds /*                                                                          */
2562*1da177e4SLinus Torvalds /* Routine Name: ips_hainit                                                 */
2563*1da177e4SLinus Torvalds /*                                                                          */
2564*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2565*1da177e4SLinus Torvalds /*                                                                          */
2566*1da177e4SLinus Torvalds /*   Initialize the controller                                              */
2567*1da177e4SLinus Torvalds /*                                                                          */
2568*1da177e4SLinus Torvalds /* NOTE: Assumes to be called from with a lock                              */
2569*1da177e4SLinus Torvalds /*                                                                          */
2570*1da177e4SLinus Torvalds /****************************************************************************/
2571*1da177e4SLinus Torvalds static int
2572*1da177e4SLinus Torvalds ips_hainit(ips_ha_t * ha)
2573*1da177e4SLinus Torvalds {
2574*1da177e4SLinus Torvalds 	int i;
2575*1da177e4SLinus Torvalds 	struct timeval tv;
2576*1da177e4SLinus Torvalds 
2577*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_hainit", 1);
2578*1da177e4SLinus Torvalds 
2579*1da177e4SLinus Torvalds 	if (!ha)
2580*1da177e4SLinus Torvalds 		return (0);
2581*1da177e4SLinus Torvalds 
2582*1da177e4SLinus Torvalds 	if (ha->func.statinit)
2583*1da177e4SLinus Torvalds 		(*ha->func.statinit) (ha);
2584*1da177e4SLinus Torvalds 
2585*1da177e4SLinus Torvalds 	if (ha->func.enableint)
2586*1da177e4SLinus Torvalds 		(*ha->func.enableint) (ha);
2587*1da177e4SLinus Torvalds 
2588*1da177e4SLinus Torvalds 	/* Send FFDC */
2589*1da177e4SLinus Torvalds 	ha->reset_count = 1;
2590*1da177e4SLinus Torvalds 	do_gettimeofday(&tv);
2591*1da177e4SLinus Torvalds 	ha->last_ffdc = tv.tv_sec;
2592*1da177e4SLinus Torvalds 	ips_ffdc_reset(ha, IPS_INTR_IORL);
2593*1da177e4SLinus Torvalds 
2594*1da177e4SLinus Torvalds 	if (!ips_read_config(ha, IPS_INTR_IORL)) {
2595*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
2596*1da177e4SLinus Torvalds 			   "unable to read config from controller.\n");
2597*1da177e4SLinus Torvalds 
2598*1da177e4SLinus Torvalds 		return (0);
2599*1da177e4SLinus Torvalds 	}
2600*1da177e4SLinus Torvalds 	/* end if */
2601*1da177e4SLinus Torvalds 	if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
2602*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
2603*1da177e4SLinus Torvalds 			   "unable to read controller status.\n");
2604*1da177e4SLinus Torvalds 
2605*1da177e4SLinus Torvalds 		return (0);
2606*1da177e4SLinus Torvalds 	}
2607*1da177e4SLinus Torvalds 
2608*1da177e4SLinus Torvalds 	/* Identify this controller */
2609*1da177e4SLinus Torvalds 	ips_identify_controller(ha);
2610*1da177e4SLinus Torvalds 
2611*1da177e4SLinus Torvalds 	if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
2612*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
2613*1da177e4SLinus Torvalds 			   "unable to read subsystem parameters.\n");
2614*1da177e4SLinus Torvalds 
2615*1da177e4SLinus Torvalds 		return (0);
2616*1da177e4SLinus Torvalds 	}
2617*1da177e4SLinus Torvalds 
2618*1da177e4SLinus Torvalds 	/* write nvram user page 5 */
2619*1da177e4SLinus Torvalds 	if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
2620*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
2621*1da177e4SLinus Torvalds 			   "unable to write driver info to controller.\n");
2622*1da177e4SLinus Torvalds 
2623*1da177e4SLinus Torvalds 		return (0);
2624*1da177e4SLinus Torvalds 	}
2625*1da177e4SLinus Torvalds 
2626*1da177e4SLinus Torvalds 	/* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
2627*1da177e4SLinus Torvalds 	if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1))
2628*1da177e4SLinus Torvalds 		ips_clear_adapter(ha, IPS_INTR_IORL);
2629*1da177e4SLinus Torvalds 
2630*1da177e4SLinus Torvalds 	/* set limits on SID, LUN, BUS */
2631*1da177e4SLinus Torvalds 	ha->ntargets = IPS_MAX_TARGETS + 1;
2632*1da177e4SLinus Torvalds 	ha->nlun = 1;
2633*1da177e4SLinus Torvalds 	ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
2634*1da177e4SLinus Torvalds 
2635*1da177e4SLinus Torvalds 	switch (ha->conf->logical_drive[0].ucStripeSize) {
2636*1da177e4SLinus Torvalds 	case 4:
2637*1da177e4SLinus Torvalds 		ha->max_xfer = 0x10000;
2638*1da177e4SLinus Torvalds 		break;
2639*1da177e4SLinus Torvalds 
2640*1da177e4SLinus Torvalds 	case 5:
2641*1da177e4SLinus Torvalds 		ha->max_xfer = 0x20000;
2642*1da177e4SLinus Torvalds 		break;
2643*1da177e4SLinus Torvalds 
2644*1da177e4SLinus Torvalds 	case 6:
2645*1da177e4SLinus Torvalds 		ha->max_xfer = 0x40000;
2646*1da177e4SLinus Torvalds 		break;
2647*1da177e4SLinus Torvalds 
2648*1da177e4SLinus Torvalds 	case 7:
2649*1da177e4SLinus Torvalds 	default:
2650*1da177e4SLinus Torvalds 		ha->max_xfer = 0x80000;
2651*1da177e4SLinus Torvalds 		break;
2652*1da177e4SLinus Torvalds 	}
2653*1da177e4SLinus Torvalds 
2654*1da177e4SLinus Torvalds 	/* setup max concurrent commands */
2655*1da177e4SLinus Torvalds 	if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
2656*1da177e4SLinus Torvalds 		/* Use the new method */
2657*1da177e4SLinus Torvalds 		ha->max_cmds = ha->enq->ucConcurrentCmdCount;
2658*1da177e4SLinus Torvalds 	} else {
2659*1da177e4SLinus Torvalds 		/* use the old method */
2660*1da177e4SLinus Torvalds 		switch (ha->conf->logical_drive[0].ucStripeSize) {
2661*1da177e4SLinus Torvalds 		case 4:
2662*1da177e4SLinus Torvalds 			ha->max_cmds = 32;
2663*1da177e4SLinus Torvalds 			break;
2664*1da177e4SLinus Torvalds 
2665*1da177e4SLinus Torvalds 		case 5:
2666*1da177e4SLinus Torvalds 			ha->max_cmds = 16;
2667*1da177e4SLinus Torvalds 			break;
2668*1da177e4SLinus Torvalds 
2669*1da177e4SLinus Torvalds 		case 6:
2670*1da177e4SLinus Torvalds 			ha->max_cmds = 8;
2671*1da177e4SLinus Torvalds 			break;
2672*1da177e4SLinus Torvalds 
2673*1da177e4SLinus Torvalds 		case 7:
2674*1da177e4SLinus Torvalds 		default:
2675*1da177e4SLinus Torvalds 			ha->max_cmds = 4;
2676*1da177e4SLinus Torvalds 			break;
2677*1da177e4SLinus Torvalds 		}
2678*1da177e4SLinus Torvalds 	}
2679*1da177e4SLinus Torvalds 
2680*1da177e4SLinus Torvalds 	/* Limit the Active Commands on a Lite Adapter */
2681*1da177e4SLinus Torvalds 	if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
2682*1da177e4SLinus Torvalds 	    (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
2683*1da177e4SLinus Torvalds 	    (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
2684*1da177e4SLinus Torvalds 		if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds))
2685*1da177e4SLinus Torvalds 			ha->max_cmds = MaxLiteCmds;
2686*1da177e4SLinus Torvalds 	}
2687*1da177e4SLinus Torvalds 
2688*1da177e4SLinus Torvalds 	/* set controller IDs */
2689*1da177e4SLinus Torvalds 	ha->ha_id[0] = IPS_ADAPTER_ID;
2690*1da177e4SLinus Torvalds 	for (i = 1; i < ha->nbus; i++) {
2691*1da177e4SLinus Torvalds 		ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f;
2692*1da177e4SLinus Torvalds 		ha->dcdb_active[i - 1] = 0;
2693*1da177e4SLinus Torvalds 	}
2694*1da177e4SLinus Torvalds 
2695*1da177e4SLinus Torvalds 	return (1);
2696*1da177e4SLinus Torvalds }
2697*1da177e4SLinus Torvalds 
2698*1da177e4SLinus Torvalds /****************************************************************************/
2699*1da177e4SLinus Torvalds /*                                                                          */
2700*1da177e4SLinus Torvalds /* Routine Name: ips_next                                                   */
2701*1da177e4SLinus Torvalds /*                                                                          */
2702*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2703*1da177e4SLinus Torvalds /*                                                                          */
2704*1da177e4SLinus Torvalds /*   Take the next command off the queue and send it to the controller      */
2705*1da177e4SLinus Torvalds /*                                                                          */
2706*1da177e4SLinus Torvalds /****************************************************************************/
2707*1da177e4SLinus Torvalds static void
2708*1da177e4SLinus Torvalds ips_next(ips_ha_t * ha, int intr)
2709*1da177e4SLinus Torvalds {
2710*1da177e4SLinus Torvalds 	ips_scb_t *scb;
2711*1da177e4SLinus Torvalds 	Scsi_Cmnd *SC;
2712*1da177e4SLinus Torvalds 	Scsi_Cmnd *p;
2713*1da177e4SLinus Torvalds 	Scsi_Cmnd *q;
2714*1da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
2715*1da177e4SLinus Torvalds 	int ret;
2716*1da177e4SLinus Torvalds 	unsigned long cpu_flags = 0;
2717*1da177e4SLinus Torvalds 	struct Scsi_Host *host;
2718*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_next", 1);
2719*1da177e4SLinus Torvalds 
2720*1da177e4SLinus Torvalds 	if (!ha)
2721*1da177e4SLinus Torvalds 		return;
2722*1da177e4SLinus Torvalds 	host = ips_sh[ha->host_num];
2723*1da177e4SLinus Torvalds 	/*
2724*1da177e4SLinus Torvalds 	 * Block access to the queue function so
2725*1da177e4SLinus Torvalds 	 * this command won't time out
2726*1da177e4SLinus Torvalds 	 */
2727*1da177e4SLinus Torvalds 	if (intr == IPS_INTR_ON)
2728*1da177e4SLinus Torvalds 		IPS_LOCK_SAVE(host->host_lock, cpu_flags);
2729*1da177e4SLinus Torvalds 
2730*1da177e4SLinus Torvalds 	if ((ha->subsys->param[3] & 0x300000)
2731*1da177e4SLinus Torvalds 	    && (ha->scb_activelist.count == 0)) {
2732*1da177e4SLinus Torvalds 		struct timeval tv;
2733*1da177e4SLinus Torvalds 
2734*1da177e4SLinus Torvalds 		do_gettimeofday(&tv);
2735*1da177e4SLinus Torvalds 
2736*1da177e4SLinus Torvalds 		if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
2737*1da177e4SLinus Torvalds 			ha->last_ffdc = tv.tv_sec;
2738*1da177e4SLinus Torvalds 			ips_ffdc_time(ha);
2739*1da177e4SLinus Torvalds 		}
2740*1da177e4SLinus Torvalds 	}
2741*1da177e4SLinus Torvalds 
2742*1da177e4SLinus Torvalds 	/*
2743*1da177e4SLinus Torvalds 	 * Send passthru commands
2744*1da177e4SLinus Torvalds 	 * These have priority over normal I/O
2745*1da177e4SLinus Torvalds 	 * but shouldn't affect performance too much
2746*1da177e4SLinus Torvalds 	 * since we limit the number that can be active
2747*1da177e4SLinus Torvalds 	 * on the card at any one time
2748*1da177e4SLinus Torvalds 	 */
2749*1da177e4SLinus Torvalds 	while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
2750*1da177e4SLinus Torvalds 	       (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) {
2751*1da177e4SLinus Torvalds 
2752*1da177e4SLinus Torvalds 		item = ips_removeq_copp_head(&ha->copp_waitlist);
2753*1da177e4SLinus Torvalds 		ha->num_ioctl++;
2754*1da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
2755*1da177e4SLinus Torvalds 			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
2756*1da177e4SLinus Torvalds 		scb->scsi_cmd = item->scsi_cmd;
2757*1da177e4SLinus Torvalds 		kfree(item);
2758*1da177e4SLinus Torvalds 
2759*1da177e4SLinus Torvalds 		ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
2760*1da177e4SLinus Torvalds 
2761*1da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
2762*1da177e4SLinus Torvalds 			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
2763*1da177e4SLinus Torvalds 		switch (ret) {
2764*1da177e4SLinus Torvalds 		case IPS_FAILURE:
2765*1da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
2766*1da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_ERROR << 16;
2767*1da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2768*1da177e4SLinus Torvalds 			}
2769*1da177e4SLinus Torvalds 
2770*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2771*1da177e4SLinus Torvalds 			break;
2772*1da177e4SLinus Torvalds 		case IPS_SUCCESS_IMM:
2773*1da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
2774*1da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_OK << 16;
2775*1da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2776*1da177e4SLinus Torvalds 			}
2777*1da177e4SLinus Torvalds 
2778*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2779*1da177e4SLinus Torvalds 			break;
2780*1da177e4SLinus Torvalds 		default:
2781*1da177e4SLinus Torvalds 			break;
2782*1da177e4SLinus Torvalds 		}		/* end case */
2783*1da177e4SLinus Torvalds 
2784*1da177e4SLinus Torvalds 		if (ret != IPS_SUCCESS) {
2785*1da177e4SLinus Torvalds 			ha->num_ioctl--;
2786*1da177e4SLinus Torvalds 			continue;
2787*1da177e4SLinus Torvalds 		}
2788*1da177e4SLinus Torvalds 
2789*1da177e4SLinus Torvalds 		ret = ips_send_cmd(ha, scb);
2790*1da177e4SLinus Torvalds 
2791*1da177e4SLinus Torvalds 		if (ret == IPS_SUCCESS)
2792*1da177e4SLinus Torvalds 			ips_putq_scb_head(&ha->scb_activelist, scb);
2793*1da177e4SLinus Torvalds 		else
2794*1da177e4SLinus Torvalds 			ha->num_ioctl--;
2795*1da177e4SLinus Torvalds 
2796*1da177e4SLinus Torvalds 		switch (ret) {
2797*1da177e4SLinus Torvalds 		case IPS_FAILURE:
2798*1da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
2799*1da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_ERROR << 16;
2800*1da177e4SLinus Torvalds 			}
2801*1da177e4SLinus Torvalds 
2802*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2803*1da177e4SLinus Torvalds 			break;
2804*1da177e4SLinus Torvalds 		case IPS_SUCCESS_IMM:
2805*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2806*1da177e4SLinus Torvalds 			break;
2807*1da177e4SLinus Torvalds 		default:
2808*1da177e4SLinus Torvalds 			break;
2809*1da177e4SLinus Torvalds 		}		/* end case */
2810*1da177e4SLinus Torvalds 
2811*1da177e4SLinus Torvalds 	}
2812*1da177e4SLinus Torvalds 
2813*1da177e4SLinus Torvalds 	/*
2814*1da177e4SLinus Torvalds 	 * Send "Normal" I/O commands
2815*1da177e4SLinus Torvalds 	 */
2816*1da177e4SLinus Torvalds 
2817*1da177e4SLinus Torvalds 	p = ha->scb_waitlist.head;
2818*1da177e4SLinus Torvalds 	while ((p) && (scb = ips_getscb(ha))) {
2819*1da177e4SLinus Torvalds 		if ((p->device->channel > 0)
2820*1da177e4SLinus Torvalds 		    && (ha->
2821*1da177e4SLinus Torvalds 			dcdb_active[p->device->channel -
2822*1da177e4SLinus Torvalds 				    1] & (1 << p->device->id))) {
2823*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2824*1da177e4SLinus Torvalds 			p = (Scsi_Cmnd *) p->host_scribble;
2825*1da177e4SLinus Torvalds 			continue;
2826*1da177e4SLinus Torvalds 		}
2827*1da177e4SLinus Torvalds 
2828*1da177e4SLinus Torvalds 		q = p;
2829*1da177e4SLinus Torvalds 		SC = ips_removeq_wait(&ha->scb_waitlist, q);
2830*1da177e4SLinus Torvalds 
2831*1da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
2832*1da177e4SLinus Torvalds 			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);	/* Unlock HA after command is taken off queue */
2833*1da177e4SLinus Torvalds 
2834*1da177e4SLinus Torvalds 		SC->result = DID_OK;
2835*1da177e4SLinus Torvalds 		SC->host_scribble = NULL;
2836*1da177e4SLinus Torvalds 
2837*1da177e4SLinus Torvalds 		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
2838*1da177e4SLinus Torvalds 
2839*1da177e4SLinus Torvalds 		scb->target_id = SC->device->id;
2840*1da177e4SLinus Torvalds 		scb->lun = SC->device->lun;
2841*1da177e4SLinus Torvalds 		scb->bus = SC->device->channel;
2842*1da177e4SLinus Torvalds 		scb->scsi_cmd = SC;
2843*1da177e4SLinus Torvalds 		scb->breakup = 0;
2844*1da177e4SLinus Torvalds 		scb->data_len = 0;
2845*1da177e4SLinus Torvalds 		scb->callback = ipsintr_done;
2846*1da177e4SLinus Torvalds 		scb->timeout = ips_cmd_timeout;
2847*1da177e4SLinus Torvalds 		memset(&scb->cmd, 0, 16);
2848*1da177e4SLinus Torvalds 
2849*1da177e4SLinus Torvalds 		/* copy in the CDB */
2850*1da177e4SLinus Torvalds 		memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
2851*1da177e4SLinus Torvalds 
2852*1da177e4SLinus Torvalds 		/* Now handle the data buffer */
2853*1da177e4SLinus Torvalds 		if (SC->use_sg) {
2854*1da177e4SLinus Torvalds 			struct scatterlist *sg;
2855*1da177e4SLinus Torvalds 			int i;
2856*1da177e4SLinus Torvalds 
2857*1da177e4SLinus Torvalds 			sg = SC->request_buffer;
2858*1da177e4SLinus Torvalds 			scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
2859*1da177e4SLinus Torvalds 						   scsi_to_pci_dma_dir(SC->
2860*1da177e4SLinus Torvalds 								       sc_data_direction));
2861*1da177e4SLinus Torvalds 			scb->flags |= IPS_SCB_MAP_SG;
2862*1da177e4SLinus Torvalds 			for (i = 0; i < scb->sg_count; i++) {
2863*1da177e4SLinus Torvalds 				if (ips_fill_scb_sg_single
2864*1da177e4SLinus Torvalds 				    (ha, sg_dma_address(&sg[i]), scb, i,
2865*1da177e4SLinus Torvalds 				     sg_dma_len(&sg[i])) < 0)
2866*1da177e4SLinus Torvalds 					break;
2867*1da177e4SLinus Torvalds 			}
2868*1da177e4SLinus Torvalds 			scb->dcdb.transfer_length = scb->data_len;
2869*1da177e4SLinus Torvalds 		} else {
2870*1da177e4SLinus Torvalds 			if (SC->request_bufflen) {
2871*1da177e4SLinus Torvalds 				scb->data_busaddr =
2872*1da177e4SLinus Torvalds 				    pci_map_single(ha->pcidev,
2873*1da177e4SLinus Torvalds 						   SC->request_buffer,
2874*1da177e4SLinus Torvalds 						   SC->request_bufflen,
2875*1da177e4SLinus Torvalds 						   scsi_to_pci_dma_dir(SC->
2876*1da177e4SLinus Torvalds 								       sc_data_direction));
2877*1da177e4SLinus Torvalds 				scb->flags |= IPS_SCB_MAP_SINGLE;
2878*1da177e4SLinus Torvalds 				ips_fill_scb_sg_single(ha, scb->data_busaddr,
2879*1da177e4SLinus Torvalds 						       scb, 0,
2880*1da177e4SLinus Torvalds 						       SC->request_bufflen);
2881*1da177e4SLinus Torvalds 				scb->dcdb.transfer_length = scb->data_len;
2882*1da177e4SLinus Torvalds 			} else {
2883*1da177e4SLinus Torvalds 				scb->data_busaddr = 0L;
2884*1da177e4SLinus Torvalds 				scb->sg_len = 0;
2885*1da177e4SLinus Torvalds 				scb->data_len = 0;
2886*1da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
2887*1da177e4SLinus Torvalds 			}
2888*1da177e4SLinus Torvalds 
2889*1da177e4SLinus Torvalds 		}
2890*1da177e4SLinus Torvalds 
2891*1da177e4SLinus Torvalds 		scb->dcdb.cmd_attribute =
2892*1da177e4SLinus Torvalds 		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
2893*1da177e4SLinus Torvalds 
2894*1da177e4SLinus Torvalds         /* Allow a WRITE BUFFER Command to Have no Data */
2895*1da177e4SLinus Torvalds         /* This is Used by Tape Flash Utilites          */
2896*1da177e4SLinus Torvalds         if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0))
2897*1da177e4SLinus Torvalds             scb->dcdb.cmd_attribute = 0;
2898*1da177e4SLinus Torvalds 
2899*1da177e4SLinus Torvalds 		if (!(scb->dcdb.cmd_attribute & 0x3))
2900*1da177e4SLinus Torvalds 			scb->dcdb.transfer_length = 0;
2901*1da177e4SLinus Torvalds 
2902*1da177e4SLinus Torvalds 		if (scb->data_len >= IPS_MAX_XFER) {
2903*1da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
2904*1da177e4SLinus Torvalds 			scb->dcdb.transfer_length = 0;
2905*1da177e4SLinus Torvalds 		}
2906*1da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON)
2907*1da177e4SLinus Torvalds 			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
2908*1da177e4SLinus Torvalds 
2909*1da177e4SLinus Torvalds 		ret = ips_send_cmd(ha, scb);
2910*1da177e4SLinus Torvalds 
2911*1da177e4SLinus Torvalds 		switch (ret) {
2912*1da177e4SLinus Torvalds 		case IPS_SUCCESS:
2913*1da177e4SLinus Torvalds 			ips_putq_scb_head(&ha->scb_activelist, scb);
2914*1da177e4SLinus Torvalds 			break;
2915*1da177e4SLinus Torvalds 		case IPS_FAILURE:
2916*1da177e4SLinus Torvalds 			if (scb->scsi_cmd) {
2917*1da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_ERROR << 16;
2918*1da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2919*1da177e4SLinus Torvalds 			}
2920*1da177e4SLinus Torvalds 
2921*1da177e4SLinus Torvalds 			if (scb->bus)
2922*1da177e4SLinus Torvalds 				ha->dcdb_active[scb->bus - 1] &=
2923*1da177e4SLinus Torvalds 				    ~(1 << scb->target_id);
2924*1da177e4SLinus Torvalds 
2925*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2926*1da177e4SLinus Torvalds 			break;
2927*1da177e4SLinus Torvalds 		case IPS_SUCCESS_IMM:
2928*1da177e4SLinus Torvalds 			if (scb->scsi_cmd)
2929*1da177e4SLinus Torvalds 				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2930*1da177e4SLinus Torvalds 
2931*1da177e4SLinus Torvalds 			if (scb->bus)
2932*1da177e4SLinus Torvalds 				ha->dcdb_active[scb->bus - 1] &=
2933*1da177e4SLinus Torvalds 				    ~(1 << scb->target_id);
2934*1da177e4SLinus Torvalds 
2935*1da177e4SLinus Torvalds 			ips_freescb(ha, scb);
2936*1da177e4SLinus Torvalds 			break;
2937*1da177e4SLinus Torvalds 		default:
2938*1da177e4SLinus Torvalds 			break;
2939*1da177e4SLinus Torvalds 		}		/* end case */
2940*1da177e4SLinus Torvalds 
2941*1da177e4SLinus Torvalds 		p = (Scsi_Cmnd *) p->host_scribble;
2942*1da177e4SLinus Torvalds 
2943*1da177e4SLinus Torvalds 	}			/* end while */
2944*1da177e4SLinus Torvalds 
2945*1da177e4SLinus Torvalds 	if (intr == IPS_INTR_ON)
2946*1da177e4SLinus Torvalds 		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
2947*1da177e4SLinus Torvalds }
2948*1da177e4SLinus Torvalds 
2949*1da177e4SLinus Torvalds /****************************************************************************/
2950*1da177e4SLinus Torvalds /*                                                                          */
2951*1da177e4SLinus Torvalds /* Routine Name: ips_putq_scb_head                                          */
2952*1da177e4SLinus Torvalds /*                                                                          */
2953*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2954*1da177e4SLinus Torvalds /*                                                                          */
2955*1da177e4SLinus Torvalds /*   Add an item to the head of the queue                                   */
2956*1da177e4SLinus Torvalds /*                                                                          */
2957*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
2958*1da177e4SLinus Torvalds /*                                                                          */
2959*1da177e4SLinus Torvalds /****************************************************************************/
2960*1da177e4SLinus Torvalds static void
2961*1da177e4SLinus Torvalds ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
2962*1da177e4SLinus Torvalds {
2963*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_putq_scb_head", 1);
2964*1da177e4SLinus Torvalds 
2965*1da177e4SLinus Torvalds 	if (!item)
2966*1da177e4SLinus Torvalds 		return;
2967*1da177e4SLinus Torvalds 
2968*1da177e4SLinus Torvalds 	item->q_next = queue->head;
2969*1da177e4SLinus Torvalds 	queue->head = item;
2970*1da177e4SLinus Torvalds 
2971*1da177e4SLinus Torvalds 	if (!queue->tail)
2972*1da177e4SLinus Torvalds 		queue->tail = item;
2973*1da177e4SLinus Torvalds 
2974*1da177e4SLinus Torvalds 	queue->count++;
2975*1da177e4SLinus Torvalds }
2976*1da177e4SLinus Torvalds 
2977*1da177e4SLinus Torvalds /****************************************************************************/
2978*1da177e4SLinus Torvalds /*                                                                          */
2979*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_scb_head                                       */
2980*1da177e4SLinus Torvalds /*                                                                          */
2981*1da177e4SLinus Torvalds /* Routine Description:                                                     */
2982*1da177e4SLinus Torvalds /*                                                                          */
2983*1da177e4SLinus Torvalds /*   Remove the head of the queue                                           */
2984*1da177e4SLinus Torvalds /*                                                                          */
2985*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
2986*1da177e4SLinus Torvalds /*                                                                          */
2987*1da177e4SLinus Torvalds /****************************************************************************/
2988*1da177e4SLinus Torvalds static ips_scb_t *
2989*1da177e4SLinus Torvalds ips_removeq_scb_head(ips_scb_queue_t * queue)
2990*1da177e4SLinus Torvalds {
2991*1da177e4SLinus Torvalds 	ips_scb_t *item;
2992*1da177e4SLinus Torvalds 
2993*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_scb_head", 1);
2994*1da177e4SLinus Torvalds 
2995*1da177e4SLinus Torvalds 	item = queue->head;
2996*1da177e4SLinus Torvalds 
2997*1da177e4SLinus Torvalds 	if (!item) {
2998*1da177e4SLinus Torvalds 		return (NULL);
2999*1da177e4SLinus Torvalds 	}
3000*1da177e4SLinus Torvalds 
3001*1da177e4SLinus Torvalds 	queue->head = item->q_next;
3002*1da177e4SLinus Torvalds 	item->q_next = NULL;
3003*1da177e4SLinus Torvalds 
3004*1da177e4SLinus Torvalds 	if (queue->tail == item)
3005*1da177e4SLinus Torvalds 		queue->tail = NULL;
3006*1da177e4SLinus Torvalds 
3007*1da177e4SLinus Torvalds 	queue->count--;
3008*1da177e4SLinus Torvalds 
3009*1da177e4SLinus Torvalds 	return (item);
3010*1da177e4SLinus Torvalds }
3011*1da177e4SLinus Torvalds 
3012*1da177e4SLinus Torvalds /****************************************************************************/
3013*1da177e4SLinus Torvalds /*                                                                          */
3014*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_scb                                            */
3015*1da177e4SLinus Torvalds /*                                                                          */
3016*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3017*1da177e4SLinus Torvalds /*                                                                          */
3018*1da177e4SLinus Torvalds /*   Remove an item from a queue                                            */
3019*1da177e4SLinus Torvalds /*                                                                          */
3020*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3021*1da177e4SLinus Torvalds /*                                                                          */
3022*1da177e4SLinus Torvalds /****************************************************************************/
3023*1da177e4SLinus Torvalds static ips_scb_t *
3024*1da177e4SLinus Torvalds ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
3025*1da177e4SLinus Torvalds {
3026*1da177e4SLinus Torvalds 	ips_scb_t *p;
3027*1da177e4SLinus Torvalds 
3028*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_scb", 1);
3029*1da177e4SLinus Torvalds 
3030*1da177e4SLinus Torvalds 	if (!item)
3031*1da177e4SLinus Torvalds 		return (NULL);
3032*1da177e4SLinus Torvalds 
3033*1da177e4SLinus Torvalds 	if (item == queue->head) {
3034*1da177e4SLinus Torvalds 		return (ips_removeq_scb_head(queue));
3035*1da177e4SLinus Torvalds 	}
3036*1da177e4SLinus Torvalds 
3037*1da177e4SLinus Torvalds 	p = queue->head;
3038*1da177e4SLinus Torvalds 
3039*1da177e4SLinus Torvalds 	while ((p) && (item != p->q_next))
3040*1da177e4SLinus Torvalds 		p = p->q_next;
3041*1da177e4SLinus Torvalds 
3042*1da177e4SLinus Torvalds 	if (p) {
3043*1da177e4SLinus Torvalds 		/* found a match */
3044*1da177e4SLinus Torvalds 		p->q_next = item->q_next;
3045*1da177e4SLinus Torvalds 
3046*1da177e4SLinus Torvalds 		if (!item->q_next)
3047*1da177e4SLinus Torvalds 			queue->tail = p;
3048*1da177e4SLinus Torvalds 
3049*1da177e4SLinus Torvalds 		item->q_next = NULL;
3050*1da177e4SLinus Torvalds 		queue->count--;
3051*1da177e4SLinus Torvalds 
3052*1da177e4SLinus Torvalds 		return (item);
3053*1da177e4SLinus Torvalds 	}
3054*1da177e4SLinus Torvalds 
3055*1da177e4SLinus Torvalds 	return (NULL);
3056*1da177e4SLinus Torvalds }
3057*1da177e4SLinus Torvalds 
3058*1da177e4SLinus Torvalds /****************************************************************************/
3059*1da177e4SLinus Torvalds /*                                                                          */
3060*1da177e4SLinus Torvalds /* Routine Name: ips_putq_wait_tail                                         */
3061*1da177e4SLinus Torvalds /*                                                                          */
3062*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3063*1da177e4SLinus Torvalds /*                                                                          */
3064*1da177e4SLinus Torvalds /*   Add an item to the tail of the queue                                   */
3065*1da177e4SLinus Torvalds /*                                                                          */
3066*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3067*1da177e4SLinus Torvalds /*                                                                          */
3068*1da177e4SLinus Torvalds /****************************************************************************/
3069*1da177e4SLinus Torvalds static void
3070*1da177e4SLinus Torvalds ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
3071*1da177e4SLinus Torvalds {
3072*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_putq_wait_tail", 1);
3073*1da177e4SLinus Torvalds 
3074*1da177e4SLinus Torvalds 	if (!item)
3075*1da177e4SLinus Torvalds 		return;
3076*1da177e4SLinus Torvalds 
3077*1da177e4SLinus Torvalds 	item->host_scribble = NULL;
3078*1da177e4SLinus Torvalds 
3079*1da177e4SLinus Torvalds 	if (queue->tail)
3080*1da177e4SLinus Torvalds 		queue->tail->host_scribble = (char *) item;
3081*1da177e4SLinus Torvalds 
3082*1da177e4SLinus Torvalds 	queue->tail = item;
3083*1da177e4SLinus Torvalds 
3084*1da177e4SLinus Torvalds 	if (!queue->head)
3085*1da177e4SLinus Torvalds 		queue->head = item;
3086*1da177e4SLinus Torvalds 
3087*1da177e4SLinus Torvalds 	queue->count++;
3088*1da177e4SLinus Torvalds }
3089*1da177e4SLinus Torvalds 
3090*1da177e4SLinus Torvalds /****************************************************************************/
3091*1da177e4SLinus Torvalds /*                                                                          */
3092*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_wait_head                                      */
3093*1da177e4SLinus Torvalds /*                                                                          */
3094*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3095*1da177e4SLinus Torvalds /*                                                                          */
3096*1da177e4SLinus Torvalds /*   Remove the head of the queue                                           */
3097*1da177e4SLinus Torvalds /*                                                                          */
3098*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3099*1da177e4SLinus Torvalds /*                                                                          */
3100*1da177e4SLinus Torvalds /****************************************************************************/
3101*1da177e4SLinus Torvalds static Scsi_Cmnd *
3102*1da177e4SLinus Torvalds ips_removeq_wait_head(ips_wait_queue_t * queue)
3103*1da177e4SLinus Torvalds {
3104*1da177e4SLinus Torvalds 	Scsi_Cmnd *item;
3105*1da177e4SLinus Torvalds 
3106*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_wait_head", 1);
3107*1da177e4SLinus Torvalds 
3108*1da177e4SLinus Torvalds 	item = queue->head;
3109*1da177e4SLinus Torvalds 
3110*1da177e4SLinus Torvalds 	if (!item) {
3111*1da177e4SLinus Torvalds 		return (NULL);
3112*1da177e4SLinus Torvalds 	}
3113*1da177e4SLinus Torvalds 
3114*1da177e4SLinus Torvalds 	queue->head = (Scsi_Cmnd *) item->host_scribble;
3115*1da177e4SLinus Torvalds 	item->host_scribble = NULL;
3116*1da177e4SLinus Torvalds 
3117*1da177e4SLinus Torvalds 	if (queue->tail == item)
3118*1da177e4SLinus Torvalds 		queue->tail = NULL;
3119*1da177e4SLinus Torvalds 
3120*1da177e4SLinus Torvalds 	queue->count--;
3121*1da177e4SLinus Torvalds 
3122*1da177e4SLinus Torvalds 	return (item);
3123*1da177e4SLinus Torvalds }
3124*1da177e4SLinus Torvalds 
3125*1da177e4SLinus Torvalds /****************************************************************************/
3126*1da177e4SLinus Torvalds /*                                                                          */
3127*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_wait                                           */
3128*1da177e4SLinus Torvalds /*                                                                          */
3129*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3130*1da177e4SLinus Torvalds /*                                                                          */
3131*1da177e4SLinus Torvalds /*   Remove an item from a queue                                            */
3132*1da177e4SLinus Torvalds /*                                                                          */
3133*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3134*1da177e4SLinus Torvalds /*                                                                          */
3135*1da177e4SLinus Torvalds /****************************************************************************/
3136*1da177e4SLinus Torvalds static Scsi_Cmnd *
3137*1da177e4SLinus Torvalds ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
3138*1da177e4SLinus Torvalds {
3139*1da177e4SLinus Torvalds 	Scsi_Cmnd *p;
3140*1da177e4SLinus Torvalds 
3141*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_wait", 1);
3142*1da177e4SLinus Torvalds 
3143*1da177e4SLinus Torvalds 	if (!item)
3144*1da177e4SLinus Torvalds 		return (NULL);
3145*1da177e4SLinus Torvalds 
3146*1da177e4SLinus Torvalds 	if (item == queue->head) {
3147*1da177e4SLinus Torvalds 		return (ips_removeq_wait_head(queue));
3148*1da177e4SLinus Torvalds 	}
3149*1da177e4SLinus Torvalds 
3150*1da177e4SLinus Torvalds 	p = queue->head;
3151*1da177e4SLinus Torvalds 
3152*1da177e4SLinus Torvalds 	while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
3153*1da177e4SLinus Torvalds 		p = (Scsi_Cmnd *) p->host_scribble;
3154*1da177e4SLinus Torvalds 
3155*1da177e4SLinus Torvalds 	if (p) {
3156*1da177e4SLinus Torvalds 		/* found a match */
3157*1da177e4SLinus Torvalds 		p->host_scribble = item->host_scribble;
3158*1da177e4SLinus Torvalds 
3159*1da177e4SLinus Torvalds 		if (!item->host_scribble)
3160*1da177e4SLinus Torvalds 			queue->tail = p;
3161*1da177e4SLinus Torvalds 
3162*1da177e4SLinus Torvalds 		item->host_scribble = NULL;
3163*1da177e4SLinus Torvalds 		queue->count--;
3164*1da177e4SLinus Torvalds 
3165*1da177e4SLinus Torvalds 		return (item);
3166*1da177e4SLinus Torvalds 	}
3167*1da177e4SLinus Torvalds 
3168*1da177e4SLinus Torvalds 	return (NULL);
3169*1da177e4SLinus Torvalds }
3170*1da177e4SLinus Torvalds 
3171*1da177e4SLinus Torvalds /****************************************************************************/
3172*1da177e4SLinus Torvalds /*                                                                          */
3173*1da177e4SLinus Torvalds /* Routine Name: ips_putq_copp_tail                                         */
3174*1da177e4SLinus Torvalds /*                                                                          */
3175*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3176*1da177e4SLinus Torvalds /*                                                                          */
3177*1da177e4SLinus Torvalds /*   Add an item to the tail of the queue                                   */
3178*1da177e4SLinus Torvalds /*                                                                          */
3179*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3180*1da177e4SLinus Torvalds /*                                                                          */
3181*1da177e4SLinus Torvalds /****************************************************************************/
3182*1da177e4SLinus Torvalds static void
3183*1da177e4SLinus Torvalds ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
3184*1da177e4SLinus Torvalds {
3185*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_putq_copp_tail", 1);
3186*1da177e4SLinus Torvalds 
3187*1da177e4SLinus Torvalds 	if (!item)
3188*1da177e4SLinus Torvalds 		return;
3189*1da177e4SLinus Torvalds 
3190*1da177e4SLinus Torvalds 	item->next = NULL;
3191*1da177e4SLinus Torvalds 
3192*1da177e4SLinus Torvalds 	if (queue->tail)
3193*1da177e4SLinus Torvalds 		queue->tail->next = item;
3194*1da177e4SLinus Torvalds 
3195*1da177e4SLinus Torvalds 	queue->tail = item;
3196*1da177e4SLinus Torvalds 
3197*1da177e4SLinus Torvalds 	if (!queue->head)
3198*1da177e4SLinus Torvalds 		queue->head = item;
3199*1da177e4SLinus Torvalds 
3200*1da177e4SLinus Torvalds 	queue->count++;
3201*1da177e4SLinus Torvalds }
3202*1da177e4SLinus Torvalds 
3203*1da177e4SLinus Torvalds /****************************************************************************/
3204*1da177e4SLinus Torvalds /*                                                                          */
3205*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_copp_head                                      */
3206*1da177e4SLinus Torvalds /*                                                                          */
3207*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3208*1da177e4SLinus Torvalds /*                                                                          */
3209*1da177e4SLinus Torvalds /*   Remove the head of the queue                                           */
3210*1da177e4SLinus Torvalds /*                                                                          */
3211*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3212*1da177e4SLinus Torvalds /*                                                                          */
3213*1da177e4SLinus Torvalds /****************************************************************************/
3214*1da177e4SLinus Torvalds static ips_copp_wait_item_t *
3215*1da177e4SLinus Torvalds ips_removeq_copp_head(ips_copp_queue_t * queue)
3216*1da177e4SLinus Torvalds {
3217*1da177e4SLinus Torvalds 	ips_copp_wait_item_t *item;
3218*1da177e4SLinus Torvalds 
3219*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_copp_head", 1);
3220*1da177e4SLinus Torvalds 
3221*1da177e4SLinus Torvalds 	item = queue->head;
3222*1da177e4SLinus Torvalds 
3223*1da177e4SLinus Torvalds 	if (!item) {
3224*1da177e4SLinus Torvalds 		return (NULL);
3225*1da177e4SLinus Torvalds 	}
3226*1da177e4SLinus Torvalds 
3227*1da177e4SLinus Torvalds 	queue->head = item->next;
3228*1da177e4SLinus Torvalds 	item->next = NULL;
3229*1da177e4SLinus Torvalds 
3230*1da177e4SLinus Torvalds 	if (queue->tail == item)
3231*1da177e4SLinus Torvalds 		queue->tail = NULL;
3232*1da177e4SLinus Torvalds 
3233*1da177e4SLinus Torvalds 	queue->count--;
3234*1da177e4SLinus Torvalds 
3235*1da177e4SLinus Torvalds 	return (item);
3236*1da177e4SLinus Torvalds }
3237*1da177e4SLinus Torvalds 
3238*1da177e4SLinus Torvalds /****************************************************************************/
3239*1da177e4SLinus Torvalds /*                                                                          */
3240*1da177e4SLinus Torvalds /* Routine Name: ips_removeq_copp                                           */
3241*1da177e4SLinus Torvalds /*                                                                          */
3242*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3243*1da177e4SLinus Torvalds /*                                                                          */
3244*1da177e4SLinus Torvalds /*   Remove an item from a queue                                            */
3245*1da177e4SLinus Torvalds /*                                                                          */
3246*1da177e4SLinus Torvalds /* ASSUMED to be called from within the HA lock                             */
3247*1da177e4SLinus Torvalds /*                                                                          */
3248*1da177e4SLinus Torvalds /****************************************************************************/
3249*1da177e4SLinus Torvalds static ips_copp_wait_item_t *
3250*1da177e4SLinus Torvalds ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
3251*1da177e4SLinus Torvalds {
3252*1da177e4SLinus Torvalds 	ips_copp_wait_item_t *p;
3253*1da177e4SLinus Torvalds 
3254*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_removeq_copp", 1);
3255*1da177e4SLinus Torvalds 
3256*1da177e4SLinus Torvalds 	if (!item)
3257*1da177e4SLinus Torvalds 		return (NULL);
3258*1da177e4SLinus Torvalds 
3259*1da177e4SLinus Torvalds 	if (item == queue->head) {
3260*1da177e4SLinus Torvalds 		return (ips_removeq_copp_head(queue));
3261*1da177e4SLinus Torvalds 	}
3262*1da177e4SLinus Torvalds 
3263*1da177e4SLinus Torvalds 	p = queue->head;
3264*1da177e4SLinus Torvalds 
3265*1da177e4SLinus Torvalds 	while ((p) && (item != p->next))
3266*1da177e4SLinus Torvalds 		p = p->next;
3267*1da177e4SLinus Torvalds 
3268*1da177e4SLinus Torvalds 	if (p) {
3269*1da177e4SLinus Torvalds 		/* found a match */
3270*1da177e4SLinus Torvalds 		p->next = item->next;
3271*1da177e4SLinus Torvalds 
3272*1da177e4SLinus Torvalds 		if (!item->next)
3273*1da177e4SLinus Torvalds 			queue->tail = p;
3274*1da177e4SLinus Torvalds 
3275*1da177e4SLinus Torvalds 		item->next = NULL;
3276*1da177e4SLinus Torvalds 		queue->count--;
3277*1da177e4SLinus Torvalds 
3278*1da177e4SLinus Torvalds 		return (item);
3279*1da177e4SLinus Torvalds 	}
3280*1da177e4SLinus Torvalds 
3281*1da177e4SLinus Torvalds 	return (NULL);
3282*1da177e4SLinus Torvalds }
3283*1da177e4SLinus Torvalds 
3284*1da177e4SLinus Torvalds /****************************************************************************/
3285*1da177e4SLinus Torvalds /*                                                                          */
3286*1da177e4SLinus Torvalds /* Routine Name: ipsintr_blocking                                           */
3287*1da177e4SLinus Torvalds /*                                                                          */
3288*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3289*1da177e4SLinus Torvalds /*                                                                          */
3290*1da177e4SLinus Torvalds /*   Finalize an interrupt for internal commands                            */
3291*1da177e4SLinus Torvalds /*                                                                          */
3292*1da177e4SLinus Torvalds /****************************************************************************/
3293*1da177e4SLinus Torvalds static void
3294*1da177e4SLinus Torvalds ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb)
3295*1da177e4SLinus Torvalds {
3296*1da177e4SLinus Torvalds 	METHOD_TRACE("ipsintr_blocking", 2);
3297*1da177e4SLinus Torvalds 
3298*1da177e4SLinus Torvalds 	ips_freescb(ha, scb);
3299*1da177e4SLinus Torvalds 	if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) {
3300*1da177e4SLinus Torvalds 		ha->waitflag = FALSE;
3301*1da177e4SLinus Torvalds 
3302*1da177e4SLinus Torvalds 		return;
3303*1da177e4SLinus Torvalds 	}
3304*1da177e4SLinus Torvalds }
3305*1da177e4SLinus Torvalds 
3306*1da177e4SLinus Torvalds /****************************************************************************/
3307*1da177e4SLinus Torvalds /*                                                                          */
3308*1da177e4SLinus Torvalds /* Routine Name: ipsintr_done                                               */
3309*1da177e4SLinus Torvalds /*                                                                          */
3310*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3311*1da177e4SLinus Torvalds /*                                                                          */
3312*1da177e4SLinus Torvalds /*   Finalize an interrupt for non-internal commands                        */
3313*1da177e4SLinus Torvalds /*                                                                          */
3314*1da177e4SLinus Torvalds /****************************************************************************/
3315*1da177e4SLinus Torvalds static void
3316*1da177e4SLinus Torvalds ipsintr_done(ips_ha_t * ha, ips_scb_t * scb)
3317*1da177e4SLinus Torvalds {
3318*1da177e4SLinus Torvalds 	METHOD_TRACE("ipsintr_done", 2);
3319*1da177e4SLinus Torvalds 
3320*1da177e4SLinus Torvalds 	if (!scb) {
3321*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
3322*1da177e4SLinus Torvalds 			   "Spurious interrupt; scb NULL.\n");
3323*1da177e4SLinus Torvalds 
3324*1da177e4SLinus Torvalds 		return;
3325*1da177e4SLinus Torvalds 	}
3326*1da177e4SLinus Torvalds 
3327*1da177e4SLinus Torvalds 	if (scb->scsi_cmd == NULL) {
3328*1da177e4SLinus Torvalds 		/* unexpected interrupt */
3329*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
3330*1da177e4SLinus Torvalds 			   "Spurious interrupt; scsi_cmd not set.\n");
3331*1da177e4SLinus Torvalds 
3332*1da177e4SLinus Torvalds 		return;
3333*1da177e4SLinus Torvalds 	}
3334*1da177e4SLinus Torvalds 
3335*1da177e4SLinus Torvalds 	ips_done(ha, scb);
3336*1da177e4SLinus Torvalds }
3337*1da177e4SLinus Torvalds 
3338*1da177e4SLinus Torvalds /****************************************************************************/
3339*1da177e4SLinus Torvalds /*                                                                          */
3340*1da177e4SLinus Torvalds /* Routine Name: ips_done                                                   */
3341*1da177e4SLinus Torvalds /*                                                                          */
3342*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3343*1da177e4SLinus Torvalds /*                                                                          */
3344*1da177e4SLinus Torvalds /*   Do housekeeping on completed commands                                  */
3345*1da177e4SLinus Torvalds /*  ASSUMED to be called form within the request lock                       */
3346*1da177e4SLinus Torvalds /****************************************************************************/
3347*1da177e4SLinus Torvalds static void
3348*1da177e4SLinus Torvalds ips_done(ips_ha_t * ha, ips_scb_t * scb)
3349*1da177e4SLinus Torvalds {
3350*1da177e4SLinus Torvalds 	int ret;
3351*1da177e4SLinus Torvalds 
3352*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_done", 1);
3353*1da177e4SLinus Torvalds 
3354*1da177e4SLinus Torvalds 	if (!scb)
3355*1da177e4SLinus Torvalds 		return;
3356*1da177e4SLinus Torvalds 
3357*1da177e4SLinus Torvalds 	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
3358*1da177e4SLinus Torvalds 		ips_cleanup_passthru(ha, scb);
3359*1da177e4SLinus Torvalds 		ha->num_ioctl--;
3360*1da177e4SLinus Torvalds 	} else {
3361*1da177e4SLinus Torvalds 		/*
3362*1da177e4SLinus Torvalds 		 * Check to see if this command had too much
3363*1da177e4SLinus Torvalds 		 * data and had to be broke up.  If so, queue
3364*1da177e4SLinus Torvalds 		 * the rest of the data and continue.
3365*1da177e4SLinus Torvalds 		 */
3366*1da177e4SLinus Torvalds 		if ((scb->breakup) || (scb->sg_break)) {
3367*1da177e4SLinus Torvalds 			/* we had a data breakup */
3368*1da177e4SLinus Torvalds 			scb->data_len = 0;
3369*1da177e4SLinus Torvalds 
3370*1da177e4SLinus Torvalds 			if (scb->sg_count) {
3371*1da177e4SLinus Torvalds 				/* S/G request */
3372*1da177e4SLinus Torvalds 				struct scatterlist *sg;
3373*1da177e4SLinus Torvalds 				int ips_sg_index = 0;
3374*1da177e4SLinus Torvalds 				int sg_dma_index;
3375*1da177e4SLinus Torvalds 
3376*1da177e4SLinus Torvalds 				sg = scb->scsi_cmd->request_buffer;
3377*1da177e4SLinus Torvalds 
3378*1da177e4SLinus Torvalds 				/* Spin forward to last dma chunk */
3379*1da177e4SLinus Torvalds 				sg_dma_index = scb->breakup;
3380*1da177e4SLinus Torvalds 
3381*1da177e4SLinus Torvalds 				/* Take care of possible partial on last chunk */
3382*1da177e4SLinus Torvalds 				ips_fill_scb_sg_single(ha,
3383*1da177e4SLinus Torvalds 						       sg_dma_address(&sg
3384*1da177e4SLinus Torvalds 								      [sg_dma_index]),
3385*1da177e4SLinus Torvalds 						       scb, ips_sg_index++,
3386*1da177e4SLinus Torvalds 						       sg_dma_len(&sg
3387*1da177e4SLinus Torvalds 								  [sg_dma_index]));
3388*1da177e4SLinus Torvalds 
3389*1da177e4SLinus Torvalds 				for (; sg_dma_index < scb->sg_count;
3390*1da177e4SLinus Torvalds 				     sg_dma_index++) {
3391*1da177e4SLinus Torvalds 					if (ips_fill_scb_sg_single
3392*1da177e4SLinus Torvalds 					    (ha,
3393*1da177e4SLinus Torvalds 					     sg_dma_address(&sg[sg_dma_index]),
3394*1da177e4SLinus Torvalds 					     scb, ips_sg_index++,
3395*1da177e4SLinus Torvalds 					     sg_dma_len(&sg[sg_dma_index])) < 0)
3396*1da177e4SLinus Torvalds 						break;
3397*1da177e4SLinus Torvalds 
3398*1da177e4SLinus Torvalds 				}
3399*1da177e4SLinus Torvalds 
3400*1da177e4SLinus Torvalds 			} else {
3401*1da177e4SLinus Torvalds 				/* Non S/G Request */
3402*1da177e4SLinus Torvalds 				(void) ips_fill_scb_sg_single(ha,
3403*1da177e4SLinus Torvalds 							      scb->
3404*1da177e4SLinus Torvalds 							      data_busaddr +
3405*1da177e4SLinus Torvalds 							      (scb->sg_break *
3406*1da177e4SLinus Torvalds 							       ha->max_xfer),
3407*1da177e4SLinus Torvalds 							      scb, 0,
3408*1da177e4SLinus Torvalds 							      scb->scsi_cmd->
3409*1da177e4SLinus Torvalds 							      request_bufflen -
3410*1da177e4SLinus Torvalds 							      (scb->sg_break *
3411*1da177e4SLinus Torvalds 							       ha->max_xfer));
3412*1da177e4SLinus Torvalds 			}
3413*1da177e4SLinus Torvalds 
3414*1da177e4SLinus Torvalds 			scb->dcdb.transfer_length = scb->data_len;
3415*1da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |=
3416*1da177e4SLinus Torvalds 			    ips_command_direction[scb->scsi_cmd->cmnd[0]];
3417*1da177e4SLinus Torvalds 
3418*1da177e4SLinus Torvalds 			if (!(scb->dcdb.cmd_attribute & 0x3))
3419*1da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
3420*1da177e4SLinus Torvalds 
3421*1da177e4SLinus Torvalds 			if (scb->data_len >= IPS_MAX_XFER) {
3422*1da177e4SLinus Torvalds 				scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
3423*1da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
3424*1da177e4SLinus Torvalds 			}
3425*1da177e4SLinus Torvalds 
3426*1da177e4SLinus Torvalds 			ret = ips_send_cmd(ha, scb);
3427*1da177e4SLinus Torvalds 
3428*1da177e4SLinus Torvalds 			switch (ret) {
3429*1da177e4SLinus Torvalds 			case IPS_FAILURE:
3430*1da177e4SLinus Torvalds 				if (scb->scsi_cmd) {
3431*1da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_ERROR << 16;
3432*1da177e4SLinus Torvalds 					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
3433*1da177e4SLinus Torvalds 				}
3434*1da177e4SLinus Torvalds 
3435*1da177e4SLinus Torvalds 				ips_freescb(ha, scb);
3436*1da177e4SLinus Torvalds 				break;
3437*1da177e4SLinus Torvalds 			case IPS_SUCCESS_IMM:
3438*1da177e4SLinus Torvalds 				if (scb->scsi_cmd) {
3439*1da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_ERROR << 16;
3440*1da177e4SLinus Torvalds 					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
3441*1da177e4SLinus Torvalds 				}
3442*1da177e4SLinus Torvalds 
3443*1da177e4SLinus Torvalds 				ips_freescb(ha, scb);
3444*1da177e4SLinus Torvalds 				break;
3445*1da177e4SLinus Torvalds 			default:
3446*1da177e4SLinus Torvalds 				break;
3447*1da177e4SLinus Torvalds 			}	/* end case */
3448*1da177e4SLinus Torvalds 
3449*1da177e4SLinus Torvalds 			return;
3450*1da177e4SLinus Torvalds 		}
3451*1da177e4SLinus Torvalds 	}			/* end if passthru */
3452*1da177e4SLinus Torvalds 
3453*1da177e4SLinus Torvalds 	if (scb->bus) {
3454*1da177e4SLinus Torvalds 		ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id);
3455*1da177e4SLinus Torvalds 	}
3456*1da177e4SLinus Torvalds 
3457*1da177e4SLinus Torvalds 	scb->scsi_cmd->scsi_done(scb->scsi_cmd);
3458*1da177e4SLinus Torvalds 
3459*1da177e4SLinus Torvalds 	ips_freescb(ha, scb);
3460*1da177e4SLinus Torvalds }
3461*1da177e4SLinus Torvalds 
3462*1da177e4SLinus Torvalds /****************************************************************************/
3463*1da177e4SLinus Torvalds /*                                                                          */
3464*1da177e4SLinus Torvalds /* Routine Name: ips_map_status                                             */
3465*1da177e4SLinus Torvalds /*                                                                          */
3466*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3467*1da177e4SLinus Torvalds /*                                                                          */
3468*1da177e4SLinus Torvalds /*   Map Controller Error codes to Linux Error Codes                        */
3469*1da177e4SLinus Torvalds /*                                                                          */
3470*1da177e4SLinus Torvalds /****************************************************************************/
3471*1da177e4SLinus Torvalds static int
3472*1da177e4SLinus Torvalds ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
3473*1da177e4SLinus Torvalds {
3474*1da177e4SLinus Torvalds 	int errcode;
3475*1da177e4SLinus Torvalds 	int device_error;
3476*1da177e4SLinus Torvalds 	uint32_t transfer_len;
3477*1da177e4SLinus Torvalds 	IPS_DCDB_TABLE_TAPE *tapeDCDB;
3478*1da177e4SLinus Torvalds 
3479*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_map_status", 1);
3480*1da177e4SLinus Torvalds 
3481*1da177e4SLinus Torvalds 	if (scb->bus) {
3482*1da177e4SLinus Torvalds 		DEBUG_VAR(2,
3483*1da177e4SLinus Torvalds 			  "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
3484*1da177e4SLinus Torvalds 			  ips_name, ha->host_num,
3485*1da177e4SLinus Torvalds 			  scb->scsi_cmd->device->channel,
3486*1da177e4SLinus Torvalds 			  scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun,
3487*1da177e4SLinus Torvalds 			  scb->basic_status, scb->extended_status,
3488*1da177e4SLinus Torvalds 			  scb->extended_status ==
3489*1da177e4SLinus Torvalds 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
3490*1da177e4SLinus Torvalds 			  scb->extended_status ==
3491*1da177e4SLinus Torvalds 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
3492*1da177e4SLinus Torvalds 			  scb->extended_status ==
3493*1da177e4SLinus Torvalds 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
3494*1da177e4SLinus Torvalds 	}
3495*1da177e4SLinus Torvalds 
3496*1da177e4SLinus Torvalds 	/* default driver error */
3497*1da177e4SLinus Torvalds 	errcode = DID_ERROR;
3498*1da177e4SLinus Torvalds 	device_error = 0;
3499*1da177e4SLinus Torvalds 
3500*1da177e4SLinus Torvalds 	switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
3501*1da177e4SLinus Torvalds 	case IPS_CMD_TIMEOUT:
3502*1da177e4SLinus Torvalds 		errcode = DID_TIME_OUT;
3503*1da177e4SLinus Torvalds 		break;
3504*1da177e4SLinus Torvalds 
3505*1da177e4SLinus Torvalds 	case IPS_INVAL_OPCO:
3506*1da177e4SLinus Torvalds 	case IPS_INVAL_CMD_BLK:
3507*1da177e4SLinus Torvalds 	case IPS_INVAL_PARM_BLK:
3508*1da177e4SLinus Torvalds 	case IPS_LD_ERROR:
3509*1da177e4SLinus Torvalds 	case IPS_CMD_CMPLT_WERROR:
3510*1da177e4SLinus Torvalds 		break;
3511*1da177e4SLinus Torvalds 
3512*1da177e4SLinus Torvalds 	case IPS_PHYS_DRV_ERROR:
3513*1da177e4SLinus Torvalds 		switch (scb->extended_status) {
3514*1da177e4SLinus Torvalds 		case IPS_ERR_SEL_TO:
3515*1da177e4SLinus Torvalds 			if (scb->bus)
3516*1da177e4SLinus Torvalds 				errcode = DID_NO_CONNECT;
3517*1da177e4SLinus Torvalds 
3518*1da177e4SLinus Torvalds 			break;
3519*1da177e4SLinus Torvalds 
3520*1da177e4SLinus Torvalds 		case IPS_ERR_OU_RUN:
3521*1da177e4SLinus Torvalds 			if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
3522*1da177e4SLinus Torvalds 			    (scb->cmd.dcdb.op_code ==
3523*1da177e4SLinus Torvalds 			     IPS_CMD_EXTENDED_DCDB_SG)) {
3524*1da177e4SLinus Torvalds 				tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
3525*1da177e4SLinus Torvalds 				transfer_len = tapeDCDB->transfer_length;
3526*1da177e4SLinus Torvalds 			} else {
3527*1da177e4SLinus Torvalds 				transfer_len =
3528*1da177e4SLinus Torvalds 				    (uint32_t) scb->dcdb.transfer_length;
3529*1da177e4SLinus Torvalds 			}
3530*1da177e4SLinus Torvalds 
3531*1da177e4SLinus Torvalds 			if ((scb->bus) && (transfer_len < scb->data_len)) {
3532*1da177e4SLinus Torvalds 				/* Underrun - set default to no error */
3533*1da177e4SLinus Torvalds 				errcode = DID_OK;
3534*1da177e4SLinus Torvalds 
3535*1da177e4SLinus Torvalds 				/* Restrict access to physical DASD */
3536*1da177e4SLinus Torvalds 				if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
3537*1da177e4SLinus Torvalds 				    ((((char *) scb->scsi_cmd->
3538*1da177e4SLinus Torvalds 				       buffer)[0] & 0x1f) == TYPE_DISK)) {
3539*1da177e4SLinus Torvalds 					/* underflow -- no error               */
3540*1da177e4SLinus Torvalds 					/* restrict access to physical DASD    */
3541*1da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
3542*1da177e4SLinus Torvalds 					break;
3543*1da177e4SLinus Torvalds 				}
3544*1da177e4SLinus Torvalds 			} else
3545*1da177e4SLinus Torvalds 				errcode = DID_ERROR;
3546*1da177e4SLinus Torvalds 
3547*1da177e4SLinus Torvalds 			break;
3548*1da177e4SLinus Torvalds 
3549*1da177e4SLinus Torvalds 		case IPS_ERR_RECOVERY:
3550*1da177e4SLinus Torvalds 			/* don't fail recovered errors */
3551*1da177e4SLinus Torvalds 			if (scb->bus)
3552*1da177e4SLinus Torvalds 				errcode = DID_OK;
3553*1da177e4SLinus Torvalds 
3554*1da177e4SLinus Torvalds 			break;
3555*1da177e4SLinus Torvalds 
3556*1da177e4SLinus Torvalds 		case IPS_ERR_HOST_RESET:
3557*1da177e4SLinus Torvalds 		case IPS_ERR_DEV_RESET:
3558*1da177e4SLinus Torvalds 			errcode = DID_RESET;
3559*1da177e4SLinus Torvalds 			break;
3560*1da177e4SLinus Torvalds 
3561*1da177e4SLinus Torvalds 		case IPS_ERR_CKCOND:
3562*1da177e4SLinus Torvalds 			if (scb->bus) {
3563*1da177e4SLinus Torvalds 				if ((scb->cmd.dcdb.op_code ==
3564*1da177e4SLinus Torvalds 				     IPS_CMD_EXTENDED_DCDB)
3565*1da177e4SLinus Torvalds 				    || (scb->cmd.dcdb.op_code ==
3566*1da177e4SLinus Torvalds 					IPS_CMD_EXTENDED_DCDB_SG)) {
3567*1da177e4SLinus Torvalds 					tapeDCDB =
3568*1da177e4SLinus Torvalds 					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
3569*1da177e4SLinus Torvalds 					memcpy(scb->scsi_cmd->sense_buffer,
3570*1da177e4SLinus Torvalds 					       tapeDCDB->sense_info,
3571*1da177e4SLinus Torvalds 					       sizeof (scb->scsi_cmd->
3572*1da177e4SLinus Torvalds 						       sense_buffer));
3573*1da177e4SLinus Torvalds 				} else {
3574*1da177e4SLinus Torvalds 					memcpy(scb->scsi_cmd->sense_buffer,
3575*1da177e4SLinus Torvalds 					       scb->dcdb.sense_info,
3576*1da177e4SLinus Torvalds 					       sizeof (scb->scsi_cmd->
3577*1da177e4SLinus Torvalds 						       sense_buffer));
3578*1da177e4SLinus Torvalds 				}
3579*1da177e4SLinus Torvalds 				device_error = 2;	/* check condition */
3580*1da177e4SLinus Torvalds 			}
3581*1da177e4SLinus Torvalds 
3582*1da177e4SLinus Torvalds 			errcode = DID_OK;
3583*1da177e4SLinus Torvalds 
3584*1da177e4SLinus Torvalds 			break;
3585*1da177e4SLinus Torvalds 
3586*1da177e4SLinus Torvalds 		default:
3587*1da177e4SLinus Torvalds 			errcode = DID_ERROR;
3588*1da177e4SLinus Torvalds 			break;
3589*1da177e4SLinus Torvalds 
3590*1da177e4SLinus Torvalds 		}		/* end switch */
3591*1da177e4SLinus Torvalds 	}			/* end switch */
3592*1da177e4SLinus Torvalds 
3593*1da177e4SLinus Torvalds 	scb->scsi_cmd->result = device_error | (errcode << 16);
3594*1da177e4SLinus Torvalds 
3595*1da177e4SLinus Torvalds 	return (1);
3596*1da177e4SLinus Torvalds }
3597*1da177e4SLinus Torvalds 
3598*1da177e4SLinus Torvalds /****************************************************************************/
3599*1da177e4SLinus Torvalds /*                                                                          */
3600*1da177e4SLinus Torvalds /* Routine Name: ips_send_wait                                              */
3601*1da177e4SLinus Torvalds /*                                                                          */
3602*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3603*1da177e4SLinus Torvalds /*                                                                          */
3604*1da177e4SLinus Torvalds /*   Send a command to the controller and wait for it to return             */
3605*1da177e4SLinus Torvalds /*                                                                          */
3606*1da177e4SLinus Torvalds /*   The FFDC Time Stamp use this function for the callback, but doesn't    */
3607*1da177e4SLinus Torvalds /*   actually need to wait.                                                 */
3608*1da177e4SLinus Torvalds /****************************************************************************/
3609*1da177e4SLinus Torvalds static int
3610*1da177e4SLinus Torvalds ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
3611*1da177e4SLinus Torvalds {
3612*1da177e4SLinus Torvalds 	int ret;
3613*1da177e4SLinus Torvalds 
3614*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_send_wait", 1);
3615*1da177e4SLinus Torvalds 
3616*1da177e4SLinus Torvalds 	if (intr != IPS_FFDC) {	/* Won't be Waiting if this is a Time Stamp */
3617*1da177e4SLinus Torvalds 		ha->waitflag = TRUE;
3618*1da177e4SLinus Torvalds 		ha->cmd_in_progress = scb->cdb[0];
3619*1da177e4SLinus Torvalds 	}
3620*1da177e4SLinus Torvalds 	scb->callback = ipsintr_blocking;
3621*1da177e4SLinus Torvalds 	ret = ips_send_cmd(ha, scb);
3622*1da177e4SLinus Torvalds 
3623*1da177e4SLinus Torvalds 	if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
3624*1da177e4SLinus Torvalds 		return (ret);
3625*1da177e4SLinus Torvalds 
3626*1da177e4SLinus Torvalds 	if (intr != IPS_FFDC)	/* Don't Wait around if this is a Time Stamp */
3627*1da177e4SLinus Torvalds 		ret = ips_wait(ha, timeout, intr);
3628*1da177e4SLinus Torvalds 
3629*1da177e4SLinus Torvalds 	return (ret);
3630*1da177e4SLinus Torvalds }
3631*1da177e4SLinus Torvalds 
3632*1da177e4SLinus Torvalds /****************************************************************************/
3633*1da177e4SLinus Torvalds /*                                                                          */
3634*1da177e4SLinus Torvalds /* Routine Name: ips_scmd_buf_write                                         */
3635*1da177e4SLinus Torvalds /*                                                                          */
3636*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3637*1da177e4SLinus Torvalds /*  Write data to Scsi_Cmnd request_buffer at proper offsets                */
3638*1da177e4SLinus Torvalds /****************************************************************************/
3639*1da177e4SLinus Torvalds static void
3640*1da177e4SLinus Torvalds ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
3641*1da177e4SLinus Torvalds 		   int count)
3642*1da177e4SLinus Torvalds {
3643*1da177e4SLinus Torvalds 	if (scmd->use_sg) {
3644*1da177e4SLinus Torvalds 		int i;
3645*1da177e4SLinus Torvalds 		unsigned int min_cnt, xfer_cnt;
3646*1da177e4SLinus Torvalds 		char *cdata = (char *) data;
3647*1da177e4SLinus Torvalds 		struct scatterlist *sg = scmd->request_buffer;
3648*1da177e4SLinus Torvalds 		for (i = 0, xfer_cnt = 0;
3649*1da177e4SLinus Torvalds 		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
3650*1da177e4SLinus Torvalds 			if (!IPS_SG_ADDRESS(&sg[i]))
3651*1da177e4SLinus Torvalds 				return;
3652*1da177e4SLinus Torvalds 			min_cnt = min(count - xfer_cnt, sg[i].length);
3653*1da177e4SLinus Torvalds 			memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt],
3654*1da177e4SLinus Torvalds 			       min_cnt);
3655*1da177e4SLinus Torvalds 			xfer_cnt += min_cnt;
3656*1da177e4SLinus Torvalds 		}
3657*1da177e4SLinus Torvalds 
3658*1da177e4SLinus Torvalds 	} else {
3659*1da177e4SLinus Torvalds 		unsigned int min_cnt = min(count, scmd->request_bufflen);
3660*1da177e4SLinus Torvalds 		memcpy(scmd->request_buffer, data, min_cnt);
3661*1da177e4SLinus Torvalds 	}
3662*1da177e4SLinus Torvalds }
3663*1da177e4SLinus Torvalds 
3664*1da177e4SLinus Torvalds /****************************************************************************/
3665*1da177e4SLinus Torvalds /*                                                                          */
3666*1da177e4SLinus Torvalds /* Routine Name: ips_scmd_buf_read                                          */
3667*1da177e4SLinus Torvalds /*                                                                          */
3668*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3669*1da177e4SLinus Torvalds /*  Copy data from a Scsi_Cmnd to a new, linear buffer                      */
3670*1da177e4SLinus Torvalds /****************************************************************************/
3671*1da177e4SLinus Torvalds static void
3672*1da177e4SLinus Torvalds ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
3673*1da177e4SLinus Torvalds 		  int count)
3674*1da177e4SLinus Torvalds {
3675*1da177e4SLinus Torvalds 	if (scmd->use_sg) {
3676*1da177e4SLinus Torvalds 		int i;
3677*1da177e4SLinus Torvalds 		unsigned int min_cnt, xfer_cnt;
3678*1da177e4SLinus Torvalds 		char *cdata = (char *) data;
3679*1da177e4SLinus Torvalds 		struct scatterlist *sg = scmd->request_buffer;
3680*1da177e4SLinus Torvalds 		for (i = 0, xfer_cnt = 0;
3681*1da177e4SLinus Torvalds 		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
3682*1da177e4SLinus Torvalds 			if (!IPS_SG_ADDRESS(&sg[i]))
3683*1da177e4SLinus Torvalds 				return;
3684*1da177e4SLinus Torvalds 			min_cnt = min(count - xfer_cnt, sg[i].length);
3685*1da177e4SLinus Torvalds 			memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]),
3686*1da177e4SLinus Torvalds 			       min_cnt);
3687*1da177e4SLinus Torvalds 			xfer_cnt += min_cnt;
3688*1da177e4SLinus Torvalds 		}
3689*1da177e4SLinus Torvalds 
3690*1da177e4SLinus Torvalds 	} else {
3691*1da177e4SLinus Torvalds 		unsigned int min_cnt = min(count, scmd->request_bufflen);
3692*1da177e4SLinus Torvalds 		memcpy(data, scmd->request_buffer, min_cnt);
3693*1da177e4SLinus Torvalds 	}
3694*1da177e4SLinus Torvalds }
3695*1da177e4SLinus Torvalds 
3696*1da177e4SLinus Torvalds /****************************************************************************/
3697*1da177e4SLinus Torvalds /*                                                                          */
3698*1da177e4SLinus Torvalds /* Routine Name: ips_send_cmd                                               */
3699*1da177e4SLinus Torvalds /*                                                                          */
3700*1da177e4SLinus Torvalds /* Routine Description:                                                     */
3701*1da177e4SLinus Torvalds /*                                                                          */
3702*1da177e4SLinus Torvalds /*   Map SCSI commands to ServeRAID commands for logical drives             */
3703*1da177e4SLinus Torvalds /*                                                                          */
3704*1da177e4SLinus Torvalds /****************************************************************************/
3705*1da177e4SLinus Torvalds static int
3706*1da177e4SLinus Torvalds ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
3707*1da177e4SLinus Torvalds {
3708*1da177e4SLinus Torvalds 	int ret;
3709*1da177e4SLinus Torvalds 	char *sp;
3710*1da177e4SLinus Torvalds 	int device_error;
3711*1da177e4SLinus Torvalds 	IPS_DCDB_TABLE_TAPE *tapeDCDB;
3712*1da177e4SLinus Torvalds 	int TimeOut;
3713*1da177e4SLinus Torvalds 
3714*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_send_cmd", 1);
3715*1da177e4SLinus Torvalds 
3716*1da177e4SLinus Torvalds 	ret = IPS_SUCCESS;
3717*1da177e4SLinus Torvalds 
3718*1da177e4SLinus Torvalds 	if (!scb->scsi_cmd) {
3719*1da177e4SLinus Torvalds 		/* internal command */
3720*1da177e4SLinus Torvalds 
3721*1da177e4SLinus Torvalds 		if (scb->bus > 0) {
3722*1da177e4SLinus Torvalds 			/* Controller commands can't be issued */
3723*1da177e4SLinus Torvalds 			/* to real devices -- fail them        */
3724*1da177e4SLinus Torvalds 			if ((ha->waitflag == TRUE) &&
3725*1da177e4SLinus Torvalds 			    (ha->cmd_in_progress == scb->cdb[0])) {
3726*1da177e4SLinus Torvalds 				ha->waitflag = FALSE;
3727*1da177e4SLinus Torvalds 			}
3728*1da177e4SLinus Torvalds 
3729*1da177e4SLinus Torvalds 			return (1);
3730*1da177e4SLinus Torvalds 		}
3731*1da177e4SLinus Torvalds 	} else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
3732*1da177e4SLinus Torvalds 		/* command to logical bus -- interpret */
3733*1da177e4SLinus Torvalds 		ret = IPS_SUCCESS_IMM;
3734*1da177e4SLinus Torvalds 
3735*1da177e4SLinus Torvalds 		switch (scb->scsi_cmd->cmnd[0]) {
3736*1da177e4SLinus Torvalds 		case ALLOW_MEDIUM_REMOVAL:
3737*1da177e4SLinus Torvalds 		case REZERO_UNIT:
3738*1da177e4SLinus Torvalds 		case ERASE:
3739*1da177e4SLinus Torvalds 		case WRITE_FILEMARKS:
3740*1da177e4SLinus Torvalds 		case SPACE:
3741*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_ERROR << 16;
3742*1da177e4SLinus Torvalds 			break;
3743*1da177e4SLinus Torvalds 
3744*1da177e4SLinus Torvalds 		case START_STOP:
3745*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
3746*1da177e4SLinus Torvalds 
3747*1da177e4SLinus Torvalds 		case TEST_UNIT_READY:
3748*1da177e4SLinus Torvalds 		case INQUIRY:
3749*1da177e4SLinus Torvalds 			if (scb->target_id == IPS_ADAPTER_ID) {
3750*1da177e4SLinus Torvalds 				/*
3751*1da177e4SLinus Torvalds 				 * Either we have a TUR
3752*1da177e4SLinus Torvalds 				 * or we have a SCSI inquiry
3753*1da177e4SLinus Torvalds 				 */
3754*1da177e4SLinus Torvalds 				if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
3755*1da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_OK << 16;
3756*1da177e4SLinus Torvalds 
3757*1da177e4SLinus Torvalds 				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
3758*1da177e4SLinus Torvalds 					IPS_SCSI_INQ_DATA inquiry;
3759*1da177e4SLinus Torvalds 
3760*1da177e4SLinus Torvalds 					memset(&inquiry, 0,
3761*1da177e4SLinus Torvalds 					       sizeof (IPS_SCSI_INQ_DATA));
3762*1da177e4SLinus Torvalds 
3763*1da177e4SLinus Torvalds 					inquiry.DeviceType =
3764*1da177e4SLinus Torvalds 					    IPS_SCSI_INQ_TYPE_PROCESSOR;
3765*1da177e4SLinus Torvalds 					inquiry.DeviceTypeQualifier =
3766*1da177e4SLinus Torvalds 					    IPS_SCSI_INQ_LU_CONNECTED;
3767*1da177e4SLinus Torvalds 					inquiry.Version = IPS_SCSI_INQ_REV2;
3768*1da177e4SLinus Torvalds 					inquiry.ResponseDataFormat =
3769*1da177e4SLinus Torvalds 					    IPS_SCSI_INQ_RD_REV2;
3770*1da177e4SLinus Torvalds 					inquiry.AdditionalLength = 31;
3771*1da177e4SLinus Torvalds 					inquiry.Flags[0] =
3772*1da177e4SLinus Torvalds 					    IPS_SCSI_INQ_Address16;
3773*1da177e4SLinus Torvalds 					inquiry.Flags[1] =
3774*1da177e4SLinus Torvalds 					    IPS_SCSI_INQ_WBus16 |
3775*1da177e4SLinus Torvalds 					    IPS_SCSI_INQ_Sync;
3776*1da177e4SLinus Torvalds 					strncpy(inquiry.VendorId, "IBM     ",
3777*1da177e4SLinus Torvalds 						8);
3778*1da177e4SLinus Torvalds 					strncpy(inquiry.ProductId,
3779*1da177e4SLinus Torvalds 						"SERVERAID       ", 16);
3780*1da177e4SLinus Torvalds 					strncpy(inquiry.ProductRevisionLevel,
3781*1da177e4SLinus Torvalds 						"1.00", 4);
3782*1da177e4SLinus Torvalds 
3783*1da177e4SLinus Torvalds 					ips_scmd_buf_write(scb->scsi_cmd,
3784*1da177e4SLinus Torvalds 							   &inquiry,
3785*1da177e4SLinus Torvalds 							   sizeof (inquiry));
3786*1da177e4SLinus Torvalds 
3787*1da177e4SLinus Torvalds 					scb->scsi_cmd->result = DID_OK << 16;
3788*1da177e4SLinus Torvalds 				}
3789*1da177e4SLinus Torvalds 			} else {
3790*1da177e4SLinus Torvalds 				scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
3791*1da177e4SLinus Torvalds 				scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
3792*1da177e4SLinus Torvalds 				scb->cmd.logical_info.reserved = 0;
3793*1da177e4SLinus Torvalds 				scb->cmd.logical_info.reserved2 = 0;
3794*1da177e4SLinus Torvalds 				scb->data_len = sizeof (IPS_LD_INFO);
3795*1da177e4SLinus Torvalds 				scb->data_busaddr = ha->logical_drive_info_dma_addr;
3796*1da177e4SLinus Torvalds 				scb->flags = 0;
3797*1da177e4SLinus Torvalds 				scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
3798*1da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
3799*1da177e4SLinus Torvalds 			}
3800*1da177e4SLinus Torvalds 
3801*1da177e4SLinus Torvalds 			break;
3802*1da177e4SLinus Torvalds 
3803*1da177e4SLinus Torvalds 		case REQUEST_SENSE:
3804*1da177e4SLinus Torvalds 			ips_reqsen(ha, scb);
3805*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
3806*1da177e4SLinus Torvalds 			break;
3807*1da177e4SLinus Torvalds 
3808*1da177e4SLinus Torvalds 		case READ_6:
3809*1da177e4SLinus Torvalds 		case WRITE_6:
3810*1da177e4SLinus Torvalds 			if (!scb->sg_len) {
3811*1da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
3812*1da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
3813*1da177e4SLinus Torvalds 				     READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
3814*1da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg = 0;
3815*1da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
3816*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
3817*1da177e4SLinus Torvalds 			} else {
3818*1da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
3819*1da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
3820*1da177e4SLinus Torvalds 				     READ_6) ? IPS_CMD_READ_SG :
3821*1da177e4SLinus Torvalds 				    IPS_CMD_WRITE_SG;
3822*1da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg =
3823*1da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
3824*1da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
3825*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
3826*1da177e4SLinus Torvalds 			}
3827*1da177e4SLinus Torvalds 
3828*1da177e4SLinus Torvalds 			scb->cmd.basic_io.segment_4G = 0;
3829*1da177e4SLinus Torvalds 			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
3830*1da177e4SLinus Torvalds 			scb->cmd.basic_io.log_drv = scb->target_id;
3831*1da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_count = scb->sg_len;
3832*1da177e4SLinus Torvalds 
3833*1da177e4SLinus Torvalds 			if (scb->cmd.basic_io.lba)
3834*1da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
3835*1da177e4SLinus Torvalds 				    cpu_to_le32(le32_to_cpu
3836*1da177e4SLinus Torvalds 						(scb->cmd.basic_io.lba) +
3837*1da177e4SLinus Torvalds 						le16_to_cpu(scb->cmd.basic_io.
3838*1da177e4SLinus Torvalds 							    sector_count));
3839*1da177e4SLinus Torvalds 			else
3840*1da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
3841*1da177e4SLinus Torvalds 				    (((scb->scsi_cmd->
3842*1da177e4SLinus Torvalds 				       cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd->
3843*1da177e4SLinus Torvalds 								 cmnd[2] << 8) |
3844*1da177e4SLinus Torvalds 				     (scb->scsi_cmd->cmnd[3]));
3845*1da177e4SLinus Torvalds 
3846*1da177e4SLinus Torvalds 			scb->cmd.basic_io.sector_count =
3847*1da177e4SLinus Torvalds 			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
3848*1da177e4SLinus Torvalds 
3849*1da177e4SLinus Torvalds 			if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
3850*1da177e4SLinus Torvalds 				scb->cmd.basic_io.sector_count =
3851*1da177e4SLinus Torvalds 				    cpu_to_le16(256);
3852*1da177e4SLinus Torvalds 
3853*1da177e4SLinus Torvalds 			ret = IPS_SUCCESS;
3854*1da177e4SLinus Torvalds 			break;
3855*1da177e4SLinus Torvalds 
3856*1da177e4SLinus Torvalds 		case READ_10:
3857*1da177e4SLinus Torvalds 		case WRITE_10:
3858*1da177e4SLinus Torvalds 			if (!scb->sg_len) {
3859*1da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
3860*1da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
3861*1da177e4SLinus Torvalds 				     READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
3862*1da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg = 0;
3863*1da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
3864*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
3865*1da177e4SLinus Torvalds 			} else {
3866*1da177e4SLinus Torvalds 				scb->cmd.basic_io.op_code =
3867*1da177e4SLinus Torvalds 				    (scb->scsi_cmd->cmnd[0] ==
3868*1da177e4SLinus Torvalds 				     READ_10) ? IPS_CMD_READ_SG :
3869*1da177e4SLinus Torvalds 				    IPS_CMD_WRITE_SG;
3870*1da177e4SLinus Torvalds 				scb->cmd.basic_io.enhanced_sg =
3871*1da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
3872*1da177e4SLinus Torvalds 				scb->cmd.basic_io.sg_addr =
3873*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
3874*1da177e4SLinus Torvalds 			}
3875*1da177e4SLinus Torvalds 
3876*1da177e4SLinus Torvalds 			scb->cmd.basic_io.segment_4G = 0;
3877*1da177e4SLinus Torvalds 			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
3878*1da177e4SLinus Torvalds 			scb->cmd.basic_io.log_drv = scb->target_id;
3879*1da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_count = scb->sg_len;
3880*1da177e4SLinus Torvalds 
3881*1da177e4SLinus Torvalds 			if (scb->cmd.basic_io.lba)
3882*1da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
3883*1da177e4SLinus Torvalds 				    cpu_to_le32(le32_to_cpu
3884*1da177e4SLinus Torvalds 						(scb->cmd.basic_io.lba) +
3885*1da177e4SLinus Torvalds 						le16_to_cpu(scb->cmd.basic_io.
3886*1da177e4SLinus Torvalds 							    sector_count));
3887*1da177e4SLinus Torvalds 			else
3888*1da177e4SLinus Torvalds 				scb->cmd.basic_io.lba =
3889*1da177e4SLinus Torvalds 				    ((scb->scsi_cmd->cmnd[2] << 24) | (scb->
3890*1da177e4SLinus Torvalds 								       scsi_cmd->
3891*1da177e4SLinus Torvalds 								       cmnd[3]
3892*1da177e4SLinus Torvalds 								       << 16) |
3893*1da177e4SLinus Torvalds 				     (scb->scsi_cmd->cmnd[4] << 8) | scb->
3894*1da177e4SLinus Torvalds 				     scsi_cmd->cmnd[5]);
3895*1da177e4SLinus Torvalds 
3896*1da177e4SLinus Torvalds 			scb->cmd.basic_io.sector_count =
3897*1da177e4SLinus Torvalds 			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
3898*1da177e4SLinus Torvalds 
3899*1da177e4SLinus Torvalds 			if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
3900*1da177e4SLinus Torvalds 				/*
3901*1da177e4SLinus Torvalds 				 * This is a null condition
3902*1da177e4SLinus Torvalds 				 * we don't have to do anything
3903*1da177e4SLinus Torvalds 				 * so just return
3904*1da177e4SLinus Torvalds 				 */
3905*1da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_OK << 16;
3906*1da177e4SLinus Torvalds 			} else
3907*1da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
3908*1da177e4SLinus Torvalds 
3909*1da177e4SLinus Torvalds 			break;
3910*1da177e4SLinus Torvalds 
3911*1da177e4SLinus Torvalds 		case RESERVE:
3912*1da177e4SLinus Torvalds 		case RELEASE:
3913*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
3914*1da177e4SLinus Torvalds 			break;
3915*1da177e4SLinus Torvalds 
3916*1da177e4SLinus Torvalds 		case MODE_SENSE:
3917*1da177e4SLinus Torvalds 			scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
3918*1da177e4SLinus Torvalds 			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
3919*1da177e4SLinus Torvalds 			scb->cmd.basic_io.segment_4G = 0;
3920*1da177e4SLinus Torvalds 			scb->cmd.basic_io.enhanced_sg = 0;
3921*1da177e4SLinus Torvalds 			scb->data_len = sizeof (*ha->enq);
3922*1da177e4SLinus Torvalds 			scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
3923*1da177e4SLinus Torvalds 			ret = IPS_SUCCESS;
3924*1da177e4SLinus Torvalds 			break;
3925*1da177e4SLinus Torvalds 
3926*1da177e4SLinus Torvalds 		case READ_CAPACITY:
3927*1da177e4SLinus Torvalds 			scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
3928*1da177e4SLinus Torvalds 			scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
3929*1da177e4SLinus Torvalds 			scb->cmd.logical_info.reserved = 0;
3930*1da177e4SLinus Torvalds 			scb->cmd.logical_info.reserved2 = 0;
3931*1da177e4SLinus Torvalds 			scb->cmd.logical_info.reserved3 = 0;
3932*1da177e4SLinus Torvalds 			scb->data_len = sizeof (IPS_LD_INFO);
3933*1da177e4SLinus Torvalds 			scb->data_busaddr = ha->logical_drive_info_dma_addr;
3934*1da177e4SLinus Torvalds 			scb->flags = 0;
3935*1da177e4SLinus Torvalds 			scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
3936*1da177e4SLinus Torvalds 			ret = IPS_SUCCESS;
3937*1da177e4SLinus Torvalds 			break;
3938*1da177e4SLinus Torvalds 
3939*1da177e4SLinus Torvalds 		case SEND_DIAGNOSTIC:
3940*1da177e4SLinus Torvalds 		case REASSIGN_BLOCKS:
3941*1da177e4SLinus Torvalds 		case FORMAT_UNIT:
3942*1da177e4SLinus Torvalds 		case SEEK_10:
3943*1da177e4SLinus Torvalds 		case VERIFY:
3944*1da177e4SLinus Torvalds 		case READ_DEFECT_DATA:
3945*1da177e4SLinus Torvalds 		case READ_BUFFER:
3946*1da177e4SLinus Torvalds 		case WRITE_BUFFER:
3947*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_OK << 16;
3948*1da177e4SLinus Torvalds 			break;
3949*1da177e4SLinus Torvalds 
3950*1da177e4SLinus Torvalds 		default:
3951*1da177e4SLinus Torvalds 			/* Set the Return Info to appear like the Command was */
3952*1da177e4SLinus Torvalds 			/* attempted, a Check Condition occurred, and Sense   */
3953*1da177e4SLinus Torvalds 			/* Data indicating an Invalid CDB OpCode is returned. */
3954*1da177e4SLinus Torvalds 			sp = (char *) scb->scsi_cmd->sense_buffer;
3955*1da177e4SLinus Torvalds 			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
3956*1da177e4SLinus Torvalds 
3957*1da177e4SLinus Torvalds 			sp[0] = 0x70;	/* Error Code               */
3958*1da177e4SLinus Torvalds 			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
3959*1da177e4SLinus Torvalds 			sp[7] = 0x0A;	/* Additional Sense Length  */
3960*1da177e4SLinus Torvalds 			sp[12] = 0x20;	/* ASC = Invalid OpCode     */
3961*1da177e4SLinus Torvalds 			sp[13] = 0x00;	/* ASCQ                     */
3962*1da177e4SLinus Torvalds 
3963*1da177e4SLinus Torvalds 			device_error = 2;	/* Indicate Check Condition */
3964*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = device_error | (DID_OK << 16);
3965*1da177e4SLinus Torvalds 			break;
3966*1da177e4SLinus Torvalds 		}		/* end switch */
3967*1da177e4SLinus Torvalds 	}
3968*1da177e4SLinus Torvalds 	/* end if */
3969*1da177e4SLinus Torvalds 	if (ret == IPS_SUCCESS_IMM)
3970*1da177e4SLinus Torvalds 		return (ret);
3971*1da177e4SLinus Torvalds 
3972*1da177e4SLinus Torvalds 	/* setup DCDB */
3973*1da177e4SLinus Torvalds 	if (scb->bus > 0) {
3974*1da177e4SLinus Torvalds 
3975*1da177e4SLinus Torvalds 		/* If we already know the Device is Not there, no need to attempt a Command   */
3976*1da177e4SLinus Torvalds 		/* This also protects an NT FailOver Controller from getting CDB's sent to it */
3977*1da177e4SLinus Torvalds 		if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) {
3978*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = DID_NO_CONNECT << 16;
3979*1da177e4SLinus Torvalds 			return (IPS_SUCCESS_IMM);
3980*1da177e4SLinus Torvalds 		}
3981*1da177e4SLinus Torvalds 
3982*1da177e4SLinus Torvalds 		ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id);
3983*1da177e4SLinus Torvalds 		scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
3984*1da177e4SLinus Torvalds 		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
3985*1da177e4SLinus Torvalds 							 (unsigned long) &scb->
3986*1da177e4SLinus Torvalds 							 dcdb -
3987*1da177e4SLinus Torvalds 							 (unsigned long) scb);
3988*1da177e4SLinus Torvalds 		scb->cmd.dcdb.reserved = 0;
3989*1da177e4SLinus Torvalds 		scb->cmd.dcdb.reserved2 = 0;
3990*1da177e4SLinus Torvalds 		scb->cmd.dcdb.reserved3 = 0;
3991*1da177e4SLinus Torvalds 		scb->cmd.dcdb.segment_4G = 0;
3992*1da177e4SLinus Torvalds 		scb->cmd.dcdb.enhanced_sg = 0;
3993*1da177e4SLinus Torvalds 
3994*1da177e4SLinus Torvalds 		TimeOut = scb->scsi_cmd->timeout_per_command;
3995*1da177e4SLinus Torvalds 
3996*1da177e4SLinus Torvalds 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
3997*1da177e4SLinus Torvalds 			if (!scb->sg_len) {
3998*1da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
3999*1da177e4SLinus Torvalds 			} else {
4000*1da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code =
4001*1da177e4SLinus Torvalds 				    IPS_CMD_EXTENDED_DCDB_SG;
4002*1da177e4SLinus Torvalds 				scb->cmd.dcdb.enhanced_sg =
4003*1da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
4004*1da177e4SLinus Torvalds 			}
4005*1da177e4SLinus Torvalds 
4006*1da177e4SLinus Torvalds 			tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;	/* Use Same Data Area as Old DCDB Struct */
4007*1da177e4SLinus Torvalds 			tapeDCDB->device_address =
4008*1da177e4SLinus Torvalds 			    ((scb->bus - 1) << 4) | scb->target_id;
4009*1da177e4SLinus Torvalds 			tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
4010*1da177e4SLinus Torvalds 			tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;	/* Always Turn OFF 64K Size Flag */
4011*1da177e4SLinus Torvalds 
4012*1da177e4SLinus Torvalds 			if (TimeOut) {
4013*1da177e4SLinus Torvalds 				if (TimeOut < (10 * HZ))
4014*1da177e4SLinus Torvalds 					tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
4015*1da177e4SLinus Torvalds 				else if (TimeOut < (60 * HZ))
4016*1da177e4SLinus Torvalds 					tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
4017*1da177e4SLinus Torvalds 				else if (TimeOut < (1200 * HZ))
4018*1da177e4SLinus Torvalds 					tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
4019*1da177e4SLinus Torvalds 			}
4020*1da177e4SLinus Torvalds 
4021*1da177e4SLinus Torvalds 			tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
4022*1da177e4SLinus Torvalds 			tapeDCDB->reserved_for_LUN = 0;
4023*1da177e4SLinus Torvalds 			tapeDCDB->transfer_length = scb->data_len;
4024*1da177e4SLinus Torvalds 			if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)
4025*1da177e4SLinus Torvalds 				tapeDCDB->buffer_pointer =
4026*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
4027*1da177e4SLinus Torvalds 			else
4028*1da177e4SLinus Torvalds 				tapeDCDB->buffer_pointer =
4029*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
4030*1da177e4SLinus Torvalds 			tapeDCDB->sg_count = scb->sg_len;
4031*1da177e4SLinus Torvalds 			tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info);
4032*1da177e4SLinus Torvalds 			tapeDCDB->scsi_status = 0;
4033*1da177e4SLinus Torvalds 			tapeDCDB->reserved = 0;
4034*1da177e4SLinus Torvalds 			memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd,
4035*1da177e4SLinus Torvalds 			       scb->scsi_cmd->cmd_len);
4036*1da177e4SLinus Torvalds 		} else {
4037*1da177e4SLinus Torvalds 			if (!scb->sg_len) {
4038*1da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
4039*1da177e4SLinus Torvalds 			} else {
4040*1da177e4SLinus Torvalds 				scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
4041*1da177e4SLinus Torvalds 				scb->cmd.dcdb.enhanced_sg =
4042*1da177e4SLinus Torvalds 				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
4043*1da177e4SLinus Torvalds 			}
4044*1da177e4SLinus Torvalds 
4045*1da177e4SLinus Torvalds 			scb->dcdb.device_address =
4046*1da177e4SLinus Torvalds 			    ((scb->bus - 1) << 4) | scb->target_id;
4047*1da177e4SLinus Torvalds 			scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
4048*1da177e4SLinus Torvalds 
4049*1da177e4SLinus Torvalds 			if (TimeOut) {
4050*1da177e4SLinus Torvalds 				if (TimeOut < (10 * HZ))
4051*1da177e4SLinus Torvalds 					scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
4052*1da177e4SLinus Torvalds 				else if (TimeOut < (60 * HZ))
4053*1da177e4SLinus Torvalds 					scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
4054*1da177e4SLinus Torvalds 				else if (TimeOut < (1200 * HZ))
4055*1da177e4SLinus Torvalds 					scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
4056*1da177e4SLinus Torvalds 			}
4057*1da177e4SLinus Torvalds 
4058*1da177e4SLinus Torvalds 			scb->dcdb.transfer_length = scb->data_len;
4059*1da177e4SLinus Torvalds 			if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K)
4060*1da177e4SLinus Torvalds 				scb->dcdb.transfer_length = 0;
4061*1da177e4SLinus Torvalds 			if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG)
4062*1da177e4SLinus Torvalds 				scb->dcdb.buffer_pointer =
4063*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->sg_busaddr);
4064*1da177e4SLinus Torvalds 			else
4065*1da177e4SLinus Torvalds 				scb->dcdb.buffer_pointer =
4066*1da177e4SLinus Torvalds 				    cpu_to_le32(scb->data_busaddr);
4067*1da177e4SLinus Torvalds 			scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
4068*1da177e4SLinus Torvalds 			scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info);
4069*1da177e4SLinus Torvalds 			scb->dcdb.sg_count = scb->sg_len;
4070*1da177e4SLinus Torvalds 			scb->dcdb.reserved = 0;
4071*1da177e4SLinus Torvalds 			memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd,
4072*1da177e4SLinus Torvalds 			       scb->scsi_cmd->cmd_len);
4073*1da177e4SLinus Torvalds 			scb->dcdb.scsi_status = 0;
4074*1da177e4SLinus Torvalds 			scb->dcdb.reserved2[0] = 0;
4075*1da177e4SLinus Torvalds 			scb->dcdb.reserved2[1] = 0;
4076*1da177e4SLinus Torvalds 			scb->dcdb.reserved2[2] = 0;
4077*1da177e4SLinus Torvalds 		}
4078*1da177e4SLinus Torvalds 	}
4079*1da177e4SLinus Torvalds 
4080*1da177e4SLinus Torvalds 	return ((*ha->func.issue) (ha, scb));
4081*1da177e4SLinus Torvalds }
4082*1da177e4SLinus Torvalds 
4083*1da177e4SLinus Torvalds /****************************************************************************/
4084*1da177e4SLinus Torvalds /*                                                                          */
4085*1da177e4SLinus Torvalds /* Routine Name: ips_chk_status                                             */
4086*1da177e4SLinus Torvalds /*                                                                          */
4087*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4088*1da177e4SLinus Torvalds /*                                                                          */
4089*1da177e4SLinus Torvalds /*   Check the status of commands to logical drives                         */
4090*1da177e4SLinus Torvalds /*   Assumed to be called with the HA lock                                  */
4091*1da177e4SLinus Torvalds /****************************************************************************/
4092*1da177e4SLinus Torvalds static void
4093*1da177e4SLinus Torvalds ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
4094*1da177e4SLinus Torvalds {
4095*1da177e4SLinus Torvalds 	ips_scb_t *scb;
4096*1da177e4SLinus Torvalds 	ips_stat_t *sp;
4097*1da177e4SLinus Torvalds 	uint8_t basic_status;
4098*1da177e4SLinus Torvalds 	uint8_t ext_status;
4099*1da177e4SLinus Torvalds 	int errcode;
4100*1da177e4SLinus Torvalds 
4101*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_chkstatus", 1);
4102*1da177e4SLinus Torvalds 
4103*1da177e4SLinus Torvalds 	scb = &ha->scbs[pstatus->fields.command_id];
4104*1da177e4SLinus Torvalds 	scb->basic_status = basic_status =
4105*1da177e4SLinus Torvalds 	    pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
4106*1da177e4SLinus Torvalds 	scb->extended_status = ext_status = pstatus->fields.extended_status;
4107*1da177e4SLinus Torvalds 
4108*1da177e4SLinus Torvalds 	sp = &ha->sp;
4109*1da177e4SLinus Torvalds 	sp->residue_len = 0;
4110*1da177e4SLinus Torvalds 	sp->scb_addr = (void *) scb;
4111*1da177e4SLinus Torvalds 
4112*1da177e4SLinus Torvalds 	/* Remove the item from the active queue */
4113*1da177e4SLinus Torvalds 	ips_removeq_scb(&ha->scb_activelist, scb);
4114*1da177e4SLinus Torvalds 
4115*1da177e4SLinus Torvalds 	if (!scb->scsi_cmd)
4116*1da177e4SLinus Torvalds 		/* internal commands are handled in do_ipsintr */
4117*1da177e4SLinus Torvalds 		return;
4118*1da177e4SLinus Torvalds 
4119*1da177e4SLinus Torvalds 	DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
4120*1da177e4SLinus Torvalds 		  ips_name,
4121*1da177e4SLinus Torvalds 		  ha->host_num,
4122*1da177e4SLinus Torvalds 		  scb->cdb[0],
4123*1da177e4SLinus Torvalds 		  scb->cmd.basic_io.command_id,
4124*1da177e4SLinus Torvalds 		  scb->bus, scb->target_id, scb->lun);
4125*1da177e4SLinus Torvalds 
4126*1da177e4SLinus Torvalds 	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
4127*1da177e4SLinus Torvalds 		/* passthru - just returns the raw result */
4128*1da177e4SLinus Torvalds 		return;
4129*1da177e4SLinus Torvalds 
4130*1da177e4SLinus Torvalds 	errcode = DID_OK;
4131*1da177e4SLinus Torvalds 
4132*1da177e4SLinus Torvalds 	if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
4133*1da177e4SLinus Torvalds 	    ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
4134*1da177e4SLinus Torvalds 
4135*1da177e4SLinus Torvalds 		if (scb->bus == 0) {
4136*1da177e4SLinus Torvalds 			if ((basic_status & IPS_GSC_STATUS_MASK) ==
4137*1da177e4SLinus Torvalds 			    IPS_CMD_RECOVERED_ERROR) {
4138*1da177e4SLinus Torvalds 				DEBUG_VAR(1,
4139*1da177e4SLinus Torvalds 					  "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
4140*1da177e4SLinus Torvalds 					  ips_name, ha->host_num,
4141*1da177e4SLinus Torvalds 					  scb->cmd.basic_io.op_code,
4142*1da177e4SLinus Torvalds 					  basic_status, ext_status);
4143*1da177e4SLinus Torvalds 			}
4144*1da177e4SLinus Torvalds 
4145*1da177e4SLinus Torvalds 			switch (scb->scsi_cmd->cmnd[0]) {
4146*1da177e4SLinus Torvalds 			case ALLOW_MEDIUM_REMOVAL:
4147*1da177e4SLinus Torvalds 			case REZERO_UNIT:
4148*1da177e4SLinus Torvalds 			case ERASE:
4149*1da177e4SLinus Torvalds 			case WRITE_FILEMARKS:
4150*1da177e4SLinus Torvalds 			case SPACE:
4151*1da177e4SLinus Torvalds 				errcode = DID_ERROR;
4152*1da177e4SLinus Torvalds 				break;
4153*1da177e4SLinus Torvalds 
4154*1da177e4SLinus Torvalds 			case START_STOP:
4155*1da177e4SLinus Torvalds 				break;
4156*1da177e4SLinus Torvalds 
4157*1da177e4SLinus Torvalds 			case TEST_UNIT_READY:
4158*1da177e4SLinus Torvalds 				if (!ips_online(ha, scb)) {
4159*1da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
4160*1da177e4SLinus Torvalds 				}
4161*1da177e4SLinus Torvalds 				break;
4162*1da177e4SLinus Torvalds 
4163*1da177e4SLinus Torvalds 			case INQUIRY:
4164*1da177e4SLinus Torvalds 				if (ips_online(ha, scb)) {
4165*1da177e4SLinus Torvalds 					ips_inquiry(ha, scb);
4166*1da177e4SLinus Torvalds 				} else {
4167*1da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
4168*1da177e4SLinus Torvalds 				}
4169*1da177e4SLinus Torvalds 				break;
4170*1da177e4SLinus Torvalds 
4171*1da177e4SLinus Torvalds 			case REQUEST_SENSE:
4172*1da177e4SLinus Torvalds 				ips_reqsen(ha, scb);
4173*1da177e4SLinus Torvalds 				break;
4174*1da177e4SLinus Torvalds 
4175*1da177e4SLinus Torvalds 			case READ_6:
4176*1da177e4SLinus Torvalds 			case WRITE_6:
4177*1da177e4SLinus Torvalds 			case READ_10:
4178*1da177e4SLinus Torvalds 			case WRITE_10:
4179*1da177e4SLinus Torvalds 			case RESERVE:
4180*1da177e4SLinus Torvalds 			case RELEASE:
4181*1da177e4SLinus Torvalds 				break;
4182*1da177e4SLinus Torvalds 
4183*1da177e4SLinus Torvalds 			case MODE_SENSE:
4184*1da177e4SLinus Torvalds 				if (!ips_online(ha, scb)
4185*1da177e4SLinus Torvalds 				    || !ips_msense(ha, scb)) {
4186*1da177e4SLinus Torvalds 					errcode = DID_ERROR;
4187*1da177e4SLinus Torvalds 				}
4188*1da177e4SLinus Torvalds 				break;
4189*1da177e4SLinus Torvalds 
4190*1da177e4SLinus Torvalds 			case READ_CAPACITY:
4191*1da177e4SLinus Torvalds 				if (ips_online(ha, scb))
4192*1da177e4SLinus Torvalds 					ips_rdcap(ha, scb);
4193*1da177e4SLinus Torvalds 				else {
4194*1da177e4SLinus Torvalds 					errcode = DID_TIME_OUT;
4195*1da177e4SLinus Torvalds 				}
4196*1da177e4SLinus Torvalds 				break;
4197*1da177e4SLinus Torvalds 
4198*1da177e4SLinus Torvalds 			case SEND_DIAGNOSTIC:
4199*1da177e4SLinus Torvalds 			case REASSIGN_BLOCKS:
4200*1da177e4SLinus Torvalds 				break;
4201*1da177e4SLinus Torvalds 
4202*1da177e4SLinus Torvalds 			case FORMAT_UNIT:
4203*1da177e4SLinus Torvalds 				errcode = DID_ERROR;
4204*1da177e4SLinus Torvalds 				break;
4205*1da177e4SLinus Torvalds 
4206*1da177e4SLinus Torvalds 			case SEEK_10:
4207*1da177e4SLinus Torvalds 			case VERIFY:
4208*1da177e4SLinus Torvalds 			case READ_DEFECT_DATA:
4209*1da177e4SLinus Torvalds 			case READ_BUFFER:
4210*1da177e4SLinus Torvalds 			case WRITE_BUFFER:
4211*1da177e4SLinus Torvalds 				break;
4212*1da177e4SLinus Torvalds 
4213*1da177e4SLinus Torvalds 			default:
4214*1da177e4SLinus Torvalds 				errcode = DID_ERROR;
4215*1da177e4SLinus Torvalds 			}	/* end switch */
4216*1da177e4SLinus Torvalds 
4217*1da177e4SLinus Torvalds 			scb->scsi_cmd->result = errcode << 16;
4218*1da177e4SLinus Torvalds 		} else {	/* bus == 0 */
4219*1da177e4SLinus Torvalds 			/* restrict access to physical drives */
4220*1da177e4SLinus Torvalds 			if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
4221*1da177e4SLinus Torvalds 			    ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) ==
4222*1da177e4SLinus Torvalds 			     TYPE_DISK)) {
4223*1da177e4SLinus Torvalds 
4224*1da177e4SLinus Torvalds 				scb->scsi_cmd->result = DID_TIME_OUT << 16;
4225*1da177e4SLinus Torvalds 			}
4226*1da177e4SLinus Torvalds 		}		/* else */
4227*1da177e4SLinus Torvalds 	} else {		/* recovered error / success */
4228*1da177e4SLinus Torvalds 		if (scb->bus == 0) {
4229*1da177e4SLinus Torvalds 			DEBUG_VAR(1,
4230*1da177e4SLinus Torvalds 				  "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
4231*1da177e4SLinus Torvalds 				  ips_name, ha->host_num,
4232*1da177e4SLinus Torvalds 				  scb->cmd.basic_io.op_code, basic_status,
4233*1da177e4SLinus Torvalds 				  ext_status);
4234*1da177e4SLinus Torvalds 		}
4235*1da177e4SLinus Torvalds 
4236*1da177e4SLinus Torvalds 		ips_map_status(ha, scb, sp);
4237*1da177e4SLinus Torvalds 	}			/* else */
4238*1da177e4SLinus Torvalds }
4239*1da177e4SLinus Torvalds 
4240*1da177e4SLinus Torvalds /****************************************************************************/
4241*1da177e4SLinus Torvalds /*                                                                          */
4242*1da177e4SLinus Torvalds /* Routine Name: ips_online                                                 */
4243*1da177e4SLinus Torvalds /*                                                                          */
4244*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4245*1da177e4SLinus Torvalds /*                                                                          */
4246*1da177e4SLinus Torvalds /*   Determine if a logical drive is online                                 */
4247*1da177e4SLinus Torvalds /*                                                                          */
4248*1da177e4SLinus Torvalds /****************************************************************************/
4249*1da177e4SLinus Torvalds static int
4250*1da177e4SLinus Torvalds ips_online(ips_ha_t * ha, ips_scb_t * scb)
4251*1da177e4SLinus Torvalds {
4252*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_online", 1);
4253*1da177e4SLinus Torvalds 
4254*1da177e4SLinus Torvalds 	if (scb->target_id >= IPS_MAX_LD)
4255*1da177e4SLinus Torvalds 		return (0);
4256*1da177e4SLinus Torvalds 
4257*1da177e4SLinus Torvalds 	if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) {
4258*1da177e4SLinus Torvalds 		memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO));
4259*1da177e4SLinus Torvalds 		return (0);
4260*1da177e4SLinus Torvalds 	}
4261*1da177e4SLinus Torvalds 
4262*1da177e4SLinus Torvalds 	if (ha->logical_drive_info->drive_info[scb->target_id].state !=
4263*1da177e4SLinus Torvalds 	    IPS_LD_OFFLINE
4264*1da177e4SLinus Torvalds 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
4265*1da177e4SLinus Torvalds 	    IPS_LD_FREE
4266*1da177e4SLinus Torvalds 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
4267*1da177e4SLinus Torvalds 	    IPS_LD_CRS
4268*1da177e4SLinus Torvalds 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
4269*1da177e4SLinus Torvalds 	    IPS_LD_SYS)
4270*1da177e4SLinus Torvalds 		return (1);
4271*1da177e4SLinus Torvalds 	else
4272*1da177e4SLinus Torvalds 		return (0);
4273*1da177e4SLinus Torvalds }
4274*1da177e4SLinus Torvalds 
4275*1da177e4SLinus Torvalds /****************************************************************************/
4276*1da177e4SLinus Torvalds /*                                                                          */
4277*1da177e4SLinus Torvalds /* Routine Name: ips_inquiry                                                */
4278*1da177e4SLinus Torvalds /*                                                                          */
4279*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4280*1da177e4SLinus Torvalds /*                                                                          */
4281*1da177e4SLinus Torvalds /*   Simulate an inquiry command to a logical drive                         */
4282*1da177e4SLinus Torvalds /*                                                                          */
4283*1da177e4SLinus Torvalds /****************************************************************************/
4284*1da177e4SLinus Torvalds static int
4285*1da177e4SLinus Torvalds ips_inquiry(ips_ha_t * ha, ips_scb_t * scb)
4286*1da177e4SLinus Torvalds {
4287*1da177e4SLinus Torvalds 	IPS_SCSI_INQ_DATA inquiry;
4288*1da177e4SLinus Torvalds 
4289*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_inquiry", 1);
4290*1da177e4SLinus Torvalds 
4291*1da177e4SLinus Torvalds 	memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA));
4292*1da177e4SLinus Torvalds 
4293*1da177e4SLinus Torvalds 	inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD;
4294*1da177e4SLinus Torvalds 	inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
4295*1da177e4SLinus Torvalds 	inquiry.Version = IPS_SCSI_INQ_REV2;
4296*1da177e4SLinus Torvalds 	inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
4297*1da177e4SLinus Torvalds 	inquiry.AdditionalLength = 31;
4298*1da177e4SLinus Torvalds 	inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
4299*1da177e4SLinus Torvalds 	inquiry.Flags[1] =
4300*1da177e4SLinus Torvalds 	    IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue;
4301*1da177e4SLinus Torvalds 	strncpy(inquiry.VendorId, "IBM     ", 8);
4302*1da177e4SLinus Torvalds 	strncpy(inquiry.ProductId, "SERVERAID       ", 16);
4303*1da177e4SLinus Torvalds 	strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
4304*1da177e4SLinus Torvalds 
4305*1da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry));
4306*1da177e4SLinus Torvalds 
4307*1da177e4SLinus Torvalds 	return (1);
4308*1da177e4SLinus Torvalds }
4309*1da177e4SLinus Torvalds 
4310*1da177e4SLinus Torvalds /****************************************************************************/
4311*1da177e4SLinus Torvalds /*                                                                          */
4312*1da177e4SLinus Torvalds /* Routine Name: ips_rdcap                                                  */
4313*1da177e4SLinus Torvalds /*                                                                          */
4314*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4315*1da177e4SLinus Torvalds /*                                                                          */
4316*1da177e4SLinus Torvalds /*   Simulate a read capacity command to a logical drive                    */
4317*1da177e4SLinus Torvalds /*                                                                          */
4318*1da177e4SLinus Torvalds /****************************************************************************/
4319*1da177e4SLinus Torvalds static int
4320*1da177e4SLinus Torvalds ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
4321*1da177e4SLinus Torvalds {
4322*1da177e4SLinus Torvalds 	IPS_SCSI_CAPACITY cap;
4323*1da177e4SLinus Torvalds 
4324*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_rdcap", 1);
4325*1da177e4SLinus Torvalds 
4326*1da177e4SLinus Torvalds 	if (scb->scsi_cmd->bufflen < 8)
4327*1da177e4SLinus Torvalds 		return (0);
4328*1da177e4SLinus Torvalds 
4329*1da177e4SLinus Torvalds 	cap.lba =
4330*1da177e4SLinus Torvalds 	    cpu_to_be32(le32_to_cpu
4331*1da177e4SLinus Torvalds 			(ha->logical_drive_info->
4332*1da177e4SLinus Torvalds 			 drive_info[scb->target_id].sector_count) - 1);
4333*1da177e4SLinus Torvalds 	cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
4334*1da177e4SLinus Torvalds 
4335*1da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap));
4336*1da177e4SLinus Torvalds 
4337*1da177e4SLinus Torvalds 	return (1);
4338*1da177e4SLinus Torvalds }
4339*1da177e4SLinus Torvalds 
4340*1da177e4SLinus Torvalds /****************************************************************************/
4341*1da177e4SLinus Torvalds /*                                                                          */
4342*1da177e4SLinus Torvalds /* Routine Name: ips_msense                                                 */
4343*1da177e4SLinus Torvalds /*                                                                          */
4344*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4345*1da177e4SLinus Torvalds /*                                                                          */
4346*1da177e4SLinus Torvalds /*   Simulate a mode sense command to a logical drive                       */
4347*1da177e4SLinus Torvalds /*                                                                          */
4348*1da177e4SLinus Torvalds /****************************************************************************/
4349*1da177e4SLinus Torvalds static int
4350*1da177e4SLinus Torvalds ips_msense(ips_ha_t * ha, ips_scb_t * scb)
4351*1da177e4SLinus Torvalds {
4352*1da177e4SLinus Torvalds 	uint16_t heads;
4353*1da177e4SLinus Torvalds 	uint16_t sectors;
4354*1da177e4SLinus Torvalds 	uint32_t cylinders;
4355*1da177e4SLinus Torvalds 	IPS_SCSI_MODE_PAGE_DATA mdata;
4356*1da177e4SLinus Torvalds 
4357*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_msense", 1);
4358*1da177e4SLinus Torvalds 
4359*1da177e4SLinus Torvalds 	if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 &&
4360*1da177e4SLinus Torvalds 	    (ha->enq->ucMiscFlag & 0x8) == 0) {
4361*1da177e4SLinus Torvalds 		heads = IPS_NORM_HEADS;
4362*1da177e4SLinus Torvalds 		sectors = IPS_NORM_SECTORS;
4363*1da177e4SLinus Torvalds 	} else {
4364*1da177e4SLinus Torvalds 		heads = IPS_COMP_HEADS;
4365*1da177e4SLinus Torvalds 		sectors = IPS_COMP_SECTORS;
4366*1da177e4SLinus Torvalds 	}
4367*1da177e4SLinus Torvalds 
4368*1da177e4SLinus Torvalds 	cylinders =
4369*1da177e4SLinus Torvalds 	    (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) -
4370*1da177e4SLinus Torvalds 	     1) / (heads * sectors);
4371*1da177e4SLinus Torvalds 
4372*1da177e4SLinus Torvalds 	memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA));
4373*1da177e4SLinus Torvalds 
4374*1da177e4SLinus Torvalds 	mdata.hdr.BlockDescLength = 8;
4375*1da177e4SLinus Torvalds 
4376*1da177e4SLinus Torvalds 	switch (scb->scsi_cmd->cmnd[2] & 0x3f) {
4377*1da177e4SLinus Torvalds 	case 0x03:		/* page 3 */
4378*1da177e4SLinus Torvalds 		mdata.pdata.pg3.PageCode = 3;
4379*1da177e4SLinus Torvalds 		mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3);
4380*1da177e4SLinus Torvalds 		mdata.hdr.DataLength =
4381*1da177e4SLinus Torvalds 		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength;
4382*1da177e4SLinus Torvalds 		mdata.pdata.pg3.TracksPerZone = 0;
4383*1da177e4SLinus Torvalds 		mdata.pdata.pg3.AltSectorsPerZone = 0;
4384*1da177e4SLinus Torvalds 		mdata.pdata.pg3.AltTracksPerZone = 0;
4385*1da177e4SLinus Torvalds 		mdata.pdata.pg3.AltTracksPerVolume = 0;
4386*1da177e4SLinus Torvalds 		mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors);
4387*1da177e4SLinus Torvalds 		mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE);
4388*1da177e4SLinus Torvalds 		mdata.pdata.pg3.Interleave = cpu_to_be16(1);
4389*1da177e4SLinus Torvalds 		mdata.pdata.pg3.TrackSkew = 0;
4390*1da177e4SLinus Torvalds 		mdata.pdata.pg3.CylinderSkew = 0;
4391*1da177e4SLinus Torvalds 		mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector;
4392*1da177e4SLinus Torvalds 		break;
4393*1da177e4SLinus Torvalds 
4394*1da177e4SLinus Torvalds 	case 0x4:
4395*1da177e4SLinus Torvalds 		mdata.pdata.pg4.PageCode = 4;
4396*1da177e4SLinus Torvalds 		mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4);
4397*1da177e4SLinus Torvalds 		mdata.hdr.DataLength =
4398*1da177e4SLinus Torvalds 		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength;
4399*1da177e4SLinus Torvalds 		mdata.pdata.pg4.CylindersHigh =
4400*1da177e4SLinus Torvalds 		    cpu_to_be16((cylinders >> 8) & 0xFFFF);
4401*1da177e4SLinus Torvalds 		mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF);
4402*1da177e4SLinus Torvalds 		mdata.pdata.pg4.Heads = heads;
4403*1da177e4SLinus Torvalds 		mdata.pdata.pg4.WritePrecompHigh = 0;
4404*1da177e4SLinus Torvalds 		mdata.pdata.pg4.WritePrecompLow = 0;
4405*1da177e4SLinus Torvalds 		mdata.pdata.pg4.ReducedWriteCurrentHigh = 0;
4406*1da177e4SLinus Torvalds 		mdata.pdata.pg4.ReducedWriteCurrentLow = 0;
4407*1da177e4SLinus Torvalds 		mdata.pdata.pg4.StepRate = cpu_to_be16(1);
4408*1da177e4SLinus Torvalds 		mdata.pdata.pg4.LandingZoneHigh = 0;
4409*1da177e4SLinus Torvalds 		mdata.pdata.pg4.LandingZoneLow = 0;
4410*1da177e4SLinus Torvalds 		mdata.pdata.pg4.flags = 0;
4411*1da177e4SLinus Torvalds 		mdata.pdata.pg4.RotationalOffset = 0;
4412*1da177e4SLinus Torvalds 		mdata.pdata.pg4.MediumRotationRate = 0;
4413*1da177e4SLinus Torvalds 		break;
4414*1da177e4SLinus Torvalds 	case 0x8:
4415*1da177e4SLinus Torvalds 		mdata.pdata.pg8.PageCode = 8;
4416*1da177e4SLinus Torvalds 		mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8);
4417*1da177e4SLinus Torvalds 		mdata.hdr.DataLength =
4418*1da177e4SLinus Torvalds 		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength;
4419*1da177e4SLinus Torvalds 		/* everything else is left set to 0 */
4420*1da177e4SLinus Torvalds 		break;
4421*1da177e4SLinus Torvalds 
4422*1da177e4SLinus Torvalds 	default:
4423*1da177e4SLinus Torvalds 		return (0);
4424*1da177e4SLinus Torvalds 	}			/* end switch */
4425*1da177e4SLinus Torvalds 
4426*1da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata));
4427*1da177e4SLinus Torvalds 
4428*1da177e4SLinus Torvalds 	return (1);
4429*1da177e4SLinus Torvalds }
4430*1da177e4SLinus Torvalds 
4431*1da177e4SLinus Torvalds /****************************************************************************/
4432*1da177e4SLinus Torvalds /*                                                                          */
4433*1da177e4SLinus Torvalds /* Routine Name: ips_reqsen                                                 */
4434*1da177e4SLinus Torvalds /*                                                                          */
4435*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4436*1da177e4SLinus Torvalds /*                                                                          */
4437*1da177e4SLinus Torvalds /*   Simulate a request sense command to a logical drive                    */
4438*1da177e4SLinus Torvalds /*                                                                          */
4439*1da177e4SLinus Torvalds /****************************************************************************/
4440*1da177e4SLinus Torvalds static int
4441*1da177e4SLinus Torvalds ips_reqsen(ips_ha_t * ha, ips_scb_t * scb)
4442*1da177e4SLinus Torvalds {
4443*1da177e4SLinus Torvalds 	IPS_SCSI_REQSEN reqsen;
4444*1da177e4SLinus Torvalds 
4445*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_reqsen", 1);
4446*1da177e4SLinus Torvalds 
4447*1da177e4SLinus Torvalds 	memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN));
4448*1da177e4SLinus Torvalds 
4449*1da177e4SLinus Torvalds 	reqsen.ResponseCode =
4450*1da177e4SLinus Torvalds 	    IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR;
4451*1da177e4SLinus Torvalds 	reqsen.AdditionalLength = 10;
4452*1da177e4SLinus Torvalds 	reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE;
4453*1da177e4SLinus Torvalds 	reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE;
4454*1da177e4SLinus Torvalds 
4455*1da177e4SLinus Torvalds 	ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen));
4456*1da177e4SLinus Torvalds 
4457*1da177e4SLinus Torvalds 	return (1);
4458*1da177e4SLinus Torvalds }
4459*1da177e4SLinus Torvalds 
4460*1da177e4SLinus Torvalds /****************************************************************************/
4461*1da177e4SLinus Torvalds /*                                                                          */
4462*1da177e4SLinus Torvalds /* Routine Name: ips_free                                                   */
4463*1da177e4SLinus Torvalds /*                                                                          */
4464*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4465*1da177e4SLinus Torvalds /*                                                                          */
4466*1da177e4SLinus Torvalds /*   Free any allocated space for this controller                           */
4467*1da177e4SLinus Torvalds /*                                                                          */
4468*1da177e4SLinus Torvalds /****************************************************************************/
4469*1da177e4SLinus Torvalds static void
4470*1da177e4SLinus Torvalds ips_free(ips_ha_t * ha)
4471*1da177e4SLinus Torvalds {
4472*1da177e4SLinus Torvalds 
4473*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_free", 1);
4474*1da177e4SLinus Torvalds 
4475*1da177e4SLinus Torvalds 	if (ha) {
4476*1da177e4SLinus Torvalds 		if (ha->enq) {
4477*1da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ),
4478*1da177e4SLinus Torvalds 					    ha->enq, ha->enq_busaddr);
4479*1da177e4SLinus Torvalds 			ha->enq = NULL;
4480*1da177e4SLinus Torvalds 		}
4481*1da177e4SLinus Torvalds 
4482*1da177e4SLinus Torvalds 		if (ha->conf) {
4483*1da177e4SLinus Torvalds 			kfree(ha->conf);
4484*1da177e4SLinus Torvalds 			ha->conf = NULL;
4485*1da177e4SLinus Torvalds 		}
4486*1da177e4SLinus Torvalds 
4487*1da177e4SLinus Torvalds 		if (ha->adapt) {
4488*1da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev,
4489*1da177e4SLinus Torvalds 					    sizeof (IPS_ADAPTER) +
4490*1da177e4SLinus Torvalds 					    sizeof (IPS_IO_CMD), ha->adapt,
4491*1da177e4SLinus Torvalds 					    ha->adapt->hw_status_start);
4492*1da177e4SLinus Torvalds 			ha->adapt = NULL;
4493*1da177e4SLinus Torvalds 		}
4494*1da177e4SLinus Torvalds 
4495*1da177e4SLinus Torvalds 		if (ha->logical_drive_info) {
4496*1da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev,
4497*1da177e4SLinus Torvalds 					    sizeof (IPS_LD_INFO),
4498*1da177e4SLinus Torvalds 					    ha->logical_drive_info,
4499*1da177e4SLinus Torvalds 					    ha->logical_drive_info_dma_addr);
4500*1da177e4SLinus Torvalds 			ha->logical_drive_info = NULL;
4501*1da177e4SLinus Torvalds 		}
4502*1da177e4SLinus Torvalds 
4503*1da177e4SLinus Torvalds 		if (ha->nvram) {
4504*1da177e4SLinus Torvalds 			kfree(ha->nvram);
4505*1da177e4SLinus Torvalds 			ha->nvram = NULL;
4506*1da177e4SLinus Torvalds 		}
4507*1da177e4SLinus Torvalds 
4508*1da177e4SLinus Torvalds 		if (ha->subsys) {
4509*1da177e4SLinus Torvalds 			kfree(ha->subsys);
4510*1da177e4SLinus Torvalds 			ha->subsys = NULL;
4511*1da177e4SLinus Torvalds 		}
4512*1da177e4SLinus Torvalds 
4513*1da177e4SLinus Torvalds 		if (ha->ioctl_data) {
4514*1da177e4SLinus Torvalds 			pci_free_consistent(ha->pcidev, ha->ioctl_len,
4515*1da177e4SLinus Torvalds 					    ha->ioctl_data, ha->ioctl_busaddr);
4516*1da177e4SLinus Torvalds 			ha->ioctl_data = NULL;
4517*1da177e4SLinus Torvalds 			ha->ioctl_datasize = 0;
4518*1da177e4SLinus Torvalds 			ha->ioctl_len = 0;
4519*1da177e4SLinus Torvalds 		}
4520*1da177e4SLinus Torvalds 		ips_deallocatescbs(ha, ha->max_cmds);
4521*1da177e4SLinus Torvalds 
4522*1da177e4SLinus Torvalds 		/* free memory mapped (if applicable) */
4523*1da177e4SLinus Torvalds 		if (ha->mem_ptr) {
4524*1da177e4SLinus Torvalds 			iounmap(ha->ioremap_ptr);
4525*1da177e4SLinus Torvalds 			ha->ioremap_ptr = NULL;
4526*1da177e4SLinus Torvalds 			ha->mem_ptr = NULL;
4527*1da177e4SLinus Torvalds 		}
4528*1da177e4SLinus Torvalds 
4529*1da177e4SLinus Torvalds 		if (ha->mem_addr)
4530*1da177e4SLinus Torvalds 			release_mem_region(ha->mem_addr, ha->mem_len);
4531*1da177e4SLinus Torvalds 		ha->mem_addr = 0;
4532*1da177e4SLinus Torvalds 
4533*1da177e4SLinus Torvalds 	}
4534*1da177e4SLinus Torvalds }
4535*1da177e4SLinus Torvalds 
4536*1da177e4SLinus Torvalds /****************************************************************************/
4537*1da177e4SLinus Torvalds /*                                                                          */
4538*1da177e4SLinus Torvalds /* Routine Name: ips_deallocatescbs                                         */
4539*1da177e4SLinus Torvalds /*                                                                          */
4540*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4541*1da177e4SLinus Torvalds /*                                                                          */
4542*1da177e4SLinus Torvalds /*   Free the command blocks                                                */
4543*1da177e4SLinus Torvalds /*                                                                          */
4544*1da177e4SLinus Torvalds /****************************************************************************/
4545*1da177e4SLinus Torvalds static int
4546*1da177e4SLinus Torvalds ips_deallocatescbs(ips_ha_t * ha, int cmds)
4547*1da177e4SLinus Torvalds {
4548*1da177e4SLinus Torvalds 	if (ha->scbs) {
4549*1da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev,
4550*1da177e4SLinus Torvalds 				    IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds,
4551*1da177e4SLinus Torvalds 				    ha->scbs->sg_list.list,
4552*1da177e4SLinus Torvalds 				    ha->scbs->sg_busaddr);
4553*1da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds,
4554*1da177e4SLinus Torvalds 				    ha->scbs, ha->scbs->scb_busaddr);
4555*1da177e4SLinus Torvalds 		ha->scbs = NULL;
4556*1da177e4SLinus Torvalds 	}			/* end if */
4557*1da177e4SLinus Torvalds 	return 1;
4558*1da177e4SLinus Torvalds }
4559*1da177e4SLinus Torvalds 
4560*1da177e4SLinus Torvalds /****************************************************************************/
4561*1da177e4SLinus Torvalds /*                                                                          */
4562*1da177e4SLinus Torvalds /* Routine Name: ips_allocatescbs                                           */
4563*1da177e4SLinus Torvalds /*                                                                          */
4564*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4565*1da177e4SLinus Torvalds /*                                                                          */
4566*1da177e4SLinus Torvalds /*   Allocate the command blocks                                            */
4567*1da177e4SLinus Torvalds /*                                                                          */
4568*1da177e4SLinus Torvalds /****************************************************************************/
4569*1da177e4SLinus Torvalds static int
4570*1da177e4SLinus Torvalds ips_allocatescbs(ips_ha_t * ha)
4571*1da177e4SLinus Torvalds {
4572*1da177e4SLinus Torvalds 	ips_scb_t *scb_p;
4573*1da177e4SLinus Torvalds 	IPS_SG_LIST ips_sg;
4574*1da177e4SLinus Torvalds 	int i;
4575*1da177e4SLinus Torvalds 	dma_addr_t command_dma, sg_dma;
4576*1da177e4SLinus Torvalds 
4577*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_allocatescbs", 1);
4578*1da177e4SLinus Torvalds 
4579*1da177e4SLinus Torvalds 	/* Allocate memory for the SCBs */
4580*1da177e4SLinus Torvalds 	ha->scbs =
4581*1da177e4SLinus Torvalds 	    pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t),
4582*1da177e4SLinus Torvalds 				 &command_dma);
4583*1da177e4SLinus Torvalds 	if (ha->scbs == NULL)
4584*1da177e4SLinus Torvalds 		return 0;
4585*1da177e4SLinus Torvalds 	ips_sg.list =
4586*1da177e4SLinus Torvalds 	    pci_alloc_consistent(ha->pcidev,
4587*1da177e4SLinus Torvalds 				 IPS_SGLIST_SIZE(ha) * IPS_MAX_SG *
4588*1da177e4SLinus Torvalds 				 ha->max_cmds, &sg_dma);
4589*1da177e4SLinus Torvalds 	if (ips_sg.list == NULL) {
4590*1da177e4SLinus Torvalds 		pci_free_consistent(ha->pcidev,
4591*1da177e4SLinus Torvalds 				    ha->max_cmds * sizeof (ips_scb_t), ha->scbs,
4592*1da177e4SLinus Torvalds 				    command_dma);
4593*1da177e4SLinus Torvalds 		return 0;
4594*1da177e4SLinus Torvalds 	}
4595*1da177e4SLinus Torvalds 
4596*1da177e4SLinus Torvalds 	memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t));
4597*1da177e4SLinus Torvalds 
4598*1da177e4SLinus Torvalds 	for (i = 0; i < ha->max_cmds; i++) {
4599*1da177e4SLinus Torvalds 		scb_p = &ha->scbs[i];
4600*1da177e4SLinus Torvalds 		scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i;
4601*1da177e4SLinus Torvalds 		/* set up S/G list */
4602*1da177e4SLinus Torvalds 		if (IPS_USE_ENH_SGLIST(ha)) {
4603*1da177e4SLinus Torvalds 			scb_p->sg_list.enh_list =
4604*1da177e4SLinus Torvalds 			    ips_sg.enh_list + i * IPS_MAX_SG;
4605*1da177e4SLinus Torvalds 			scb_p->sg_busaddr =
4606*1da177e4SLinus Torvalds 			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
4607*1da177e4SLinus Torvalds 		} else {
4608*1da177e4SLinus Torvalds 			scb_p->sg_list.std_list =
4609*1da177e4SLinus Torvalds 			    ips_sg.std_list + i * IPS_MAX_SG;
4610*1da177e4SLinus Torvalds 			scb_p->sg_busaddr =
4611*1da177e4SLinus Torvalds 			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
4612*1da177e4SLinus Torvalds 		}
4613*1da177e4SLinus Torvalds 
4614*1da177e4SLinus Torvalds 		/* add to the free list */
4615*1da177e4SLinus Torvalds 		if (i < ha->max_cmds - 1) {
4616*1da177e4SLinus Torvalds 			scb_p->q_next = ha->scb_freelist;
4617*1da177e4SLinus Torvalds 			ha->scb_freelist = scb_p;
4618*1da177e4SLinus Torvalds 		}
4619*1da177e4SLinus Torvalds 	}
4620*1da177e4SLinus Torvalds 
4621*1da177e4SLinus Torvalds 	/* success */
4622*1da177e4SLinus Torvalds 	return (1);
4623*1da177e4SLinus Torvalds }
4624*1da177e4SLinus Torvalds 
4625*1da177e4SLinus Torvalds /****************************************************************************/
4626*1da177e4SLinus Torvalds /*                                                                          */
4627*1da177e4SLinus Torvalds /* Routine Name: ips_init_scb                                               */
4628*1da177e4SLinus Torvalds /*                                                                          */
4629*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4630*1da177e4SLinus Torvalds /*                                                                          */
4631*1da177e4SLinus Torvalds /*   Initialize a CCB to default values                                     */
4632*1da177e4SLinus Torvalds /*                                                                          */
4633*1da177e4SLinus Torvalds /****************************************************************************/
4634*1da177e4SLinus Torvalds static void
4635*1da177e4SLinus Torvalds ips_init_scb(ips_ha_t * ha, ips_scb_t * scb)
4636*1da177e4SLinus Torvalds {
4637*1da177e4SLinus Torvalds 	IPS_SG_LIST sg_list;
4638*1da177e4SLinus Torvalds 	uint32_t cmd_busaddr, sg_busaddr;
4639*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_scb", 1);
4640*1da177e4SLinus Torvalds 
4641*1da177e4SLinus Torvalds 	if (scb == NULL)
4642*1da177e4SLinus Torvalds 		return;
4643*1da177e4SLinus Torvalds 
4644*1da177e4SLinus Torvalds 	sg_list.list = scb->sg_list.list;
4645*1da177e4SLinus Torvalds 	cmd_busaddr = scb->scb_busaddr;
4646*1da177e4SLinus Torvalds 	sg_busaddr = scb->sg_busaddr;
4647*1da177e4SLinus Torvalds 	/* zero fill */
4648*1da177e4SLinus Torvalds 	memset(scb, 0, sizeof (ips_scb_t));
4649*1da177e4SLinus Torvalds 	memset(ha->dummy, 0, sizeof (IPS_IO_CMD));
4650*1da177e4SLinus Torvalds 
4651*1da177e4SLinus Torvalds 	/* Initialize dummy command bucket */
4652*1da177e4SLinus Torvalds 	ha->dummy->op_code = 0xFF;
4653*1da177e4SLinus Torvalds 	ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
4654*1da177e4SLinus Torvalds 				       + sizeof (IPS_ADAPTER));
4655*1da177e4SLinus Torvalds 	ha->dummy->command_id = IPS_MAX_CMDS;
4656*1da177e4SLinus Torvalds 
4657*1da177e4SLinus Torvalds 	/* set bus address of scb */
4658*1da177e4SLinus Torvalds 	scb->scb_busaddr = cmd_busaddr;
4659*1da177e4SLinus Torvalds 	scb->sg_busaddr = sg_busaddr;
4660*1da177e4SLinus Torvalds 	scb->sg_list.list = sg_list.list;
4661*1da177e4SLinus Torvalds 
4662*1da177e4SLinus Torvalds 	/* Neptune Fix */
4663*1da177e4SLinus Torvalds 	scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
4664*1da177e4SLinus Torvalds 	scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
4665*1da177e4SLinus Torvalds 					      + sizeof (IPS_ADAPTER));
4666*1da177e4SLinus Torvalds }
4667*1da177e4SLinus Torvalds 
4668*1da177e4SLinus Torvalds /****************************************************************************/
4669*1da177e4SLinus Torvalds /*                                                                          */
4670*1da177e4SLinus Torvalds /* Routine Name: ips_get_scb                                                */
4671*1da177e4SLinus Torvalds /*                                                                          */
4672*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4673*1da177e4SLinus Torvalds /*                                                                          */
4674*1da177e4SLinus Torvalds /*   Initialize a CCB to default values                                     */
4675*1da177e4SLinus Torvalds /*                                                                          */
4676*1da177e4SLinus Torvalds /* ASSUMED to be callled from within a lock                                 */
4677*1da177e4SLinus Torvalds /*                                                                          */
4678*1da177e4SLinus Torvalds /****************************************************************************/
4679*1da177e4SLinus Torvalds static ips_scb_t *
4680*1da177e4SLinus Torvalds ips_getscb(ips_ha_t * ha)
4681*1da177e4SLinus Torvalds {
4682*1da177e4SLinus Torvalds 	ips_scb_t *scb;
4683*1da177e4SLinus Torvalds 
4684*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_getscb", 1);
4685*1da177e4SLinus Torvalds 
4686*1da177e4SLinus Torvalds 	if ((scb = ha->scb_freelist) == NULL) {
4687*1da177e4SLinus Torvalds 
4688*1da177e4SLinus Torvalds 		return (NULL);
4689*1da177e4SLinus Torvalds 	}
4690*1da177e4SLinus Torvalds 
4691*1da177e4SLinus Torvalds 	ha->scb_freelist = scb->q_next;
4692*1da177e4SLinus Torvalds 	scb->flags = 0;
4693*1da177e4SLinus Torvalds 	scb->q_next = NULL;
4694*1da177e4SLinus Torvalds 
4695*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
4696*1da177e4SLinus Torvalds 
4697*1da177e4SLinus Torvalds 	return (scb);
4698*1da177e4SLinus Torvalds }
4699*1da177e4SLinus Torvalds 
4700*1da177e4SLinus Torvalds /****************************************************************************/
4701*1da177e4SLinus Torvalds /*                                                                          */
4702*1da177e4SLinus Torvalds /* Routine Name: ips_free_scb                                               */
4703*1da177e4SLinus Torvalds /*                                                                          */
4704*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4705*1da177e4SLinus Torvalds /*                                                                          */
4706*1da177e4SLinus Torvalds /*   Return an unused CCB back to the free list                             */
4707*1da177e4SLinus Torvalds /*                                                                          */
4708*1da177e4SLinus Torvalds /* ASSUMED to be called from within a lock                                  */
4709*1da177e4SLinus Torvalds /*                                                                          */
4710*1da177e4SLinus Torvalds /****************************************************************************/
4711*1da177e4SLinus Torvalds static void
4712*1da177e4SLinus Torvalds ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
4713*1da177e4SLinus Torvalds {
4714*1da177e4SLinus Torvalds 
4715*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_freescb", 1);
4716*1da177e4SLinus Torvalds 	if (scb->flags & IPS_SCB_MAP_SG)
4717*1da177e4SLinus Torvalds 		pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
4718*1da177e4SLinus Torvalds 			     scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb));
4719*1da177e4SLinus Torvalds 	else if (scb->flags & IPS_SCB_MAP_SINGLE)
4720*1da177e4SLinus Torvalds 		pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
4721*1da177e4SLinus Torvalds 				 IPS_DMA_DIR(scb));
4722*1da177e4SLinus Torvalds 
4723*1da177e4SLinus Torvalds 	/* check to make sure this is not our "special" scb */
4724*1da177e4SLinus Torvalds 	if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
4725*1da177e4SLinus Torvalds 		scb->q_next = ha->scb_freelist;
4726*1da177e4SLinus Torvalds 		ha->scb_freelist = scb;
4727*1da177e4SLinus Torvalds 	}
4728*1da177e4SLinus Torvalds }
4729*1da177e4SLinus Torvalds 
4730*1da177e4SLinus Torvalds /****************************************************************************/
4731*1da177e4SLinus Torvalds /*                                                                          */
4732*1da177e4SLinus Torvalds /* Routine Name: ips_isinit_copperhead                                      */
4733*1da177e4SLinus Torvalds /*                                                                          */
4734*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4735*1da177e4SLinus Torvalds /*                                                                          */
4736*1da177e4SLinus Torvalds /*   Is controller initialized ?                                            */
4737*1da177e4SLinus Torvalds /*                                                                          */
4738*1da177e4SLinus Torvalds /****************************************************************************/
4739*1da177e4SLinus Torvalds static int
4740*1da177e4SLinus Torvalds ips_isinit_copperhead(ips_ha_t * ha)
4741*1da177e4SLinus Torvalds {
4742*1da177e4SLinus Torvalds 	uint8_t scpr;
4743*1da177e4SLinus Torvalds 	uint8_t isr;
4744*1da177e4SLinus Torvalds 
4745*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_isinit_copperhead", 1);
4746*1da177e4SLinus Torvalds 
4747*1da177e4SLinus Torvalds 	isr = inb(ha->io_addr + IPS_REG_HISR);
4748*1da177e4SLinus Torvalds 	scpr = inb(ha->io_addr + IPS_REG_SCPR);
4749*1da177e4SLinus Torvalds 
4750*1da177e4SLinus Torvalds 	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
4751*1da177e4SLinus Torvalds 		return (0);
4752*1da177e4SLinus Torvalds 	else
4753*1da177e4SLinus Torvalds 		return (1);
4754*1da177e4SLinus Torvalds }
4755*1da177e4SLinus Torvalds 
4756*1da177e4SLinus Torvalds /****************************************************************************/
4757*1da177e4SLinus Torvalds /*                                                                          */
4758*1da177e4SLinus Torvalds /* Routine Name: ips_isinit_copperhead_memio                                */
4759*1da177e4SLinus Torvalds /*                                                                          */
4760*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4761*1da177e4SLinus Torvalds /*                                                                          */
4762*1da177e4SLinus Torvalds /*   Is controller initialized ?                                            */
4763*1da177e4SLinus Torvalds /*                                                                          */
4764*1da177e4SLinus Torvalds /****************************************************************************/
4765*1da177e4SLinus Torvalds static int
4766*1da177e4SLinus Torvalds ips_isinit_copperhead_memio(ips_ha_t * ha)
4767*1da177e4SLinus Torvalds {
4768*1da177e4SLinus Torvalds 	uint8_t isr = 0;
4769*1da177e4SLinus Torvalds 	uint8_t scpr;
4770*1da177e4SLinus Torvalds 
4771*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_is_init_copperhead_memio", 1);
4772*1da177e4SLinus Torvalds 
4773*1da177e4SLinus Torvalds 	isr = readb(ha->mem_ptr + IPS_REG_HISR);
4774*1da177e4SLinus Torvalds 	scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
4775*1da177e4SLinus Torvalds 
4776*1da177e4SLinus Torvalds 	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
4777*1da177e4SLinus Torvalds 		return (0);
4778*1da177e4SLinus Torvalds 	else
4779*1da177e4SLinus Torvalds 		return (1);
4780*1da177e4SLinus Torvalds }
4781*1da177e4SLinus Torvalds 
4782*1da177e4SLinus Torvalds /****************************************************************************/
4783*1da177e4SLinus Torvalds /*                                                                          */
4784*1da177e4SLinus Torvalds /* Routine Name: ips_isinit_morpheus                                        */
4785*1da177e4SLinus Torvalds /*                                                                          */
4786*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4787*1da177e4SLinus Torvalds /*                                                                          */
4788*1da177e4SLinus Torvalds /*   Is controller initialized ?                                            */
4789*1da177e4SLinus Torvalds /*                                                                          */
4790*1da177e4SLinus Torvalds /****************************************************************************/
4791*1da177e4SLinus Torvalds static int
4792*1da177e4SLinus Torvalds ips_isinit_morpheus(ips_ha_t * ha)
4793*1da177e4SLinus Torvalds {
4794*1da177e4SLinus Torvalds 	uint32_t post;
4795*1da177e4SLinus Torvalds 	uint32_t bits;
4796*1da177e4SLinus Torvalds 
4797*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_is_init_morpheus", 1);
4798*1da177e4SLinus Torvalds 
4799*1da177e4SLinus Torvalds 	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
4800*1da177e4SLinus Torvalds 	bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
4801*1da177e4SLinus Torvalds 
4802*1da177e4SLinus Torvalds 	if (post == 0)
4803*1da177e4SLinus Torvalds 		return (0);
4804*1da177e4SLinus Torvalds 	else if (bits & 0x3)
4805*1da177e4SLinus Torvalds 		return (0);
4806*1da177e4SLinus Torvalds 	else
4807*1da177e4SLinus Torvalds 		return (1);
4808*1da177e4SLinus Torvalds }
4809*1da177e4SLinus Torvalds 
4810*1da177e4SLinus Torvalds /****************************************************************************/
4811*1da177e4SLinus Torvalds /*                                                                          */
4812*1da177e4SLinus Torvalds /* Routine Name: ips_enable_int_copperhead                                  */
4813*1da177e4SLinus Torvalds /*                                                                          */
4814*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4815*1da177e4SLinus Torvalds /*   Turn on interrupts                                                     */
4816*1da177e4SLinus Torvalds /*                                                                          */
4817*1da177e4SLinus Torvalds /****************************************************************************/
4818*1da177e4SLinus Torvalds static void
4819*1da177e4SLinus Torvalds ips_enable_int_copperhead(ips_ha_t * ha)
4820*1da177e4SLinus Torvalds {
4821*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_enable_int_copperhead", 1);
4822*1da177e4SLinus Torvalds 
4823*1da177e4SLinus Torvalds 	outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
4824*1da177e4SLinus Torvalds 	inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
4825*1da177e4SLinus Torvalds }
4826*1da177e4SLinus Torvalds 
4827*1da177e4SLinus Torvalds /****************************************************************************/
4828*1da177e4SLinus Torvalds /*                                                                          */
4829*1da177e4SLinus Torvalds /* Routine Name: ips_enable_int_copperhead_memio                            */
4830*1da177e4SLinus Torvalds /*                                                                          */
4831*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4832*1da177e4SLinus Torvalds /*   Turn on interrupts                                                     */
4833*1da177e4SLinus Torvalds /*                                                                          */
4834*1da177e4SLinus Torvalds /****************************************************************************/
4835*1da177e4SLinus Torvalds static void
4836*1da177e4SLinus Torvalds ips_enable_int_copperhead_memio(ips_ha_t * ha)
4837*1da177e4SLinus Torvalds {
4838*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
4839*1da177e4SLinus Torvalds 
4840*1da177e4SLinus Torvalds 	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
4841*1da177e4SLinus Torvalds 	readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
4842*1da177e4SLinus Torvalds }
4843*1da177e4SLinus Torvalds 
4844*1da177e4SLinus Torvalds /****************************************************************************/
4845*1da177e4SLinus Torvalds /*                                                                          */
4846*1da177e4SLinus Torvalds /* Routine Name: ips_enable_int_morpheus                                    */
4847*1da177e4SLinus Torvalds /*                                                                          */
4848*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4849*1da177e4SLinus Torvalds /*   Turn on interrupts                                                     */
4850*1da177e4SLinus Torvalds /*                                                                          */
4851*1da177e4SLinus Torvalds /****************************************************************************/
4852*1da177e4SLinus Torvalds static void
4853*1da177e4SLinus Torvalds ips_enable_int_morpheus(ips_ha_t * ha)
4854*1da177e4SLinus Torvalds {
4855*1da177e4SLinus Torvalds 	uint32_t Oimr;
4856*1da177e4SLinus Torvalds 
4857*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_enable_int_morpheus", 1);
4858*1da177e4SLinus Torvalds 
4859*1da177e4SLinus Torvalds 	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
4860*1da177e4SLinus Torvalds 	Oimr &= ~0x08;
4861*1da177e4SLinus Torvalds 	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
4862*1da177e4SLinus Torvalds 	readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/
4863*1da177e4SLinus Torvalds }
4864*1da177e4SLinus Torvalds 
4865*1da177e4SLinus Torvalds /****************************************************************************/
4866*1da177e4SLinus Torvalds /*                                                                          */
4867*1da177e4SLinus Torvalds /* Routine Name: ips_init_copperhead                                        */
4868*1da177e4SLinus Torvalds /*                                                                          */
4869*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4870*1da177e4SLinus Torvalds /*                                                                          */
4871*1da177e4SLinus Torvalds /*   Initialize a copperhead controller                                     */
4872*1da177e4SLinus Torvalds /*                                                                          */
4873*1da177e4SLinus Torvalds /****************************************************************************/
4874*1da177e4SLinus Torvalds static int
4875*1da177e4SLinus Torvalds ips_init_copperhead(ips_ha_t * ha)
4876*1da177e4SLinus Torvalds {
4877*1da177e4SLinus Torvalds 	uint8_t Isr;
4878*1da177e4SLinus Torvalds 	uint8_t Cbsp;
4879*1da177e4SLinus Torvalds 	uint8_t PostByte[IPS_MAX_POST_BYTES];
4880*1da177e4SLinus Torvalds 	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
4881*1da177e4SLinus Torvalds 	int i, j;
4882*1da177e4SLinus Torvalds 
4883*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_copperhead", 1);
4884*1da177e4SLinus Torvalds 
4885*1da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
4886*1da177e4SLinus Torvalds 		for (j = 0; j < 45; j++) {
4887*1da177e4SLinus Torvalds 			Isr = inb(ha->io_addr + IPS_REG_HISR);
4888*1da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
4889*1da177e4SLinus Torvalds 				break;
4890*1da177e4SLinus Torvalds 
4891*1da177e4SLinus Torvalds 			/* Delay for 1 Second */
4892*1da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
4893*1da177e4SLinus Torvalds 		}
4894*1da177e4SLinus Torvalds 
4895*1da177e4SLinus Torvalds 		if (j >= 45)
4896*1da177e4SLinus Torvalds 			/* error occurred */
4897*1da177e4SLinus Torvalds 			return (0);
4898*1da177e4SLinus Torvalds 
4899*1da177e4SLinus Torvalds 		PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
4900*1da177e4SLinus Torvalds 		outb(Isr, ha->io_addr + IPS_REG_HISR);
4901*1da177e4SLinus Torvalds 	}
4902*1da177e4SLinus Torvalds 
4903*1da177e4SLinus Torvalds 	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
4904*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
4905*1da177e4SLinus Torvalds 			   "reset controller fails (post status %x %x).\n",
4906*1da177e4SLinus Torvalds 			   PostByte[0], PostByte[1]);
4907*1da177e4SLinus Torvalds 
4908*1da177e4SLinus Torvalds 		return (0);
4909*1da177e4SLinus Torvalds 	}
4910*1da177e4SLinus Torvalds 
4911*1da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
4912*1da177e4SLinus Torvalds 		for (j = 0; j < 240; j++) {
4913*1da177e4SLinus Torvalds 			Isr = inb(ha->io_addr + IPS_REG_HISR);
4914*1da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
4915*1da177e4SLinus Torvalds 				break;
4916*1da177e4SLinus Torvalds 
4917*1da177e4SLinus Torvalds 			/* Delay for 1 Second */
4918*1da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
4919*1da177e4SLinus Torvalds 		}
4920*1da177e4SLinus Torvalds 
4921*1da177e4SLinus Torvalds 		if (j >= 240)
4922*1da177e4SLinus Torvalds 			/* error occurred */
4923*1da177e4SLinus Torvalds 			return (0);
4924*1da177e4SLinus Torvalds 
4925*1da177e4SLinus Torvalds 		ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
4926*1da177e4SLinus Torvalds 		outb(Isr, ha->io_addr + IPS_REG_HISR);
4927*1da177e4SLinus Torvalds 	}
4928*1da177e4SLinus Torvalds 
4929*1da177e4SLinus Torvalds 	for (i = 0; i < 240; i++) {
4930*1da177e4SLinus Torvalds 		Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
4931*1da177e4SLinus Torvalds 
4932*1da177e4SLinus Torvalds 		if ((Cbsp & IPS_BIT_OP) == 0)
4933*1da177e4SLinus Torvalds 			break;
4934*1da177e4SLinus Torvalds 
4935*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
4936*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
4937*1da177e4SLinus Torvalds 	}
4938*1da177e4SLinus Torvalds 
4939*1da177e4SLinus Torvalds 	if (i >= 240)
4940*1da177e4SLinus Torvalds 		/* reset failed */
4941*1da177e4SLinus Torvalds 		return (0);
4942*1da177e4SLinus Torvalds 
4943*1da177e4SLinus Torvalds 	/* setup CCCR */
4944*1da177e4SLinus Torvalds 	outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);
4945*1da177e4SLinus Torvalds 
4946*1da177e4SLinus Torvalds 	/* Enable busmastering */
4947*1da177e4SLinus Torvalds 	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
4948*1da177e4SLinus Torvalds 
4949*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
4950*1da177e4SLinus Torvalds 		/* fix for anaconda64 */
4951*1da177e4SLinus Torvalds 		outl(0, ha->io_addr + IPS_REG_NDAE);
4952*1da177e4SLinus Torvalds 
4953*1da177e4SLinus Torvalds 	/* Enable interrupts */
4954*1da177e4SLinus Torvalds 	outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
4955*1da177e4SLinus Torvalds 
4956*1da177e4SLinus Torvalds 	return (1);
4957*1da177e4SLinus Torvalds }
4958*1da177e4SLinus Torvalds 
4959*1da177e4SLinus Torvalds /****************************************************************************/
4960*1da177e4SLinus Torvalds /*                                                                          */
4961*1da177e4SLinus Torvalds /* Routine Name: ips_init_copperhead_memio                                  */
4962*1da177e4SLinus Torvalds /*                                                                          */
4963*1da177e4SLinus Torvalds /* Routine Description:                                                     */
4964*1da177e4SLinus Torvalds /*                                                                          */
4965*1da177e4SLinus Torvalds /*   Initialize a copperhead controller with memory mapped I/O              */
4966*1da177e4SLinus Torvalds /*                                                                          */
4967*1da177e4SLinus Torvalds /****************************************************************************/
4968*1da177e4SLinus Torvalds static int
4969*1da177e4SLinus Torvalds ips_init_copperhead_memio(ips_ha_t * ha)
4970*1da177e4SLinus Torvalds {
4971*1da177e4SLinus Torvalds 	uint8_t Isr = 0;
4972*1da177e4SLinus Torvalds 	uint8_t Cbsp;
4973*1da177e4SLinus Torvalds 	uint8_t PostByte[IPS_MAX_POST_BYTES];
4974*1da177e4SLinus Torvalds 	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
4975*1da177e4SLinus Torvalds 	int i, j;
4976*1da177e4SLinus Torvalds 
4977*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_copperhead_memio", 1);
4978*1da177e4SLinus Torvalds 
4979*1da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
4980*1da177e4SLinus Torvalds 		for (j = 0; j < 45; j++) {
4981*1da177e4SLinus Torvalds 			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
4982*1da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
4983*1da177e4SLinus Torvalds 				break;
4984*1da177e4SLinus Torvalds 
4985*1da177e4SLinus Torvalds 			/* Delay for 1 Second */
4986*1da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
4987*1da177e4SLinus Torvalds 		}
4988*1da177e4SLinus Torvalds 
4989*1da177e4SLinus Torvalds 		if (j >= 45)
4990*1da177e4SLinus Torvalds 			/* error occurred */
4991*1da177e4SLinus Torvalds 			return (0);
4992*1da177e4SLinus Torvalds 
4993*1da177e4SLinus Torvalds 		PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
4994*1da177e4SLinus Torvalds 		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
4995*1da177e4SLinus Torvalds 	}
4996*1da177e4SLinus Torvalds 
4997*1da177e4SLinus Torvalds 	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
4998*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
4999*1da177e4SLinus Torvalds 			   "reset controller fails (post status %x %x).\n",
5000*1da177e4SLinus Torvalds 			   PostByte[0], PostByte[1]);
5001*1da177e4SLinus Torvalds 
5002*1da177e4SLinus Torvalds 		return (0);
5003*1da177e4SLinus Torvalds 	}
5004*1da177e4SLinus Torvalds 
5005*1da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
5006*1da177e4SLinus Torvalds 		for (j = 0; j < 240; j++) {
5007*1da177e4SLinus Torvalds 			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
5008*1da177e4SLinus Torvalds 			if (Isr & IPS_BIT_GHI)
5009*1da177e4SLinus Torvalds 				break;
5010*1da177e4SLinus Torvalds 
5011*1da177e4SLinus Torvalds 			/* Delay for 1 Second */
5012*1da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
5013*1da177e4SLinus Torvalds 		}
5014*1da177e4SLinus Torvalds 
5015*1da177e4SLinus Torvalds 		if (j >= 240)
5016*1da177e4SLinus Torvalds 			/* error occurred */
5017*1da177e4SLinus Torvalds 			return (0);
5018*1da177e4SLinus Torvalds 
5019*1da177e4SLinus Torvalds 		ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
5020*1da177e4SLinus Torvalds 		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
5021*1da177e4SLinus Torvalds 	}
5022*1da177e4SLinus Torvalds 
5023*1da177e4SLinus Torvalds 	for (i = 0; i < 240; i++) {
5024*1da177e4SLinus Torvalds 		Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
5025*1da177e4SLinus Torvalds 
5026*1da177e4SLinus Torvalds 		if ((Cbsp & IPS_BIT_OP) == 0)
5027*1da177e4SLinus Torvalds 			break;
5028*1da177e4SLinus Torvalds 
5029*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5030*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5031*1da177e4SLinus Torvalds 	}
5032*1da177e4SLinus Torvalds 
5033*1da177e4SLinus Torvalds 	if (i >= 240)
5034*1da177e4SLinus Torvalds 		/* error occurred */
5035*1da177e4SLinus Torvalds 		return (0);
5036*1da177e4SLinus Torvalds 
5037*1da177e4SLinus Torvalds 	/* setup CCCR */
5038*1da177e4SLinus Torvalds 	writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
5039*1da177e4SLinus Torvalds 
5040*1da177e4SLinus Torvalds 	/* Enable busmastering */
5041*1da177e4SLinus Torvalds 	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
5042*1da177e4SLinus Torvalds 
5043*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
5044*1da177e4SLinus Torvalds 		/* fix for anaconda64 */
5045*1da177e4SLinus Torvalds 		writel(0, ha->mem_ptr + IPS_REG_NDAE);
5046*1da177e4SLinus Torvalds 
5047*1da177e4SLinus Torvalds 	/* Enable interrupts */
5048*1da177e4SLinus Torvalds 	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
5049*1da177e4SLinus Torvalds 
5050*1da177e4SLinus Torvalds 	/* if we get here then everything went OK */
5051*1da177e4SLinus Torvalds 	return (1);
5052*1da177e4SLinus Torvalds }
5053*1da177e4SLinus Torvalds 
5054*1da177e4SLinus Torvalds /****************************************************************************/
5055*1da177e4SLinus Torvalds /*                                                                          */
5056*1da177e4SLinus Torvalds /* Routine Name: ips_init_morpheus                                          */
5057*1da177e4SLinus Torvalds /*                                                                          */
5058*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5059*1da177e4SLinus Torvalds /*                                                                          */
5060*1da177e4SLinus Torvalds /*   Initialize a morpheus controller                                       */
5061*1da177e4SLinus Torvalds /*                                                                          */
5062*1da177e4SLinus Torvalds /****************************************************************************/
5063*1da177e4SLinus Torvalds static int
5064*1da177e4SLinus Torvalds ips_init_morpheus(ips_ha_t * ha)
5065*1da177e4SLinus Torvalds {
5066*1da177e4SLinus Torvalds 	uint32_t Post;
5067*1da177e4SLinus Torvalds 	uint32_t Config;
5068*1da177e4SLinus Torvalds 	uint32_t Isr;
5069*1da177e4SLinus Torvalds 	uint32_t Oimr;
5070*1da177e4SLinus Torvalds 	int i;
5071*1da177e4SLinus Torvalds 
5072*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_morpheus", 1);
5073*1da177e4SLinus Torvalds 
5074*1da177e4SLinus Torvalds 	/* Wait up to 45 secs for Post */
5075*1da177e4SLinus Torvalds 	for (i = 0; i < 45; i++) {
5076*1da177e4SLinus Torvalds 		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
5077*1da177e4SLinus Torvalds 
5078*1da177e4SLinus Torvalds 		if (Isr & IPS_BIT_I960_MSG0I)
5079*1da177e4SLinus Torvalds 			break;
5080*1da177e4SLinus Torvalds 
5081*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5082*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5083*1da177e4SLinus Torvalds 	}
5084*1da177e4SLinus Torvalds 
5085*1da177e4SLinus Torvalds 	if (i >= 45) {
5086*1da177e4SLinus Torvalds 		/* error occurred */
5087*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
5088*1da177e4SLinus Torvalds 			   "timeout waiting for post.\n");
5089*1da177e4SLinus Torvalds 
5090*1da177e4SLinus Torvalds 		return (0);
5091*1da177e4SLinus Torvalds 	}
5092*1da177e4SLinus Torvalds 
5093*1da177e4SLinus Torvalds 	Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
5094*1da177e4SLinus Torvalds 
5095*1da177e4SLinus Torvalds 	if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */
5096*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
5097*1da177e4SLinus Torvalds 			   "Flashing Battery PIC, Please wait ...\n");
5098*1da177e4SLinus Torvalds 
5099*1da177e4SLinus Torvalds 		/* Clear the interrupt bit */
5100*1da177e4SLinus Torvalds 		Isr = (uint32_t) IPS_BIT_I960_MSG0I;
5101*1da177e4SLinus Torvalds 		writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
5102*1da177e4SLinus Torvalds 
5103*1da177e4SLinus Torvalds 		for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */
5104*1da177e4SLinus Torvalds 			Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
5105*1da177e4SLinus Torvalds 			if (Post != 0x4F00)
5106*1da177e4SLinus Torvalds 				break;
5107*1da177e4SLinus Torvalds 			/* Delay for 1 Second */
5108*1da177e4SLinus Torvalds 			MDELAY(IPS_ONE_SEC);
5109*1da177e4SLinus Torvalds 		}
5110*1da177e4SLinus Torvalds 
5111*1da177e4SLinus Torvalds 		if (i >= 120) {
5112*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
5113*1da177e4SLinus Torvalds 				   "timeout waiting for Battery PIC Flash\n");
5114*1da177e4SLinus Torvalds 			return (0);
5115*1da177e4SLinus Torvalds 		}
5116*1da177e4SLinus Torvalds 
5117*1da177e4SLinus Torvalds 	}
5118*1da177e4SLinus Torvalds 
5119*1da177e4SLinus Torvalds 	/* Clear the interrupt bit */
5120*1da177e4SLinus Torvalds 	Isr = (uint32_t) IPS_BIT_I960_MSG0I;
5121*1da177e4SLinus Torvalds 	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
5122*1da177e4SLinus Torvalds 
5123*1da177e4SLinus Torvalds 	if (Post < (IPS_GOOD_POST_STATUS << 8)) {
5124*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
5125*1da177e4SLinus Torvalds 			   "reset controller fails (post status %x).\n", Post);
5126*1da177e4SLinus Torvalds 
5127*1da177e4SLinus Torvalds 		return (0);
5128*1da177e4SLinus Torvalds 	}
5129*1da177e4SLinus Torvalds 
5130*1da177e4SLinus Torvalds 	/* Wait up to 240 secs for config bytes */
5131*1da177e4SLinus Torvalds 	for (i = 0; i < 240; i++) {
5132*1da177e4SLinus Torvalds 		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
5133*1da177e4SLinus Torvalds 
5134*1da177e4SLinus Torvalds 		if (Isr & IPS_BIT_I960_MSG1I)
5135*1da177e4SLinus Torvalds 			break;
5136*1da177e4SLinus Torvalds 
5137*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5138*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5139*1da177e4SLinus Torvalds 	}
5140*1da177e4SLinus Torvalds 
5141*1da177e4SLinus Torvalds 	if (i >= 240) {
5142*1da177e4SLinus Torvalds 		/* error occurred */
5143*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
5144*1da177e4SLinus Torvalds 			   "timeout waiting for config.\n");
5145*1da177e4SLinus Torvalds 
5146*1da177e4SLinus Torvalds 		return (0);
5147*1da177e4SLinus Torvalds 	}
5148*1da177e4SLinus Torvalds 
5149*1da177e4SLinus Torvalds 	Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
5150*1da177e4SLinus Torvalds 
5151*1da177e4SLinus Torvalds 	/* Clear interrupt bit */
5152*1da177e4SLinus Torvalds 	Isr = (uint32_t) IPS_BIT_I960_MSG1I;
5153*1da177e4SLinus Torvalds 	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
5154*1da177e4SLinus Torvalds 
5155*1da177e4SLinus Torvalds 	/* Turn on the interrupts */
5156*1da177e4SLinus Torvalds 	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
5157*1da177e4SLinus Torvalds 	Oimr &= ~0x8;
5158*1da177e4SLinus Torvalds 	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
5159*1da177e4SLinus Torvalds 
5160*1da177e4SLinus Torvalds 	/* if we get here then everything went OK */
5161*1da177e4SLinus Torvalds 
5162*1da177e4SLinus Torvalds 	/* Since we did a RESET, an EraseStripeLock may be needed */
5163*1da177e4SLinus Torvalds 	if (Post == 0xEF10) {
5164*1da177e4SLinus Torvalds 		if ((Config == 0x000F) || (Config == 0x0009))
5165*1da177e4SLinus Torvalds 			ha->requires_esl = 1;
5166*1da177e4SLinus Torvalds 	}
5167*1da177e4SLinus Torvalds 
5168*1da177e4SLinus Torvalds 	return (1);
5169*1da177e4SLinus Torvalds }
5170*1da177e4SLinus Torvalds 
5171*1da177e4SLinus Torvalds /****************************************************************************/
5172*1da177e4SLinus Torvalds /*                                                                          */
5173*1da177e4SLinus Torvalds /* Routine Name: ips_reset_copperhead                                       */
5174*1da177e4SLinus Torvalds /*                                                                          */
5175*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5176*1da177e4SLinus Torvalds /*                                                                          */
5177*1da177e4SLinus Torvalds /*   Reset the controller                                                   */
5178*1da177e4SLinus Torvalds /*                                                                          */
5179*1da177e4SLinus Torvalds /****************************************************************************/
5180*1da177e4SLinus Torvalds static int
5181*1da177e4SLinus Torvalds ips_reset_copperhead(ips_ha_t * ha)
5182*1da177e4SLinus Torvalds {
5183*1da177e4SLinus Torvalds 	int reset_counter;
5184*1da177e4SLinus Torvalds 
5185*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_reset_copperhead", 1);
5186*1da177e4SLinus Torvalds 
5187*1da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
5188*1da177e4SLinus Torvalds 		  ips_name, ha->host_num, ha->io_addr, ha->irq);
5189*1da177e4SLinus Torvalds 
5190*1da177e4SLinus Torvalds 	reset_counter = 0;
5191*1da177e4SLinus Torvalds 
5192*1da177e4SLinus Torvalds 	while (reset_counter < 2) {
5193*1da177e4SLinus Torvalds 		reset_counter++;
5194*1da177e4SLinus Torvalds 
5195*1da177e4SLinus Torvalds 		outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
5196*1da177e4SLinus Torvalds 
5197*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5198*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5199*1da177e4SLinus Torvalds 
5200*1da177e4SLinus Torvalds 		outb(0, ha->io_addr + IPS_REG_SCPR);
5201*1da177e4SLinus Torvalds 
5202*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5203*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5204*1da177e4SLinus Torvalds 
5205*1da177e4SLinus Torvalds 		if ((*ha->func.init) (ha))
5206*1da177e4SLinus Torvalds 			break;
5207*1da177e4SLinus Torvalds 		else if (reset_counter >= 2) {
5208*1da177e4SLinus Torvalds 
5209*1da177e4SLinus Torvalds 			return (0);
5210*1da177e4SLinus Torvalds 		}
5211*1da177e4SLinus Torvalds 	}
5212*1da177e4SLinus Torvalds 
5213*1da177e4SLinus Torvalds 	return (1);
5214*1da177e4SLinus Torvalds }
5215*1da177e4SLinus Torvalds 
5216*1da177e4SLinus Torvalds /****************************************************************************/
5217*1da177e4SLinus Torvalds /*                                                                          */
5218*1da177e4SLinus Torvalds /* Routine Name: ips_reset_copperhead_memio                                 */
5219*1da177e4SLinus Torvalds /*                                                                          */
5220*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5221*1da177e4SLinus Torvalds /*                                                                          */
5222*1da177e4SLinus Torvalds /*   Reset the controller                                                   */
5223*1da177e4SLinus Torvalds /*                                                                          */
5224*1da177e4SLinus Torvalds /****************************************************************************/
5225*1da177e4SLinus Torvalds static int
5226*1da177e4SLinus Torvalds ips_reset_copperhead_memio(ips_ha_t * ha)
5227*1da177e4SLinus Torvalds {
5228*1da177e4SLinus Torvalds 	int reset_counter;
5229*1da177e4SLinus Torvalds 
5230*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_reset_copperhead_memio", 1);
5231*1da177e4SLinus Torvalds 
5232*1da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
5233*1da177e4SLinus Torvalds 		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
5234*1da177e4SLinus Torvalds 
5235*1da177e4SLinus Torvalds 	reset_counter = 0;
5236*1da177e4SLinus Torvalds 
5237*1da177e4SLinus Torvalds 	while (reset_counter < 2) {
5238*1da177e4SLinus Torvalds 		reset_counter++;
5239*1da177e4SLinus Torvalds 
5240*1da177e4SLinus Torvalds 		writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
5241*1da177e4SLinus Torvalds 
5242*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5243*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5244*1da177e4SLinus Torvalds 
5245*1da177e4SLinus Torvalds 		writeb(0, ha->mem_ptr + IPS_REG_SCPR);
5246*1da177e4SLinus Torvalds 
5247*1da177e4SLinus Torvalds 		/* Delay for 1 Second */
5248*1da177e4SLinus Torvalds 		MDELAY(IPS_ONE_SEC);
5249*1da177e4SLinus Torvalds 
5250*1da177e4SLinus Torvalds 		if ((*ha->func.init) (ha))
5251*1da177e4SLinus Torvalds 			break;
5252*1da177e4SLinus Torvalds 		else if (reset_counter >= 2) {
5253*1da177e4SLinus Torvalds 
5254*1da177e4SLinus Torvalds 			return (0);
5255*1da177e4SLinus Torvalds 		}
5256*1da177e4SLinus Torvalds 	}
5257*1da177e4SLinus Torvalds 
5258*1da177e4SLinus Torvalds 	return (1);
5259*1da177e4SLinus Torvalds }
5260*1da177e4SLinus Torvalds 
5261*1da177e4SLinus Torvalds /****************************************************************************/
5262*1da177e4SLinus Torvalds /*                                                                          */
5263*1da177e4SLinus Torvalds /* Routine Name: ips_reset_morpheus                                         */
5264*1da177e4SLinus Torvalds /*                                                                          */
5265*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5266*1da177e4SLinus Torvalds /*                                                                          */
5267*1da177e4SLinus Torvalds /*   Reset the controller                                                   */
5268*1da177e4SLinus Torvalds /*                                                                          */
5269*1da177e4SLinus Torvalds /****************************************************************************/
5270*1da177e4SLinus Torvalds static int
5271*1da177e4SLinus Torvalds ips_reset_morpheus(ips_ha_t * ha)
5272*1da177e4SLinus Torvalds {
5273*1da177e4SLinus Torvalds 	int reset_counter;
5274*1da177e4SLinus Torvalds 	uint8_t junk;
5275*1da177e4SLinus Torvalds 
5276*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_reset_morpheus", 1);
5277*1da177e4SLinus Torvalds 
5278*1da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
5279*1da177e4SLinus Torvalds 		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
5280*1da177e4SLinus Torvalds 
5281*1da177e4SLinus Torvalds 	reset_counter = 0;
5282*1da177e4SLinus Torvalds 
5283*1da177e4SLinus Torvalds 	while (reset_counter < 2) {
5284*1da177e4SLinus Torvalds 		reset_counter++;
5285*1da177e4SLinus Torvalds 
5286*1da177e4SLinus Torvalds 		writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
5287*1da177e4SLinus Torvalds 
5288*1da177e4SLinus Torvalds 		/* Delay for 5 Seconds */
5289*1da177e4SLinus Torvalds 		MDELAY(5 * IPS_ONE_SEC);
5290*1da177e4SLinus Torvalds 
5291*1da177e4SLinus Torvalds 		/* Do a PCI config read to wait for adapter */
5292*1da177e4SLinus Torvalds 		pci_read_config_byte(ha->pcidev, 4, &junk);
5293*1da177e4SLinus Torvalds 
5294*1da177e4SLinus Torvalds 		if ((*ha->func.init) (ha))
5295*1da177e4SLinus Torvalds 			break;
5296*1da177e4SLinus Torvalds 		else if (reset_counter >= 2) {
5297*1da177e4SLinus Torvalds 
5298*1da177e4SLinus Torvalds 			return (0);
5299*1da177e4SLinus Torvalds 		}
5300*1da177e4SLinus Torvalds 	}
5301*1da177e4SLinus Torvalds 
5302*1da177e4SLinus Torvalds 	return (1);
5303*1da177e4SLinus Torvalds }
5304*1da177e4SLinus Torvalds 
5305*1da177e4SLinus Torvalds /****************************************************************************/
5306*1da177e4SLinus Torvalds /*                                                                          */
5307*1da177e4SLinus Torvalds /* Routine Name: ips_statinit                                               */
5308*1da177e4SLinus Torvalds /*                                                                          */
5309*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5310*1da177e4SLinus Torvalds /*                                                                          */
5311*1da177e4SLinus Torvalds /*   Initialize the status queues on the controller                         */
5312*1da177e4SLinus Torvalds /*                                                                          */
5313*1da177e4SLinus Torvalds /****************************************************************************/
5314*1da177e4SLinus Torvalds static void
5315*1da177e4SLinus Torvalds ips_statinit(ips_ha_t * ha)
5316*1da177e4SLinus Torvalds {
5317*1da177e4SLinus Torvalds 	uint32_t phys_status_start;
5318*1da177e4SLinus Torvalds 
5319*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_statinit", 1);
5320*1da177e4SLinus Torvalds 
5321*1da177e4SLinus Torvalds 	ha->adapt->p_status_start = ha->adapt->status;
5322*1da177e4SLinus Torvalds 	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
5323*1da177e4SLinus Torvalds 	ha->adapt->p_status_tail = ha->adapt->status;
5324*1da177e4SLinus Torvalds 
5325*1da177e4SLinus Torvalds 	phys_status_start = ha->adapt->hw_status_start;
5326*1da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);
5327*1da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE),
5328*1da177e4SLinus Torvalds 	     ha->io_addr + IPS_REG_SQER);
5329*1da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE),
5330*1da177e4SLinus Torvalds 	     ha->io_addr + IPS_REG_SQHR);
5331*1da177e4SLinus Torvalds 	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);
5332*1da177e4SLinus Torvalds 
5333*1da177e4SLinus Torvalds 	ha->adapt->hw_status_tail = phys_status_start;
5334*1da177e4SLinus Torvalds }
5335*1da177e4SLinus Torvalds 
5336*1da177e4SLinus Torvalds /****************************************************************************/
5337*1da177e4SLinus Torvalds /*                                                                          */
5338*1da177e4SLinus Torvalds /* Routine Name: ips_statinit_memio                                         */
5339*1da177e4SLinus Torvalds /*                                                                          */
5340*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5341*1da177e4SLinus Torvalds /*                                                                          */
5342*1da177e4SLinus Torvalds /*   Initialize the status queues on the controller                         */
5343*1da177e4SLinus Torvalds /*                                                                          */
5344*1da177e4SLinus Torvalds /****************************************************************************/
5345*1da177e4SLinus Torvalds static void
5346*1da177e4SLinus Torvalds ips_statinit_memio(ips_ha_t * ha)
5347*1da177e4SLinus Torvalds {
5348*1da177e4SLinus Torvalds 	uint32_t phys_status_start;
5349*1da177e4SLinus Torvalds 
5350*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_statinit_memio", 1);
5351*1da177e4SLinus Torvalds 
5352*1da177e4SLinus Torvalds 	ha->adapt->p_status_start = ha->adapt->status;
5353*1da177e4SLinus Torvalds 	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
5354*1da177e4SLinus Torvalds 	ha->adapt->p_status_tail = ha->adapt->status;
5355*1da177e4SLinus Torvalds 
5356*1da177e4SLinus Torvalds 	phys_status_start = ha->adapt->hw_status_start;
5357*1da177e4SLinus Torvalds 	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
5358*1da177e4SLinus Torvalds 	writel(phys_status_start + IPS_STATUS_Q_SIZE,
5359*1da177e4SLinus Torvalds 	       ha->mem_ptr + IPS_REG_SQER);
5360*1da177e4SLinus Torvalds 	writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
5361*1da177e4SLinus Torvalds 	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
5362*1da177e4SLinus Torvalds 
5363*1da177e4SLinus Torvalds 	ha->adapt->hw_status_tail = phys_status_start;
5364*1da177e4SLinus Torvalds }
5365*1da177e4SLinus Torvalds 
5366*1da177e4SLinus Torvalds /****************************************************************************/
5367*1da177e4SLinus Torvalds /*                                                                          */
5368*1da177e4SLinus Torvalds /* Routine Name: ips_statupd_copperhead                                     */
5369*1da177e4SLinus Torvalds /*                                                                          */
5370*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5371*1da177e4SLinus Torvalds /*                                                                          */
5372*1da177e4SLinus Torvalds /*   Remove an element from the status queue                                */
5373*1da177e4SLinus Torvalds /*                                                                          */
5374*1da177e4SLinus Torvalds /****************************************************************************/
5375*1da177e4SLinus Torvalds static uint32_t
5376*1da177e4SLinus Torvalds ips_statupd_copperhead(ips_ha_t * ha)
5377*1da177e4SLinus Torvalds {
5378*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_statupd_copperhead", 1);
5379*1da177e4SLinus Torvalds 
5380*1da177e4SLinus Torvalds 	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
5381*1da177e4SLinus Torvalds 		ha->adapt->p_status_tail++;
5382*1da177e4SLinus Torvalds 		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
5383*1da177e4SLinus Torvalds 	} else {
5384*1da177e4SLinus Torvalds 		ha->adapt->p_status_tail = ha->adapt->p_status_start;
5385*1da177e4SLinus Torvalds 		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
5386*1da177e4SLinus Torvalds 	}
5387*1da177e4SLinus Torvalds 
5388*1da177e4SLinus Torvalds 	outl(cpu_to_le32(ha->adapt->hw_status_tail),
5389*1da177e4SLinus Torvalds 	     ha->io_addr + IPS_REG_SQTR);
5390*1da177e4SLinus Torvalds 
5391*1da177e4SLinus Torvalds 	return (ha->adapt->p_status_tail->value);
5392*1da177e4SLinus Torvalds }
5393*1da177e4SLinus Torvalds 
5394*1da177e4SLinus Torvalds /****************************************************************************/
5395*1da177e4SLinus Torvalds /*                                                                          */
5396*1da177e4SLinus Torvalds /* Routine Name: ips_statupd_copperhead_memio                               */
5397*1da177e4SLinus Torvalds /*                                                                          */
5398*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5399*1da177e4SLinus Torvalds /*                                                                          */
5400*1da177e4SLinus Torvalds /*   Remove an element from the status queue                                */
5401*1da177e4SLinus Torvalds /*                                                                          */
5402*1da177e4SLinus Torvalds /****************************************************************************/
5403*1da177e4SLinus Torvalds static uint32_t
5404*1da177e4SLinus Torvalds ips_statupd_copperhead_memio(ips_ha_t * ha)
5405*1da177e4SLinus Torvalds {
5406*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_statupd_copperhead_memio", 1);
5407*1da177e4SLinus Torvalds 
5408*1da177e4SLinus Torvalds 	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
5409*1da177e4SLinus Torvalds 		ha->adapt->p_status_tail++;
5410*1da177e4SLinus Torvalds 		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
5411*1da177e4SLinus Torvalds 	} else {
5412*1da177e4SLinus Torvalds 		ha->adapt->p_status_tail = ha->adapt->p_status_start;
5413*1da177e4SLinus Torvalds 		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
5414*1da177e4SLinus Torvalds 	}
5415*1da177e4SLinus Torvalds 
5416*1da177e4SLinus Torvalds 	writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
5417*1da177e4SLinus Torvalds 
5418*1da177e4SLinus Torvalds 	return (ha->adapt->p_status_tail->value);
5419*1da177e4SLinus Torvalds }
5420*1da177e4SLinus Torvalds 
5421*1da177e4SLinus Torvalds /****************************************************************************/
5422*1da177e4SLinus Torvalds /*                                                                          */
5423*1da177e4SLinus Torvalds /* Routine Name: ips_statupd_morpheus                                       */
5424*1da177e4SLinus Torvalds /*                                                                          */
5425*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5426*1da177e4SLinus Torvalds /*                                                                          */
5427*1da177e4SLinus Torvalds /*   Remove an element from the status queue                                */
5428*1da177e4SLinus Torvalds /*                                                                          */
5429*1da177e4SLinus Torvalds /****************************************************************************/
5430*1da177e4SLinus Torvalds static uint32_t
5431*1da177e4SLinus Torvalds ips_statupd_morpheus(ips_ha_t * ha)
5432*1da177e4SLinus Torvalds {
5433*1da177e4SLinus Torvalds 	uint32_t val;
5434*1da177e4SLinus Torvalds 
5435*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_statupd_morpheus", 1);
5436*1da177e4SLinus Torvalds 
5437*1da177e4SLinus Torvalds 	val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
5438*1da177e4SLinus Torvalds 
5439*1da177e4SLinus Torvalds 	return (val);
5440*1da177e4SLinus Torvalds }
5441*1da177e4SLinus Torvalds 
5442*1da177e4SLinus Torvalds /****************************************************************************/
5443*1da177e4SLinus Torvalds /*                                                                          */
5444*1da177e4SLinus Torvalds /* Routine Name: ips_issue_copperhead                                       */
5445*1da177e4SLinus Torvalds /*                                                                          */
5446*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5447*1da177e4SLinus Torvalds /*                                                                          */
5448*1da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
5449*1da177e4SLinus Torvalds /*                                                                          */
5450*1da177e4SLinus Torvalds /****************************************************************************/
5451*1da177e4SLinus Torvalds static int
5452*1da177e4SLinus Torvalds ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb)
5453*1da177e4SLinus Torvalds {
5454*1da177e4SLinus Torvalds 	uint32_t TimeOut;
5455*1da177e4SLinus Torvalds 	uint32_t val;
5456*1da177e4SLinus Torvalds 
5457*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_copperhead", 1);
5458*1da177e4SLinus Torvalds 
5459*1da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
5460*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5461*1da177e4SLinus Torvalds 			  ips_name,
5462*1da177e4SLinus Torvalds 			  ha->host_num,
5463*1da177e4SLinus Torvalds 			  scb->cdb[0],
5464*1da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
5465*1da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
5466*1da177e4SLinus Torvalds 	} else {
5467*1da177e4SLinus Torvalds 		DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
5468*1da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5469*1da177e4SLinus Torvalds 	}
5470*1da177e4SLinus Torvalds 
5471*1da177e4SLinus Torvalds 	TimeOut = 0;
5472*1da177e4SLinus Torvalds 
5473*1da177e4SLinus Torvalds 	while ((val =
5474*1da177e4SLinus Torvalds 		le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
5475*1da177e4SLinus Torvalds 		udelay(1000);
5476*1da177e4SLinus Torvalds 
5477*1da177e4SLinus Torvalds 		if (++TimeOut >= IPS_SEM_TIMEOUT) {
5478*1da177e4SLinus Torvalds 			if (!(val & IPS_BIT_START_STOP))
5479*1da177e4SLinus Torvalds 				break;
5480*1da177e4SLinus Torvalds 
5481*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
5482*1da177e4SLinus Torvalds 				   "ips_issue val [0x%x].\n", val);
5483*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
5484*1da177e4SLinus Torvalds 				   "ips_issue semaphore chk timeout.\n");
5485*1da177e4SLinus Torvalds 
5486*1da177e4SLinus Torvalds 			return (IPS_FAILURE);
5487*1da177e4SLinus Torvalds 		}		/* end if */
5488*1da177e4SLinus Torvalds 	}			/* end while */
5489*1da177e4SLinus Torvalds 
5490*1da177e4SLinus Torvalds 	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
5491*1da177e4SLinus Torvalds 	outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
5492*1da177e4SLinus Torvalds 
5493*1da177e4SLinus Torvalds 	return (IPS_SUCCESS);
5494*1da177e4SLinus Torvalds }
5495*1da177e4SLinus Torvalds 
5496*1da177e4SLinus Torvalds /****************************************************************************/
5497*1da177e4SLinus Torvalds /*                                                                          */
5498*1da177e4SLinus Torvalds /* Routine Name: ips_issue_copperhead_memio                                 */
5499*1da177e4SLinus Torvalds /*                                                                          */
5500*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5501*1da177e4SLinus Torvalds /*                                                                          */
5502*1da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
5503*1da177e4SLinus Torvalds /*                                                                          */
5504*1da177e4SLinus Torvalds /****************************************************************************/
5505*1da177e4SLinus Torvalds static int
5506*1da177e4SLinus Torvalds ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb)
5507*1da177e4SLinus Torvalds {
5508*1da177e4SLinus Torvalds 	uint32_t TimeOut;
5509*1da177e4SLinus Torvalds 	uint32_t val;
5510*1da177e4SLinus Torvalds 
5511*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_copperhead_memio", 1);
5512*1da177e4SLinus Torvalds 
5513*1da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
5514*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5515*1da177e4SLinus Torvalds 			  ips_name,
5516*1da177e4SLinus Torvalds 			  ha->host_num,
5517*1da177e4SLinus Torvalds 			  scb->cdb[0],
5518*1da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
5519*1da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
5520*1da177e4SLinus Torvalds 	} else {
5521*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
5522*1da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5523*1da177e4SLinus Torvalds 	}
5524*1da177e4SLinus Torvalds 
5525*1da177e4SLinus Torvalds 	TimeOut = 0;
5526*1da177e4SLinus Torvalds 
5527*1da177e4SLinus Torvalds 	while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
5528*1da177e4SLinus Torvalds 		udelay(1000);
5529*1da177e4SLinus Torvalds 
5530*1da177e4SLinus Torvalds 		if (++TimeOut >= IPS_SEM_TIMEOUT) {
5531*1da177e4SLinus Torvalds 			if (!(val & IPS_BIT_START_STOP))
5532*1da177e4SLinus Torvalds 				break;
5533*1da177e4SLinus Torvalds 
5534*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
5535*1da177e4SLinus Torvalds 				   "ips_issue val [0x%x].\n", val);
5536*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
5537*1da177e4SLinus Torvalds 				   "ips_issue semaphore chk timeout.\n");
5538*1da177e4SLinus Torvalds 
5539*1da177e4SLinus Torvalds 			return (IPS_FAILURE);
5540*1da177e4SLinus Torvalds 		}		/* end if */
5541*1da177e4SLinus Torvalds 	}			/* end while */
5542*1da177e4SLinus Torvalds 
5543*1da177e4SLinus Torvalds 	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
5544*1da177e4SLinus Torvalds 	writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
5545*1da177e4SLinus Torvalds 
5546*1da177e4SLinus Torvalds 	return (IPS_SUCCESS);
5547*1da177e4SLinus Torvalds }
5548*1da177e4SLinus Torvalds 
5549*1da177e4SLinus Torvalds /****************************************************************************/
5550*1da177e4SLinus Torvalds /*                                                                          */
5551*1da177e4SLinus Torvalds /* Routine Name: ips_issue_i2o                                              */
5552*1da177e4SLinus Torvalds /*                                                                          */
5553*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5554*1da177e4SLinus Torvalds /*                                                                          */
5555*1da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
5556*1da177e4SLinus Torvalds /*                                                                          */
5557*1da177e4SLinus Torvalds /****************************************************************************/
5558*1da177e4SLinus Torvalds static int
5559*1da177e4SLinus Torvalds ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb)
5560*1da177e4SLinus Torvalds {
5561*1da177e4SLinus Torvalds 
5562*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_i2o", 1);
5563*1da177e4SLinus Torvalds 
5564*1da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
5565*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5566*1da177e4SLinus Torvalds 			  ips_name,
5567*1da177e4SLinus Torvalds 			  ha->host_num,
5568*1da177e4SLinus Torvalds 			  scb->cdb[0],
5569*1da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
5570*1da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
5571*1da177e4SLinus Torvalds 	} else {
5572*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
5573*1da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5574*1da177e4SLinus Torvalds 	}
5575*1da177e4SLinus Torvalds 
5576*1da177e4SLinus Torvalds 	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
5577*1da177e4SLinus Torvalds 
5578*1da177e4SLinus Torvalds 	return (IPS_SUCCESS);
5579*1da177e4SLinus Torvalds }
5580*1da177e4SLinus Torvalds 
5581*1da177e4SLinus Torvalds /****************************************************************************/
5582*1da177e4SLinus Torvalds /*                                                                          */
5583*1da177e4SLinus Torvalds /* Routine Name: ips_issue_i2o_memio                                        */
5584*1da177e4SLinus Torvalds /*                                                                          */
5585*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5586*1da177e4SLinus Torvalds /*                                                                          */
5587*1da177e4SLinus Torvalds /*   Send a command down to the controller                                  */
5588*1da177e4SLinus Torvalds /*                                                                          */
5589*1da177e4SLinus Torvalds /****************************************************************************/
5590*1da177e4SLinus Torvalds static int
5591*1da177e4SLinus Torvalds ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb)
5592*1da177e4SLinus Torvalds {
5593*1da177e4SLinus Torvalds 
5594*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_issue_i2o_memio", 1);
5595*1da177e4SLinus Torvalds 
5596*1da177e4SLinus Torvalds 	if (scb->scsi_cmd) {
5597*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5598*1da177e4SLinus Torvalds 			  ips_name,
5599*1da177e4SLinus Torvalds 			  ha->host_num,
5600*1da177e4SLinus Torvalds 			  scb->cdb[0],
5601*1da177e4SLinus Torvalds 			  scb->cmd.basic_io.command_id,
5602*1da177e4SLinus Torvalds 			  scb->bus, scb->target_id, scb->lun);
5603*1da177e4SLinus Torvalds 	} else {
5604*1da177e4SLinus Torvalds 		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
5605*1da177e4SLinus Torvalds 			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5606*1da177e4SLinus Torvalds 	}
5607*1da177e4SLinus Torvalds 
5608*1da177e4SLinus Torvalds 	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
5609*1da177e4SLinus Torvalds 
5610*1da177e4SLinus Torvalds 	return (IPS_SUCCESS);
5611*1da177e4SLinus Torvalds }
5612*1da177e4SLinus Torvalds 
5613*1da177e4SLinus Torvalds /****************************************************************************/
5614*1da177e4SLinus Torvalds /*                                                                          */
5615*1da177e4SLinus Torvalds /* Routine Name: ips_isintr_copperhead                                      */
5616*1da177e4SLinus Torvalds /*                                                                          */
5617*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5618*1da177e4SLinus Torvalds /*                                                                          */
5619*1da177e4SLinus Torvalds /*   Test to see if an interrupt is for us                                  */
5620*1da177e4SLinus Torvalds /*                                                                          */
5621*1da177e4SLinus Torvalds /****************************************************************************/
5622*1da177e4SLinus Torvalds static int
5623*1da177e4SLinus Torvalds ips_isintr_copperhead(ips_ha_t * ha)
5624*1da177e4SLinus Torvalds {
5625*1da177e4SLinus Torvalds 	uint8_t Isr;
5626*1da177e4SLinus Torvalds 
5627*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_isintr_copperhead", 2);
5628*1da177e4SLinus Torvalds 
5629*1da177e4SLinus Torvalds 	Isr = inb(ha->io_addr + IPS_REG_HISR);
5630*1da177e4SLinus Torvalds 
5631*1da177e4SLinus Torvalds 	if (Isr == 0xFF)
5632*1da177e4SLinus Torvalds 		/* ?!?! Nothing really there */
5633*1da177e4SLinus Torvalds 		return (0);
5634*1da177e4SLinus Torvalds 
5635*1da177e4SLinus Torvalds 	if (Isr & IPS_BIT_SCE)
5636*1da177e4SLinus Torvalds 		return (1);
5637*1da177e4SLinus Torvalds 	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
5638*1da177e4SLinus Torvalds 		/* status queue overflow or GHI */
5639*1da177e4SLinus Torvalds 		/* just clear the interrupt */
5640*1da177e4SLinus Torvalds 		outb(Isr, ha->io_addr + IPS_REG_HISR);
5641*1da177e4SLinus Torvalds 	}
5642*1da177e4SLinus Torvalds 
5643*1da177e4SLinus Torvalds 	return (0);
5644*1da177e4SLinus Torvalds }
5645*1da177e4SLinus Torvalds 
5646*1da177e4SLinus Torvalds /****************************************************************************/
5647*1da177e4SLinus Torvalds /*                                                                          */
5648*1da177e4SLinus Torvalds /* Routine Name: ips_isintr_copperhead_memio                                */
5649*1da177e4SLinus Torvalds /*                                                                          */
5650*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5651*1da177e4SLinus Torvalds /*                                                                          */
5652*1da177e4SLinus Torvalds /*   Test to see if an interrupt is for us                                  */
5653*1da177e4SLinus Torvalds /*                                                                          */
5654*1da177e4SLinus Torvalds /****************************************************************************/
5655*1da177e4SLinus Torvalds static int
5656*1da177e4SLinus Torvalds ips_isintr_copperhead_memio(ips_ha_t * ha)
5657*1da177e4SLinus Torvalds {
5658*1da177e4SLinus Torvalds 	uint8_t Isr;
5659*1da177e4SLinus Torvalds 
5660*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_isintr_memio", 2);
5661*1da177e4SLinus Torvalds 
5662*1da177e4SLinus Torvalds 	Isr = readb(ha->mem_ptr + IPS_REG_HISR);
5663*1da177e4SLinus Torvalds 
5664*1da177e4SLinus Torvalds 	if (Isr == 0xFF)
5665*1da177e4SLinus Torvalds 		/* ?!?! Nothing really there */
5666*1da177e4SLinus Torvalds 		return (0);
5667*1da177e4SLinus Torvalds 
5668*1da177e4SLinus Torvalds 	if (Isr & IPS_BIT_SCE)
5669*1da177e4SLinus Torvalds 		return (1);
5670*1da177e4SLinus Torvalds 	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
5671*1da177e4SLinus Torvalds 		/* status queue overflow or GHI */
5672*1da177e4SLinus Torvalds 		/* just clear the interrupt */
5673*1da177e4SLinus Torvalds 		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
5674*1da177e4SLinus Torvalds 	}
5675*1da177e4SLinus Torvalds 
5676*1da177e4SLinus Torvalds 	return (0);
5677*1da177e4SLinus Torvalds }
5678*1da177e4SLinus Torvalds 
5679*1da177e4SLinus Torvalds /****************************************************************************/
5680*1da177e4SLinus Torvalds /*                                                                          */
5681*1da177e4SLinus Torvalds /* Routine Name: ips_isintr_morpheus                                        */
5682*1da177e4SLinus Torvalds /*                                                                          */
5683*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5684*1da177e4SLinus Torvalds /*                                                                          */
5685*1da177e4SLinus Torvalds /*   Test to see if an interrupt is for us                                  */
5686*1da177e4SLinus Torvalds /*                                                                          */
5687*1da177e4SLinus Torvalds /****************************************************************************/
5688*1da177e4SLinus Torvalds static int
5689*1da177e4SLinus Torvalds ips_isintr_morpheus(ips_ha_t * ha)
5690*1da177e4SLinus Torvalds {
5691*1da177e4SLinus Torvalds 	uint32_t Isr;
5692*1da177e4SLinus Torvalds 
5693*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_isintr_morpheus", 2);
5694*1da177e4SLinus Torvalds 
5695*1da177e4SLinus Torvalds 	Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
5696*1da177e4SLinus Torvalds 
5697*1da177e4SLinus Torvalds 	if (Isr & IPS_BIT_I2O_OPQI)
5698*1da177e4SLinus Torvalds 		return (1);
5699*1da177e4SLinus Torvalds 	else
5700*1da177e4SLinus Torvalds 		return (0);
5701*1da177e4SLinus Torvalds }
5702*1da177e4SLinus Torvalds 
5703*1da177e4SLinus Torvalds /****************************************************************************/
5704*1da177e4SLinus Torvalds /*                                                                          */
5705*1da177e4SLinus Torvalds /* Routine Name: ips_wait                                                   */
5706*1da177e4SLinus Torvalds /*                                                                          */
5707*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5708*1da177e4SLinus Torvalds /*                                                                          */
5709*1da177e4SLinus Torvalds /*   Wait for a command to complete                                         */
5710*1da177e4SLinus Torvalds /*                                                                          */
5711*1da177e4SLinus Torvalds /****************************************************************************/
5712*1da177e4SLinus Torvalds static int
5713*1da177e4SLinus Torvalds ips_wait(ips_ha_t * ha, int time, int intr)
5714*1da177e4SLinus Torvalds {
5715*1da177e4SLinus Torvalds 	int ret;
5716*1da177e4SLinus Torvalds 	int done;
5717*1da177e4SLinus Torvalds 
5718*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_wait", 1);
5719*1da177e4SLinus Torvalds 
5720*1da177e4SLinus Torvalds 	ret = IPS_FAILURE;
5721*1da177e4SLinus Torvalds 	done = FALSE;
5722*1da177e4SLinus Torvalds 
5723*1da177e4SLinus Torvalds 	time *= IPS_ONE_SEC;	/* convert seconds */
5724*1da177e4SLinus Torvalds 
5725*1da177e4SLinus Torvalds 	while ((time > 0) && (!done)) {
5726*1da177e4SLinus Torvalds 		if (intr == IPS_INTR_ON) {
5727*1da177e4SLinus Torvalds 			if (ha->waitflag == FALSE) {
5728*1da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
5729*1da177e4SLinus Torvalds 				done = TRUE;
5730*1da177e4SLinus Torvalds 				break;
5731*1da177e4SLinus Torvalds 			}
5732*1da177e4SLinus Torvalds 		} else if (intr == IPS_INTR_IORL) {
5733*1da177e4SLinus Torvalds 			if (ha->waitflag == FALSE) {
5734*1da177e4SLinus Torvalds 				/*
5735*1da177e4SLinus Torvalds 				 * controller generated an interrupt to
5736*1da177e4SLinus Torvalds 				 * acknowledge completion of the command
5737*1da177e4SLinus Torvalds 				 * and ips_intr() has serviced the interrupt.
5738*1da177e4SLinus Torvalds 				 */
5739*1da177e4SLinus Torvalds 				ret = IPS_SUCCESS;
5740*1da177e4SLinus Torvalds 				done = TRUE;
5741*1da177e4SLinus Torvalds 				break;
5742*1da177e4SLinus Torvalds 			}
5743*1da177e4SLinus Torvalds 
5744*1da177e4SLinus Torvalds 			/*
5745*1da177e4SLinus Torvalds 			 * NOTE: we already have the io_request_lock so
5746*1da177e4SLinus Torvalds 			 * even if we get an interrupt it won't get serviced
5747*1da177e4SLinus Torvalds 			 * until after we finish.
5748*1da177e4SLinus Torvalds 			 */
5749*1da177e4SLinus Torvalds 
5750*1da177e4SLinus Torvalds 			(*ha->func.intr) (ha);
5751*1da177e4SLinus Torvalds 		}
5752*1da177e4SLinus Torvalds 
5753*1da177e4SLinus Torvalds 		/* This looks like a very evil loop, but it only does this during start-up */
5754*1da177e4SLinus Torvalds 		udelay(1000);
5755*1da177e4SLinus Torvalds 		time--;
5756*1da177e4SLinus Torvalds 	}
5757*1da177e4SLinus Torvalds 
5758*1da177e4SLinus Torvalds 	return (ret);
5759*1da177e4SLinus Torvalds }
5760*1da177e4SLinus Torvalds 
5761*1da177e4SLinus Torvalds /****************************************************************************/
5762*1da177e4SLinus Torvalds /*                                                                          */
5763*1da177e4SLinus Torvalds /* Routine Name: ips_write_driver_status                                    */
5764*1da177e4SLinus Torvalds /*                                                                          */
5765*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5766*1da177e4SLinus Torvalds /*                                                                          */
5767*1da177e4SLinus Torvalds /*   Write OS/Driver version to Page 5 of the nvram on the controller       */
5768*1da177e4SLinus Torvalds /*                                                                          */
5769*1da177e4SLinus Torvalds /****************************************************************************/
5770*1da177e4SLinus Torvalds static int
5771*1da177e4SLinus Torvalds ips_write_driver_status(ips_ha_t * ha, int intr)
5772*1da177e4SLinus Torvalds {
5773*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_write_driver_status", 1);
5774*1da177e4SLinus Torvalds 
5775*1da177e4SLinus Torvalds 	if (!ips_readwrite_page5(ha, FALSE, intr)) {
5776*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
5777*1da177e4SLinus Torvalds 			   "unable to read NVRAM page 5.\n");
5778*1da177e4SLinus Torvalds 
5779*1da177e4SLinus Torvalds 		return (0);
5780*1da177e4SLinus Torvalds 	}
5781*1da177e4SLinus Torvalds 
5782*1da177e4SLinus Torvalds 	/* check to make sure the page has a valid */
5783*1da177e4SLinus Torvalds 	/* signature */
5784*1da177e4SLinus Torvalds 	if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
5785*1da177e4SLinus Torvalds 		DEBUG_VAR(1,
5786*1da177e4SLinus Torvalds 			  "(%s%d) NVRAM page 5 has an invalid signature: %X.",
5787*1da177e4SLinus Torvalds 			  ips_name, ha->host_num, ha->nvram->signature);
5788*1da177e4SLinus Torvalds 		ha->nvram->signature = IPS_NVRAM_P5_SIG;
5789*1da177e4SLinus Torvalds 	}
5790*1da177e4SLinus Torvalds 
5791*1da177e4SLinus Torvalds 	DEBUG_VAR(2,
5792*1da177e4SLinus Torvalds 		  "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
5793*1da177e4SLinus Torvalds 		  ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),
5794*1da177e4SLinus Torvalds 		  ha->nvram->adapter_slot, ha->nvram->bios_high[0],
5795*1da177e4SLinus Torvalds 		  ha->nvram->bios_high[1], ha->nvram->bios_high[2],
5796*1da177e4SLinus Torvalds 		  ha->nvram->bios_high[3], ha->nvram->bios_low[0],
5797*1da177e4SLinus Torvalds 		  ha->nvram->bios_low[1], ha->nvram->bios_low[2],
5798*1da177e4SLinus Torvalds 		  ha->nvram->bios_low[3]);
5799*1da177e4SLinus Torvalds 
5800*1da177e4SLinus Torvalds 	ips_get_bios_version(ha, intr);
5801*1da177e4SLinus Torvalds 
5802*1da177e4SLinus Torvalds 	/* change values (as needed) */
5803*1da177e4SLinus Torvalds 	ha->nvram->operating_system = IPS_OS_LINUX;
5804*1da177e4SLinus Torvalds 	ha->nvram->adapter_type = ha->ad_type;
5805*1da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
5806*1da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);
5807*1da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
5808*1da177e4SLinus Torvalds 	strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
5809*1da177e4SLinus Torvalds 
5810*1da177e4SLinus Torvalds 	ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */
5811*1da177e4SLinus Torvalds 
5812*1da177e4SLinus Torvalds 	/* now update the page */
5813*1da177e4SLinus Torvalds 	if (!ips_readwrite_page5(ha, TRUE, intr)) {
5814*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
5815*1da177e4SLinus Torvalds 			   "unable to write NVRAM page 5.\n");
5816*1da177e4SLinus Torvalds 
5817*1da177e4SLinus Torvalds 		return (0);
5818*1da177e4SLinus Torvalds 	}
5819*1da177e4SLinus Torvalds 
5820*1da177e4SLinus Torvalds 	/* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
5821*1da177e4SLinus Torvalds 	ha->slot_num = ha->nvram->adapter_slot;
5822*1da177e4SLinus Torvalds 
5823*1da177e4SLinus Torvalds 	return (1);
5824*1da177e4SLinus Torvalds }
5825*1da177e4SLinus Torvalds 
5826*1da177e4SLinus Torvalds /****************************************************************************/
5827*1da177e4SLinus Torvalds /*                                                                          */
5828*1da177e4SLinus Torvalds /* Routine Name: ips_read_adapter_status                                    */
5829*1da177e4SLinus Torvalds /*                                                                          */
5830*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5831*1da177e4SLinus Torvalds /*                                                                          */
5832*1da177e4SLinus Torvalds /*   Do an Inquiry command to the adapter                                   */
5833*1da177e4SLinus Torvalds /*                                                                          */
5834*1da177e4SLinus Torvalds /****************************************************************************/
5835*1da177e4SLinus Torvalds static int
5836*1da177e4SLinus Torvalds ips_read_adapter_status(ips_ha_t * ha, int intr)
5837*1da177e4SLinus Torvalds {
5838*1da177e4SLinus Torvalds 	ips_scb_t *scb;
5839*1da177e4SLinus Torvalds 	int ret;
5840*1da177e4SLinus Torvalds 
5841*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_read_adapter_status", 1);
5842*1da177e4SLinus Torvalds 
5843*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
5844*1da177e4SLinus Torvalds 
5845*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
5846*1da177e4SLinus Torvalds 
5847*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
5848*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_ENQUIRY;
5849*1da177e4SLinus Torvalds 
5850*1da177e4SLinus Torvalds 	scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
5851*1da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
5852*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_count = 0;
5853*1da177e4SLinus Torvalds 	scb->cmd.basic_io.lba = 0;
5854*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sector_count = 0;
5855*1da177e4SLinus Torvalds 	scb->cmd.basic_io.log_drv = 0;
5856*1da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->enq);
5857*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
5858*1da177e4SLinus Torvalds 
5859*1da177e4SLinus Torvalds 	/* send command */
5860*1da177e4SLinus Torvalds 	if (((ret =
5861*1da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5862*1da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
5863*1da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
5864*1da177e4SLinus Torvalds 		return (0);
5865*1da177e4SLinus Torvalds 
5866*1da177e4SLinus Torvalds 	return (1);
5867*1da177e4SLinus Torvalds }
5868*1da177e4SLinus Torvalds 
5869*1da177e4SLinus Torvalds /****************************************************************************/
5870*1da177e4SLinus Torvalds /*                                                                          */
5871*1da177e4SLinus Torvalds /* Routine Name: ips_read_subsystem_parameters                              */
5872*1da177e4SLinus Torvalds /*                                                                          */
5873*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5874*1da177e4SLinus Torvalds /*                                                                          */
5875*1da177e4SLinus Torvalds /*   Read subsystem parameters from the adapter                             */
5876*1da177e4SLinus Torvalds /*                                                                          */
5877*1da177e4SLinus Torvalds /****************************************************************************/
5878*1da177e4SLinus Torvalds static int
5879*1da177e4SLinus Torvalds ips_read_subsystem_parameters(ips_ha_t * ha, int intr)
5880*1da177e4SLinus Torvalds {
5881*1da177e4SLinus Torvalds 	ips_scb_t *scb;
5882*1da177e4SLinus Torvalds 	int ret;
5883*1da177e4SLinus Torvalds 
5884*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_read_subsystem_parameters", 1);
5885*1da177e4SLinus Torvalds 
5886*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
5887*1da177e4SLinus Torvalds 
5888*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
5889*1da177e4SLinus Torvalds 
5890*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
5891*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_GET_SUBSYS;
5892*1da177e4SLinus Torvalds 
5893*1da177e4SLinus Torvalds 	scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
5894*1da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
5895*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_count = 0;
5896*1da177e4SLinus Torvalds 	scb->cmd.basic_io.lba = 0;
5897*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sector_count = 0;
5898*1da177e4SLinus Torvalds 	scb->cmd.basic_io.log_drv = 0;
5899*1da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->subsys);
5900*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
5901*1da177e4SLinus Torvalds 
5902*1da177e4SLinus Torvalds 	/* send command */
5903*1da177e4SLinus Torvalds 	if (((ret =
5904*1da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5905*1da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
5906*1da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
5907*1da177e4SLinus Torvalds 		return (0);
5908*1da177e4SLinus Torvalds 
5909*1da177e4SLinus Torvalds 	memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys));
5910*1da177e4SLinus Torvalds 	return (1);
5911*1da177e4SLinus Torvalds }
5912*1da177e4SLinus Torvalds 
5913*1da177e4SLinus Torvalds /****************************************************************************/
5914*1da177e4SLinus Torvalds /*                                                                          */
5915*1da177e4SLinus Torvalds /* Routine Name: ips_read_config                                            */
5916*1da177e4SLinus Torvalds /*                                                                          */
5917*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5918*1da177e4SLinus Torvalds /*                                                                          */
5919*1da177e4SLinus Torvalds /*   Read the configuration on the adapter                                  */
5920*1da177e4SLinus Torvalds /*                                                                          */
5921*1da177e4SLinus Torvalds /****************************************************************************/
5922*1da177e4SLinus Torvalds static int
5923*1da177e4SLinus Torvalds ips_read_config(ips_ha_t * ha, int intr)
5924*1da177e4SLinus Torvalds {
5925*1da177e4SLinus Torvalds 	ips_scb_t *scb;
5926*1da177e4SLinus Torvalds 	int i;
5927*1da177e4SLinus Torvalds 	int ret;
5928*1da177e4SLinus Torvalds 
5929*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_read_config", 1);
5930*1da177e4SLinus Torvalds 
5931*1da177e4SLinus Torvalds 	/* set defaults for initiator IDs */
5932*1da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
5933*1da177e4SLinus Torvalds 		ha->conf->init_id[i] = 7;
5934*1da177e4SLinus Torvalds 
5935*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
5936*1da177e4SLinus Torvalds 
5937*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
5938*1da177e4SLinus Torvalds 
5939*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
5940*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_READ_CONF;
5941*1da177e4SLinus Torvalds 
5942*1da177e4SLinus Torvalds 	scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
5943*1da177e4SLinus Torvalds 	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
5944*1da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->conf);
5945*1da177e4SLinus Torvalds 	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
5946*1da177e4SLinus Torvalds 
5947*1da177e4SLinus Torvalds 	/* send command */
5948*1da177e4SLinus Torvalds 	if (((ret =
5949*1da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5950*1da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
5951*1da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
5952*1da177e4SLinus Torvalds 
5953*1da177e4SLinus Torvalds 		memset(ha->conf, 0, sizeof (IPS_CONF));
5954*1da177e4SLinus Torvalds 
5955*1da177e4SLinus Torvalds 		/* reset initiator IDs */
5956*1da177e4SLinus Torvalds 		for (i = 0; i < 4; i++)
5957*1da177e4SLinus Torvalds 			ha->conf->init_id[i] = 7;
5958*1da177e4SLinus Torvalds 
5959*1da177e4SLinus Torvalds 		/* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
5960*1da177e4SLinus Torvalds 		if ((scb->basic_status & IPS_GSC_STATUS_MASK) ==
5961*1da177e4SLinus Torvalds 		    IPS_CMD_CMPLT_WERROR)
5962*1da177e4SLinus Torvalds 			return (1);
5963*1da177e4SLinus Torvalds 
5964*1da177e4SLinus Torvalds 		return (0);
5965*1da177e4SLinus Torvalds 	}
5966*1da177e4SLinus Torvalds 
5967*1da177e4SLinus Torvalds 	memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
5968*1da177e4SLinus Torvalds 	return (1);
5969*1da177e4SLinus Torvalds }
5970*1da177e4SLinus Torvalds 
5971*1da177e4SLinus Torvalds /****************************************************************************/
5972*1da177e4SLinus Torvalds /*                                                                          */
5973*1da177e4SLinus Torvalds /* Routine Name: ips_readwrite_page5                                        */
5974*1da177e4SLinus Torvalds /*                                                                          */
5975*1da177e4SLinus Torvalds /* Routine Description:                                                     */
5976*1da177e4SLinus Torvalds /*                                                                          */
5977*1da177e4SLinus Torvalds /*   Read nvram page 5 from the adapter                                     */
5978*1da177e4SLinus Torvalds /*                                                                          */
5979*1da177e4SLinus Torvalds /****************************************************************************/
5980*1da177e4SLinus Torvalds static int
5981*1da177e4SLinus Torvalds ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
5982*1da177e4SLinus Torvalds {
5983*1da177e4SLinus Torvalds 	ips_scb_t *scb;
5984*1da177e4SLinus Torvalds 	int ret;
5985*1da177e4SLinus Torvalds 
5986*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_readwrite_page5", 1);
5987*1da177e4SLinus Torvalds 
5988*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
5989*1da177e4SLinus Torvalds 
5990*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
5991*1da177e4SLinus Torvalds 
5992*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
5993*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;
5994*1da177e4SLinus Torvalds 
5995*1da177e4SLinus Torvalds 	scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;
5996*1da177e4SLinus Torvalds 	scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
5997*1da177e4SLinus Torvalds 	scb->cmd.nvram.page = 5;
5998*1da177e4SLinus Torvalds 	scb->cmd.nvram.write = write;
5999*1da177e4SLinus Torvalds 	scb->cmd.nvram.reserved = 0;
6000*1da177e4SLinus Torvalds 	scb->cmd.nvram.reserved2 = 0;
6001*1da177e4SLinus Torvalds 	scb->data_len = sizeof (*ha->nvram);
6002*1da177e4SLinus Torvalds 	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
6003*1da177e4SLinus Torvalds 	if (write)
6004*1da177e4SLinus Torvalds 		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
6005*1da177e4SLinus Torvalds 
6006*1da177e4SLinus Torvalds 	/* issue the command */
6007*1da177e4SLinus Torvalds 	if (((ret =
6008*1da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
6009*1da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
6010*1da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
6011*1da177e4SLinus Torvalds 
6012*1da177e4SLinus Torvalds 		memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));
6013*1da177e4SLinus Torvalds 
6014*1da177e4SLinus Torvalds 		return (0);
6015*1da177e4SLinus Torvalds 	}
6016*1da177e4SLinus Torvalds 	if (!write)
6017*1da177e4SLinus Torvalds 		memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram));
6018*1da177e4SLinus Torvalds 	return (1);
6019*1da177e4SLinus Torvalds }
6020*1da177e4SLinus Torvalds 
6021*1da177e4SLinus Torvalds /****************************************************************************/
6022*1da177e4SLinus Torvalds /*                                                                          */
6023*1da177e4SLinus Torvalds /* Routine Name: ips_clear_adapter                                          */
6024*1da177e4SLinus Torvalds /*                                                                          */
6025*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6026*1da177e4SLinus Torvalds /*                                                                          */
6027*1da177e4SLinus Torvalds /*   Clear the stripe lock tables                                           */
6028*1da177e4SLinus Torvalds /*                                                                          */
6029*1da177e4SLinus Torvalds /****************************************************************************/
6030*1da177e4SLinus Torvalds static int
6031*1da177e4SLinus Torvalds ips_clear_adapter(ips_ha_t * ha, int intr)
6032*1da177e4SLinus Torvalds {
6033*1da177e4SLinus Torvalds 	ips_scb_t *scb;
6034*1da177e4SLinus Torvalds 	int ret;
6035*1da177e4SLinus Torvalds 
6036*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_clear_adapter", 1);
6037*1da177e4SLinus Torvalds 
6038*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
6039*1da177e4SLinus Torvalds 
6040*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
6041*1da177e4SLinus Torvalds 
6042*1da177e4SLinus Torvalds 	scb->timeout = ips_reset_timeout;
6043*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_CONFIG_SYNC;
6044*1da177e4SLinus Torvalds 
6045*1da177e4SLinus Torvalds 	scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;
6046*1da177e4SLinus Torvalds 	scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);
6047*1da177e4SLinus Torvalds 	scb->cmd.config_sync.channel = 0;
6048*1da177e4SLinus Torvalds 	scb->cmd.config_sync.source_target = IPS_POCL;
6049*1da177e4SLinus Torvalds 	scb->cmd.config_sync.reserved = 0;
6050*1da177e4SLinus Torvalds 	scb->cmd.config_sync.reserved2 = 0;
6051*1da177e4SLinus Torvalds 	scb->cmd.config_sync.reserved3 = 0;
6052*1da177e4SLinus Torvalds 
6053*1da177e4SLinus Torvalds 	/* issue command */
6054*1da177e4SLinus Torvalds 	if (((ret =
6055*1da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE)
6056*1da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
6057*1da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
6058*1da177e4SLinus Torvalds 		return (0);
6059*1da177e4SLinus Torvalds 
6060*1da177e4SLinus Torvalds 	/* send unlock stripe command */
6061*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
6062*1da177e4SLinus Torvalds 
6063*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_ERROR_TABLE;
6064*1da177e4SLinus Torvalds 	scb->timeout = ips_reset_timeout;
6065*1da177e4SLinus Torvalds 
6066*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;
6067*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);
6068*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.log_drv = 0;
6069*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.control = IPS_CSL;
6070*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.reserved = 0;
6071*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.reserved2 = 0;
6072*1da177e4SLinus Torvalds 	scb->cmd.unlock_stripe.reserved3 = 0;
6073*1da177e4SLinus Torvalds 
6074*1da177e4SLinus Torvalds 	/* issue command */
6075*1da177e4SLinus Torvalds 	if (((ret =
6076*1da177e4SLinus Torvalds 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
6077*1da177e4SLinus Torvalds 	    || (ret == IPS_SUCCESS_IMM)
6078*1da177e4SLinus Torvalds 	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
6079*1da177e4SLinus Torvalds 		return (0);
6080*1da177e4SLinus Torvalds 
6081*1da177e4SLinus Torvalds 	return (1);
6082*1da177e4SLinus Torvalds }
6083*1da177e4SLinus Torvalds 
6084*1da177e4SLinus Torvalds /****************************************************************************/
6085*1da177e4SLinus Torvalds /*                                                                          */
6086*1da177e4SLinus Torvalds /* Routine Name: ips_ffdc_reset                                             */
6087*1da177e4SLinus Torvalds /*                                                                          */
6088*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6089*1da177e4SLinus Torvalds /*                                                                          */
6090*1da177e4SLinus Torvalds /*   FFDC: write reset info                                                 */
6091*1da177e4SLinus Torvalds /*                                                                          */
6092*1da177e4SLinus Torvalds /****************************************************************************/
6093*1da177e4SLinus Torvalds static void
6094*1da177e4SLinus Torvalds ips_ffdc_reset(ips_ha_t * ha, int intr)
6095*1da177e4SLinus Torvalds {
6096*1da177e4SLinus Torvalds 	ips_scb_t *scb;
6097*1da177e4SLinus Torvalds 
6098*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_ffdc_reset", 1);
6099*1da177e4SLinus Torvalds 
6100*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
6101*1da177e4SLinus Torvalds 
6102*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
6103*1da177e4SLinus Torvalds 
6104*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
6105*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_FFDC;
6106*1da177e4SLinus Torvalds 	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
6107*1da177e4SLinus Torvalds 	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
6108*1da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_count = ha->reset_count;
6109*1da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_type = 0x80;
6110*1da177e4SLinus Torvalds 
6111*1da177e4SLinus Torvalds 	/* convert time to what the card wants */
6112*1da177e4SLinus Torvalds 	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
6113*1da177e4SLinus Torvalds 
6114*1da177e4SLinus Torvalds 	/* issue command */
6115*1da177e4SLinus Torvalds 	ips_send_wait(ha, scb, ips_cmd_timeout, intr);
6116*1da177e4SLinus Torvalds }
6117*1da177e4SLinus Torvalds 
6118*1da177e4SLinus Torvalds /****************************************************************************/
6119*1da177e4SLinus Torvalds /*                                                                          */
6120*1da177e4SLinus Torvalds /* Routine Name: ips_ffdc_time                                              */
6121*1da177e4SLinus Torvalds /*                                                                          */
6122*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6123*1da177e4SLinus Torvalds /*                                                                          */
6124*1da177e4SLinus Torvalds /*   FFDC: write time info                                                  */
6125*1da177e4SLinus Torvalds /*                                                                          */
6126*1da177e4SLinus Torvalds /****************************************************************************/
6127*1da177e4SLinus Torvalds static void
6128*1da177e4SLinus Torvalds ips_ffdc_time(ips_ha_t * ha)
6129*1da177e4SLinus Torvalds {
6130*1da177e4SLinus Torvalds 	ips_scb_t *scb;
6131*1da177e4SLinus Torvalds 
6132*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_ffdc_time", 1);
6133*1da177e4SLinus Torvalds 
6134*1da177e4SLinus Torvalds 	DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);
6135*1da177e4SLinus Torvalds 
6136*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
6137*1da177e4SLinus Torvalds 
6138*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
6139*1da177e4SLinus Torvalds 
6140*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
6141*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_FFDC;
6142*1da177e4SLinus Torvalds 	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
6143*1da177e4SLinus Torvalds 	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
6144*1da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_count = 0;
6145*1da177e4SLinus Torvalds 	scb->cmd.ffdc.reset_type = 0;
6146*1da177e4SLinus Torvalds 
6147*1da177e4SLinus Torvalds 	/* convert time to what the card wants */
6148*1da177e4SLinus Torvalds 	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
6149*1da177e4SLinus Torvalds 
6150*1da177e4SLinus Torvalds 	/* issue command */
6151*1da177e4SLinus Torvalds 	ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
6152*1da177e4SLinus Torvalds }
6153*1da177e4SLinus Torvalds 
6154*1da177e4SLinus Torvalds /****************************************************************************/
6155*1da177e4SLinus Torvalds /*                                                                          */
6156*1da177e4SLinus Torvalds /* Routine Name: ips_fix_ffdc_time                                          */
6157*1da177e4SLinus Torvalds /*                                                                          */
6158*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6159*1da177e4SLinus Torvalds /*   Adjust time_t to what the card wants                                   */
6160*1da177e4SLinus Torvalds /*                                                                          */
6161*1da177e4SLinus Torvalds /****************************************************************************/
6162*1da177e4SLinus Torvalds static void
6163*1da177e4SLinus Torvalds ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time)
6164*1da177e4SLinus Torvalds {
6165*1da177e4SLinus Torvalds 	long days;
6166*1da177e4SLinus Torvalds 	long rem;
6167*1da177e4SLinus Torvalds 	int i;
6168*1da177e4SLinus Torvalds 	int year;
6169*1da177e4SLinus Torvalds 	int yleap;
6170*1da177e4SLinus Torvalds 	int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };
6171*1da177e4SLinus Torvalds 	int month_lengths[12][2] = { {31, 31},
6172*1da177e4SLinus Torvalds 	{28, 29},
6173*1da177e4SLinus Torvalds 	{31, 31},
6174*1da177e4SLinus Torvalds 	{30, 30},
6175*1da177e4SLinus Torvalds 	{31, 31},
6176*1da177e4SLinus Torvalds 	{30, 30},
6177*1da177e4SLinus Torvalds 	{31, 31},
6178*1da177e4SLinus Torvalds 	{31, 31},
6179*1da177e4SLinus Torvalds 	{30, 30},
6180*1da177e4SLinus Torvalds 	{31, 31},
6181*1da177e4SLinus Torvalds 	{30, 30},
6182*1da177e4SLinus Torvalds 	{31, 31}
6183*1da177e4SLinus Torvalds 	};
6184*1da177e4SLinus Torvalds 
6185*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_fix_ffdc_time", 1);
6186*1da177e4SLinus Torvalds 
6187*1da177e4SLinus Torvalds 	days = current_time / IPS_SECS_DAY;
6188*1da177e4SLinus Torvalds 	rem = current_time % IPS_SECS_DAY;
6189*1da177e4SLinus Torvalds 
6190*1da177e4SLinus Torvalds 	scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);
6191*1da177e4SLinus Torvalds 	rem = rem % IPS_SECS_HOUR;
6192*1da177e4SLinus Torvalds 	scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);
6193*1da177e4SLinus Torvalds 	scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);
6194*1da177e4SLinus Torvalds 
6195*1da177e4SLinus Torvalds 	year = IPS_EPOCH_YEAR;
6196*1da177e4SLinus Torvalds 	while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {
6197*1da177e4SLinus Torvalds 		int newy;
6198*1da177e4SLinus Torvalds 
6199*1da177e4SLinus Torvalds 		newy = year + (days / IPS_DAYS_NORMAL_YEAR);
6200*1da177e4SLinus Torvalds 		if (days < 0)
6201*1da177e4SLinus Torvalds 			--newy;
6202*1da177e4SLinus Torvalds 		days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +
6203*1da177e4SLinus Torvalds 		    IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -
6204*1da177e4SLinus Torvalds 		    IPS_NUM_LEAP_YEARS_THROUGH(year - 1);
6205*1da177e4SLinus Torvalds 		year = newy;
6206*1da177e4SLinus Torvalds 	}
6207*1da177e4SLinus Torvalds 
6208*1da177e4SLinus Torvalds 	scb->cmd.ffdc.yearH = year / 100;
6209*1da177e4SLinus Torvalds 	scb->cmd.ffdc.yearL = year % 100;
6210*1da177e4SLinus Torvalds 
6211*1da177e4SLinus Torvalds 	for (i = 0; days >= month_lengths[i][yleap]; ++i)
6212*1da177e4SLinus Torvalds 		days -= month_lengths[i][yleap];
6213*1da177e4SLinus Torvalds 
6214*1da177e4SLinus Torvalds 	scb->cmd.ffdc.month = i + 1;
6215*1da177e4SLinus Torvalds 	scb->cmd.ffdc.day = days + 1;
6216*1da177e4SLinus Torvalds }
6217*1da177e4SLinus Torvalds 
6218*1da177e4SLinus Torvalds /****************************************************************************
6219*1da177e4SLinus Torvalds  * BIOS Flash Routines                                                      *
6220*1da177e4SLinus Torvalds  ****************************************************************************/
6221*1da177e4SLinus Torvalds 
6222*1da177e4SLinus Torvalds /****************************************************************************/
6223*1da177e4SLinus Torvalds /*                                                                          */
6224*1da177e4SLinus Torvalds /* Routine Name: ips_erase_bios                                             */
6225*1da177e4SLinus Torvalds /*                                                                          */
6226*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6227*1da177e4SLinus Torvalds /*   Erase the BIOS on the adapter                                          */
6228*1da177e4SLinus Torvalds /*                                                                          */
6229*1da177e4SLinus Torvalds /****************************************************************************/
6230*1da177e4SLinus Torvalds static int
6231*1da177e4SLinus Torvalds ips_erase_bios(ips_ha_t * ha)
6232*1da177e4SLinus Torvalds {
6233*1da177e4SLinus Torvalds 	int timeout;
6234*1da177e4SLinus Torvalds 	uint8_t status = 0;
6235*1da177e4SLinus Torvalds 
6236*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_erase_bios", 1);
6237*1da177e4SLinus Torvalds 
6238*1da177e4SLinus Torvalds 	status = 0;
6239*1da177e4SLinus Torvalds 
6240*1da177e4SLinus Torvalds 	/* Clear the status register */
6241*1da177e4SLinus Torvalds 	outl(0, ha->io_addr + IPS_REG_FLAP);
6242*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6243*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6244*1da177e4SLinus Torvalds 
6245*1da177e4SLinus Torvalds 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
6246*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6247*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6248*1da177e4SLinus Torvalds 
6249*1da177e4SLinus Torvalds 	/* Erase Setup */
6250*1da177e4SLinus Torvalds 	outb(0x20, ha->io_addr + IPS_REG_FLDP);
6251*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6252*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6253*1da177e4SLinus Torvalds 
6254*1da177e4SLinus Torvalds 	/* Erase Confirm */
6255*1da177e4SLinus Torvalds 	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
6256*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6257*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6258*1da177e4SLinus Torvalds 
6259*1da177e4SLinus Torvalds 	/* Erase Status */
6260*1da177e4SLinus Torvalds 	outb(0x70, ha->io_addr + IPS_REG_FLDP);
6261*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6262*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6263*1da177e4SLinus Torvalds 
6264*1da177e4SLinus Torvalds 	timeout = 80000;	/* 80 seconds */
6265*1da177e4SLinus Torvalds 
6266*1da177e4SLinus Torvalds 	while (timeout > 0) {
6267*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64) {
6268*1da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
6269*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6270*1da177e4SLinus Torvalds 		}
6271*1da177e4SLinus Torvalds 
6272*1da177e4SLinus Torvalds 		status = inb(ha->io_addr + IPS_REG_FLDP);
6273*1da177e4SLinus Torvalds 
6274*1da177e4SLinus Torvalds 		if (status & 0x80)
6275*1da177e4SLinus Torvalds 			break;
6276*1da177e4SLinus Torvalds 
6277*1da177e4SLinus Torvalds 		MDELAY(1);
6278*1da177e4SLinus Torvalds 		timeout--;
6279*1da177e4SLinus Torvalds 	}
6280*1da177e4SLinus Torvalds 
6281*1da177e4SLinus Torvalds 	/* check for timeout */
6282*1da177e4SLinus Torvalds 	if (timeout <= 0) {
6283*1da177e4SLinus Torvalds 		/* timeout */
6284*1da177e4SLinus Torvalds 
6285*1da177e4SLinus Torvalds 		/* try to suspend the erase */
6286*1da177e4SLinus Torvalds 		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
6287*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6288*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6289*1da177e4SLinus Torvalds 
6290*1da177e4SLinus Torvalds 		/* wait for 10 seconds */
6291*1da177e4SLinus Torvalds 		timeout = 10000;
6292*1da177e4SLinus Torvalds 		while (timeout > 0) {
6293*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
6294*1da177e4SLinus Torvalds 				outl(0, ha->io_addr + IPS_REG_FLAP);
6295*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6296*1da177e4SLinus Torvalds 			}
6297*1da177e4SLinus Torvalds 
6298*1da177e4SLinus Torvalds 			status = inb(ha->io_addr + IPS_REG_FLDP);
6299*1da177e4SLinus Torvalds 
6300*1da177e4SLinus Torvalds 			if (status & 0xC0)
6301*1da177e4SLinus Torvalds 				break;
6302*1da177e4SLinus Torvalds 
6303*1da177e4SLinus Torvalds 			MDELAY(1);
6304*1da177e4SLinus Torvalds 			timeout--;
6305*1da177e4SLinus Torvalds 		}
6306*1da177e4SLinus Torvalds 
6307*1da177e4SLinus Torvalds 		return (1);
6308*1da177e4SLinus Torvalds 	}
6309*1da177e4SLinus Torvalds 
6310*1da177e4SLinus Torvalds 	/* check for valid VPP */
6311*1da177e4SLinus Torvalds 	if (status & 0x08)
6312*1da177e4SLinus Torvalds 		/* VPP failure */
6313*1da177e4SLinus Torvalds 		return (1);
6314*1da177e4SLinus Torvalds 
6315*1da177e4SLinus Torvalds 	/* check for succesful flash */
6316*1da177e4SLinus Torvalds 	if (status & 0x30)
6317*1da177e4SLinus Torvalds 		/* sequence error */
6318*1da177e4SLinus Torvalds 		return (1);
6319*1da177e4SLinus Torvalds 
6320*1da177e4SLinus Torvalds 	/* Otherwise, we were successful */
6321*1da177e4SLinus Torvalds 	/* clear status */
6322*1da177e4SLinus Torvalds 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
6323*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6324*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6325*1da177e4SLinus Torvalds 
6326*1da177e4SLinus Torvalds 	/* enable reads */
6327*1da177e4SLinus Torvalds 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6328*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6329*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6330*1da177e4SLinus Torvalds 
6331*1da177e4SLinus Torvalds 	return (0);
6332*1da177e4SLinus Torvalds }
6333*1da177e4SLinus Torvalds 
6334*1da177e4SLinus Torvalds /****************************************************************************/
6335*1da177e4SLinus Torvalds /*                                                                          */
6336*1da177e4SLinus Torvalds /* Routine Name: ips_erase_bios_memio                                       */
6337*1da177e4SLinus Torvalds /*                                                                          */
6338*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6339*1da177e4SLinus Torvalds /*   Erase the BIOS on the adapter                                          */
6340*1da177e4SLinus Torvalds /*                                                                          */
6341*1da177e4SLinus Torvalds /****************************************************************************/
6342*1da177e4SLinus Torvalds static int
6343*1da177e4SLinus Torvalds ips_erase_bios_memio(ips_ha_t * ha)
6344*1da177e4SLinus Torvalds {
6345*1da177e4SLinus Torvalds 	int timeout;
6346*1da177e4SLinus Torvalds 	uint8_t status;
6347*1da177e4SLinus Torvalds 
6348*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_erase_bios_memio", 1);
6349*1da177e4SLinus Torvalds 
6350*1da177e4SLinus Torvalds 	status = 0;
6351*1da177e4SLinus Torvalds 
6352*1da177e4SLinus Torvalds 	/* Clear the status register */
6353*1da177e4SLinus Torvalds 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
6354*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6355*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6356*1da177e4SLinus Torvalds 
6357*1da177e4SLinus Torvalds 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
6358*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6359*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6360*1da177e4SLinus Torvalds 
6361*1da177e4SLinus Torvalds 	/* Erase Setup */
6362*1da177e4SLinus Torvalds 	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
6363*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6364*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6365*1da177e4SLinus Torvalds 
6366*1da177e4SLinus Torvalds 	/* Erase Confirm */
6367*1da177e4SLinus Torvalds 	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
6368*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6369*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6370*1da177e4SLinus Torvalds 
6371*1da177e4SLinus Torvalds 	/* Erase Status */
6372*1da177e4SLinus Torvalds 	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
6373*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6374*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6375*1da177e4SLinus Torvalds 
6376*1da177e4SLinus Torvalds 	timeout = 80000;	/* 80 seconds */
6377*1da177e4SLinus Torvalds 
6378*1da177e4SLinus Torvalds 	while (timeout > 0) {
6379*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64) {
6380*1da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
6381*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6382*1da177e4SLinus Torvalds 		}
6383*1da177e4SLinus Torvalds 
6384*1da177e4SLinus Torvalds 		status = readb(ha->mem_ptr + IPS_REG_FLDP);
6385*1da177e4SLinus Torvalds 
6386*1da177e4SLinus Torvalds 		if (status & 0x80)
6387*1da177e4SLinus Torvalds 			break;
6388*1da177e4SLinus Torvalds 
6389*1da177e4SLinus Torvalds 		MDELAY(1);
6390*1da177e4SLinus Torvalds 		timeout--;
6391*1da177e4SLinus Torvalds 	}
6392*1da177e4SLinus Torvalds 
6393*1da177e4SLinus Torvalds 	/* check for timeout */
6394*1da177e4SLinus Torvalds 	if (timeout <= 0) {
6395*1da177e4SLinus Torvalds 		/* timeout */
6396*1da177e4SLinus Torvalds 
6397*1da177e4SLinus Torvalds 		/* try to suspend the erase */
6398*1da177e4SLinus Torvalds 		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
6399*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6400*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6401*1da177e4SLinus Torvalds 
6402*1da177e4SLinus Torvalds 		/* wait for 10 seconds */
6403*1da177e4SLinus Torvalds 		timeout = 10000;
6404*1da177e4SLinus Torvalds 		while (timeout > 0) {
6405*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
6406*1da177e4SLinus Torvalds 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
6407*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6408*1da177e4SLinus Torvalds 			}
6409*1da177e4SLinus Torvalds 
6410*1da177e4SLinus Torvalds 			status = readb(ha->mem_ptr + IPS_REG_FLDP);
6411*1da177e4SLinus Torvalds 
6412*1da177e4SLinus Torvalds 			if (status & 0xC0)
6413*1da177e4SLinus Torvalds 				break;
6414*1da177e4SLinus Torvalds 
6415*1da177e4SLinus Torvalds 			MDELAY(1);
6416*1da177e4SLinus Torvalds 			timeout--;
6417*1da177e4SLinus Torvalds 		}
6418*1da177e4SLinus Torvalds 
6419*1da177e4SLinus Torvalds 		return (1);
6420*1da177e4SLinus Torvalds 	}
6421*1da177e4SLinus Torvalds 
6422*1da177e4SLinus Torvalds 	/* check for valid VPP */
6423*1da177e4SLinus Torvalds 	if (status & 0x08)
6424*1da177e4SLinus Torvalds 		/* VPP failure */
6425*1da177e4SLinus Torvalds 		return (1);
6426*1da177e4SLinus Torvalds 
6427*1da177e4SLinus Torvalds 	/* check for succesful flash */
6428*1da177e4SLinus Torvalds 	if (status & 0x30)
6429*1da177e4SLinus Torvalds 		/* sequence error */
6430*1da177e4SLinus Torvalds 		return (1);
6431*1da177e4SLinus Torvalds 
6432*1da177e4SLinus Torvalds 	/* Otherwise, we were successful */
6433*1da177e4SLinus Torvalds 	/* clear status */
6434*1da177e4SLinus Torvalds 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
6435*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6436*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6437*1da177e4SLinus Torvalds 
6438*1da177e4SLinus Torvalds 	/* enable reads */
6439*1da177e4SLinus Torvalds 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6440*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6441*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6442*1da177e4SLinus Torvalds 
6443*1da177e4SLinus Torvalds 	return (0);
6444*1da177e4SLinus Torvalds }
6445*1da177e4SLinus Torvalds 
6446*1da177e4SLinus Torvalds /****************************************************************************/
6447*1da177e4SLinus Torvalds /*                                                                          */
6448*1da177e4SLinus Torvalds /* Routine Name: ips_program_bios                                           */
6449*1da177e4SLinus Torvalds /*                                                                          */
6450*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6451*1da177e4SLinus Torvalds /*   Program the BIOS on the adapter                                        */
6452*1da177e4SLinus Torvalds /*                                                                          */
6453*1da177e4SLinus Torvalds /****************************************************************************/
6454*1da177e4SLinus Torvalds static int
6455*1da177e4SLinus Torvalds ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6456*1da177e4SLinus Torvalds 		 uint32_t offset)
6457*1da177e4SLinus Torvalds {
6458*1da177e4SLinus Torvalds 	int i;
6459*1da177e4SLinus Torvalds 	int timeout;
6460*1da177e4SLinus Torvalds 	uint8_t status = 0;
6461*1da177e4SLinus Torvalds 
6462*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_program_bios", 1);
6463*1da177e4SLinus Torvalds 
6464*1da177e4SLinus Torvalds 	status = 0;
6465*1da177e4SLinus Torvalds 
6466*1da177e4SLinus Torvalds 	for (i = 0; i < buffersize; i++) {
6467*1da177e4SLinus Torvalds 		/* write a byte */
6468*1da177e4SLinus Torvalds 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
6469*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6470*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6471*1da177e4SLinus Torvalds 
6472*1da177e4SLinus Torvalds 		outb(0x40, ha->io_addr + IPS_REG_FLDP);
6473*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6474*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6475*1da177e4SLinus Torvalds 
6476*1da177e4SLinus Torvalds 		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
6477*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6478*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6479*1da177e4SLinus Torvalds 
6480*1da177e4SLinus Torvalds 		/* wait up to one second */
6481*1da177e4SLinus Torvalds 		timeout = 1000;
6482*1da177e4SLinus Torvalds 		while (timeout > 0) {
6483*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
6484*1da177e4SLinus Torvalds 				outl(0, ha->io_addr + IPS_REG_FLAP);
6485*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6486*1da177e4SLinus Torvalds 			}
6487*1da177e4SLinus Torvalds 
6488*1da177e4SLinus Torvalds 			status = inb(ha->io_addr + IPS_REG_FLDP);
6489*1da177e4SLinus Torvalds 
6490*1da177e4SLinus Torvalds 			if (status & 0x80)
6491*1da177e4SLinus Torvalds 				break;
6492*1da177e4SLinus Torvalds 
6493*1da177e4SLinus Torvalds 			MDELAY(1);
6494*1da177e4SLinus Torvalds 			timeout--;
6495*1da177e4SLinus Torvalds 		}
6496*1da177e4SLinus Torvalds 
6497*1da177e4SLinus Torvalds 		if (timeout == 0) {
6498*1da177e4SLinus Torvalds 			/* timeout error */
6499*1da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
6500*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6501*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6502*1da177e4SLinus Torvalds 
6503*1da177e4SLinus Torvalds 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6504*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6505*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6506*1da177e4SLinus Torvalds 
6507*1da177e4SLinus Torvalds 			return (1);
6508*1da177e4SLinus Torvalds 		}
6509*1da177e4SLinus Torvalds 
6510*1da177e4SLinus Torvalds 		/* check the status */
6511*1da177e4SLinus Torvalds 		if (status & 0x18) {
6512*1da177e4SLinus Torvalds 			/* programming error */
6513*1da177e4SLinus Torvalds 			outl(0, ha->io_addr + IPS_REG_FLAP);
6514*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6515*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6516*1da177e4SLinus Torvalds 
6517*1da177e4SLinus Torvalds 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6518*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6519*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6520*1da177e4SLinus Torvalds 
6521*1da177e4SLinus Torvalds 			return (1);
6522*1da177e4SLinus Torvalds 		}
6523*1da177e4SLinus Torvalds 	}			/* end for */
6524*1da177e4SLinus Torvalds 
6525*1da177e4SLinus Torvalds 	/* Enable reading */
6526*1da177e4SLinus Torvalds 	outl(0, ha->io_addr + IPS_REG_FLAP);
6527*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6528*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6529*1da177e4SLinus Torvalds 
6530*1da177e4SLinus Torvalds 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6531*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6532*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6533*1da177e4SLinus Torvalds 
6534*1da177e4SLinus Torvalds 	return (0);
6535*1da177e4SLinus Torvalds }
6536*1da177e4SLinus Torvalds 
6537*1da177e4SLinus Torvalds /****************************************************************************/
6538*1da177e4SLinus Torvalds /*                                                                          */
6539*1da177e4SLinus Torvalds /* Routine Name: ips_program_bios_memio                                     */
6540*1da177e4SLinus Torvalds /*                                                                          */
6541*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6542*1da177e4SLinus Torvalds /*   Program the BIOS on the adapter                                        */
6543*1da177e4SLinus Torvalds /*                                                                          */
6544*1da177e4SLinus Torvalds /****************************************************************************/
6545*1da177e4SLinus Torvalds static int
6546*1da177e4SLinus Torvalds ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6547*1da177e4SLinus Torvalds 		       uint32_t offset)
6548*1da177e4SLinus Torvalds {
6549*1da177e4SLinus Torvalds 	int i;
6550*1da177e4SLinus Torvalds 	int timeout;
6551*1da177e4SLinus Torvalds 	uint8_t status = 0;
6552*1da177e4SLinus Torvalds 
6553*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_program_bios_memio", 1);
6554*1da177e4SLinus Torvalds 
6555*1da177e4SLinus Torvalds 	status = 0;
6556*1da177e4SLinus Torvalds 
6557*1da177e4SLinus Torvalds 	for (i = 0; i < buffersize; i++) {
6558*1da177e4SLinus Torvalds 		/* write a byte */
6559*1da177e4SLinus Torvalds 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
6560*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6561*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6562*1da177e4SLinus Torvalds 
6563*1da177e4SLinus Torvalds 		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
6564*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6565*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6566*1da177e4SLinus Torvalds 
6567*1da177e4SLinus Torvalds 		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
6568*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6569*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6570*1da177e4SLinus Torvalds 
6571*1da177e4SLinus Torvalds 		/* wait up to one second */
6572*1da177e4SLinus Torvalds 		timeout = 1000;
6573*1da177e4SLinus Torvalds 		while (timeout > 0) {
6574*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64) {
6575*1da177e4SLinus Torvalds 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
6576*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6577*1da177e4SLinus Torvalds 			}
6578*1da177e4SLinus Torvalds 
6579*1da177e4SLinus Torvalds 			status = readb(ha->mem_ptr + IPS_REG_FLDP);
6580*1da177e4SLinus Torvalds 
6581*1da177e4SLinus Torvalds 			if (status & 0x80)
6582*1da177e4SLinus Torvalds 				break;
6583*1da177e4SLinus Torvalds 
6584*1da177e4SLinus Torvalds 			MDELAY(1);
6585*1da177e4SLinus Torvalds 			timeout--;
6586*1da177e4SLinus Torvalds 		}
6587*1da177e4SLinus Torvalds 
6588*1da177e4SLinus Torvalds 		if (timeout == 0) {
6589*1da177e4SLinus Torvalds 			/* timeout error */
6590*1da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
6591*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6592*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6593*1da177e4SLinus Torvalds 
6594*1da177e4SLinus Torvalds 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6595*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6596*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6597*1da177e4SLinus Torvalds 
6598*1da177e4SLinus Torvalds 			return (1);
6599*1da177e4SLinus Torvalds 		}
6600*1da177e4SLinus Torvalds 
6601*1da177e4SLinus Torvalds 		/* check the status */
6602*1da177e4SLinus Torvalds 		if (status & 0x18) {
6603*1da177e4SLinus Torvalds 			/* programming error */
6604*1da177e4SLinus Torvalds 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
6605*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6606*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6607*1da177e4SLinus Torvalds 
6608*1da177e4SLinus Torvalds 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6609*1da177e4SLinus Torvalds 			if (ha->revision_id == IPS_REVID_TROMBONE64)
6610*1da177e4SLinus Torvalds 				udelay(25);	/* 25 us */
6611*1da177e4SLinus Torvalds 
6612*1da177e4SLinus Torvalds 			return (1);
6613*1da177e4SLinus Torvalds 		}
6614*1da177e4SLinus Torvalds 	}			/* end for */
6615*1da177e4SLinus Torvalds 
6616*1da177e4SLinus Torvalds 	/* Enable reading */
6617*1da177e4SLinus Torvalds 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
6618*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6619*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6620*1da177e4SLinus Torvalds 
6621*1da177e4SLinus Torvalds 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6622*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6623*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6624*1da177e4SLinus Torvalds 
6625*1da177e4SLinus Torvalds 	return (0);
6626*1da177e4SLinus Torvalds }
6627*1da177e4SLinus Torvalds 
6628*1da177e4SLinus Torvalds /****************************************************************************/
6629*1da177e4SLinus Torvalds /*                                                                          */
6630*1da177e4SLinus Torvalds /* Routine Name: ips_verify_bios                                            */
6631*1da177e4SLinus Torvalds /*                                                                          */
6632*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6633*1da177e4SLinus Torvalds /*   Verify the BIOS on the adapter                                         */
6634*1da177e4SLinus Torvalds /*                                                                          */
6635*1da177e4SLinus Torvalds /****************************************************************************/
6636*1da177e4SLinus Torvalds static int
6637*1da177e4SLinus Torvalds ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6638*1da177e4SLinus Torvalds 		uint32_t offset)
6639*1da177e4SLinus Torvalds {
6640*1da177e4SLinus Torvalds 	uint8_t checksum;
6641*1da177e4SLinus Torvalds 	int i;
6642*1da177e4SLinus Torvalds 
6643*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_verify_bios", 1);
6644*1da177e4SLinus Torvalds 
6645*1da177e4SLinus Torvalds 	/* test 1st byte */
6646*1da177e4SLinus Torvalds 	outl(0, ha->io_addr + IPS_REG_FLAP);
6647*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6648*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6649*1da177e4SLinus Torvalds 
6650*1da177e4SLinus Torvalds 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
6651*1da177e4SLinus Torvalds 		return (1);
6652*1da177e4SLinus Torvalds 
6653*1da177e4SLinus Torvalds 	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
6654*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6655*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6656*1da177e4SLinus Torvalds 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
6657*1da177e4SLinus Torvalds 		return (1);
6658*1da177e4SLinus Torvalds 
6659*1da177e4SLinus Torvalds 	checksum = 0xff;
6660*1da177e4SLinus Torvalds 	for (i = 2; i < buffersize; i++) {
6661*1da177e4SLinus Torvalds 
6662*1da177e4SLinus Torvalds 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
6663*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6664*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6665*1da177e4SLinus Torvalds 
6666*1da177e4SLinus Torvalds 		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
6667*1da177e4SLinus Torvalds 	}
6668*1da177e4SLinus Torvalds 
6669*1da177e4SLinus Torvalds 	if (checksum != 0)
6670*1da177e4SLinus Torvalds 		/* failure */
6671*1da177e4SLinus Torvalds 		return (1);
6672*1da177e4SLinus Torvalds 	else
6673*1da177e4SLinus Torvalds 		/* success */
6674*1da177e4SLinus Torvalds 		return (0);
6675*1da177e4SLinus Torvalds }
6676*1da177e4SLinus Torvalds 
6677*1da177e4SLinus Torvalds /****************************************************************************/
6678*1da177e4SLinus Torvalds /*                                                                          */
6679*1da177e4SLinus Torvalds /* Routine Name: ips_verify_bios_memio                                      */
6680*1da177e4SLinus Torvalds /*                                                                          */
6681*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6682*1da177e4SLinus Torvalds /*   Verify the BIOS on the adapter                                         */
6683*1da177e4SLinus Torvalds /*                                                                          */
6684*1da177e4SLinus Torvalds /****************************************************************************/
6685*1da177e4SLinus Torvalds static int
6686*1da177e4SLinus Torvalds ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6687*1da177e4SLinus Torvalds 		      uint32_t offset)
6688*1da177e4SLinus Torvalds {
6689*1da177e4SLinus Torvalds 	uint8_t checksum;
6690*1da177e4SLinus Torvalds 	int i;
6691*1da177e4SLinus Torvalds 
6692*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_verify_bios_memio", 1);
6693*1da177e4SLinus Torvalds 
6694*1da177e4SLinus Torvalds 	/* test 1st byte */
6695*1da177e4SLinus Torvalds 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
6696*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6697*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6698*1da177e4SLinus Torvalds 
6699*1da177e4SLinus Torvalds 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
6700*1da177e4SLinus Torvalds 		return (1);
6701*1da177e4SLinus Torvalds 
6702*1da177e4SLinus Torvalds 	writel(1, ha->mem_ptr + IPS_REG_FLAP);
6703*1da177e4SLinus Torvalds 	if (ha->revision_id == IPS_REVID_TROMBONE64)
6704*1da177e4SLinus Torvalds 		udelay(25);	/* 25 us */
6705*1da177e4SLinus Torvalds 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
6706*1da177e4SLinus Torvalds 		return (1);
6707*1da177e4SLinus Torvalds 
6708*1da177e4SLinus Torvalds 	checksum = 0xff;
6709*1da177e4SLinus Torvalds 	for (i = 2; i < buffersize; i++) {
6710*1da177e4SLinus Torvalds 
6711*1da177e4SLinus Torvalds 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
6712*1da177e4SLinus Torvalds 		if (ha->revision_id == IPS_REVID_TROMBONE64)
6713*1da177e4SLinus Torvalds 			udelay(25);	/* 25 us */
6714*1da177e4SLinus Torvalds 
6715*1da177e4SLinus Torvalds 		checksum =
6716*1da177e4SLinus Torvalds 		    (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
6717*1da177e4SLinus Torvalds 	}
6718*1da177e4SLinus Torvalds 
6719*1da177e4SLinus Torvalds 	if (checksum != 0)
6720*1da177e4SLinus Torvalds 		/* failure */
6721*1da177e4SLinus Torvalds 		return (1);
6722*1da177e4SLinus Torvalds 	else
6723*1da177e4SLinus Torvalds 		/* success */
6724*1da177e4SLinus Torvalds 		return (0);
6725*1da177e4SLinus Torvalds }
6726*1da177e4SLinus Torvalds 
6727*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
6728*1da177e4SLinus Torvalds /*   Routine Name: ips_version_check                                         */
6729*1da177e4SLinus Torvalds /*                                                                           */
6730*1da177e4SLinus Torvalds /*   Dependencies:                                                           */
6731*1da177e4SLinus Torvalds /*     Assumes that ips_read_adapter_status() is called first filling in     */
6732*1da177e4SLinus Torvalds /*     the data for SubSystem Parameters.                                    */
6733*1da177e4SLinus Torvalds /*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */
6734*1da177e4SLinus Torvalds /*     Data is available.                                                    */
6735*1da177e4SLinus Torvalds /*                                                                           */
6736*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
6737*1da177e4SLinus Torvalds static void
6738*1da177e4SLinus Torvalds ips_version_check(ips_ha_t * ha, int intr)
6739*1da177e4SLinus Torvalds {
6740*1da177e4SLinus Torvalds 	IPS_VERSION_DATA *VersionInfo;
6741*1da177e4SLinus Torvalds 	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
6742*1da177e4SLinus Torvalds 	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
6743*1da177e4SLinus Torvalds 	int MatchError;
6744*1da177e4SLinus Torvalds 	int rc;
6745*1da177e4SLinus Torvalds 	char BiosString[10];
6746*1da177e4SLinus Torvalds 	char FirmwareString[10];
6747*1da177e4SLinus Torvalds 
6748*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_version_check", 1);
6749*1da177e4SLinus Torvalds 
6750*1da177e4SLinus Torvalds 	VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;
6751*1da177e4SLinus Torvalds 
6752*1da177e4SLinus Torvalds 	memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
6753*1da177e4SLinus Torvalds 	memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
6754*1da177e4SLinus Torvalds 
6755*1da177e4SLinus Torvalds 	/* Get the Compatible BIOS Version from NVRAM Page 5 */
6756*1da177e4SLinus Torvalds 	memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,
6757*1da177e4SLinus Torvalds 	       IPS_COMPAT_ID_LENGTH);
6758*1da177e4SLinus Torvalds 
6759*1da177e4SLinus Torvalds 	rc = IPS_FAILURE;
6760*1da177e4SLinus Torvalds 	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */
6761*1da177e4SLinus Torvalds 		/* Get the Version Info with a Get Version Command */
6762*1da177e4SLinus Torvalds 		memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
6763*1da177e4SLinus Torvalds 		rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);
6764*1da177e4SLinus Torvalds 		if (rc == IPS_SUCCESS)
6765*1da177e4SLinus Torvalds 			memcpy(FirmwareVersion, VersionInfo->compatibilityId,
6766*1da177e4SLinus Torvalds 			       IPS_COMPAT_ID_LENGTH);
6767*1da177e4SLinus Torvalds 	}
6768*1da177e4SLinus Torvalds 
6769*1da177e4SLinus Torvalds 	if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */
6770*1da177e4SLinus Torvalds 		/* Get the Firmware Version from Enquiry Data */
6771*1da177e4SLinus Torvalds 		memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,
6772*1da177e4SLinus Torvalds 		       IPS_COMPAT_ID_LENGTH);
6773*1da177e4SLinus Torvalds 	}
6774*1da177e4SLinus Torvalds 
6775*1da177e4SLinus Torvalds 	/* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
6776*1da177e4SLinus Torvalds 	/* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
6777*1da177e4SLinus Torvalds 	/* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
6778*1da177e4SLinus Torvalds 	/* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
6779*1da177e4SLinus Torvalds 
6780*1da177e4SLinus Torvalds 	MatchError = 0;
6781*1da177e4SLinus Torvalds 
6782*1da177e4SLinus Torvalds 	if (strncmp
6783*1da177e4SLinus Torvalds 	    (FirmwareVersion, Compatable[ha->nvram->adapter_type],
6784*1da177e4SLinus Torvalds 	     IPS_COMPAT_ID_LENGTH) != 0)
6785*1da177e4SLinus Torvalds 		MatchError = 1;
6786*1da177e4SLinus Torvalds 
6787*1da177e4SLinus Torvalds 	if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
6788*1da177e4SLinus Torvalds 		MatchError = 1;
6789*1da177e4SLinus Torvalds 
6790*1da177e4SLinus Torvalds 	ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */
6791*1da177e4SLinus Torvalds 
6792*1da177e4SLinus Torvalds 	if (MatchError) {
6793*1da177e4SLinus Torvalds 		ha->nvram->version_mismatch = 1;
6794*1da177e4SLinus Torvalds 		if (ips_cd_boot == 0) {
6795*1da177e4SLinus Torvalds 			strncpy(&BiosString[0], ha->nvram->bios_high, 4);
6796*1da177e4SLinus Torvalds 			strncpy(&BiosString[4], ha->nvram->bios_low, 4);
6797*1da177e4SLinus Torvalds 			BiosString[8] = 0;
6798*1da177e4SLinus Torvalds 
6799*1da177e4SLinus Torvalds 			strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
6800*1da177e4SLinus Torvalds 			FirmwareString[8] = 0;
6801*1da177e4SLinus Torvalds 
6802*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
6803*1da177e4SLinus Torvalds 				   "Warning ! ! ! ServeRAID Version Mismatch\n");
6804*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
6805*1da177e4SLinus Torvalds 				   "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
6806*1da177e4SLinus Torvalds 				   BiosString, FirmwareString, IPS_VERSION_HIGH,
6807*1da177e4SLinus Torvalds 				   IPS_VERSION_LOW);
6808*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, ha->pcidev,
6809*1da177e4SLinus Torvalds 				   "These levels should match to avoid possible compatibility problems.\n");
6810*1da177e4SLinus Torvalds 		}
6811*1da177e4SLinus Torvalds 	} else {
6812*1da177e4SLinus Torvalds 		ha->nvram->version_mismatch = 0;
6813*1da177e4SLinus Torvalds 	}
6814*1da177e4SLinus Torvalds 
6815*1da177e4SLinus Torvalds 	return;
6816*1da177e4SLinus Torvalds }
6817*1da177e4SLinus Torvalds 
6818*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
6819*1da177e4SLinus Torvalds /*   Routine Name: ips_get_version_info                                      */
6820*1da177e4SLinus Torvalds /*                                                                           */
6821*1da177e4SLinus Torvalds /*   Routine Description:                                                    */
6822*1da177e4SLinus Torvalds /*     Issue an internal GETVERSION Command                                  */
6823*1da177e4SLinus Torvalds /*                                                                           */
6824*1da177e4SLinus Torvalds /*   Return Value:                                                           */
6825*1da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
6826*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
6827*1da177e4SLinus Torvalds static int
6828*1da177e4SLinus Torvalds ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr)
6829*1da177e4SLinus Torvalds {
6830*1da177e4SLinus Torvalds 	ips_scb_t *scb;
6831*1da177e4SLinus Torvalds 	int rc;
6832*1da177e4SLinus Torvalds 
6833*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_get_version_info", 1);
6834*1da177e4SLinus Torvalds 
6835*1da177e4SLinus Torvalds 	scb = &ha->scbs[ha->max_cmds - 1];
6836*1da177e4SLinus Torvalds 
6837*1da177e4SLinus Torvalds 	ips_init_scb(ha, scb);
6838*1da177e4SLinus Torvalds 
6839*1da177e4SLinus Torvalds 	scb->timeout = ips_cmd_timeout;
6840*1da177e4SLinus Torvalds 	scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
6841*1da177e4SLinus Torvalds 	scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
6842*1da177e4SLinus Torvalds 	scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
6843*1da177e4SLinus Torvalds 	scb->cmd.version_info.reserved = 0;
6844*1da177e4SLinus Torvalds 	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
6845*1da177e4SLinus Torvalds 	scb->cmd.version_info.reserved2 = 0;
6846*1da177e4SLinus Torvalds 	scb->data_len = sizeof (IPS_VERSION_DATA);
6847*1da177e4SLinus Torvalds 	scb->data_busaddr = Buffer;
6848*1da177e4SLinus Torvalds 	scb->cmd.version_info.buffer_addr = Buffer;
6849*1da177e4SLinus Torvalds 	scb->flags = 0;
6850*1da177e4SLinus Torvalds 
6851*1da177e4SLinus Torvalds 	/* issue command */
6852*1da177e4SLinus Torvalds 	rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
6853*1da177e4SLinus Torvalds 	return (rc);
6854*1da177e4SLinus Torvalds }
6855*1da177e4SLinus Torvalds 
6856*1da177e4SLinus Torvalds /****************************************************************************/
6857*1da177e4SLinus Torvalds /*                                                                          */
6858*1da177e4SLinus Torvalds /* Routine Name: ips_abort_init                                             */
6859*1da177e4SLinus Torvalds /*                                                                          */
6860*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6861*1da177e4SLinus Torvalds /*   cleanup routine for a failed adapter initialization                    */
6862*1da177e4SLinus Torvalds /****************************************************************************/
6863*1da177e4SLinus Torvalds static int
6864*1da177e4SLinus Torvalds ips_abort_init(ips_ha_t * ha, int index)
6865*1da177e4SLinus Torvalds {
6866*1da177e4SLinus Torvalds 	ha->active = 0;
6867*1da177e4SLinus Torvalds 	ips_free(ha);
6868*1da177e4SLinus Torvalds 	ips_ha[index] = NULL;
6869*1da177e4SLinus Torvalds 	ips_sh[index] = NULL;
6870*1da177e4SLinus Torvalds 	return -1;
6871*1da177e4SLinus Torvalds }
6872*1da177e4SLinus Torvalds 
6873*1da177e4SLinus Torvalds /****************************************************************************/
6874*1da177e4SLinus Torvalds /*                                                                          */
6875*1da177e4SLinus Torvalds /* Routine Name: ips_shift_controllers                                      */
6876*1da177e4SLinus Torvalds /*                                                                          */
6877*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6878*1da177e4SLinus Torvalds /*   helper function for ordering adapters                                  */
6879*1da177e4SLinus Torvalds /****************************************************************************/
6880*1da177e4SLinus Torvalds static void
6881*1da177e4SLinus Torvalds ips_shift_controllers(int lowindex, int highindex)
6882*1da177e4SLinus Torvalds {
6883*1da177e4SLinus Torvalds 	ips_ha_t *ha_sav = ips_ha[highindex];
6884*1da177e4SLinus Torvalds 	struct Scsi_Host *sh_sav = ips_sh[highindex];
6885*1da177e4SLinus Torvalds 	int i;
6886*1da177e4SLinus Torvalds 
6887*1da177e4SLinus Torvalds 	for (i = highindex; i > lowindex; i--) {
6888*1da177e4SLinus Torvalds 		ips_ha[i] = ips_ha[i - 1];
6889*1da177e4SLinus Torvalds 		ips_sh[i] = ips_sh[i - 1];
6890*1da177e4SLinus Torvalds 		ips_ha[i]->host_num = i;
6891*1da177e4SLinus Torvalds 	}
6892*1da177e4SLinus Torvalds 	ha_sav->host_num = lowindex;
6893*1da177e4SLinus Torvalds 	ips_ha[lowindex] = ha_sav;
6894*1da177e4SLinus Torvalds 	ips_sh[lowindex] = sh_sav;
6895*1da177e4SLinus Torvalds }
6896*1da177e4SLinus Torvalds 
6897*1da177e4SLinus Torvalds /****************************************************************************/
6898*1da177e4SLinus Torvalds /*                                                                          */
6899*1da177e4SLinus Torvalds /* Routine Name: ips_order_controllers                                      */
6900*1da177e4SLinus Torvalds /*                                                                          */
6901*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6902*1da177e4SLinus Torvalds /*   place controllers is the "proper" boot order                           */
6903*1da177e4SLinus Torvalds /****************************************************************************/
6904*1da177e4SLinus Torvalds static void
6905*1da177e4SLinus Torvalds ips_order_controllers(void)
6906*1da177e4SLinus Torvalds {
6907*1da177e4SLinus Torvalds 	int i, j, tmp, position = 0;
6908*1da177e4SLinus Torvalds 	IPS_NVRAM_P5 *nvram;
6909*1da177e4SLinus Torvalds 	if (!ips_ha[0])
6910*1da177e4SLinus Torvalds 		return;
6911*1da177e4SLinus Torvalds 	nvram = ips_ha[0]->nvram;
6912*1da177e4SLinus Torvalds 
6913*1da177e4SLinus Torvalds 	if (nvram->adapter_order[0]) {
6914*1da177e4SLinus Torvalds 		for (i = 1; i <= nvram->adapter_order[0]; i++) {
6915*1da177e4SLinus Torvalds 			for (j = position; j < ips_num_controllers; j++) {
6916*1da177e4SLinus Torvalds 				switch (ips_ha[j]->ad_type) {
6917*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID6M:
6918*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID7M:
6919*1da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'M') {
6920*1da177e4SLinus Torvalds 						ips_shift_controllers(position,
6921*1da177e4SLinus Torvalds 								      j);
6922*1da177e4SLinus Torvalds 						position++;
6923*1da177e4SLinus Torvalds 					}
6924*1da177e4SLinus Torvalds 					break;
6925*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4L:
6926*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4M:
6927*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4MX:
6928*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4LX:
6929*1da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'N') {
6930*1da177e4SLinus Torvalds 						ips_shift_controllers(position,
6931*1da177e4SLinus Torvalds 								      j);
6932*1da177e4SLinus Torvalds 						position++;
6933*1da177e4SLinus Torvalds 					}
6934*1da177e4SLinus Torvalds 					break;
6935*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID6I:
6936*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID5I2:
6937*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID5I1:
6938*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID7k:
6939*1da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'S') {
6940*1da177e4SLinus Torvalds 						ips_shift_controllers(position,
6941*1da177e4SLinus Torvalds 								      j);
6942*1da177e4SLinus Torvalds 						position++;
6943*1da177e4SLinus Torvalds 					}
6944*1da177e4SLinus Torvalds 					break;
6945*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID:
6946*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID2:
6947*1da177e4SLinus Torvalds 				case IPS_ADTYPE_NAVAJO:
6948*1da177e4SLinus Torvalds 				case IPS_ADTYPE_KIOWA:
6949*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID3L:
6950*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID3:
6951*1da177e4SLinus Torvalds 				case IPS_ADTYPE_SERVERAID4H:
6952*1da177e4SLinus Torvalds 					if (nvram->adapter_order[i] == 'A') {
6953*1da177e4SLinus Torvalds 						ips_shift_controllers(position,
6954*1da177e4SLinus Torvalds 								      j);
6955*1da177e4SLinus Torvalds 						position++;
6956*1da177e4SLinus Torvalds 					}
6957*1da177e4SLinus Torvalds 					break;
6958*1da177e4SLinus Torvalds 				default:
6959*1da177e4SLinus Torvalds 					break;
6960*1da177e4SLinus Torvalds 				}
6961*1da177e4SLinus Torvalds 			}
6962*1da177e4SLinus Torvalds 		}
6963*1da177e4SLinus Torvalds 		/* if adapter_order[0], then ordering is complete */
6964*1da177e4SLinus Torvalds 		return;
6965*1da177e4SLinus Torvalds 	}
6966*1da177e4SLinus Torvalds 	/* old bios, use older ordering */
6967*1da177e4SLinus Torvalds 	tmp = 0;
6968*1da177e4SLinus Torvalds 	for (i = position; i < ips_num_controllers; i++) {
6969*1da177e4SLinus Torvalds 		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 ||
6970*1da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) {
6971*1da177e4SLinus Torvalds 			ips_shift_controllers(position, i);
6972*1da177e4SLinus Torvalds 			position++;
6973*1da177e4SLinus Torvalds 			tmp = 1;
6974*1da177e4SLinus Torvalds 		}
6975*1da177e4SLinus Torvalds 	}
6976*1da177e4SLinus Torvalds 	/* if there were no 5I cards, then don't do any extra ordering */
6977*1da177e4SLinus Torvalds 	if (!tmp)
6978*1da177e4SLinus Torvalds 		return;
6979*1da177e4SLinus Torvalds 	for (i = position; i < ips_num_controllers; i++) {
6980*1da177e4SLinus Torvalds 		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L ||
6981*1da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M ||
6982*1da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX ||
6983*1da177e4SLinus Torvalds 		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) {
6984*1da177e4SLinus Torvalds 			ips_shift_controllers(position, i);
6985*1da177e4SLinus Torvalds 			position++;
6986*1da177e4SLinus Torvalds 		}
6987*1da177e4SLinus Torvalds 	}
6988*1da177e4SLinus Torvalds 
6989*1da177e4SLinus Torvalds 	return;
6990*1da177e4SLinus Torvalds }
6991*1da177e4SLinus Torvalds 
6992*1da177e4SLinus Torvalds /****************************************************************************/
6993*1da177e4SLinus Torvalds /*                                                                          */
6994*1da177e4SLinus Torvalds /* Routine Name: ips_register_scsi                                          */
6995*1da177e4SLinus Torvalds /*                                                                          */
6996*1da177e4SLinus Torvalds /* Routine Description:                                                     */
6997*1da177e4SLinus Torvalds /*   perform any registration and setup with the scsi layer                 */
6998*1da177e4SLinus Torvalds /****************************************************************************/
6999*1da177e4SLinus Torvalds static int
7000*1da177e4SLinus Torvalds ips_register_scsi(int index)
7001*1da177e4SLinus Torvalds {
7002*1da177e4SLinus Torvalds 	struct Scsi_Host *sh;
7003*1da177e4SLinus Torvalds 	ips_ha_t *ha, *oldha = ips_ha[index];
7004*1da177e4SLinus Torvalds 	sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t));
7005*1da177e4SLinus Torvalds 	if (!sh) {
7006*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, oldha->pcidev,
7007*1da177e4SLinus Torvalds 			   "Unable to register controller with SCSI subsystem\n");
7008*1da177e4SLinus Torvalds 		return -1;
7009*1da177e4SLinus Torvalds 	}
7010*1da177e4SLinus Torvalds 	ha = IPS_HA(sh);
7011*1da177e4SLinus Torvalds 	memcpy(ha, oldha, sizeof (ips_ha_t));
7012*1da177e4SLinus Torvalds 	free_irq(oldha->irq, oldha);
7013*1da177e4SLinus Torvalds 	/* Install the interrupt handler with the new ha */
7014*1da177e4SLinus Torvalds 	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
7015*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
7016*1da177e4SLinus Torvalds 			   "Unable to install interrupt handler\n");
7017*1da177e4SLinus Torvalds 		scsi_host_put(sh);
7018*1da177e4SLinus Torvalds 		return -1;
7019*1da177e4SLinus Torvalds 	}
7020*1da177e4SLinus Torvalds 
7021*1da177e4SLinus Torvalds 	kfree(oldha);
7022*1da177e4SLinus Torvalds 	ips_sh[index] = sh;
7023*1da177e4SLinus Torvalds 	ips_ha[index] = ha;
7024*1da177e4SLinus Torvalds 	IPS_SCSI_SET_DEVICE(sh, ha);
7025*1da177e4SLinus Torvalds 
7026*1da177e4SLinus Torvalds 	/* Store away needed values for later use */
7027*1da177e4SLinus Torvalds 	sh->io_port = ha->io_addr;
7028*1da177e4SLinus Torvalds 	sh->n_io_port = ha->io_addr ? 255 : 0;
7029*1da177e4SLinus Torvalds 	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
7030*1da177e4SLinus Torvalds 	sh->irq = ha->irq;
7031*1da177e4SLinus Torvalds 	sh->sg_tablesize = sh->hostt->sg_tablesize;
7032*1da177e4SLinus Torvalds 	sh->can_queue = sh->hostt->can_queue;
7033*1da177e4SLinus Torvalds 	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
7034*1da177e4SLinus Torvalds 	sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
7035*1da177e4SLinus Torvalds 	sh->use_clustering = sh->hostt->use_clustering;
7036*1da177e4SLinus Torvalds 
7037*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
7038*1da177e4SLinus Torvalds 	sh->max_sectors = 128;
7039*1da177e4SLinus Torvalds #endif
7040*1da177e4SLinus Torvalds 
7041*1da177e4SLinus Torvalds 	sh->max_id = ha->ntargets;
7042*1da177e4SLinus Torvalds 	sh->max_lun = ha->nlun;
7043*1da177e4SLinus Torvalds 	sh->max_channel = ha->nbus - 1;
7044*1da177e4SLinus Torvalds 	sh->can_queue = ha->max_cmds - 1;
7045*1da177e4SLinus Torvalds 
7046*1da177e4SLinus Torvalds 	IPS_ADD_HOST(sh, NULL);
7047*1da177e4SLinus Torvalds 	return 0;
7048*1da177e4SLinus Torvalds }
7049*1da177e4SLinus Torvalds 
7050*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7051*1da177e4SLinus Torvalds /*   Routine Name: ips_remove_device                                         */
7052*1da177e4SLinus Torvalds /*                                                                           */
7053*1da177e4SLinus Torvalds /*   Routine Description:                                                    */
7054*1da177e4SLinus Torvalds /*     Remove one Adapter ( Hot Plugging )                                   */
7055*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7056*1da177e4SLinus Torvalds static void __devexit
7057*1da177e4SLinus Torvalds ips_remove_device(struct pci_dev *pci_dev)
7058*1da177e4SLinus Torvalds {
7059*1da177e4SLinus Torvalds 	int i;
7060*1da177e4SLinus Torvalds 	struct Scsi_Host *sh;
7061*1da177e4SLinus Torvalds 	ips_ha_t *ha;
7062*1da177e4SLinus Torvalds 
7063*1da177e4SLinus Torvalds 	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
7064*1da177e4SLinus Torvalds 		ha = ips_ha[i];
7065*1da177e4SLinus Torvalds 		if (ha) {
7066*1da177e4SLinus Torvalds 			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
7067*1da177e4SLinus Torvalds 			    (pci_dev->devfn == ha->pcidev->devfn)) {
7068*1da177e4SLinus Torvalds 				sh = ips_sh[i];
7069*1da177e4SLinus Torvalds 				ips_release(sh);
7070*1da177e4SLinus Torvalds 			}
7071*1da177e4SLinus Torvalds 		}
7072*1da177e4SLinus Torvalds 	}
7073*1da177e4SLinus Torvalds }
7074*1da177e4SLinus Torvalds 
7075*1da177e4SLinus Torvalds /****************************************************************************/
7076*1da177e4SLinus Torvalds /*                                                                          */
7077*1da177e4SLinus Torvalds /* Routine Name: ips_module_init                                            */
7078*1da177e4SLinus Torvalds /*                                                                          */
7079*1da177e4SLinus Torvalds /* Routine Description:                                                     */
7080*1da177e4SLinus Torvalds /*   function called on module load                                         */
7081*1da177e4SLinus Torvalds /****************************************************************************/
7082*1da177e4SLinus Torvalds static int __init
7083*1da177e4SLinus Torvalds ips_module_init(void)
7084*1da177e4SLinus Torvalds {
7085*1da177e4SLinus Torvalds 	if (pci_module_init(&ips_pci_driver) < 0)
7086*1da177e4SLinus Torvalds 		return -ENODEV;
7087*1da177e4SLinus Torvalds 	ips_driver_template.module = THIS_MODULE;
7088*1da177e4SLinus Torvalds 	ips_order_controllers();
7089*1da177e4SLinus Torvalds 	if (IPS_REGISTER_HOSTS(&ips_driver_template)) {
7090*1da177e4SLinus Torvalds 		pci_unregister_driver(&ips_pci_driver);
7091*1da177e4SLinus Torvalds 		return -ENODEV;
7092*1da177e4SLinus Torvalds 	}
7093*1da177e4SLinus Torvalds 	register_reboot_notifier(&ips_notifier);
7094*1da177e4SLinus Torvalds 	return 0;
7095*1da177e4SLinus Torvalds }
7096*1da177e4SLinus Torvalds 
7097*1da177e4SLinus Torvalds /****************************************************************************/
7098*1da177e4SLinus Torvalds /*                                                                          */
7099*1da177e4SLinus Torvalds /* Routine Name: ips_module_exit                                            */
7100*1da177e4SLinus Torvalds /*                                                                          */
7101*1da177e4SLinus Torvalds /* Routine Description:                                                     */
7102*1da177e4SLinus Torvalds /*   function called on module unload                                       */
7103*1da177e4SLinus Torvalds /****************************************************************************/
7104*1da177e4SLinus Torvalds static void __exit
7105*1da177e4SLinus Torvalds ips_module_exit(void)
7106*1da177e4SLinus Torvalds {
7107*1da177e4SLinus Torvalds 	IPS_UNREGISTER_HOSTS(&ips_driver_template);
7108*1da177e4SLinus Torvalds 	pci_unregister_driver(&ips_pci_driver);
7109*1da177e4SLinus Torvalds 	unregister_reboot_notifier(&ips_notifier);
7110*1da177e4SLinus Torvalds }
7111*1da177e4SLinus Torvalds 
7112*1da177e4SLinus Torvalds module_init(ips_module_init);
7113*1da177e4SLinus Torvalds module_exit(ips_module_exit);
7114*1da177e4SLinus Torvalds 
7115*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7116*1da177e4SLinus Torvalds /*   Routine Name: ips_insert_device                                         */
7117*1da177e4SLinus Torvalds /*                                                                           */
7118*1da177e4SLinus Torvalds /*   Routine Description:                                                    */
7119*1da177e4SLinus Torvalds /*     Add One Adapter ( Hot Plug )                                          */
7120*1da177e4SLinus Torvalds /*                                                                           */
7121*1da177e4SLinus Torvalds /*   Return Value:                                                           */
7122*1da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
7123*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7124*1da177e4SLinus Torvalds static int __devinit
7125*1da177e4SLinus Torvalds ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
7126*1da177e4SLinus Torvalds {
7127*1da177e4SLinus Torvalds 	int index;
7128*1da177e4SLinus Torvalds 	int rc;
7129*1da177e4SLinus Torvalds 
7130*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_insert_device", 1);
7131*1da177e4SLinus Torvalds 	if (pci_enable_device(pci_dev))
7132*1da177e4SLinus Torvalds 		return -1;
7133*1da177e4SLinus Torvalds 
7134*1da177e4SLinus Torvalds 	rc = ips_init_phase1(pci_dev, &index);
7135*1da177e4SLinus Torvalds 	if (rc == SUCCESS)
7136*1da177e4SLinus Torvalds 		rc = ips_init_phase2(index);
7137*1da177e4SLinus Torvalds 
7138*1da177e4SLinus Torvalds 	if (ips_hotplug)
7139*1da177e4SLinus Torvalds 		if (ips_register_scsi(index)) {
7140*1da177e4SLinus Torvalds 			ips_free(ips_ha[index]);
7141*1da177e4SLinus Torvalds 			rc = -1;
7142*1da177e4SLinus Torvalds 		}
7143*1da177e4SLinus Torvalds 
7144*1da177e4SLinus Torvalds 	if (rc == SUCCESS)
7145*1da177e4SLinus Torvalds 		ips_num_controllers++;
7146*1da177e4SLinus Torvalds 
7147*1da177e4SLinus Torvalds 	ips_next_controller = ips_num_controllers;
7148*1da177e4SLinus Torvalds 	return rc;
7149*1da177e4SLinus Torvalds }
7150*1da177e4SLinus Torvalds 
7151*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7152*1da177e4SLinus Torvalds /*   Routine Name: ips_init_phase1                                           */
7153*1da177e4SLinus Torvalds /*                                                                           */
7154*1da177e4SLinus Torvalds /*   Routine Description:                                                    */
7155*1da177e4SLinus Torvalds /*     Adapter Initialization                                                */
7156*1da177e4SLinus Torvalds /*                                                                           */
7157*1da177e4SLinus Torvalds /*   Return Value:                                                           */
7158*1da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
7159*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7160*1da177e4SLinus Torvalds static int
7161*1da177e4SLinus Torvalds ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
7162*1da177e4SLinus Torvalds {
7163*1da177e4SLinus Torvalds 	ips_ha_t *ha;
7164*1da177e4SLinus Torvalds 	uint32_t io_addr;
7165*1da177e4SLinus Torvalds 	uint32_t mem_addr;
7166*1da177e4SLinus Torvalds 	uint32_t io_len;
7167*1da177e4SLinus Torvalds 	uint32_t mem_len;
7168*1da177e4SLinus Torvalds 	uint8_t revision_id;
7169*1da177e4SLinus Torvalds 	uint8_t bus;
7170*1da177e4SLinus Torvalds 	uint8_t func;
7171*1da177e4SLinus Torvalds 	uint8_t irq;
7172*1da177e4SLinus Torvalds 	uint16_t subdevice_id;
7173*1da177e4SLinus Torvalds 	int j;
7174*1da177e4SLinus Torvalds 	int index;
7175*1da177e4SLinus Torvalds 	dma_addr_t dma_address;
7176*1da177e4SLinus Torvalds 	char __iomem *ioremap_ptr;
7177*1da177e4SLinus Torvalds 	char __iomem *mem_ptr;
7178*1da177e4SLinus Torvalds 	uint32_t IsDead;
7179*1da177e4SLinus Torvalds 
7180*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_phase1", 1);
7181*1da177e4SLinus Torvalds 	index = IPS_MAX_ADAPTERS;
7182*1da177e4SLinus Torvalds 	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
7183*1da177e4SLinus Torvalds 		if (ips_ha[j] == 0) {
7184*1da177e4SLinus Torvalds 			index = j;
7185*1da177e4SLinus Torvalds 			break;
7186*1da177e4SLinus Torvalds 		}
7187*1da177e4SLinus Torvalds 	}
7188*1da177e4SLinus Torvalds 
7189*1da177e4SLinus Torvalds 	if (index >= IPS_MAX_ADAPTERS)
7190*1da177e4SLinus Torvalds 		return -1;
7191*1da177e4SLinus Torvalds 
7192*1da177e4SLinus Torvalds 	/* stuff that we get in dev */
7193*1da177e4SLinus Torvalds 	irq = pci_dev->irq;
7194*1da177e4SLinus Torvalds 	bus = pci_dev->bus->number;
7195*1da177e4SLinus Torvalds 	func = pci_dev->devfn;
7196*1da177e4SLinus Torvalds 
7197*1da177e4SLinus Torvalds 	/* Init MEM/IO addresses to 0 */
7198*1da177e4SLinus Torvalds 	mem_addr = 0;
7199*1da177e4SLinus Torvalds 	io_addr = 0;
7200*1da177e4SLinus Torvalds 	mem_len = 0;
7201*1da177e4SLinus Torvalds 	io_len = 0;
7202*1da177e4SLinus Torvalds 
7203*1da177e4SLinus Torvalds 	for (j = 0; j < 2; j++) {
7204*1da177e4SLinus Torvalds 		if (!pci_resource_start(pci_dev, j))
7205*1da177e4SLinus Torvalds 			break;
7206*1da177e4SLinus Torvalds 
7207*1da177e4SLinus Torvalds 		if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
7208*1da177e4SLinus Torvalds 			io_addr = pci_resource_start(pci_dev, j);
7209*1da177e4SLinus Torvalds 			io_len = pci_resource_len(pci_dev, j);
7210*1da177e4SLinus Torvalds 		} else {
7211*1da177e4SLinus Torvalds 			mem_addr = pci_resource_start(pci_dev, j);
7212*1da177e4SLinus Torvalds 			mem_len = pci_resource_len(pci_dev, j);
7213*1da177e4SLinus Torvalds 		}
7214*1da177e4SLinus Torvalds 	}
7215*1da177e4SLinus Torvalds 
7216*1da177e4SLinus Torvalds 	/* setup memory mapped area (if applicable) */
7217*1da177e4SLinus Torvalds 	if (mem_addr) {
7218*1da177e4SLinus Torvalds 		uint32_t base;
7219*1da177e4SLinus Torvalds 		uint32_t offs;
7220*1da177e4SLinus Torvalds 
7221*1da177e4SLinus Torvalds 		if (!request_mem_region(mem_addr, mem_len, "ips")) {
7222*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, pci_dev,
7223*1da177e4SLinus Torvalds 				   "Couldn't allocate IO Memory space %x len %d.\n",
7224*1da177e4SLinus Torvalds 				   mem_addr, mem_len);
7225*1da177e4SLinus Torvalds 			return -1;
7226*1da177e4SLinus Torvalds 		}
7227*1da177e4SLinus Torvalds 
7228*1da177e4SLinus Torvalds 		base = mem_addr & PAGE_MASK;
7229*1da177e4SLinus Torvalds 		offs = mem_addr - base;
7230*1da177e4SLinus Torvalds 		ioremap_ptr = ioremap(base, PAGE_SIZE);
7231*1da177e4SLinus Torvalds 		mem_ptr = ioremap_ptr + offs;
7232*1da177e4SLinus Torvalds 	} else {
7233*1da177e4SLinus Torvalds 		ioremap_ptr = NULL;
7234*1da177e4SLinus Torvalds 		mem_ptr = NULL;
7235*1da177e4SLinus Torvalds 	}
7236*1da177e4SLinus Torvalds 
7237*1da177e4SLinus Torvalds 	/* setup I/O mapped area (if applicable) */
7238*1da177e4SLinus Torvalds 	if (io_addr) {
7239*1da177e4SLinus Torvalds 		if (!request_region(io_addr, io_len, "ips")) {
7240*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, pci_dev,
7241*1da177e4SLinus Torvalds 				   "Couldn't allocate IO space %x len %d.\n",
7242*1da177e4SLinus Torvalds 				   io_addr, io_len);
7243*1da177e4SLinus Torvalds 			return -1;
7244*1da177e4SLinus Torvalds 		}
7245*1da177e4SLinus Torvalds 	}
7246*1da177e4SLinus Torvalds 
7247*1da177e4SLinus Torvalds 	/* get the revision ID */
7248*1da177e4SLinus Torvalds 	if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
7249*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");
7250*1da177e4SLinus Torvalds 		return -1;
7251*1da177e4SLinus Torvalds 	}
7252*1da177e4SLinus Torvalds 
7253*1da177e4SLinus Torvalds 	subdevice_id = pci_dev->subsystem_device;
7254*1da177e4SLinus Torvalds 
7255*1da177e4SLinus Torvalds 	/* found a controller */
7256*1da177e4SLinus Torvalds 	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
7257*1da177e4SLinus Torvalds 	if (ha == NULL) {
7258*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7259*1da177e4SLinus Torvalds 			   "Unable to allocate temporary ha struct\n");
7260*1da177e4SLinus Torvalds 		return -1;
7261*1da177e4SLinus Torvalds 	}
7262*1da177e4SLinus Torvalds 
7263*1da177e4SLinus Torvalds 	memset(ha, 0, sizeof (ips_ha_t));
7264*1da177e4SLinus Torvalds 
7265*1da177e4SLinus Torvalds 	ips_sh[index] = NULL;
7266*1da177e4SLinus Torvalds 	ips_ha[index] = ha;
7267*1da177e4SLinus Torvalds 	ha->active = 1;
7268*1da177e4SLinus Torvalds 
7269*1da177e4SLinus Torvalds 	/* Store info in HA structure */
7270*1da177e4SLinus Torvalds 	ha->irq = irq;
7271*1da177e4SLinus Torvalds 	ha->io_addr = io_addr;
7272*1da177e4SLinus Torvalds 	ha->io_len = io_len;
7273*1da177e4SLinus Torvalds 	ha->mem_addr = mem_addr;
7274*1da177e4SLinus Torvalds 	ha->mem_len = mem_len;
7275*1da177e4SLinus Torvalds 	ha->mem_ptr = mem_ptr;
7276*1da177e4SLinus Torvalds 	ha->ioremap_ptr = ioremap_ptr;
7277*1da177e4SLinus Torvalds 	ha->host_num = (uint32_t) index;
7278*1da177e4SLinus Torvalds 	ha->revision_id = revision_id;
7279*1da177e4SLinus Torvalds 	ha->slot_num = PCI_SLOT(pci_dev->devfn);
7280*1da177e4SLinus Torvalds 	ha->device_id = pci_dev->device;
7281*1da177e4SLinus Torvalds 	ha->subdevice_id = subdevice_id;
7282*1da177e4SLinus Torvalds 	ha->pcidev = pci_dev;
7283*1da177e4SLinus Torvalds 
7284*1da177e4SLinus Torvalds 	/*
7285*1da177e4SLinus Torvalds 	 * Set the pci_dev's dma_mask.  Not all adapters support 64bit
7286*1da177e4SLinus Torvalds 	 * addressing so don't enable it if the adapter can't support
7287*1da177e4SLinus Torvalds 	 * it!  Also, don't use 64bit addressing if dma addresses
7288*1da177e4SLinus Torvalds 	 * are guaranteed to be < 4G.
7289*1da177e4SLinus Torvalds 	 */
7290*1da177e4SLinus Torvalds 	if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
7291*1da177e4SLinus Torvalds 	    !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) {
7292*1da177e4SLinus Torvalds 		(ha)->flags |= IPS_HA_ENH_SG;
7293*1da177e4SLinus Torvalds 	} else {
7294*1da177e4SLinus Torvalds 		if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) {
7295*1da177e4SLinus Torvalds 			printk(KERN_WARNING "Unable to set DMA Mask\n");
7296*1da177e4SLinus Torvalds 			return ips_abort_init(ha, index);
7297*1da177e4SLinus Torvalds 		}
7298*1da177e4SLinus Torvalds 	}
7299*1da177e4SLinus Torvalds 	if(ips_cd_boot && !ips_FlashData){
7300*1da177e4SLinus Torvalds 		ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7,
7301*1da177e4SLinus Torvalds 						     &ips_flashbusaddr);
7302*1da177e4SLinus Torvalds 	}
7303*1da177e4SLinus Torvalds 
7304*1da177e4SLinus Torvalds 	ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ),
7305*1da177e4SLinus Torvalds 				       &ha->enq_busaddr);
7306*1da177e4SLinus Torvalds 	if (!ha->enq) {
7307*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7308*1da177e4SLinus Torvalds 			   "Unable to allocate host inquiry structure\n");
7309*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7310*1da177e4SLinus Torvalds 	}
7311*1da177e4SLinus Torvalds 
7312*1da177e4SLinus Torvalds 	ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) +
7313*1da177e4SLinus Torvalds 					 sizeof (IPS_IO_CMD), &dma_address);
7314*1da177e4SLinus Torvalds 	if (!ha->adapt) {
7315*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7316*1da177e4SLinus Torvalds 			   "Unable to allocate host adapt & dummy structures\n");
7317*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7318*1da177e4SLinus Torvalds 	}
7319*1da177e4SLinus Torvalds 	ha->adapt->hw_status_start = dma_address;
7320*1da177e4SLinus Torvalds 	ha->dummy = (void *) (ha->adapt + 1);
7321*1da177e4SLinus Torvalds 
7322*1da177e4SLinus Torvalds 
7323*1da177e4SLinus Torvalds 
7324*1da177e4SLinus Torvalds 	ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address);
7325*1da177e4SLinus Torvalds 	if (!ha->logical_drive_info) {
7326*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7327*1da177e4SLinus Torvalds 			   "Unable to allocate logical drive info structure\n");
7328*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7329*1da177e4SLinus Torvalds 	}
7330*1da177e4SLinus Torvalds 	ha->logical_drive_info_dma_addr = dma_address;
7331*1da177e4SLinus Torvalds 
7332*1da177e4SLinus Torvalds 
7333*1da177e4SLinus Torvalds 	ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);
7334*1da177e4SLinus Torvalds 
7335*1da177e4SLinus Torvalds 	if (!ha->conf) {
7336*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7337*1da177e4SLinus Torvalds 			   "Unable to allocate host conf structure\n");
7338*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7339*1da177e4SLinus Torvalds 	}
7340*1da177e4SLinus Torvalds 
7341*1da177e4SLinus Torvalds 	ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);
7342*1da177e4SLinus Torvalds 
7343*1da177e4SLinus Torvalds 	if (!ha->nvram) {
7344*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7345*1da177e4SLinus Torvalds 			   "Unable to allocate host NVRAM structure\n");
7346*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7347*1da177e4SLinus Torvalds 	}
7348*1da177e4SLinus Torvalds 
7349*1da177e4SLinus Torvalds 	ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);
7350*1da177e4SLinus Torvalds 
7351*1da177e4SLinus Torvalds 	if (!ha->subsys) {
7352*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7353*1da177e4SLinus Torvalds 			   "Unable to allocate host subsystem structure\n");
7354*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7355*1da177e4SLinus Torvalds 	}
7356*1da177e4SLinus Torvalds 
7357*1da177e4SLinus Torvalds 	/* the ioctl buffer is now used during adapter initialization, so its
7358*1da177e4SLinus Torvalds 	 * successful allocation is now required */
7359*1da177e4SLinus Torvalds 	if (ips_ioctlsize < PAGE_SIZE)
7360*1da177e4SLinus Torvalds 		ips_ioctlsize = PAGE_SIZE;
7361*1da177e4SLinus Torvalds 
7362*1da177e4SLinus Torvalds 	ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize,
7363*1da177e4SLinus Torvalds 					      &ha->ioctl_busaddr);
7364*1da177e4SLinus Torvalds 	ha->ioctl_len = ips_ioctlsize;
7365*1da177e4SLinus Torvalds 	if (!ha->ioctl_data) {
7366*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, pci_dev,
7367*1da177e4SLinus Torvalds 			   "Unable to allocate IOCTL data\n");
7368*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7369*1da177e4SLinus Torvalds 	}
7370*1da177e4SLinus Torvalds 
7371*1da177e4SLinus Torvalds 	/*
7372*1da177e4SLinus Torvalds 	 * Setup Functions
7373*1da177e4SLinus Torvalds 	 */
7374*1da177e4SLinus Torvalds 	ips_setup_funclist(ha);
7375*1da177e4SLinus Torvalds 
7376*1da177e4SLinus Torvalds 	if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) {
7377*1da177e4SLinus Torvalds 		/* If Morpheus appears dead, reset it */
7378*1da177e4SLinus Torvalds 		IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
7379*1da177e4SLinus Torvalds 		if (IsDead == 0xDEADBEEF) {
7380*1da177e4SLinus Torvalds 			ips_reset_morpheus(ha);
7381*1da177e4SLinus Torvalds 		}
7382*1da177e4SLinus Torvalds 	}
7383*1da177e4SLinus Torvalds 
7384*1da177e4SLinus Torvalds 	/*
7385*1da177e4SLinus Torvalds 	 * Initialize the card if it isn't already
7386*1da177e4SLinus Torvalds 	 */
7387*1da177e4SLinus Torvalds 
7388*1da177e4SLinus Torvalds 	if (!(*ha->func.isinit) (ha)) {
7389*1da177e4SLinus Torvalds 		if (!(*ha->func.init) (ha)) {
7390*1da177e4SLinus Torvalds 			/*
7391*1da177e4SLinus Torvalds 			 * Initialization failed
7392*1da177e4SLinus Torvalds 			 */
7393*1da177e4SLinus Torvalds 			IPS_PRINTK(KERN_WARNING, pci_dev,
7394*1da177e4SLinus Torvalds 				   "Unable to initialize controller\n");
7395*1da177e4SLinus Torvalds 			return ips_abort_init(ha, index);
7396*1da177e4SLinus Torvalds 		}
7397*1da177e4SLinus Torvalds 	}
7398*1da177e4SLinus Torvalds 
7399*1da177e4SLinus Torvalds 	*indexPtr = index;
7400*1da177e4SLinus Torvalds 	return SUCCESS;
7401*1da177e4SLinus Torvalds }
7402*1da177e4SLinus Torvalds 
7403*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7404*1da177e4SLinus Torvalds /*   Routine Name: ips_init_phase2                                           */
7405*1da177e4SLinus Torvalds /*                                                                           */
7406*1da177e4SLinus Torvalds /*   Routine Description:                                                    */
7407*1da177e4SLinus Torvalds /*     Adapter Initialization Phase 2                                        */
7408*1da177e4SLinus Torvalds /*                                                                           */
7409*1da177e4SLinus Torvalds /*   Return Value:                                                           */
7410*1da177e4SLinus Torvalds /*     0 if Successful, else non-zero                                        */
7411*1da177e4SLinus Torvalds /*---------------------------------------------------------------------------*/
7412*1da177e4SLinus Torvalds static int
7413*1da177e4SLinus Torvalds ips_init_phase2(int index)
7414*1da177e4SLinus Torvalds {
7415*1da177e4SLinus Torvalds 	ips_ha_t *ha;
7416*1da177e4SLinus Torvalds 
7417*1da177e4SLinus Torvalds 	ha = ips_ha[index];
7418*1da177e4SLinus Torvalds 
7419*1da177e4SLinus Torvalds 	METHOD_TRACE("ips_init_phase2", 1);
7420*1da177e4SLinus Torvalds 	if (!ha->active) {
7421*1da177e4SLinus Torvalds 		ips_ha[index] = NULL;
7422*1da177e4SLinus Torvalds 		return -1;
7423*1da177e4SLinus Torvalds 	}
7424*1da177e4SLinus Torvalds 
7425*1da177e4SLinus Torvalds 	/* Install the interrupt handler */
7426*1da177e4SLinus Torvalds 	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
7427*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
7428*1da177e4SLinus Torvalds 			   "Unable to install interrupt handler\n");
7429*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7430*1da177e4SLinus Torvalds 	}
7431*1da177e4SLinus Torvalds 
7432*1da177e4SLinus Torvalds 	/*
7433*1da177e4SLinus Torvalds 	 * Allocate a temporary SCB for initialization
7434*1da177e4SLinus Torvalds 	 */
7435*1da177e4SLinus Torvalds 	ha->max_cmds = 1;
7436*1da177e4SLinus Torvalds 	if (!ips_allocatescbs(ha)) {
7437*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
7438*1da177e4SLinus Torvalds 			   "Unable to allocate a CCB\n");
7439*1da177e4SLinus Torvalds 		free_irq(ha->irq, ha);
7440*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7441*1da177e4SLinus Torvalds 	}
7442*1da177e4SLinus Torvalds 
7443*1da177e4SLinus Torvalds 	if (!ips_hainit(ha)) {
7444*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
7445*1da177e4SLinus Torvalds 			   "Unable to initialize controller\n");
7446*1da177e4SLinus Torvalds 		free_irq(ha->irq, ha);
7447*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7448*1da177e4SLinus Torvalds 	}
7449*1da177e4SLinus Torvalds 	/* Free the temporary SCB */
7450*1da177e4SLinus Torvalds 	ips_deallocatescbs(ha, 1);
7451*1da177e4SLinus Torvalds 
7452*1da177e4SLinus Torvalds 	/* allocate CCBs */
7453*1da177e4SLinus Torvalds 	if (!ips_allocatescbs(ha)) {
7454*1da177e4SLinus Torvalds 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
7455*1da177e4SLinus Torvalds 			   "Unable to allocate CCBs\n");
7456*1da177e4SLinus Torvalds 		free_irq(ha->irq, ha);
7457*1da177e4SLinus Torvalds 		return ips_abort_init(ha, index);
7458*1da177e4SLinus Torvalds 	}
7459*1da177e4SLinus Torvalds 
7460*1da177e4SLinus Torvalds 	return SUCCESS;
7461*1da177e4SLinus Torvalds }
7462*1da177e4SLinus Torvalds 
7463*1da177e4SLinus Torvalds #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
7464*1da177e4SLinus Torvalds MODULE_LICENSE("GPL");
7465*1da177e4SLinus Torvalds #endif
7466*1da177e4SLinus Torvalds 
7467*1da177e4SLinus Torvalds MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
7468*1da177e4SLinus Torvalds 
7469*1da177e4SLinus Torvalds #ifdef MODULE_VERSION
7470*1da177e4SLinus Torvalds MODULE_VERSION(IPS_VER_STRING);
7471*1da177e4SLinus Torvalds #endif
7472*1da177e4SLinus Torvalds 
7473*1da177e4SLinus Torvalds 
7474*1da177e4SLinus Torvalds /*
7475*1da177e4SLinus Torvalds  * Overrides for Emacs so that we almost follow Linus's tabbing style.
7476*1da177e4SLinus Torvalds  * Emacs will notice this stuff at the end of the file and automatically
7477*1da177e4SLinus Torvalds  * adjust the settings for this buffer only.  This must remain at the end
7478*1da177e4SLinus Torvalds  * of the file.
7479*1da177e4SLinus Torvalds  * ---------------------------------------------------------------------------
7480*1da177e4SLinus Torvalds  * Local variables:
7481*1da177e4SLinus Torvalds  * c-indent-level: 2
7482*1da177e4SLinus Torvalds  * c-brace-imaginary-offset: 0
7483*1da177e4SLinus Torvalds  * c-brace-offset: -2
7484*1da177e4SLinus Torvalds  * c-argdecl-indent: 2
7485*1da177e4SLinus Torvalds  * c-label-offset: -2
7486*1da177e4SLinus Torvalds  * c-continued-statement-offset: 2
7487*1da177e4SLinus Torvalds  * c-continued-brace-offset: 0
7488*1da177e4SLinus Torvalds  * indent-tabs-mode: nil
7489*1da177e4SLinus Torvalds  * tab-width: 8
7490*1da177e4SLinus Torvalds  * End:
7491*1da177e4SLinus Torvalds  */
7492