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