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