1*4882a593Smuzhiyun /*****************************************************************************/
2*4882a593Smuzhiyun /* ips.c -- driver for the Adaptec / IBM ServeRAID controller */
3*4882a593Smuzhiyun /* */
4*4882a593Smuzhiyun /* Written By: Keith Mitchell, IBM Corporation */
5*4882a593Smuzhiyun /* Jack Hammer, Adaptec, Inc. */
6*4882a593Smuzhiyun /* David Jeffery, Adaptec, Inc. */
7*4882a593Smuzhiyun /* */
8*4882a593Smuzhiyun /* Copyright (C) 2000 IBM Corporation */
9*4882a593Smuzhiyun /* Copyright (C) 2002,2003 Adaptec, Inc. */
10*4882a593Smuzhiyun /* */
11*4882a593Smuzhiyun /* This program is free software; you can redistribute it and/or modify */
12*4882a593Smuzhiyun /* it under the terms of the GNU General Public License as published by */
13*4882a593Smuzhiyun /* the Free Software Foundation; either version 2 of the License, or */
14*4882a593Smuzhiyun /* (at your option) any later version. */
15*4882a593Smuzhiyun /* */
16*4882a593Smuzhiyun /* This program is distributed in the hope that it will be useful, */
17*4882a593Smuzhiyun /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18*4882a593Smuzhiyun /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19*4882a593Smuzhiyun /* GNU General Public License for more details. */
20*4882a593Smuzhiyun /* */
21*4882a593Smuzhiyun /* NO WARRANTY */
22*4882a593Smuzhiyun /* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */
23*4882a593Smuzhiyun /* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */
24*4882a593Smuzhiyun /* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */
25*4882a593Smuzhiyun /* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */
26*4882a593Smuzhiyun /* solely responsible for determining the appropriateness of using and */
27*4882a593Smuzhiyun /* distributing the Program and assumes all risks associated with its */
28*4882a593Smuzhiyun /* exercise of rights under this Agreement, including but not limited to */
29*4882a593Smuzhiyun /* the risks and costs of program errors, damage to or loss of data, */
30*4882a593Smuzhiyun /* programs or equipment, and unavailability or interruption of operations. */
31*4882a593Smuzhiyun /* */
32*4882a593Smuzhiyun /* DISCLAIMER OF LIABILITY */
33*4882a593Smuzhiyun /* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */
34*4882a593Smuzhiyun /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
35*4882a593Smuzhiyun /* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */
36*4882a593Smuzhiyun /* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */
37*4882a593Smuzhiyun /* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */
38*4882a593Smuzhiyun /* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */
39*4882a593Smuzhiyun /* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */
40*4882a593Smuzhiyun /* */
41*4882a593Smuzhiyun /* You should have received a copy of the GNU General Public License */
42*4882a593Smuzhiyun /* along with this program; if not, write to the Free Software */
43*4882a593Smuzhiyun /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
44*4882a593Smuzhiyun /* */
45*4882a593Smuzhiyun /* Bugs/Comments/Suggestions about this driver should be mailed to: */
46*4882a593Smuzhiyun /* ipslinux@adaptec.com */
47*4882a593Smuzhiyun /* */
48*4882a593Smuzhiyun /* For system support issues, contact your local IBM Customer support. */
49*4882a593Smuzhiyun /* Directions to find IBM Customer Support for each country can be found at: */
50*4882a593Smuzhiyun /* http://www.ibm.com/planetwide/ */
51*4882a593Smuzhiyun /* */
52*4882a593Smuzhiyun /*****************************************************************************/
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /*****************************************************************************/
55*4882a593Smuzhiyun /* Change Log */
56*4882a593Smuzhiyun /* */
57*4882a593Smuzhiyun /* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size */
58*4882a593Smuzhiyun /* 0.99.03 - Make interrupt routine handle all completed request on the */
59*4882a593Smuzhiyun /* adapter not just the first one */
60*4882a593Smuzhiyun /* - Make sure passthru commands get woken up if we run out of */
61*4882a593Smuzhiyun /* SCBs */
62*4882a593Smuzhiyun /* - Send all of the commands on the queue at once rather than */
63*4882a593Smuzhiyun /* one at a time since the card will support it. */
64*4882a593Smuzhiyun /* 0.99.04 - Fix race condition in the passthru mechanism -- this required */
65*4882a593Smuzhiyun /* the interface to the utilities to change */
66*4882a593Smuzhiyun /* - Fix error recovery code */
67*4882a593Smuzhiyun /* 0.99.05 - Fix an oops when we get certain passthru commands */
68*4882a593Smuzhiyun /* 1.00.00 - Initial Public Release */
69*4882a593Smuzhiyun /* Functionally equivalent to 0.99.05 */
70*4882a593Smuzhiyun /* 3.60.00 - Bump max commands to 128 for use with firmware 3.60 */
71*4882a593Smuzhiyun /* - Change version to 3.60 to coincide with release numbering. */
72*4882a593Smuzhiyun /* 3.60.01 - Remove bogus error check in passthru routine */
73*4882a593Smuzhiyun /* 3.60.02 - Make DCDB direction based on lookup table */
74*4882a593Smuzhiyun /* - Only allow one DCDB command to a SCSI ID at a time */
75*4882a593Smuzhiyun /* 4.00.00 - Add support for ServeRAID 4 */
76*4882a593Smuzhiyun /* 4.00.01 - Add support for First Failure Data Capture */
77*4882a593Smuzhiyun /* 4.00.02 - Fix problem with PT DCDB with no buffer */
78*4882a593Smuzhiyun /* 4.00.03 - Add alternative passthru interface */
79*4882a593Smuzhiyun /* - Add ability to flash BIOS */
80*4882a593Smuzhiyun /* 4.00.04 - Rename structures/constants to be prefixed with IPS_ */
81*4882a593Smuzhiyun /* 4.00.05 - Remove wish_block from init routine */
82*4882a593Smuzhiyun /* - Use linux/spinlock.h instead of asm/spinlock.h for kernels */
83*4882a593Smuzhiyun /* 2.3.18 and later */
84*4882a593Smuzhiyun /* - Sync with other changes from the 2.3 kernels */
85*4882a593Smuzhiyun /* 4.00.06 - Fix timeout with initial FFDC command */
86*4882a593Smuzhiyun /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */
87*4882a593Smuzhiyun /* 4.10.00 - Add support for ServeRAID 4M/4L */
88*4882a593Smuzhiyun /* 4.10.13 - Fix for dynamic unload and proc file system */
89*4882a593Smuzhiyun /* 4.20.03 - Rename version to coincide with new release schedules */
90*4882a593Smuzhiyun /* Performance fixes */
91*4882a593Smuzhiyun /* Fix truncation of /proc files with cat */
92*4882a593Smuzhiyun /* Merge in changes through kernel 2.4.0test1ac21 */
93*4882a593Smuzhiyun /* 4.20.13 - Fix some failure cases / reset code */
94*4882a593Smuzhiyun /* - Hook into the reboot_notifier to flush the controller cache */
95*4882a593Smuzhiyun /* 4.50.01 - Fix problem when there is a hole in logical drive numbering */
96*4882a593Smuzhiyun /* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */
97*4882a593Smuzhiyun /* - Add IPSSEND Flash Support */
98*4882a593Smuzhiyun /* - Set Sense Data for Unknown SCSI Command */
99*4882a593Smuzhiyun /* - Use Slot Number from NVRAM Page 5 */
100*4882a593Smuzhiyun /* - Restore caller's DCDB Structure */
101*4882a593Smuzhiyun /* 4.70.12 - Corrective actions for bad controller ( during initialization )*/
102*4882a593Smuzhiyun /* 4.70.13 - Don't Send CDB's if we already know the device is not present */
103*4882a593Smuzhiyun /* - Don't release HA Lock in ips_next() until SC taken off queue */
104*4882a593Smuzhiyun /* - Unregister SCSI device in ips_release() */
105*4882a593Smuzhiyun /* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */
106*4882a593Smuzhiyun /* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */
107*4882a593Smuzhiyun /* Code Clean-Up for 2.4.x kernel */
108*4882a593Smuzhiyun /* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */
109*4882a593Smuzhiyun /* 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) */
110*4882a593Smuzhiyun /* - Don't Issue Internal FFDC Command if there are Active Commands */
111*4882a593Smuzhiyun /* - Close Window for getting too many IOCTL's active */
112*4882a593Smuzhiyun /* 4.80.00 - Make ia64 Safe */
113*4882a593Smuzhiyun /* 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater */
114*4882a593Smuzhiyun /* - Adjustments to Device Queue Depth */
115*4882a593Smuzhiyun /* 4.80.14 - Take all semaphores off stack */
116*4882a593Smuzhiyun /* - Clean Up New_IOCTL path */
117*4882a593Smuzhiyun /* 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) */
118*4882a593Smuzhiyun /* - 5 second delay needed after resetting an i960 adapter */
119*4882a593Smuzhiyun /* 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) */
120*4882a593Smuzhiyun /* 4.90.01 - Version Matching for FirmWare, BIOS, and Driver */
121*4882a593Smuzhiyun /* 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development */
122*4882a593Smuzhiyun /* 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) */
123*4882a593Smuzhiyun /* 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K */
124*4882a593Smuzhiyun /* 4.90.11 - Don't actually RESET unless it's physically required */
125*4882a593Smuzhiyun /* - Remove unused compile options */
126*4882a593Smuzhiyun /* 5.00.01 - Sarasota ( 5i ) adapters must always be scanned first */
127*4882a593Smuzhiyun /* - Get rid on IOCTL_NEW_COMMAND code */
128*4882a593Smuzhiyun /* - Add Extended DCDB Commands for Tape Support in 5I */
129*4882a593Smuzhiyun /* 5.10.12 - use pci_dma interfaces, update for 2.5 kernel changes */
130*4882a593Smuzhiyun /* 5.10.15 - remove unused code (sem, macros, etc.) */
131*4882a593Smuzhiyun /* 5.30.00 - use __devexit_p() */
132*4882a593Smuzhiyun /* 6.00.00 - Add 6x Adapters and Battery Flash */
133*4882a593Smuzhiyun /* 6.10.00 - Remove 1G Addressing Limitations */
134*4882a593Smuzhiyun /* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */
135*4882a593Smuzhiyun /* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */
136*4882a593Smuzhiyun /* 7.10.18 - Add highmem_io flag in SCSI Templete for 2.4 kernels */
137*4882a593Smuzhiyun /* - Fix path/name for scsi_hosts.h include for 2.6 kernels */
138*4882a593Smuzhiyun /* - Fix sort order of 7k */
139*4882a593Smuzhiyun /* - Remove 3 unused "inline" functions */
140*4882a593Smuzhiyun /* 7.12.xx - Use STATIC functions wherever possible */
141*4882a593Smuzhiyun /* - Clean up deprecated MODULE_PARM calls */
142*4882a593Smuzhiyun /* 7.12.05 - Remove Version Matching per IBM request */
143*4882a593Smuzhiyun /*****************************************************************************/
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /*
146*4882a593Smuzhiyun * Conditional Compilation directives for this driver:
147*4882a593Smuzhiyun *
148*4882a593Smuzhiyun * IPS_DEBUG - Turn on debugging info
149*4882a593Smuzhiyun *
150*4882a593Smuzhiyun * Parameters:
151*4882a593Smuzhiyun *
152*4882a593Smuzhiyun * debug:<number> - Set debug level to <number>
153*4882a593Smuzhiyun * NOTE: only works when IPS_DEBUG compile directive is used.
154*4882a593Smuzhiyun * 1 - Normal debug messages
155*4882a593Smuzhiyun * 2 - Verbose debug messages
156*4882a593Smuzhiyun * 11 - Method trace (non interrupt)
157*4882a593Smuzhiyun * 12 - Method trace (includes interrupt)
158*4882a593Smuzhiyun *
159*4882a593Smuzhiyun * noi2o - Don't use I2O Queues (ServeRAID 4 only)
160*4882a593Smuzhiyun * nommap - Don't use memory mapped I/O
161*4882a593Smuzhiyun * ioctlsize - Initial size of the IOCTL buffer
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun #include <asm/io.h>
165*4882a593Smuzhiyun #include <asm/byteorder.h>
166*4882a593Smuzhiyun #include <asm/page.h>
167*4882a593Smuzhiyun #include <linux/stddef.h>
168*4882a593Smuzhiyun #include <linux/string.h>
169*4882a593Smuzhiyun #include <linux/errno.h>
170*4882a593Smuzhiyun #include <linux/kernel.h>
171*4882a593Smuzhiyun #include <linux/ioport.h>
172*4882a593Smuzhiyun #include <linux/slab.h>
173*4882a593Smuzhiyun #include <linux/delay.h>
174*4882a593Smuzhiyun #include <linux/pci.h>
175*4882a593Smuzhiyun #include <linux/proc_fs.h>
176*4882a593Smuzhiyun #include <linux/reboot.h>
177*4882a593Smuzhiyun #include <linux/interrupt.h>
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun #include <linux/blkdev.h>
180*4882a593Smuzhiyun #include <linux/types.h>
181*4882a593Smuzhiyun #include <linux/dma-mapping.h>
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun #include <scsi/sg.h>
184*4882a593Smuzhiyun #include "scsi.h"
185*4882a593Smuzhiyun #include <scsi/scsi_host.h>
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun #include "ips.h"
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun #include <linux/module.h>
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun #include <linux/stat.h>
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun #include <linux/spinlock.h>
194*4882a593Smuzhiyun #include <linux/init.h>
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun #include <linux/smp.h>
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun #ifdef MODULE
199*4882a593Smuzhiyun static char *ips = NULL;
200*4882a593Smuzhiyun module_param(ips, charp, 0);
201*4882a593Smuzhiyun #endif
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * DRIVER_VER
205*4882a593Smuzhiyun */
206*4882a593Smuzhiyun #define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING
207*4882a593Smuzhiyun #define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " "
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
210*4882a593Smuzhiyun DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
211*4882a593Smuzhiyun DMA_BIDIRECTIONAL : \
212*4882a593Smuzhiyun scb->scsi_cmd->sc_data_direction)
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun #ifdef IPS_DEBUG
215*4882a593Smuzhiyun #define METHOD_TRACE(s, i) if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
216*4882a593Smuzhiyun #define DEBUG(i, s) if (ips_debug >= i) printk(KERN_NOTICE s "\n");
217*4882a593Smuzhiyun #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
218*4882a593Smuzhiyun #else
219*4882a593Smuzhiyun #define METHOD_TRACE(s, i)
220*4882a593Smuzhiyun #define DEBUG(i, s)
221*4882a593Smuzhiyun #define DEBUG_VAR(i, s, v...)
222*4882a593Smuzhiyun #endif
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /*
225*4882a593Smuzhiyun * Function prototypes
226*4882a593Smuzhiyun */
227*4882a593Smuzhiyun static int ips_eh_abort(struct scsi_cmnd *);
228*4882a593Smuzhiyun static int ips_eh_reset(struct scsi_cmnd *);
229*4882a593Smuzhiyun static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *);
230*4882a593Smuzhiyun static const char *ips_info(struct Scsi_Host *);
231*4882a593Smuzhiyun static irqreturn_t do_ipsintr(int, void *);
232*4882a593Smuzhiyun static int ips_hainit(ips_ha_t *);
233*4882a593Smuzhiyun static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
234*4882a593Smuzhiyun static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
235*4882a593Smuzhiyun static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
236*4882a593Smuzhiyun static int ips_online(ips_ha_t *, ips_scb_t *);
237*4882a593Smuzhiyun static int ips_inquiry(ips_ha_t *, ips_scb_t *);
238*4882a593Smuzhiyun static int ips_rdcap(ips_ha_t *, ips_scb_t *);
239*4882a593Smuzhiyun static int ips_msense(ips_ha_t *, ips_scb_t *);
240*4882a593Smuzhiyun static int ips_reqsen(ips_ha_t *, ips_scb_t *);
241*4882a593Smuzhiyun static int ips_deallocatescbs(ips_ha_t *, int);
242*4882a593Smuzhiyun static int ips_allocatescbs(ips_ha_t *);
243*4882a593Smuzhiyun static int ips_reset_copperhead(ips_ha_t *);
244*4882a593Smuzhiyun static int ips_reset_copperhead_memio(ips_ha_t *);
245*4882a593Smuzhiyun static int ips_reset_morpheus(ips_ha_t *);
246*4882a593Smuzhiyun static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
247*4882a593Smuzhiyun static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
248*4882a593Smuzhiyun static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
249*4882a593Smuzhiyun static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
250*4882a593Smuzhiyun static int ips_isintr_copperhead(ips_ha_t *);
251*4882a593Smuzhiyun static int ips_isintr_copperhead_memio(ips_ha_t *);
252*4882a593Smuzhiyun static int ips_isintr_morpheus(ips_ha_t *);
253*4882a593Smuzhiyun static int ips_wait(ips_ha_t *, int, int);
254*4882a593Smuzhiyun static int ips_write_driver_status(ips_ha_t *, int);
255*4882a593Smuzhiyun static int ips_read_adapter_status(ips_ha_t *, int);
256*4882a593Smuzhiyun static int ips_read_subsystem_parameters(ips_ha_t *, int);
257*4882a593Smuzhiyun static int ips_read_config(ips_ha_t *, int);
258*4882a593Smuzhiyun static int ips_clear_adapter(ips_ha_t *, int);
259*4882a593Smuzhiyun static int ips_readwrite_page5(ips_ha_t *, int, int);
260*4882a593Smuzhiyun static int ips_init_copperhead(ips_ha_t *);
261*4882a593Smuzhiyun static int ips_init_copperhead_memio(ips_ha_t *);
262*4882a593Smuzhiyun static int ips_init_morpheus(ips_ha_t *);
263*4882a593Smuzhiyun static int ips_isinit_copperhead(ips_ha_t *);
264*4882a593Smuzhiyun static int ips_isinit_copperhead_memio(ips_ha_t *);
265*4882a593Smuzhiyun static int ips_isinit_morpheus(ips_ha_t *);
266*4882a593Smuzhiyun static int ips_erase_bios(ips_ha_t *);
267*4882a593Smuzhiyun static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
268*4882a593Smuzhiyun static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
269*4882a593Smuzhiyun static int ips_erase_bios_memio(ips_ha_t *);
270*4882a593Smuzhiyun static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
271*4882a593Smuzhiyun static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
272*4882a593Smuzhiyun static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
273*4882a593Smuzhiyun static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
274*4882a593Smuzhiyun static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
275*4882a593Smuzhiyun static void ips_free_flash_copperhead(ips_ha_t * ha);
276*4882a593Smuzhiyun static void ips_get_bios_version(ips_ha_t *, int);
277*4882a593Smuzhiyun static void ips_identify_controller(ips_ha_t *);
278*4882a593Smuzhiyun static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
279*4882a593Smuzhiyun static void ips_enable_int_copperhead(ips_ha_t *);
280*4882a593Smuzhiyun static void ips_enable_int_copperhead_memio(ips_ha_t *);
281*4882a593Smuzhiyun static void ips_enable_int_morpheus(ips_ha_t *);
282*4882a593Smuzhiyun static int ips_intr_copperhead(ips_ha_t *);
283*4882a593Smuzhiyun static int ips_intr_morpheus(ips_ha_t *);
284*4882a593Smuzhiyun static void ips_next(ips_ha_t *, int);
285*4882a593Smuzhiyun static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
286*4882a593Smuzhiyun static void ipsintr_done(ips_ha_t *, struct ips_scb *);
287*4882a593Smuzhiyun static void ips_done(ips_ha_t *, ips_scb_t *);
288*4882a593Smuzhiyun static void ips_free(ips_ha_t *);
289*4882a593Smuzhiyun static void ips_init_scb(ips_ha_t *, ips_scb_t *);
290*4882a593Smuzhiyun static void ips_freescb(ips_ha_t *, ips_scb_t *);
291*4882a593Smuzhiyun static void ips_setup_funclist(ips_ha_t *);
292*4882a593Smuzhiyun static void ips_statinit(ips_ha_t *);
293*4882a593Smuzhiyun static void ips_statinit_memio(ips_ha_t *);
294*4882a593Smuzhiyun static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time64_t);
295*4882a593Smuzhiyun static void ips_ffdc_reset(ips_ha_t *, int);
296*4882a593Smuzhiyun static void ips_ffdc_time(ips_ha_t *);
297*4882a593Smuzhiyun static uint32_t ips_statupd_copperhead(ips_ha_t *);
298*4882a593Smuzhiyun static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
299*4882a593Smuzhiyun static uint32_t ips_statupd_morpheus(ips_ha_t *);
300*4882a593Smuzhiyun static ips_scb_t *ips_getscb(ips_ha_t *);
301*4882a593Smuzhiyun static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
302*4882a593Smuzhiyun static void ips_putq_wait_tail(ips_wait_queue_entry_t *, struct scsi_cmnd *);
303*4882a593Smuzhiyun static void ips_putq_copp_tail(ips_copp_queue_t *,
304*4882a593Smuzhiyun ips_copp_wait_item_t *);
305*4882a593Smuzhiyun static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
306*4882a593Smuzhiyun static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
307*4882a593Smuzhiyun static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_entry_t *);
308*4882a593Smuzhiyun static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_entry_t *,
309*4882a593Smuzhiyun struct scsi_cmnd *);
310*4882a593Smuzhiyun static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
311*4882a593Smuzhiyun ips_copp_wait_item_t *);
312*4882a593Smuzhiyun static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun static int ips_is_passthru(struct scsi_cmnd *);
315*4882a593Smuzhiyun static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int);
316*4882a593Smuzhiyun static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
317*4882a593Smuzhiyun static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
318*4882a593Smuzhiyun static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
319*4882a593Smuzhiyun unsigned int count);
320*4882a593Smuzhiyun static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data,
321*4882a593Smuzhiyun unsigned int count);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun static int ips_write_info(struct Scsi_Host *, char *, int);
324*4882a593Smuzhiyun static int ips_show_info(struct seq_file *, struct Scsi_Host *);
325*4882a593Smuzhiyun static int ips_host_info(ips_ha_t *, struct seq_file *);
326*4882a593Smuzhiyun static int ips_abort_init(ips_ha_t * ha, int index);
327*4882a593Smuzhiyun static int ips_init_phase2(int index);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
330*4882a593Smuzhiyun static int ips_register_scsi(int index);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun static int ips_poll_for_flush_complete(ips_ha_t * ha);
333*4882a593Smuzhiyun static void ips_flush_and_reset(ips_ha_t *ha);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /*
336*4882a593Smuzhiyun * global variables
337*4882a593Smuzhiyun */
338*4882a593Smuzhiyun static const char ips_name[] = "ips";
339*4882a593Smuzhiyun static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */
340*4882a593Smuzhiyun static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */
341*4882a593Smuzhiyun static unsigned int ips_next_controller;
342*4882a593Smuzhiyun static unsigned int ips_num_controllers;
343*4882a593Smuzhiyun static unsigned int ips_released_controllers;
344*4882a593Smuzhiyun static int ips_hotplug;
345*4882a593Smuzhiyun static int ips_cmd_timeout = 60;
346*4882a593Smuzhiyun static int ips_reset_timeout = 60 * 5;
347*4882a593Smuzhiyun static int ips_force_memio = 1; /* Always use Memory Mapped I/O */
348*4882a593Smuzhiyun static int ips_force_i2o = 1; /* Always use I2O command delivery */
349*4882a593Smuzhiyun static int ips_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */
350*4882a593Smuzhiyun static int ips_cd_boot; /* Booting from Manager CD */
351*4882a593Smuzhiyun static char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */
352*4882a593Smuzhiyun static dma_addr_t ips_flashbusaddr;
353*4882a593Smuzhiyun static long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */
354*4882a593Smuzhiyun static uint32_t MaxLiteCmds = 32; /* Max Active Cmds for a Lite Adapter */
355*4882a593Smuzhiyun static struct scsi_host_template ips_driver_template = {
356*4882a593Smuzhiyun .info = ips_info,
357*4882a593Smuzhiyun .queuecommand = ips_queue,
358*4882a593Smuzhiyun .eh_abort_handler = ips_eh_abort,
359*4882a593Smuzhiyun .eh_host_reset_handler = ips_eh_reset,
360*4882a593Smuzhiyun .proc_name = "ips",
361*4882a593Smuzhiyun .show_info = ips_show_info,
362*4882a593Smuzhiyun .write_info = ips_write_info,
363*4882a593Smuzhiyun .slave_configure = ips_slave_configure,
364*4882a593Smuzhiyun .bios_param = ips_biosparam,
365*4882a593Smuzhiyun .this_id = -1,
366*4882a593Smuzhiyun .sg_tablesize = IPS_MAX_SG,
367*4882a593Smuzhiyun .cmd_per_lun = 3,
368*4882a593Smuzhiyun .no_write_same = 1,
369*4882a593Smuzhiyun };
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /* This table describes all ServeRAID Adapters */
373*4882a593Smuzhiyun static struct pci_device_id ips_pci_table[] = {
374*4882a593Smuzhiyun { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
375*4882a593Smuzhiyun { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
376*4882a593Smuzhiyun { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
377*4882a593Smuzhiyun { 0, }
378*4882a593Smuzhiyun };
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun MODULE_DEVICE_TABLE( pci, ips_pci_table );
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun static char ips_hot_plug_name[] = "ips";
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun static int ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
385*4882a593Smuzhiyun static void ips_remove_device(struct pci_dev *pci_dev);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun static struct pci_driver ips_pci_driver = {
388*4882a593Smuzhiyun .name = ips_hot_plug_name,
389*4882a593Smuzhiyun .id_table = ips_pci_table,
390*4882a593Smuzhiyun .probe = ips_insert_device,
391*4882a593Smuzhiyun .remove = ips_remove_device,
392*4882a593Smuzhiyun };
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun /*
396*4882a593Smuzhiyun * Necessary forward function protoypes
397*4882a593Smuzhiyun */
398*4882a593Smuzhiyun static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun #define MAX_ADAPTER_NAME 15
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun static char ips_adapter_name[][30] = {
403*4882a593Smuzhiyun "ServeRAID",
404*4882a593Smuzhiyun "ServeRAID II",
405*4882a593Smuzhiyun "ServeRAID on motherboard",
406*4882a593Smuzhiyun "ServeRAID on motherboard",
407*4882a593Smuzhiyun "ServeRAID 3H",
408*4882a593Smuzhiyun "ServeRAID 3L",
409*4882a593Smuzhiyun "ServeRAID 4H",
410*4882a593Smuzhiyun "ServeRAID 4M",
411*4882a593Smuzhiyun "ServeRAID 4L",
412*4882a593Smuzhiyun "ServeRAID 4Mx",
413*4882a593Smuzhiyun "ServeRAID 4Lx",
414*4882a593Smuzhiyun "ServeRAID 5i",
415*4882a593Smuzhiyun "ServeRAID 5i",
416*4882a593Smuzhiyun "ServeRAID 6M",
417*4882a593Smuzhiyun "ServeRAID 6i",
418*4882a593Smuzhiyun "ServeRAID 7t",
419*4882a593Smuzhiyun "ServeRAID 7k",
420*4882a593Smuzhiyun "ServeRAID 7M"
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun static struct notifier_block ips_notifier = {
424*4882a593Smuzhiyun ips_halt, NULL, 0
425*4882a593Smuzhiyun };
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun /*
428*4882a593Smuzhiyun * Direction table
429*4882a593Smuzhiyun */
430*4882a593Smuzhiyun static char ips_command_direction[] = {
431*4882a593Smuzhiyun IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
432*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,
433*4882a593Smuzhiyun IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
434*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
435*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
436*4882a593Smuzhiyun IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
437*4882a593Smuzhiyun IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,
438*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
439*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,
440*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
441*4882a593Smuzhiyun IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,
442*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
443*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,
444*4882a593Smuzhiyun IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,
445*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
446*4882a593Smuzhiyun IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
447*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
448*4882a593Smuzhiyun IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
449*4882a593Smuzhiyun IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
450*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
451*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
452*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
453*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
454*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
455*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
456*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
457*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
458*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
459*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
460*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
461*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
462*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
463*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
464*4882a593Smuzhiyun IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,
465*4882a593Smuzhiyun IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,
466*4882a593Smuzhiyun IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,
467*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,
468*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
469*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
470*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
471*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
472*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
473*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
474*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
475*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
476*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
477*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,
478*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
479*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
480*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
481*4882a593Smuzhiyun IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
482*4882a593Smuzhiyun };
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /****************************************************************************/
486*4882a593Smuzhiyun /* */
487*4882a593Smuzhiyun /* Routine Name: ips_setup */
488*4882a593Smuzhiyun /* */
489*4882a593Smuzhiyun /* Routine Description: */
490*4882a593Smuzhiyun /* */
491*4882a593Smuzhiyun /* setup parameters to the driver */
492*4882a593Smuzhiyun /* */
493*4882a593Smuzhiyun /****************************************************************************/
494*4882a593Smuzhiyun static int
ips_setup(char * ips_str)495*4882a593Smuzhiyun ips_setup(char *ips_str)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun int i;
499*4882a593Smuzhiyun char *key;
500*4882a593Smuzhiyun char *value;
501*4882a593Smuzhiyun static const IPS_OPTION options[] = {
502*4882a593Smuzhiyun {"noi2o", &ips_force_i2o, 0},
503*4882a593Smuzhiyun {"nommap", &ips_force_memio, 0},
504*4882a593Smuzhiyun {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
505*4882a593Smuzhiyun {"cdboot", &ips_cd_boot, 0},
506*4882a593Smuzhiyun {"maxcmds", &MaxLiteCmds, 32},
507*4882a593Smuzhiyun };
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
510*4882a593Smuzhiyun /* Search for value */
511*4882a593Smuzhiyun while ((key = strsep(&ips_str, ",."))) {
512*4882a593Smuzhiyun if (!*key)
513*4882a593Smuzhiyun continue;
514*4882a593Smuzhiyun value = strchr(key, ':');
515*4882a593Smuzhiyun if (value)
516*4882a593Smuzhiyun *value++ = '\0';
517*4882a593Smuzhiyun /*
518*4882a593Smuzhiyun * We now have key/value pairs.
519*4882a593Smuzhiyun * Update the variables
520*4882a593Smuzhiyun */
521*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(options); i++) {
522*4882a593Smuzhiyun if (strncasecmp
523*4882a593Smuzhiyun (key, options[i].option_name,
524*4882a593Smuzhiyun strlen(options[i].option_name)) == 0) {
525*4882a593Smuzhiyun if (value)
526*4882a593Smuzhiyun *options[i].option_flag =
527*4882a593Smuzhiyun simple_strtoul(value, NULL, 0);
528*4882a593Smuzhiyun else
529*4882a593Smuzhiyun *options[i].option_flag =
530*4882a593Smuzhiyun options[i].option_value;
531*4882a593Smuzhiyun break;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun return (1);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun __setup("ips=", ips_setup);
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /****************************************************************************/
542*4882a593Smuzhiyun /* */
543*4882a593Smuzhiyun /* Routine Name: ips_detect */
544*4882a593Smuzhiyun /* */
545*4882a593Smuzhiyun /* Routine Description: */
546*4882a593Smuzhiyun /* */
547*4882a593Smuzhiyun /* Detect and initialize the driver */
548*4882a593Smuzhiyun /* */
549*4882a593Smuzhiyun /* NOTE: this routine is called under the io_request_lock spinlock */
550*4882a593Smuzhiyun /* */
551*4882a593Smuzhiyun /****************************************************************************/
552*4882a593Smuzhiyun static int
ips_detect(struct scsi_host_template * SHT)553*4882a593Smuzhiyun ips_detect(struct scsi_host_template * SHT)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun int i;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun METHOD_TRACE("ips_detect", 1);
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun #ifdef MODULE
560*4882a593Smuzhiyun if (ips)
561*4882a593Smuzhiyun ips_setup(ips);
562*4882a593Smuzhiyun #endif
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun for (i = 0; i < ips_num_controllers; i++) {
565*4882a593Smuzhiyun if (ips_register_scsi(i))
566*4882a593Smuzhiyun ips_free(ips_ha[i]);
567*4882a593Smuzhiyun ips_released_controllers++;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun ips_hotplug = 1;
570*4882a593Smuzhiyun return (ips_num_controllers);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /****************************************************************************/
574*4882a593Smuzhiyun /* configure the function pointers to use the functions that will work */
575*4882a593Smuzhiyun /* with the found version of the adapter */
576*4882a593Smuzhiyun /****************************************************************************/
577*4882a593Smuzhiyun static void
ips_setup_funclist(ips_ha_t * ha)578*4882a593Smuzhiyun ips_setup_funclist(ips_ha_t * ha)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /*
582*4882a593Smuzhiyun * Setup Functions
583*4882a593Smuzhiyun */
584*4882a593Smuzhiyun if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
585*4882a593Smuzhiyun /* morpheus / marco / sebring */
586*4882a593Smuzhiyun ha->func.isintr = ips_isintr_morpheus;
587*4882a593Smuzhiyun ha->func.isinit = ips_isinit_morpheus;
588*4882a593Smuzhiyun ha->func.issue = ips_issue_i2o_memio;
589*4882a593Smuzhiyun ha->func.init = ips_init_morpheus;
590*4882a593Smuzhiyun ha->func.statupd = ips_statupd_morpheus;
591*4882a593Smuzhiyun ha->func.reset = ips_reset_morpheus;
592*4882a593Smuzhiyun ha->func.intr = ips_intr_morpheus;
593*4882a593Smuzhiyun ha->func.enableint = ips_enable_int_morpheus;
594*4882a593Smuzhiyun } else if (IPS_USE_MEMIO(ha)) {
595*4882a593Smuzhiyun /* copperhead w/MEMIO */
596*4882a593Smuzhiyun ha->func.isintr = ips_isintr_copperhead_memio;
597*4882a593Smuzhiyun ha->func.isinit = ips_isinit_copperhead_memio;
598*4882a593Smuzhiyun ha->func.init = ips_init_copperhead_memio;
599*4882a593Smuzhiyun ha->func.statupd = ips_statupd_copperhead_memio;
600*4882a593Smuzhiyun ha->func.statinit = ips_statinit_memio;
601*4882a593Smuzhiyun ha->func.reset = ips_reset_copperhead_memio;
602*4882a593Smuzhiyun ha->func.intr = ips_intr_copperhead;
603*4882a593Smuzhiyun ha->func.erasebios = ips_erase_bios_memio;
604*4882a593Smuzhiyun ha->func.programbios = ips_program_bios_memio;
605*4882a593Smuzhiyun ha->func.verifybios = ips_verify_bios_memio;
606*4882a593Smuzhiyun ha->func.enableint = ips_enable_int_copperhead_memio;
607*4882a593Smuzhiyun if (IPS_USE_I2O_DELIVER(ha))
608*4882a593Smuzhiyun ha->func.issue = ips_issue_i2o_memio;
609*4882a593Smuzhiyun else
610*4882a593Smuzhiyun ha->func.issue = ips_issue_copperhead_memio;
611*4882a593Smuzhiyun } else {
612*4882a593Smuzhiyun /* copperhead */
613*4882a593Smuzhiyun ha->func.isintr = ips_isintr_copperhead;
614*4882a593Smuzhiyun ha->func.isinit = ips_isinit_copperhead;
615*4882a593Smuzhiyun ha->func.init = ips_init_copperhead;
616*4882a593Smuzhiyun ha->func.statupd = ips_statupd_copperhead;
617*4882a593Smuzhiyun ha->func.statinit = ips_statinit;
618*4882a593Smuzhiyun ha->func.reset = ips_reset_copperhead;
619*4882a593Smuzhiyun ha->func.intr = ips_intr_copperhead;
620*4882a593Smuzhiyun ha->func.erasebios = ips_erase_bios;
621*4882a593Smuzhiyun ha->func.programbios = ips_program_bios;
622*4882a593Smuzhiyun ha->func.verifybios = ips_verify_bios;
623*4882a593Smuzhiyun ha->func.enableint = ips_enable_int_copperhead;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun if (IPS_USE_I2O_DELIVER(ha))
626*4882a593Smuzhiyun ha->func.issue = ips_issue_i2o;
627*4882a593Smuzhiyun else
628*4882a593Smuzhiyun ha->func.issue = ips_issue_copperhead;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /****************************************************************************/
633*4882a593Smuzhiyun /* */
634*4882a593Smuzhiyun /* Routine Name: ips_release */
635*4882a593Smuzhiyun /* */
636*4882a593Smuzhiyun /* Routine Description: */
637*4882a593Smuzhiyun /* */
638*4882a593Smuzhiyun /* Remove a driver */
639*4882a593Smuzhiyun /* */
640*4882a593Smuzhiyun /****************************************************************************/
641*4882a593Smuzhiyun static int
ips_release(struct Scsi_Host * sh)642*4882a593Smuzhiyun ips_release(struct Scsi_Host *sh)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun ips_scb_t *scb;
645*4882a593Smuzhiyun ips_ha_t *ha;
646*4882a593Smuzhiyun int i;
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun METHOD_TRACE("ips_release", 1);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun scsi_remove_host(sh);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun if (i == IPS_MAX_ADAPTERS) {
655*4882a593Smuzhiyun printk(KERN_WARNING
656*4882a593Smuzhiyun "(%s) release, invalid Scsi_Host pointer.\n", ips_name);
657*4882a593Smuzhiyun BUG();
658*4882a593Smuzhiyun return (FALSE);
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun ha = IPS_HA(sh);
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun if (!ha)
664*4882a593Smuzhiyun return (FALSE);
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun /* flush the cache on the controller */
667*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun ips_init_scb(ha, scb);
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
672*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_FLUSH;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
675*4882a593Smuzhiyun scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
676*4882a593Smuzhiyun scb->cmd.flush_cache.state = IPS_NORM_STATE;
677*4882a593Smuzhiyun scb->cmd.flush_cache.reserved = 0;
678*4882a593Smuzhiyun scb->cmd.flush_cache.reserved2 = 0;
679*4882a593Smuzhiyun scb->cmd.flush_cache.reserved3 = 0;
680*4882a593Smuzhiyun scb->cmd.flush_cache.reserved4 = 0;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun /* send command */
685*4882a593Smuzhiyun if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
686*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun ips_sh[i] = NULL;
691*4882a593Smuzhiyun ips_ha[i] = NULL;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun /* free extra memory */
694*4882a593Smuzhiyun ips_free(ha);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun /* free IRQ */
697*4882a593Smuzhiyun free_irq(ha->pcidev->irq, ha);
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun scsi_host_put(sh);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun ips_released_controllers++;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun return (FALSE);
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun /****************************************************************************/
707*4882a593Smuzhiyun /* */
708*4882a593Smuzhiyun /* Routine Name: ips_halt */
709*4882a593Smuzhiyun /* */
710*4882a593Smuzhiyun /* Routine Description: */
711*4882a593Smuzhiyun /* */
712*4882a593Smuzhiyun /* Perform cleanup when the system reboots */
713*4882a593Smuzhiyun /* */
714*4882a593Smuzhiyun /****************************************************************************/
715*4882a593Smuzhiyun static int
ips_halt(struct notifier_block * nb,ulong event,void * buf)716*4882a593Smuzhiyun ips_halt(struct notifier_block *nb, ulong event, void *buf)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun ips_scb_t *scb;
719*4882a593Smuzhiyun ips_ha_t *ha;
720*4882a593Smuzhiyun int i;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun if ((event != SYS_RESTART) && (event != SYS_HALT) &&
723*4882a593Smuzhiyun (event != SYS_POWER_OFF))
724*4882a593Smuzhiyun return (NOTIFY_DONE);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun for (i = 0; i < ips_next_controller; i++) {
727*4882a593Smuzhiyun ha = (ips_ha_t *) ips_ha[i];
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun if (!ha)
730*4882a593Smuzhiyun continue;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun if (!ha->active)
733*4882a593Smuzhiyun continue;
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun /* flush the cache on the controller */
736*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun ips_init_scb(ha, scb);
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
741*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_FLUSH;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
744*4882a593Smuzhiyun scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
745*4882a593Smuzhiyun scb->cmd.flush_cache.state = IPS_NORM_STATE;
746*4882a593Smuzhiyun scb->cmd.flush_cache.reserved = 0;
747*4882a593Smuzhiyun scb->cmd.flush_cache.reserved2 = 0;
748*4882a593Smuzhiyun scb->cmd.flush_cache.reserved3 = 0;
749*4882a593Smuzhiyun scb->cmd.flush_cache.reserved4 = 0;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun /* send command */
754*4882a593Smuzhiyun if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==
755*4882a593Smuzhiyun IPS_FAILURE)
756*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
757*4882a593Smuzhiyun "Incomplete Flush.\n");
758*4882a593Smuzhiyun else
759*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
760*4882a593Smuzhiyun "Flushing Complete.\n");
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun return (NOTIFY_OK);
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun /****************************************************************************/
767*4882a593Smuzhiyun /* */
768*4882a593Smuzhiyun /* Routine Name: ips_eh_abort */
769*4882a593Smuzhiyun /* */
770*4882a593Smuzhiyun /* Routine Description: */
771*4882a593Smuzhiyun /* */
772*4882a593Smuzhiyun /* Abort a command (using the new error code stuff) */
773*4882a593Smuzhiyun /* Note: this routine is called under the io_request_lock */
774*4882a593Smuzhiyun /****************************************************************************/
ips_eh_abort(struct scsi_cmnd * SC)775*4882a593Smuzhiyun int ips_eh_abort(struct scsi_cmnd *SC)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun ips_ha_t *ha;
778*4882a593Smuzhiyun ips_copp_wait_item_t *item;
779*4882a593Smuzhiyun int ret;
780*4882a593Smuzhiyun struct Scsi_Host *host;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun METHOD_TRACE("ips_eh_abort", 1);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun if (!SC)
785*4882a593Smuzhiyun return (FAILED);
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun host = SC->device->host;
788*4882a593Smuzhiyun ha = (ips_ha_t *) SC->device->host->hostdata;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun if (!ha)
791*4882a593Smuzhiyun return (FAILED);
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun if (!ha->active)
794*4882a593Smuzhiyun return (FAILED);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun spin_lock(host->host_lock);
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun /* See if the command is on the copp queue */
799*4882a593Smuzhiyun item = ha->copp_waitlist.head;
800*4882a593Smuzhiyun while ((item) && (item->scsi_cmd != SC))
801*4882a593Smuzhiyun item = item->next;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun if (item) {
804*4882a593Smuzhiyun /* Found it */
805*4882a593Smuzhiyun ips_removeq_copp(&ha->copp_waitlist, item);
806*4882a593Smuzhiyun ret = (SUCCESS);
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun /* See if the command is on the wait queue */
809*4882a593Smuzhiyun } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
810*4882a593Smuzhiyun /* command not sent yet */
811*4882a593Smuzhiyun ret = (SUCCESS);
812*4882a593Smuzhiyun } else {
813*4882a593Smuzhiyun /* command must have already been sent */
814*4882a593Smuzhiyun ret = (FAILED);
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun spin_unlock(host->host_lock);
818*4882a593Smuzhiyun return ret;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun /****************************************************************************/
822*4882a593Smuzhiyun /* */
823*4882a593Smuzhiyun /* Routine Name: ips_eh_reset */
824*4882a593Smuzhiyun /* */
825*4882a593Smuzhiyun /* Routine Description: */
826*4882a593Smuzhiyun /* */
827*4882a593Smuzhiyun /* Reset the controller (with new eh error code) */
828*4882a593Smuzhiyun /* */
829*4882a593Smuzhiyun /* NOTE: this routine is called under the io_request_lock spinlock */
830*4882a593Smuzhiyun /* */
831*4882a593Smuzhiyun /****************************************************************************/
__ips_eh_reset(struct scsi_cmnd * SC)832*4882a593Smuzhiyun static int __ips_eh_reset(struct scsi_cmnd *SC)
833*4882a593Smuzhiyun {
834*4882a593Smuzhiyun int ret;
835*4882a593Smuzhiyun int i;
836*4882a593Smuzhiyun ips_ha_t *ha;
837*4882a593Smuzhiyun ips_scb_t *scb;
838*4882a593Smuzhiyun ips_copp_wait_item_t *item;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun METHOD_TRACE("ips_eh_reset", 1);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun #ifdef NO_IPS_RESET
843*4882a593Smuzhiyun return (FAILED);
844*4882a593Smuzhiyun #else
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun if (!SC) {
847*4882a593Smuzhiyun DEBUG(1, "Reset called with NULL scsi command");
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun return (FAILED);
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun ha = (ips_ha_t *) SC->device->host->hostdata;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun if (!ha) {
855*4882a593Smuzhiyun DEBUG(1, "Reset called with NULL ha struct");
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun return (FAILED);
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun if (!ha->active)
861*4882a593Smuzhiyun return (FAILED);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun /* See if the command is on the copp queue */
864*4882a593Smuzhiyun item = ha->copp_waitlist.head;
865*4882a593Smuzhiyun while ((item) && (item->scsi_cmd != SC))
866*4882a593Smuzhiyun item = item->next;
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun if (item) {
869*4882a593Smuzhiyun /* Found it */
870*4882a593Smuzhiyun ips_removeq_copp(&ha->copp_waitlist, item);
871*4882a593Smuzhiyun return (SUCCESS);
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun /* See if the command is on the wait queue */
875*4882a593Smuzhiyun if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
876*4882a593Smuzhiyun /* command not sent yet */
877*4882a593Smuzhiyun return (SUCCESS);
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun /* An explanation for the casual observer: */
881*4882a593Smuzhiyun /* Part of the function of a RAID controller is automatic error */
882*4882a593Smuzhiyun /* detection and recovery. As such, the only problem that physically */
883*4882a593Smuzhiyun /* resetting an adapter will ever fix is when, for some reason, */
884*4882a593Smuzhiyun /* the driver is not successfully communicating with the adapter. */
885*4882a593Smuzhiyun /* Therefore, we will attempt to flush this adapter. If that succeeds, */
886*4882a593Smuzhiyun /* then there's no real purpose in a physical reset. This will complete */
887*4882a593Smuzhiyun /* much faster and avoids any problems that might be caused by a */
888*4882a593Smuzhiyun /* physical reset ( such as having to fail all the outstanding I/O's ). */
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun if (ha->ioctl_reset == 0) { /* IF Not an IOCTL Requested Reset */
891*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun ips_init_scb(ha, scb);
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
896*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_FLUSH;
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
899*4882a593Smuzhiyun scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
900*4882a593Smuzhiyun scb->cmd.flush_cache.state = IPS_NORM_STATE;
901*4882a593Smuzhiyun scb->cmd.flush_cache.reserved = 0;
902*4882a593Smuzhiyun scb->cmd.flush_cache.reserved2 = 0;
903*4882a593Smuzhiyun scb->cmd.flush_cache.reserved3 = 0;
904*4882a593Smuzhiyun scb->cmd.flush_cache.reserved4 = 0;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun /* Attempt the flush command */
907*4882a593Smuzhiyun ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
908*4882a593Smuzhiyun if (ret == IPS_SUCCESS) {
909*4882a593Smuzhiyun IPS_PRINTK(KERN_NOTICE, ha->pcidev,
910*4882a593Smuzhiyun "Reset Request - Flushed Cache\n");
911*4882a593Smuzhiyun return (SUCCESS);
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /* Either we can't communicate with the adapter or it's an IOCTL request */
916*4882a593Smuzhiyun /* from a utility. A physical reset is needed at this point. */
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun ha->ioctl_reset = 0; /* Reset the IOCTL Requested Reset Flag */
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun /*
921*4882a593Smuzhiyun * command must have already been sent
922*4882a593Smuzhiyun * reset the controller
923*4882a593Smuzhiyun */
924*4882a593Smuzhiyun IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
925*4882a593Smuzhiyun ret = (*ha->func.reset) (ha);
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun if (!ret) {
928*4882a593Smuzhiyun struct scsi_cmnd *scsi_cmd;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun IPS_PRINTK(KERN_NOTICE, ha->pcidev,
931*4882a593Smuzhiyun "Controller reset failed - controller now offline.\n");
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun /* Now fail all of the active commands */
934*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Failing active commands",
935*4882a593Smuzhiyun ips_name, ha->host_num);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
938*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
939*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
940*4882a593Smuzhiyun ips_freescb(ha, scb);
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun /* Now fail all of the pending commands */
944*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Failing pending commands",
945*4882a593Smuzhiyun ips_name, ha->host_num);
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
948*4882a593Smuzhiyun scsi_cmd->result = DID_ERROR;
949*4882a593Smuzhiyun scsi_cmd->scsi_done(scsi_cmd);
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun ha->active = FALSE;
953*4882a593Smuzhiyun return (FAILED);
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
957*4882a593Smuzhiyun struct scsi_cmnd *scsi_cmd;
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun IPS_PRINTK(KERN_NOTICE, ha->pcidev,
960*4882a593Smuzhiyun "Controller reset failed - controller now offline.\n");
961*4882a593Smuzhiyun
962*4882a593Smuzhiyun /* Now fail all of the active commands */
963*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Failing active commands",
964*4882a593Smuzhiyun ips_name, ha->host_num);
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
967*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
968*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
969*4882a593Smuzhiyun ips_freescb(ha, scb);
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun /* Now fail all of the pending commands */
973*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Failing pending commands",
974*4882a593Smuzhiyun ips_name, ha->host_num);
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
977*4882a593Smuzhiyun scsi_cmd->result = DID_ERROR << 16;
978*4882a593Smuzhiyun scsi_cmd->scsi_done(scsi_cmd);
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun ha->active = FALSE;
982*4882a593Smuzhiyun return (FAILED);
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun /* FFDC */
986*4882a593Smuzhiyun if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
987*4882a593Smuzhiyun ha->last_ffdc = ktime_get_real_seconds();
988*4882a593Smuzhiyun ha->reset_count++;
989*4882a593Smuzhiyun ips_ffdc_reset(ha, IPS_INTR_IORL);
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun /* Now fail all of the active commands */
993*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
996*4882a593Smuzhiyun scb->scsi_cmd->result = DID_RESET << 16;
997*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
998*4882a593Smuzhiyun ips_freescb(ha, scb);
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun /* Reset DCDB active command bits */
1002*4882a593Smuzhiyun for (i = 1; i < ha->nbus; i++)
1003*4882a593Smuzhiyun ha->dcdb_active[i - 1] = 0;
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun /* Reset the number of active IOCTLs */
1006*4882a593Smuzhiyun ha->num_ioctl = 0;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun ips_next(ha, IPS_INTR_IORL);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun return (SUCCESS);
1011*4882a593Smuzhiyun #endif /* NO_IPS_RESET */
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun
ips_eh_reset(struct scsi_cmnd * SC)1015*4882a593Smuzhiyun static int ips_eh_reset(struct scsi_cmnd *SC)
1016*4882a593Smuzhiyun {
1017*4882a593Smuzhiyun int rc;
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun spin_lock_irq(SC->device->host->host_lock);
1020*4882a593Smuzhiyun rc = __ips_eh_reset(SC);
1021*4882a593Smuzhiyun spin_unlock_irq(SC->device->host->host_lock);
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun return rc;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun /****************************************************************************/
1027*4882a593Smuzhiyun /* */
1028*4882a593Smuzhiyun /* Routine Name: ips_queue */
1029*4882a593Smuzhiyun /* */
1030*4882a593Smuzhiyun /* Routine Description: */
1031*4882a593Smuzhiyun /* */
1032*4882a593Smuzhiyun /* Send a command to the controller */
1033*4882a593Smuzhiyun /* */
1034*4882a593Smuzhiyun /* NOTE: */
1035*4882a593Smuzhiyun /* Linux obtains io_request_lock before calling this function */
1036*4882a593Smuzhiyun /* */
1037*4882a593Smuzhiyun /****************************************************************************/
ips_queue_lck(struct scsi_cmnd * SC,void (* done)(struct scsi_cmnd *))1038*4882a593Smuzhiyun static int ips_queue_lck(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
1039*4882a593Smuzhiyun {
1040*4882a593Smuzhiyun ips_ha_t *ha;
1041*4882a593Smuzhiyun ips_passthru_t *pt;
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun METHOD_TRACE("ips_queue", 1);
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun ha = (ips_ha_t *) SC->device->host->hostdata;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun if (!ha)
1048*4882a593Smuzhiyun return (1);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun if (!ha->active)
1051*4882a593Smuzhiyun return (DID_ERROR);
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun if (ips_is_passthru(SC)) {
1054*4882a593Smuzhiyun if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
1055*4882a593Smuzhiyun SC->result = DID_BUS_BUSY << 16;
1056*4882a593Smuzhiyun done(SC);
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun return (0);
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
1061*4882a593Smuzhiyun SC->result = DID_BUS_BUSY << 16;
1062*4882a593Smuzhiyun done(SC);
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun return (0);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun SC->scsi_done = done;
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
1070*4882a593Smuzhiyun ips_name,
1071*4882a593Smuzhiyun ha->host_num,
1072*4882a593Smuzhiyun SC->cmnd[0],
1073*4882a593Smuzhiyun SC->device->channel, SC->device->id, SC->device->lun);
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun /* Check for command to initiator IDs */
1076*4882a593Smuzhiyun if ((scmd_channel(SC) > 0)
1077*4882a593Smuzhiyun && (scmd_id(SC) == ha->ha_id[scmd_channel(SC)])) {
1078*4882a593Smuzhiyun SC->result = DID_NO_CONNECT << 16;
1079*4882a593Smuzhiyun done(SC);
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun return (0);
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun if (ips_is_passthru(SC)) {
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun ips_copp_wait_item_t *scratch;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun /* A Reset IOCTL is only sent by the boot CD in extreme cases. */
1089*4882a593Smuzhiyun /* There can never be any system activity ( network or disk ), but check */
1090*4882a593Smuzhiyun /* anyway just as a good practice. */
1091*4882a593Smuzhiyun pt = (ips_passthru_t *) scsi_sglist(SC);
1092*4882a593Smuzhiyun if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
1093*4882a593Smuzhiyun (pt->CoppCP.cmd.reset.adapter_flag == 1)) {
1094*4882a593Smuzhiyun if (ha->scb_activelist.count != 0) {
1095*4882a593Smuzhiyun SC->result = DID_BUS_BUSY << 16;
1096*4882a593Smuzhiyun done(SC);
1097*4882a593Smuzhiyun return (0);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun ha->ioctl_reset = 1; /* This reset request is from an IOCTL */
1100*4882a593Smuzhiyun __ips_eh_reset(SC);
1101*4882a593Smuzhiyun SC->result = DID_OK << 16;
1102*4882a593Smuzhiyun SC->scsi_done(SC);
1103*4882a593Smuzhiyun return (0);
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun /* allocate space for the scribble */
1107*4882a593Smuzhiyun scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC);
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun if (!scratch) {
1110*4882a593Smuzhiyun SC->result = DID_ERROR << 16;
1111*4882a593Smuzhiyun done(SC);
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun return (0);
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun scratch->scsi_cmd = SC;
1117*4882a593Smuzhiyun scratch->next = NULL;
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun ips_putq_copp_tail(&ha->copp_waitlist, scratch);
1120*4882a593Smuzhiyun } else {
1121*4882a593Smuzhiyun ips_putq_wait_tail(&ha->scb_waitlist, SC);
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun ips_next(ha, IPS_INTR_IORL);
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun return (0);
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun
DEF_SCSI_QCMD(ips_queue)1129*4882a593Smuzhiyun static DEF_SCSI_QCMD(ips_queue)
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun /****************************************************************************/
1132*4882a593Smuzhiyun /* */
1133*4882a593Smuzhiyun /* Routine Name: ips_biosparam */
1134*4882a593Smuzhiyun /* */
1135*4882a593Smuzhiyun /* Routine Description: */
1136*4882a593Smuzhiyun /* */
1137*4882a593Smuzhiyun /* Set bios geometry for the controller */
1138*4882a593Smuzhiyun /* */
1139*4882a593Smuzhiyun /****************************************************************************/
1140*4882a593Smuzhiyun static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
1141*4882a593Smuzhiyun sector_t capacity, int geom[])
1142*4882a593Smuzhiyun {
1143*4882a593Smuzhiyun ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
1144*4882a593Smuzhiyun int heads;
1145*4882a593Smuzhiyun int sectors;
1146*4882a593Smuzhiyun int cylinders;
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun METHOD_TRACE("ips_biosparam", 1);
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun if (!ha)
1151*4882a593Smuzhiyun /* ?!?! host adater info invalid */
1152*4882a593Smuzhiyun return (0);
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun if (!ha->active)
1155*4882a593Smuzhiyun return (0);
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun if (!ips_read_adapter_status(ha, IPS_INTR_ON))
1158*4882a593Smuzhiyun /* ?!?! Enquiry command failed */
1159*4882a593Smuzhiyun return (0);
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
1162*4882a593Smuzhiyun heads = IPS_NORM_HEADS;
1163*4882a593Smuzhiyun sectors = IPS_NORM_SECTORS;
1164*4882a593Smuzhiyun } else {
1165*4882a593Smuzhiyun heads = IPS_COMP_HEADS;
1166*4882a593Smuzhiyun sectors = IPS_COMP_SECTORS;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun cylinders = (unsigned long) capacity / (heads * sectors);
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
1172*4882a593Smuzhiyun heads, sectors, cylinders);
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun geom[0] = heads;
1175*4882a593Smuzhiyun geom[1] = sectors;
1176*4882a593Smuzhiyun geom[2] = cylinders;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun return (0);
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun /****************************************************************************/
1182*4882a593Smuzhiyun /* */
1183*4882a593Smuzhiyun /* Routine Name: ips_slave_configure */
1184*4882a593Smuzhiyun /* */
1185*4882a593Smuzhiyun /* Routine Description: */
1186*4882a593Smuzhiyun /* */
1187*4882a593Smuzhiyun /* Set queue depths on devices once scan is complete */
1188*4882a593Smuzhiyun /* */
1189*4882a593Smuzhiyun /****************************************************************************/
1190*4882a593Smuzhiyun static int
ips_slave_configure(struct scsi_device * SDptr)1191*4882a593Smuzhiyun ips_slave_configure(struct scsi_device * SDptr)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun ips_ha_t *ha;
1194*4882a593Smuzhiyun int min;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun ha = IPS_HA(SDptr->host);
1197*4882a593Smuzhiyun if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) {
1198*4882a593Smuzhiyun min = ha->max_cmds / 2;
1199*4882a593Smuzhiyun if (ha->enq->ucLogDriveCount <= 2)
1200*4882a593Smuzhiyun min = ha->max_cmds - 1;
1201*4882a593Smuzhiyun scsi_change_queue_depth(SDptr, min);
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun
1204*4882a593Smuzhiyun SDptr->skip_ms_page_8 = 1;
1205*4882a593Smuzhiyun SDptr->skip_ms_page_3f = 1;
1206*4882a593Smuzhiyun return 0;
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun /****************************************************************************/
1210*4882a593Smuzhiyun /* */
1211*4882a593Smuzhiyun /* Routine Name: do_ipsintr */
1212*4882a593Smuzhiyun /* */
1213*4882a593Smuzhiyun /* Routine Description: */
1214*4882a593Smuzhiyun /* */
1215*4882a593Smuzhiyun /* Wrapper for the interrupt handler */
1216*4882a593Smuzhiyun /* */
1217*4882a593Smuzhiyun /****************************************************************************/
1218*4882a593Smuzhiyun static irqreturn_t
do_ipsintr(int irq,void * dev_id)1219*4882a593Smuzhiyun do_ipsintr(int irq, void *dev_id)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun ips_ha_t *ha;
1222*4882a593Smuzhiyun struct Scsi_Host *host;
1223*4882a593Smuzhiyun int irqstatus;
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun METHOD_TRACE("do_ipsintr", 2);
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun ha = (ips_ha_t *) dev_id;
1228*4882a593Smuzhiyun if (!ha)
1229*4882a593Smuzhiyun return IRQ_NONE;
1230*4882a593Smuzhiyun host = ips_sh[ha->host_num];
1231*4882a593Smuzhiyun /* interrupt during initialization */
1232*4882a593Smuzhiyun if (!host) {
1233*4882a593Smuzhiyun (*ha->func.intr) (ha);
1234*4882a593Smuzhiyun return IRQ_HANDLED;
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun spin_lock(host->host_lock);
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun if (!ha->active) {
1240*4882a593Smuzhiyun spin_unlock(host->host_lock);
1241*4882a593Smuzhiyun return IRQ_HANDLED;
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun irqstatus = (*ha->func.intr) (ha);
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun spin_unlock(host->host_lock);
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun /* start the next command */
1249*4882a593Smuzhiyun ips_next(ha, IPS_INTR_ON);
1250*4882a593Smuzhiyun return IRQ_RETVAL(irqstatus);
1251*4882a593Smuzhiyun }
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun /****************************************************************************/
1254*4882a593Smuzhiyun /* */
1255*4882a593Smuzhiyun /* Routine Name: ips_intr_copperhead */
1256*4882a593Smuzhiyun /* */
1257*4882a593Smuzhiyun /* Routine Description: */
1258*4882a593Smuzhiyun /* */
1259*4882a593Smuzhiyun /* Polling interrupt handler */
1260*4882a593Smuzhiyun /* */
1261*4882a593Smuzhiyun /* ASSUMES interrupts are disabled */
1262*4882a593Smuzhiyun /* */
1263*4882a593Smuzhiyun /****************************************************************************/
1264*4882a593Smuzhiyun int
ips_intr_copperhead(ips_ha_t * ha)1265*4882a593Smuzhiyun ips_intr_copperhead(ips_ha_t * ha)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun ips_stat_t *sp;
1268*4882a593Smuzhiyun ips_scb_t *scb;
1269*4882a593Smuzhiyun IPS_STATUS cstatus;
1270*4882a593Smuzhiyun int intrstatus;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun METHOD_TRACE("ips_intr", 2);
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun if (!ha)
1275*4882a593Smuzhiyun return 0;
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun if (!ha->active)
1278*4882a593Smuzhiyun return 0;
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun intrstatus = (*ha->func.isintr) (ha);
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun if (!intrstatus) {
1283*4882a593Smuzhiyun /*
1284*4882a593Smuzhiyun * Unexpected/Shared interrupt
1285*4882a593Smuzhiyun */
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun return 0;
1288*4882a593Smuzhiyun }
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun while (TRUE) {
1291*4882a593Smuzhiyun sp = &ha->sp;
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun intrstatus = (*ha->func.isintr) (ha);
1294*4882a593Smuzhiyun
1295*4882a593Smuzhiyun if (!intrstatus)
1296*4882a593Smuzhiyun break;
1297*4882a593Smuzhiyun else
1298*4882a593Smuzhiyun cstatus.value = (*ha->func.statupd) (ha);
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
1301*4882a593Smuzhiyun /* Spurious Interrupt ? */
1302*4882a593Smuzhiyun continue;
1303*4882a593Smuzhiyun }
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun ips_chkstatus(ha, &cstatus);
1306*4882a593Smuzhiyun scb = (ips_scb_t *) sp->scb_addr;
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun /*
1309*4882a593Smuzhiyun * use the callback function to finish things up
1310*4882a593Smuzhiyun * NOTE: interrupts are OFF for this
1311*4882a593Smuzhiyun */
1312*4882a593Smuzhiyun (*scb->callback) (ha, scb);
1313*4882a593Smuzhiyun } /* end while */
1314*4882a593Smuzhiyun return 1;
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun
1317*4882a593Smuzhiyun /****************************************************************************/
1318*4882a593Smuzhiyun /* */
1319*4882a593Smuzhiyun /* Routine Name: ips_intr_morpheus */
1320*4882a593Smuzhiyun /* */
1321*4882a593Smuzhiyun /* Routine Description: */
1322*4882a593Smuzhiyun /* */
1323*4882a593Smuzhiyun /* Polling interrupt handler */
1324*4882a593Smuzhiyun /* */
1325*4882a593Smuzhiyun /* ASSUMES interrupts are disabled */
1326*4882a593Smuzhiyun /* */
1327*4882a593Smuzhiyun /****************************************************************************/
1328*4882a593Smuzhiyun int
ips_intr_morpheus(ips_ha_t * ha)1329*4882a593Smuzhiyun ips_intr_morpheus(ips_ha_t * ha)
1330*4882a593Smuzhiyun {
1331*4882a593Smuzhiyun ips_stat_t *sp;
1332*4882a593Smuzhiyun ips_scb_t *scb;
1333*4882a593Smuzhiyun IPS_STATUS cstatus;
1334*4882a593Smuzhiyun int intrstatus;
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun METHOD_TRACE("ips_intr_morpheus", 2);
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun if (!ha)
1339*4882a593Smuzhiyun return 0;
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun if (!ha->active)
1342*4882a593Smuzhiyun return 0;
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun intrstatus = (*ha->func.isintr) (ha);
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun if (!intrstatus) {
1347*4882a593Smuzhiyun /*
1348*4882a593Smuzhiyun * Unexpected/Shared interrupt
1349*4882a593Smuzhiyun */
1350*4882a593Smuzhiyun
1351*4882a593Smuzhiyun return 0;
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun
1354*4882a593Smuzhiyun while (TRUE) {
1355*4882a593Smuzhiyun sp = &ha->sp;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun intrstatus = (*ha->func.isintr) (ha);
1358*4882a593Smuzhiyun
1359*4882a593Smuzhiyun if (!intrstatus)
1360*4882a593Smuzhiyun break;
1361*4882a593Smuzhiyun else
1362*4882a593Smuzhiyun cstatus.value = (*ha->func.statupd) (ha);
1363*4882a593Smuzhiyun
1364*4882a593Smuzhiyun if (cstatus.value == 0xffffffff)
1365*4882a593Smuzhiyun /* No more to process */
1366*4882a593Smuzhiyun break;
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
1369*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
1370*4882a593Smuzhiyun "Spurious interrupt; no ccb.\n");
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun continue;
1373*4882a593Smuzhiyun }
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun ips_chkstatus(ha, &cstatus);
1376*4882a593Smuzhiyun scb = (ips_scb_t *) sp->scb_addr;
1377*4882a593Smuzhiyun
1378*4882a593Smuzhiyun /*
1379*4882a593Smuzhiyun * use the callback function to finish things up
1380*4882a593Smuzhiyun * NOTE: interrupts are OFF for this
1381*4882a593Smuzhiyun */
1382*4882a593Smuzhiyun (*scb->callback) (ha, scb);
1383*4882a593Smuzhiyun } /* end while */
1384*4882a593Smuzhiyun return 1;
1385*4882a593Smuzhiyun }
1386*4882a593Smuzhiyun
1387*4882a593Smuzhiyun /****************************************************************************/
1388*4882a593Smuzhiyun /* */
1389*4882a593Smuzhiyun /* Routine Name: ips_info */
1390*4882a593Smuzhiyun /* */
1391*4882a593Smuzhiyun /* Routine Description: */
1392*4882a593Smuzhiyun /* */
1393*4882a593Smuzhiyun /* Return info about the driver */
1394*4882a593Smuzhiyun /* */
1395*4882a593Smuzhiyun /****************************************************************************/
1396*4882a593Smuzhiyun static const char *
ips_info(struct Scsi_Host * SH)1397*4882a593Smuzhiyun ips_info(struct Scsi_Host *SH)
1398*4882a593Smuzhiyun {
1399*4882a593Smuzhiyun static char buffer[256];
1400*4882a593Smuzhiyun char *bp;
1401*4882a593Smuzhiyun ips_ha_t *ha;
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun METHOD_TRACE("ips_info", 1);
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun ha = IPS_HA(SH);
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun if (!ha)
1408*4882a593Smuzhiyun return (NULL);
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun bp = &buffer[0];
1411*4882a593Smuzhiyun memset(bp, 0, sizeof (buffer));
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ",
1414*4882a593Smuzhiyun IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT);
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) {
1417*4882a593Smuzhiyun strcat(bp, " <");
1418*4882a593Smuzhiyun strcat(bp, ips_adapter_name[ha->ad_type - 1]);
1419*4882a593Smuzhiyun strcat(bp, ">");
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun return (bp);
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun static int
ips_write_info(struct Scsi_Host * host,char * buffer,int length)1426*4882a593Smuzhiyun ips_write_info(struct Scsi_Host *host, char *buffer, int length)
1427*4882a593Smuzhiyun {
1428*4882a593Smuzhiyun int i;
1429*4882a593Smuzhiyun ips_ha_t *ha = NULL;
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun /* Find our host structure */
1432*4882a593Smuzhiyun for (i = 0; i < ips_next_controller; i++) {
1433*4882a593Smuzhiyun if (ips_sh[i]) {
1434*4882a593Smuzhiyun if (ips_sh[i] == host) {
1435*4882a593Smuzhiyun ha = (ips_ha_t *) ips_sh[i]->hostdata;
1436*4882a593Smuzhiyun break;
1437*4882a593Smuzhiyun }
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun if (!ha)
1442*4882a593Smuzhiyun return (-EINVAL);
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun return 0;
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun static int
ips_show_info(struct seq_file * m,struct Scsi_Host * host)1448*4882a593Smuzhiyun ips_show_info(struct seq_file *m, struct Scsi_Host *host)
1449*4882a593Smuzhiyun {
1450*4882a593Smuzhiyun int i;
1451*4882a593Smuzhiyun ips_ha_t *ha = NULL;
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun /* Find our host structure */
1454*4882a593Smuzhiyun for (i = 0; i < ips_next_controller; i++) {
1455*4882a593Smuzhiyun if (ips_sh[i]) {
1456*4882a593Smuzhiyun if (ips_sh[i] == host) {
1457*4882a593Smuzhiyun ha = (ips_ha_t *) ips_sh[i]->hostdata;
1458*4882a593Smuzhiyun break;
1459*4882a593Smuzhiyun }
1460*4882a593Smuzhiyun }
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun if (!ha)
1464*4882a593Smuzhiyun return (-EINVAL);
1465*4882a593Smuzhiyun
1466*4882a593Smuzhiyun return ips_host_info(ha, m);
1467*4882a593Smuzhiyun }
1468*4882a593Smuzhiyun
1469*4882a593Smuzhiyun /*--------------------------------------------------------------------------*/
1470*4882a593Smuzhiyun /* Helper Functions */
1471*4882a593Smuzhiyun /*--------------------------------------------------------------------------*/
1472*4882a593Smuzhiyun
1473*4882a593Smuzhiyun /****************************************************************************/
1474*4882a593Smuzhiyun /* */
1475*4882a593Smuzhiyun /* Routine Name: ips_is_passthru */
1476*4882a593Smuzhiyun /* */
1477*4882a593Smuzhiyun /* Routine Description: */
1478*4882a593Smuzhiyun /* */
1479*4882a593Smuzhiyun /* Determine if the specified SCSI command is really a passthru command */
1480*4882a593Smuzhiyun /* */
1481*4882a593Smuzhiyun /****************************************************************************/
ips_is_passthru(struct scsi_cmnd * SC)1482*4882a593Smuzhiyun static int ips_is_passthru(struct scsi_cmnd *SC)
1483*4882a593Smuzhiyun {
1484*4882a593Smuzhiyun unsigned long flags;
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun METHOD_TRACE("ips_is_passthru", 1);
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun if (!SC)
1489*4882a593Smuzhiyun return (0);
1490*4882a593Smuzhiyun
1491*4882a593Smuzhiyun if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
1492*4882a593Smuzhiyun (SC->device->channel == 0) &&
1493*4882a593Smuzhiyun (SC->device->id == IPS_ADAPTER_ID) &&
1494*4882a593Smuzhiyun (SC->device->lun == 0) && scsi_sglist(SC)) {
1495*4882a593Smuzhiyun struct scatterlist *sg = scsi_sglist(SC);
1496*4882a593Smuzhiyun char *buffer;
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun /* kmap_atomic() ensures addressability of the user buffer.*/
1499*4882a593Smuzhiyun /* local_irq_save() protects the KM_IRQ0 address slot. */
1500*4882a593Smuzhiyun local_irq_save(flags);
1501*4882a593Smuzhiyun buffer = kmap_atomic(sg_page(sg)) + sg->offset;
1502*4882a593Smuzhiyun if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
1503*4882a593Smuzhiyun buffer[2] == 'P' && buffer[3] == 'P') {
1504*4882a593Smuzhiyun kunmap_atomic(buffer - sg->offset);
1505*4882a593Smuzhiyun local_irq_restore(flags);
1506*4882a593Smuzhiyun return 1;
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun kunmap_atomic(buffer - sg->offset);
1509*4882a593Smuzhiyun local_irq_restore(flags);
1510*4882a593Smuzhiyun }
1511*4882a593Smuzhiyun return 0;
1512*4882a593Smuzhiyun }
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun /****************************************************************************/
1515*4882a593Smuzhiyun /* */
1516*4882a593Smuzhiyun /* Routine Name: ips_alloc_passthru_buffer */
1517*4882a593Smuzhiyun /* */
1518*4882a593Smuzhiyun /* Routine Description: */
1519*4882a593Smuzhiyun /* allocate a buffer large enough for the ioctl data if the ioctl buffer */
1520*4882a593Smuzhiyun /* is too small or doesn't exist */
1521*4882a593Smuzhiyun /****************************************************************************/
1522*4882a593Smuzhiyun static int
ips_alloc_passthru_buffer(ips_ha_t * ha,int length)1523*4882a593Smuzhiyun ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
1524*4882a593Smuzhiyun {
1525*4882a593Smuzhiyun void *bigger_buf;
1526*4882a593Smuzhiyun dma_addr_t dma_busaddr;
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun if (ha->ioctl_data && length <= ha->ioctl_len)
1529*4882a593Smuzhiyun return 0;
1530*4882a593Smuzhiyun /* there is no buffer or it's not big enough, allocate a new one */
1531*4882a593Smuzhiyun bigger_buf = dma_alloc_coherent(&ha->pcidev->dev, length, &dma_busaddr,
1532*4882a593Smuzhiyun GFP_KERNEL);
1533*4882a593Smuzhiyun if (bigger_buf) {
1534*4882a593Smuzhiyun /* free the old memory */
1535*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len,
1536*4882a593Smuzhiyun ha->ioctl_data, ha->ioctl_busaddr);
1537*4882a593Smuzhiyun /* use the new memory */
1538*4882a593Smuzhiyun ha->ioctl_data = (char *) bigger_buf;
1539*4882a593Smuzhiyun ha->ioctl_len = length;
1540*4882a593Smuzhiyun ha->ioctl_busaddr = dma_busaddr;
1541*4882a593Smuzhiyun } else {
1542*4882a593Smuzhiyun return -1;
1543*4882a593Smuzhiyun }
1544*4882a593Smuzhiyun return 0;
1545*4882a593Smuzhiyun }
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun /****************************************************************************/
1548*4882a593Smuzhiyun /* */
1549*4882a593Smuzhiyun /* Routine Name: ips_make_passthru */
1550*4882a593Smuzhiyun /* */
1551*4882a593Smuzhiyun /* Routine Description: */
1552*4882a593Smuzhiyun /* */
1553*4882a593Smuzhiyun /* Make a passthru command out of the info in the Scsi block */
1554*4882a593Smuzhiyun /* */
1555*4882a593Smuzhiyun /****************************************************************************/
1556*4882a593Smuzhiyun static int
ips_make_passthru(ips_ha_t * ha,struct scsi_cmnd * SC,ips_scb_t * scb,int intr)1557*4882a593Smuzhiyun ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
1558*4882a593Smuzhiyun {
1559*4882a593Smuzhiyun ips_passthru_t *pt;
1560*4882a593Smuzhiyun int length = 0;
1561*4882a593Smuzhiyun int i, ret;
1562*4882a593Smuzhiyun struct scatterlist *sg = scsi_sglist(SC);
1563*4882a593Smuzhiyun
1564*4882a593Smuzhiyun METHOD_TRACE("ips_make_passthru", 1);
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i)
1567*4882a593Smuzhiyun length += sg->length;
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun if (length < sizeof (ips_passthru_t)) {
1570*4882a593Smuzhiyun /* wrong size */
1571*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
1572*4882a593Smuzhiyun ips_name, ha->host_num);
1573*4882a593Smuzhiyun return (IPS_FAILURE);
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun if (ips_alloc_passthru_buffer(ha, length)) {
1576*4882a593Smuzhiyun /* allocation failure! If ha->ioctl_data exists, use it to return
1577*4882a593Smuzhiyun some error codes. Return a failed command to the scsi layer. */
1578*4882a593Smuzhiyun if (ha->ioctl_data) {
1579*4882a593Smuzhiyun pt = (ips_passthru_t *) ha->ioctl_data;
1580*4882a593Smuzhiyun ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t));
1581*4882a593Smuzhiyun pt->BasicStatus = 0x0B;
1582*4882a593Smuzhiyun pt->ExtendedStatus = 0x00;
1583*4882a593Smuzhiyun ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t));
1584*4882a593Smuzhiyun }
1585*4882a593Smuzhiyun return IPS_FAILURE;
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun ha->ioctl_datasize = length;
1588*4882a593Smuzhiyun
1589*4882a593Smuzhiyun ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize);
1590*4882a593Smuzhiyun pt = (ips_passthru_t *) ha->ioctl_data;
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyun /*
1593*4882a593Smuzhiyun * Some notes about the passthru interface used
1594*4882a593Smuzhiyun *
1595*4882a593Smuzhiyun * IF the scsi op_code == 0x0d then we assume
1596*4882a593Smuzhiyun * that the data came along with/goes with the
1597*4882a593Smuzhiyun * packet we received from the sg driver. In this
1598*4882a593Smuzhiyun * case the CmdBSize field of the pt structure is
1599*4882a593Smuzhiyun * used for the size of the buffer.
1600*4882a593Smuzhiyun */
1601*4882a593Smuzhiyun
1602*4882a593Smuzhiyun switch (pt->CoppCmd) {
1603*4882a593Smuzhiyun case IPS_NUMCTRLS:
1604*4882a593Smuzhiyun memcpy(ha->ioctl_data + sizeof (ips_passthru_t),
1605*4882a593Smuzhiyun &ips_num_controllers, sizeof (int));
1606*4882a593Smuzhiyun ips_scmd_buf_write(SC, ha->ioctl_data,
1607*4882a593Smuzhiyun sizeof (ips_passthru_t) + sizeof (int));
1608*4882a593Smuzhiyun SC->result = DID_OK << 16;
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun return (IPS_SUCCESS_IMM);
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun case IPS_COPPUSRCMD:
1613*4882a593Smuzhiyun case IPS_COPPIOCCMD:
1614*4882a593Smuzhiyun if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
1615*4882a593Smuzhiyun if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) {
1616*4882a593Smuzhiyun /* wrong size */
1617*4882a593Smuzhiyun DEBUG_VAR(1,
1618*4882a593Smuzhiyun "(%s%d) Passthru structure wrong size",
1619*4882a593Smuzhiyun ips_name, ha->host_num);
1620*4882a593Smuzhiyun
1621*4882a593Smuzhiyun return (IPS_FAILURE);
1622*4882a593Smuzhiyun }
1623*4882a593Smuzhiyun
1624*4882a593Smuzhiyun if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
1625*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.op_code ==
1626*4882a593Smuzhiyun IPS_CMD_RW_BIOSFW) {
1627*4882a593Smuzhiyun ret = ips_flash_copperhead(ha, pt, scb);
1628*4882a593Smuzhiyun ips_scmd_buf_write(SC, ha->ioctl_data,
1629*4882a593Smuzhiyun sizeof (ips_passthru_t));
1630*4882a593Smuzhiyun return ret;
1631*4882a593Smuzhiyun }
1632*4882a593Smuzhiyun if (ips_usrcmd(ha, pt, scb))
1633*4882a593Smuzhiyun return (IPS_SUCCESS);
1634*4882a593Smuzhiyun else
1635*4882a593Smuzhiyun return (IPS_FAILURE);
1636*4882a593Smuzhiyun }
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun break;
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun } /* end switch */
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun return (IPS_FAILURE);
1643*4882a593Smuzhiyun }
1644*4882a593Smuzhiyun
1645*4882a593Smuzhiyun /****************************************************************************/
1646*4882a593Smuzhiyun /* Routine Name: ips_flash_copperhead */
1647*4882a593Smuzhiyun /* Routine Description: */
1648*4882a593Smuzhiyun /* Flash the BIOS/FW on a Copperhead style controller */
1649*4882a593Smuzhiyun /****************************************************************************/
1650*4882a593Smuzhiyun static int
ips_flash_copperhead(ips_ha_t * ha,ips_passthru_t * pt,ips_scb_t * scb)1651*4882a593Smuzhiyun ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1652*4882a593Smuzhiyun {
1653*4882a593Smuzhiyun int datasize;
1654*4882a593Smuzhiyun
1655*4882a593Smuzhiyun /* Trombone is the only copperhead that can do packet flash, but only
1656*4882a593Smuzhiyun * for firmware. No one said it had to make sense. */
1657*4882a593Smuzhiyun if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) {
1658*4882a593Smuzhiyun if (ips_usrcmd(ha, pt, scb))
1659*4882a593Smuzhiyun return IPS_SUCCESS;
1660*4882a593Smuzhiyun else
1661*4882a593Smuzhiyun return IPS_FAILURE;
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun pt->BasicStatus = 0x0B;
1664*4882a593Smuzhiyun pt->ExtendedStatus = 0;
1665*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
1666*4882a593Smuzhiyun /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */
1667*4882a593Smuzhiyun /* avoid allocating a huge buffer per adapter ( which can fail ). */
1668*4882a593Smuzhiyun if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
1669*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
1670*4882a593Smuzhiyun pt->BasicStatus = 0;
1671*4882a593Smuzhiyun return ips_flash_bios(ha, pt, scb);
1672*4882a593Smuzhiyun } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) {
1673*4882a593Smuzhiyun if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){
1674*4882a593Smuzhiyun ha->flash_data = ips_FlashData;
1675*4882a593Smuzhiyun ha->flash_busaddr = ips_flashbusaddr;
1676*4882a593Smuzhiyun ha->flash_len = PAGE_SIZE << 7;
1677*4882a593Smuzhiyun ha->flash_datasize = 0;
1678*4882a593Smuzhiyun } else if (!ha->flash_data) {
1679*4882a593Smuzhiyun datasize = pt->CoppCP.cmd.flashfw.total_packets *
1680*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.count;
1681*4882a593Smuzhiyun ha->flash_data = dma_alloc_coherent(&ha->pcidev->dev,
1682*4882a593Smuzhiyun datasize, &ha->flash_busaddr, GFP_KERNEL);
1683*4882a593Smuzhiyun if (!ha->flash_data){
1684*4882a593Smuzhiyun printk(KERN_WARNING "Unable to allocate a flash buffer\n");
1685*4882a593Smuzhiyun return IPS_FAILURE;
1686*4882a593Smuzhiyun }
1687*4882a593Smuzhiyun ha->flash_datasize = 0;
1688*4882a593Smuzhiyun ha->flash_len = datasize;
1689*4882a593Smuzhiyun } else
1690*4882a593Smuzhiyun return IPS_FAILURE;
1691*4882a593Smuzhiyun } else {
1692*4882a593Smuzhiyun if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
1693*4882a593Smuzhiyun ha->flash_len) {
1694*4882a593Smuzhiyun ips_free_flash_copperhead(ha);
1695*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
1696*4882a593Smuzhiyun "failed size sanity check\n");
1697*4882a593Smuzhiyun return IPS_FAILURE;
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun }
1700*4882a593Smuzhiyun if (!ha->flash_data)
1701*4882a593Smuzhiyun return IPS_FAILURE;
1702*4882a593Smuzhiyun pt->BasicStatus = 0;
1703*4882a593Smuzhiyun memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
1704*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.count);
1705*4882a593Smuzhiyun ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
1706*4882a593Smuzhiyun if (pt->CoppCP.cmd.flashfw.packet_num ==
1707*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.total_packets - 1) {
1708*4882a593Smuzhiyun if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
1709*4882a593Smuzhiyun return ips_flash_bios(ha, pt, scb);
1710*4882a593Smuzhiyun else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
1711*4882a593Smuzhiyun return ips_flash_firmware(ha, pt, scb);
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun return IPS_SUCCESS_IMM;
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun
1716*4882a593Smuzhiyun /****************************************************************************/
1717*4882a593Smuzhiyun /* Routine Name: ips_flash_bios */
1718*4882a593Smuzhiyun /* Routine Description: */
1719*4882a593Smuzhiyun /* flashes the bios of a copperhead adapter */
1720*4882a593Smuzhiyun /****************************************************************************/
1721*4882a593Smuzhiyun static int
ips_flash_bios(ips_ha_t * ha,ips_passthru_t * pt,ips_scb_t * scb)1722*4882a593Smuzhiyun ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1723*4882a593Smuzhiyun {
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
1726*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) {
1727*4882a593Smuzhiyun if ((!ha->func.programbios) || (!ha->func.erasebios) ||
1728*4882a593Smuzhiyun (!ha->func.verifybios))
1729*4882a593Smuzhiyun goto error;
1730*4882a593Smuzhiyun if ((*ha->func.erasebios) (ha)) {
1731*4882a593Smuzhiyun DEBUG_VAR(1,
1732*4882a593Smuzhiyun "(%s%d) flash bios failed - unable to erase flash",
1733*4882a593Smuzhiyun ips_name, ha->host_num);
1734*4882a593Smuzhiyun goto error;
1735*4882a593Smuzhiyun } else
1736*4882a593Smuzhiyun if ((*ha->func.programbios) (ha,
1737*4882a593Smuzhiyun ha->flash_data +
1738*4882a593Smuzhiyun IPS_BIOS_HEADER,
1739*4882a593Smuzhiyun ha->flash_datasize -
1740*4882a593Smuzhiyun IPS_BIOS_HEADER, 0)) {
1741*4882a593Smuzhiyun DEBUG_VAR(1,
1742*4882a593Smuzhiyun "(%s%d) flash bios failed - unable to flash",
1743*4882a593Smuzhiyun ips_name, ha->host_num);
1744*4882a593Smuzhiyun goto error;
1745*4882a593Smuzhiyun } else
1746*4882a593Smuzhiyun if ((*ha->func.verifybios) (ha,
1747*4882a593Smuzhiyun ha->flash_data +
1748*4882a593Smuzhiyun IPS_BIOS_HEADER,
1749*4882a593Smuzhiyun ha->flash_datasize -
1750*4882a593Smuzhiyun IPS_BIOS_HEADER, 0)) {
1751*4882a593Smuzhiyun DEBUG_VAR(1,
1752*4882a593Smuzhiyun "(%s%d) flash bios failed - unable to verify flash",
1753*4882a593Smuzhiyun ips_name, ha->host_num);
1754*4882a593Smuzhiyun goto error;
1755*4882a593Smuzhiyun }
1756*4882a593Smuzhiyun ips_free_flash_copperhead(ha);
1757*4882a593Smuzhiyun return IPS_SUCCESS_IMM;
1758*4882a593Smuzhiyun } else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
1759*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
1760*4882a593Smuzhiyun if (!ha->func.erasebios)
1761*4882a593Smuzhiyun goto error;
1762*4882a593Smuzhiyun if ((*ha->func.erasebios) (ha)) {
1763*4882a593Smuzhiyun DEBUG_VAR(1,
1764*4882a593Smuzhiyun "(%s%d) flash bios failed - unable to erase flash",
1765*4882a593Smuzhiyun ips_name, ha->host_num);
1766*4882a593Smuzhiyun goto error;
1767*4882a593Smuzhiyun }
1768*4882a593Smuzhiyun return IPS_SUCCESS_IMM;
1769*4882a593Smuzhiyun }
1770*4882a593Smuzhiyun error:
1771*4882a593Smuzhiyun pt->BasicStatus = 0x0B;
1772*4882a593Smuzhiyun pt->ExtendedStatus = 0x00;
1773*4882a593Smuzhiyun ips_free_flash_copperhead(ha);
1774*4882a593Smuzhiyun return IPS_FAILURE;
1775*4882a593Smuzhiyun }
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun /****************************************************************************/
1778*4882a593Smuzhiyun /* */
1779*4882a593Smuzhiyun /* Routine Name: ips_fill_scb_sg_single */
1780*4882a593Smuzhiyun /* */
1781*4882a593Smuzhiyun /* Routine Description: */
1782*4882a593Smuzhiyun /* Fill in a single scb sg_list element from an address */
1783*4882a593Smuzhiyun /* return a -1 if a breakup occurred */
1784*4882a593Smuzhiyun /****************************************************************************/
1785*4882a593Smuzhiyun static int
ips_fill_scb_sg_single(ips_ha_t * ha,dma_addr_t busaddr,ips_scb_t * scb,int indx,unsigned int e_len)1786*4882a593Smuzhiyun ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
1787*4882a593Smuzhiyun ips_scb_t * scb, int indx, unsigned int e_len)
1788*4882a593Smuzhiyun {
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun int ret_val = 0;
1791*4882a593Smuzhiyun
1792*4882a593Smuzhiyun if ((scb->data_len + e_len) > ha->max_xfer) {
1793*4882a593Smuzhiyun e_len = ha->max_xfer - scb->data_len;
1794*4882a593Smuzhiyun scb->breakup = indx;
1795*4882a593Smuzhiyun ++scb->sg_break;
1796*4882a593Smuzhiyun ret_val = -1;
1797*4882a593Smuzhiyun } else {
1798*4882a593Smuzhiyun scb->breakup = 0;
1799*4882a593Smuzhiyun scb->sg_break = 0;
1800*4882a593Smuzhiyun }
1801*4882a593Smuzhiyun if (IPS_USE_ENH_SGLIST(ha)) {
1802*4882a593Smuzhiyun scb->sg_list.enh_list[indx].address_lo =
1803*4882a593Smuzhiyun cpu_to_le32(lower_32_bits(busaddr));
1804*4882a593Smuzhiyun scb->sg_list.enh_list[indx].address_hi =
1805*4882a593Smuzhiyun cpu_to_le32(upper_32_bits(busaddr));
1806*4882a593Smuzhiyun scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len);
1807*4882a593Smuzhiyun } else {
1808*4882a593Smuzhiyun scb->sg_list.std_list[indx].address =
1809*4882a593Smuzhiyun cpu_to_le32(lower_32_bits(busaddr));
1810*4882a593Smuzhiyun scb->sg_list.std_list[indx].length = cpu_to_le32(e_len);
1811*4882a593Smuzhiyun }
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun ++scb->sg_len;
1814*4882a593Smuzhiyun scb->data_len += e_len;
1815*4882a593Smuzhiyun return ret_val;
1816*4882a593Smuzhiyun }
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun /****************************************************************************/
1819*4882a593Smuzhiyun /* Routine Name: ips_flash_firmware */
1820*4882a593Smuzhiyun /* Routine Description: */
1821*4882a593Smuzhiyun /* flashes the firmware of a copperhead adapter */
1822*4882a593Smuzhiyun /****************************************************************************/
1823*4882a593Smuzhiyun static int
ips_flash_firmware(ips_ha_t * ha,ips_passthru_t * pt,ips_scb_t * scb)1824*4882a593Smuzhiyun ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1825*4882a593Smuzhiyun {
1826*4882a593Smuzhiyun IPS_SG_LIST sg_list;
1827*4882a593Smuzhiyun uint32_t cmd_busaddr;
1828*4882a593Smuzhiyun
1829*4882a593Smuzhiyun if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
1830*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) {
1831*4882a593Smuzhiyun memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND));
1832*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
1833*4882a593Smuzhiyun pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
1834*4882a593Smuzhiyun } else {
1835*4882a593Smuzhiyun pt->BasicStatus = 0x0B;
1836*4882a593Smuzhiyun pt->ExtendedStatus = 0x00;
1837*4882a593Smuzhiyun ips_free_flash_copperhead(ha);
1838*4882a593Smuzhiyun return IPS_FAILURE;
1839*4882a593Smuzhiyun }
1840*4882a593Smuzhiyun /* Save the S/G list pointer so it doesn't get clobbered */
1841*4882a593Smuzhiyun sg_list.list = scb->sg_list.list;
1842*4882a593Smuzhiyun cmd_busaddr = scb->scb_busaddr;
1843*4882a593Smuzhiyun /* copy in the CP */
1844*4882a593Smuzhiyun memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
1845*4882a593Smuzhiyun /* FIX stuff that might be wrong */
1846*4882a593Smuzhiyun scb->sg_list.list = sg_list.list;
1847*4882a593Smuzhiyun scb->scb_busaddr = cmd_busaddr;
1848*4882a593Smuzhiyun scb->bus = scb->scsi_cmd->device->channel;
1849*4882a593Smuzhiyun scb->target_id = scb->scsi_cmd->device->id;
1850*4882a593Smuzhiyun scb->lun = scb->scsi_cmd->device->lun;
1851*4882a593Smuzhiyun scb->sg_len = 0;
1852*4882a593Smuzhiyun scb->data_len = 0;
1853*4882a593Smuzhiyun scb->flags = 0;
1854*4882a593Smuzhiyun scb->op_code = 0;
1855*4882a593Smuzhiyun scb->callback = ipsintr_done;
1856*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun scb->data_len = ha->flash_datasize;
1859*4882a593Smuzhiyun scb->data_busaddr =
1860*4882a593Smuzhiyun dma_map_single(&ha->pcidev->dev, ha->flash_data, scb->data_len,
1861*4882a593Smuzhiyun IPS_DMA_DIR(scb));
1862*4882a593Smuzhiyun scb->flags |= IPS_SCB_MAP_SINGLE;
1863*4882a593Smuzhiyun scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
1864*4882a593Smuzhiyun scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr);
1865*4882a593Smuzhiyun if (pt->TimeOut)
1866*4882a593Smuzhiyun scb->timeout = pt->TimeOut;
1867*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
1868*4882a593Smuzhiyun return IPS_SUCCESS;
1869*4882a593Smuzhiyun }
1870*4882a593Smuzhiyun
1871*4882a593Smuzhiyun /****************************************************************************/
1872*4882a593Smuzhiyun /* Routine Name: ips_free_flash_copperhead */
1873*4882a593Smuzhiyun /* Routine Description: */
1874*4882a593Smuzhiyun /* release the memory resources used to hold the flash image */
1875*4882a593Smuzhiyun /****************************************************************************/
1876*4882a593Smuzhiyun static void
ips_free_flash_copperhead(ips_ha_t * ha)1877*4882a593Smuzhiyun ips_free_flash_copperhead(ips_ha_t * ha)
1878*4882a593Smuzhiyun {
1879*4882a593Smuzhiyun if (ha->flash_data == ips_FlashData)
1880*4882a593Smuzhiyun test_and_clear_bit(0, &ips_FlashDataInUse);
1881*4882a593Smuzhiyun else if (ha->flash_data)
1882*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev, ha->flash_len,
1883*4882a593Smuzhiyun ha->flash_data, ha->flash_busaddr);
1884*4882a593Smuzhiyun ha->flash_data = NULL;
1885*4882a593Smuzhiyun }
1886*4882a593Smuzhiyun
1887*4882a593Smuzhiyun /****************************************************************************/
1888*4882a593Smuzhiyun /* */
1889*4882a593Smuzhiyun /* Routine Name: ips_usrcmd */
1890*4882a593Smuzhiyun /* */
1891*4882a593Smuzhiyun /* Routine Description: */
1892*4882a593Smuzhiyun /* */
1893*4882a593Smuzhiyun /* Process a user command and make it ready to send */
1894*4882a593Smuzhiyun /* */
1895*4882a593Smuzhiyun /****************************************************************************/
1896*4882a593Smuzhiyun static int
ips_usrcmd(ips_ha_t * ha,ips_passthru_t * pt,ips_scb_t * scb)1897*4882a593Smuzhiyun ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun IPS_SG_LIST sg_list;
1900*4882a593Smuzhiyun uint32_t cmd_busaddr;
1901*4882a593Smuzhiyun
1902*4882a593Smuzhiyun METHOD_TRACE("ips_usrcmd", 1);
1903*4882a593Smuzhiyun
1904*4882a593Smuzhiyun if ((!scb) || (!pt) || (!ha))
1905*4882a593Smuzhiyun return (0);
1906*4882a593Smuzhiyun
1907*4882a593Smuzhiyun /* Save the S/G list pointer so it doesn't get clobbered */
1908*4882a593Smuzhiyun sg_list.list = scb->sg_list.list;
1909*4882a593Smuzhiyun cmd_busaddr = scb->scb_busaddr;
1910*4882a593Smuzhiyun /* copy in the CP */
1911*4882a593Smuzhiyun memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
1912*4882a593Smuzhiyun memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE));
1913*4882a593Smuzhiyun
1914*4882a593Smuzhiyun /* FIX stuff that might be wrong */
1915*4882a593Smuzhiyun scb->sg_list.list = sg_list.list;
1916*4882a593Smuzhiyun scb->scb_busaddr = cmd_busaddr;
1917*4882a593Smuzhiyun scb->bus = scb->scsi_cmd->device->channel;
1918*4882a593Smuzhiyun scb->target_id = scb->scsi_cmd->device->id;
1919*4882a593Smuzhiyun scb->lun = scb->scsi_cmd->device->lun;
1920*4882a593Smuzhiyun scb->sg_len = 0;
1921*4882a593Smuzhiyun scb->data_len = 0;
1922*4882a593Smuzhiyun scb->flags = 0;
1923*4882a593Smuzhiyun scb->op_code = 0;
1924*4882a593Smuzhiyun scb->callback = ipsintr_done;
1925*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
1926*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
1927*4882a593Smuzhiyun
1928*4882a593Smuzhiyun /* we don't support DCDB/READ/WRITE Scatter Gather */
1929*4882a593Smuzhiyun if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
1930*4882a593Smuzhiyun (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
1931*4882a593Smuzhiyun (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
1932*4882a593Smuzhiyun return (0);
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun if (pt->CmdBSize) {
1935*4882a593Smuzhiyun scb->data_len = pt->CmdBSize;
1936*4882a593Smuzhiyun scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t);
1937*4882a593Smuzhiyun } else {
1938*4882a593Smuzhiyun scb->data_busaddr = 0L;
1939*4882a593Smuzhiyun }
1940*4882a593Smuzhiyun
1941*4882a593Smuzhiyun if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
1942*4882a593Smuzhiyun scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
1943*4882a593Smuzhiyun (unsigned long) &scb->
1944*4882a593Smuzhiyun dcdb -
1945*4882a593Smuzhiyun (unsigned long) scb);
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun if (pt->CmdBSize) {
1948*4882a593Smuzhiyun if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
1949*4882a593Smuzhiyun scb->dcdb.buffer_pointer =
1950*4882a593Smuzhiyun cpu_to_le32(scb->data_busaddr);
1951*4882a593Smuzhiyun else
1952*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr =
1953*4882a593Smuzhiyun cpu_to_le32(scb->data_busaddr);
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun
1956*4882a593Smuzhiyun /* set timeouts */
1957*4882a593Smuzhiyun if (pt->TimeOut) {
1958*4882a593Smuzhiyun scb->timeout = pt->TimeOut;
1959*4882a593Smuzhiyun
1960*4882a593Smuzhiyun if (pt->TimeOut <= 10)
1961*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
1962*4882a593Smuzhiyun else if (pt->TimeOut <= 60)
1963*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
1964*4882a593Smuzhiyun else
1965*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
1966*4882a593Smuzhiyun }
1967*4882a593Smuzhiyun
1968*4882a593Smuzhiyun /* assume success */
1969*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun /* success */
1972*4882a593Smuzhiyun return (1);
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun
1975*4882a593Smuzhiyun /****************************************************************************/
1976*4882a593Smuzhiyun /* */
1977*4882a593Smuzhiyun /* Routine Name: ips_cleanup_passthru */
1978*4882a593Smuzhiyun /* */
1979*4882a593Smuzhiyun /* Routine Description: */
1980*4882a593Smuzhiyun /* */
1981*4882a593Smuzhiyun /* Cleanup after a passthru command */
1982*4882a593Smuzhiyun /* */
1983*4882a593Smuzhiyun /****************************************************************************/
1984*4882a593Smuzhiyun static void
ips_cleanup_passthru(ips_ha_t * ha,ips_scb_t * scb)1985*4882a593Smuzhiyun ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
1986*4882a593Smuzhiyun {
1987*4882a593Smuzhiyun ips_passthru_t *pt;
1988*4882a593Smuzhiyun
1989*4882a593Smuzhiyun METHOD_TRACE("ips_cleanup_passthru", 1);
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun if ((!scb) || (!scb->scsi_cmd) || (!scsi_sglist(scb->scsi_cmd))) {
1992*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
1993*4882a593Smuzhiyun ips_name, ha->host_num);
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun return;
1996*4882a593Smuzhiyun }
1997*4882a593Smuzhiyun pt = (ips_passthru_t *) ha->ioctl_data;
1998*4882a593Smuzhiyun
1999*4882a593Smuzhiyun /* Copy data back to the user */
2000*4882a593Smuzhiyun if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) /* Copy DCDB Back to Caller's Area */
2001*4882a593Smuzhiyun memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE));
2002*4882a593Smuzhiyun
2003*4882a593Smuzhiyun pt->BasicStatus = scb->basic_status;
2004*4882a593Smuzhiyun pt->ExtendedStatus = scb->extended_status;
2005*4882a593Smuzhiyun pt->AdapterType = ha->ad_type;
2006*4882a593Smuzhiyun
2007*4882a593Smuzhiyun if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
2008*4882a593Smuzhiyun (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
2009*4882a593Smuzhiyun scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
2010*4882a593Smuzhiyun ips_free_flash_copperhead(ha);
2011*4882a593Smuzhiyun
2012*4882a593Smuzhiyun ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize);
2013*4882a593Smuzhiyun }
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun /****************************************************************************/
2016*4882a593Smuzhiyun /* */
2017*4882a593Smuzhiyun /* Routine Name: ips_host_info */
2018*4882a593Smuzhiyun /* */
2019*4882a593Smuzhiyun /* Routine Description: */
2020*4882a593Smuzhiyun /* */
2021*4882a593Smuzhiyun /* The passthru interface for the driver */
2022*4882a593Smuzhiyun /* */
2023*4882a593Smuzhiyun /****************************************************************************/
2024*4882a593Smuzhiyun static int
ips_host_info(ips_ha_t * ha,struct seq_file * m)2025*4882a593Smuzhiyun ips_host_info(ips_ha_t *ha, struct seq_file *m)
2026*4882a593Smuzhiyun {
2027*4882a593Smuzhiyun METHOD_TRACE("ips_host_info", 1);
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun seq_puts(m, "\nIBM ServeRAID General Information:\n\n");
2030*4882a593Smuzhiyun
2031*4882a593Smuzhiyun if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
2032*4882a593Smuzhiyun (le16_to_cpu(ha->nvram->adapter_type) != 0))
2033*4882a593Smuzhiyun seq_printf(m, "\tController Type : %s\n",
2034*4882a593Smuzhiyun ips_adapter_name[ha->ad_type - 1]);
2035*4882a593Smuzhiyun else
2036*4882a593Smuzhiyun seq_puts(m, "\tController Type : Unknown\n");
2037*4882a593Smuzhiyun
2038*4882a593Smuzhiyun if (ha->io_addr)
2039*4882a593Smuzhiyun seq_printf(m,
2040*4882a593Smuzhiyun "\tIO region : 0x%x (%d bytes)\n",
2041*4882a593Smuzhiyun ha->io_addr, ha->io_len);
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun if (ha->mem_addr) {
2044*4882a593Smuzhiyun seq_printf(m,
2045*4882a593Smuzhiyun "\tMemory region : 0x%x (%d bytes)\n",
2046*4882a593Smuzhiyun ha->mem_addr, ha->mem_len);
2047*4882a593Smuzhiyun seq_printf(m,
2048*4882a593Smuzhiyun "\tShared memory address : 0x%lx\n",
2049*4882a593Smuzhiyun (unsigned long)ha->mem_ptr);
2050*4882a593Smuzhiyun }
2051*4882a593Smuzhiyun
2052*4882a593Smuzhiyun seq_printf(m, "\tIRQ number : %d\n", ha->pcidev->irq);
2053*4882a593Smuzhiyun
2054*4882a593Smuzhiyun /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
2055*4882a593Smuzhiyun /* That keeps everything happy for "text" operations on the proc file. */
2056*4882a593Smuzhiyun
2057*4882a593Smuzhiyun if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
2058*4882a593Smuzhiyun if (ha->nvram->bios_low[3] == 0) {
2059*4882a593Smuzhiyun seq_printf(m,
2060*4882a593Smuzhiyun "\tBIOS Version : %c%c%c%c%c%c%c\n",
2061*4882a593Smuzhiyun ha->nvram->bios_high[0], ha->nvram->bios_high[1],
2062*4882a593Smuzhiyun ha->nvram->bios_high[2], ha->nvram->bios_high[3],
2063*4882a593Smuzhiyun ha->nvram->bios_low[0], ha->nvram->bios_low[1],
2064*4882a593Smuzhiyun ha->nvram->bios_low[2]);
2065*4882a593Smuzhiyun
2066*4882a593Smuzhiyun } else {
2067*4882a593Smuzhiyun seq_printf(m,
2068*4882a593Smuzhiyun "\tBIOS Version : %c%c%c%c%c%c%c%c\n",
2069*4882a593Smuzhiyun ha->nvram->bios_high[0], ha->nvram->bios_high[1],
2070*4882a593Smuzhiyun ha->nvram->bios_high[2], ha->nvram->bios_high[3],
2071*4882a593Smuzhiyun ha->nvram->bios_low[0], ha->nvram->bios_low[1],
2072*4882a593Smuzhiyun ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
2073*4882a593Smuzhiyun }
2074*4882a593Smuzhiyun
2075*4882a593Smuzhiyun }
2076*4882a593Smuzhiyun
2077*4882a593Smuzhiyun if (ha->enq->CodeBlkVersion[7] == 0) {
2078*4882a593Smuzhiyun seq_printf(m,
2079*4882a593Smuzhiyun "\tFirmware Version : %c%c%c%c%c%c%c\n",
2080*4882a593Smuzhiyun ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
2081*4882a593Smuzhiyun ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
2082*4882a593Smuzhiyun ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
2083*4882a593Smuzhiyun ha->enq->CodeBlkVersion[6]);
2084*4882a593Smuzhiyun } else {
2085*4882a593Smuzhiyun seq_printf(m,
2086*4882a593Smuzhiyun "\tFirmware Version : %c%c%c%c%c%c%c%c\n",
2087*4882a593Smuzhiyun ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
2088*4882a593Smuzhiyun ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
2089*4882a593Smuzhiyun ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
2090*4882a593Smuzhiyun ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
2091*4882a593Smuzhiyun }
2092*4882a593Smuzhiyun
2093*4882a593Smuzhiyun if (ha->enq->BootBlkVersion[7] == 0) {
2094*4882a593Smuzhiyun seq_printf(m,
2095*4882a593Smuzhiyun "\tBoot Block Version : %c%c%c%c%c%c%c\n",
2096*4882a593Smuzhiyun ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
2097*4882a593Smuzhiyun ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
2098*4882a593Smuzhiyun ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
2099*4882a593Smuzhiyun ha->enq->BootBlkVersion[6]);
2100*4882a593Smuzhiyun } else {
2101*4882a593Smuzhiyun seq_printf(m,
2102*4882a593Smuzhiyun "\tBoot Block Version : %c%c%c%c%c%c%c%c\n",
2103*4882a593Smuzhiyun ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
2104*4882a593Smuzhiyun ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
2105*4882a593Smuzhiyun ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
2106*4882a593Smuzhiyun ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
2107*4882a593Smuzhiyun }
2108*4882a593Smuzhiyun
2109*4882a593Smuzhiyun seq_printf(m, "\tDriver Version : %s%s\n",
2110*4882a593Smuzhiyun IPS_VERSION_HIGH, IPS_VERSION_LOW);
2111*4882a593Smuzhiyun
2112*4882a593Smuzhiyun seq_printf(m, "\tDriver Build : %d\n",
2113*4882a593Smuzhiyun IPS_BUILD_IDENT);
2114*4882a593Smuzhiyun
2115*4882a593Smuzhiyun seq_printf(m, "\tMax Physical Devices : %d\n",
2116*4882a593Smuzhiyun ha->enq->ucMaxPhysicalDevices);
2117*4882a593Smuzhiyun seq_printf(m, "\tMax Active Commands : %d\n",
2118*4882a593Smuzhiyun ha->max_cmds);
2119*4882a593Smuzhiyun seq_printf(m, "\tCurrent Queued Commands : %d\n",
2120*4882a593Smuzhiyun ha->scb_waitlist.count);
2121*4882a593Smuzhiyun seq_printf(m, "\tCurrent Active Commands : %d\n",
2122*4882a593Smuzhiyun ha->scb_activelist.count - ha->num_ioctl);
2123*4882a593Smuzhiyun seq_printf(m, "\tCurrent Queued PT Commands : %d\n",
2124*4882a593Smuzhiyun ha->copp_waitlist.count);
2125*4882a593Smuzhiyun seq_printf(m, "\tCurrent Active PT Commands : %d\n",
2126*4882a593Smuzhiyun ha->num_ioctl);
2127*4882a593Smuzhiyun
2128*4882a593Smuzhiyun seq_putc(m, '\n');
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyun return 0;
2131*4882a593Smuzhiyun }
2132*4882a593Smuzhiyun
2133*4882a593Smuzhiyun /****************************************************************************/
2134*4882a593Smuzhiyun /* */
2135*4882a593Smuzhiyun /* Routine Name: ips_identify_controller */
2136*4882a593Smuzhiyun /* */
2137*4882a593Smuzhiyun /* Routine Description: */
2138*4882a593Smuzhiyun /* */
2139*4882a593Smuzhiyun /* Identify this controller */
2140*4882a593Smuzhiyun /* */
2141*4882a593Smuzhiyun /****************************************************************************/
2142*4882a593Smuzhiyun static void
ips_identify_controller(ips_ha_t * ha)2143*4882a593Smuzhiyun ips_identify_controller(ips_ha_t * ha)
2144*4882a593Smuzhiyun {
2145*4882a593Smuzhiyun METHOD_TRACE("ips_identify_controller", 1);
2146*4882a593Smuzhiyun
2147*4882a593Smuzhiyun switch (ha->pcidev->device) {
2148*4882a593Smuzhiyun case IPS_DEVICEID_COPPERHEAD:
2149*4882a593Smuzhiyun if (ha->pcidev->revision <= IPS_REVID_SERVERAID) {
2150*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID;
2151*4882a593Smuzhiyun } else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) {
2152*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID2;
2153*4882a593Smuzhiyun } else if (ha->pcidev->revision == IPS_REVID_NAVAJO) {
2154*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_NAVAJO;
2155*4882a593Smuzhiyun } else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2)
2156*4882a593Smuzhiyun && (ha->slot_num == 0)) {
2157*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_KIOWA;
2158*4882a593Smuzhiyun } else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) &&
2159*4882a593Smuzhiyun (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) {
2160*4882a593Smuzhiyun if (ha->enq->ucMaxPhysicalDevices == 15)
2161*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID3L;
2162*4882a593Smuzhiyun else
2163*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID3;
2164*4882a593Smuzhiyun } else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) &&
2165*4882a593Smuzhiyun (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) {
2166*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID4H;
2167*4882a593Smuzhiyun }
2168*4882a593Smuzhiyun break;
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun case IPS_DEVICEID_MORPHEUS:
2171*4882a593Smuzhiyun switch (ha->pcidev->subsystem_device) {
2172*4882a593Smuzhiyun case IPS_SUBDEVICEID_4L:
2173*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID4L;
2174*4882a593Smuzhiyun break;
2175*4882a593Smuzhiyun
2176*4882a593Smuzhiyun case IPS_SUBDEVICEID_4M:
2177*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID4M;
2178*4882a593Smuzhiyun break;
2179*4882a593Smuzhiyun
2180*4882a593Smuzhiyun case IPS_SUBDEVICEID_4MX:
2181*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
2182*4882a593Smuzhiyun break;
2183*4882a593Smuzhiyun
2184*4882a593Smuzhiyun case IPS_SUBDEVICEID_4LX:
2185*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
2186*4882a593Smuzhiyun break;
2187*4882a593Smuzhiyun
2188*4882a593Smuzhiyun case IPS_SUBDEVICEID_5I2:
2189*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
2190*4882a593Smuzhiyun break;
2191*4882a593Smuzhiyun
2192*4882a593Smuzhiyun case IPS_SUBDEVICEID_5I1:
2193*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
2194*4882a593Smuzhiyun break;
2195*4882a593Smuzhiyun }
2196*4882a593Smuzhiyun
2197*4882a593Smuzhiyun break;
2198*4882a593Smuzhiyun
2199*4882a593Smuzhiyun case IPS_DEVICEID_MARCO:
2200*4882a593Smuzhiyun switch (ha->pcidev->subsystem_device) {
2201*4882a593Smuzhiyun case IPS_SUBDEVICEID_6M:
2202*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID6M;
2203*4882a593Smuzhiyun break;
2204*4882a593Smuzhiyun case IPS_SUBDEVICEID_6I:
2205*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID6I;
2206*4882a593Smuzhiyun break;
2207*4882a593Smuzhiyun case IPS_SUBDEVICEID_7k:
2208*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID7k;
2209*4882a593Smuzhiyun break;
2210*4882a593Smuzhiyun case IPS_SUBDEVICEID_7M:
2211*4882a593Smuzhiyun ha->ad_type = IPS_ADTYPE_SERVERAID7M;
2212*4882a593Smuzhiyun break;
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun break;
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun }
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun /****************************************************************************/
2219*4882a593Smuzhiyun /* */
2220*4882a593Smuzhiyun /* Routine Name: ips_get_bios_version */
2221*4882a593Smuzhiyun /* */
2222*4882a593Smuzhiyun /* Routine Description: */
2223*4882a593Smuzhiyun /* */
2224*4882a593Smuzhiyun /* Get the BIOS revision number */
2225*4882a593Smuzhiyun /* */
2226*4882a593Smuzhiyun /****************************************************************************/
2227*4882a593Smuzhiyun static void
ips_get_bios_version(ips_ha_t * ha,int intr)2228*4882a593Smuzhiyun ips_get_bios_version(ips_ha_t * ha, int intr)
2229*4882a593Smuzhiyun {
2230*4882a593Smuzhiyun ips_scb_t *scb;
2231*4882a593Smuzhiyun int ret;
2232*4882a593Smuzhiyun uint8_t major;
2233*4882a593Smuzhiyun uint8_t minor;
2234*4882a593Smuzhiyun uint8_t subminor;
2235*4882a593Smuzhiyun uint8_t *buffer;
2236*4882a593Smuzhiyun
2237*4882a593Smuzhiyun METHOD_TRACE("ips_get_bios_version", 1);
2238*4882a593Smuzhiyun
2239*4882a593Smuzhiyun major = 0;
2240*4882a593Smuzhiyun minor = 0;
2241*4882a593Smuzhiyun
2242*4882a593Smuzhiyun memcpy(ha->bios_version, " ?", 8);
2243*4882a593Smuzhiyun
2244*4882a593Smuzhiyun if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) {
2245*4882a593Smuzhiyun if (IPS_USE_MEMIO(ha)) {
2246*4882a593Smuzhiyun /* Memory Mapped I/O */
2247*4882a593Smuzhiyun
2248*4882a593Smuzhiyun /* test 1st byte */
2249*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
2250*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2251*4882a593Smuzhiyun udelay(25); /* 25 us */
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
2254*4882a593Smuzhiyun return;
2255*4882a593Smuzhiyun
2256*4882a593Smuzhiyun writel(1, ha->mem_ptr + IPS_REG_FLAP);
2257*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2258*4882a593Smuzhiyun udelay(25); /* 25 us */
2259*4882a593Smuzhiyun
2260*4882a593Smuzhiyun if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
2261*4882a593Smuzhiyun return;
2262*4882a593Smuzhiyun
2263*4882a593Smuzhiyun /* Get Major version */
2264*4882a593Smuzhiyun writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
2265*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2266*4882a593Smuzhiyun udelay(25); /* 25 us */
2267*4882a593Smuzhiyun
2268*4882a593Smuzhiyun major = readb(ha->mem_ptr + IPS_REG_FLDP);
2269*4882a593Smuzhiyun
2270*4882a593Smuzhiyun /* Get Minor version */
2271*4882a593Smuzhiyun writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
2272*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2273*4882a593Smuzhiyun udelay(25); /* 25 us */
2274*4882a593Smuzhiyun minor = readb(ha->mem_ptr + IPS_REG_FLDP);
2275*4882a593Smuzhiyun
2276*4882a593Smuzhiyun /* Get SubMinor version */
2277*4882a593Smuzhiyun writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
2278*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2279*4882a593Smuzhiyun udelay(25); /* 25 us */
2280*4882a593Smuzhiyun subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
2281*4882a593Smuzhiyun
2282*4882a593Smuzhiyun } else {
2283*4882a593Smuzhiyun /* Programmed I/O */
2284*4882a593Smuzhiyun
2285*4882a593Smuzhiyun /* test 1st byte */
2286*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
2287*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2288*4882a593Smuzhiyun udelay(25); /* 25 us */
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
2291*4882a593Smuzhiyun return;
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun outl(1, ha->io_addr + IPS_REG_FLAP);
2294*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2295*4882a593Smuzhiyun udelay(25); /* 25 us */
2296*4882a593Smuzhiyun
2297*4882a593Smuzhiyun if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
2298*4882a593Smuzhiyun return;
2299*4882a593Smuzhiyun
2300*4882a593Smuzhiyun /* Get Major version */
2301*4882a593Smuzhiyun outl(0x1FF, ha->io_addr + IPS_REG_FLAP);
2302*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2303*4882a593Smuzhiyun udelay(25); /* 25 us */
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun major = inb(ha->io_addr + IPS_REG_FLDP);
2306*4882a593Smuzhiyun
2307*4882a593Smuzhiyun /* Get Minor version */
2308*4882a593Smuzhiyun outl(0x1FE, ha->io_addr + IPS_REG_FLAP);
2309*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2310*4882a593Smuzhiyun udelay(25); /* 25 us */
2311*4882a593Smuzhiyun
2312*4882a593Smuzhiyun minor = inb(ha->io_addr + IPS_REG_FLDP);
2313*4882a593Smuzhiyun
2314*4882a593Smuzhiyun /* Get SubMinor version */
2315*4882a593Smuzhiyun outl(0x1FD, ha->io_addr + IPS_REG_FLAP);
2316*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
2317*4882a593Smuzhiyun udelay(25); /* 25 us */
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun subminor = inb(ha->io_addr + IPS_REG_FLDP);
2320*4882a593Smuzhiyun
2321*4882a593Smuzhiyun }
2322*4882a593Smuzhiyun } else {
2323*4882a593Smuzhiyun /* Morpheus Family - Send Command to the card */
2324*4882a593Smuzhiyun
2325*4882a593Smuzhiyun buffer = ha->ioctl_data;
2326*4882a593Smuzhiyun
2327*4882a593Smuzhiyun memset(buffer, 0, 0x1000);
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
2330*4882a593Smuzhiyun
2331*4882a593Smuzhiyun ips_init_scb(ha, scb);
2332*4882a593Smuzhiyun
2333*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
2334*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_RW_BIOSFW;
2335*4882a593Smuzhiyun
2336*4882a593Smuzhiyun scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
2337*4882a593Smuzhiyun scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
2338*4882a593Smuzhiyun scb->cmd.flashfw.type = 1;
2339*4882a593Smuzhiyun scb->cmd.flashfw.direction = 0;
2340*4882a593Smuzhiyun scb->cmd.flashfw.count = cpu_to_le32(0x800);
2341*4882a593Smuzhiyun scb->cmd.flashfw.total_packets = 1;
2342*4882a593Smuzhiyun scb->cmd.flashfw.packet_num = 0;
2343*4882a593Smuzhiyun scb->data_len = 0x1000;
2344*4882a593Smuzhiyun scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr;
2345*4882a593Smuzhiyun
2346*4882a593Smuzhiyun /* issue the command */
2347*4882a593Smuzhiyun if (((ret =
2348*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout,
2349*4882a593Smuzhiyun intr)) == IPS_FAILURE)
2350*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
2351*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
2352*4882a593Smuzhiyun /* Error occurred */
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun return;
2355*4882a593Smuzhiyun }
2356*4882a593Smuzhiyun
2357*4882a593Smuzhiyun if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
2358*4882a593Smuzhiyun major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */
2359*4882a593Smuzhiyun minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */
2360*4882a593Smuzhiyun subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fd after the header (0xc0) */
2361*4882a593Smuzhiyun } else {
2362*4882a593Smuzhiyun return;
2363*4882a593Smuzhiyun }
2364*4882a593Smuzhiyun }
2365*4882a593Smuzhiyun
2366*4882a593Smuzhiyun ha->bios_version[0] = hex_asc_upper_hi(major);
2367*4882a593Smuzhiyun ha->bios_version[1] = '.';
2368*4882a593Smuzhiyun ha->bios_version[2] = hex_asc_upper_lo(major);
2369*4882a593Smuzhiyun ha->bios_version[3] = hex_asc_upper_lo(subminor);
2370*4882a593Smuzhiyun ha->bios_version[4] = '.';
2371*4882a593Smuzhiyun ha->bios_version[5] = hex_asc_upper_hi(minor);
2372*4882a593Smuzhiyun ha->bios_version[6] = hex_asc_upper_lo(minor);
2373*4882a593Smuzhiyun ha->bios_version[7] = 0;
2374*4882a593Smuzhiyun }
2375*4882a593Smuzhiyun
2376*4882a593Smuzhiyun /****************************************************************************/
2377*4882a593Smuzhiyun /* */
2378*4882a593Smuzhiyun /* Routine Name: ips_hainit */
2379*4882a593Smuzhiyun /* */
2380*4882a593Smuzhiyun /* Routine Description: */
2381*4882a593Smuzhiyun /* */
2382*4882a593Smuzhiyun /* Initialize the controller */
2383*4882a593Smuzhiyun /* */
2384*4882a593Smuzhiyun /* NOTE: Assumes to be called from with a lock */
2385*4882a593Smuzhiyun /* */
2386*4882a593Smuzhiyun /****************************************************************************/
2387*4882a593Smuzhiyun static int
ips_hainit(ips_ha_t * ha)2388*4882a593Smuzhiyun ips_hainit(ips_ha_t * ha)
2389*4882a593Smuzhiyun {
2390*4882a593Smuzhiyun int i;
2391*4882a593Smuzhiyun
2392*4882a593Smuzhiyun METHOD_TRACE("ips_hainit", 1);
2393*4882a593Smuzhiyun
2394*4882a593Smuzhiyun if (!ha)
2395*4882a593Smuzhiyun return (0);
2396*4882a593Smuzhiyun
2397*4882a593Smuzhiyun if (ha->func.statinit)
2398*4882a593Smuzhiyun (*ha->func.statinit) (ha);
2399*4882a593Smuzhiyun
2400*4882a593Smuzhiyun if (ha->func.enableint)
2401*4882a593Smuzhiyun (*ha->func.enableint) (ha);
2402*4882a593Smuzhiyun
2403*4882a593Smuzhiyun /* Send FFDC */
2404*4882a593Smuzhiyun ha->reset_count = 1;
2405*4882a593Smuzhiyun ha->last_ffdc = ktime_get_real_seconds();
2406*4882a593Smuzhiyun ips_ffdc_reset(ha, IPS_INTR_IORL);
2407*4882a593Smuzhiyun
2408*4882a593Smuzhiyun if (!ips_read_config(ha, IPS_INTR_IORL)) {
2409*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
2410*4882a593Smuzhiyun "unable to read config from controller.\n");
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun return (0);
2413*4882a593Smuzhiyun }
2414*4882a593Smuzhiyun /* end if */
2415*4882a593Smuzhiyun if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
2416*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
2417*4882a593Smuzhiyun "unable to read controller status.\n");
2418*4882a593Smuzhiyun
2419*4882a593Smuzhiyun return (0);
2420*4882a593Smuzhiyun }
2421*4882a593Smuzhiyun
2422*4882a593Smuzhiyun /* Identify this controller */
2423*4882a593Smuzhiyun ips_identify_controller(ha);
2424*4882a593Smuzhiyun
2425*4882a593Smuzhiyun if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
2426*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
2427*4882a593Smuzhiyun "unable to read subsystem parameters.\n");
2428*4882a593Smuzhiyun
2429*4882a593Smuzhiyun return (0);
2430*4882a593Smuzhiyun }
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun /* write nvram user page 5 */
2433*4882a593Smuzhiyun if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
2434*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
2435*4882a593Smuzhiyun "unable to write driver info to controller.\n");
2436*4882a593Smuzhiyun
2437*4882a593Smuzhiyun return (0);
2438*4882a593Smuzhiyun }
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
2441*4882a593Smuzhiyun if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1))
2442*4882a593Smuzhiyun ips_clear_adapter(ha, IPS_INTR_IORL);
2443*4882a593Smuzhiyun
2444*4882a593Smuzhiyun /* set limits on SID, LUN, BUS */
2445*4882a593Smuzhiyun ha->ntargets = IPS_MAX_TARGETS + 1;
2446*4882a593Smuzhiyun ha->nlun = 1;
2447*4882a593Smuzhiyun ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
2448*4882a593Smuzhiyun
2449*4882a593Smuzhiyun switch (ha->conf->logical_drive[0].ucStripeSize) {
2450*4882a593Smuzhiyun case 4:
2451*4882a593Smuzhiyun ha->max_xfer = 0x10000;
2452*4882a593Smuzhiyun break;
2453*4882a593Smuzhiyun
2454*4882a593Smuzhiyun case 5:
2455*4882a593Smuzhiyun ha->max_xfer = 0x20000;
2456*4882a593Smuzhiyun break;
2457*4882a593Smuzhiyun
2458*4882a593Smuzhiyun case 6:
2459*4882a593Smuzhiyun ha->max_xfer = 0x40000;
2460*4882a593Smuzhiyun break;
2461*4882a593Smuzhiyun
2462*4882a593Smuzhiyun case 7:
2463*4882a593Smuzhiyun default:
2464*4882a593Smuzhiyun ha->max_xfer = 0x80000;
2465*4882a593Smuzhiyun break;
2466*4882a593Smuzhiyun }
2467*4882a593Smuzhiyun
2468*4882a593Smuzhiyun /* setup max concurrent commands */
2469*4882a593Smuzhiyun if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
2470*4882a593Smuzhiyun /* Use the new method */
2471*4882a593Smuzhiyun ha->max_cmds = ha->enq->ucConcurrentCmdCount;
2472*4882a593Smuzhiyun } else {
2473*4882a593Smuzhiyun /* use the old method */
2474*4882a593Smuzhiyun switch (ha->conf->logical_drive[0].ucStripeSize) {
2475*4882a593Smuzhiyun case 4:
2476*4882a593Smuzhiyun ha->max_cmds = 32;
2477*4882a593Smuzhiyun break;
2478*4882a593Smuzhiyun
2479*4882a593Smuzhiyun case 5:
2480*4882a593Smuzhiyun ha->max_cmds = 16;
2481*4882a593Smuzhiyun break;
2482*4882a593Smuzhiyun
2483*4882a593Smuzhiyun case 6:
2484*4882a593Smuzhiyun ha->max_cmds = 8;
2485*4882a593Smuzhiyun break;
2486*4882a593Smuzhiyun
2487*4882a593Smuzhiyun case 7:
2488*4882a593Smuzhiyun default:
2489*4882a593Smuzhiyun ha->max_cmds = 4;
2490*4882a593Smuzhiyun break;
2491*4882a593Smuzhiyun }
2492*4882a593Smuzhiyun }
2493*4882a593Smuzhiyun
2494*4882a593Smuzhiyun /* Limit the Active Commands on a Lite Adapter */
2495*4882a593Smuzhiyun if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
2496*4882a593Smuzhiyun (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
2497*4882a593Smuzhiyun (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
2498*4882a593Smuzhiyun if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds))
2499*4882a593Smuzhiyun ha->max_cmds = MaxLiteCmds;
2500*4882a593Smuzhiyun }
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun /* set controller IDs */
2503*4882a593Smuzhiyun ha->ha_id[0] = IPS_ADAPTER_ID;
2504*4882a593Smuzhiyun for (i = 1; i < ha->nbus; i++) {
2505*4882a593Smuzhiyun ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f;
2506*4882a593Smuzhiyun ha->dcdb_active[i - 1] = 0;
2507*4882a593Smuzhiyun }
2508*4882a593Smuzhiyun
2509*4882a593Smuzhiyun return (1);
2510*4882a593Smuzhiyun }
2511*4882a593Smuzhiyun
2512*4882a593Smuzhiyun /****************************************************************************/
2513*4882a593Smuzhiyun /* */
2514*4882a593Smuzhiyun /* Routine Name: ips_next */
2515*4882a593Smuzhiyun /* */
2516*4882a593Smuzhiyun /* Routine Description: */
2517*4882a593Smuzhiyun /* */
2518*4882a593Smuzhiyun /* Take the next command off the queue and send it to the controller */
2519*4882a593Smuzhiyun /* */
2520*4882a593Smuzhiyun /****************************************************************************/
2521*4882a593Smuzhiyun static void
ips_next(ips_ha_t * ha,int intr)2522*4882a593Smuzhiyun ips_next(ips_ha_t * ha, int intr)
2523*4882a593Smuzhiyun {
2524*4882a593Smuzhiyun ips_scb_t *scb;
2525*4882a593Smuzhiyun struct scsi_cmnd *SC;
2526*4882a593Smuzhiyun struct scsi_cmnd *p;
2527*4882a593Smuzhiyun struct scsi_cmnd *q;
2528*4882a593Smuzhiyun ips_copp_wait_item_t *item;
2529*4882a593Smuzhiyun int ret;
2530*4882a593Smuzhiyun struct Scsi_Host *host;
2531*4882a593Smuzhiyun METHOD_TRACE("ips_next", 1);
2532*4882a593Smuzhiyun
2533*4882a593Smuzhiyun if (!ha)
2534*4882a593Smuzhiyun return;
2535*4882a593Smuzhiyun host = ips_sh[ha->host_num];
2536*4882a593Smuzhiyun /*
2537*4882a593Smuzhiyun * Block access to the queue function so
2538*4882a593Smuzhiyun * this command won't time out
2539*4882a593Smuzhiyun */
2540*4882a593Smuzhiyun if (intr == IPS_INTR_ON)
2541*4882a593Smuzhiyun spin_lock(host->host_lock);
2542*4882a593Smuzhiyun
2543*4882a593Smuzhiyun if ((ha->subsys->param[3] & 0x300000)
2544*4882a593Smuzhiyun && (ha->scb_activelist.count == 0)) {
2545*4882a593Smuzhiyun time64_t now = ktime_get_real_seconds();
2546*4882a593Smuzhiyun if (now - ha->last_ffdc > IPS_SECS_8HOURS) {
2547*4882a593Smuzhiyun ha->last_ffdc = now;
2548*4882a593Smuzhiyun ips_ffdc_time(ha);
2549*4882a593Smuzhiyun }
2550*4882a593Smuzhiyun }
2551*4882a593Smuzhiyun
2552*4882a593Smuzhiyun /*
2553*4882a593Smuzhiyun * Send passthru commands
2554*4882a593Smuzhiyun * These have priority over normal I/O
2555*4882a593Smuzhiyun * but shouldn't affect performance too much
2556*4882a593Smuzhiyun * since we limit the number that can be active
2557*4882a593Smuzhiyun * on the card at any one time
2558*4882a593Smuzhiyun */
2559*4882a593Smuzhiyun while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
2560*4882a593Smuzhiyun (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) {
2561*4882a593Smuzhiyun
2562*4882a593Smuzhiyun item = ips_removeq_copp_head(&ha->copp_waitlist);
2563*4882a593Smuzhiyun ha->num_ioctl++;
2564*4882a593Smuzhiyun if (intr == IPS_INTR_ON)
2565*4882a593Smuzhiyun spin_unlock(host->host_lock);
2566*4882a593Smuzhiyun scb->scsi_cmd = item->scsi_cmd;
2567*4882a593Smuzhiyun kfree(item);
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
2570*4882a593Smuzhiyun
2571*4882a593Smuzhiyun if (intr == IPS_INTR_ON)
2572*4882a593Smuzhiyun spin_lock(host->host_lock);
2573*4882a593Smuzhiyun switch (ret) {
2574*4882a593Smuzhiyun case IPS_FAILURE:
2575*4882a593Smuzhiyun if (scb->scsi_cmd) {
2576*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
2577*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2578*4882a593Smuzhiyun }
2579*4882a593Smuzhiyun
2580*4882a593Smuzhiyun ips_freescb(ha, scb);
2581*4882a593Smuzhiyun break;
2582*4882a593Smuzhiyun case IPS_SUCCESS_IMM:
2583*4882a593Smuzhiyun if (scb->scsi_cmd) {
2584*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
2585*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2586*4882a593Smuzhiyun }
2587*4882a593Smuzhiyun
2588*4882a593Smuzhiyun ips_freescb(ha, scb);
2589*4882a593Smuzhiyun break;
2590*4882a593Smuzhiyun default:
2591*4882a593Smuzhiyun break;
2592*4882a593Smuzhiyun } /* end case */
2593*4882a593Smuzhiyun
2594*4882a593Smuzhiyun if (ret != IPS_SUCCESS) {
2595*4882a593Smuzhiyun ha->num_ioctl--;
2596*4882a593Smuzhiyun continue;
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun
2599*4882a593Smuzhiyun ret = ips_send_cmd(ha, scb);
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun if (ret == IPS_SUCCESS)
2602*4882a593Smuzhiyun ips_putq_scb_head(&ha->scb_activelist, scb);
2603*4882a593Smuzhiyun else
2604*4882a593Smuzhiyun ha->num_ioctl--;
2605*4882a593Smuzhiyun
2606*4882a593Smuzhiyun switch (ret) {
2607*4882a593Smuzhiyun case IPS_FAILURE:
2608*4882a593Smuzhiyun if (scb->scsi_cmd) {
2609*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
2610*4882a593Smuzhiyun }
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun ips_freescb(ha, scb);
2613*4882a593Smuzhiyun break;
2614*4882a593Smuzhiyun case IPS_SUCCESS_IMM:
2615*4882a593Smuzhiyun ips_freescb(ha, scb);
2616*4882a593Smuzhiyun break;
2617*4882a593Smuzhiyun default:
2618*4882a593Smuzhiyun break;
2619*4882a593Smuzhiyun } /* end case */
2620*4882a593Smuzhiyun
2621*4882a593Smuzhiyun }
2622*4882a593Smuzhiyun
2623*4882a593Smuzhiyun /*
2624*4882a593Smuzhiyun * Send "Normal" I/O commands
2625*4882a593Smuzhiyun */
2626*4882a593Smuzhiyun
2627*4882a593Smuzhiyun p = ha->scb_waitlist.head;
2628*4882a593Smuzhiyun while ((p) && (scb = ips_getscb(ha))) {
2629*4882a593Smuzhiyun if ((scmd_channel(p) > 0)
2630*4882a593Smuzhiyun && (ha->
2631*4882a593Smuzhiyun dcdb_active[scmd_channel(p) -
2632*4882a593Smuzhiyun 1] & (1 << scmd_id(p)))) {
2633*4882a593Smuzhiyun ips_freescb(ha, scb);
2634*4882a593Smuzhiyun p = (struct scsi_cmnd *) p->host_scribble;
2635*4882a593Smuzhiyun continue;
2636*4882a593Smuzhiyun }
2637*4882a593Smuzhiyun
2638*4882a593Smuzhiyun q = p;
2639*4882a593Smuzhiyun SC = ips_removeq_wait(&ha->scb_waitlist, q);
2640*4882a593Smuzhiyun
2641*4882a593Smuzhiyun if (intr == IPS_INTR_ON)
2642*4882a593Smuzhiyun spin_unlock(host->host_lock); /* Unlock HA after command is taken off queue */
2643*4882a593Smuzhiyun
2644*4882a593Smuzhiyun SC->result = DID_OK;
2645*4882a593Smuzhiyun SC->host_scribble = NULL;
2646*4882a593Smuzhiyun
2647*4882a593Smuzhiyun scb->target_id = SC->device->id;
2648*4882a593Smuzhiyun scb->lun = SC->device->lun;
2649*4882a593Smuzhiyun scb->bus = SC->device->channel;
2650*4882a593Smuzhiyun scb->scsi_cmd = SC;
2651*4882a593Smuzhiyun scb->breakup = 0;
2652*4882a593Smuzhiyun scb->data_len = 0;
2653*4882a593Smuzhiyun scb->callback = ipsintr_done;
2654*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
2655*4882a593Smuzhiyun memset(&scb->cmd, 0, 16);
2656*4882a593Smuzhiyun
2657*4882a593Smuzhiyun /* copy in the CDB */
2658*4882a593Smuzhiyun memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
2659*4882a593Smuzhiyun
2660*4882a593Smuzhiyun scb->sg_count = scsi_dma_map(SC);
2661*4882a593Smuzhiyun BUG_ON(scb->sg_count < 0);
2662*4882a593Smuzhiyun if (scb->sg_count) {
2663*4882a593Smuzhiyun struct scatterlist *sg;
2664*4882a593Smuzhiyun int i;
2665*4882a593Smuzhiyun
2666*4882a593Smuzhiyun scb->flags |= IPS_SCB_MAP_SG;
2667*4882a593Smuzhiyun
2668*4882a593Smuzhiyun scsi_for_each_sg(SC, sg, scb->sg_count, i) {
2669*4882a593Smuzhiyun if (ips_fill_scb_sg_single
2670*4882a593Smuzhiyun (ha, sg_dma_address(sg), scb, i,
2671*4882a593Smuzhiyun sg_dma_len(sg)) < 0)
2672*4882a593Smuzhiyun break;
2673*4882a593Smuzhiyun }
2674*4882a593Smuzhiyun scb->dcdb.transfer_length = scb->data_len;
2675*4882a593Smuzhiyun } else {
2676*4882a593Smuzhiyun scb->data_busaddr = 0L;
2677*4882a593Smuzhiyun scb->sg_len = 0;
2678*4882a593Smuzhiyun scb->data_len = 0;
2679*4882a593Smuzhiyun scb->dcdb.transfer_length = 0;
2680*4882a593Smuzhiyun }
2681*4882a593Smuzhiyun
2682*4882a593Smuzhiyun scb->dcdb.cmd_attribute =
2683*4882a593Smuzhiyun ips_command_direction[scb->scsi_cmd->cmnd[0]];
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun /* Allow a WRITE BUFFER Command to Have no Data */
2686*4882a593Smuzhiyun /* This is Used by Tape Flash Utilites */
2687*4882a593Smuzhiyun if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) &&
2688*4882a593Smuzhiyun (scb->data_len == 0))
2689*4882a593Smuzhiyun scb->dcdb.cmd_attribute = 0;
2690*4882a593Smuzhiyun
2691*4882a593Smuzhiyun if (!(scb->dcdb.cmd_attribute & 0x3))
2692*4882a593Smuzhiyun scb->dcdb.transfer_length = 0;
2693*4882a593Smuzhiyun
2694*4882a593Smuzhiyun if (scb->data_len >= IPS_MAX_XFER) {
2695*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
2696*4882a593Smuzhiyun scb->dcdb.transfer_length = 0;
2697*4882a593Smuzhiyun }
2698*4882a593Smuzhiyun if (intr == IPS_INTR_ON)
2699*4882a593Smuzhiyun spin_lock(host->host_lock);
2700*4882a593Smuzhiyun
2701*4882a593Smuzhiyun ret = ips_send_cmd(ha, scb);
2702*4882a593Smuzhiyun
2703*4882a593Smuzhiyun switch (ret) {
2704*4882a593Smuzhiyun case IPS_SUCCESS:
2705*4882a593Smuzhiyun ips_putq_scb_head(&ha->scb_activelist, scb);
2706*4882a593Smuzhiyun break;
2707*4882a593Smuzhiyun case IPS_FAILURE:
2708*4882a593Smuzhiyun if (scb->scsi_cmd) {
2709*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
2710*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2711*4882a593Smuzhiyun }
2712*4882a593Smuzhiyun
2713*4882a593Smuzhiyun if (scb->bus)
2714*4882a593Smuzhiyun ha->dcdb_active[scb->bus - 1] &=
2715*4882a593Smuzhiyun ~(1 << scb->target_id);
2716*4882a593Smuzhiyun
2717*4882a593Smuzhiyun ips_freescb(ha, scb);
2718*4882a593Smuzhiyun break;
2719*4882a593Smuzhiyun case IPS_SUCCESS_IMM:
2720*4882a593Smuzhiyun if (scb->scsi_cmd)
2721*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
2722*4882a593Smuzhiyun
2723*4882a593Smuzhiyun if (scb->bus)
2724*4882a593Smuzhiyun ha->dcdb_active[scb->bus - 1] &=
2725*4882a593Smuzhiyun ~(1 << scb->target_id);
2726*4882a593Smuzhiyun
2727*4882a593Smuzhiyun ips_freescb(ha, scb);
2728*4882a593Smuzhiyun break;
2729*4882a593Smuzhiyun default:
2730*4882a593Smuzhiyun break;
2731*4882a593Smuzhiyun } /* end case */
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun p = (struct scsi_cmnd *) p->host_scribble;
2734*4882a593Smuzhiyun
2735*4882a593Smuzhiyun } /* end while */
2736*4882a593Smuzhiyun
2737*4882a593Smuzhiyun if (intr == IPS_INTR_ON)
2738*4882a593Smuzhiyun spin_unlock(host->host_lock);
2739*4882a593Smuzhiyun }
2740*4882a593Smuzhiyun
2741*4882a593Smuzhiyun /****************************************************************************/
2742*4882a593Smuzhiyun /* */
2743*4882a593Smuzhiyun /* Routine Name: ips_putq_scb_head */
2744*4882a593Smuzhiyun /* */
2745*4882a593Smuzhiyun /* Routine Description: */
2746*4882a593Smuzhiyun /* */
2747*4882a593Smuzhiyun /* Add an item to the head of the queue */
2748*4882a593Smuzhiyun /* */
2749*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2750*4882a593Smuzhiyun /* */
2751*4882a593Smuzhiyun /****************************************************************************/
2752*4882a593Smuzhiyun static void
ips_putq_scb_head(ips_scb_queue_t * queue,ips_scb_t * item)2753*4882a593Smuzhiyun ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
2754*4882a593Smuzhiyun {
2755*4882a593Smuzhiyun METHOD_TRACE("ips_putq_scb_head", 1);
2756*4882a593Smuzhiyun
2757*4882a593Smuzhiyun if (!item)
2758*4882a593Smuzhiyun return;
2759*4882a593Smuzhiyun
2760*4882a593Smuzhiyun item->q_next = queue->head;
2761*4882a593Smuzhiyun queue->head = item;
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun if (!queue->tail)
2764*4882a593Smuzhiyun queue->tail = item;
2765*4882a593Smuzhiyun
2766*4882a593Smuzhiyun queue->count++;
2767*4882a593Smuzhiyun }
2768*4882a593Smuzhiyun
2769*4882a593Smuzhiyun /****************************************************************************/
2770*4882a593Smuzhiyun /* */
2771*4882a593Smuzhiyun /* Routine Name: ips_removeq_scb_head */
2772*4882a593Smuzhiyun /* */
2773*4882a593Smuzhiyun /* Routine Description: */
2774*4882a593Smuzhiyun /* */
2775*4882a593Smuzhiyun /* Remove the head of the queue */
2776*4882a593Smuzhiyun /* */
2777*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2778*4882a593Smuzhiyun /* */
2779*4882a593Smuzhiyun /****************************************************************************/
2780*4882a593Smuzhiyun static ips_scb_t *
ips_removeq_scb_head(ips_scb_queue_t * queue)2781*4882a593Smuzhiyun ips_removeq_scb_head(ips_scb_queue_t * queue)
2782*4882a593Smuzhiyun {
2783*4882a593Smuzhiyun ips_scb_t *item;
2784*4882a593Smuzhiyun
2785*4882a593Smuzhiyun METHOD_TRACE("ips_removeq_scb_head", 1);
2786*4882a593Smuzhiyun
2787*4882a593Smuzhiyun item = queue->head;
2788*4882a593Smuzhiyun
2789*4882a593Smuzhiyun if (!item) {
2790*4882a593Smuzhiyun return (NULL);
2791*4882a593Smuzhiyun }
2792*4882a593Smuzhiyun
2793*4882a593Smuzhiyun queue->head = item->q_next;
2794*4882a593Smuzhiyun item->q_next = NULL;
2795*4882a593Smuzhiyun
2796*4882a593Smuzhiyun if (queue->tail == item)
2797*4882a593Smuzhiyun queue->tail = NULL;
2798*4882a593Smuzhiyun
2799*4882a593Smuzhiyun queue->count--;
2800*4882a593Smuzhiyun
2801*4882a593Smuzhiyun return (item);
2802*4882a593Smuzhiyun }
2803*4882a593Smuzhiyun
2804*4882a593Smuzhiyun /****************************************************************************/
2805*4882a593Smuzhiyun /* */
2806*4882a593Smuzhiyun /* Routine Name: ips_removeq_scb */
2807*4882a593Smuzhiyun /* */
2808*4882a593Smuzhiyun /* Routine Description: */
2809*4882a593Smuzhiyun /* */
2810*4882a593Smuzhiyun /* Remove an item from a queue */
2811*4882a593Smuzhiyun /* */
2812*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2813*4882a593Smuzhiyun /* */
2814*4882a593Smuzhiyun /****************************************************************************/
2815*4882a593Smuzhiyun static ips_scb_t *
ips_removeq_scb(ips_scb_queue_t * queue,ips_scb_t * item)2816*4882a593Smuzhiyun ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
2817*4882a593Smuzhiyun {
2818*4882a593Smuzhiyun ips_scb_t *p;
2819*4882a593Smuzhiyun
2820*4882a593Smuzhiyun METHOD_TRACE("ips_removeq_scb", 1);
2821*4882a593Smuzhiyun
2822*4882a593Smuzhiyun if (!item)
2823*4882a593Smuzhiyun return (NULL);
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun if (item == queue->head) {
2826*4882a593Smuzhiyun return (ips_removeq_scb_head(queue));
2827*4882a593Smuzhiyun }
2828*4882a593Smuzhiyun
2829*4882a593Smuzhiyun p = queue->head;
2830*4882a593Smuzhiyun
2831*4882a593Smuzhiyun while ((p) && (item != p->q_next))
2832*4882a593Smuzhiyun p = p->q_next;
2833*4882a593Smuzhiyun
2834*4882a593Smuzhiyun if (p) {
2835*4882a593Smuzhiyun /* found a match */
2836*4882a593Smuzhiyun p->q_next = item->q_next;
2837*4882a593Smuzhiyun
2838*4882a593Smuzhiyun if (!item->q_next)
2839*4882a593Smuzhiyun queue->tail = p;
2840*4882a593Smuzhiyun
2841*4882a593Smuzhiyun item->q_next = NULL;
2842*4882a593Smuzhiyun queue->count--;
2843*4882a593Smuzhiyun
2844*4882a593Smuzhiyun return (item);
2845*4882a593Smuzhiyun }
2846*4882a593Smuzhiyun
2847*4882a593Smuzhiyun return (NULL);
2848*4882a593Smuzhiyun }
2849*4882a593Smuzhiyun
2850*4882a593Smuzhiyun /****************************************************************************/
2851*4882a593Smuzhiyun /* */
2852*4882a593Smuzhiyun /* Routine Name: ips_putq_wait_tail */
2853*4882a593Smuzhiyun /* */
2854*4882a593Smuzhiyun /* Routine Description: */
2855*4882a593Smuzhiyun /* */
2856*4882a593Smuzhiyun /* Add an item to the tail of the queue */
2857*4882a593Smuzhiyun /* */
2858*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2859*4882a593Smuzhiyun /* */
2860*4882a593Smuzhiyun /****************************************************************************/
ips_putq_wait_tail(ips_wait_queue_entry_t * queue,struct scsi_cmnd * item)2861*4882a593Smuzhiyun static void ips_putq_wait_tail(ips_wait_queue_entry_t *queue, struct scsi_cmnd *item)
2862*4882a593Smuzhiyun {
2863*4882a593Smuzhiyun METHOD_TRACE("ips_putq_wait_tail", 1);
2864*4882a593Smuzhiyun
2865*4882a593Smuzhiyun if (!item)
2866*4882a593Smuzhiyun return;
2867*4882a593Smuzhiyun
2868*4882a593Smuzhiyun item->host_scribble = NULL;
2869*4882a593Smuzhiyun
2870*4882a593Smuzhiyun if (queue->tail)
2871*4882a593Smuzhiyun queue->tail->host_scribble = (char *) item;
2872*4882a593Smuzhiyun
2873*4882a593Smuzhiyun queue->tail = item;
2874*4882a593Smuzhiyun
2875*4882a593Smuzhiyun if (!queue->head)
2876*4882a593Smuzhiyun queue->head = item;
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun queue->count++;
2879*4882a593Smuzhiyun }
2880*4882a593Smuzhiyun
2881*4882a593Smuzhiyun /****************************************************************************/
2882*4882a593Smuzhiyun /* */
2883*4882a593Smuzhiyun /* Routine Name: ips_removeq_wait_head */
2884*4882a593Smuzhiyun /* */
2885*4882a593Smuzhiyun /* Routine Description: */
2886*4882a593Smuzhiyun /* */
2887*4882a593Smuzhiyun /* Remove the head of the queue */
2888*4882a593Smuzhiyun /* */
2889*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2890*4882a593Smuzhiyun /* */
2891*4882a593Smuzhiyun /****************************************************************************/
ips_removeq_wait_head(ips_wait_queue_entry_t * queue)2892*4882a593Smuzhiyun static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_entry_t *queue)
2893*4882a593Smuzhiyun {
2894*4882a593Smuzhiyun struct scsi_cmnd *item;
2895*4882a593Smuzhiyun
2896*4882a593Smuzhiyun METHOD_TRACE("ips_removeq_wait_head", 1);
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun item = queue->head;
2899*4882a593Smuzhiyun
2900*4882a593Smuzhiyun if (!item) {
2901*4882a593Smuzhiyun return (NULL);
2902*4882a593Smuzhiyun }
2903*4882a593Smuzhiyun
2904*4882a593Smuzhiyun queue->head = (struct scsi_cmnd *) item->host_scribble;
2905*4882a593Smuzhiyun item->host_scribble = NULL;
2906*4882a593Smuzhiyun
2907*4882a593Smuzhiyun if (queue->tail == item)
2908*4882a593Smuzhiyun queue->tail = NULL;
2909*4882a593Smuzhiyun
2910*4882a593Smuzhiyun queue->count--;
2911*4882a593Smuzhiyun
2912*4882a593Smuzhiyun return (item);
2913*4882a593Smuzhiyun }
2914*4882a593Smuzhiyun
2915*4882a593Smuzhiyun /****************************************************************************/
2916*4882a593Smuzhiyun /* */
2917*4882a593Smuzhiyun /* Routine Name: ips_removeq_wait */
2918*4882a593Smuzhiyun /* */
2919*4882a593Smuzhiyun /* Routine Description: */
2920*4882a593Smuzhiyun /* */
2921*4882a593Smuzhiyun /* Remove an item from a queue */
2922*4882a593Smuzhiyun /* */
2923*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2924*4882a593Smuzhiyun /* */
2925*4882a593Smuzhiyun /****************************************************************************/
ips_removeq_wait(ips_wait_queue_entry_t * queue,struct scsi_cmnd * item)2926*4882a593Smuzhiyun static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_entry_t *queue,
2927*4882a593Smuzhiyun struct scsi_cmnd *item)
2928*4882a593Smuzhiyun {
2929*4882a593Smuzhiyun struct scsi_cmnd *p;
2930*4882a593Smuzhiyun
2931*4882a593Smuzhiyun METHOD_TRACE("ips_removeq_wait", 1);
2932*4882a593Smuzhiyun
2933*4882a593Smuzhiyun if (!item)
2934*4882a593Smuzhiyun return (NULL);
2935*4882a593Smuzhiyun
2936*4882a593Smuzhiyun if (item == queue->head) {
2937*4882a593Smuzhiyun return (ips_removeq_wait_head(queue));
2938*4882a593Smuzhiyun }
2939*4882a593Smuzhiyun
2940*4882a593Smuzhiyun p = queue->head;
2941*4882a593Smuzhiyun
2942*4882a593Smuzhiyun while ((p) && (item != (struct scsi_cmnd *) p->host_scribble))
2943*4882a593Smuzhiyun p = (struct scsi_cmnd *) p->host_scribble;
2944*4882a593Smuzhiyun
2945*4882a593Smuzhiyun if (p) {
2946*4882a593Smuzhiyun /* found a match */
2947*4882a593Smuzhiyun p->host_scribble = item->host_scribble;
2948*4882a593Smuzhiyun
2949*4882a593Smuzhiyun if (!item->host_scribble)
2950*4882a593Smuzhiyun queue->tail = p;
2951*4882a593Smuzhiyun
2952*4882a593Smuzhiyun item->host_scribble = NULL;
2953*4882a593Smuzhiyun queue->count--;
2954*4882a593Smuzhiyun
2955*4882a593Smuzhiyun return (item);
2956*4882a593Smuzhiyun }
2957*4882a593Smuzhiyun
2958*4882a593Smuzhiyun return (NULL);
2959*4882a593Smuzhiyun }
2960*4882a593Smuzhiyun
2961*4882a593Smuzhiyun /****************************************************************************/
2962*4882a593Smuzhiyun /* */
2963*4882a593Smuzhiyun /* Routine Name: ips_putq_copp_tail */
2964*4882a593Smuzhiyun /* */
2965*4882a593Smuzhiyun /* Routine Description: */
2966*4882a593Smuzhiyun /* */
2967*4882a593Smuzhiyun /* Add an item to the tail of the queue */
2968*4882a593Smuzhiyun /* */
2969*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
2970*4882a593Smuzhiyun /* */
2971*4882a593Smuzhiyun /****************************************************************************/
2972*4882a593Smuzhiyun static void
ips_putq_copp_tail(ips_copp_queue_t * queue,ips_copp_wait_item_t * item)2973*4882a593Smuzhiyun ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
2974*4882a593Smuzhiyun {
2975*4882a593Smuzhiyun METHOD_TRACE("ips_putq_copp_tail", 1);
2976*4882a593Smuzhiyun
2977*4882a593Smuzhiyun if (!item)
2978*4882a593Smuzhiyun return;
2979*4882a593Smuzhiyun
2980*4882a593Smuzhiyun item->next = NULL;
2981*4882a593Smuzhiyun
2982*4882a593Smuzhiyun if (queue->tail)
2983*4882a593Smuzhiyun queue->tail->next = item;
2984*4882a593Smuzhiyun
2985*4882a593Smuzhiyun queue->tail = item;
2986*4882a593Smuzhiyun
2987*4882a593Smuzhiyun if (!queue->head)
2988*4882a593Smuzhiyun queue->head = item;
2989*4882a593Smuzhiyun
2990*4882a593Smuzhiyun queue->count++;
2991*4882a593Smuzhiyun }
2992*4882a593Smuzhiyun
2993*4882a593Smuzhiyun /****************************************************************************/
2994*4882a593Smuzhiyun /* */
2995*4882a593Smuzhiyun /* Routine Name: ips_removeq_copp_head */
2996*4882a593Smuzhiyun /* */
2997*4882a593Smuzhiyun /* Routine Description: */
2998*4882a593Smuzhiyun /* */
2999*4882a593Smuzhiyun /* Remove the head of the queue */
3000*4882a593Smuzhiyun /* */
3001*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
3002*4882a593Smuzhiyun /* */
3003*4882a593Smuzhiyun /****************************************************************************/
3004*4882a593Smuzhiyun static ips_copp_wait_item_t *
ips_removeq_copp_head(ips_copp_queue_t * queue)3005*4882a593Smuzhiyun ips_removeq_copp_head(ips_copp_queue_t * queue)
3006*4882a593Smuzhiyun {
3007*4882a593Smuzhiyun ips_copp_wait_item_t *item;
3008*4882a593Smuzhiyun
3009*4882a593Smuzhiyun METHOD_TRACE("ips_removeq_copp_head", 1);
3010*4882a593Smuzhiyun
3011*4882a593Smuzhiyun item = queue->head;
3012*4882a593Smuzhiyun
3013*4882a593Smuzhiyun if (!item) {
3014*4882a593Smuzhiyun return (NULL);
3015*4882a593Smuzhiyun }
3016*4882a593Smuzhiyun
3017*4882a593Smuzhiyun queue->head = item->next;
3018*4882a593Smuzhiyun item->next = NULL;
3019*4882a593Smuzhiyun
3020*4882a593Smuzhiyun if (queue->tail == item)
3021*4882a593Smuzhiyun queue->tail = NULL;
3022*4882a593Smuzhiyun
3023*4882a593Smuzhiyun queue->count--;
3024*4882a593Smuzhiyun
3025*4882a593Smuzhiyun return (item);
3026*4882a593Smuzhiyun }
3027*4882a593Smuzhiyun
3028*4882a593Smuzhiyun /****************************************************************************/
3029*4882a593Smuzhiyun /* */
3030*4882a593Smuzhiyun /* Routine Name: ips_removeq_copp */
3031*4882a593Smuzhiyun /* */
3032*4882a593Smuzhiyun /* Routine Description: */
3033*4882a593Smuzhiyun /* */
3034*4882a593Smuzhiyun /* Remove an item from a queue */
3035*4882a593Smuzhiyun /* */
3036*4882a593Smuzhiyun /* ASSUMED to be called from within the HA lock */
3037*4882a593Smuzhiyun /* */
3038*4882a593Smuzhiyun /****************************************************************************/
3039*4882a593Smuzhiyun static ips_copp_wait_item_t *
ips_removeq_copp(ips_copp_queue_t * queue,ips_copp_wait_item_t * item)3040*4882a593Smuzhiyun ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
3041*4882a593Smuzhiyun {
3042*4882a593Smuzhiyun ips_copp_wait_item_t *p;
3043*4882a593Smuzhiyun
3044*4882a593Smuzhiyun METHOD_TRACE("ips_removeq_copp", 1);
3045*4882a593Smuzhiyun
3046*4882a593Smuzhiyun if (!item)
3047*4882a593Smuzhiyun return (NULL);
3048*4882a593Smuzhiyun
3049*4882a593Smuzhiyun if (item == queue->head) {
3050*4882a593Smuzhiyun return (ips_removeq_copp_head(queue));
3051*4882a593Smuzhiyun }
3052*4882a593Smuzhiyun
3053*4882a593Smuzhiyun p = queue->head;
3054*4882a593Smuzhiyun
3055*4882a593Smuzhiyun while ((p) && (item != p->next))
3056*4882a593Smuzhiyun p = p->next;
3057*4882a593Smuzhiyun
3058*4882a593Smuzhiyun if (p) {
3059*4882a593Smuzhiyun /* found a match */
3060*4882a593Smuzhiyun p->next = item->next;
3061*4882a593Smuzhiyun
3062*4882a593Smuzhiyun if (!item->next)
3063*4882a593Smuzhiyun queue->tail = p;
3064*4882a593Smuzhiyun
3065*4882a593Smuzhiyun item->next = NULL;
3066*4882a593Smuzhiyun queue->count--;
3067*4882a593Smuzhiyun
3068*4882a593Smuzhiyun return (item);
3069*4882a593Smuzhiyun }
3070*4882a593Smuzhiyun
3071*4882a593Smuzhiyun return (NULL);
3072*4882a593Smuzhiyun }
3073*4882a593Smuzhiyun
3074*4882a593Smuzhiyun /****************************************************************************/
3075*4882a593Smuzhiyun /* */
3076*4882a593Smuzhiyun /* Routine Name: ipsintr_blocking */
3077*4882a593Smuzhiyun /* */
3078*4882a593Smuzhiyun /* Routine Description: */
3079*4882a593Smuzhiyun /* */
3080*4882a593Smuzhiyun /* Finalize an interrupt for internal commands */
3081*4882a593Smuzhiyun /* */
3082*4882a593Smuzhiyun /****************************************************************************/
3083*4882a593Smuzhiyun static void
ipsintr_blocking(ips_ha_t * ha,ips_scb_t * scb)3084*4882a593Smuzhiyun ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb)
3085*4882a593Smuzhiyun {
3086*4882a593Smuzhiyun METHOD_TRACE("ipsintr_blocking", 2);
3087*4882a593Smuzhiyun
3088*4882a593Smuzhiyun ips_freescb(ha, scb);
3089*4882a593Smuzhiyun if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) {
3090*4882a593Smuzhiyun ha->waitflag = FALSE;
3091*4882a593Smuzhiyun
3092*4882a593Smuzhiyun return;
3093*4882a593Smuzhiyun }
3094*4882a593Smuzhiyun }
3095*4882a593Smuzhiyun
3096*4882a593Smuzhiyun /****************************************************************************/
3097*4882a593Smuzhiyun /* */
3098*4882a593Smuzhiyun /* Routine Name: ipsintr_done */
3099*4882a593Smuzhiyun /* */
3100*4882a593Smuzhiyun /* Routine Description: */
3101*4882a593Smuzhiyun /* */
3102*4882a593Smuzhiyun /* Finalize an interrupt for non-internal commands */
3103*4882a593Smuzhiyun /* */
3104*4882a593Smuzhiyun /****************************************************************************/
3105*4882a593Smuzhiyun static void
ipsintr_done(ips_ha_t * ha,ips_scb_t * scb)3106*4882a593Smuzhiyun ipsintr_done(ips_ha_t * ha, ips_scb_t * scb)
3107*4882a593Smuzhiyun {
3108*4882a593Smuzhiyun METHOD_TRACE("ipsintr_done", 2);
3109*4882a593Smuzhiyun
3110*4882a593Smuzhiyun if (!scb) {
3111*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
3112*4882a593Smuzhiyun "Spurious interrupt; scb NULL.\n");
3113*4882a593Smuzhiyun
3114*4882a593Smuzhiyun return;
3115*4882a593Smuzhiyun }
3116*4882a593Smuzhiyun
3117*4882a593Smuzhiyun if (scb->scsi_cmd == NULL) {
3118*4882a593Smuzhiyun /* unexpected interrupt */
3119*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
3120*4882a593Smuzhiyun "Spurious interrupt; scsi_cmd not set.\n");
3121*4882a593Smuzhiyun
3122*4882a593Smuzhiyun return;
3123*4882a593Smuzhiyun }
3124*4882a593Smuzhiyun
3125*4882a593Smuzhiyun ips_done(ha, scb);
3126*4882a593Smuzhiyun }
3127*4882a593Smuzhiyun
3128*4882a593Smuzhiyun /****************************************************************************/
3129*4882a593Smuzhiyun /* */
3130*4882a593Smuzhiyun /* Routine Name: ips_done */
3131*4882a593Smuzhiyun /* */
3132*4882a593Smuzhiyun /* Routine Description: */
3133*4882a593Smuzhiyun /* */
3134*4882a593Smuzhiyun /* Do housekeeping on completed commands */
3135*4882a593Smuzhiyun /* ASSUMED to be called form within the request lock */
3136*4882a593Smuzhiyun /****************************************************************************/
3137*4882a593Smuzhiyun static void
ips_done(ips_ha_t * ha,ips_scb_t * scb)3138*4882a593Smuzhiyun ips_done(ips_ha_t * ha, ips_scb_t * scb)
3139*4882a593Smuzhiyun {
3140*4882a593Smuzhiyun int ret;
3141*4882a593Smuzhiyun
3142*4882a593Smuzhiyun METHOD_TRACE("ips_done", 1);
3143*4882a593Smuzhiyun
3144*4882a593Smuzhiyun if (!scb)
3145*4882a593Smuzhiyun return;
3146*4882a593Smuzhiyun
3147*4882a593Smuzhiyun if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
3148*4882a593Smuzhiyun ips_cleanup_passthru(ha, scb);
3149*4882a593Smuzhiyun ha->num_ioctl--;
3150*4882a593Smuzhiyun } else {
3151*4882a593Smuzhiyun /*
3152*4882a593Smuzhiyun * Check to see if this command had too much
3153*4882a593Smuzhiyun * data and had to be broke up. If so, queue
3154*4882a593Smuzhiyun * the rest of the data and continue.
3155*4882a593Smuzhiyun */
3156*4882a593Smuzhiyun if ((scb->breakup) || (scb->sg_break)) {
3157*4882a593Smuzhiyun struct scatterlist *sg;
3158*4882a593Smuzhiyun int i, sg_dma_index, ips_sg_index = 0;
3159*4882a593Smuzhiyun
3160*4882a593Smuzhiyun /* we had a data breakup */
3161*4882a593Smuzhiyun scb->data_len = 0;
3162*4882a593Smuzhiyun
3163*4882a593Smuzhiyun sg = scsi_sglist(scb->scsi_cmd);
3164*4882a593Smuzhiyun
3165*4882a593Smuzhiyun /* Spin forward to last dma chunk */
3166*4882a593Smuzhiyun sg_dma_index = scb->breakup;
3167*4882a593Smuzhiyun for (i = 0; i < scb->breakup; i++)
3168*4882a593Smuzhiyun sg = sg_next(sg);
3169*4882a593Smuzhiyun
3170*4882a593Smuzhiyun /* Take care of possible partial on last chunk */
3171*4882a593Smuzhiyun ips_fill_scb_sg_single(ha,
3172*4882a593Smuzhiyun sg_dma_address(sg),
3173*4882a593Smuzhiyun scb, ips_sg_index++,
3174*4882a593Smuzhiyun sg_dma_len(sg));
3175*4882a593Smuzhiyun
3176*4882a593Smuzhiyun for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd);
3177*4882a593Smuzhiyun sg_dma_index++, sg = sg_next(sg)) {
3178*4882a593Smuzhiyun if (ips_fill_scb_sg_single
3179*4882a593Smuzhiyun (ha,
3180*4882a593Smuzhiyun sg_dma_address(sg),
3181*4882a593Smuzhiyun scb, ips_sg_index++,
3182*4882a593Smuzhiyun sg_dma_len(sg)) < 0)
3183*4882a593Smuzhiyun break;
3184*4882a593Smuzhiyun }
3185*4882a593Smuzhiyun
3186*4882a593Smuzhiyun scb->dcdb.transfer_length = scb->data_len;
3187*4882a593Smuzhiyun scb->dcdb.cmd_attribute |=
3188*4882a593Smuzhiyun ips_command_direction[scb->scsi_cmd->cmnd[0]];
3189*4882a593Smuzhiyun
3190*4882a593Smuzhiyun if (!(scb->dcdb.cmd_attribute & 0x3))
3191*4882a593Smuzhiyun scb->dcdb.transfer_length = 0;
3192*4882a593Smuzhiyun
3193*4882a593Smuzhiyun if (scb->data_len >= IPS_MAX_XFER) {
3194*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
3195*4882a593Smuzhiyun scb->dcdb.transfer_length = 0;
3196*4882a593Smuzhiyun }
3197*4882a593Smuzhiyun
3198*4882a593Smuzhiyun ret = ips_send_cmd(ha, scb);
3199*4882a593Smuzhiyun
3200*4882a593Smuzhiyun switch (ret) {
3201*4882a593Smuzhiyun case IPS_FAILURE:
3202*4882a593Smuzhiyun if (scb->scsi_cmd) {
3203*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
3204*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
3205*4882a593Smuzhiyun }
3206*4882a593Smuzhiyun
3207*4882a593Smuzhiyun ips_freescb(ha, scb);
3208*4882a593Smuzhiyun break;
3209*4882a593Smuzhiyun case IPS_SUCCESS_IMM:
3210*4882a593Smuzhiyun if (scb->scsi_cmd) {
3211*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
3212*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
3213*4882a593Smuzhiyun }
3214*4882a593Smuzhiyun
3215*4882a593Smuzhiyun ips_freescb(ha, scb);
3216*4882a593Smuzhiyun break;
3217*4882a593Smuzhiyun default:
3218*4882a593Smuzhiyun break;
3219*4882a593Smuzhiyun } /* end case */
3220*4882a593Smuzhiyun
3221*4882a593Smuzhiyun return;
3222*4882a593Smuzhiyun }
3223*4882a593Smuzhiyun } /* end if passthru */
3224*4882a593Smuzhiyun
3225*4882a593Smuzhiyun if (scb->bus) {
3226*4882a593Smuzhiyun ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id);
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun
3229*4882a593Smuzhiyun scb->scsi_cmd->scsi_done(scb->scsi_cmd);
3230*4882a593Smuzhiyun
3231*4882a593Smuzhiyun ips_freescb(ha, scb);
3232*4882a593Smuzhiyun }
3233*4882a593Smuzhiyun
3234*4882a593Smuzhiyun /****************************************************************************/
3235*4882a593Smuzhiyun /* */
3236*4882a593Smuzhiyun /* Routine Name: ips_map_status */
3237*4882a593Smuzhiyun /* */
3238*4882a593Smuzhiyun /* Routine Description: */
3239*4882a593Smuzhiyun /* */
3240*4882a593Smuzhiyun /* Map Controller Error codes to Linux Error Codes */
3241*4882a593Smuzhiyun /* */
3242*4882a593Smuzhiyun /****************************************************************************/
3243*4882a593Smuzhiyun static int
ips_map_status(ips_ha_t * ha,ips_scb_t * scb,ips_stat_t * sp)3244*4882a593Smuzhiyun ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
3245*4882a593Smuzhiyun {
3246*4882a593Smuzhiyun int errcode;
3247*4882a593Smuzhiyun int device_error;
3248*4882a593Smuzhiyun uint32_t transfer_len;
3249*4882a593Smuzhiyun IPS_DCDB_TABLE_TAPE *tapeDCDB;
3250*4882a593Smuzhiyun IPS_SCSI_INQ_DATA inquiryData;
3251*4882a593Smuzhiyun
3252*4882a593Smuzhiyun METHOD_TRACE("ips_map_status", 1);
3253*4882a593Smuzhiyun
3254*4882a593Smuzhiyun if (scb->bus) {
3255*4882a593Smuzhiyun DEBUG_VAR(2,
3256*4882a593Smuzhiyun "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
3257*4882a593Smuzhiyun ips_name, ha->host_num,
3258*4882a593Smuzhiyun scb->scsi_cmd->device->channel,
3259*4882a593Smuzhiyun scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun,
3260*4882a593Smuzhiyun scb->basic_status, scb->extended_status,
3261*4882a593Smuzhiyun scb->extended_status ==
3262*4882a593Smuzhiyun IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
3263*4882a593Smuzhiyun scb->extended_status ==
3264*4882a593Smuzhiyun IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
3265*4882a593Smuzhiyun scb->extended_status ==
3266*4882a593Smuzhiyun IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
3267*4882a593Smuzhiyun }
3268*4882a593Smuzhiyun
3269*4882a593Smuzhiyun /* default driver error */
3270*4882a593Smuzhiyun errcode = DID_ERROR;
3271*4882a593Smuzhiyun device_error = 0;
3272*4882a593Smuzhiyun
3273*4882a593Smuzhiyun switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
3274*4882a593Smuzhiyun case IPS_CMD_TIMEOUT:
3275*4882a593Smuzhiyun errcode = DID_TIME_OUT;
3276*4882a593Smuzhiyun break;
3277*4882a593Smuzhiyun
3278*4882a593Smuzhiyun case IPS_INVAL_OPCO:
3279*4882a593Smuzhiyun case IPS_INVAL_CMD_BLK:
3280*4882a593Smuzhiyun case IPS_INVAL_PARM_BLK:
3281*4882a593Smuzhiyun case IPS_LD_ERROR:
3282*4882a593Smuzhiyun case IPS_CMD_CMPLT_WERROR:
3283*4882a593Smuzhiyun break;
3284*4882a593Smuzhiyun
3285*4882a593Smuzhiyun case IPS_PHYS_DRV_ERROR:
3286*4882a593Smuzhiyun switch (scb->extended_status) {
3287*4882a593Smuzhiyun case IPS_ERR_SEL_TO:
3288*4882a593Smuzhiyun if (scb->bus)
3289*4882a593Smuzhiyun errcode = DID_NO_CONNECT;
3290*4882a593Smuzhiyun
3291*4882a593Smuzhiyun break;
3292*4882a593Smuzhiyun
3293*4882a593Smuzhiyun case IPS_ERR_OU_RUN:
3294*4882a593Smuzhiyun if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
3295*4882a593Smuzhiyun (scb->cmd.dcdb.op_code ==
3296*4882a593Smuzhiyun IPS_CMD_EXTENDED_DCDB_SG)) {
3297*4882a593Smuzhiyun tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
3298*4882a593Smuzhiyun transfer_len = tapeDCDB->transfer_length;
3299*4882a593Smuzhiyun } else {
3300*4882a593Smuzhiyun transfer_len =
3301*4882a593Smuzhiyun (uint32_t) scb->dcdb.transfer_length;
3302*4882a593Smuzhiyun }
3303*4882a593Smuzhiyun
3304*4882a593Smuzhiyun if ((scb->bus) && (transfer_len < scb->data_len)) {
3305*4882a593Smuzhiyun /* Underrun - set default to no error */
3306*4882a593Smuzhiyun errcode = DID_OK;
3307*4882a593Smuzhiyun
3308*4882a593Smuzhiyun /* Restrict access to physical DASD */
3309*4882a593Smuzhiyun if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
3310*4882a593Smuzhiyun ips_scmd_buf_read(scb->scsi_cmd,
3311*4882a593Smuzhiyun &inquiryData, sizeof (inquiryData));
3312*4882a593Smuzhiyun if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
3313*4882a593Smuzhiyun errcode = DID_TIME_OUT;
3314*4882a593Smuzhiyun break;
3315*4882a593Smuzhiyun }
3316*4882a593Smuzhiyun }
3317*4882a593Smuzhiyun } else
3318*4882a593Smuzhiyun errcode = DID_ERROR;
3319*4882a593Smuzhiyun
3320*4882a593Smuzhiyun break;
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun case IPS_ERR_RECOVERY:
3323*4882a593Smuzhiyun /* don't fail recovered errors */
3324*4882a593Smuzhiyun if (scb->bus)
3325*4882a593Smuzhiyun errcode = DID_OK;
3326*4882a593Smuzhiyun
3327*4882a593Smuzhiyun break;
3328*4882a593Smuzhiyun
3329*4882a593Smuzhiyun case IPS_ERR_HOST_RESET:
3330*4882a593Smuzhiyun case IPS_ERR_DEV_RESET:
3331*4882a593Smuzhiyun errcode = DID_RESET;
3332*4882a593Smuzhiyun break;
3333*4882a593Smuzhiyun
3334*4882a593Smuzhiyun case IPS_ERR_CKCOND:
3335*4882a593Smuzhiyun if (scb->bus) {
3336*4882a593Smuzhiyun if ((scb->cmd.dcdb.op_code ==
3337*4882a593Smuzhiyun IPS_CMD_EXTENDED_DCDB)
3338*4882a593Smuzhiyun || (scb->cmd.dcdb.op_code ==
3339*4882a593Smuzhiyun IPS_CMD_EXTENDED_DCDB_SG)) {
3340*4882a593Smuzhiyun tapeDCDB =
3341*4882a593Smuzhiyun (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
3342*4882a593Smuzhiyun memcpy(scb->scsi_cmd->sense_buffer,
3343*4882a593Smuzhiyun tapeDCDB->sense_info,
3344*4882a593Smuzhiyun SCSI_SENSE_BUFFERSIZE);
3345*4882a593Smuzhiyun } else {
3346*4882a593Smuzhiyun memcpy(scb->scsi_cmd->sense_buffer,
3347*4882a593Smuzhiyun scb->dcdb.sense_info,
3348*4882a593Smuzhiyun SCSI_SENSE_BUFFERSIZE);
3349*4882a593Smuzhiyun }
3350*4882a593Smuzhiyun device_error = 2; /* check condition */
3351*4882a593Smuzhiyun }
3352*4882a593Smuzhiyun
3353*4882a593Smuzhiyun errcode = DID_OK;
3354*4882a593Smuzhiyun
3355*4882a593Smuzhiyun break;
3356*4882a593Smuzhiyun
3357*4882a593Smuzhiyun default:
3358*4882a593Smuzhiyun errcode = DID_ERROR;
3359*4882a593Smuzhiyun break;
3360*4882a593Smuzhiyun
3361*4882a593Smuzhiyun } /* end switch */
3362*4882a593Smuzhiyun } /* end switch */
3363*4882a593Smuzhiyun
3364*4882a593Smuzhiyun scb->scsi_cmd->result = device_error | (errcode << 16);
3365*4882a593Smuzhiyun
3366*4882a593Smuzhiyun return (1);
3367*4882a593Smuzhiyun }
3368*4882a593Smuzhiyun
3369*4882a593Smuzhiyun /****************************************************************************/
3370*4882a593Smuzhiyun /* */
3371*4882a593Smuzhiyun /* Routine Name: ips_send_wait */
3372*4882a593Smuzhiyun /* */
3373*4882a593Smuzhiyun /* Routine Description: */
3374*4882a593Smuzhiyun /* */
3375*4882a593Smuzhiyun /* Send a command to the controller and wait for it to return */
3376*4882a593Smuzhiyun /* */
3377*4882a593Smuzhiyun /* The FFDC Time Stamp use this function for the callback, but doesn't */
3378*4882a593Smuzhiyun /* actually need to wait. */
3379*4882a593Smuzhiyun /****************************************************************************/
3380*4882a593Smuzhiyun static int
ips_send_wait(ips_ha_t * ha,ips_scb_t * scb,int timeout,int intr)3381*4882a593Smuzhiyun ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
3382*4882a593Smuzhiyun {
3383*4882a593Smuzhiyun int ret;
3384*4882a593Smuzhiyun
3385*4882a593Smuzhiyun METHOD_TRACE("ips_send_wait", 1);
3386*4882a593Smuzhiyun
3387*4882a593Smuzhiyun if (intr != IPS_FFDC) { /* Won't be Waiting if this is a Time Stamp */
3388*4882a593Smuzhiyun ha->waitflag = TRUE;
3389*4882a593Smuzhiyun ha->cmd_in_progress = scb->cdb[0];
3390*4882a593Smuzhiyun }
3391*4882a593Smuzhiyun scb->callback = ipsintr_blocking;
3392*4882a593Smuzhiyun ret = ips_send_cmd(ha, scb);
3393*4882a593Smuzhiyun
3394*4882a593Smuzhiyun if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
3395*4882a593Smuzhiyun return (ret);
3396*4882a593Smuzhiyun
3397*4882a593Smuzhiyun if (intr != IPS_FFDC) /* Don't Wait around if this is a Time Stamp */
3398*4882a593Smuzhiyun ret = ips_wait(ha, timeout, intr);
3399*4882a593Smuzhiyun
3400*4882a593Smuzhiyun return (ret);
3401*4882a593Smuzhiyun }
3402*4882a593Smuzhiyun
3403*4882a593Smuzhiyun /****************************************************************************/
3404*4882a593Smuzhiyun /* */
3405*4882a593Smuzhiyun /* Routine Name: ips_scmd_buf_write */
3406*4882a593Smuzhiyun /* */
3407*4882a593Smuzhiyun /* Routine Description: */
3408*4882a593Smuzhiyun /* Write data to struct scsi_cmnd request_buffer at proper offsets */
3409*4882a593Smuzhiyun /****************************************************************************/
3410*4882a593Smuzhiyun static void
ips_scmd_buf_write(struct scsi_cmnd * scmd,void * data,unsigned int count)3411*4882a593Smuzhiyun ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
3412*4882a593Smuzhiyun {
3413*4882a593Smuzhiyun unsigned long flags;
3414*4882a593Smuzhiyun
3415*4882a593Smuzhiyun local_irq_save(flags);
3416*4882a593Smuzhiyun scsi_sg_copy_from_buffer(scmd, data, count);
3417*4882a593Smuzhiyun local_irq_restore(flags);
3418*4882a593Smuzhiyun }
3419*4882a593Smuzhiyun
3420*4882a593Smuzhiyun /****************************************************************************/
3421*4882a593Smuzhiyun /* */
3422*4882a593Smuzhiyun /* Routine Name: ips_scmd_buf_read */
3423*4882a593Smuzhiyun /* */
3424*4882a593Smuzhiyun /* Routine Description: */
3425*4882a593Smuzhiyun /* Copy data from a struct scsi_cmnd to a new, linear buffer */
3426*4882a593Smuzhiyun /****************************************************************************/
3427*4882a593Smuzhiyun static void
ips_scmd_buf_read(struct scsi_cmnd * scmd,void * data,unsigned int count)3428*4882a593Smuzhiyun ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
3429*4882a593Smuzhiyun {
3430*4882a593Smuzhiyun unsigned long flags;
3431*4882a593Smuzhiyun
3432*4882a593Smuzhiyun local_irq_save(flags);
3433*4882a593Smuzhiyun scsi_sg_copy_to_buffer(scmd, data, count);
3434*4882a593Smuzhiyun local_irq_restore(flags);
3435*4882a593Smuzhiyun }
3436*4882a593Smuzhiyun
3437*4882a593Smuzhiyun /****************************************************************************/
3438*4882a593Smuzhiyun /* */
3439*4882a593Smuzhiyun /* Routine Name: ips_send_cmd */
3440*4882a593Smuzhiyun /* */
3441*4882a593Smuzhiyun /* Routine Description: */
3442*4882a593Smuzhiyun /* */
3443*4882a593Smuzhiyun /* Map SCSI commands to ServeRAID commands for logical drives */
3444*4882a593Smuzhiyun /* */
3445*4882a593Smuzhiyun /****************************************************************************/
3446*4882a593Smuzhiyun static int
ips_send_cmd(ips_ha_t * ha,ips_scb_t * scb)3447*4882a593Smuzhiyun ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
3448*4882a593Smuzhiyun {
3449*4882a593Smuzhiyun int ret;
3450*4882a593Smuzhiyun char *sp;
3451*4882a593Smuzhiyun int device_error;
3452*4882a593Smuzhiyun IPS_DCDB_TABLE_TAPE *tapeDCDB;
3453*4882a593Smuzhiyun int TimeOut;
3454*4882a593Smuzhiyun
3455*4882a593Smuzhiyun METHOD_TRACE("ips_send_cmd", 1);
3456*4882a593Smuzhiyun
3457*4882a593Smuzhiyun ret = IPS_SUCCESS;
3458*4882a593Smuzhiyun
3459*4882a593Smuzhiyun if (!scb->scsi_cmd) {
3460*4882a593Smuzhiyun /* internal command */
3461*4882a593Smuzhiyun
3462*4882a593Smuzhiyun if (scb->bus > 0) {
3463*4882a593Smuzhiyun /* Controller commands can't be issued */
3464*4882a593Smuzhiyun /* to real devices -- fail them */
3465*4882a593Smuzhiyun if ((ha->waitflag == TRUE) &&
3466*4882a593Smuzhiyun (ha->cmd_in_progress == scb->cdb[0])) {
3467*4882a593Smuzhiyun ha->waitflag = FALSE;
3468*4882a593Smuzhiyun }
3469*4882a593Smuzhiyun
3470*4882a593Smuzhiyun return (1);
3471*4882a593Smuzhiyun }
3472*4882a593Smuzhiyun } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
3473*4882a593Smuzhiyun /* command to logical bus -- interpret */
3474*4882a593Smuzhiyun ret = IPS_SUCCESS_IMM;
3475*4882a593Smuzhiyun
3476*4882a593Smuzhiyun switch (scb->scsi_cmd->cmnd[0]) {
3477*4882a593Smuzhiyun case ALLOW_MEDIUM_REMOVAL:
3478*4882a593Smuzhiyun case REZERO_UNIT:
3479*4882a593Smuzhiyun case ERASE:
3480*4882a593Smuzhiyun case WRITE_FILEMARKS:
3481*4882a593Smuzhiyun case SPACE:
3482*4882a593Smuzhiyun scb->scsi_cmd->result = DID_ERROR << 16;
3483*4882a593Smuzhiyun break;
3484*4882a593Smuzhiyun
3485*4882a593Smuzhiyun case START_STOP:
3486*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3487*4882a593Smuzhiyun break;
3488*4882a593Smuzhiyun
3489*4882a593Smuzhiyun case TEST_UNIT_READY:
3490*4882a593Smuzhiyun case INQUIRY:
3491*4882a593Smuzhiyun if (scb->target_id == IPS_ADAPTER_ID) {
3492*4882a593Smuzhiyun /*
3493*4882a593Smuzhiyun * Either we have a TUR
3494*4882a593Smuzhiyun * or we have a SCSI inquiry
3495*4882a593Smuzhiyun */
3496*4882a593Smuzhiyun if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
3497*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3498*4882a593Smuzhiyun
3499*4882a593Smuzhiyun if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
3500*4882a593Smuzhiyun IPS_SCSI_INQ_DATA inquiry;
3501*4882a593Smuzhiyun
3502*4882a593Smuzhiyun memset(&inquiry, 0,
3503*4882a593Smuzhiyun sizeof (IPS_SCSI_INQ_DATA));
3504*4882a593Smuzhiyun
3505*4882a593Smuzhiyun inquiry.DeviceType =
3506*4882a593Smuzhiyun IPS_SCSI_INQ_TYPE_PROCESSOR;
3507*4882a593Smuzhiyun inquiry.DeviceTypeQualifier =
3508*4882a593Smuzhiyun IPS_SCSI_INQ_LU_CONNECTED;
3509*4882a593Smuzhiyun inquiry.Version = IPS_SCSI_INQ_REV2;
3510*4882a593Smuzhiyun inquiry.ResponseDataFormat =
3511*4882a593Smuzhiyun IPS_SCSI_INQ_RD_REV2;
3512*4882a593Smuzhiyun inquiry.AdditionalLength = 31;
3513*4882a593Smuzhiyun inquiry.Flags[0] =
3514*4882a593Smuzhiyun IPS_SCSI_INQ_Address16;
3515*4882a593Smuzhiyun inquiry.Flags[1] =
3516*4882a593Smuzhiyun IPS_SCSI_INQ_WBus16 |
3517*4882a593Smuzhiyun IPS_SCSI_INQ_Sync;
3518*4882a593Smuzhiyun memcpy(inquiry.VendorId, "IBM ",
3519*4882a593Smuzhiyun 8);
3520*4882a593Smuzhiyun memcpy(inquiry.ProductId,
3521*4882a593Smuzhiyun "SERVERAID ", 16);
3522*4882a593Smuzhiyun memcpy(inquiry.ProductRevisionLevel,
3523*4882a593Smuzhiyun "1.00", 4);
3524*4882a593Smuzhiyun
3525*4882a593Smuzhiyun ips_scmd_buf_write(scb->scsi_cmd,
3526*4882a593Smuzhiyun &inquiry,
3527*4882a593Smuzhiyun sizeof (inquiry));
3528*4882a593Smuzhiyun
3529*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3530*4882a593Smuzhiyun }
3531*4882a593Smuzhiyun } else {
3532*4882a593Smuzhiyun scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
3533*4882a593Smuzhiyun scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
3534*4882a593Smuzhiyun scb->cmd.logical_info.reserved = 0;
3535*4882a593Smuzhiyun scb->cmd.logical_info.reserved2 = 0;
3536*4882a593Smuzhiyun scb->data_len = sizeof (IPS_LD_INFO);
3537*4882a593Smuzhiyun scb->data_busaddr = ha->logical_drive_info_dma_addr;
3538*4882a593Smuzhiyun scb->flags = 0;
3539*4882a593Smuzhiyun scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
3540*4882a593Smuzhiyun ret = IPS_SUCCESS;
3541*4882a593Smuzhiyun }
3542*4882a593Smuzhiyun
3543*4882a593Smuzhiyun break;
3544*4882a593Smuzhiyun
3545*4882a593Smuzhiyun case REQUEST_SENSE:
3546*4882a593Smuzhiyun ips_reqsen(ha, scb);
3547*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3548*4882a593Smuzhiyun break;
3549*4882a593Smuzhiyun
3550*4882a593Smuzhiyun case READ_6:
3551*4882a593Smuzhiyun case WRITE_6:
3552*4882a593Smuzhiyun if (!scb->sg_len) {
3553*4882a593Smuzhiyun scb->cmd.basic_io.op_code =
3554*4882a593Smuzhiyun (scb->scsi_cmd->cmnd[0] ==
3555*4882a593Smuzhiyun READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
3556*4882a593Smuzhiyun scb->cmd.basic_io.enhanced_sg = 0;
3557*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr =
3558*4882a593Smuzhiyun cpu_to_le32(scb->data_busaddr);
3559*4882a593Smuzhiyun } else {
3560*4882a593Smuzhiyun scb->cmd.basic_io.op_code =
3561*4882a593Smuzhiyun (scb->scsi_cmd->cmnd[0] ==
3562*4882a593Smuzhiyun READ_6) ? IPS_CMD_READ_SG :
3563*4882a593Smuzhiyun IPS_CMD_WRITE_SG;
3564*4882a593Smuzhiyun scb->cmd.basic_io.enhanced_sg =
3565*4882a593Smuzhiyun IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
3566*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr =
3567*4882a593Smuzhiyun cpu_to_le32(scb->sg_busaddr);
3568*4882a593Smuzhiyun }
3569*4882a593Smuzhiyun
3570*4882a593Smuzhiyun scb->cmd.basic_io.segment_4G = 0;
3571*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
3572*4882a593Smuzhiyun scb->cmd.basic_io.log_drv = scb->target_id;
3573*4882a593Smuzhiyun scb->cmd.basic_io.sg_count = scb->sg_len;
3574*4882a593Smuzhiyun
3575*4882a593Smuzhiyun if (scb->cmd.basic_io.lba)
3576*4882a593Smuzhiyun le32_add_cpu(&scb->cmd.basic_io.lba,
3577*4882a593Smuzhiyun le16_to_cpu(scb->cmd.basic_io.
3578*4882a593Smuzhiyun sector_count));
3579*4882a593Smuzhiyun else
3580*4882a593Smuzhiyun scb->cmd.basic_io.lba =
3581*4882a593Smuzhiyun (((scb->scsi_cmd->
3582*4882a593Smuzhiyun cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd->
3583*4882a593Smuzhiyun cmnd[2] << 8) |
3584*4882a593Smuzhiyun (scb->scsi_cmd->cmnd[3]));
3585*4882a593Smuzhiyun
3586*4882a593Smuzhiyun scb->cmd.basic_io.sector_count =
3587*4882a593Smuzhiyun cpu_to_le16(scb->data_len / IPS_BLKSIZE);
3588*4882a593Smuzhiyun
3589*4882a593Smuzhiyun if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
3590*4882a593Smuzhiyun scb->cmd.basic_io.sector_count =
3591*4882a593Smuzhiyun cpu_to_le16(256);
3592*4882a593Smuzhiyun
3593*4882a593Smuzhiyun ret = IPS_SUCCESS;
3594*4882a593Smuzhiyun break;
3595*4882a593Smuzhiyun
3596*4882a593Smuzhiyun case READ_10:
3597*4882a593Smuzhiyun case WRITE_10:
3598*4882a593Smuzhiyun if (!scb->sg_len) {
3599*4882a593Smuzhiyun scb->cmd.basic_io.op_code =
3600*4882a593Smuzhiyun (scb->scsi_cmd->cmnd[0] ==
3601*4882a593Smuzhiyun READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
3602*4882a593Smuzhiyun scb->cmd.basic_io.enhanced_sg = 0;
3603*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr =
3604*4882a593Smuzhiyun cpu_to_le32(scb->data_busaddr);
3605*4882a593Smuzhiyun } else {
3606*4882a593Smuzhiyun scb->cmd.basic_io.op_code =
3607*4882a593Smuzhiyun (scb->scsi_cmd->cmnd[0] ==
3608*4882a593Smuzhiyun READ_10) ? IPS_CMD_READ_SG :
3609*4882a593Smuzhiyun IPS_CMD_WRITE_SG;
3610*4882a593Smuzhiyun scb->cmd.basic_io.enhanced_sg =
3611*4882a593Smuzhiyun IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
3612*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr =
3613*4882a593Smuzhiyun cpu_to_le32(scb->sg_busaddr);
3614*4882a593Smuzhiyun }
3615*4882a593Smuzhiyun
3616*4882a593Smuzhiyun scb->cmd.basic_io.segment_4G = 0;
3617*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
3618*4882a593Smuzhiyun scb->cmd.basic_io.log_drv = scb->target_id;
3619*4882a593Smuzhiyun scb->cmd.basic_io.sg_count = scb->sg_len;
3620*4882a593Smuzhiyun
3621*4882a593Smuzhiyun if (scb->cmd.basic_io.lba)
3622*4882a593Smuzhiyun le32_add_cpu(&scb->cmd.basic_io.lba,
3623*4882a593Smuzhiyun le16_to_cpu(scb->cmd.basic_io.
3624*4882a593Smuzhiyun sector_count));
3625*4882a593Smuzhiyun else
3626*4882a593Smuzhiyun scb->cmd.basic_io.lba =
3627*4882a593Smuzhiyun ((scb->scsi_cmd->cmnd[2] << 24) | (scb->
3628*4882a593Smuzhiyun scsi_cmd->
3629*4882a593Smuzhiyun cmnd[3]
3630*4882a593Smuzhiyun << 16) |
3631*4882a593Smuzhiyun (scb->scsi_cmd->cmnd[4] << 8) | scb->
3632*4882a593Smuzhiyun scsi_cmd->cmnd[5]);
3633*4882a593Smuzhiyun
3634*4882a593Smuzhiyun scb->cmd.basic_io.sector_count =
3635*4882a593Smuzhiyun cpu_to_le16(scb->data_len / IPS_BLKSIZE);
3636*4882a593Smuzhiyun
3637*4882a593Smuzhiyun if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
3638*4882a593Smuzhiyun /*
3639*4882a593Smuzhiyun * This is a null condition
3640*4882a593Smuzhiyun * we don't have to do anything
3641*4882a593Smuzhiyun * so just return
3642*4882a593Smuzhiyun */
3643*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3644*4882a593Smuzhiyun } else
3645*4882a593Smuzhiyun ret = IPS_SUCCESS;
3646*4882a593Smuzhiyun
3647*4882a593Smuzhiyun break;
3648*4882a593Smuzhiyun
3649*4882a593Smuzhiyun case RESERVE:
3650*4882a593Smuzhiyun case RELEASE:
3651*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3652*4882a593Smuzhiyun break;
3653*4882a593Smuzhiyun
3654*4882a593Smuzhiyun case MODE_SENSE:
3655*4882a593Smuzhiyun scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
3656*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
3657*4882a593Smuzhiyun scb->cmd.basic_io.segment_4G = 0;
3658*4882a593Smuzhiyun scb->cmd.basic_io.enhanced_sg = 0;
3659*4882a593Smuzhiyun scb->data_len = sizeof (*ha->enq);
3660*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
3661*4882a593Smuzhiyun ret = IPS_SUCCESS;
3662*4882a593Smuzhiyun break;
3663*4882a593Smuzhiyun
3664*4882a593Smuzhiyun case READ_CAPACITY:
3665*4882a593Smuzhiyun scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
3666*4882a593Smuzhiyun scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
3667*4882a593Smuzhiyun scb->cmd.logical_info.reserved = 0;
3668*4882a593Smuzhiyun scb->cmd.logical_info.reserved2 = 0;
3669*4882a593Smuzhiyun scb->cmd.logical_info.reserved3 = 0;
3670*4882a593Smuzhiyun scb->data_len = sizeof (IPS_LD_INFO);
3671*4882a593Smuzhiyun scb->data_busaddr = ha->logical_drive_info_dma_addr;
3672*4882a593Smuzhiyun scb->flags = 0;
3673*4882a593Smuzhiyun scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
3674*4882a593Smuzhiyun ret = IPS_SUCCESS;
3675*4882a593Smuzhiyun break;
3676*4882a593Smuzhiyun
3677*4882a593Smuzhiyun case SEND_DIAGNOSTIC:
3678*4882a593Smuzhiyun case REASSIGN_BLOCKS:
3679*4882a593Smuzhiyun case FORMAT_UNIT:
3680*4882a593Smuzhiyun case SEEK_10:
3681*4882a593Smuzhiyun case VERIFY:
3682*4882a593Smuzhiyun case READ_DEFECT_DATA:
3683*4882a593Smuzhiyun case READ_BUFFER:
3684*4882a593Smuzhiyun case WRITE_BUFFER:
3685*4882a593Smuzhiyun scb->scsi_cmd->result = DID_OK << 16;
3686*4882a593Smuzhiyun break;
3687*4882a593Smuzhiyun
3688*4882a593Smuzhiyun default:
3689*4882a593Smuzhiyun /* Set the Return Info to appear like the Command was */
3690*4882a593Smuzhiyun /* attempted, a Check Condition occurred, and Sense */
3691*4882a593Smuzhiyun /* Data indicating an Invalid CDB OpCode is returned. */
3692*4882a593Smuzhiyun sp = (char *) scb->scsi_cmd->sense_buffer;
3693*4882a593Smuzhiyun
3694*4882a593Smuzhiyun sp[0] = 0x70; /* Error Code */
3695*4882a593Smuzhiyun sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */
3696*4882a593Smuzhiyun sp[7] = 0x0A; /* Additional Sense Length */
3697*4882a593Smuzhiyun sp[12] = 0x20; /* ASC = Invalid OpCode */
3698*4882a593Smuzhiyun sp[13] = 0x00; /* ASCQ */
3699*4882a593Smuzhiyun
3700*4882a593Smuzhiyun device_error = 2; /* Indicate Check Condition */
3701*4882a593Smuzhiyun scb->scsi_cmd->result = device_error | (DID_OK << 16);
3702*4882a593Smuzhiyun break;
3703*4882a593Smuzhiyun } /* end switch */
3704*4882a593Smuzhiyun }
3705*4882a593Smuzhiyun /* end if */
3706*4882a593Smuzhiyun if (ret == IPS_SUCCESS_IMM)
3707*4882a593Smuzhiyun return (ret);
3708*4882a593Smuzhiyun
3709*4882a593Smuzhiyun /* setup DCDB */
3710*4882a593Smuzhiyun if (scb->bus > 0) {
3711*4882a593Smuzhiyun
3712*4882a593Smuzhiyun /* If we already know the Device is Not there, no need to attempt a Command */
3713*4882a593Smuzhiyun /* This also protects an NT FailOver Controller from getting CDB's sent to it */
3714*4882a593Smuzhiyun if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) {
3715*4882a593Smuzhiyun scb->scsi_cmd->result = DID_NO_CONNECT << 16;
3716*4882a593Smuzhiyun return (IPS_SUCCESS_IMM);
3717*4882a593Smuzhiyun }
3718*4882a593Smuzhiyun
3719*4882a593Smuzhiyun ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id);
3720*4882a593Smuzhiyun scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
3721*4882a593Smuzhiyun scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
3722*4882a593Smuzhiyun (unsigned long) &scb->
3723*4882a593Smuzhiyun dcdb -
3724*4882a593Smuzhiyun (unsigned long) scb);
3725*4882a593Smuzhiyun scb->cmd.dcdb.reserved = 0;
3726*4882a593Smuzhiyun scb->cmd.dcdb.reserved2 = 0;
3727*4882a593Smuzhiyun scb->cmd.dcdb.reserved3 = 0;
3728*4882a593Smuzhiyun scb->cmd.dcdb.segment_4G = 0;
3729*4882a593Smuzhiyun scb->cmd.dcdb.enhanced_sg = 0;
3730*4882a593Smuzhiyun
3731*4882a593Smuzhiyun TimeOut = scb->scsi_cmd->request->timeout;
3732*4882a593Smuzhiyun
3733*4882a593Smuzhiyun if (ha->subsys->param[4] & 0x00100000) { /* If NEW Tape DCDB is Supported */
3734*4882a593Smuzhiyun if (!scb->sg_len) {
3735*4882a593Smuzhiyun scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
3736*4882a593Smuzhiyun } else {
3737*4882a593Smuzhiyun scb->cmd.dcdb.op_code =
3738*4882a593Smuzhiyun IPS_CMD_EXTENDED_DCDB_SG;
3739*4882a593Smuzhiyun scb->cmd.dcdb.enhanced_sg =
3740*4882a593Smuzhiyun IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
3741*4882a593Smuzhiyun }
3742*4882a593Smuzhiyun
3743*4882a593Smuzhiyun tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; /* Use Same Data Area as Old DCDB Struct */
3744*4882a593Smuzhiyun tapeDCDB->device_address =
3745*4882a593Smuzhiyun ((scb->bus - 1) << 4) | scb->target_id;
3746*4882a593Smuzhiyun tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
3747*4882a593Smuzhiyun tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K; /* Always Turn OFF 64K Size Flag */
3748*4882a593Smuzhiyun
3749*4882a593Smuzhiyun if (TimeOut) {
3750*4882a593Smuzhiyun if (TimeOut < (10 * HZ))
3751*4882a593Smuzhiyun tapeDCDB->cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */
3752*4882a593Smuzhiyun else if (TimeOut < (60 * HZ))
3753*4882a593Smuzhiyun tapeDCDB->cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */
3754*4882a593Smuzhiyun else if (TimeOut < (1200 * HZ))
3755*4882a593Smuzhiyun tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */
3756*4882a593Smuzhiyun }
3757*4882a593Smuzhiyun
3758*4882a593Smuzhiyun tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
3759*4882a593Smuzhiyun tapeDCDB->reserved_for_LUN = 0;
3760*4882a593Smuzhiyun tapeDCDB->transfer_length = scb->data_len;
3761*4882a593Smuzhiyun if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)
3762*4882a593Smuzhiyun tapeDCDB->buffer_pointer =
3763*4882a593Smuzhiyun cpu_to_le32(scb->sg_busaddr);
3764*4882a593Smuzhiyun else
3765*4882a593Smuzhiyun tapeDCDB->buffer_pointer =
3766*4882a593Smuzhiyun cpu_to_le32(scb->data_busaddr);
3767*4882a593Smuzhiyun tapeDCDB->sg_count = scb->sg_len;
3768*4882a593Smuzhiyun tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info);
3769*4882a593Smuzhiyun tapeDCDB->scsi_status = 0;
3770*4882a593Smuzhiyun tapeDCDB->reserved = 0;
3771*4882a593Smuzhiyun memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd,
3772*4882a593Smuzhiyun scb->scsi_cmd->cmd_len);
3773*4882a593Smuzhiyun } else {
3774*4882a593Smuzhiyun if (!scb->sg_len) {
3775*4882a593Smuzhiyun scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
3776*4882a593Smuzhiyun } else {
3777*4882a593Smuzhiyun scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
3778*4882a593Smuzhiyun scb->cmd.dcdb.enhanced_sg =
3779*4882a593Smuzhiyun IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
3780*4882a593Smuzhiyun }
3781*4882a593Smuzhiyun
3782*4882a593Smuzhiyun scb->dcdb.device_address =
3783*4882a593Smuzhiyun ((scb->bus - 1) << 4) | scb->target_id;
3784*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
3785*4882a593Smuzhiyun
3786*4882a593Smuzhiyun if (TimeOut) {
3787*4882a593Smuzhiyun if (TimeOut < (10 * HZ))
3788*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */
3789*4882a593Smuzhiyun else if (TimeOut < (60 * HZ))
3790*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */
3791*4882a593Smuzhiyun else if (TimeOut < (1200 * HZ))
3792*4882a593Smuzhiyun scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */
3793*4882a593Smuzhiyun }
3794*4882a593Smuzhiyun
3795*4882a593Smuzhiyun scb->dcdb.transfer_length = scb->data_len;
3796*4882a593Smuzhiyun if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K)
3797*4882a593Smuzhiyun scb->dcdb.transfer_length = 0;
3798*4882a593Smuzhiyun if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG)
3799*4882a593Smuzhiyun scb->dcdb.buffer_pointer =
3800*4882a593Smuzhiyun cpu_to_le32(scb->sg_busaddr);
3801*4882a593Smuzhiyun else
3802*4882a593Smuzhiyun scb->dcdb.buffer_pointer =
3803*4882a593Smuzhiyun cpu_to_le32(scb->data_busaddr);
3804*4882a593Smuzhiyun scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
3805*4882a593Smuzhiyun scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info);
3806*4882a593Smuzhiyun scb->dcdb.sg_count = scb->sg_len;
3807*4882a593Smuzhiyun scb->dcdb.reserved = 0;
3808*4882a593Smuzhiyun memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd,
3809*4882a593Smuzhiyun scb->scsi_cmd->cmd_len);
3810*4882a593Smuzhiyun scb->dcdb.scsi_status = 0;
3811*4882a593Smuzhiyun scb->dcdb.reserved2[0] = 0;
3812*4882a593Smuzhiyun scb->dcdb.reserved2[1] = 0;
3813*4882a593Smuzhiyun scb->dcdb.reserved2[2] = 0;
3814*4882a593Smuzhiyun }
3815*4882a593Smuzhiyun }
3816*4882a593Smuzhiyun
3817*4882a593Smuzhiyun return ((*ha->func.issue) (ha, scb));
3818*4882a593Smuzhiyun }
3819*4882a593Smuzhiyun
3820*4882a593Smuzhiyun /****************************************************************************/
3821*4882a593Smuzhiyun /* */
3822*4882a593Smuzhiyun /* Routine Name: ips_chk_status */
3823*4882a593Smuzhiyun /* */
3824*4882a593Smuzhiyun /* Routine Description: */
3825*4882a593Smuzhiyun /* */
3826*4882a593Smuzhiyun /* Check the status of commands to logical drives */
3827*4882a593Smuzhiyun /* Assumed to be called with the HA lock */
3828*4882a593Smuzhiyun /****************************************************************************/
3829*4882a593Smuzhiyun static void
ips_chkstatus(ips_ha_t * ha,IPS_STATUS * pstatus)3830*4882a593Smuzhiyun ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
3831*4882a593Smuzhiyun {
3832*4882a593Smuzhiyun ips_scb_t *scb;
3833*4882a593Smuzhiyun ips_stat_t *sp;
3834*4882a593Smuzhiyun uint8_t basic_status;
3835*4882a593Smuzhiyun uint8_t ext_status;
3836*4882a593Smuzhiyun int errcode;
3837*4882a593Smuzhiyun IPS_SCSI_INQ_DATA inquiryData;
3838*4882a593Smuzhiyun
3839*4882a593Smuzhiyun METHOD_TRACE("ips_chkstatus", 1);
3840*4882a593Smuzhiyun
3841*4882a593Smuzhiyun scb = &ha->scbs[pstatus->fields.command_id];
3842*4882a593Smuzhiyun scb->basic_status = basic_status =
3843*4882a593Smuzhiyun pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
3844*4882a593Smuzhiyun scb->extended_status = ext_status = pstatus->fields.extended_status;
3845*4882a593Smuzhiyun
3846*4882a593Smuzhiyun sp = &ha->sp;
3847*4882a593Smuzhiyun sp->residue_len = 0;
3848*4882a593Smuzhiyun sp->scb_addr = (void *) scb;
3849*4882a593Smuzhiyun
3850*4882a593Smuzhiyun /* Remove the item from the active queue */
3851*4882a593Smuzhiyun ips_removeq_scb(&ha->scb_activelist, scb);
3852*4882a593Smuzhiyun
3853*4882a593Smuzhiyun if (!scb->scsi_cmd)
3854*4882a593Smuzhiyun /* internal commands are handled in do_ipsintr */
3855*4882a593Smuzhiyun return;
3856*4882a593Smuzhiyun
3857*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
3858*4882a593Smuzhiyun ips_name,
3859*4882a593Smuzhiyun ha->host_num,
3860*4882a593Smuzhiyun scb->cdb[0],
3861*4882a593Smuzhiyun scb->cmd.basic_io.command_id,
3862*4882a593Smuzhiyun scb->bus, scb->target_id, scb->lun);
3863*4882a593Smuzhiyun
3864*4882a593Smuzhiyun if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
3865*4882a593Smuzhiyun /* passthru - just returns the raw result */
3866*4882a593Smuzhiyun return;
3867*4882a593Smuzhiyun
3868*4882a593Smuzhiyun errcode = DID_OK;
3869*4882a593Smuzhiyun
3870*4882a593Smuzhiyun if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
3871*4882a593Smuzhiyun ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
3872*4882a593Smuzhiyun
3873*4882a593Smuzhiyun if (scb->bus == 0) {
3874*4882a593Smuzhiyun if ((basic_status & IPS_GSC_STATUS_MASK) ==
3875*4882a593Smuzhiyun IPS_CMD_RECOVERED_ERROR) {
3876*4882a593Smuzhiyun DEBUG_VAR(1,
3877*4882a593Smuzhiyun "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
3878*4882a593Smuzhiyun ips_name, ha->host_num,
3879*4882a593Smuzhiyun scb->cmd.basic_io.op_code,
3880*4882a593Smuzhiyun basic_status, ext_status);
3881*4882a593Smuzhiyun }
3882*4882a593Smuzhiyun
3883*4882a593Smuzhiyun switch (scb->scsi_cmd->cmnd[0]) {
3884*4882a593Smuzhiyun case ALLOW_MEDIUM_REMOVAL:
3885*4882a593Smuzhiyun case REZERO_UNIT:
3886*4882a593Smuzhiyun case ERASE:
3887*4882a593Smuzhiyun case WRITE_FILEMARKS:
3888*4882a593Smuzhiyun case SPACE:
3889*4882a593Smuzhiyun errcode = DID_ERROR;
3890*4882a593Smuzhiyun break;
3891*4882a593Smuzhiyun
3892*4882a593Smuzhiyun case START_STOP:
3893*4882a593Smuzhiyun break;
3894*4882a593Smuzhiyun
3895*4882a593Smuzhiyun case TEST_UNIT_READY:
3896*4882a593Smuzhiyun if (!ips_online(ha, scb)) {
3897*4882a593Smuzhiyun errcode = DID_TIME_OUT;
3898*4882a593Smuzhiyun }
3899*4882a593Smuzhiyun break;
3900*4882a593Smuzhiyun
3901*4882a593Smuzhiyun case INQUIRY:
3902*4882a593Smuzhiyun if (ips_online(ha, scb)) {
3903*4882a593Smuzhiyun ips_inquiry(ha, scb);
3904*4882a593Smuzhiyun } else {
3905*4882a593Smuzhiyun errcode = DID_TIME_OUT;
3906*4882a593Smuzhiyun }
3907*4882a593Smuzhiyun break;
3908*4882a593Smuzhiyun
3909*4882a593Smuzhiyun case REQUEST_SENSE:
3910*4882a593Smuzhiyun ips_reqsen(ha, scb);
3911*4882a593Smuzhiyun break;
3912*4882a593Smuzhiyun
3913*4882a593Smuzhiyun case READ_6:
3914*4882a593Smuzhiyun case WRITE_6:
3915*4882a593Smuzhiyun case READ_10:
3916*4882a593Smuzhiyun case WRITE_10:
3917*4882a593Smuzhiyun case RESERVE:
3918*4882a593Smuzhiyun case RELEASE:
3919*4882a593Smuzhiyun break;
3920*4882a593Smuzhiyun
3921*4882a593Smuzhiyun case MODE_SENSE:
3922*4882a593Smuzhiyun if (!ips_online(ha, scb)
3923*4882a593Smuzhiyun || !ips_msense(ha, scb)) {
3924*4882a593Smuzhiyun errcode = DID_ERROR;
3925*4882a593Smuzhiyun }
3926*4882a593Smuzhiyun break;
3927*4882a593Smuzhiyun
3928*4882a593Smuzhiyun case READ_CAPACITY:
3929*4882a593Smuzhiyun if (ips_online(ha, scb))
3930*4882a593Smuzhiyun ips_rdcap(ha, scb);
3931*4882a593Smuzhiyun else {
3932*4882a593Smuzhiyun errcode = DID_TIME_OUT;
3933*4882a593Smuzhiyun }
3934*4882a593Smuzhiyun break;
3935*4882a593Smuzhiyun
3936*4882a593Smuzhiyun case SEND_DIAGNOSTIC:
3937*4882a593Smuzhiyun case REASSIGN_BLOCKS:
3938*4882a593Smuzhiyun break;
3939*4882a593Smuzhiyun
3940*4882a593Smuzhiyun case FORMAT_UNIT:
3941*4882a593Smuzhiyun errcode = DID_ERROR;
3942*4882a593Smuzhiyun break;
3943*4882a593Smuzhiyun
3944*4882a593Smuzhiyun case SEEK_10:
3945*4882a593Smuzhiyun case VERIFY:
3946*4882a593Smuzhiyun case READ_DEFECT_DATA:
3947*4882a593Smuzhiyun case READ_BUFFER:
3948*4882a593Smuzhiyun case WRITE_BUFFER:
3949*4882a593Smuzhiyun break;
3950*4882a593Smuzhiyun
3951*4882a593Smuzhiyun default:
3952*4882a593Smuzhiyun errcode = DID_ERROR;
3953*4882a593Smuzhiyun } /* end switch */
3954*4882a593Smuzhiyun
3955*4882a593Smuzhiyun scb->scsi_cmd->result = errcode << 16;
3956*4882a593Smuzhiyun } else { /* bus == 0 */
3957*4882a593Smuzhiyun /* restrict access to physical drives */
3958*4882a593Smuzhiyun if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
3959*4882a593Smuzhiyun ips_scmd_buf_read(scb->scsi_cmd,
3960*4882a593Smuzhiyun &inquiryData, sizeof (inquiryData));
3961*4882a593Smuzhiyun if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK)
3962*4882a593Smuzhiyun scb->scsi_cmd->result = DID_TIME_OUT << 16;
3963*4882a593Smuzhiyun }
3964*4882a593Smuzhiyun } /* else */
3965*4882a593Smuzhiyun } else { /* recovered error / success */
3966*4882a593Smuzhiyun if (scb->bus == 0) {
3967*4882a593Smuzhiyun DEBUG_VAR(1,
3968*4882a593Smuzhiyun "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
3969*4882a593Smuzhiyun ips_name, ha->host_num,
3970*4882a593Smuzhiyun scb->cmd.basic_io.op_code, basic_status,
3971*4882a593Smuzhiyun ext_status);
3972*4882a593Smuzhiyun }
3973*4882a593Smuzhiyun
3974*4882a593Smuzhiyun ips_map_status(ha, scb, sp);
3975*4882a593Smuzhiyun } /* else */
3976*4882a593Smuzhiyun }
3977*4882a593Smuzhiyun
3978*4882a593Smuzhiyun /****************************************************************************/
3979*4882a593Smuzhiyun /* */
3980*4882a593Smuzhiyun /* Routine Name: ips_online */
3981*4882a593Smuzhiyun /* */
3982*4882a593Smuzhiyun /* Routine Description: */
3983*4882a593Smuzhiyun /* */
3984*4882a593Smuzhiyun /* Determine if a logical drive is online */
3985*4882a593Smuzhiyun /* */
3986*4882a593Smuzhiyun /****************************************************************************/
3987*4882a593Smuzhiyun static int
ips_online(ips_ha_t * ha,ips_scb_t * scb)3988*4882a593Smuzhiyun ips_online(ips_ha_t * ha, ips_scb_t * scb)
3989*4882a593Smuzhiyun {
3990*4882a593Smuzhiyun METHOD_TRACE("ips_online", 1);
3991*4882a593Smuzhiyun
3992*4882a593Smuzhiyun if (scb->target_id >= IPS_MAX_LD)
3993*4882a593Smuzhiyun return (0);
3994*4882a593Smuzhiyun
3995*4882a593Smuzhiyun if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) {
3996*4882a593Smuzhiyun memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO));
3997*4882a593Smuzhiyun return (0);
3998*4882a593Smuzhiyun }
3999*4882a593Smuzhiyun
4000*4882a593Smuzhiyun if (ha->logical_drive_info->drive_info[scb->target_id].state !=
4001*4882a593Smuzhiyun IPS_LD_OFFLINE
4002*4882a593Smuzhiyun && ha->logical_drive_info->drive_info[scb->target_id].state !=
4003*4882a593Smuzhiyun IPS_LD_FREE
4004*4882a593Smuzhiyun && ha->logical_drive_info->drive_info[scb->target_id].state !=
4005*4882a593Smuzhiyun IPS_LD_CRS
4006*4882a593Smuzhiyun && ha->logical_drive_info->drive_info[scb->target_id].state !=
4007*4882a593Smuzhiyun IPS_LD_SYS)
4008*4882a593Smuzhiyun return (1);
4009*4882a593Smuzhiyun else
4010*4882a593Smuzhiyun return (0);
4011*4882a593Smuzhiyun }
4012*4882a593Smuzhiyun
4013*4882a593Smuzhiyun /****************************************************************************/
4014*4882a593Smuzhiyun /* */
4015*4882a593Smuzhiyun /* Routine Name: ips_inquiry */
4016*4882a593Smuzhiyun /* */
4017*4882a593Smuzhiyun /* Routine Description: */
4018*4882a593Smuzhiyun /* */
4019*4882a593Smuzhiyun /* Simulate an inquiry command to a logical drive */
4020*4882a593Smuzhiyun /* */
4021*4882a593Smuzhiyun /****************************************************************************/
4022*4882a593Smuzhiyun static int
ips_inquiry(ips_ha_t * ha,ips_scb_t * scb)4023*4882a593Smuzhiyun ips_inquiry(ips_ha_t * ha, ips_scb_t * scb)
4024*4882a593Smuzhiyun {
4025*4882a593Smuzhiyun IPS_SCSI_INQ_DATA inquiry;
4026*4882a593Smuzhiyun
4027*4882a593Smuzhiyun METHOD_TRACE("ips_inquiry", 1);
4028*4882a593Smuzhiyun
4029*4882a593Smuzhiyun memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA));
4030*4882a593Smuzhiyun
4031*4882a593Smuzhiyun inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD;
4032*4882a593Smuzhiyun inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
4033*4882a593Smuzhiyun inquiry.Version = IPS_SCSI_INQ_REV2;
4034*4882a593Smuzhiyun inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
4035*4882a593Smuzhiyun inquiry.AdditionalLength = 31;
4036*4882a593Smuzhiyun inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
4037*4882a593Smuzhiyun inquiry.Flags[1] =
4038*4882a593Smuzhiyun IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue;
4039*4882a593Smuzhiyun memcpy(inquiry.VendorId, "IBM ", 8);
4040*4882a593Smuzhiyun memcpy(inquiry.ProductId, "SERVERAID ", 16);
4041*4882a593Smuzhiyun memcpy(inquiry.ProductRevisionLevel, "1.00", 4);
4042*4882a593Smuzhiyun
4043*4882a593Smuzhiyun ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry));
4044*4882a593Smuzhiyun
4045*4882a593Smuzhiyun return (1);
4046*4882a593Smuzhiyun }
4047*4882a593Smuzhiyun
4048*4882a593Smuzhiyun /****************************************************************************/
4049*4882a593Smuzhiyun /* */
4050*4882a593Smuzhiyun /* Routine Name: ips_rdcap */
4051*4882a593Smuzhiyun /* */
4052*4882a593Smuzhiyun /* Routine Description: */
4053*4882a593Smuzhiyun /* */
4054*4882a593Smuzhiyun /* Simulate a read capacity command to a logical drive */
4055*4882a593Smuzhiyun /* */
4056*4882a593Smuzhiyun /****************************************************************************/
4057*4882a593Smuzhiyun static int
ips_rdcap(ips_ha_t * ha,ips_scb_t * scb)4058*4882a593Smuzhiyun ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
4059*4882a593Smuzhiyun {
4060*4882a593Smuzhiyun IPS_SCSI_CAPACITY cap;
4061*4882a593Smuzhiyun
4062*4882a593Smuzhiyun METHOD_TRACE("ips_rdcap", 1);
4063*4882a593Smuzhiyun
4064*4882a593Smuzhiyun if (scsi_bufflen(scb->scsi_cmd) < 8)
4065*4882a593Smuzhiyun return (0);
4066*4882a593Smuzhiyun
4067*4882a593Smuzhiyun cap.lba =
4068*4882a593Smuzhiyun cpu_to_be32(le32_to_cpu
4069*4882a593Smuzhiyun (ha->logical_drive_info->
4070*4882a593Smuzhiyun drive_info[scb->target_id].sector_count) - 1);
4071*4882a593Smuzhiyun cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
4072*4882a593Smuzhiyun
4073*4882a593Smuzhiyun ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap));
4074*4882a593Smuzhiyun
4075*4882a593Smuzhiyun return (1);
4076*4882a593Smuzhiyun }
4077*4882a593Smuzhiyun
4078*4882a593Smuzhiyun /****************************************************************************/
4079*4882a593Smuzhiyun /* */
4080*4882a593Smuzhiyun /* Routine Name: ips_msense */
4081*4882a593Smuzhiyun /* */
4082*4882a593Smuzhiyun /* Routine Description: */
4083*4882a593Smuzhiyun /* */
4084*4882a593Smuzhiyun /* Simulate a mode sense command to a logical drive */
4085*4882a593Smuzhiyun /* */
4086*4882a593Smuzhiyun /****************************************************************************/
4087*4882a593Smuzhiyun static int
ips_msense(ips_ha_t * ha,ips_scb_t * scb)4088*4882a593Smuzhiyun ips_msense(ips_ha_t * ha, ips_scb_t * scb)
4089*4882a593Smuzhiyun {
4090*4882a593Smuzhiyun uint16_t heads;
4091*4882a593Smuzhiyun uint16_t sectors;
4092*4882a593Smuzhiyun uint32_t cylinders;
4093*4882a593Smuzhiyun IPS_SCSI_MODE_PAGE_DATA mdata;
4094*4882a593Smuzhiyun
4095*4882a593Smuzhiyun METHOD_TRACE("ips_msense", 1);
4096*4882a593Smuzhiyun
4097*4882a593Smuzhiyun if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 &&
4098*4882a593Smuzhiyun (ha->enq->ucMiscFlag & 0x8) == 0) {
4099*4882a593Smuzhiyun heads = IPS_NORM_HEADS;
4100*4882a593Smuzhiyun sectors = IPS_NORM_SECTORS;
4101*4882a593Smuzhiyun } else {
4102*4882a593Smuzhiyun heads = IPS_COMP_HEADS;
4103*4882a593Smuzhiyun sectors = IPS_COMP_SECTORS;
4104*4882a593Smuzhiyun }
4105*4882a593Smuzhiyun
4106*4882a593Smuzhiyun cylinders =
4107*4882a593Smuzhiyun (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) -
4108*4882a593Smuzhiyun 1) / (heads * sectors);
4109*4882a593Smuzhiyun
4110*4882a593Smuzhiyun memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA));
4111*4882a593Smuzhiyun
4112*4882a593Smuzhiyun mdata.hdr.BlockDescLength = 8;
4113*4882a593Smuzhiyun
4114*4882a593Smuzhiyun switch (scb->scsi_cmd->cmnd[2] & 0x3f) {
4115*4882a593Smuzhiyun case 0x03: /* page 3 */
4116*4882a593Smuzhiyun mdata.pdata.pg3.PageCode = 3;
4117*4882a593Smuzhiyun mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3);
4118*4882a593Smuzhiyun mdata.hdr.DataLength =
4119*4882a593Smuzhiyun 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength;
4120*4882a593Smuzhiyun mdata.pdata.pg3.TracksPerZone = 0;
4121*4882a593Smuzhiyun mdata.pdata.pg3.AltSectorsPerZone = 0;
4122*4882a593Smuzhiyun mdata.pdata.pg3.AltTracksPerZone = 0;
4123*4882a593Smuzhiyun mdata.pdata.pg3.AltTracksPerVolume = 0;
4124*4882a593Smuzhiyun mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors);
4125*4882a593Smuzhiyun mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE);
4126*4882a593Smuzhiyun mdata.pdata.pg3.Interleave = cpu_to_be16(1);
4127*4882a593Smuzhiyun mdata.pdata.pg3.TrackSkew = 0;
4128*4882a593Smuzhiyun mdata.pdata.pg3.CylinderSkew = 0;
4129*4882a593Smuzhiyun mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector;
4130*4882a593Smuzhiyun break;
4131*4882a593Smuzhiyun
4132*4882a593Smuzhiyun case 0x4:
4133*4882a593Smuzhiyun mdata.pdata.pg4.PageCode = 4;
4134*4882a593Smuzhiyun mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4);
4135*4882a593Smuzhiyun mdata.hdr.DataLength =
4136*4882a593Smuzhiyun 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength;
4137*4882a593Smuzhiyun mdata.pdata.pg4.CylindersHigh =
4138*4882a593Smuzhiyun cpu_to_be16((cylinders >> 8) & 0xFFFF);
4139*4882a593Smuzhiyun mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF);
4140*4882a593Smuzhiyun mdata.pdata.pg4.Heads = heads;
4141*4882a593Smuzhiyun mdata.pdata.pg4.WritePrecompHigh = 0;
4142*4882a593Smuzhiyun mdata.pdata.pg4.WritePrecompLow = 0;
4143*4882a593Smuzhiyun mdata.pdata.pg4.ReducedWriteCurrentHigh = 0;
4144*4882a593Smuzhiyun mdata.pdata.pg4.ReducedWriteCurrentLow = 0;
4145*4882a593Smuzhiyun mdata.pdata.pg4.StepRate = cpu_to_be16(1);
4146*4882a593Smuzhiyun mdata.pdata.pg4.LandingZoneHigh = 0;
4147*4882a593Smuzhiyun mdata.pdata.pg4.LandingZoneLow = 0;
4148*4882a593Smuzhiyun mdata.pdata.pg4.flags = 0;
4149*4882a593Smuzhiyun mdata.pdata.pg4.RotationalOffset = 0;
4150*4882a593Smuzhiyun mdata.pdata.pg4.MediumRotationRate = 0;
4151*4882a593Smuzhiyun break;
4152*4882a593Smuzhiyun case 0x8:
4153*4882a593Smuzhiyun mdata.pdata.pg8.PageCode = 8;
4154*4882a593Smuzhiyun mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8);
4155*4882a593Smuzhiyun mdata.hdr.DataLength =
4156*4882a593Smuzhiyun 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength;
4157*4882a593Smuzhiyun /* everything else is left set to 0 */
4158*4882a593Smuzhiyun break;
4159*4882a593Smuzhiyun
4160*4882a593Smuzhiyun default:
4161*4882a593Smuzhiyun return (0);
4162*4882a593Smuzhiyun } /* end switch */
4163*4882a593Smuzhiyun
4164*4882a593Smuzhiyun ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata));
4165*4882a593Smuzhiyun
4166*4882a593Smuzhiyun return (1);
4167*4882a593Smuzhiyun }
4168*4882a593Smuzhiyun
4169*4882a593Smuzhiyun /****************************************************************************/
4170*4882a593Smuzhiyun /* */
4171*4882a593Smuzhiyun /* Routine Name: ips_reqsen */
4172*4882a593Smuzhiyun /* */
4173*4882a593Smuzhiyun /* Routine Description: */
4174*4882a593Smuzhiyun /* */
4175*4882a593Smuzhiyun /* Simulate a request sense command to a logical drive */
4176*4882a593Smuzhiyun /* */
4177*4882a593Smuzhiyun /****************************************************************************/
4178*4882a593Smuzhiyun static int
ips_reqsen(ips_ha_t * ha,ips_scb_t * scb)4179*4882a593Smuzhiyun ips_reqsen(ips_ha_t * ha, ips_scb_t * scb)
4180*4882a593Smuzhiyun {
4181*4882a593Smuzhiyun IPS_SCSI_REQSEN reqsen;
4182*4882a593Smuzhiyun
4183*4882a593Smuzhiyun METHOD_TRACE("ips_reqsen", 1);
4184*4882a593Smuzhiyun
4185*4882a593Smuzhiyun memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN));
4186*4882a593Smuzhiyun
4187*4882a593Smuzhiyun reqsen.ResponseCode =
4188*4882a593Smuzhiyun IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR;
4189*4882a593Smuzhiyun reqsen.AdditionalLength = 10;
4190*4882a593Smuzhiyun reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE;
4191*4882a593Smuzhiyun reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE;
4192*4882a593Smuzhiyun
4193*4882a593Smuzhiyun ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen));
4194*4882a593Smuzhiyun
4195*4882a593Smuzhiyun return (1);
4196*4882a593Smuzhiyun }
4197*4882a593Smuzhiyun
4198*4882a593Smuzhiyun /****************************************************************************/
4199*4882a593Smuzhiyun /* */
4200*4882a593Smuzhiyun /* Routine Name: ips_free */
4201*4882a593Smuzhiyun /* */
4202*4882a593Smuzhiyun /* Routine Description: */
4203*4882a593Smuzhiyun /* */
4204*4882a593Smuzhiyun /* Free any allocated space for this controller */
4205*4882a593Smuzhiyun /* */
4206*4882a593Smuzhiyun /****************************************************************************/
4207*4882a593Smuzhiyun static void
ips_free(ips_ha_t * ha)4208*4882a593Smuzhiyun ips_free(ips_ha_t * ha)
4209*4882a593Smuzhiyun {
4210*4882a593Smuzhiyun
4211*4882a593Smuzhiyun METHOD_TRACE("ips_free", 1);
4212*4882a593Smuzhiyun
4213*4882a593Smuzhiyun if (ha) {
4214*4882a593Smuzhiyun if (ha->enq) {
4215*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev, sizeof(IPS_ENQ),
4216*4882a593Smuzhiyun ha->enq, ha->enq_busaddr);
4217*4882a593Smuzhiyun ha->enq = NULL;
4218*4882a593Smuzhiyun }
4219*4882a593Smuzhiyun
4220*4882a593Smuzhiyun kfree(ha->conf);
4221*4882a593Smuzhiyun ha->conf = NULL;
4222*4882a593Smuzhiyun
4223*4882a593Smuzhiyun if (ha->adapt) {
4224*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev,
4225*4882a593Smuzhiyun sizeof (IPS_ADAPTER) +
4226*4882a593Smuzhiyun sizeof (IPS_IO_CMD), ha->adapt,
4227*4882a593Smuzhiyun ha->adapt->hw_status_start);
4228*4882a593Smuzhiyun ha->adapt = NULL;
4229*4882a593Smuzhiyun }
4230*4882a593Smuzhiyun
4231*4882a593Smuzhiyun if (ha->logical_drive_info) {
4232*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev,
4233*4882a593Smuzhiyun sizeof (IPS_LD_INFO),
4234*4882a593Smuzhiyun ha->logical_drive_info,
4235*4882a593Smuzhiyun ha->logical_drive_info_dma_addr);
4236*4882a593Smuzhiyun ha->logical_drive_info = NULL;
4237*4882a593Smuzhiyun }
4238*4882a593Smuzhiyun
4239*4882a593Smuzhiyun kfree(ha->nvram);
4240*4882a593Smuzhiyun ha->nvram = NULL;
4241*4882a593Smuzhiyun
4242*4882a593Smuzhiyun kfree(ha->subsys);
4243*4882a593Smuzhiyun ha->subsys = NULL;
4244*4882a593Smuzhiyun
4245*4882a593Smuzhiyun if (ha->ioctl_data) {
4246*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len,
4247*4882a593Smuzhiyun ha->ioctl_data, ha->ioctl_busaddr);
4248*4882a593Smuzhiyun ha->ioctl_data = NULL;
4249*4882a593Smuzhiyun ha->ioctl_datasize = 0;
4250*4882a593Smuzhiyun ha->ioctl_len = 0;
4251*4882a593Smuzhiyun }
4252*4882a593Smuzhiyun ips_deallocatescbs(ha, ha->max_cmds);
4253*4882a593Smuzhiyun
4254*4882a593Smuzhiyun /* free memory mapped (if applicable) */
4255*4882a593Smuzhiyun if (ha->mem_ptr) {
4256*4882a593Smuzhiyun iounmap(ha->ioremap_ptr);
4257*4882a593Smuzhiyun ha->ioremap_ptr = NULL;
4258*4882a593Smuzhiyun ha->mem_ptr = NULL;
4259*4882a593Smuzhiyun }
4260*4882a593Smuzhiyun
4261*4882a593Smuzhiyun ha->mem_addr = 0;
4262*4882a593Smuzhiyun
4263*4882a593Smuzhiyun }
4264*4882a593Smuzhiyun }
4265*4882a593Smuzhiyun
4266*4882a593Smuzhiyun /****************************************************************************/
4267*4882a593Smuzhiyun /* */
4268*4882a593Smuzhiyun /* Routine Name: ips_deallocatescbs */
4269*4882a593Smuzhiyun /* */
4270*4882a593Smuzhiyun /* Routine Description: */
4271*4882a593Smuzhiyun /* */
4272*4882a593Smuzhiyun /* Free the command blocks */
4273*4882a593Smuzhiyun /* */
4274*4882a593Smuzhiyun /****************************************************************************/
4275*4882a593Smuzhiyun static int
ips_deallocatescbs(ips_ha_t * ha,int cmds)4276*4882a593Smuzhiyun ips_deallocatescbs(ips_ha_t * ha, int cmds)
4277*4882a593Smuzhiyun {
4278*4882a593Smuzhiyun if (ha->scbs) {
4279*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev,
4280*4882a593Smuzhiyun IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds,
4281*4882a593Smuzhiyun ha->scbs->sg_list.list,
4282*4882a593Smuzhiyun ha->scbs->sg_busaddr);
4283*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev, sizeof (ips_scb_t) * cmds,
4284*4882a593Smuzhiyun ha->scbs, ha->scbs->scb_busaddr);
4285*4882a593Smuzhiyun ha->scbs = NULL;
4286*4882a593Smuzhiyun } /* end if */
4287*4882a593Smuzhiyun return 1;
4288*4882a593Smuzhiyun }
4289*4882a593Smuzhiyun
4290*4882a593Smuzhiyun /****************************************************************************/
4291*4882a593Smuzhiyun /* */
4292*4882a593Smuzhiyun /* Routine Name: ips_allocatescbs */
4293*4882a593Smuzhiyun /* */
4294*4882a593Smuzhiyun /* Routine Description: */
4295*4882a593Smuzhiyun /* */
4296*4882a593Smuzhiyun /* Allocate the command blocks */
4297*4882a593Smuzhiyun /* */
4298*4882a593Smuzhiyun /****************************************************************************/
4299*4882a593Smuzhiyun static int
ips_allocatescbs(ips_ha_t * ha)4300*4882a593Smuzhiyun ips_allocatescbs(ips_ha_t * ha)
4301*4882a593Smuzhiyun {
4302*4882a593Smuzhiyun ips_scb_t *scb_p;
4303*4882a593Smuzhiyun IPS_SG_LIST ips_sg;
4304*4882a593Smuzhiyun int i;
4305*4882a593Smuzhiyun dma_addr_t command_dma, sg_dma;
4306*4882a593Smuzhiyun
4307*4882a593Smuzhiyun METHOD_TRACE("ips_allocatescbs", 1);
4308*4882a593Smuzhiyun
4309*4882a593Smuzhiyun /* Allocate memory for the SCBs */
4310*4882a593Smuzhiyun ha->scbs = dma_alloc_coherent(&ha->pcidev->dev,
4311*4882a593Smuzhiyun ha->max_cmds * sizeof (ips_scb_t),
4312*4882a593Smuzhiyun &command_dma, GFP_KERNEL);
4313*4882a593Smuzhiyun if (ha->scbs == NULL)
4314*4882a593Smuzhiyun return 0;
4315*4882a593Smuzhiyun ips_sg.list = dma_alloc_coherent(&ha->pcidev->dev,
4316*4882a593Smuzhiyun IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * ha->max_cmds,
4317*4882a593Smuzhiyun &sg_dma, GFP_KERNEL);
4318*4882a593Smuzhiyun if (ips_sg.list == NULL) {
4319*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev,
4320*4882a593Smuzhiyun ha->max_cmds * sizeof (ips_scb_t), ha->scbs,
4321*4882a593Smuzhiyun command_dma);
4322*4882a593Smuzhiyun return 0;
4323*4882a593Smuzhiyun }
4324*4882a593Smuzhiyun
4325*4882a593Smuzhiyun memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t));
4326*4882a593Smuzhiyun
4327*4882a593Smuzhiyun for (i = 0; i < ha->max_cmds; i++) {
4328*4882a593Smuzhiyun scb_p = &ha->scbs[i];
4329*4882a593Smuzhiyun scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i;
4330*4882a593Smuzhiyun /* set up S/G list */
4331*4882a593Smuzhiyun if (IPS_USE_ENH_SGLIST(ha)) {
4332*4882a593Smuzhiyun scb_p->sg_list.enh_list =
4333*4882a593Smuzhiyun ips_sg.enh_list + i * IPS_MAX_SG;
4334*4882a593Smuzhiyun scb_p->sg_busaddr =
4335*4882a593Smuzhiyun sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
4336*4882a593Smuzhiyun } else {
4337*4882a593Smuzhiyun scb_p->sg_list.std_list =
4338*4882a593Smuzhiyun ips_sg.std_list + i * IPS_MAX_SG;
4339*4882a593Smuzhiyun scb_p->sg_busaddr =
4340*4882a593Smuzhiyun sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
4341*4882a593Smuzhiyun }
4342*4882a593Smuzhiyun
4343*4882a593Smuzhiyun /* add to the free list */
4344*4882a593Smuzhiyun if (i < ha->max_cmds - 1) {
4345*4882a593Smuzhiyun scb_p->q_next = ha->scb_freelist;
4346*4882a593Smuzhiyun ha->scb_freelist = scb_p;
4347*4882a593Smuzhiyun }
4348*4882a593Smuzhiyun }
4349*4882a593Smuzhiyun
4350*4882a593Smuzhiyun /* success */
4351*4882a593Smuzhiyun return (1);
4352*4882a593Smuzhiyun }
4353*4882a593Smuzhiyun
4354*4882a593Smuzhiyun /****************************************************************************/
4355*4882a593Smuzhiyun /* */
4356*4882a593Smuzhiyun /* Routine Name: ips_init_scb */
4357*4882a593Smuzhiyun /* */
4358*4882a593Smuzhiyun /* Routine Description: */
4359*4882a593Smuzhiyun /* */
4360*4882a593Smuzhiyun /* Initialize a CCB to default values */
4361*4882a593Smuzhiyun /* */
4362*4882a593Smuzhiyun /****************************************************************************/
4363*4882a593Smuzhiyun static void
ips_init_scb(ips_ha_t * ha,ips_scb_t * scb)4364*4882a593Smuzhiyun ips_init_scb(ips_ha_t * ha, ips_scb_t * scb)
4365*4882a593Smuzhiyun {
4366*4882a593Smuzhiyun IPS_SG_LIST sg_list;
4367*4882a593Smuzhiyun uint32_t cmd_busaddr, sg_busaddr;
4368*4882a593Smuzhiyun METHOD_TRACE("ips_init_scb", 1);
4369*4882a593Smuzhiyun
4370*4882a593Smuzhiyun if (scb == NULL)
4371*4882a593Smuzhiyun return;
4372*4882a593Smuzhiyun
4373*4882a593Smuzhiyun sg_list.list = scb->sg_list.list;
4374*4882a593Smuzhiyun cmd_busaddr = scb->scb_busaddr;
4375*4882a593Smuzhiyun sg_busaddr = scb->sg_busaddr;
4376*4882a593Smuzhiyun /* zero fill */
4377*4882a593Smuzhiyun memset(scb, 0, sizeof (ips_scb_t));
4378*4882a593Smuzhiyun memset(ha->dummy, 0, sizeof (IPS_IO_CMD));
4379*4882a593Smuzhiyun
4380*4882a593Smuzhiyun /* Initialize dummy command bucket */
4381*4882a593Smuzhiyun ha->dummy->op_code = 0xFF;
4382*4882a593Smuzhiyun ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
4383*4882a593Smuzhiyun + sizeof (IPS_ADAPTER));
4384*4882a593Smuzhiyun ha->dummy->command_id = IPS_MAX_CMDS;
4385*4882a593Smuzhiyun
4386*4882a593Smuzhiyun /* set bus address of scb */
4387*4882a593Smuzhiyun scb->scb_busaddr = cmd_busaddr;
4388*4882a593Smuzhiyun scb->sg_busaddr = sg_busaddr;
4389*4882a593Smuzhiyun scb->sg_list.list = sg_list.list;
4390*4882a593Smuzhiyun
4391*4882a593Smuzhiyun /* Neptune Fix */
4392*4882a593Smuzhiyun scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
4393*4882a593Smuzhiyun scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
4394*4882a593Smuzhiyun + sizeof (IPS_ADAPTER));
4395*4882a593Smuzhiyun }
4396*4882a593Smuzhiyun
4397*4882a593Smuzhiyun /****************************************************************************/
4398*4882a593Smuzhiyun /* */
4399*4882a593Smuzhiyun /* Routine Name: ips_get_scb */
4400*4882a593Smuzhiyun /* */
4401*4882a593Smuzhiyun /* Routine Description: */
4402*4882a593Smuzhiyun /* */
4403*4882a593Smuzhiyun /* Initialize a CCB to default values */
4404*4882a593Smuzhiyun /* */
4405*4882a593Smuzhiyun /* ASSUMED to be called from within a lock */
4406*4882a593Smuzhiyun /* */
4407*4882a593Smuzhiyun /****************************************************************************/
4408*4882a593Smuzhiyun static ips_scb_t *
ips_getscb(ips_ha_t * ha)4409*4882a593Smuzhiyun ips_getscb(ips_ha_t * ha)
4410*4882a593Smuzhiyun {
4411*4882a593Smuzhiyun ips_scb_t *scb;
4412*4882a593Smuzhiyun
4413*4882a593Smuzhiyun METHOD_TRACE("ips_getscb", 1);
4414*4882a593Smuzhiyun
4415*4882a593Smuzhiyun if ((scb = ha->scb_freelist) == NULL) {
4416*4882a593Smuzhiyun
4417*4882a593Smuzhiyun return (NULL);
4418*4882a593Smuzhiyun }
4419*4882a593Smuzhiyun
4420*4882a593Smuzhiyun ha->scb_freelist = scb->q_next;
4421*4882a593Smuzhiyun scb->flags = 0;
4422*4882a593Smuzhiyun scb->q_next = NULL;
4423*4882a593Smuzhiyun
4424*4882a593Smuzhiyun ips_init_scb(ha, scb);
4425*4882a593Smuzhiyun
4426*4882a593Smuzhiyun return (scb);
4427*4882a593Smuzhiyun }
4428*4882a593Smuzhiyun
4429*4882a593Smuzhiyun /****************************************************************************/
4430*4882a593Smuzhiyun /* */
4431*4882a593Smuzhiyun /* Routine Name: ips_free_scb */
4432*4882a593Smuzhiyun /* */
4433*4882a593Smuzhiyun /* Routine Description: */
4434*4882a593Smuzhiyun /* */
4435*4882a593Smuzhiyun /* Return an unused CCB back to the free list */
4436*4882a593Smuzhiyun /* */
4437*4882a593Smuzhiyun /* ASSUMED to be called from within a lock */
4438*4882a593Smuzhiyun /* */
4439*4882a593Smuzhiyun /****************************************************************************/
4440*4882a593Smuzhiyun static void
ips_freescb(ips_ha_t * ha,ips_scb_t * scb)4441*4882a593Smuzhiyun ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
4442*4882a593Smuzhiyun {
4443*4882a593Smuzhiyun
4444*4882a593Smuzhiyun METHOD_TRACE("ips_freescb", 1);
4445*4882a593Smuzhiyun if (scb->flags & IPS_SCB_MAP_SG)
4446*4882a593Smuzhiyun scsi_dma_unmap(scb->scsi_cmd);
4447*4882a593Smuzhiyun else if (scb->flags & IPS_SCB_MAP_SINGLE)
4448*4882a593Smuzhiyun dma_unmap_single(&ha->pcidev->dev, scb->data_busaddr,
4449*4882a593Smuzhiyun scb->data_len, IPS_DMA_DIR(scb));
4450*4882a593Smuzhiyun
4451*4882a593Smuzhiyun /* check to make sure this is not our "special" scb */
4452*4882a593Smuzhiyun if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
4453*4882a593Smuzhiyun scb->q_next = ha->scb_freelist;
4454*4882a593Smuzhiyun ha->scb_freelist = scb;
4455*4882a593Smuzhiyun }
4456*4882a593Smuzhiyun }
4457*4882a593Smuzhiyun
4458*4882a593Smuzhiyun /****************************************************************************/
4459*4882a593Smuzhiyun /* */
4460*4882a593Smuzhiyun /* Routine Name: ips_isinit_copperhead */
4461*4882a593Smuzhiyun /* */
4462*4882a593Smuzhiyun /* Routine Description: */
4463*4882a593Smuzhiyun /* */
4464*4882a593Smuzhiyun /* Is controller initialized ? */
4465*4882a593Smuzhiyun /* */
4466*4882a593Smuzhiyun /****************************************************************************/
4467*4882a593Smuzhiyun static int
ips_isinit_copperhead(ips_ha_t * ha)4468*4882a593Smuzhiyun ips_isinit_copperhead(ips_ha_t * ha)
4469*4882a593Smuzhiyun {
4470*4882a593Smuzhiyun uint8_t scpr;
4471*4882a593Smuzhiyun uint8_t isr;
4472*4882a593Smuzhiyun
4473*4882a593Smuzhiyun METHOD_TRACE("ips_isinit_copperhead", 1);
4474*4882a593Smuzhiyun
4475*4882a593Smuzhiyun isr = inb(ha->io_addr + IPS_REG_HISR);
4476*4882a593Smuzhiyun scpr = inb(ha->io_addr + IPS_REG_SCPR);
4477*4882a593Smuzhiyun
4478*4882a593Smuzhiyun if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
4479*4882a593Smuzhiyun return (0);
4480*4882a593Smuzhiyun else
4481*4882a593Smuzhiyun return (1);
4482*4882a593Smuzhiyun }
4483*4882a593Smuzhiyun
4484*4882a593Smuzhiyun /****************************************************************************/
4485*4882a593Smuzhiyun /* */
4486*4882a593Smuzhiyun /* Routine Name: ips_isinit_copperhead_memio */
4487*4882a593Smuzhiyun /* */
4488*4882a593Smuzhiyun /* Routine Description: */
4489*4882a593Smuzhiyun /* */
4490*4882a593Smuzhiyun /* Is controller initialized ? */
4491*4882a593Smuzhiyun /* */
4492*4882a593Smuzhiyun /****************************************************************************/
4493*4882a593Smuzhiyun static int
ips_isinit_copperhead_memio(ips_ha_t * ha)4494*4882a593Smuzhiyun ips_isinit_copperhead_memio(ips_ha_t * ha)
4495*4882a593Smuzhiyun {
4496*4882a593Smuzhiyun uint8_t isr = 0;
4497*4882a593Smuzhiyun uint8_t scpr;
4498*4882a593Smuzhiyun
4499*4882a593Smuzhiyun METHOD_TRACE("ips_is_init_copperhead_memio", 1);
4500*4882a593Smuzhiyun
4501*4882a593Smuzhiyun isr = readb(ha->mem_ptr + IPS_REG_HISR);
4502*4882a593Smuzhiyun scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
4503*4882a593Smuzhiyun
4504*4882a593Smuzhiyun if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
4505*4882a593Smuzhiyun return (0);
4506*4882a593Smuzhiyun else
4507*4882a593Smuzhiyun return (1);
4508*4882a593Smuzhiyun }
4509*4882a593Smuzhiyun
4510*4882a593Smuzhiyun /****************************************************************************/
4511*4882a593Smuzhiyun /* */
4512*4882a593Smuzhiyun /* Routine Name: ips_isinit_morpheus */
4513*4882a593Smuzhiyun /* */
4514*4882a593Smuzhiyun /* Routine Description: */
4515*4882a593Smuzhiyun /* */
4516*4882a593Smuzhiyun /* Is controller initialized ? */
4517*4882a593Smuzhiyun /* */
4518*4882a593Smuzhiyun /****************************************************************************/
4519*4882a593Smuzhiyun static int
ips_isinit_morpheus(ips_ha_t * ha)4520*4882a593Smuzhiyun ips_isinit_morpheus(ips_ha_t * ha)
4521*4882a593Smuzhiyun {
4522*4882a593Smuzhiyun uint32_t post;
4523*4882a593Smuzhiyun uint32_t bits;
4524*4882a593Smuzhiyun
4525*4882a593Smuzhiyun METHOD_TRACE("ips_is_init_morpheus", 1);
4526*4882a593Smuzhiyun
4527*4882a593Smuzhiyun if (ips_isintr_morpheus(ha))
4528*4882a593Smuzhiyun ips_flush_and_reset(ha);
4529*4882a593Smuzhiyun
4530*4882a593Smuzhiyun post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
4531*4882a593Smuzhiyun bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
4532*4882a593Smuzhiyun
4533*4882a593Smuzhiyun if (post == 0)
4534*4882a593Smuzhiyun return (0);
4535*4882a593Smuzhiyun else if (bits & 0x3)
4536*4882a593Smuzhiyun return (0);
4537*4882a593Smuzhiyun else
4538*4882a593Smuzhiyun return (1);
4539*4882a593Smuzhiyun }
4540*4882a593Smuzhiyun
4541*4882a593Smuzhiyun /****************************************************************************/
4542*4882a593Smuzhiyun /* */
4543*4882a593Smuzhiyun /* Routine Name: ips_flush_and_reset */
4544*4882a593Smuzhiyun /* */
4545*4882a593Smuzhiyun /* Routine Description: */
4546*4882a593Smuzhiyun /* */
4547*4882a593Smuzhiyun /* Perform cleanup ( FLUSH and RESET ) when the adapter is in an unknown */
4548*4882a593Smuzhiyun /* state ( was trying to INIT and an interrupt was already pending ) ... */
4549*4882a593Smuzhiyun /* */
4550*4882a593Smuzhiyun /****************************************************************************/
4551*4882a593Smuzhiyun static void
ips_flush_and_reset(ips_ha_t * ha)4552*4882a593Smuzhiyun ips_flush_and_reset(ips_ha_t *ha)
4553*4882a593Smuzhiyun {
4554*4882a593Smuzhiyun ips_scb_t *scb;
4555*4882a593Smuzhiyun int ret;
4556*4882a593Smuzhiyun int time;
4557*4882a593Smuzhiyun int done;
4558*4882a593Smuzhiyun dma_addr_t command_dma;
4559*4882a593Smuzhiyun
4560*4882a593Smuzhiyun /* Create a usuable SCB */
4561*4882a593Smuzhiyun scb = dma_alloc_coherent(&ha->pcidev->dev, sizeof(ips_scb_t),
4562*4882a593Smuzhiyun &command_dma, GFP_KERNEL);
4563*4882a593Smuzhiyun if (scb) {
4564*4882a593Smuzhiyun memset(scb, 0, sizeof(ips_scb_t));
4565*4882a593Smuzhiyun ips_init_scb(ha, scb);
4566*4882a593Smuzhiyun scb->scb_busaddr = command_dma;
4567*4882a593Smuzhiyun
4568*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
4569*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_FLUSH;
4570*4882a593Smuzhiyun
4571*4882a593Smuzhiyun scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
4572*4882a593Smuzhiyun scb->cmd.flush_cache.command_id = IPS_MAX_CMDS; /* Use an ID that would otherwise not exist */
4573*4882a593Smuzhiyun scb->cmd.flush_cache.state = IPS_NORM_STATE;
4574*4882a593Smuzhiyun scb->cmd.flush_cache.reserved = 0;
4575*4882a593Smuzhiyun scb->cmd.flush_cache.reserved2 = 0;
4576*4882a593Smuzhiyun scb->cmd.flush_cache.reserved3 = 0;
4577*4882a593Smuzhiyun scb->cmd.flush_cache.reserved4 = 0;
4578*4882a593Smuzhiyun
4579*4882a593Smuzhiyun ret = ips_send_cmd(ha, scb); /* Send the Flush Command */
4580*4882a593Smuzhiyun
4581*4882a593Smuzhiyun if (ret == IPS_SUCCESS) {
4582*4882a593Smuzhiyun time = 60 * IPS_ONE_SEC; /* Max Wait time is 60 seconds */
4583*4882a593Smuzhiyun done = 0;
4584*4882a593Smuzhiyun
4585*4882a593Smuzhiyun while ((time > 0) && (!done)) {
4586*4882a593Smuzhiyun done = ips_poll_for_flush_complete(ha);
4587*4882a593Smuzhiyun /* This may look evil, but it's only done during extremely rare start-up conditions ! */
4588*4882a593Smuzhiyun udelay(1000);
4589*4882a593Smuzhiyun time--;
4590*4882a593Smuzhiyun }
4591*4882a593Smuzhiyun }
4592*4882a593Smuzhiyun }
4593*4882a593Smuzhiyun
4594*4882a593Smuzhiyun /* Now RESET and INIT the adapter */
4595*4882a593Smuzhiyun (*ha->func.reset) (ha);
4596*4882a593Smuzhiyun
4597*4882a593Smuzhiyun dma_free_coherent(&ha->pcidev->dev, sizeof(ips_scb_t), scb, command_dma);
4598*4882a593Smuzhiyun return;
4599*4882a593Smuzhiyun }
4600*4882a593Smuzhiyun
4601*4882a593Smuzhiyun /****************************************************************************/
4602*4882a593Smuzhiyun /* */
4603*4882a593Smuzhiyun /* Routine Name: ips_poll_for_flush_complete */
4604*4882a593Smuzhiyun /* */
4605*4882a593Smuzhiyun /* Routine Description: */
4606*4882a593Smuzhiyun /* */
4607*4882a593Smuzhiyun /* Poll for the Flush Command issued by ips_flush_and_reset() to complete */
4608*4882a593Smuzhiyun /* All other responses are just taken off the queue and ignored */
4609*4882a593Smuzhiyun /* */
4610*4882a593Smuzhiyun /****************************************************************************/
4611*4882a593Smuzhiyun static int
ips_poll_for_flush_complete(ips_ha_t * ha)4612*4882a593Smuzhiyun ips_poll_for_flush_complete(ips_ha_t * ha)
4613*4882a593Smuzhiyun {
4614*4882a593Smuzhiyun IPS_STATUS cstatus;
4615*4882a593Smuzhiyun
4616*4882a593Smuzhiyun while (TRUE) {
4617*4882a593Smuzhiyun cstatus.value = (*ha->func.statupd) (ha);
4618*4882a593Smuzhiyun
4619*4882a593Smuzhiyun if (cstatus.value == 0xffffffff) /* If No Interrupt to process */
4620*4882a593Smuzhiyun break;
4621*4882a593Smuzhiyun
4622*4882a593Smuzhiyun /* Success is when we see the Flush Command ID */
4623*4882a593Smuzhiyun if (cstatus.fields.command_id == IPS_MAX_CMDS)
4624*4882a593Smuzhiyun return 1;
4625*4882a593Smuzhiyun }
4626*4882a593Smuzhiyun
4627*4882a593Smuzhiyun return 0;
4628*4882a593Smuzhiyun }
4629*4882a593Smuzhiyun
4630*4882a593Smuzhiyun /****************************************************************************/
4631*4882a593Smuzhiyun /* */
4632*4882a593Smuzhiyun /* Routine Name: ips_enable_int_copperhead */
4633*4882a593Smuzhiyun /* */
4634*4882a593Smuzhiyun /* Routine Description: */
4635*4882a593Smuzhiyun /* Turn on interrupts */
4636*4882a593Smuzhiyun /* */
4637*4882a593Smuzhiyun /****************************************************************************/
4638*4882a593Smuzhiyun static void
ips_enable_int_copperhead(ips_ha_t * ha)4639*4882a593Smuzhiyun ips_enable_int_copperhead(ips_ha_t * ha)
4640*4882a593Smuzhiyun {
4641*4882a593Smuzhiyun METHOD_TRACE("ips_enable_int_copperhead", 1);
4642*4882a593Smuzhiyun
4643*4882a593Smuzhiyun outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
4644*4882a593Smuzhiyun inb(ha->io_addr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/
4645*4882a593Smuzhiyun }
4646*4882a593Smuzhiyun
4647*4882a593Smuzhiyun /****************************************************************************/
4648*4882a593Smuzhiyun /* */
4649*4882a593Smuzhiyun /* Routine Name: ips_enable_int_copperhead_memio */
4650*4882a593Smuzhiyun /* */
4651*4882a593Smuzhiyun /* Routine Description: */
4652*4882a593Smuzhiyun /* Turn on interrupts */
4653*4882a593Smuzhiyun /* */
4654*4882a593Smuzhiyun /****************************************************************************/
4655*4882a593Smuzhiyun static void
ips_enable_int_copperhead_memio(ips_ha_t * ha)4656*4882a593Smuzhiyun ips_enable_int_copperhead_memio(ips_ha_t * ha)
4657*4882a593Smuzhiyun {
4658*4882a593Smuzhiyun METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
4659*4882a593Smuzhiyun
4660*4882a593Smuzhiyun writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
4661*4882a593Smuzhiyun readb(ha->mem_ptr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/
4662*4882a593Smuzhiyun }
4663*4882a593Smuzhiyun
4664*4882a593Smuzhiyun /****************************************************************************/
4665*4882a593Smuzhiyun /* */
4666*4882a593Smuzhiyun /* Routine Name: ips_enable_int_morpheus */
4667*4882a593Smuzhiyun /* */
4668*4882a593Smuzhiyun /* Routine Description: */
4669*4882a593Smuzhiyun /* Turn on interrupts */
4670*4882a593Smuzhiyun /* */
4671*4882a593Smuzhiyun /****************************************************************************/
4672*4882a593Smuzhiyun static void
ips_enable_int_morpheus(ips_ha_t * ha)4673*4882a593Smuzhiyun ips_enable_int_morpheus(ips_ha_t * ha)
4674*4882a593Smuzhiyun {
4675*4882a593Smuzhiyun uint32_t Oimr;
4676*4882a593Smuzhiyun
4677*4882a593Smuzhiyun METHOD_TRACE("ips_enable_int_morpheus", 1);
4678*4882a593Smuzhiyun
4679*4882a593Smuzhiyun Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
4680*4882a593Smuzhiyun Oimr &= ~0x08;
4681*4882a593Smuzhiyun writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
4682*4882a593Smuzhiyun readl(ha->mem_ptr + IPS_REG_I960_OIMR); /*Ensure PCI Posting Completes*/
4683*4882a593Smuzhiyun }
4684*4882a593Smuzhiyun
4685*4882a593Smuzhiyun /****************************************************************************/
4686*4882a593Smuzhiyun /* */
4687*4882a593Smuzhiyun /* Routine Name: ips_init_copperhead */
4688*4882a593Smuzhiyun /* */
4689*4882a593Smuzhiyun /* Routine Description: */
4690*4882a593Smuzhiyun /* */
4691*4882a593Smuzhiyun /* Initialize a copperhead controller */
4692*4882a593Smuzhiyun /* */
4693*4882a593Smuzhiyun /****************************************************************************/
4694*4882a593Smuzhiyun static int
ips_init_copperhead(ips_ha_t * ha)4695*4882a593Smuzhiyun ips_init_copperhead(ips_ha_t * ha)
4696*4882a593Smuzhiyun {
4697*4882a593Smuzhiyun uint8_t Isr;
4698*4882a593Smuzhiyun uint8_t Cbsp;
4699*4882a593Smuzhiyun uint8_t PostByte[IPS_MAX_POST_BYTES];
4700*4882a593Smuzhiyun int i, j;
4701*4882a593Smuzhiyun
4702*4882a593Smuzhiyun METHOD_TRACE("ips_init_copperhead", 1);
4703*4882a593Smuzhiyun
4704*4882a593Smuzhiyun for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
4705*4882a593Smuzhiyun for (j = 0; j < 45; j++) {
4706*4882a593Smuzhiyun Isr = inb(ha->io_addr + IPS_REG_HISR);
4707*4882a593Smuzhiyun if (Isr & IPS_BIT_GHI)
4708*4882a593Smuzhiyun break;
4709*4882a593Smuzhiyun
4710*4882a593Smuzhiyun /* Delay for 1 Second */
4711*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4712*4882a593Smuzhiyun }
4713*4882a593Smuzhiyun
4714*4882a593Smuzhiyun if (j >= 45)
4715*4882a593Smuzhiyun /* error occurred */
4716*4882a593Smuzhiyun return (0);
4717*4882a593Smuzhiyun
4718*4882a593Smuzhiyun PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
4719*4882a593Smuzhiyun outb(Isr, ha->io_addr + IPS_REG_HISR);
4720*4882a593Smuzhiyun }
4721*4882a593Smuzhiyun
4722*4882a593Smuzhiyun if (PostByte[0] < IPS_GOOD_POST_STATUS) {
4723*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4724*4882a593Smuzhiyun "reset controller fails (post status %x %x).\n",
4725*4882a593Smuzhiyun PostByte[0], PostByte[1]);
4726*4882a593Smuzhiyun
4727*4882a593Smuzhiyun return (0);
4728*4882a593Smuzhiyun }
4729*4882a593Smuzhiyun
4730*4882a593Smuzhiyun for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
4731*4882a593Smuzhiyun for (j = 0; j < 240; j++) {
4732*4882a593Smuzhiyun Isr = inb(ha->io_addr + IPS_REG_HISR);
4733*4882a593Smuzhiyun if (Isr & IPS_BIT_GHI)
4734*4882a593Smuzhiyun break;
4735*4882a593Smuzhiyun
4736*4882a593Smuzhiyun /* Delay for 1 Second */
4737*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4738*4882a593Smuzhiyun }
4739*4882a593Smuzhiyun
4740*4882a593Smuzhiyun if (j >= 240)
4741*4882a593Smuzhiyun /* error occurred */
4742*4882a593Smuzhiyun return (0);
4743*4882a593Smuzhiyun
4744*4882a593Smuzhiyun inb(ha->io_addr + IPS_REG_ISPR);
4745*4882a593Smuzhiyun outb(Isr, ha->io_addr + IPS_REG_HISR);
4746*4882a593Smuzhiyun }
4747*4882a593Smuzhiyun
4748*4882a593Smuzhiyun for (i = 0; i < 240; i++) {
4749*4882a593Smuzhiyun Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
4750*4882a593Smuzhiyun
4751*4882a593Smuzhiyun if ((Cbsp & IPS_BIT_OP) == 0)
4752*4882a593Smuzhiyun break;
4753*4882a593Smuzhiyun
4754*4882a593Smuzhiyun /* Delay for 1 Second */
4755*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4756*4882a593Smuzhiyun }
4757*4882a593Smuzhiyun
4758*4882a593Smuzhiyun if (i >= 240)
4759*4882a593Smuzhiyun /* reset failed */
4760*4882a593Smuzhiyun return (0);
4761*4882a593Smuzhiyun
4762*4882a593Smuzhiyun /* setup CCCR */
4763*4882a593Smuzhiyun outl(0x1010, ha->io_addr + IPS_REG_CCCR);
4764*4882a593Smuzhiyun
4765*4882a593Smuzhiyun /* Enable busmastering */
4766*4882a593Smuzhiyun outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
4767*4882a593Smuzhiyun
4768*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
4769*4882a593Smuzhiyun /* fix for anaconda64 */
4770*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_NDAE);
4771*4882a593Smuzhiyun
4772*4882a593Smuzhiyun /* Enable interrupts */
4773*4882a593Smuzhiyun outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
4774*4882a593Smuzhiyun
4775*4882a593Smuzhiyun return (1);
4776*4882a593Smuzhiyun }
4777*4882a593Smuzhiyun
4778*4882a593Smuzhiyun /****************************************************************************/
4779*4882a593Smuzhiyun /* */
4780*4882a593Smuzhiyun /* Routine Name: ips_init_copperhead_memio */
4781*4882a593Smuzhiyun /* */
4782*4882a593Smuzhiyun /* Routine Description: */
4783*4882a593Smuzhiyun /* */
4784*4882a593Smuzhiyun /* Initialize a copperhead controller with memory mapped I/O */
4785*4882a593Smuzhiyun /* */
4786*4882a593Smuzhiyun /****************************************************************************/
4787*4882a593Smuzhiyun static int
ips_init_copperhead_memio(ips_ha_t * ha)4788*4882a593Smuzhiyun ips_init_copperhead_memio(ips_ha_t * ha)
4789*4882a593Smuzhiyun {
4790*4882a593Smuzhiyun uint8_t Isr = 0;
4791*4882a593Smuzhiyun uint8_t Cbsp;
4792*4882a593Smuzhiyun uint8_t PostByte[IPS_MAX_POST_BYTES];
4793*4882a593Smuzhiyun int i, j;
4794*4882a593Smuzhiyun
4795*4882a593Smuzhiyun METHOD_TRACE("ips_init_copperhead_memio", 1);
4796*4882a593Smuzhiyun
4797*4882a593Smuzhiyun for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
4798*4882a593Smuzhiyun for (j = 0; j < 45; j++) {
4799*4882a593Smuzhiyun Isr = readb(ha->mem_ptr + IPS_REG_HISR);
4800*4882a593Smuzhiyun if (Isr & IPS_BIT_GHI)
4801*4882a593Smuzhiyun break;
4802*4882a593Smuzhiyun
4803*4882a593Smuzhiyun /* Delay for 1 Second */
4804*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4805*4882a593Smuzhiyun }
4806*4882a593Smuzhiyun
4807*4882a593Smuzhiyun if (j >= 45)
4808*4882a593Smuzhiyun /* error occurred */
4809*4882a593Smuzhiyun return (0);
4810*4882a593Smuzhiyun
4811*4882a593Smuzhiyun PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
4812*4882a593Smuzhiyun writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
4813*4882a593Smuzhiyun }
4814*4882a593Smuzhiyun
4815*4882a593Smuzhiyun if (PostByte[0] < IPS_GOOD_POST_STATUS) {
4816*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4817*4882a593Smuzhiyun "reset controller fails (post status %x %x).\n",
4818*4882a593Smuzhiyun PostByte[0], PostByte[1]);
4819*4882a593Smuzhiyun
4820*4882a593Smuzhiyun return (0);
4821*4882a593Smuzhiyun }
4822*4882a593Smuzhiyun
4823*4882a593Smuzhiyun for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
4824*4882a593Smuzhiyun for (j = 0; j < 240; j++) {
4825*4882a593Smuzhiyun Isr = readb(ha->mem_ptr + IPS_REG_HISR);
4826*4882a593Smuzhiyun if (Isr & IPS_BIT_GHI)
4827*4882a593Smuzhiyun break;
4828*4882a593Smuzhiyun
4829*4882a593Smuzhiyun /* Delay for 1 Second */
4830*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4831*4882a593Smuzhiyun }
4832*4882a593Smuzhiyun
4833*4882a593Smuzhiyun if (j >= 240)
4834*4882a593Smuzhiyun /* error occurred */
4835*4882a593Smuzhiyun return (0);
4836*4882a593Smuzhiyun
4837*4882a593Smuzhiyun readb(ha->mem_ptr + IPS_REG_ISPR);
4838*4882a593Smuzhiyun writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
4839*4882a593Smuzhiyun }
4840*4882a593Smuzhiyun
4841*4882a593Smuzhiyun for (i = 0; i < 240; i++) {
4842*4882a593Smuzhiyun Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
4843*4882a593Smuzhiyun
4844*4882a593Smuzhiyun if ((Cbsp & IPS_BIT_OP) == 0)
4845*4882a593Smuzhiyun break;
4846*4882a593Smuzhiyun
4847*4882a593Smuzhiyun /* Delay for 1 Second */
4848*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4849*4882a593Smuzhiyun }
4850*4882a593Smuzhiyun
4851*4882a593Smuzhiyun if (i >= 240)
4852*4882a593Smuzhiyun /* error occurred */
4853*4882a593Smuzhiyun return (0);
4854*4882a593Smuzhiyun
4855*4882a593Smuzhiyun /* setup CCCR */
4856*4882a593Smuzhiyun writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
4857*4882a593Smuzhiyun
4858*4882a593Smuzhiyun /* Enable busmastering */
4859*4882a593Smuzhiyun writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
4860*4882a593Smuzhiyun
4861*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
4862*4882a593Smuzhiyun /* fix for anaconda64 */
4863*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_NDAE);
4864*4882a593Smuzhiyun
4865*4882a593Smuzhiyun /* Enable interrupts */
4866*4882a593Smuzhiyun writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
4867*4882a593Smuzhiyun
4868*4882a593Smuzhiyun /* if we get here then everything went OK */
4869*4882a593Smuzhiyun return (1);
4870*4882a593Smuzhiyun }
4871*4882a593Smuzhiyun
4872*4882a593Smuzhiyun /****************************************************************************/
4873*4882a593Smuzhiyun /* */
4874*4882a593Smuzhiyun /* Routine Name: ips_init_morpheus */
4875*4882a593Smuzhiyun /* */
4876*4882a593Smuzhiyun /* Routine Description: */
4877*4882a593Smuzhiyun /* */
4878*4882a593Smuzhiyun /* Initialize a morpheus controller */
4879*4882a593Smuzhiyun /* */
4880*4882a593Smuzhiyun /****************************************************************************/
4881*4882a593Smuzhiyun static int
ips_init_morpheus(ips_ha_t * ha)4882*4882a593Smuzhiyun ips_init_morpheus(ips_ha_t * ha)
4883*4882a593Smuzhiyun {
4884*4882a593Smuzhiyun uint32_t Post;
4885*4882a593Smuzhiyun uint32_t Config;
4886*4882a593Smuzhiyun uint32_t Isr;
4887*4882a593Smuzhiyun uint32_t Oimr;
4888*4882a593Smuzhiyun int i;
4889*4882a593Smuzhiyun
4890*4882a593Smuzhiyun METHOD_TRACE("ips_init_morpheus", 1);
4891*4882a593Smuzhiyun
4892*4882a593Smuzhiyun /* Wait up to 45 secs for Post */
4893*4882a593Smuzhiyun for (i = 0; i < 45; i++) {
4894*4882a593Smuzhiyun Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
4895*4882a593Smuzhiyun
4896*4882a593Smuzhiyun if (Isr & IPS_BIT_I960_MSG0I)
4897*4882a593Smuzhiyun break;
4898*4882a593Smuzhiyun
4899*4882a593Smuzhiyun /* Delay for 1 Second */
4900*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4901*4882a593Smuzhiyun }
4902*4882a593Smuzhiyun
4903*4882a593Smuzhiyun if (i >= 45) {
4904*4882a593Smuzhiyun /* error occurred */
4905*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4906*4882a593Smuzhiyun "timeout waiting for post.\n");
4907*4882a593Smuzhiyun
4908*4882a593Smuzhiyun return (0);
4909*4882a593Smuzhiyun }
4910*4882a593Smuzhiyun
4911*4882a593Smuzhiyun Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
4912*4882a593Smuzhiyun
4913*4882a593Smuzhiyun if (Post == 0x4F00) { /* If Flashing the Battery PIC */
4914*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4915*4882a593Smuzhiyun "Flashing Battery PIC, Please wait ...\n");
4916*4882a593Smuzhiyun
4917*4882a593Smuzhiyun /* Clear the interrupt bit */
4918*4882a593Smuzhiyun Isr = (uint32_t) IPS_BIT_I960_MSG0I;
4919*4882a593Smuzhiyun writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
4920*4882a593Smuzhiyun
4921*4882a593Smuzhiyun for (i = 0; i < 120; i++) { /* Wait Up to 2 Min. for Completion */
4922*4882a593Smuzhiyun Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
4923*4882a593Smuzhiyun if (Post != 0x4F00)
4924*4882a593Smuzhiyun break;
4925*4882a593Smuzhiyun /* Delay for 1 Second */
4926*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4927*4882a593Smuzhiyun }
4928*4882a593Smuzhiyun
4929*4882a593Smuzhiyun if (i >= 120) {
4930*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4931*4882a593Smuzhiyun "timeout waiting for Battery PIC Flash\n");
4932*4882a593Smuzhiyun return (0);
4933*4882a593Smuzhiyun }
4934*4882a593Smuzhiyun
4935*4882a593Smuzhiyun }
4936*4882a593Smuzhiyun
4937*4882a593Smuzhiyun /* Clear the interrupt bit */
4938*4882a593Smuzhiyun Isr = (uint32_t) IPS_BIT_I960_MSG0I;
4939*4882a593Smuzhiyun writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
4940*4882a593Smuzhiyun
4941*4882a593Smuzhiyun if (Post < (IPS_GOOD_POST_STATUS << 8)) {
4942*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4943*4882a593Smuzhiyun "reset controller fails (post status %x).\n", Post);
4944*4882a593Smuzhiyun
4945*4882a593Smuzhiyun return (0);
4946*4882a593Smuzhiyun }
4947*4882a593Smuzhiyun
4948*4882a593Smuzhiyun /* Wait up to 240 secs for config bytes */
4949*4882a593Smuzhiyun for (i = 0; i < 240; i++) {
4950*4882a593Smuzhiyun Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
4951*4882a593Smuzhiyun
4952*4882a593Smuzhiyun if (Isr & IPS_BIT_I960_MSG1I)
4953*4882a593Smuzhiyun break;
4954*4882a593Smuzhiyun
4955*4882a593Smuzhiyun /* Delay for 1 Second */
4956*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
4957*4882a593Smuzhiyun }
4958*4882a593Smuzhiyun
4959*4882a593Smuzhiyun if (i >= 240) {
4960*4882a593Smuzhiyun /* error occurred */
4961*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
4962*4882a593Smuzhiyun "timeout waiting for config.\n");
4963*4882a593Smuzhiyun
4964*4882a593Smuzhiyun return (0);
4965*4882a593Smuzhiyun }
4966*4882a593Smuzhiyun
4967*4882a593Smuzhiyun Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
4968*4882a593Smuzhiyun
4969*4882a593Smuzhiyun /* Clear interrupt bit */
4970*4882a593Smuzhiyun Isr = (uint32_t) IPS_BIT_I960_MSG1I;
4971*4882a593Smuzhiyun writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
4972*4882a593Smuzhiyun
4973*4882a593Smuzhiyun /* Turn on the interrupts */
4974*4882a593Smuzhiyun Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
4975*4882a593Smuzhiyun Oimr &= ~0x8;
4976*4882a593Smuzhiyun writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
4977*4882a593Smuzhiyun
4978*4882a593Smuzhiyun /* if we get here then everything went OK */
4979*4882a593Smuzhiyun
4980*4882a593Smuzhiyun /* Since we did a RESET, an EraseStripeLock may be needed */
4981*4882a593Smuzhiyun if (Post == 0xEF10) {
4982*4882a593Smuzhiyun if ((Config == 0x000F) || (Config == 0x0009))
4983*4882a593Smuzhiyun ha->requires_esl = 1;
4984*4882a593Smuzhiyun }
4985*4882a593Smuzhiyun
4986*4882a593Smuzhiyun return (1);
4987*4882a593Smuzhiyun }
4988*4882a593Smuzhiyun
4989*4882a593Smuzhiyun /****************************************************************************/
4990*4882a593Smuzhiyun /* */
4991*4882a593Smuzhiyun /* Routine Name: ips_reset_copperhead */
4992*4882a593Smuzhiyun /* */
4993*4882a593Smuzhiyun /* Routine Description: */
4994*4882a593Smuzhiyun /* */
4995*4882a593Smuzhiyun /* Reset the controller */
4996*4882a593Smuzhiyun /* */
4997*4882a593Smuzhiyun /****************************************************************************/
4998*4882a593Smuzhiyun static int
ips_reset_copperhead(ips_ha_t * ha)4999*4882a593Smuzhiyun ips_reset_copperhead(ips_ha_t * ha)
5000*4882a593Smuzhiyun {
5001*4882a593Smuzhiyun int reset_counter;
5002*4882a593Smuzhiyun
5003*4882a593Smuzhiyun METHOD_TRACE("ips_reset_copperhead", 1);
5004*4882a593Smuzhiyun
5005*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
5006*4882a593Smuzhiyun ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq);
5007*4882a593Smuzhiyun
5008*4882a593Smuzhiyun reset_counter = 0;
5009*4882a593Smuzhiyun
5010*4882a593Smuzhiyun while (reset_counter < 2) {
5011*4882a593Smuzhiyun reset_counter++;
5012*4882a593Smuzhiyun
5013*4882a593Smuzhiyun outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
5014*4882a593Smuzhiyun
5015*4882a593Smuzhiyun /* Delay for 1 Second */
5016*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
5017*4882a593Smuzhiyun
5018*4882a593Smuzhiyun outb(0, ha->io_addr + IPS_REG_SCPR);
5019*4882a593Smuzhiyun
5020*4882a593Smuzhiyun /* Delay for 1 Second */
5021*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
5022*4882a593Smuzhiyun
5023*4882a593Smuzhiyun if ((*ha->func.init) (ha))
5024*4882a593Smuzhiyun break;
5025*4882a593Smuzhiyun else if (reset_counter >= 2) {
5026*4882a593Smuzhiyun
5027*4882a593Smuzhiyun return (0);
5028*4882a593Smuzhiyun }
5029*4882a593Smuzhiyun }
5030*4882a593Smuzhiyun
5031*4882a593Smuzhiyun return (1);
5032*4882a593Smuzhiyun }
5033*4882a593Smuzhiyun
5034*4882a593Smuzhiyun /****************************************************************************/
5035*4882a593Smuzhiyun /* */
5036*4882a593Smuzhiyun /* Routine Name: ips_reset_copperhead_memio */
5037*4882a593Smuzhiyun /* */
5038*4882a593Smuzhiyun /* Routine Description: */
5039*4882a593Smuzhiyun /* */
5040*4882a593Smuzhiyun /* Reset the controller */
5041*4882a593Smuzhiyun /* */
5042*4882a593Smuzhiyun /****************************************************************************/
5043*4882a593Smuzhiyun static int
ips_reset_copperhead_memio(ips_ha_t * ha)5044*4882a593Smuzhiyun ips_reset_copperhead_memio(ips_ha_t * ha)
5045*4882a593Smuzhiyun {
5046*4882a593Smuzhiyun int reset_counter;
5047*4882a593Smuzhiyun
5048*4882a593Smuzhiyun METHOD_TRACE("ips_reset_copperhead_memio", 1);
5049*4882a593Smuzhiyun
5050*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
5051*4882a593Smuzhiyun ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
5052*4882a593Smuzhiyun
5053*4882a593Smuzhiyun reset_counter = 0;
5054*4882a593Smuzhiyun
5055*4882a593Smuzhiyun while (reset_counter < 2) {
5056*4882a593Smuzhiyun reset_counter++;
5057*4882a593Smuzhiyun
5058*4882a593Smuzhiyun writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
5059*4882a593Smuzhiyun
5060*4882a593Smuzhiyun /* Delay for 1 Second */
5061*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
5062*4882a593Smuzhiyun
5063*4882a593Smuzhiyun writeb(0, ha->mem_ptr + IPS_REG_SCPR);
5064*4882a593Smuzhiyun
5065*4882a593Smuzhiyun /* Delay for 1 Second */
5066*4882a593Smuzhiyun MDELAY(IPS_ONE_SEC);
5067*4882a593Smuzhiyun
5068*4882a593Smuzhiyun if ((*ha->func.init) (ha))
5069*4882a593Smuzhiyun break;
5070*4882a593Smuzhiyun else if (reset_counter >= 2) {
5071*4882a593Smuzhiyun
5072*4882a593Smuzhiyun return (0);
5073*4882a593Smuzhiyun }
5074*4882a593Smuzhiyun }
5075*4882a593Smuzhiyun
5076*4882a593Smuzhiyun return (1);
5077*4882a593Smuzhiyun }
5078*4882a593Smuzhiyun
5079*4882a593Smuzhiyun /****************************************************************************/
5080*4882a593Smuzhiyun /* */
5081*4882a593Smuzhiyun /* Routine Name: ips_reset_morpheus */
5082*4882a593Smuzhiyun /* */
5083*4882a593Smuzhiyun /* Routine Description: */
5084*4882a593Smuzhiyun /* */
5085*4882a593Smuzhiyun /* Reset the controller */
5086*4882a593Smuzhiyun /* */
5087*4882a593Smuzhiyun /****************************************************************************/
5088*4882a593Smuzhiyun static int
ips_reset_morpheus(ips_ha_t * ha)5089*4882a593Smuzhiyun ips_reset_morpheus(ips_ha_t * ha)
5090*4882a593Smuzhiyun {
5091*4882a593Smuzhiyun int reset_counter;
5092*4882a593Smuzhiyun uint8_t junk;
5093*4882a593Smuzhiyun
5094*4882a593Smuzhiyun METHOD_TRACE("ips_reset_morpheus", 1);
5095*4882a593Smuzhiyun
5096*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
5097*4882a593Smuzhiyun ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
5098*4882a593Smuzhiyun
5099*4882a593Smuzhiyun reset_counter = 0;
5100*4882a593Smuzhiyun
5101*4882a593Smuzhiyun while (reset_counter < 2) {
5102*4882a593Smuzhiyun reset_counter++;
5103*4882a593Smuzhiyun
5104*4882a593Smuzhiyun writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
5105*4882a593Smuzhiyun
5106*4882a593Smuzhiyun /* Delay for 5 Seconds */
5107*4882a593Smuzhiyun MDELAY(5 * IPS_ONE_SEC);
5108*4882a593Smuzhiyun
5109*4882a593Smuzhiyun /* Do a PCI config read to wait for adapter */
5110*4882a593Smuzhiyun pci_read_config_byte(ha->pcidev, 4, &junk);
5111*4882a593Smuzhiyun
5112*4882a593Smuzhiyun if ((*ha->func.init) (ha))
5113*4882a593Smuzhiyun break;
5114*4882a593Smuzhiyun else if (reset_counter >= 2) {
5115*4882a593Smuzhiyun
5116*4882a593Smuzhiyun return (0);
5117*4882a593Smuzhiyun }
5118*4882a593Smuzhiyun }
5119*4882a593Smuzhiyun
5120*4882a593Smuzhiyun return (1);
5121*4882a593Smuzhiyun }
5122*4882a593Smuzhiyun
5123*4882a593Smuzhiyun /****************************************************************************/
5124*4882a593Smuzhiyun /* */
5125*4882a593Smuzhiyun /* Routine Name: ips_statinit */
5126*4882a593Smuzhiyun /* */
5127*4882a593Smuzhiyun /* Routine Description: */
5128*4882a593Smuzhiyun /* */
5129*4882a593Smuzhiyun /* Initialize the status queues on the controller */
5130*4882a593Smuzhiyun /* */
5131*4882a593Smuzhiyun /****************************************************************************/
5132*4882a593Smuzhiyun static void
ips_statinit(ips_ha_t * ha)5133*4882a593Smuzhiyun ips_statinit(ips_ha_t * ha)
5134*4882a593Smuzhiyun {
5135*4882a593Smuzhiyun uint32_t phys_status_start;
5136*4882a593Smuzhiyun
5137*4882a593Smuzhiyun METHOD_TRACE("ips_statinit", 1);
5138*4882a593Smuzhiyun
5139*4882a593Smuzhiyun ha->adapt->p_status_start = ha->adapt->status;
5140*4882a593Smuzhiyun ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
5141*4882a593Smuzhiyun ha->adapt->p_status_tail = ha->adapt->status;
5142*4882a593Smuzhiyun
5143*4882a593Smuzhiyun phys_status_start = ha->adapt->hw_status_start;
5144*4882a593Smuzhiyun outl(phys_status_start, ha->io_addr + IPS_REG_SQSR);
5145*4882a593Smuzhiyun outl(phys_status_start + IPS_STATUS_Q_SIZE,
5146*4882a593Smuzhiyun ha->io_addr + IPS_REG_SQER);
5147*4882a593Smuzhiyun outl(phys_status_start + IPS_STATUS_SIZE,
5148*4882a593Smuzhiyun ha->io_addr + IPS_REG_SQHR);
5149*4882a593Smuzhiyun outl(phys_status_start, ha->io_addr + IPS_REG_SQTR);
5150*4882a593Smuzhiyun
5151*4882a593Smuzhiyun ha->adapt->hw_status_tail = phys_status_start;
5152*4882a593Smuzhiyun }
5153*4882a593Smuzhiyun
5154*4882a593Smuzhiyun /****************************************************************************/
5155*4882a593Smuzhiyun /* */
5156*4882a593Smuzhiyun /* Routine Name: ips_statinit_memio */
5157*4882a593Smuzhiyun /* */
5158*4882a593Smuzhiyun /* Routine Description: */
5159*4882a593Smuzhiyun /* */
5160*4882a593Smuzhiyun /* Initialize the status queues on the controller */
5161*4882a593Smuzhiyun /* */
5162*4882a593Smuzhiyun /****************************************************************************/
5163*4882a593Smuzhiyun static void
ips_statinit_memio(ips_ha_t * ha)5164*4882a593Smuzhiyun ips_statinit_memio(ips_ha_t * ha)
5165*4882a593Smuzhiyun {
5166*4882a593Smuzhiyun uint32_t phys_status_start;
5167*4882a593Smuzhiyun
5168*4882a593Smuzhiyun METHOD_TRACE("ips_statinit_memio", 1);
5169*4882a593Smuzhiyun
5170*4882a593Smuzhiyun ha->adapt->p_status_start = ha->adapt->status;
5171*4882a593Smuzhiyun ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
5172*4882a593Smuzhiyun ha->adapt->p_status_tail = ha->adapt->status;
5173*4882a593Smuzhiyun
5174*4882a593Smuzhiyun phys_status_start = ha->adapt->hw_status_start;
5175*4882a593Smuzhiyun writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
5176*4882a593Smuzhiyun writel(phys_status_start + IPS_STATUS_Q_SIZE,
5177*4882a593Smuzhiyun ha->mem_ptr + IPS_REG_SQER);
5178*4882a593Smuzhiyun writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
5179*4882a593Smuzhiyun writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
5180*4882a593Smuzhiyun
5181*4882a593Smuzhiyun ha->adapt->hw_status_tail = phys_status_start;
5182*4882a593Smuzhiyun }
5183*4882a593Smuzhiyun
5184*4882a593Smuzhiyun /****************************************************************************/
5185*4882a593Smuzhiyun /* */
5186*4882a593Smuzhiyun /* Routine Name: ips_statupd_copperhead */
5187*4882a593Smuzhiyun /* */
5188*4882a593Smuzhiyun /* Routine Description: */
5189*4882a593Smuzhiyun /* */
5190*4882a593Smuzhiyun /* Remove an element from the status queue */
5191*4882a593Smuzhiyun /* */
5192*4882a593Smuzhiyun /****************************************************************************/
5193*4882a593Smuzhiyun static uint32_t
ips_statupd_copperhead(ips_ha_t * ha)5194*4882a593Smuzhiyun ips_statupd_copperhead(ips_ha_t * ha)
5195*4882a593Smuzhiyun {
5196*4882a593Smuzhiyun METHOD_TRACE("ips_statupd_copperhead", 1);
5197*4882a593Smuzhiyun
5198*4882a593Smuzhiyun if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
5199*4882a593Smuzhiyun ha->adapt->p_status_tail++;
5200*4882a593Smuzhiyun ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
5201*4882a593Smuzhiyun } else {
5202*4882a593Smuzhiyun ha->adapt->p_status_tail = ha->adapt->p_status_start;
5203*4882a593Smuzhiyun ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
5204*4882a593Smuzhiyun }
5205*4882a593Smuzhiyun
5206*4882a593Smuzhiyun outl(ha->adapt->hw_status_tail,
5207*4882a593Smuzhiyun ha->io_addr + IPS_REG_SQTR);
5208*4882a593Smuzhiyun
5209*4882a593Smuzhiyun return (ha->adapt->p_status_tail->value);
5210*4882a593Smuzhiyun }
5211*4882a593Smuzhiyun
5212*4882a593Smuzhiyun /****************************************************************************/
5213*4882a593Smuzhiyun /* */
5214*4882a593Smuzhiyun /* Routine Name: ips_statupd_copperhead_memio */
5215*4882a593Smuzhiyun /* */
5216*4882a593Smuzhiyun /* Routine Description: */
5217*4882a593Smuzhiyun /* */
5218*4882a593Smuzhiyun /* Remove an element from the status queue */
5219*4882a593Smuzhiyun /* */
5220*4882a593Smuzhiyun /****************************************************************************/
5221*4882a593Smuzhiyun static uint32_t
ips_statupd_copperhead_memio(ips_ha_t * ha)5222*4882a593Smuzhiyun ips_statupd_copperhead_memio(ips_ha_t * ha)
5223*4882a593Smuzhiyun {
5224*4882a593Smuzhiyun METHOD_TRACE("ips_statupd_copperhead_memio", 1);
5225*4882a593Smuzhiyun
5226*4882a593Smuzhiyun if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
5227*4882a593Smuzhiyun ha->adapt->p_status_tail++;
5228*4882a593Smuzhiyun ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
5229*4882a593Smuzhiyun } else {
5230*4882a593Smuzhiyun ha->adapt->p_status_tail = ha->adapt->p_status_start;
5231*4882a593Smuzhiyun ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
5232*4882a593Smuzhiyun }
5233*4882a593Smuzhiyun
5234*4882a593Smuzhiyun writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
5235*4882a593Smuzhiyun
5236*4882a593Smuzhiyun return (ha->adapt->p_status_tail->value);
5237*4882a593Smuzhiyun }
5238*4882a593Smuzhiyun
5239*4882a593Smuzhiyun /****************************************************************************/
5240*4882a593Smuzhiyun /* */
5241*4882a593Smuzhiyun /* Routine Name: ips_statupd_morpheus */
5242*4882a593Smuzhiyun /* */
5243*4882a593Smuzhiyun /* Routine Description: */
5244*4882a593Smuzhiyun /* */
5245*4882a593Smuzhiyun /* Remove an element from the status queue */
5246*4882a593Smuzhiyun /* */
5247*4882a593Smuzhiyun /****************************************************************************/
5248*4882a593Smuzhiyun static uint32_t
ips_statupd_morpheus(ips_ha_t * ha)5249*4882a593Smuzhiyun ips_statupd_morpheus(ips_ha_t * ha)
5250*4882a593Smuzhiyun {
5251*4882a593Smuzhiyun uint32_t val;
5252*4882a593Smuzhiyun
5253*4882a593Smuzhiyun METHOD_TRACE("ips_statupd_morpheus", 1);
5254*4882a593Smuzhiyun
5255*4882a593Smuzhiyun val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
5256*4882a593Smuzhiyun
5257*4882a593Smuzhiyun return (val);
5258*4882a593Smuzhiyun }
5259*4882a593Smuzhiyun
5260*4882a593Smuzhiyun /****************************************************************************/
5261*4882a593Smuzhiyun /* */
5262*4882a593Smuzhiyun /* Routine Name: ips_issue_copperhead */
5263*4882a593Smuzhiyun /* */
5264*4882a593Smuzhiyun /* Routine Description: */
5265*4882a593Smuzhiyun /* */
5266*4882a593Smuzhiyun /* Send a command down to the controller */
5267*4882a593Smuzhiyun /* */
5268*4882a593Smuzhiyun /****************************************************************************/
5269*4882a593Smuzhiyun static int
ips_issue_copperhead(ips_ha_t * ha,ips_scb_t * scb)5270*4882a593Smuzhiyun ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb)
5271*4882a593Smuzhiyun {
5272*4882a593Smuzhiyun uint32_t TimeOut;
5273*4882a593Smuzhiyun uint32_t val;
5274*4882a593Smuzhiyun
5275*4882a593Smuzhiyun METHOD_TRACE("ips_issue_copperhead", 1);
5276*4882a593Smuzhiyun
5277*4882a593Smuzhiyun if (scb->scsi_cmd) {
5278*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5279*4882a593Smuzhiyun ips_name,
5280*4882a593Smuzhiyun ha->host_num,
5281*4882a593Smuzhiyun scb->cdb[0],
5282*4882a593Smuzhiyun scb->cmd.basic_io.command_id,
5283*4882a593Smuzhiyun scb->bus, scb->target_id, scb->lun);
5284*4882a593Smuzhiyun } else {
5285*4882a593Smuzhiyun DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
5286*4882a593Smuzhiyun ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5287*4882a593Smuzhiyun }
5288*4882a593Smuzhiyun
5289*4882a593Smuzhiyun TimeOut = 0;
5290*4882a593Smuzhiyun
5291*4882a593Smuzhiyun while ((val =
5292*4882a593Smuzhiyun le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
5293*4882a593Smuzhiyun udelay(1000);
5294*4882a593Smuzhiyun
5295*4882a593Smuzhiyun if (++TimeOut >= IPS_SEM_TIMEOUT) {
5296*4882a593Smuzhiyun if (!(val & IPS_BIT_START_STOP))
5297*4882a593Smuzhiyun break;
5298*4882a593Smuzhiyun
5299*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
5300*4882a593Smuzhiyun "ips_issue val [0x%x].\n", val);
5301*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
5302*4882a593Smuzhiyun "ips_issue semaphore chk timeout.\n");
5303*4882a593Smuzhiyun
5304*4882a593Smuzhiyun return (IPS_FAILURE);
5305*4882a593Smuzhiyun } /* end if */
5306*4882a593Smuzhiyun } /* end while */
5307*4882a593Smuzhiyun
5308*4882a593Smuzhiyun outl(scb->scb_busaddr, ha->io_addr + IPS_REG_CCSAR);
5309*4882a593Smuzhiyun outw(IPS_BIT_START_CMD, ha->io_addr + IPS_REG_CCCR);
5310*4882a593Smuzhiyun
5311*4882a593Smuzhiyun return (IPS_SUCCESS);
5312*4882a593Smuzhiyun }
5313*4882a593Smuzhiyun
5314*4882a593Smuzhiyun /****************************************************************************/
5315*4882a593Smuzhiyun /* */
5316*4882a593Smuzhiyun /* Routine Name: ips_issue_copperhead_memio */
5317*4882a593Smuzhiyun /* */
5318*4882a593Smuzhiyun /* Routine Description: */
5319*4882a593Smuzhiyun /* */
5320*4882a593Smuzhiyun /* Send a command down to the controller */
5321*4882a593Smuzhiyun /* */
5322*4882a593Smuzhiyun /****************************************************************************/
5323*4882a593Smuzhiyun static int
ips_issue_copperhead_memio(ips_ha_t * ha,ips_scb_t * scb)5324*4882a593Smuzhiyun ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb)
5325*4882a593Smuzhiyun {
5326*4882a593Smuzhiyun uint32_t TimeOut;
5327*4882a593Smuzhiyun uint32_t val;
5328*4882a593Smuzhiyun
5329*4882a593Smuzhiyun METHOD_TRACE("ips_issue_copperhead_memio", 1);
5330*4882a593Smuzhiyun
5331*4882a593Smuzhiyun if (scb->scsi_cmd) {
5332*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5333*4882a593Smuzhiyun ips_name,
5334*4882a593Smuzhiyun ha->host_num,
5335*4882a593Smuzhiyun scb->cdb[0],
5336*4882a593Smuzhiyun scb->cmd.basic_io.command_id,
5337*4882a593Smuzhiyun scb->bus, scb->target_id, scb->lun);
5338*4882a593Smuzhiyun } else {
5339*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
5340*4882a593Smuzhiyun ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5341*4882a593Smuzhiyun }
5342*4882a593Smuzhiyun
5343*4882a593Smuzhiyun TimeOut = 0;
5344*4882a593Smuzhiyun
5345*4882a593Smuzhiyun while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
5346*4882a593Smuzhiyun udelay(1000);
5347*4882a593Smuzhiyun
5348*4882a593Smuzhiyun if (++TimeOut >= IPS_SEM_TIMEOUT) {
5349*4882a593Smuzhiyun if (!(val & IPS_BIT_START_STOP))
5350*4882a593Smuzhiyun break;
5351*4882a593Smuzhiyun
5352*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
5353*4882a593Smuzhiyun "ips_issue val [0x%x].\n", val);
5354*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
5355*4882a593Smuzhiyun "ips_issue semaphore chk timeout.\n");
5356*4882a593Smuzhiyun
5357*4882a593Smuzhiyun return (IPS_FAILURE);
5358*4882a593Smuzhiyun } /* end if */
5359*4882a593Smuzhiyun } /* end while */
5360*4882a593Smuzhiyun
5361*4882a593Smuzhiyun writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
5362*4882a593Smuzhiyun writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
5363*4882a593Smuzhiyun
5364*4882a593Smuzhiyun return (IPS_SUCCESS);
5365*4882a593Smuzhiyun }
5366*4882a593Smuzhiyun
5367*4882a593Smuzhiyun /****************************************************************************/
5368*4882a593Smuzhiyun /* */
5369*4882a593Smuzhiyun /* Routine Name: ips_issue_i2o */
5370*4882a593Smuzhiyun /* */
5371*4882a593Smuzhiyun /* Routine Description: */
5372*4882a593Smuzhiyun /* */
5373*4882a593Smuzhiyun /* Send a command down to the controller */
5374*4882a593Smuzhiyun /* */
5375*4882a593Smuzhiyun /****************************************************************************/
5376*4882a593Smuzhiyun static int
ips_issue_i2o(ips_ha_t * ha,ips_scb_t * scb)5377*4882a593Smuzhiyun ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb)
5378*4882a593Smuzhiyun {
5379*4882a593Smuzhiyun
5380*4882a593Smuzhiyun METHOD_TRACE("ips_issue_i2o", 1);
5381*4882a593Smuzhiyun
5382*4882a593Smuzhiyun if (scb->scsi_cmd) {
5383*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5384*4882a593Smuzhiyun ips_name,
5385*4882a593Smuzhiyun ha->host_num,
5386*4882a593Smuzhiyun scb->cdb[0],
5387*4882a593Smuzhiyun scb->cmd.basic_io.command_id,
5388*4882a593Smuzhiyun scb->bus, scb->target_id, scb->lun);
5389*4882a593Smuzhiyun } else {
5390*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
5391*4882a593Smuzhiyun ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5392*4882a593Smuzhiyun }
5393*4882a593Smuzhiyun
5394*4882a593Smuzhiyun outl(scb->scb_busaddr, ha->io_addr + IPS_REG_I2O_INMSGQ);
5395*4882a593Smuzhiyun
5396*4882a593Smuzhiyun return (IPS_SUCCESS);
5397*4882a593Smuzhiyun }
5398*4882a593Smuzhiyun
5399*4882a593Smuzhiyun /****************************************************************************/
5400*4882a593Smuzhiyun /* */
5401*4882a593Smuzhiyun /* Routine Name: ips_issue_i2o_memio */
5402*4882a593Smuzhiyun /* */
5403*4882a593Smuzhiyun /* Routine Description: */
5404*4882a593Smuzhiyun /* */
5405*4882a593Smuzhiyun /* Send a command down to the controller */
5406*4882a593Smuzhiyun /* */
5407*4882a593Smuzhiyun /****************************************************************************/
5408*4882a593Smuzhiyun static int
ips_issue_i2o_memio(ips_ha_t * ha,ips_scb_t * scb)5409*4882a593Smuzhiyun ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb)
5410*4882a593Smuzhiyun {
5411*4882a593Smuzhiyun
5412*4882a593Smuzhiyun METHOD_TRACE("ips_issue_i2o_memio", 1);
5413*4882a593Smuzhiyun
5414*4882a593Smuzhiyun if (scb->scsi_cmd) {
5415*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
5416*4882a593Smuzhiyun ips_name,
5417*4882a593Smuzhiyun ha->host_num,
5418*4882a593Smuzhiyun scb->cdb[0],
5419*4882a593Smuzhiyun scb->cmd.basic_io.command_id,
5420*4882a593Smuzhiyun scb->bus, scb->target_id, scb->lun);
5421*4882a593Smuzhiyun } else {
5422*4882a593Smuzhiyun DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
5423*4882a593Smuzhiyun ips_name, ha->host_num, scb->cmd.basic_io.command_id);
5424*4882a593Smuzhiyun }
5425*4882a593Smuzhiyun
5426*4882a593Smuzhiyun writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
5427*4882a593Smuzhiyun
5428*4882a593Smuzhiyun return (IPS_SUCCESS);
5429*4882a593Smuzhiyun }
5430*4882a593Smuzhiyun
5431*4882a593Smuzhiyun /****************************************************************************/
5432*4882a593Smuzhiyun /* */
5433*4882a593Smuzhiyun /* Routine Name: ips_isintr_copperhead */
5434*4882a593Smuzhiyun /* */
5435*4882a593Smuzhiyun /* Routine Description: */
5436*4882a593Smuzhiyun /* */
5437*4882a593Smuzhiyun /* Test to see if an interrupt is for us */
5438*4882a593Smuzhiyun /* */
5439*4882a593Smuzhiyun /****************************************************************************/
5440*4882a593Smuzhiyun static int
ips_isintr_copperhead(ips_ha_t * ha)5441*4882a593Smuzhiyun ips_isintr_copperhead(ips_ha_t * ha)
5442*4882a593Smuzhiyun {
5443*4882a593Smuzhiyun uint8_t Isr;
5444*4882a593Smuzhiyun
5445*4882a593Smuzhiyun METHOD_TRACE("ips_isintr_copperhead", 2);
5446*4882a593Smuzhiyun
5447*4882a593Smuzhiyun Isr = inb(ha->io_addr + IPS_REG_HISR);
5448*4882a593Smuzhiyun
5449*4882a593Smuzhiyun if (Isr == 0xFF)
5450*4882a593Smuzhiyun /* ?!?! Nothing really there */
5451*4882a593Smuzhiyun return (0);
5452*4882a593Smuzhiyun
5453*4882a593Smuzhiyun if (Isr & IPS_BIT_SCE)
5454*4882a593Smuzhiyun return (1);
5455*4882a593Smuzhiyun else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
5456*4882a593Smuzhiyun /* status queue overflow or GHI */
5457*4882a593Smuzhiyun /* just clear the interrupt */
5458*4882a593Smuzhiyun outb(Isr, ha->io_addr + IPS_REG_HISR);
5459*4882a593Smuzhiyun }
5460*4882a593Smuzhiyun
5461*4882a593Smuzhiyun return (0);
5462*4882a593Smuzhiyun }
5463*4882a593Smuzhiyun
5464*4882a593Smuzhiyun /****************************************************************************/
5465*4882a593Smuzhiyun /* */
5466*4882a593Smuzhiyun /* Routine Name: ips_isintr_copperhead_memio */
5467*4882a593Smuzhiyun /* */
5468*4882a593Smuzhiyun /* Routine Description: */
5469*4882a593Smuzhiyun /* */
5470*4882a593Smuzhiyun /* Test to see if an interrupt is for us */
5471*4882a593Smuzhiyun /* */
5472*4882a593Smuzhiyun /****************************************************************************/
5473*4882a593Smuzhiyun static int
ips_isintr_copperhead_memio(ips_ha_t * ha)5474*4882a593Smuzhiyun ips_isintr_copperhead_memio(ips_ha_t * ha)
5475*4882a593Smuzhiyun {
5476*4882a593Smuzhiyun uint8_t Isr;
5477*4882a593Smuzhiyun
5478*4882a593Smuzhiyun METHOD_TRACE("ips_isintr_memio", 2);
5479*4882a593Smuzhiyun
5480*4882a593Smuzhiyun Isr = readb(ha->mem_ptr + IPS_REG_HISR);
5481*4882a593Smuzhiyun
5482*4882a593Smuzhiyun if (Isr == 0xFF)
5483*4882a593Smuzhiyun /* ?!?! Nothing really there */
5484*4882a593Smuzhiyun return (0);
5485*4882a593Smuzhiyun
5486*4882a593Smuzhiyun if (Isr & IPS_BIT_SCE)
5487*4882a593Smuzhiyun return (1);
5488*4882a593Smuzhiyun else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
5489*4882a593Smuzhiyun /* status queue overflow or GHI */
5490*4882a593Smuzhiyun /* just clear the interrupt */
5491*4882a593Smuzhiyun writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
5492*4882a593Smuzhiyun }
5493*4882a593Smuzhiyun
5494*4882a593Smuzhiyun return (0);
5495*4882a593Smuzhiyun }
5496*4882a593Smuzhiyun
5497*4882a593Smuzhiyun /****************************************************************************/
5498*4882a593Smuzhiyun /* */
5499*4882a593Smuzhiyun /* Routine Name: ips_isintr_morpheus */
5500*4882a593Smuzhiyun /* */
5501*4882a593Smuzhiyun /* Routine Description: */
5502*4882a593Smuzhiyun /* */
5503*4882a593Smuzhiyun /* Test to see if an interrupt is for us */
5504*4882a593Smuzhiyun /* */
5505*4882a593Smuzhiyun /****************************************************************************/
5506*4882a593Smuzhiyun static int
ips_isintr_morpheus(ips_ha_t * ha)5507*4882a593Smuzhiyun ips_isintr_morpheus(ips_ha_t * ha)
5508*4882a593Smuzhiyun {
5509*4882a593Smuzhiyun uint32_t Isr;
5510*4882a593Smuzhiyun
5511*4882a593Smuzhiyun METHOD_TRACE("ips_isintr_morpheus", 2);
5512*4882a593Smuzhiyun
5513*4882a593Smuzhiyun Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
5514*4882a593Smuzhiyun
5515*4882a593Smuzhiyun if (Isr & IPS_BIT_I2O_OPQI)
5516*4882a593Smuzhiyun return (1);
5517*4882a593Smuzhiyun else
5518*4882a593Smuzhiyun return (0);
5519*4882a593Smuzhiyun }
5520*4882a593Smuzhiyun
5521*4882a593Smuzhiyun /****************************************************************************/
5522*4882a593Smuzhiyun /* */
5523*4882a593Smuzhiyun /* Routine Name: ips_wait */
5524*4882a593Smuzhiyun /* */
5525*4882a593Smuzhiyun /* Routine Description: */
5526*4882a593Smuzhiyun /* */
5527*4882a593Smuzhiyun /* Wait for a command to complete */
5528*4882a593Smuzhiyun /* */
5529*4882a593Smuzhiyun /****************************************************************************/
5530*4882a593Smuzhiyun static int
ips_wait(ips_ha_t * ha,int time,int intr)5531*4882a593Smuzhiyun ips_wait(ips_ha_t * ha, int time, int intr)
5532*4882a593Smuzhiyun {
5533*4882a593Smuzhiyun int ret;
5534*4882a593Smuzhiyun int done;
5535*4882a593Smuzhiyun
5536*4882a593Smuzhiyun METHOD_TRACE("ips_wait", 1);
5537*4882a593Smuzhiyun
5538*4882a593Smuzhiyun ret = IPS_FAILURE;
5539*4882a593Smuzhiyun done = FALSE;
5540*4882a593Smuzhiyun
5541*4882a593Smuzhiyun time *= IPS_ONE_SEC; /* convert seconds */
5542*4882a593Smuzhiyun
5543*4882a593Smuzhiyun while ((time > 0) && (!done)) {
5544*4882a593Smuzhiyun if (intr == IPS_INTR_ON) {
5545*4882a593Smuzhiyun if (ha->waitflag == FALSE) {
5546*4882a593Smuzhiyun ret = IPS_SUCCESS;
5547*4882a593Smuzhiyun done = TRUE;
5548*4882a593Smuzhiyun break;
5549*4882a593Smuzhiyun }
5550*4882a593Smuzhiyun } else if (intr == IPS_INTR_IORL) {
5551*4882a593Smuzhiyun if (ha->waitflag == FALSE) {
5552*4882a593Smuzhiyun /*
5553*4882a593Smuzhiyun * controller generated an interrupt to
5554*4882a593Smuzhiyun * acknowledge completion of the command
5555*4882a593Smuzhiyun * and ips_intr() has serviced the interrupt.
5556*4882a593Smuzhiyun */
5557*4882a593Smuzhiyun ret = IPS_SUCCESS;
5558*4882a593Smuzhiyun done = TRUE;
5559*4882a593Smuzhiyun break;
5560*4882a593Smuzhiyun }
5561*4882a593Smuzhiyun
5562*4882a593Smuzhiyun /*
5563*4882a593Smuzhiyun * NOTE: we already have the io_request_lock so
5564*4882a593Smuzhiyun * even if we get an interrupt it won't get serviced
5565*4882a593Smuzhiyun * until after we finish.
5566*4882a593Smuzhiyun */
5567*4882a593Smuzhiyun
5568*4882a593Smuzhiyun (*ha->func.intr) (ha);
5569*4882a593Smuzhiyun }
5570*4882a593Smuzhiyun
5571*4882a593Smuzhiyun /* This looks like a very evil loop, but it only does this during start-up */
5572*4882a593Smuzhiyun udelay(1000);
5573*4882a593Smuzhiyun time--;
5574*4882a593Smuzhiyun }
5575*4882a593Smuzhiyun
5576*4882a593Smuzhiyun return (ret);
5577*4882a593Smuzhiyun }
5578*4882a593Smuzhiyun
5579*4882a593Smuzhiyun /****************************************************************************/
5580*4882a593Smuzhiyun /* */
5581*4882a593Smuzhiyun /* Routine Name: ips_write_driver_status */
5582*4882a593Smuzhiyun /* */
5583*4882a593Smuzhiyun /* Routine Description: */
5584*4882a593Smuzhiyun /* */
5585*4882a593Smuzhiyun /* Write OS/Driver version to Page 5 of the nvram on the controller */
5586*4882a593Smuzhiyun /* */
5587*4882a593Smuzhiyun /****************************************************************************/
5588*4882a593Smuzhiyun static int
ips_write_driver_status(ips_ha_t * ha,int intr)5589*4882a593Smuzhiyun ips_write_driver_status(ips_ha_t * ha, int intr)
5590*4882a593Smuzhiyun {
5591*4882a593Smuzhiyun METHOD_TRACE("ips_write_driver_status", 1);
5592*4882a593Smuzhiyun
5593*4882a593Smuzhiyun if (!ips_readwrite_page5(ha, FALSE, intr)) {
5594*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
5595*4882a593Smuzhiyun "unable to read NVRAM page 5.\n");
5596*4882a593Smuzhiyun
5597*4882a593Smuzhiyun return (0);
5598*4882a593Smuzhiyun }
5599*4882a593Smuzhiyun
5600*4882a593Smuzhiyun /* check to make sure the page has a valid */
5601*4882a593Smuzhiyun /* signature */
5602*4882a593Smuzhiyun if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
5603*4882a593Smuzhiyun DEBUG_VAR(1,
5604*4882a593Smuzhiyun "(%s%d) NVRAM page 5 has an invalid signature: %X.",
5605*4882a593Smuzhiyun ips_name, ha->host_num, ha->nvram->signature);
5606*4882a593Smuzhiyun ha->nvram->signature = IPS_NVRAM_P5_SIG;
5607*4882a593Smuzhiyun }
5608*4882a593Smuzhiyun
5609*4882a593Smuzhiyun DEBUG_VAR(2,
5610*4882a593Smuzhiyun "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
5611*4882a593Smuzhiyun ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),
5612*4882a593Smuzhiyun ha->nvram->adapter_slot, ha->nvram->bios_high[0],
5613*4882a593Smuzhiyun ha->nvram->bios_high[1], ha->nvram->bios_high[2],
5614*4882a593Smuzhiyun ha->nvram->bios_high[3], ha->nvram->bios_low[0],
5615*4882a593Smuzhiyun ha->nvram->bios_low[1], ha->nvram->bios_low[2],
5616*4882a593Smuzhiyun ha->nvram->bios_low[3]);
5617*4882a593Smuzhiyun
5618*4882a593Smuzhiyun ips_get_bios_version(ha, intr);
5619*4882a593Smuzhiyun
5620*4882a593Smuzhiyun /* change values (as needed) */
5621*4882a593Smuzhiyun ha->nvram->operating_system = IPS_OS_LINUX;
5622*4882a593Smuzhiyun ha->nvram->adapter_type = ha->ad_type;
5623*4882a593Smuzhiyun memcpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
5624*4882a593Smuzhiyun memcpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);
5625*4882a593Smuzhiyun memcpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
5626*4882a593Smuzhiyun memcpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
5627*4882a593Smuzhiyun
5628*4882a593Smuzhiyun ha->nvram->versioning = 0; /* Indicate the Driver Does Not Support Versioning */
5629*4882a593Smuzhiyun
5630*4882a593Smuzhiyun /* now update the page */
5631*4882a593Smuzhiyun if (!ips_readwrite_page5(ha, TRUE, intr)) {
5632*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
5633*4882a593Smuzhiyun "unable to write NVRAM page 5.\n");
5634*4882a593Smuzhiyun
5635*4882a593Smuzhiyun return (0);
5636*4882a593Smuzhiyun }
5637*4882a593Smuzhiyun
5638*4882a593Smuzhiyun /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
5639*4882a593Smuzhiyun ha->slot_num = ha->nvram->adapter_slot;
5640*4882a593Smuzhiyun
5641*4882a593Smuzhiyun return (1);
5642*4882a593Smuzhiyun }
5643*4882a593Smuzhiyun
5644*4882a593Smuzhiyun /****************************************************************************/
5645*4882a593Smuzhiyun /* */
5646*4882a593Smuzhiyun /* Routine Name: ips_read_adapter_status */
5647*4882a593Smuzhiyun /* */
5648*4882a593Smuzhiyun /* Routine Description: */
5649*4882a593Smuzhiyun /* */
5650*4882a593Smuzhiyun /* Do an Inquiry command to the adapter */
5651*4882a593Smuzhiyun /* */
5652*4882a593Smuzhiyun /****************************************************************************/
5653*4882a593Smuzhiyun static int
ips_read_adapter_status(ips_ha_t * ha,int intr)5654*4882a593Smuzhiyun ips_read_adapter_status(ips_ha_t * ha, int intr)
5655*4882a593Smuzhiyun {
5656*4882a593Smuzhiyun ips_scb_t *scb;
5657*4882a593Smuzhiyun int ret;
5658*4882a593Smuzhiyun
5659*4882a593Smuzhiyun METHOD_TRACE("ips_read_adapter_status", 1);
5660*4882a593Smuzhiyun
5661*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5662*4882a593Smuzhiyun
5663*4882a593Smuzhiyun ips_init_scb(ha, scb);
5664*4882a593Smuzhiyun
5665*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
5666*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_ENQUIRY;
5667*4882a593Smuzhiyun
5668*4882a593Smuzhiyun scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
5669*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
5670*4882a593Smuzhiyun scb->cmd.basic_io.sg_count = 0;
5671*4882a593Smuzhiyun scb->cmd.basic_io.lba = 0;
5672*4882a593Smuzhiyun scb->cmd.basic_io.sector_count = 0;
5673*4882a593Smuzhiyun scb->cmd.basic_io.log_drv = 0;
5674*4882a593Smuzhiyun scb->data_len = sizeof (*ha->enq);
5675*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
5676*4882a593Smuzhiyun
5677*4882a593Smuzhiyun /* send command */
5678*4882a593Smuzhiyun if (((ret =
5679*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5680*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
5681*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
5682*4882a593Smuzhiyun return (0);
5683*4882a593Smuzhiyun
5684*4882a593Smuzhiyun return (1);
5685*4882a593Smuzhiyun }
5686*4882a593Smuzhiyun
5687*4882a593Smuzhiyun /****************************************************************************/
5688*4882a593Smuzhiyun /* */
5689*4882a593Smuzhiyun /* Routine Name: ips_read_subsystem_parameters */
5690*4882a593Smuzhiyun /* */
5691*4882a593Smuzhiyun /* Routine Description: */
5692*4882a593Smuzhiyun /* */
5693*4882a593Smuzhiyun /* Read subsystem parameters from the adapter */
5694*4882a593Smuzhiyun /* */
5695*4882a593Smuzhiyun /****************************************************************************/
5696*4882a593Smuzhiyun static int
ips_read_subsystem_parameters(ips_ha_t * ha,int intr)5697*4882a593Smuzhiyun ips_read_subsystem_parameters(ips_ha_t * ha, int intr)
5698*4882a593Smuzhiyun {
5699*4882a593Smuzhiyun ips_scb_t *scb;
5700*4882a593Smuzhiyun int ret;
5701*4882a593Smuzhiyun
5702*4882a593Smuzhiyun METHOD_TRACE("ips_read_subsystem_parameters", 1);
5703*4882a593Smuzhiyun
5704*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5705*4882a593Smuzhiyun
5706*4882a593Smuzhiyun ips_init_scb(ha, scb);
5707*4882a593Smuzhiyun
5708*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
5709*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_GET_SUBSYS;
5710*4882a593Smuzhiyun
5711*4882a593Smuzhiyun scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
5712*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
5713*4882a593Smuzhiyun scb->cmd.basic_io.sg_count = 0;
5714*4882a593Smuzhiyun scb->cmd.basic_io.lba = 0;
5715*4882a593Smuzhiyun scb->cmd.basic_io.sector_count = 0;
5716*4882a593Smuzhiyun scb->cmd.basic_io.log_drv = 0;
5717*4882a593Smuzhiyun scb->data_len = sizeof (*ha->subsys);
5718*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
5719*4882a593Smuzhiyun
5720*4882a593Smuzhiyun /* send command */
5721*4882a593Smuzhiyun if (((ret =
5722*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5723*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
5724*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
5725*4882a593Smuzhiyun return (0);
5726*4882a593Smuzhiyun
5727*4882a593Smuzhiyun memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys));
5728*4882a593Smuzhiyun return (1);
5729*4882a593Smuzhiyun }
5730*4882a593Smuzhiyun
5731*4882a593Smuzhiyun /****************************************************************************/
5732*4882a593Smuzhiyun /* */
5733*4882a593Smuzhiyun /* Routine Name: ips_read_config */
5734*4882a593Smuzhiyun /* */
5735*4882a593Smuzhiyun /* Routine Description: */
5736*4882a593Smuzhiyun /* */
5737*4882a593Smuzhiyun /* Read the configuration on the adapter */
5738*4882a593Smuzhiyun /* */
5739*4882a593Smuzhiyun /****************************************************************************/
5740*4882a593Smuzhiyun static int
ips_read_config(ips_ha_t * ha,int intr)5741*4882a593Smuzhiyun ips_read_config(ips_ha_t * ha, int intr)
5742*4882a593Smuzhiyun {
5743*4882a593Smuzhiyun ips_scb_t *scb;
5744*4882a593Smuzhiyun int i;
5745*4882a593Smuzhiyun int ret;
5746*4882a593Smuzhiyun
5747*4882a593Smuzhiyun METHOD_TRACE("ips_read_config", 1);
5748*4882a593Smuzhiyun
5749*4882a593Smuzhiyun /* set defaults for initiator IDs */
5750*4882a593Smuzhiyun for (i = 0; i < 4; i++)
5751*4882a593Smuzhiyun ha->conf->init_id[i] = 7;
5752*4882a593Smuzhiyun
5753*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5754*4882a593Smuzhiyun
5755*4882a593Smuzhiyun ips_init_scb(ha, scb);
5756*4882a593Smuzhiyun
5757*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
5758*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_READ_CONF;
5759*4882a593Smuzhiyun
5760*4882a593Smuzhiyun scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
5761*4882a593Smuzhiyun scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
5762*4882a593Smuzhiyun scb->data_len = sizeof (*ha->conf);
5763*4882a593Smuzhiyun scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
5764*4882a593Smuzhiyun
5765*4882a593Smuzhiyun /* send command */
5766*4882a593Smuzhiyun if (((ret =
5767*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5768*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
5769*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
5770*4882a593Smuzhiyun
5771*4882a593Smuzhiyun memset(ha->conf, 0, sizeof (IPS_CONF));
5772*4882a593Smuzhiyun
5773*4882a593Smuzhiyun /* reset initiator IDs */
5774*4882a593Smuzhiyun for (i = 0; i < 4; i++)
5775*4882a593Smuzhiyun ha->conf->init_id[i] = 7;
5776*4882a593Smuzhiyun
5777*4882a593Smuzhiyun /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
5778*4882a593Smuzhiyun if ((scb->basic_status & IPS_GSC_STATUS_MASK) ==
5779*4882a593Smuzhiyun IPS_CMD_CMPLT_WERROR)
5780*4882a593Smuzhiyun return (1);
5781*4882a593Smuzhiyun
5782*4882a593Smuzhiyun return (0);
5783*4882a593Smuzhiyun }
5784*4882a593Smuzhiyun
5785*4882a593Smuzhiyun memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
5786*4882a593Smuzhiyun return (1);
5787*4882a593Smuzhiyun }
5788*4882a593Smuzhiyun
5789*4882a593Smuzhiyun /****************************************************************************/
5790*4882a593Smuzhiyun /* */
5791*4882a593Smuzhiyun /* Routine Name: ips_readwrite_page5 */
5792*4882a593Smuzhiyun /* */
5793*4882a593Smuzhiyun /* Routine Description: */
5794*4882a593Smuzhiyun /* */
5795*4882a593Smuzhiyun /* Read nvram page 5 from the adapter */
5796*4882a593Smuzhiyun /* */
5797*4882a593Smuzhiyun /****************************************************************************/
5798*4882a593Smuzhiyun static int
ips_readwrite_page5(ips_ha_t * ha,int write,int intr)5799*4882a593Smuzhiyun ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
5800*4882a593Smuzhiyun {
5801*4882a593Smuzhiyun ips_scb_t *scb;
5802*4882a593Smuzhiyun int ret;
5803*4882a593Smuzhiyun
5804*4882a593Smuzhiyun METHOD_TRACE("ips_readwrite_page5", 1);
5805*4882a593Smuzhiyun
5806*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5807*4882a593Smuzhiyun
5808*4882a593Smuzhiyun ips_init_scb(ha, scb);
5809*4882a593Smuzhiyun
5810*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
5811*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;
5812*4882a593Smuzhiyun
5813*4882a593Smuzhiyun scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;
5814*4882a593Smuzhiyun scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
5815*4882a593Smuzhiyun scb->cmd.nvram.page = 5;
5816*4882a593Smuzhiyun scb->cmd.nvram.write = write;
5817*4882a593Smuzhiyun scb->cmd.nvram.reserved = 0;
5818*4882a593Smuzhiyun scb->cmd.nvram.reserved2 = 0;
5819*4882a593Smuzhiyun scb->data_len = sizeof (*ha->nvram);
5820*4882a593Smuzhiyun scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
5821*4882a593Smuzhiyun if (write)
5822*4882a593Smuzhiyun memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
5823*4882a593Smuzhiyun
5824*4882a593Smuzhiyun /* issue the command */
5825*4882a593Smuzhiyun if (((ret =
5826*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5827*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
5828*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
5829*4882a593Smuzhiyun
5830*4882a593Smuzhiyun memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));
5831*4882a593Smuzhiyun
5832*4882a593Smuzhiyun return (0);
5833*4882a593Smuzhiyun }
5834*4882a593Smuzhiyun if (!write)
5835*4882a593Smuzhiyun memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram));
5836*4882a593Smuzhiyun return (1);
5837*4882a593Smuzhiyun }
5838*4882a593Smuzhiyun
5839*4882a593Smuzhiyun /****************************************************************************/
5840*4882a593Smuzhiyun /* */
5841*4882a593Smuzhiyun /* Routine Name: ips_clear_adapter */
5842*4882a593Smuzhiyun /* */
5843*4882a593Smuzhiyun /* Routine Description: */
5844*4882a593Smuzhiyun /* */
5845*4882a593Smuzhiyun /* Clear the stripe lock tables */
5846*4882a593Smuzhiyun /* */
5847*4882a593Smuzhiyun /****************************************************************************/
5848*4882a593Smuzhiyun static int
ips_clear_adapter(ips_ha_t * ha,int intr)5849*4882a593Smuzhiyun ips_clear_adapter(ips_ha_t * ha, int intr)
5850*4882a593Smuzhiyun {
5851*4882a593Smuzhiyun ips_scb_t *scb;
5852*4882a593Smuzhiyun int ret;
5853*4882a593Smuzhiyun
5854*4882a593Smuzhiyun METHOD_TRACE("ips_clear_adapter", 1);
5855*4882a593Smuzhiyun
5856*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5857*4882a593Smuzhiyun
5858*4882a593Smuzhiyun ips_init_scb(ha, scb);
5859*4882a593Smuzhiyun
5860*4882a593Smuzhiyun scb->timeout = ips_reset_timeout;
5861*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_CONFIG_SYNC;
5862*4882a593Smuzhiyun
5863*4882a593Smuzhiyun scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;
5864*4882a593Smuzhiyun scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);
5865*4882a593Smuzhiyun scb->cmd.config_sync.channel = 0;
5866*4882a593Smuzhiyun scb->cmd.config_sync.source_target = IPS_POCL;
5867*4882a593Smuzhiyun scb->cmd.config_sync.reserved = 0;
5868*4882a593Smuzhiyun scb->cmd.config_sync.reserved2 = 0;
5869*4882a593Smuzhiyun scb->cmd.config_sync.reserved3 = 0;
5870*4882a593Smuzhiyun
5871*4882a593Smuzhiyun /* issue command */
5872*4882a593Smuzhiyun if (((ret =
5873*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE)
5874*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
5875*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
5876*4882a593Smuzhiyun return (0);
5877*4882a593Smuzhiyun
5878*4882a593Smuzhiyun /* send unlock stripe command */
5879*4882a593Smuzhiyun ips_init_scb(ha, scb);
5880*4882a593Smuzhiyun
5881*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_ERROR_TABLE;
5882*4882a593Smuzhiyun scb->timeout = ips_reset_timeout;
5883*4882a593Smuzhiyun
5884*4882a593Smuzhiyun scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;
5885*4882a593Smuzhiyun scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);
5886*4882a593Smuzhiyun scb->cmd.unlock_stripe.log_drv = 0;
5887*4882a593Smuzhiyun scb->cmd.unlock_stripe.control = IPS_CSL;
5888*4882a593Smuzhiyun scb->cmd.unlock_stripe.reserved = 0;
5889*4882a593Smuzhiyun scb->cmd.unlock_stripe.reserved2 = 0;
5890*4882a593Smuzhiyun scb->cmd.unlock_stripe.reserved3 = 0;
5891*4882a593Smuzhiyun
5892*4882a593Smuzhiyun /* issue command */
5893*4882a593Smuzhiyun if (((ret =
5894*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
5895*4882a593Smuzhiyun || (ret == IPS_SUCCESS_IMM)
5896*4882a593Smuzhiyun || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
5897*4882a593Smuzhiyun return (0);
5898*4882a593Smuzhiyun
5899*4882a593Smuzhiyun return (1);
5900*4882a593Smuzhiyun }
5901*4882a593Smuzhiyun
5902*4882a593Smuzhiyun /****************************************************************************/
5903*4882a593Smuzhiyun /* */
5904*4882a593Smuzhiyun /* Routine Name: ips_ffdc_reset */
5905*4882a593Smuzhiyun /* */
5906*4882a593Smuzhiyun /* Routine Description: */
5907*4882a593Smuzhiyun /* */
5908*4882a593Smuzhiyun /* FFDC: write reset info */
5909*4882a593Smuzhiyun /* */
5910*4882a593Smuzhiyun /****************************************************************************/
5911*4882a593Smuzhiyun static void
ips_ffdc_reset(ips_ha_t * ha,int intr)5912*4882a593Smuzhiyun ips_ffdc_reset(ips_ha_t * ha, int intr)
5913*4882a593Smuzhiyun {
5914*4882a593Smuzhiyun ips_scb_t *scb;
5915*4882a593Smuzhiyun
5916*4882a593Smuzhiyun METHOD_TRACE("ips_ffdc_reset", 1);
5917*4882a593Smuzhiyun
5918*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5919*4882a593Smuzhiyun
5920*4882a593Smuzhiyun ips_init_scb(ha, scb);
5921*4882a593Smuzhiyun
5922*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
5923*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_FFDC;
5924*4882a593Smuzhiyun scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
5925*4882a593Smuzhiyun scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
5926*4882a593Smuzhiyun scb->cmd.ffdc.reset_count = ha->reset_count;
5927*4882a593Smuzhiyun scb->cmd.ffdc.reset_type = 0x80;
5928*4882a593Smuzhiyun
5929*4882a593Smuzhiyun /* convert time to what the card wants */
5930*4882a593Smuzhiyun ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
5931*4882a593Smuzhiyun
5932*4882a593Smuzhiyun /* issue command */
5933*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, intr);
5934*4882a593Smuzhiyun }
5935*4882a593Smuzhiyun
5936*4882a593Smuzhiyun /****************************************************************************/
5937*4882a593Smuzhiyun /* */
5938*4882a593Smuzhiyun /* Routine Name: ips_ffdc_time */
5939*4882a593Smuzhiyun /* */
5940*4882a593Smuzhiyun /* Routine Description: */
5941*4882a593Smuzhiyun /* */
5942*4882a593Smuzhiyun /* FFDC: write time info */
5943*4882a593Smuzhiyun /* */
5944*4882a593Smuzhiyun /****************************************************************************/
5945*4882a593Smuzhiyun static void
ips_ffdc_time(ips_ha_t * ha)5946*4882a593Smuzhiyun ips_ffdc_time(ips_ha_t * ha)
5947*4882a593Smuzhiyun {
5948*4882a593Smuzhiyun ips_scb_t *scb;
5949*4882a593Smuzhiyun
5950*4882a593Smuzhiyun METHOD_TRACE("ips_ffdc_time", 1);
5951*4882a593Smuzhiyun
5952*4882a593Smuzhiyun DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);
5953*4882a593Smuzhiyun
5954*4882a593Smuzhiyun scb = &ha->scbs[ha->max_cmds - 1];
5955*4882a593Smuzhiyun
5956*4882a593Smuzhiyun ips_init_scb(ha, scb);
5957*4882a593Smuzhiyun
5958*4882a593Smuzhiyun scb->timeout = ips_cmd_timeout;
5959*4882a593Smuzhiyun scb->cdb[0] = IPS_CMD_FFDC;
5960*4882a593Smuzhiyun scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
5961*4882a593Smuzhiyun scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
5962*4882a593Smuzhiyun scb->cmd.ffdc.reset_count = 0;
5963*4882a593Smuzhiyun scb->cmd.ffdc.reset_type = 0;
5964*4882a593Smuzhiyun
5965*4882a593Smuzhiyun /* convert time to what the card wants */
5966*4882a593Smuzhiyun ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
5967*4882a593Smuzhiyun
5968*4882a593Smuzhiyun /* issue command */
5969*4882a593Smuzhiyun ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
5970*4882a593Smuzhiyun }
5971*4882a593Smuzhiyun
5972*4882a593Smuzhiyun /****************************************************************************/
5973*4882a593Smuzhiyun /* */
5974*4882a593Smuzhiyun /* Routine Name: ips_fix_ffdc_time */
5975*4882a593Smuzhiyun /* */
5976*4882a593Smuzhiyun /* Routine Description: */
5977*4882a593Smuzhiyun /* Adjust time_t to what the card wants */
5978*4882a593Smuzhiyun /* */
5979*4882a593Smuzhiyun /****************************************************************************/
5980*4882a593Smuzhiyun static void
ips_fix_ffdc_time(ips_ha_t * ha,ips_scb_t * scb,time64_t current_time)5981*4882a593Smuzhiyun ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time64_t current_time)
5982*4882a593Smuzhiyun {
5983*4882a593Smuzhiyun struct tm tm;
5984*4882a593Smuzhiyun
5985*4882a593Smuzhiyun METHOD_TRACE("ips_fix_ffdc_time", 1);
5986*4882a593Smuzhiyun
5987*4882a593Smuzhiyun time64_to_tm(current_time, 0, &tm);
5988*4882a593Smuzhiyun
5989*4882a593Smuzhiyun scb->cmd.ffdc.hour = tm.tm_hour;
5990*4882a593Smuzhiyun scb->cmd.ffdc.minute = tm.tm_min;
5991*4882a593Smuzhiyun scb->cmd.ffdc.second = tm.tm_sec;
5992*4882a593Smuzhiyun scb->cmd.ffdc.yearH = (tm.tm_year + 1900) / 100;
5993*4882a593Smuzhiyun scb->cmd.ffdc.yearL = tm.tm_year % 100;
5994*4882a593Smuzhiyun scb->cmd.ffdc.month = tm.tm_mon + 1;
5995*4882a593Smuzhiyun scb->cmd.ffdc.day = tm.tm_mday;
5996*4882a593Smuzhiyun }
5997*4882a593Smuzhiyun
5998*4882a593Smuzhiyun /****************************************************************************
5999*4882a593Smuzhiyun * BIOS Flash Routines *
6000*4882a593Smuzhiyun ****************************************************************************/
6001*4882a593Smuzhiyun
6002*4882a593Smuzhiyun /****************************************************************************/
6003*4882a593Smuzhiyun /* */
6004*4882a593Smuzhiyun /* Routine Name: ips_erase_bios */
6005*4882a593Smuzhiyun /* */
6006*4882a593Smuzhiyun /* Routine Description: */
6007*4882a593Smuzhiyun /* Erase the BIOS on the adapter */
6008*4882a593Smuzhiyun /* */
6009*4882a593Smuzhiyun /****************************************************************************/
6010*4882a593Smuzhiyun static int
ips_erase_bios(ips_ha_t * ha)6011*4882a593Smuzhiyun ips_erase_bios(ips_ha_t * ha)
6012*4882a593Smuzhiyun {
6013*4882a593Smuzhiyun int timeout;
6014*4882a593Smuzhiyun uint8_t status = 0;
6015*4882a593Smuzhiyun
6016*4882a593Smuzhiyun METHOD_TRACE("ips_erase_bios", 1);
6017*4882a593Smuzhiyun
6018*4882a593Smuzhiyun status = 0;
6019*4882a593Smuzhiyun
6020*4882a593Smuzhiyun /* Clear the status register */
6021*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6022*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6023*4882a593Smuzhiyun udelay(25); /* 25 us */
6024*4882a593Smuzhiyun
6025*4882a593Smuzhiyun outb(0x50, ha->io_addr + IPS_REG_FLDP);
6026*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6027*4882a593Smuzhiyun udelay(25); /* 25 us */
6028*4882a593Smuzhiyun
6029*4882a593Smuzhiyun /* Erase Setup */
6030*4882a593Smuzhiyun outb(0x20, ha->io_addr + IPS_REG_FLDP);
6031*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6032*4882a593Smuzhiyun udelay(25); /* 25 us */
6033*4882a593Smuzhiyun
6034*4882a593Smuzhiyun /* Erase Confirm */
6035*4882a593Smuzhiyun outb(0xD0, ha->io_addr + IPS_REG_FLDP);
6036*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6037*4882a593Smuzhiyun udelay(25); /* 25 us */
6038*4882a593Smuzhiyun
6039*4882a593Smuzhiyun /* Erase Status */
6040*4882a593Smuzhiyun outb(0x70, ha->io_addr + IPS_REG_FLDP);
6041*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6042*4882a593Smuzhiyun udelay(25); /* 25 us */
6043*4882a593Smuzhiyun
6044*4882a593Smuzhiyun timeout = 80000; /* 80 seconds */
6045*4882a593Smuzhiyun
6046*4882a593Smuzhiyun while (timeout > 0) {
6047*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
6048*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6049*4882a593Smuzhiyun udelay(25); /* 25 us */
6050*4882a593Smuzhiyun }
6051*4882a593Smuzhiyun
6052*4882a593Smuzhiyun status = inb(ha->io_addr + IPS_REG_FLDP);
6053*4882a593Smuzhiyun
6054*4882a593Smuzhiyun if (status & 0x80)
6055*4882a593Smuzhiyun break;
6056*4882a593Smuzhiyun
6057*4882a593Smuzhiyun MDELAY(1);
6058*4882a593Smuzhiyun timeout--;
6059*4882a593Smuzhiyun }
6060*4882a593Smuzhiyun
6061*4882a593Smuzhiyun /* check for timeout */
6062*4882a593Smuzhiyun if (timeout <= 0) {
6063*4882a593Smuzhiyun /* timeout */
6064*4882a593Smuzhiyun
6065*4882a593Smuzhiyun /* try to suspend the erase */
6066*4882a593Smuzhiyun outb(0xB0, ha->io_addr + IPS_REG_FLDP);
6067*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6068*4882a593Smuzhiyun udelay(25); /* 25 us */
6069*4882a593Smuzhiyun
6070*4882a593Smuzhiyun /* wait for 10 seconds */
6071*4882a593Smuzhiyun timeout = 10000;
6072*4882a593Smuzhiyun while (timeout > 0) {
6073*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
6074*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6075*4882a593Smuzhiyun udelay(25); /* 25 us */
6076*4882a593Smuzhiyun }
6077*4882a593Smuzhiyun
6078*4882a593Smuzhiyun status = inb(ha->io_addr + IPS_REG_FLDP);
6079*4882a593Smuzhiyun
6080*4882a593Smuzhiyun if (status & 0xC0)
6081*4882a593Smuzhiyun break;
6082*4882a593Smuzhiyun
6083*4882a593Smuzhiyun MDELAY(1);
6084*4882a593Smuzhiyun timeout--;
6085*4882a593Smuzhiyun }
6086*4882a593Smuzhiyun
6087*4882a593Smuzhiyun return (1);
6088*4882a593Smuzhiyun }
6089*4882a593Smuzhiyun
6090*4882a593Smuzhiyun /* check for valid VPP */
6091*4882a593Smuzhiyun if (status & 0x08)
6092*4882a593Smuzhiyun /* VPP failure */
6093*4882a593Smuzhiyun return (1);
6094*4882a593Smuzhiyun
6095*4882a593Smuzhiyun /* check for successful flash */
6096*4882a593Smuzhiyun if (status & 0x30)
6097*4882a593Smuzhiyun /* sequence error */
6098*4882a593Smuzhiyun return (1);
6099*4882a593Smuzhiyun
6100*4882a593Smuzhiyun /* Otherwise, we were successful */
6101*4882a593Smuzhiyun /* clear status */
6102*4882a593Smuzhiyun outb(0x50, ha->io_addr + IPS_REG_FLDP);
6103*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6104*4882a593Smuzhiyun udelay(25); /* 25 us */
6105*4882a593Smuzhiyun
6106*4882a593Smuzhiyun /* enable reads */
6107*4882a593Smuzhiyun outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6108*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6109*4882a593Smuzhiyun udelay(25); /* 25 us */
6110*4882a593Smuzhiyun
6111*4882a593Smuzhiyun return (0);
6112*4882a593Smuzhiyun }
6113*4882a593Smuzhiyun
6114*4882a593Smuzhiyun /****************************************************************************/
6115*4882a593Smuzhiyun /* */
6116*4882a593Smuzhiyun /* Routine Name: ips_erase_bios_memio */
6117*4882a593Smuzhiyun /* */
6118*4882a593Smuzhiyun /* Routine Description: */
6119*4882a593Smuzhiyun /* Erase the BIOS on the adapter */
6120*4882a593Smuzhiyun /* */
6121*4882a593Smuzhiyun /****************************************************************************/
6122*4882a593Smuzhiyun static int
ips_erase_bios_memio(ips_ha_t * ha)6123*4882a593Smuzhiyun ips_erase_bios_memio(ips_ha_t * ha)
6124*4882a593Smuzhiyun {
6125*4882a593Smuzhiyun int timeout;
6126*4882a593Smuzhiyun uint8_t status;
6127*4882a593Smuzhiyun
6128*4882a593Smuzhiyun METHOD_TRACE("ips_erase_bios_memio", 1);
6129*4882a593Smuzhiyun
6130*4882a593Smuzhiyun status = 0;
6131*4882a593Smuzhiyun
6132*4882a593Smuzhiyun /* Clear the status register */
6133*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6134*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6135*4882a593Smuzhiyun udelay(25); /* 25 us */
6136*4882a593Smuzhiyun
6137*4882a593Smuzhiyun writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
6138*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6139*4882a593Smuzhiyun udelay(25); /* 25 us */
6140*4882a593Smuzhiyun
6141*4882a593Smuzhiyun /* Erase Setup */
6142*4882a593Smuzhiyun writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
6143*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6144*4882a593Smuzhiyun udelay(25); /* 25 us */
6145*4882a593Smuzhiyun
6146*4882a593Smuzhiyun /* Erase Confirm */
6147*4882a593Smuzhiyun writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
6148*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6149*4882a593Smuzhiyun udelay(25); /* 25 us */
6150*4882a593Smuzhiyun
6151*4882a593Smuzhiyun /* Erase Status */
6152*4882a593Smuzhiyun writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
6153*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6154*4882a593Smuzhiyun udelay(25); /* 25 us */
6155*4882a593Smuzhiyun
6156*4882a593Smuzhiyun timeout = 80000; /* 80 seconds */
6157*4882a593Smuzhiyun
6158*4882a593Smuzhiyun while (timeout > 0) {
6159*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
6160*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6161*4882a593Smuzhiyun udelay(25); /* 25 us */
6162*4882a593Smuzhiyun }
6163*4882a593Smuzhiyun
6164*4882a593Smuzhiyun status = readb(ha->mem_ptr + IPS_REG_FLDP);
6165*4882a593Smuzhiyun
6166*4882a593Smuzhiyun if (status & 0x80)
6167*4882a593Smuzhiyun break;
6168*4882a593Smuzhiyun
6169*4882a593Smuzhiyun MDELAY(1);
6170*4882a593Smuzhiyun timeout--;
6171*4882a593Smuzhiyun }
6172*4882a593Smuzhiyun
6173*4882a593Smuzhiyun /* check for timeout */
6174*4882a593Smuzhiyun if (timeout <= 0) {
6175*4882a593Smuzhiyun /* timeout */
6176*4882a593Smuzhiyun
6177*4882a593Smuzhiyun /* try to suspend the erase */
6178*4882a593Smuzhiyun writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
6179*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6180*4882a593Smuzhiyun udelay(25); /* 25 us */
6181*4882a593Smuzhiyun
6182*4882a593Smuzhiyun /* wait for 10 seconds */
6183*4882a593Smuzhiyun timeout = 10000;
6184*4882a593Smuzhiyun while (timeout > 0) {
6185*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
6186*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6187*4882a593Smuzhiyun udelay(25); /* 25 us */
6188*4882a593Smuzhiyun }
6189*4882a593Smuzhiyun
6190*4882a593Smuzhiyun status = readb(ha->mem_ptr + IPS_REG_FLDP);
6191*4882a593Smuzhiyun
6192*4882a593Smuzhiyun if (status & 0xC0)
6193*4882a593Smuzhiyun break;
6194*4882a593Smuzhiyun
6195*4882a593Smuzhiyun MDELAY(1);
6196*4882a593Smuzhiyun timeout--;
6197*4882a593Smuzhiyun }
6198*4882a593Smuzhiyun
6199*4882a593Smuzhiyun return (1);
6200*4882a593Smuzhiyun }
6201*4882a593Smuzhiyun
6202*4882a593Smuzhiyun /* check for valid VPP */
6203*4882a593Smuzhiyun if (status & 0x08)
6204*4882a593Smuzhiyun /* VPP failure */
6205*4882a593Smuzhiyun return (1);
6206*4882a593Smuzhiyun
6207*4882a593Smuzhiyun /* check for successful flash */
6208*4882a593Smuzhiyun if (status & 0x30)
6209*4882a593Smuzhiyun /* sequence error */
6210*4882a593Smuzhiyun return (1);
6211*4882a593Smuzhiyun
6212*4882a593Smuzhiyun /* Otherwise, we were successful */
6213*4882a593Smuzhiyun /* clear status */
6214*4882a593Smuzhiyun writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
6215*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6216*4882a593Smuzhiyun udelay(25); /* 25 us */
6217*4882a593Smuzhiyun
6218*4882a593Smuzhiyun /* enable reads */
6219*4882a593Smuzhiyun writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6220*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6221*4882a593Smuzhiyun udelay(25); /* 25 us */
6222*4882a593Smuzhiyun
6223*4882a593Smuzhiyun return (0);
6224*4882a593Smuzhiyun }
6225*4882a593Smuzhiyun
6226*4882a593Smuzhiyun /****************************************************************************/
6227*4882a593Smuzhiyun /* */
6228*4882a593Smuzhiyun /* Routine Name: ips_program_bios */
6229*4882a593Smuzhiyun /* */
6230*4882a593Smuzhiyun /* Routine Description: */
6231*4882a593Smuzhiyun /* Program the BIOS on the adapter */
6232*4882a593Smuzhiyun /* */
6233*4882a593Smuzhiyun /****************************************************************************/
6234*4882a593Smuzhiyun static int
ips_program_bios(ips_ha_t * ha,char * buffer,uint32_t buffersize,uint32_t offset)6235*4882a593Smuzhiyun ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6236*4882a593Smuzhiyun uint32_t offset)
6237*4882a593Smuzhiyun {
6238*4882a593Smuzhiyun int i;
6239*4882a593Smuzhiyun int timeout;
6240*4882a593Smuzhiyun uint8_t status = 0;
6241*4882a593Smuzhiyun
6242*4882a593Smuzhiyun METHOD_TRACE("ips_program_bios", 1);
6243*4882a593Smuzhiyun
6244*4882a593Smuzhiyun status = 0;
6245*4882a593Smuzhiyun
6246*4882a593Smuzhiyun for (i = 0; i < buffersize; i++) {
6247*4882a593Smuzhiyun /* write a byte */
6248*4882a593Smuzhiyun outl(i + offset, ha->io_addr + IPS_REG_FLAP);
6249*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6250*4882a593Smuzhiyun udelay(25); /* 25 us */
6251*4882a593Smuzhiyun
6252*4882a593Smuzhiyun outb(0x40, ha->io_addr + IPS_REG_FLDP);
6253*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6254*4882a593Smuzhiyun udelay(25); /* 25 us */
6255*4882a593Smuzhiyun
6256*4882a593Smuzhiyun outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
6257*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6258*4882a593Smuzhiyun udelay(25); /* 25 us */
6259*4882a593Smuzhiyun
6260*4882a593Smuzhiyun /* wait up to one second */
6261*4882a593Smuzhiyun timeout = 1000;
6262*4882a593Smuzhiyun while (timeout > 0) {
6263*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
6264*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6265*4882a593Smuzhiyun udelay(25); /* 25 us */
6266*4882a593Smuzhiyun }
6267*4882a593Smuzhiyun
6268*4882a593Smuzhiyun status = inb(ha->io_addr + IPS_REG_FLDP);
6269*4882a593Smuzhiyun
6270*4882a593Smuzhiyun if (status & 0x80)
6271*4882a593Smuzhiyun break;
6272*4882a593Smuzhiyun
6273*4882a593Smuzhiyun MDELAY(1);
6274*4882a593Smuzhiyun timeout--;
6275*4882a593Smuzhiyun }
6276*4882a593Smuzhiyun
6277*4882a593Smuzhiyun if (timeout == 0) {
6278*4882a593Smuzhiyun /* timeout error */
6279*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6280*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6281*4882a593Smuzhiyun udelay(25); /* 25 us */
6282*4882a593Smuzhiyun
6283*4882a593Smuzhiyun outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6284*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6285*4882a593Smuzhiyun udelay(25); /* 25 us */
6286*4882a593Smuzhiyun
6287*4882a593Smuzhiyun return (1);
6288*4882a593Smuzhiyun }
6289*4882a593Smuzhiyun
6290*4882a593Smuzhiyun /* check the status */
6291*4882a593Smuzhiyun if (status & 0x18) {
6292*4882a593Smuzhiyun /* programming error */
6293*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6294*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6295*4882a593Smuzhiyun udelay(25); /* 25 us */
6296*4882a593Smuzhiyun
6297*4882a593Smuzhiyun outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6298*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6299*4882a593Smuzhiyun udelay(25); /* 25 us */
6300*4882a593Smuzhiyun
6301*4882a593Smuzhiyun return (1);
6302*4882a593Smuzhiyun }
6303*4882a593Smuzhiyun } /* end for */
6304*4882a593Smuzhiyun
6305*4882a593Smuzhiyun /* Enable reading */
6306*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6307*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6308*4882a593Smuzhiyun udelay(25); /* 25 us */
6309*4882a593Smuzhiyun
6310*4882a593Smuzhiyun outb(0xFF, ha->io_addr + IPS_REG_FLDP);
6311*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6312*4882a593Smuzhiyun udelay(25); /* 25 us */
6313*4882a593Smuzhiyun
6314*4882a593Smuzhiyun return (0);
6315*4882a593Smuzhiyun }
6316*4882a593Smuzhiyun
6317*4882a593Smuzhiyun /****************************************************************************/
6318*4882a593Smuzhiyun /* */
6319*4882a593Smuzhiyun /* Routine Name: ips_program_bios_memio */
6320*4882a593Smuzhiyun /* */
6321*4882a593Smuzhiyun /* Routine Description: */
6322*4882a593Smuzhiyun /* Program the BIOS on the adapter */
6323*4882a593Smuzhiyun /* */
6324*4882a593Smuzhiyun /****************************************************************************/
6325*4882a593Smuzhiyun static int
ips_program_bios_memio(ips_ha_t * ha,char * buffer,uint32_t buffersize,uint32_t offset)6326*4882a593Smuzhiyun ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6327*4882a593Smuzhiyun uint32_t offset)
6328*4882a593Smuzhiyun {
6329*4882a593Smuzhiyun int i;
6330*4882a593Smuzhiyun int timeout;
6331*4882a593Smuzhiyun uint8_t status = 0;
6332*4882a593Smuzhiyun
6333*4882a593Smuzhiyun METHOD_TRACE("ips_program_bios_memio", 1);
6334*4882a593Smuzhiyun
6335*4882a593Smuzhiyun status = 0;
6336*4882a593Smuzhiyun
6337*4882a593Smuzhiyun for (i = 0; i < buffersize; i++) {
6338*4882a593Smuzhiyun /* write a byte */
6339*4882a593Smuzhiyun writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
6340*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6341*4882a593Smuzhiyun udelay(25); /* 25 us */
6342*4882a593Smuzhiyun
6343*4882a593Smuzhiyun writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
6344*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6345*4882a593Smuzhiyun udelay(25); /* 25 us */
6346*4882a593Smuzhiyun
6347*4882a593Smuzhiyun writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
6348*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6349*4882a593Smuzhiyun udelay(25); /* 25 us */
6350*4882a593Smuzhiyun
6351*4882a593Smuzhiyun /* wait up to one second */
6352*4882a593Smuzhiyun timeout = 1000;
6353*4882a593Smuzhiyun while (timeout > 0) {
6354*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
6355*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6356*4882a593Smuzhiyun udelay(25); /* 25 us */
6357*4882a593Smuzhiyun }
6358*4882a593Smuzhiyun
6359*4882a593Smuzhiyun status = readb(ha->mem_ptr + IPS_REG_FLDP);
6360*4882a593Smuzhiyun
6361*4882a593Smuzhiyun if (status & 0x80)
6362*4882a593Smuzhiyun break;
6363*4882a593Smuzhiyun
6364*4882a593Smuzhiyun MDELAY(1);
6365*4882a593Smuzhiyun timeout--;
6366*4882a593Smuzhiyun }
6367*4882a593Smuzhiyun
6368*4882a593Smuzhiyun if (timeout == 0) {
6369*4882a593Smuzhiyun /* timeout error */
6370*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6371*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6372*4882a593Smuzhiyun udelay(25); /* 25 us */
6373*4882a593Smuzhiyun
6374*4882a593Smuzhiyun writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6375*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6376*4882a593Smuzhiyun udelay(25); /* 25 us */
6377*4882a593Smuzhiyun
6378*4882a593Smuzhiyun return (1);
6379*4882a593Smuzhiyun }
6380*4882a593Smuzhiyun
6381*4882a593Smuzhiyun /* check the status */
6382*4882a593Smuzhiyun if (status & 0x18) {
6383*4882a593Smuzhiyun /* programming error */
6384*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6385*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6386*4882a593Smuzhiyun udelay(25); /* 25 us */
6387*4882a593Smuzhiyun
6388*4882a593Smuzhiyun writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6389*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6390*4882a593Smuzhiyun udelay(25); /* 25 us */
6391*4882a593Smuzhiyun
6392*4882a593Smuzhiyun return (1);
6393*4882a593Smuzhiyun }
6394*4882a593Smuzhiyun } /* end for */
6395*4882a593Smuzhiyun
6396*4882a593Smuzhiyun /* Enable reading */
6397*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6398*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6399*4882a593Smuzhiyun udelay(25); /* 25 us */
6400*4882a593Smuzhiyun
6401*4882a593Smuzhiyun writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
6402*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6403*4882a593Smuzhiyun udelay(25); /* 25 us */
6404*4882a593Smuzhiyun
6405*4882a593Smuzhiyun return (0);
6406*4882a593Smuzhiyun }
6407*4882a593Smuzhiyun
6408*4882a593Smuzhiyun /****************************************************************************/
6409*4882a593Smuzhiyun /* */
6410*4882a593Smuzhiyun /* Routine Name: ips_verify_bios */
6411*4882a593Smuzhiyun /* */
6412*4882a593Smuzhiyun /* Routine Description: */
6413*4882a593Smuzhiyun /* Verify the BIOS on the adapter */
6414*4882a593Smuzhiyun /* */
6415*4882a593Smuzhiyun /****************************************************************************/
6416*4882a593Smuzhiyun static int
ips_verify_bios(ips_ha_t * ha,char * buffer,uint32_t buffersize,uint32_t offset)6417*4882a593Smuzhiyun ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6418*4882a593Smuzhiyun uint32_t offset)
6419*4882a593Smuzhiyun {
6420*4882a593Smuzhiyun uint8_t checksum;
6421*4882a593Smuzhiyun int i;
6422*4882a593Smuzhiyun
6423*4882a593Smuzhiyun METHOD_TRACE("ips_verify_bios", 1);
6424*4882a593Smuzhiyun
6425*4882a593Smuzhiyun /* test 1st byte */
6426*4882a593Smuzhiyun outl(0, ha->io_addr + IPS_REG_FLAP);
6427*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6428*4882a593Smuzhiyun udelay(25); /* 25 us */
6429*4882a593Smuzhiyun
6430*4882a593Smuzhiyun if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
6431*4882a593Smuzhiyun return (1);
6432*4882a593Smuzhiyun
6433*4882a593Smuzhiyun outl(1, ha->io_addr + IPS_REG_FLAP);
6434*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6435*4882a593Smuzhiyun udelay(25); /* 25 us */
6436*4882a593Smuzhiyun if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
6437*4882a593Smuzhiyun return (1);
6438*4882a593Smuzhiyun
6439*4882a593Smuzhiyun checksum = 0xff;
6440*4882a593Smuzhiyun for (i = 2; i < buffersize; i++) {
6441*4882a593Smuzhiyun
6442*4882a593Smuzhiyun outl(i + offset, ha->io_addr + IPS_REG_FLAP);
6443*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6444*4882a593Smuzhiyun udelay(25); /* 25 us */
6445*4882a593Smuzhiyun
6446*4882a593Smuzhiyun checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
6447*4882a593Smuzhiyun }
6448*4882a593Smuzhiyun
6449*4882a593Smuzhiyun if (checksum != 0)
6450*4882a593Smuzhiyun /* failure */
6451*4882a593Smuzhiyun return (1);
6452*4882a593Smuzhiyun else
6453*4882a593Smuzhiyun /* success */
6454*4882a593Smuzhiyun return (0);
6455*4882a593Smuzhiyun }
6456*4882a593Smuzhiyun
6457*4882a593Smuzhiyun /****************************************************************************/
6458*4882a593Smuzhiyun /* */
6459*4882a593Smuzhiyun /* Routine Name: ips_verify_bios_memio */
6460*4882a593Smuzhiyun /* */
6461*4882a593Smuzhiyun /* Routine Description: */
6462*4882a593Smuzhiyun /* Verify the BIOS on the adapter */
6463*4882a593Smuzhiyun /* */
6464*4882a593Smuzhiyun /****************************************************************************/
6465*4882a593Smuzhiyun static int
ips_verify_bios_memio(ips_ha_t * ha,char * buffer,uint32_t buffersize,uint32_t offset)6466*4882a593Smuzhiyun ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
6467*4882a593Smuzhiyun uint32_t offset)
6468*4882a593Smuzhiyun {
6469*4882a593Smuzhiyun uint8_t checksum;
6470*4882a593Smuzhiyun int i;
6471*4882a593Smuzhiyun
6472*4882a593Smuzhiyun METHOD_TRACE("ips_verify_bios_memio", 1);
6473*4882a593Smuzhiyun
6474*4882a593Smuzhiyun /* test 1st byte */
6475*4882a593Smuzhiyun writel(0, ha->mem_ptr + IPS_REG_FLAP);
6476*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6477*4882a593Smuzhiyun udelay(25); /* 25 us */
6478*4882a593Smuzhiyun
6479*4882a593Smuzhiyun if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
6480*4882a593Smuzhiyun return (1);
6481*4882a593Smuzhiyun
6482*4882a593Smuzhiyun writel(1, ha->mem_ptr + IPS_REG_FLAP);
6483*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6484*4882a593Smuzhiyun udelay(25); /* 25 us */
6485*4882a593Smuzhiyun if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
6486*4882a593Smuzhiyun return (1);
6487*4882a593Smuzhiyun
6488*4882a593Smuzhiyun checksum = 0xff;
6489*4882a593Smuzhiyun for (i = 2; i < buffersize; i++) {
6490*4882a593Smuzhiyun
6491*4882a593Smuzhiyun writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
6492*4882a593Smuzhiyun if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
6493*4882a593Smuzhiyun udelay(25); /* 25 us */
6494*4882a593Smuzhiyun
6495*4882a593Smuzhiyun checksum =
6496*4882a593Smuzhiyun (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
6497*4882a593Smuzhiyun }
6498*4882a593Smuzhiyun
6499*4882a593Smuzhiyun if (checksum != 0)
6500*4882a593Smuzhiyun /* failure */
6501*4882a593Smuzhiyun return (1);
6502*4882a593Smuzhiyun else
6503*4882a593Smuzhiyun /* success */
6504*4882a593Smuzhiyun return (0);
6505*4882a593Smuzhiyun }
6506*4882a593Smuzhiyun
6507*4882a593Smuzhiyun /****************************************************************************/
6508*4882a593Smuzhiyun /* */
6509*4882a593Smuzhiyun /* Routine Name: ips_abort_init */
6510*4882a593Smuzhiyun /* */
6511*4882a593Smuzhiyun /* Routine Description: */
6512*4882a593Smuzhiyun /* cleanup routine for a failed adapter initialization */
6513*4882a593Smuzhiyun /****************************************************************************/
6514*4882a593Smuzhiyun static int
ips_abort_init(ips_ha_t * ha,int index)6515*4882a593Smuzhiyun ips_abort_init(ips_ha_t * ha, int index)
6516*4882a593Smuzhiyun {
6517*4882a593Smuzhiyun ha->active = 0;
6518*4882a593Smuzhiyun ips_free(ha);
6519*4882a593Smuzhiyun ips_ha[index] = NULL;
6520*4882a593Smuzhiyun ips_sh[index] = NULL;
6521*4882a593Smuzhiyun return -1;
6522*4882a593Smuzhiyun }
6523*4882a593Smuzhiyun
6524*4882a593Smuzhiyun /****************************************************************************/
6525*4882a593Smuzhiyun /* */
6526*4882a593Smuzhiyun /* Routine Name: ips_shift_controllers */
6527*4882a593Smuzhiyun /* */
6528*4882a593Smuzhiyun /* Routine Description: */
6529*4882a593Smuzhiyun /* helper function for ordering adapters */
6530*4882a593Smuzhiyun /****************************************************************************/
6531*4882a593Smuzhiyun static void
ips_shift_controllers(int lowindex,int highindex)6532*4882a593Smuzhiyun ips_shift_controllers(int lowindex, int highindex)
6533*4882a593Smuzhiyun {
6534*4882a593Smuzhiyun ips_ha_t *ha_sav = ips_ha[highindex];
6535*4882a593Smuzhiyun struct Scsi_Host *sh_sav = ips_sh[highindex];
6536*4882a593Smuzhiyun int i;
6537*4882a593Smuzhiyun
6538*4882a593Smuzhiyun for (i = highindex; i > lowindex; i--) {
6539*4882a593Smuzhiyun ips_ha[i] = ips_ha[i - 1];
6540*4882a593Smuzhiyun ips_sh[i] = ips_sh[i - 1];
6541*4882a593Smuzhiyun ips_ha[i]->host_num = i;
6542*4882a593Smuzhiyun }
6543*4882a593Smuzhiyun ha_sav->host_num = lowindex;
6544*4882a593Smuzhiyun ips_ha[lowindex] = ha_sav;
6545*4882a593Smuzhiyun ips_sh[lowindex] = sh_sav;
6546*4882a593Smuzhiyun }
6547*4882a593Smuzhiyun
6548*4882a593Smuzhiyun /****************************************************************************/
6549*4882a593Smuzhiyun /* */
6550*4882a593Smuzhiyun /* Routine Name: ips_order_controllers */
6551*4882a593Smuzhiyun /* */
6552*4882a593Smuzhiyun /* Routine Description: */
6553*4882a593Smuzhiyun /* place controllers is the "proper" boot order */
6554*4882a593Smuzhiyun /****************************************************************************/
6555*4882a593Smuzhiyun static void
ips_order_controllers(void)6556*4882a593Smuzhiyun ips_order_controllers(void)
6557*4882a593Smuzhiyun {
6558*4882a593Smuzhiyun int i, j, tmp, position = 0;
6559*4882a593Smuzhiyun IPS_NVRAM_P5 *nvram;
6560*4882a593Smuzhiyun if (!ips_ha[0])
6561*4882a593Smuzhiyun return;
6562*4882a593Smuzhiyun nvram = ips_ha[0]->nvram;
6563*4882a593Smuzhiyun
6564*4882a593Smuzhiyun if (nvram->adapter_order[0]) {
6565*4882a593Smuzhiyun for (i = 1; i <= nvram->adapter_order[0]; i++) {
6566*4882a593Smuzhiyun for (j = position; j < ips_num_controllers; j++) {
6567*4882a593Smuzhiyun switch (ips_ha[j]->ad_type) {
6568*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID6M:
6569*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID7M:
6570*4882a593Smuzhiyun if (nvram->adapter_order[i] == 'M') {
6571*4882a593Smuzhiyun ips_shift_controllers(position,
6572*4882a593Smuzhiyun j);
6573*4882a593Smuzhiyun position++;
6574*4882a593Smuzhiyun }
6575*4882a593Smuzhiyun break;
6576*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID4L:
6577*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID4M:
6578*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID4MX:
6579*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID4LX:
6580*4882a593Smuzhiyun if (nvram->adapter_order[i] == 'N') {
6581*4882a593Smuzhiyun ips_shift_controllers(position,
6582*4882a593Smuzhiyun j);
6583*4882a593Smuzhiyun position++;
6584*4882a593Smuzhiyun }
6585*4882a593Smuzhiyun break;
6586*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID6I:
6587*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID5I2:
6588*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID5I1:
6589*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID7k:
6590*4882a593Smuzhiyun if (nvram->adapter_order[i] == 'S') {
6591*4882a593Smuzhiyun ips_shift_controllers(position,
6592*4882a593Smuzhiyun j);
6593*4882a593Smuzhiyun position++;
6594*4882a593Smuzhiyun }
6595*4882a593Smuzhiyun break;
6596*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID:
6597*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID2:
6598*4882a593Smuzhiyun case IPS_ADTYPE_NAVAJO:
6599*4882a593Smuzhiyun case IPS_ADTYPE_KIOWA:
6600*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID3L:
6601*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID3:
6602*4882a593Smuzhiyun case IPS_ADTYPE_SERVERAID4H:
6603*4882a593Smuzhiyun if (nvram->adapter_order[i] == 'A') {
6604*4882a593Smuzhiyun ips_shift_controllers(position,
6605*4882a593Smuzhiyun j);
6606*4882a593Smuzhiyun position++;
6607*4882a593Smuzhiyun }
6608*4882a593Smuzhiyun break;
6609*4882a593Smuzhiyun default:
6610*4882a593Smuzhiyun break;
6611*4882a593Smuzhiyun }
6612*4882a593Smuzhiyun }
6613*4882a593Smuzhiyun }
6614*4882a593Smuzhiyun /* if adapter_order[0], then ordering is complete */
6615*4882a593Smuzhiyun return;
6616*4882a593Smuzhiyun }
6617*4882a593Smuzhiyun /* old bios, use older ordering */
6618*4882a593Smuzhiyun tmp = 0;
6619*4882a593Smuzhiyun for (i = position; i < ips_num_controllers; i++) {
6620*4882a593Smuzhiyun if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 ||
6621*4882a593Smuzhiyun ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) {
6622*4882a593Smuzhiyun ips_shift_controllers(position, i);
6623*4882a593Smuzhiyun position++;
6624*4882a593Smuzhiyun tmp = 1;
6625*4882a593Smuzhiyun }
6626*4882a593Smuzhiyun }
6627*4882a593Smuzhiyun /* if there were no 5I cards, then don't do any extra ordering */
6628*4882a593Smuzhiyun if (!tmp)
6629*4882a593Smuzhiyun return;
6630*4882a593Smuzhiyun for (i = position; i < ips_num_controllers; i++) {
6631*4882a593Smuzhiyun if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L ||
6632*4882a593Smuzhiyun ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M ||
6633*4882a593Smuzhiyun ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX ||
6634*4882a593Smuzhiyun ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) {
6635*4882a593Smuzhiyun ips_shift_controllers(position, i);
6636*4882a593Smuzhiyun position++;
6637*4882a593Smuzhiyun }
6638*4882a593Smuzhiyun }
6639*4882a593Smuzhiyun
6640*4882a593Smuzhiyun return;
6641*4882a593Smuzhiyun }
6642*4882a593Smuzhiyun
6643*4882a593Smuzhiyun /****************************************************************************/
6644*4882a593Smuzhiyun /* */
6645*4882a593Smuzhiyun /* Routine Name: ips_register_scsi */
6646*4882a593Smuzhiyun /* */
6647*4882a593Smuzhiyun /* Routine Description: */
6648*4882a593Smuzhiyun /* perform any registration and setup with the scsi layer */
6649*4882a593Smuzhiyun /****************************************************************************/
6650*4882a593Smuzhiyun static int
ips_register_scsi(int index)6651*4882a593Smuzhiyun ips_register_scsi(int index)
6652*4882a593Smuzhiyun {
6653*4882a593Smuzhiyun struct Scsi_Host *sh;
6654*4882a593Smuzhiyun ips_ha_t *ha, *oldha = ips_ha[index];
6655*4882a593Smuzhiyun sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t));
6656*4882a593Smuzhiyun if (!sh) {
6657*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, oldha->pcidev,
6658*4882a593Smuzhiyun "Unable to register controller with SCSI subsystem\n");
6659*4882a593Smuzhiyun return -1;
6660*4882a593Smuzhiyun }
6661*4882a593Smuzhiyun ha = IPS_HA(sh);
6662*4882a593Smuzhiyun memcpy(ha, oldha, sizeof (ips_ha_t));
6663*4882a593Smuzhiyun free_irq(oldha->pcidev->irq, oldha);
6664*4882a593Smuzhiyun /* Install the interrupt handler with the new ha */
6665*4882a593Smuzhiyun if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
6666*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
6667*4882a593Smuzhiyun "Unable to install interrupt handler\n");
6668*4882a593Smuzhiyun goto err_out_sh;
6669*4882a593Smuzhiyun }
6670*4882a593Smuzhiyun
6671*4882a593Smuzhiyun kfree(oldha);
6672*4882a593Smuzhiyun
6673*4882a593Smuzhiyun /* Store away needed values for later use */
6674*4882a593Smuzhiyun sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
6675*4882a593Smuzhiyun sh->sg_tablesize = sh->hostt->sg_tablesize;
6676*4882a593Smuzhiyun sh->can_queue = sh->hostt->can_queue;
6677*4882a593Smuzhiyun sh->cmd_per_lun = sh->hostt->cmd_per_lun;
6678*4882a593Smuzhiyun sh->max_sectors = 128;
6679*4882a593Smuzhiyun
6680*4882a593Smuzhiyun sh->max_id = ha->ntargets;
6681*4882a593Smuzhiyun sh->max_lun = ha->nlun;
6682*4882a593Smuzhiyun sh->max_channel = ha->nbus - 1;
6683*4882a593Smuzhiyun sh->can_queue = ha->max_cmds - 1;
6684*4882a593Smuzhiyun
6685*4882a593Smuzhiyun if (scsi_add_host(sh, &ha->pcidev->dev))
6686*4882a593Smuzhiyun goto err_out;
6687*4882a593Smuzhiyun
6688*4882a593Smuzhiyun ips_sh[index] = sh;
6689*4882a593Smuzhiyun ips_ha[index] = ha;
6690*4882a593Smuzhiyun
6691*4882a593Smuzhiyun scsi_scan_host(sh);
6692*4882a593Smuzhiyun
6693*4882a593Smuzhiyun return 0;
6694*4882a593Smuzhiyun
6695*4882a593Smuzhiyun err_out:
6696*4882a593Smuzhiyun free_irq(ha->pcidev->irq, ha);
6697*4882a593Smuzhiyun err_out_sh:
6698*4882a593Smuzhiyun scsi_host_put(sh);
6699*4882a593Smuzhiyun return -1;
6700*4882a593Smuzhiyun }
6701*4882a593Smuzhiyun
6702*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
6703*4882a593Smuzhiyun /* Routine Name: ips_remove_device */
6704*4882a593Smuzhiyun /* */
6705*4882a593Smuzhiyun /* Routine Description: */
6706*4882a593Smuzhiyun /* Remove one Adapter ( Hot Plugging ) */
6707*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
6708*4882a593Smuzhiyun static void
ips_remove_device(struct pci_dev * pci_dev)6709*4882a593Smuzhiyun ips_remove_device(struct pci_dev *pci_dev)
6710*4882a593Smuzhiyun {
6711*4882a593Smuzhiyun struct Scsi_Host *sh = pci_get_drvdata(pci_dev);
6712*4882a593Smuzhiyun
6713*4882a593Smuzhiyun pci_set_drvdata(pci_dev, NULL);
6714*4882a593Smuzhiyun
6715*4882a593Smuzhiyun ips_release(sh);
6716*4882a593Smuzhiyun
6717*4882a593Smuzhiyun pci_release_regions(pci_dev);
6718*4882a593Smuzhiyun pci_disable_device(pci_dev);
6719*4882a593Smuzhiyun }
6720*4882a593Smuzhiyun
6721*4882a593Smuzhiyun /****************************************************************************/
6722*4882a593Smuzhiyun /* */
6723*4882a593Smuzhiyun /* Routine Name: ips_module_init */
6724*4882a593Smuzhiyun /* */
6725*4882a593Smuzhiyun /* Routine Description: */
6726*4882a593Smuzhiyun /* function called on module load */
6727*4882a593Smuzhiyun /****************************************************************************/
6728*4882a593Smuzhiyun static int __init
ips_module_init(void)6729*4882a593Smuzhiyun ips_module_init(void)
6730*4882a593Smuzhiyun {
6731*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
6732*4882a593Smuzhiyun printk(KERN_ERR "ips: This driver has only been tested on the x86/ia64/x86_64 platforms\n");
6733*4882a593Smuzhiyun add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
6734*4882a593Smuzhiyun #endif
6735*4882a593Smuzhiyun
6736*4882a593Smuzhiyun if (pci_register_driver(&ips_pci_driver) < 0)
6737*4882a593Smuzhiyun return -ENODEV;
6738*4882a593Smuzhiyun ips_driver_template.module = THIS_MODULE;
6739*4882a593Smuzhiyun ips_order_controllers();
6740*4882a593Smuzhiyun if (!ips_detect(&ips_driver_template)) {
6741*4882a593Smuzhiyun pci_unregister_driver(&ips_pci_driver);
6742*4882a593Smuzhiyun return -ENODEV;
6743*4882a593Smuzhiyun }
6744*4882a593Smuzhiyun register_reboot_notifier(&ips_notifier);
6745*4882a593Smuzhiyun return 0;
6746*4882a593Smuzhiyun }
6747*4882a593Smuzhiyun
6748*4882a593Smuzhiyun /****************************************************************************/
6749*4882a593Smuzhiyun /* */
6750*4882a593Smuzhiyun /* Routine Name: ips_module_exit */
6751*4882a593Smuzhiyun /* */
6752*4882a593Smuzhiyun /* Routine Description: */
6753*4882a593Smuzhiyun /* function called on module unload */
6754*4882a593Smuzhiyun /****************************************************************************/
6755*4882a593Smuzhiyun static void __exit
ips_module_exit(void)6756*4882a593Smuzhiyun ips_module_exit(void)
6757*4882a593Smuzhiyun {
6758*4882a593Smuzhiyun pci_unregister_driver(&ips_pci_driver);
6759*4882a593Smuzhiyun unregister_reboot_notifier(&ips_notifier);
6760*4882a593Smuzhiyun }
6761*4882a593Smuzhiyun
6762*4882a593Smuzhiyun module_init(ips_module_init);
6763*4882a593Smuzhiyun module_exit(ips_module_exit);
6764*4882a593Smuzhiyun
6765*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
6766*4882a593Smuzhiyun /* Routine Name: ips_insert_device */
6767*4882a593Smuzhiyun /* */
6768*4882a593Smuzhiyun /* Routine Description: */
6769*4882a593Smuzhiyun /* Add One Adapter ( Hot Plug ) */
6770*4882a593Smuzhiyun /* */
6771*4882a593Smuzhiyun /* Return Value: */
6772*4882a593Smuzhiyun /* 0 if Successful, else non-zero */
6773*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
6774*4882a593Smuzhiyun static int
ips_insert_device(struct pci_dev * pci_dev,const struct pci_device_id * ent)6775*4882a593Smuzhiyun ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
6776*4882a593Smuzhiyun {
6777*4882a593Smuzhiyun int index = -1;
6778*4882a593Smuzhiyun int rc;
6779*4882a593Smuzhiyun
6780*4882a593Smuzhiyun METHOD_TRACE("ips_insert_device", 1);
6781*4882a593Smuzhiyun rc = pci_enable_device(pci_dev);
6782*4882a593Smuzhiyun if (rc)
6783*4882a593Smuzhiyun return rc;
6784*4882a593Smuzhiyun
6785*4882a593Smuzhiyun rc = pci_request_regions(pci_dev, "ips");
6786*4882a593Smuzhiyun if (rc)
6787*4882a593Smuzhiyun goto err_out;
6788*4882a593Smuzhiyun
6789*4882a593Smuzhiyun rc = ips_init_phase1(pci_dev, &index);
6790*4882a593Smuzhiyun if (rc == SUCCESS)
6791*4882a593Smuzhiyun rc = ips_init_phase2(index);
6792*4882a593Smuzhiyun
6793*4882a593Smuzhiyun if (ips_hotplug)
6794*4882a593Smuzhiyun if (ips_register_scsi(index)) {
6795*4882a593Smuzhiyun ips_free(ips_ha[index]);
6796*4882a593Smuzhiyun rc = -1;
6797*4882a593Smuzhiyun }
6798*4882a593Smuzhiyun
6799*4882a593Smuzhiyun if (rc == SUCCESS)
6800*4882a593Smuzhiyun ips_num_controllers++;
6801*4882a593Smuzhiyun
6802*4882a593Smuzhiyun ips_next_controller = ips_num_controllers;
6803*4882a593Smuzhiyun
6804*4882a593Smuzhiyun if (rc < 0) {
6805*4882a593Smuzhiyun rc = -ENODEV;
6806*4882a593Smuzhiyun goto err_out_regions;
6807*4882a593Smuzhiyun }
6808*4882a593Smuzhiyun
6809*4882a593Smuzhiyun pci_set_drvdata(pci_dev, ips_sh[index]);
6810*4882a593Smuzhiyun return 0;
6811*4882a593Smuzhiyun
6812*4882a593Smuzhiyun err_out_regions:
6813*4882a593Smuzhiyun pci_release_regions(pci_dev);
6814*4882a593Smuzhiyun err_out:
6815*4882a593Smuzhiyun pci_disable_device(pci_dev);
6816*4882a593Smuzhiyun return rc;
6817*4882a593Smuzhiyun }
6818*4882a593Smuzhiyun
6819*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
6820*4882a593Smuzhiyun /* Routine Name: ips_init_phase1 */
6821*4882a593Smuzhiyun /* */
6822*4882a593Smuzhiyun /* Routine Description: */
6823*4882a593Smuzhiyun /* Adapter Initialization */
6824*4882a593Smuzhiyun /* */
6825*4882a593Smuzhiyun /* Return Value: */
6826*4882a593Smuzhiyun /* 0 if Successful, else non-zero */
6827*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
6828*4882a593Smuzhiyun static int
ips_init_phase1(struct pci_dev * pci_dev,int * indexPtr)6829*4882a593Smuzhiyun ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
6830*4882a593Smuzhiyun {
6831*4882a593Smuzhiyun ips_ha_t *ha;
6832*4882a593Smuzhiyun uint32_t io_addr;
6833*4882a593Smuzhiyun uint32_t mem_addr;
6834*4882a593Smuzhiyun uint32_t io_len;
6835*4882a593Smuzhiyun uint32_t mem_len;
6836*4882a593Smuzhiyun int j;
6837*4882a593Smuzhiyun int index;
6838*4882a593Smuzhiyun dma_addr_t dma_address;
6839*4882a593Smuzhiyun char __iomem *ioremap_ptr;
6840*4882a593Smuzhiyun char __iomem *mem_ptr;
6841*4882a593Smuzhiyun uint32_t IsDead;
6842*4882a593Smuzhiyun
6843*4882a593Smuzhiyun METHOD_TRACE("ips_init_phase1", 1);
6844*4882a593Smuzhiyun index = IPS_MAX_ADAPTERS;
6845*4882a593Smuzhiyun for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
6846*4882a593Smuzhiyun if (ips_ha[j] == NULL) {
6847*4882a593Smuzhiyun index = j;
6848*4882a593Smuzhiyun break;
6849*4882a593Smuzhiyun }
6850*4882a593Smuzhiyun }
6851*4882a593Smuzhiyun
6852*4882a593Smuzhiyun if (index >= IPS_MAX_ADAPTERS)
6853*4882a593Smuzhiyun return -1;
6854*4882a593Smuzhiyun
6855*4882a593Smuzhiyun /* Init MEM/IO addresses to 0 */
6856*4882a593Smuzhiyun mem_addr = 0;
6857*4882a593Smuzhiyun io_addr = 0;
6858*4882a593Smuzhiyun mem_len = 0;
6859*4882a593Smuzhiyun io_len = 0;
6860*4882a593Smuzhiyun
6861*4882a593Smuzhiyun for (j = 0; j < 2; j++) {
6862*4882a593Smuzhiyun if (!pci_resource_start(pci_dev, j))
6863*4882a593Smuzhiyun break;
6864*4882a593Smuzhiyun
6865*4882a593Smuzhiyun if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
6866*4882a593Smuzhiyun io_addr = pci_resource_start(pci_dev, j);
6867*4882a593Smuzhiyun io_len = pci_resource_len(pci_dev, j);
6868*4882a593Smuzhiyun } else {
6869*4882a593Smuzhiyun mem_addr = pci_resource_start(pci_dev, j);
6870*4882a593Smuzhiyun mem_len = pci_resource_len(pci_dev, j);
6871*4882a593Smuzhiyun }
6872*4882a593Smuzhiyun }
6873*4882a593Smuzhiyun
6874*4882a593Smuzhiyun /* setup memory mapped area (if applicable) */
6875*4882a593Smuzhiyun if (mem_addr) {
6876*4882a593Smuzhiyun uint32_t base;
6877*4882a593Smuzhiyun uint32_t offs;
6878*4882a593Smuzhiyun
6879*4882a593Smuzhiyun base = mem_addr & PAGE_MASK;
6880*4882a593Smuzhiyun offs = mem_addr - base;
6881*4882a593Smuzhiyun ioremap_ptr = ioremap(base, PAGE_SIZE);
6882*4882a593Smuzhiyun if (!ioremap_ptr)
6883*4882a593Smuzhiyun return -1;
6884*4882a593Smuzhiyun mem_ptr = ioremap_ptr + offs;
6885*4882a593Smuzhiyun } else {
6886*4882a593Smuzhiyun ioremap_ptr = NULL;
6887*4882a593Smuzhiyun mem_ptr = NULL;
6888*4882a593Smuzhiyun }
6889*4882a593Smuzhiyun
6890*4882a593Smuzhiyun /* found a controller */
6891*4882a593Smuzhiyun ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
6892*4882a593Smuzhiyun if (ha == NULL) {
6893*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6894*4882a593Smuzhiyun "Unable to allocate temporary ha struct\n");
6895*4882a593Smuzhiyun return -1;
6896*4882a593Smuzhiyun }
6897*4882a593Smuzhiyun
6898*4882a593Smuzhiyun ips_sh[index] = NULL;
6899*4882a593Smuzhiyun ips_ha[index] = ha;
6900*4882a593Smuzhiyun ha->active = 1;
6901*4882a593Smuzhiyun
6902*4882a593Smuzhiyun /* Store info in HA structure */
6903*4882a593Smuzhiyun ha->io_addr = io_addr;
6904*4882a593Smuzhiyun ha->io_len = io_len;
6905*4882a593Smuzhiyun ha->mem_addr = mem_addr;
6906*4882a593Smuzhiyun ha->mem_len = mem_len;
6907*4882a593Smuzhiyun ha->mem_ptr = mem_ptr;
6908*4882a593Smuzhiyun ha->ioremap_ptr = ioremap_ptr;
6909*4882a593Smuzhiyun ha->host_num = (uint32_t) index;
6910*4882a593Smuzhiyun ha->slot_num = PCI_SLOT(pci_dev->devfn);
6911*4882a593Smuzhiyun ha->pcidev = pci_dev;
6912*4882a593Smuzhiyun
6913*4882a593Smuzhiyun /*
6914*4882a593Smuzhiyun * Set the pci_dev's dma_mask. Not all adapters support 64bit
6915*4882a593Smuzhiyun * addressing so don't enable it if the adapter can't support
6916*4882a593Smuzhiyun * it! Also, don't use 64bit addressing if dma addresses
6917*4882a593Smuzhiyun * are guaranteed to be < 4G.
6918*4882a593Smuzhiyun */
6919*4882a593Smuzhiyun if (sizeof(dma_addr_t) > 4 && IPS_HAS_ENH_SGLIST(ha) &&
6920*4882a593Smuzhiyun !dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(64))) {
6921*4882a593Smuzhiyun (ha)->flags |= IPS_HA_ENH_SG;
6922*4882a593Smuzhiyun } else {
6923*4882a593Smuzhiyun if (dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(32)) != 0) {
6924*4882a593Smuzhiyun printk(KERN_WARNING "Unable to set DMA Mask\n");
6925*4882a593Smuzhiyun return ips_abort_init(ha, index);
6926*4882a593Smuzhiyun }
6927*4882a593Smuzhiyun }
6928*4882a593Smuzhiyun if(ips_cd_boot && !ips_FlashData){
6929*4882a593Smuzhiyun ips_FlashData = dma_alloc_coherent(&pci_dev->dev,
6930*4882a593Smuzhiyun PAGE_SIZE << 7, &ips_flashbusaddr, GFP_KERNEL);
6931*4882a593Smuzhiyun }
6932*4882a593Smuzhiyun
6933*4882a593Smuzhiyun ha->enq = dma_alloc_coherent(&pci_dev->dev, sizeof (IPS_ENQ),
6934*4882a593Smuzhiyun &ha->enq_busaddr, GFP_KERNEL);
6935*4882a593Smuzhiyun if (!ha->enq) {
6936*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6937*4882a593Smuzhiyun "Unable to allocate host inquiry structure\n");
6938*4882a593Smuzhiyun return ips_abort_init(ha, index);
6939*4882a593Smuzhiyun }
6940*4882a593Smuzhiyun
6941*4882a593Smuzhiyun ha->adapt = dma_alloc_coherent(&pci_dev->dev,
6942*4882a593Smuzhiyun sizeof (IPS_ADAPTER) + sizeof (IPS_IO_CMD),
6943*4882a593Smuzhiyun &dma_address, GFP_KERNEL);
6944*4882a593Smuzhiyun if (!ha->adapt) {
6945*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6946*4882a593Smuzhiyun "Unable to allocate host adapt & dummy structures\n");
6947*4882a593Smuzhiyun return ips_abort_init(ha, index);
6948*4882a593Smuzhiyun }
6949*4882a593Smuzhiyun ha->adapt->hw_status_start = dma_address;
6950*4882a593Smuzhiyun ha->dummy = (void *) (ha->adapt + 1);
6951*4882a593Smuzhiyun
6952*4882a593Smuzhiyun
6953*4882a593Smuzhiyun
6954*4882a593Smuzhiyun ha->logical_drive_info = dma_alloc_coherent(&pci_dev->dev,
6955*4882a593Smuzhiyun sizeof (IPS_LD_INFO), &dma_address, GFP_KERNEL);
6956*4882a593Smuzhiyun if (!ha->logical_drive_info) {
6957*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6958*4882a593Smuzhiyun "Unable to allocate logical drive info structure\n");
6959*4882a593Smuzhiyun return ips_abort_init(ha, index);
6960*4882a593Smuzhiyun }
6961*4882a593Smuzhiyun ha->logical_drive_info_dma_addr = dma_address;
6962*4882a593Smuzhiyun
6963*4882a593Smuzhiyun
6964*4882a593Smuzhiyun ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);
6965*4882a593Smuzhiyun
6966*4882a593Smuzhiyun if (!ha->conf) {
6967*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6968*4882a593Smuzhiyun "Unable to allocate host conf structure\n");
6969*4882a593Smuzhiyun return ips_abort_init(ha, index);
6970*4882a593Smuzhiyun }
6971*4882a593Smuzhiyun
6972*4882a593Smuzhiyun ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);
6973*4882a593Smuzhiyun
6974*4882a593Smuzhiyun if (!ha->nvram) {
6975*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6976*4882a593Smuzhiyun "Unable to allocate host NVRAM structure\n");
6977*4882a593Smuzhiyun return ips_abort_init(ha, index);
6978*4882a593Smuzhiyun }
6979*4882a593Smuzhiyun
6980*4882a593Smuzhiyun ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);
6981*4882a593Smuzhiyun
6982*4882a593Smuzhiyun if (!ha->subsys) {
6983*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6984*4882a593Smuzhiyun "Unable to allocate host subsystem structure\n");
6985*4882a593Smuzhiyun return ips_abort_init(ha, index);
6986*4882a593Smuzhiyun }
6987*4882a593Smuzhiyun
6988*4882a593Smuzhiyun /* the ioctl buffer is now used during adapter initialization, so its
6989*4882a593Smuzhiyun * successful allocation is now required */
6990*4882a593Smuzhiyun if (ips_ioctlsize < PAGE_SIZE)
6991*4882a593Smuzhiyun ips_ioctlsize = PAGE_SIZE;
6992*4882a593Smuzhiyun
6993*4882a593Smuzhiyun ha->ioctl_data = dma_alloc_coherent(&pci_dev->dev, ips_ioctlsize,
6994*4882a593Smuzhiyun &ha->ioctl_busaddr, GFP_KERNEL);
6995*4882a593Smuzhiyun ha->ioctl_len = ips_ioctlsize;
6996*4882a593Smuzhiyun if (!ha->ioctl_data) {
6997*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
6998*4882a593Smuzhiyun "Unable to allocate IOCTL data\n");
6999*4882a593Smuzhiyun return ips_abort_init(ha, index);
7000*4882a593Smuzhiyun }
7001*4882a593Smuzhiyun
7002*4882a593Smuzhiyun /*
7003*4882a593Smuzhiyun * Setup Functions
7004*4882a593Smuzhiyun */
7005*4882a593Smuzhiyun ips_setup_funclist(ha);
7006*4882a593Smuzhiyun
7007*4882a593Smuzhiyun if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) {
7008*4882a593Smuzhiyun /* If Morpheus appears dead, reset it */
7009*4882a593Smuzhiyun IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
7010*4882a593Smuzhiyun if (IsDead == 0xDEADBEEF) {
7011*4882a593Smuzhiyun ips_reset_morpheus(ha);
7012*4882a593Smuzhiyun }
7013*4882a593Smuzhiyun }
7014*4882a593Smuzhiyun
7015*4882a593Smuzhiyun /*
7016*4882a593Smuzhiyun * Initialize the card if it isn't already
7017*4882a593Smuzhiyun */
7018*4882a593Smuzhiyun
7019*4882a593Smuzhiyun if (!(*ha->func.isinit) (ha)) {
7020*4882a593Smuzhiyun if (!(*ha->func.init) (ha)) {
7021*4882a593Smuzhiyun /*
7022*4882a593Smuzhiyun * Initialization failed
7023*4882a593Smuzhiyun */
7024*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, pci_dev,
7025*4882a593Smuzhiyun "Unable to initialize controller\n");
7026*4882a593Smuzhiyun return ips_abort_init(ha, index);
7027*4882a593Smuzhiyun }
7028*4882a593Smuzhiyun }
7029*4882a593Smuzhiyun
7030*4882a593Smuzhiyun *indexPtr = index;
7031*4882a593Smuzhiyun return SUCCESS;
7032*4882a593Smuzhiyun }
7033*4882a593Smuzhiyun
7034*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
7035*4882a593Smuzhiyun /* Routine Name: ips_init_phase2 */
7036*4882a593Smuzhiyun /* */
7037*4882a593Smuzhiyun /* Routine Description: */
7038*4882a593Smuzhiyun /* Adapter Initialization Phase 2 */
7039*4882a593Smuzhiyun /* */
7040*4882a593Smuzhiyun /* Return Value: */
7041*4882a593Smuzhiyun /* 0 if Successful, else non-zero */
7042*4882a593Smuzhiyun /*---------------------------------------------------------------------------*/
7043*4882a593Smuzhiyun static int
ips_init_phase2(int index)7044*4882a593Smuzhiyun ips_init_phase2(int index)
7045*4882a593Smuzhiyun {
7046*4882a593Smuzhiyun ips_ha_t *ha;
7047*4882a593Smuzhiyun
7048*4882a593Smuzhiyun ha = ips_ha[index];
7049*4882a593Smuzhiyun
7050*4882a593Smuzhiyun METHOD_TRACE("ips_init_phase2", 1);
7051*4882a593Smuzhiyun if (!ha->active) {
7052*4882a593Smuzhiyun ips_ha[index] = NULL;
7053*4882a593Smuzhiyun return -1;
7054*4882a593Smuzhiyun }
7055*4882a593Smuzhiyun
7056*4882a593Smuzhiyun /* Install the interrupt handler */
7057*4882a593Smuzhiyun if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
7058*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
7059*4882a593Smuzhiyun "Unable to install interrupt handler\n");
7060*4882a593Smuzhiyun return ips_abort_init(ha, index);
7061*4882a593Smuzhiyun }
7062*4882a593Smuzhiyun
7063*4882a593Smuzhiyun /*
7064*4882a593Smuzhiyun * Allocate a temporary SCB for initialization
7065*4882a593Smuzhiyun */
7066*4882a593Smuzhiyun ha->max_cmds = 1;
7067*4882a593Smuzhiyun if (!ips_allocatescbs(ha)) {
7068*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
7069*4882a593Smuzhiyun "Unable to allocate a CCB\n");
7070*4882a593Smuzhiyun free_irq(ha->pcidev->irq, ha);
7071*4882a593Smuzhiyun return ips_abort_init(ha, index);
7072*4882a593Smuzhiyun }
7073*4882a593Smuzhiyun
7074*4882a593Smuzhiyun if (!ips_hainit(ha)) {
7075*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
7076*4882a593Smuzhiyun "Unable to initialize controller\n");
7077*4882a593Smuzhiyun free_irq(ha->pcidev->irq, ha);
7078*4882a593Smuzhiyun return ips_abort_init(ha, index);
7079*4882a593Smuzhiyun }
7080*4882a593Smuzhiyun /* Free the temporary SCB */
7081*4882a593Smuzhiyun ips_deallocatescbs(ha, 1);
7082*4882a593Smuzhiyun
7083*4882a593Smuzhiyun /* allocate CCBs */
7084*4882a593Smuzhiyun if (!ips_allocatescbs(ha)) {
7085*4882a593Smuzhiyun IPS_PRINTK(KERN_WARNING, ha->pcidev,
7086*4882a593Smuzhiyun "Unable to allocate CCBs\n");
7087*4882a593Smuzhiyun free_irq(ha->pcidev->irq, ha);
7088*4882a593Smuzhiyun return ips_abort_init(ha, index);
7089*4882a593Smuzhiyun }
7090*4882a593Smuzhiyun
7091*4882a593Smuzhiyun return SUCCESS;
7092*4882a593Smuzhiyun }
7093*4882a593Smuzhiyun
7094*4882a593Smuzhiyun MODULE_LICENSE("GPL");
7095*4882a593Smuzhiyun MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
7096*4882a593Smuzhiyun MODULE_VERSION(IPS_VER_STRING);
7097*4882a593Smuzhiyun
7098*4882a593Smuzhiyun
7099*4882a593Smuzhiyun /*
7100*4882a593Smuzhiyun * Overrides for Emacs so that we almost follow Linus's tabbing style.
7101*4882a593Smuzhiyun * Emacs will notice this stuff at the end of the file and automatically
7102*4882a593Smuzhiyun * adjust the settings for this buffer only. This must remain at the end
7103*4882a593Smuzhiyun * of the file.
7104*4882a593Smuzhiyun * ---------------------------------------------------------------------------
7105*4882a593Smuzhiyun * Local variables:
7106*4882a593Smuzhiyun * c-indent-level: 2
7107*4882a593Smuzhiyun * c-brace-imaginary-offset: 0
7108*4882a593Smuzhiyun * c-brace-offset: -2
7109*4882a593Smuzhiyun * c-argdecl-indent: 2
7110*4882a593Smuzhiyun * c-label-offset: -2
7111*4882a593Smuzhiyun * c-continued-statement-offset: 2
7112*4882a593Smuzhiyun * c-continued-brace-offset: 0
7113*4882a593Smuzhiyun * indent-tabs-mode: nil
7114*4882a593Smuzhiyun * tab-width: 8
7115*4882a593Smuzhiyun * End:
7116*4882a593Smuzhiyun */
7117