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