162306a36Sopenharmony_ci/*****************************************************************************/ 262306a36Sopenharmony_ci/* ips.c -- driver for the Adaptec / IBM ServeRAID controller */ 362306a36Sopenharmony_ci/* */ 462306a36Sopenharmony_ci/* Written By: Keith Mitchell, IBM Corporation */ 562306a36Sopenharmony_ci/* Jack Hammer, Adaptec, Inc. */ 662306a36Sopenharmony_ci/* David Jeffery, Adaptec, Inc. */ 762306a36Sopenharmony_ci/* */ 862306a36Sopenharmony_ci/* Copyright (C) 2000 IBM Corporation */ 962306a36Sopenharmony_ci/* Copyright (C) 2002,2003 Adaptec, Inc. */ 1062306a36Sopenharmony_ci/* */ 1162306a36Sopenharmony_ci/* This program is free software; you can redistribute it and/or modify */ 1262306a36Sopenharmony_ci/* it under the terms of the GNU General Public License as published by */ 1362306a36Sopenharmony_ci/* the Free Software Foundation; either version 2 of the License, or */ 1462306a36Sopenharmony_ci/* (at your option) any later version. */ 1562306a36Sopenharmony_ci/* */ 1662306a36Sopenharmony_ci/* This program is distributed in the hope that it will be useful, */ 1762306a36Sopenharmony_ci/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 1862306a36Sopenharmony_ci/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 1962306a36Sopenharmony_ci/* GNU General Public License for more details. */ 2062306a36Sopenharmony_ci/* */ 2162306a36Sopenharmony_ci/* NO WARRANTY */ 2262306a36Sopenharmony_ci/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ 2362306a36Sopenharmony_ci/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ 2462306a36Sopenharmony_ci/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ 2562306a36Sopenharmony_ci/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ 2662306a36Sopenharmony_ci/* solely responsible for determining the appropriateness of using and */ 2762306a36Sopenharmony_ci/* distributing the Program and assumes all risks associated with its */ 2862306a36Sopenharmony_ci/* exercise of rights under this Agreement, including but not limited to */ 2962306a36Sopenharmony_ci/* the risks and costs of program errors, damage to or loss of data, */ 3062306a36Sopenharmony_ci/* programs or equipment, and unavailability or interruption of operations. */ 3162306a36Sopenharmony_ci/* */ 3262306a36Sopenharmony_ci/* DISCLAIMER OF LIABILITY */ 3362306a36Sopenharmony_ci/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ 3462306a36Sopenharmony_ci/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ 3562306a36Sopenharmony_ci/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ 3662306a36Sopenharmony_ci/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ 3762306a36Sopenharmony_ci/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ 3862306a36Sopenharmony_ci/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ 3962306a36Sopenharmony_ci/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ 4062306a36Sopenharmony_ci/* */ 4162306a36Sopenharmony_ci/* You should have received a copy of the GNU General Public License */ 4262306a36Sopenharmony_ci/* along with this program; if not, write to the Free Software */ 4362306a36Sopenharmony_ci/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 4462306a36Sopenharmony_ci/* */ 4562306a36Sopenharmony_ci/* Bugs/Comments/Suggestions about this driver should be mailed to: */ 4662306a36Sopenharmony_ci/* ipslinux@adaptec.com */ 4762306a36Sopenharmony_ci/* */ 4862306a36Sopenharmony_ci/* For system support issues, contact your local IBM Customer support. */ 4962306a36Sopenharmony_ci/* Directions to find IBM Customer Support for each country can be found at: */ 5062306a36Sopenharmony_ci/* http://www.ibm.com/planetwide/ */ 5162306a36Sopenharmony_ci/* */ 5262306a36Sopenharmony_ci/*****************************************************************************/ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/*****************************************************************************/ 5562306a36Sopenharmony_ci/* Change Log */ 5662306a36Sopenharmony_ci/* */ 5762306a36Sopenharmony_ci/* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size */ 5862306a36Sopenharmony_ci/* 0.99.03 - Make interrupt routine handle all completed request on the */ 5962306a36Sopenharmony_ci/* adapter not just the first one */ 6062306a36Sopenharmony_ci/* - Make sure passthru commands get woken up if we run out of */ 6162306a36Sopenharmony_ci/* SCBs */ 6262306a36Sopenharmony_ci/* - Send all of the commands on the queue at once rather than */ 6362306a36Sopenharmony_ci/* one at a time since the card will support it. */ 6462306a36Sopenharmony_ci/* 0.99.04 - Fix race condition in the passthru mechanism -- this required */ 6562306a36Sopenharmony_ci/* the interface to the utilities to change */ 6662306a36Sopenharmony_ci/* - Fix error recovery code */ 6762306a36Sopenharmony_ci/* 0.99.05 - Fix an oops when we get certain passthru commands */ 6862306a36Sopenharmony_ci/* 1.00.00 - Initial Public Release */ 6962306a36Sopenharmony_ci/* Functionally equivalent to 0.99.05 */ 7062306a36Sopenharmony_ci/* 3.60.00 - Bump max commands to 128 for use with firmware 3.60 */ 7162306a36Sopenharmony_ci/* - Change version to 3.60 to coincide with release numbering. */ 7262306a36Sopenharmony_ci/* 3.60.01 - Remove bogus error check in passthru routine */ 7362306a36Sopenharmony_ci/* 3.60.02 - Make DCDB direction based on lookup table */ 7462306a36Sopenharmony_ci/* - Only allow one DCDB command to a SCSI ID at a time */ 7562306a36Sopenharmony_ci/* 4.00.00 - Add support for ServeRAID 4 */ 7662306a36Sopenharmony_ci/* 4.00.01 - Add support for First Failure Data Capture */ 7762306a36Sopenharmony_ci/* 4.00.02 - Fix problem with PT DCDB with no buffer */ 7862306a36Sopenharmony_ci/* 4.00.03 - Add alternative passthru interface */ 7962306a36Sopenharmony_ci/* - Add ability to flash BIOS */ 8062306a36Sopenharmony_ci/* 4.00.04 - Rename structures/constants to be prefixed with IPS_ */ 8162306a36Sopenharmony_ci/* 4.00.05 - Remove wish_block from init routine */ 8262306a36Sopenharmony_ci/* - Use linux/spinlock.h instead of asm/spinlock.h for kernels */ 8362306a36Sopenharmony_ci/* 2.3.18 and later */ 8462306a36Sopenharmony_ci/* - Sync with other changes from the 2.3 kernels */ 8562306a36Sopenharmony_ci/* 4.00.06 - Fix timeout with initial FFDC command */ 8662306a36Sopenharmony_ci/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */ 8762306a36Sopenharmony_ci/* 4.10.00 - Add support for ServeRAID 4M/4L */ 8862306a36Sopenharmony_ci/* 4.10.13 - Fix for dynamic unload and proc file system */ 8962306a36Sopenharmony_ci/* 4.20.03 - Rename version to coincide with new release schedules */ 9062306a36Sopenharmony_ci/* Performance fixes */ 9162306a36Sopenharmony_ci/* Fix truncation of /proc files with cat */ 9262306a36Sopenharmony_ci/* Merge in changes through kernel 2.4.0test1ac21 */ 9362306a36Sopenharmony_ci/* 4.20.13 - Fix some failure cases / reset code */ 9462306a36Sopenharmony_ci/* - Hook into the reboot_notifier to flush the controller cache */ 9562306a36Sopenharmony_ci/* 4.50.01 - Fix problem when there is a hole in logical drive numbering */ 9662306a36Sopenharmony_ci/* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */ 9762306a36Sopenharmony_ci/* - Add IPSSEND Flash Support */ 9862306a36Sopenharmony_ci/* - Set Sense Data for Unknown SCSI Command */ 9962306a36Sopenharmony_ci/* - Use Slot Number from NVRAM Page 5 */ 10062306a36Sopenharmony_ci/* - Restore caller's DCDB Structure */ 10162306a36Sopenharmony_ci/* 4.70.12 - Corrective actions for bad controller ( during initialization )*/ 10262306a36Sopenharmony_ci/* 4.70.13 - Don't Send CDB's if we already know the device is not present */ 10362306a36Sopenharmony_ci/* - Don't release HA Lock in ips_next() until SC taken off queue */ 10462306a36Sopenharmony_ci/* - Unregister SCSI device in ips_release() */ 10562306a36Sopenharmony_ci/* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */ 10662306a36Sopenharmony_ci/* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */ 10762306a36Sopenharmony_ci/* Code Clean-Up for 2.4.x kernel */ 10862306a36Sopenharmony_ci/* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */ 10962306a36Sopenharmony_ci/* 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) */ 11062306a36Sopenharmony_ci/* - Don't Issue Internal FFDC Command if there are Active Commands */ 11162306a36Sopenharmony_ci/* - Close Window for getting too many IOCTL's active */ 11262306a36Sopenharmony_ci/* 4.80.00 - Make ia64 Safe */ 11362306a36Sopenharmony_ci/* 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater */ 11462306a36Sopenharmony_ci/* - Adjustments to Device Queue Depth */ 11562306a36Sopenharmony_ci/* 4.80.14 - Take all semaphores off stack */ 11662306a36Sopenharmony_ci/* - Clean Up New_IOCTL path */ 11762306a36Sopenharmony_ci/* 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) */ 11862306a36Sopenharmony_ci/* - 5 second delay needed after resetting an i960 adapter */ 11962306a36Sopenharmony_ci/* 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) */ 12062306a36Sopenharmony_ci/* 4.90.01 - Version Matching for FirmWare, BIOS, and Driver */ 12162306a36Sopenharmony_ci/* 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development */ 12262306a36Sopenharmony_ci/* 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) */ 12362306a36Sopenharmony_ci/* 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K */ 12462306a36Sopenharmony_ci/* 4.90.11 - Don't actually RESET unless it's physically required */ 12562306a36Sopenharmony_ci/* - Remove unused compile options */ 12662306a36Sopenharmony_ci/* 5.00.01 - Sarasota ( 5i ) adapters must always be scanned first */ 12762306a36Sopenharmony_ci/* - Get rid on IOCTL_NEW_COMMAND code */ 12862306a36Sopenharmony_ci/* - Add Extended DCDB Commands for Tape Support in 5I */ 12962306a36Sopenharmony_ci/* 5.10.12 - use pci_dma interfaces, update for 2.5 kernel changes */ 13062306a36Sopenharmony_ci/* 5.10.15 - remove unused code (sem, macros, etc.) */ 13162306a36Sopenharmony_ci/* 5.30.00 - use __devexit_p() */ 13262306a36Sopenharmony_ci/* 6.00.00 - Add 6x Adapters and Battery Flash */ 13362306a36Sopenharmony_ci/* 6.10.00 - Remove 1G Addressing Limitations */ 13462306a36Sopenharmony_ci/* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */ 13562306a36Sopenharmony_ci/* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */ 13662306a36Sopenharmony_ci/* 7.10.18 - Add highmem_io flag in SCSI Templete for 2.4 kernels */ 13762306a36Sopenharmony_ci/* - Fix path/name for scsi_hosts.h include for 2.6 kernels */ 13862306a36Sopenharmony_ci/* - Fix sort order of 7k */ 13962306a36Sopenharmony_ci/* - Remove 3 unused "inline" functions */ 14062306a36Sopenharmony_ci/* 7.12.xx - Use STATIC functions wherever possible */ 14162306a36Sopenharmony_ci/* - Clean up deprecated MODULE_PARM calls */ 14262306a36Sopenharmony_ci/* 7.12.05 - Remove Version Matching per IBM request */ 14362306a36Sopenharmony_ci/*****************************************************************************/ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * Conditional Compilation directives for this driver: 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * IPS_DEBUG - Turn on debugging info 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * Parameters: 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * debug:<number> - Set debug level to <number> 15362306a36Sopenharmony_ci * NOTE: only works when IPS_DEBUG compile directive is used. 15462306a36Sopenharmony_ci * 1 - Normal debug messages 15562306a36Sopenharmony_ci * 2 - Verbose debug messages 15662306a36Sopenharmony_ci * 11 - Method trace (non interrupt) 15762306a36Sopenharmony_ci * 12 - Method trace (includes interrupt) 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * noi2o - Don't use I2O Queues (ServeRAID 4 only) 16062306a36Sopenharmony_ci * nommap - Don't use memory mapped I/O 16162306a36Sopenharmony_ci * ioctlsize - Initial size of the IOCTL buffer 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#include <asm/io.h> 16562306a36Sopenharmony_ci#include <asm/byteorder.h> 16662306a36Sopenharmony_ci#include <asm/page.h> 16762306a36Sopenharmony_ci#include <linux/stddef.h> 16862306a36Sopenharmony_ci#include <linux/string.h> 16962306a36Sopenharmony_ci#include <linux/errno.h> 17062306a36Sopenharmony_ci#include <linux/kernel.h> 17162306a36Sopenharmony_ci#include <linux/ioport.h> 17262306a36Sopenharmony_ci#include <linux/slab.h> 17362306a36Sopenharmony_ci#include <linux/delay.h> 17462306a36Sopenharmony_ci#include <linux/pci.h> 17562306a36Sopenharmony_ci#include <linux/proc_fs.h> 17662306a36Sopenharmony_ci#include <linux/reboot.h> 17762306a36Sopenharmony_ci#include <linux/interrupt.h> 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci#include <linux/blkdev.h> 18062306a36Sopenharmony_ci#include <linux/types.h> 18162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci#include <scsi/scsi.h> 18462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 18562306a36Sopenharmony_ci#include <scsi/scsi_device.h> 18662306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 18762306a36Sopenharmony_ci#include <scsi/scsi_host.h> 18862306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 18962306a36Sopenharmony_ci#include <scsi/sg.h> 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#include "ips.h" 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#include <linux/module.h> 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#include <linux/stat.h> 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#include <linux/spinlock.h> 19862306a36Sopenharmony_ci#include <linux/init.h> 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#include <linux/smp.h> 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#ifdef MODULE 20362306a36Sopenharmony_cistatic char *ips = NULL; 20462306a36Sopenharmony_cimodule_param(ips, charp, 0); 20562306a36Sopenharmony_ci#endif 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/* 20862306a36Sopenharmony_ci * DRIVER_VER 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci#define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING 21162306a36Sopenharmony_ci#define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " " 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \ 21462306a36Sopenharmony_ci DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \ 21562306a36Sopenharmony_ci DMA_BIDIRECTIONAL : \ 21662306a36Sopenharmony_ci scb->scsi_cmd->sc_data_direction) 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci#ifdef IPS_DEBUG 21962306a36Sopenharmony_ci#define METHOD_TRACE(s, i) if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); 22062306a36Sopenharmony_ci#define DEBUG(i, s) if (ips_debug >= i) printk(KERN_NOTICE s "\n"); 22162306a36Sopenharmony_ci#define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v); 22262306a36Sopenharmony_ci#else 22362306a36Sopenharmony_ci#define METHOD_TRACE(s, i) 22462306a36Sopenharmony_ci#define DEBUG(i, s) 22562306a36Sopenharmony_ci#define DEBUG_VAR(i, s, v...) 22662306a36Sopenharmony_ci#endif 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* 22962306a36Sopenharmony_ci * Function prototypes 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_cistatic int ips_eh_abort(struct scsi_cmnd *); 23262306a36Sopenharmony_cistatic int ips_eh_reset(struct scsi_cmnd *); 23362306a36Sopenharmony_cistatic int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); 23462306a36Sopenharmony_cistatic const char *ips_info(struct Scsi_Host *); 23562306a36Sopenharmony_cistatic irqreturn_t do_ipsintr(int, void *); 23662306a36Sopenharmony_cistatic int ips_hainit(ips_ha_t *); 23762306a36Sopenharmony_cistatic int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); 23862306a36Sopenharmony_cistatic int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); 23962306a36Sopenharmony_cistatic int ips_send_cmd(ips_ha_t *, ips_scb_t *); 24062306a36Sopenharmony_cistatic int ips_online(ips_ha_t *, ips_scb_t *); 24162306a36Sopenharmony_cistatic int ips_inquiry(ips_ha_t *, ips_scb_t *); 24262306a36Sopenharmony_cistatic int ips_rdcap(ips_ha_t *, ips_scb_t *); 24362306a36Sopenharmony_cistatic int ips_msense(ips_ha_t *, ips_scb_t *); 24462306a36Sopenharmony_cistatic int ips_reqsen(ips_ha_t *, ips_scb_t *); 24562306a36Sopenharmony_cistatic int ips_deallocatescbs(ips_ha_t *, int); 24662306a36Sopenharmony_cistatic int ips_allocatescbs(ips_ha_t *); 24762306a36Sopenharmony_cistatic int ips_reset_copperhead(ips_ha_t *); 24862306a36Sopenharmony_cistatic int ips_reset_copperhead_memio(ips_ha_t *); 24962306a36Sopenharmony_cistatic int ips_reset_morpheus(ips_ha_t *); 25062306a36Sopenharmony_cistatic int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); 25162306a36Sopenharmony_cistatic int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); 25262306a36Sopenharmony_cistatic int ips_issue_i2o(ips_ha_t *, ips_scb_t *); 25362306a36Sopenharmony_cistatic int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); 25462306a36Sopenharmony_cistatic int ips_isintr_copperhead(ips_ha_t *); 25562306a36Sopenharmony_cistatic int ips_isintr_copperhead_memio(ips_ha_t *); 25662306a36Sopenharmony_cistatic int ips_isintr_morpheus(ips_ha_t *); 25762306a36Sopenharmony_cistatic int ips_wait(ips_ha_t *, int, int); 25862306a36Sopenharmony_cistatic int ips_write_driver_status(ips_ha_t *, int); 25962306a36Sopenharmony_cistatic int ips_read_adapter_status(ips_ha_t *, int); 26062306a36Sopenharmony_cistatic int ips_read_subsystem_parameters(ips_ha_t *, int); 26162306a36Sopenharmony_cistatic int ips_read_config(ips_ha_t *, int); 26262306a36Sopenharmony_cistatic int ips_clear_adapter(ips_ha_t *, int); 26362306a36Sopenharmony_cistatic int ips_readwrite_page5(ips_ha_t *, int, int); 26462306a36Sopenharmony_cistatic int ips_init_copperhead(ips_ha_t *); 26562306a36Sopenharmony_cistatic int ips_init_copperhead_memio(ips_ha_t *); 26662306a36Sopenharmony_cistatic int ips_init_morpheus(ips_ha_t *); 26762306a36Sopenharmony_cistatic int ips_isinit_copperhead(ips_ha_t *); 26862306a36Sopenharmony_cistatic int ips_isinit_copperhead_memio(ips_ha_t *); 26962306a36Sopenharmony_cistatic int ips_isinit_morpheus(ips_ha_t *); 27062306a36Sopenharmony_cistatic int ips_erase_bios(ips_ha_t *); 27162306a36Sopenharmony_cistatic int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t); 27262306a36Sopenharmony_cistatic int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t); 27362306a36Sopenharmony_cistatic int ips_erase_bios_memio(ips_ha_t *); 27462306a36Sopenharmony_cistatic int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); 27562306a36Sopenharmony_cistatic int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); 27662306a36Sopenharmony_cistatic int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 27762306a36Sopenharmony_cistatic int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 27862306a36Sopenharmony_cistatic int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 27962306a36Sopenharmony_cistatic void ips_free_flash_copperhead(ips_ha_t * ha); 28062306a36Sopenharmony_cistatic void ips_get_bios_version(ips_ha_t *, int); 28162306a36Sopenharmony_cistatic void ips_identify_controller(ips_ha_t *); 28262306a36Sopenharmony_cistatic void ips_chkstatus(ips_ha_t *, IPS_STATUS *); 28362306a36Sopenharmony_cistatic void ips_enable_int_copperhead(ips_ha_t *); 28462306a36Sopenharmony_cistatic void ips_enable_int_copperhead_memio(ips_ha_t *); 28562306a36Sopenharmony_cistatic void ips_enable_int_morpheus(ips_ha_t *); 28662306a36Sopenharmony_cistatic int ips_intr_copperhead(ips_ha_t *); 28762306a36Sopenharmony_cistatic int ips_intr_morpheus(ips_ha_t *); 28862306a36Sopenharmony_cistatic void ips_next(ips_ha_t *, int); 28962306a36Sopenharmony_cistatic void ipsintr_blocking(ips_ha_t *, struct ips_scb *); 29062306a36Sopenharmony_cistatic void ipsintr_done(ips_ha_t *, struct ips_scb *); 29162306a36Sopenharmony_cistatic void ips_done(ips_ha_t *, ips_scb_t *); 29262306a36Sopenharmony_cistatic void ips_free(ips_ha_t *); 29362306a36Sopenharmony_cistatic void ips_init_scb(ips_ha_t *, ips_scb_t *); 29462306a36Sopenharmony_cistatic void ips_freescb(ips_ha_t *, ips_scb_t *); 29562306a36Sopenharmony_cistatic void ips_setup_funclist(ips_ha_t *); 29662306a36Sopenharmony_cistatic void ips_statinit(ips_ha_t *); 29762306a36Sopenharmony_cistatic void ips_statinit_memio(ips_ha_t *); 29862306a36Sopenharmony_cistatic void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time64_t); 29962306a36Sopenharmony_cistatic void ips_ffdc_reset(ips_ha_t *, int); 30062306a36Sopenharmony_cistatic void ips_ffdc_time(ips_ha_t *); 30162306a36Sopenharmony_cistatic uint32_t ips_statupd_copperhead(ips_ha_t *); 30262306a36Sopenharmony_cistatic uint32_t ips_statupd_copperhead_memio(ips_ha_t *); 30362306a36Sopenharmony_cistatic uint32_t ips_statupd_morpheus(ips_ha_t *); 30462306a36Sopenharmony_cistatic ips_scb_t *ips_getscb(ips_ha_t *); 30562306a36Sopenharmony_cistatic void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); 30662306a36Sopenharmony_cistatic void ips_putq_wait_tail(ips_wait_queue_entry_t *, struct scsi_cmnd *); 30762306a36Sopenharmony_cistatic void ips_putq_copp_tail(ips_copp_queue_t *, 30862306a36Sopenharmony_ci ips_copp_wait_item_t *); 30962306a36Sopenharmony_cistatic ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); 31062306a36Sopenharmony_cistatic ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); 31162306a36Sopenharmony_cistatic struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_entry_t *); 31262306a36Sopenharmony_cistatic struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_entry_t *, 31362306a36Sopenharmony_ci struct scsi_cmnd *); 31462306a36Sopenharmony_cistatic ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, 31562306a36Sopenharmony_ci ips_copp_wait_item_t *); 31662306a36Sopenharmony_cistatic ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int ips_is_passthru(struct scsi_cmnd *); 31962306a36Sopenharmony_cistatic int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int); 32062306a36Sopenharmony_cistatic int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); 32162306a36Sopenharmony_cistatic void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); 32262306a36Sopenharmony_cistatic void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data, 32362306a36Sopenharmony_ci unsigned int count); 32462306a36Sopenharmony_cistatic void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data, 32562306a36Sopenharmony_ci unsigned int count); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int ips_write_info(struct Scsi_Host *, char *, int); 32862306a36Sopenharmony_cistatic int ips_show_info(struct seq_file *, struct Scsi_Host *); 32962306a36Sopenharmony_cistatic int ips_host_info(ips_ha_t *, struct seq_file *); 33062306a36Sopenharmony_cistatic int ips_abort_init(ips_ha_t * ha, int index); 33162306a36Sopenharmony_cistatic int ips_init_phase2(int index); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr); 33462306a36Sopenharmony_cistatic int ips_register_scsi(int index); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int ips_poll_for_flush_complete(ips_ha_t * ha); 33762306a36Sopenharmony_cistatic void ips_flush_and_reset(ips_ha_t *ha); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/* 34062306a36Sopenharmony_ci * global variables 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_cistatic const char ips_name[] = "ips"; 34362306a36Sopenharmony_cistatic struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */ 34462306a36Sopenharmony_cistatic ips_ha_t *ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */ 34562306a36Sopenharmony_cistatic unsigned int ips_next_controller; 34662306a36Sopenharmony_cistatic unsigned int ips_num_controllers; 34762306a36Sopenharmony_cistatic unsigned int ips_released_controllers; 34862306a36Sopenharmony_cistatic int ips_hotplug; 34962306a36Sopenharmony_cistatic int ips_cmd_timeout = 60; 35062306a36Sopenharmony_cistatic int ips_reset_timeout = 60 * 5; 35162306a36Sopenharmony_cistatic int ips_force_memio = 1; /* Always use Memory Mapped I/O */ 35262306a36Sopenharmony_cistatic int ips_force_i2o = 1; /* Always use I2O command delivery */ 35362306a36Sopenharmony_cistatic int ips_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */ 35462306a36Sopenharmony_cistatic int ips_cd_boot; /* Booting from Manager CD */ 35562306a36Sopenharmony_cistatic char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */ 35662306a36Sopenharmony_cistatic dma_addr_t ips_flashbusaddr; 35762306a36Sopenharmony_cistatic long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */ 35862306a36Sopenharmony_cistatic uint32_t MaxLiteCmds = 32; /* Max Active Cmds for a Lite Adapter */ 35962306a36Sopenharmony_cistatic struct scsi_host_template ips_driver_template = { 36062306a36Sopenharmony_ci .info = ips_info, 36162306a36Sopenharmony_ci .queuecommand = ips_queue, 36262306a36Sopenharmony_ci .eh_abort_handler = ips_eh_abort, 36362306a36Sopenharmony_ci .eh_host_reset_handler = ips_eh_reset, 36462306a36Sopenharmony_ci .proc_name = "ips", 36562306a36Sopenharmony_ci .show_info = ips_show_info, 36662306a36Sopenharmony_ci .write_info = ips_write_info, 36762306a36Sopenharmony_ci .slave_configure = ips_slave_configure, 36862306a36Sopenharmony_ci .bios_param = ips_biosparam, 36962306a36Sopenharmony_ci .this_id = -1, 37062306a36Sopenharmony_ci .sg_tablesize = IPS_MAX_SG, 37162306a36Sopenharmony_ci .cmd_per_lun = 3, 37262306a36Sopenharmony_ci .no_write_same = 1, 37362306a36Sopenharmony_ci}; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* This table describes all ServeRAID Adapters */ 37762306a36Sopenharmony_cistatic struct pci_device_id ips_pci_table[] = { 37862306a36Sopenharmony_ci { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, 37962306a36Sopenharmony_ci { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, 38062306a36Sopenharmony_ci { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, 38162306a36Sopenharmony_ci { 0, } 38262306a36Sopenharmony_ci}; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ciMODULE_DEVICE_TABLE( pci, ips_pci_table ); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic char ips_hot_plug_name[] = "ips"; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); 38962306a36Sopenharmony_cistatic void ips_remove_device(struct pci_dev *pci_dev); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic struct pci_driver ips_pci_driver = { 39262306a36Sopenharmony_ci .name = ips_hot_plug_name, 39362306a36Sopenharmony_ci .id_table = ips_pci_table, 39462306a36Sopenharmony_ci .probe = ips_insert_device, 39562306a36Sopenharmony_ci .remove = ips_remove_device, 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/* 40062306a36Sopenharmony_ci * Necessary forward function protoypes 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_cistatic int ips_halt(struct notifier_block *nb, ulong event, void *buf); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci#define MAX_ADAPTER_NAME 15 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic char ips_adapter_name[][30] = { 40762306a36Sopenharmony_ci "ServeRAID", 40862306a36Sopenharmony_ci "ServeRAID II", 40962306a36Sopenharmony_ci "ServeRAID on motherboard", 41062306a36Sopenharmony_ci "ServeRAID on motherboard", 41162306a36Sopenharmony_ci "ServeRAID 3H", 41262306a36Sopenharmony_ci "ServeRAID 3L", 41362306a36Sopenharmony_ci "ServeRAID 4H", 41462306a36Sopenharmony_ci "ServeRAID 4M", 41562306a36Sopenharmony_ci "ServeRAID 4L", 41662306a36Sopenharmony_ci "ServeRAID 4Mx", 41762306a36Sopenharmony_ci "ServeRAID 4Lx", 41862306a36Sopenharmony_ci "ServeRAID 5i", 41962306a36Sopenharmony_ci "ServeRAID 5i", 42062306a36Sopenharmony_ci "ServeRAID 6M", 42162306a36Sopenharmony_ci "ServeRAID 6i", 42262306a36Sopenharmony_ci "ServeRAID 7t", 42362306a36Sopenharmony_ci "ServeRAID 7k", 42462306a36Sopenharmony_ci "ServeRAID 7M" 42562306a36Sopenharmony_ci}; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic struct notifier_block ips_notifier = { 42862306a36Sopenharmony_ci ips_halt, NULL, 0 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci/* 43262306a36Sopenharmony_ci * Direction table 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_cistatic char ips_command_direction[] = { 43562306a36Sopenharmony_ci IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, 43662306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, 43762306a36Sopenharmony_ci IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 43862306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, 43962306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT, 44062306a36Sopenharmony_ci IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, 44162306a36Sopenharmony_ci IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN, 44262306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, 44362306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK, 44462306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, 44562306a36Sopenharmony_ci IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, 44662306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, 44762306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, 44862306a36Sopenharmony_ci IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE, 44962306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, 45062306a36Sopenharmony_ci IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, 45162306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45262306a36Sopenharmony_ci IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45362306a36Sopenharmony_ci IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45462306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45562306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45662306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45762306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45862306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 45962306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46062306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46162306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46262306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46362306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46462306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46562306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46662306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46762306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 46862306a36Sopenharmony_ci IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE, 46962306a36Sopenharmony_ci IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT, 47062306a36Sopenharmony_ci IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE, 47162306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, 47262306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47362306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47462306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47562306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47662306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47762306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47862306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 47962306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 48062306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 48162306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT, 48262306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 48362306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 48462306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, 48562306a36Sopenharmony_ci IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK 48662306a36Sopenharmony_ci}; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/****************************************************************************/ 49062306a36Sopenharmony_ci/* */ 49162306a36Sopenharmony_ci/* Routine Name: ips_setup */ 49262306a36Sopenharmony_ci/* */ 49362306a36Sopenharmony_ci/* Routine Description: */ 49462306a36Sopenharmony_ci/* */ 49562306a36Sopenharmony_ci/* setup parameters to the driver */ 49662306a36Sopenharmony_ci/* */ 49762306a36Sopenharmony_ci/****************************************************************************/ 49862306a36Sopenharmony_cistatic int 49962306a36Sopenharmony_ciips_setup(char *ips_str) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci int i; 50362306a36Sopenharmony_ci char *key; 50462306a36Sopenharmony_ci char *value; 50562306a36Sopenharmony_ci static const IPS_OPTION options[] = { 50662306a36Sopenharmony_ci {"noi2o", &ips_force_i2o, 0}, 50762306a36Sopenharmony_ci {"nommap", &ips_force_memio, 0}, 50862306a36Sopenharmony_ci {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, 50962306a36Sopenharmony_ci {"cdboot", &ips_cd_boot, 0}, 51062306a36Sopenharmony_ci {"maxcmds", &MaxLiteCmds, 32}, 51162306a36Sopenharmony_ci }; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */ 51462306a36Sopenharmony_ci /* Search for value */ 51562306a36Sopenharmony_ci while ((key = strsep(&ips_str, ",."))) { 51662306a36Sopenharmony_ci if (!*key) 51762306a36Sopenharmony_ci continue; 51862306a36Sopenharmony_ci value = strchr(key, ':'); 51962306a36Sopenharmony_ci if (value) 52062306a36Sopenharmony_ci *value++ = '\0'; 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * We now have key/value pairs. 52362306a36Sopenharmony_ci * Update the variables 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(options); i++) { 52662306a36Sopenharmony_ci if (strncasecmp 52762306a36Sopenharmony_ci (key, options[i].option_name, 52862306a36Sopenharmony_ci strlen(options[i].option_name)) == 0) { 52962306a36Sopenharmony_ci if (value) 53062306a36Sopenharmony_ci *options[i].option_flag = 53162306a36Sopenharmony_ci simple_strtoul(value, NULL, 0); 53262306a36Sopenharmony_ci else 53362306a36Sopenharmony_ci *options[i].option_flag = 53462306a36Sopenharmony_ci options[i].option_value; 53562306a36Sopenharmony_ci break; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return (1); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci__setup("ips=", ips_setup); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/****************************************************************************/ 54662306a36Sopenharmony_ci/* */ 54762306a36Sopenharmony_ci/* Routine Name: ips_detect */ 54862306a36Sopenharmony_ci/* */ 54962306a36Sopenharmony_ci/* Routine Description: */ 55062306a36Sopenharmony_ci/* */ 55162306a36Sopenharmony_ci/* Detect and initialize the driver */ 55262306a36Sopenharmony_ci/* */ 55362306a36Sopenharmony_ci/* NOTE: this routine is called under the io_request_lock spinlock */ 55462306a36Sopenharmony_ci/* */ 55562306a36Sopenharmony_ci/****************************************************************************/ 55662306a36Sopenharmony_cistatic int 55762306a36Sopenharmony_ciips_detect(struct scsi_host_template * SHT) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci int i; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci METHOD_TRACE("ips_detect", 1); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci#ifdef MODULE 56462306a36Sopenharmony_ci if (ips) 56562306a36Sopenharmony_ci ips_setup(ips); 56662306a36Sopenharmony_ci#endif 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci for (i = 0; i < ips_num_controllers; i++) { 56962306a36Sopenharmony_ci if (ips_register_scsi(i)) 57062306a36Sopenharmony_ci ips_free(ips_ha[i]); 57162306a36Sopenharmony_ci ips_released_controllers++; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci ips_hotplug = 1; 57462306a36Sopenharmony_ci return (ips_num_controllers); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci/****************************************************************************/ 57862306a36Sopenharmony_ci/* configure the function pointers to use the functions that will work */ 57962306a36Sopenharmony_ci/* with the found version of the adapter */ 58062306a36Sopenharmony_ci/****************************************************************************/ 58162306a36Sopenharmony_cistatic void 58262306a36Sopenharmony_ciips_setup_funclist(ips_ha_t * ha) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * Setup Functions 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) { 58962306a36Sopenharmony_ci /* morpheus / marco / sebring */ 59062306a36Sopenharmony_ci ha->func.isintr = ips_isintr_morpheus; 59162306a36Sopenharmony_ci ha->func.isinit = ips_isinit_morpheus; 59262306a36Sopenharmony_ci ha->func.issue = ips_issue_i2o_memio; 59362306a36Sopenharmony_ci ha->func.init = ips_init_morpheus; 59462306a36Sopenharmony_ci ha->func.statupd = ips_statupd_morpheus; 59562306a36Sopenharmony_ci ha->func.reset = ips_reset_morpheus; 59662306a36Sopenharmony_ci ha->func.intr = ips_intr_morpheus; 59762306a36Sopenharmony_ci ha->func.enableint = ips_enable_int_morpheus; 59862306a36Sopenharmony_ci } else if (IPS_USE_MEMIO(ha)) { 59962306a36Sopenharmony_ci /* copperhead w/MEMIO */ 60062306a36Sopenharmony_ci ha->func.isintr = ips_isintr_copperhead_memio; 60162306a36Sopenharmony_ci ha->func.isinit = ips_isinit_copperhead_memio; 60262306a36Sopenharmony_ci ha->func.init = ips_init_copperhead_memio; 60362306a36Sopenharmony_ci ha->func.statupd = ips_statupd_copperhead_memio; 60462306a36Sopenharmony_ci ha->func.statinit = ips_statinit_memio; 60562306a36Sopenharmony_ci ha->func.reset = ips_reset_copperhead_memio; 60662306a36Sopenharmony_ci ha->func.intr = ips_intr_copperhead; 60762306a36Sopenharmony_ci ha->func.erasebios = ips_erase_bios_memio; 60862306a36Sopenharmony_ci ha->func.programbios = ips_program_bios_memio; 60962306a36Sopenharmony_ci ha->func.verifybios = ips_verify_bios_memio; 61062306a36Sopenharmony_ci ha->func.enableint = ips_enable_int_copperhead_memio; 61162306a36Sopenharmony_ci if (IPS_USE_I2O_DELIVER(ha)) 61262306a36Sopenharmony_ci ha->func.issue = ips_issue_i2o_memio; 61362306a36Sopenharmony_ci else 61462306a36Sopenharmony_ci ha->func.issue = ips_issue_copperhead_memio; 61562306a36Sopenharmony_ci } else { 61662306a36Sopenharmony_ci /* copperhead */ 61762306a36Sopenharmony_ci ha->func.isintr = ips_isintr_copperhead; 61862306a36Sopenharmony_ci ha->func.isinit = ips_isinit_copperhead; 61962306a36Sopenharmony_ci ha->func.init = ips_init_copperhead; 62062306a36Sopenharmony_ci ha->func.statupd = ips_statupd_copperhead; 62162306a36Sopenharmony_ci ha->func.statinit = ips_statinit; 62262306a36Sopenharmony_ci ha->func.reset = ips_reset_copperhead; 62362306a36Sopenharmony_ci ha->func.intr = ips_intr_copperhead; 62462306a36Sopenharmony_ci ha->func.erasebios = ips_erase_bios; 62562306a36Sopenharmony_ci ha->func.programbios = ips_program_bios; 62662306a36Sopenharmony_ci ha->func.verifybios = ips_verify_bios; 62762306a36Sopenharmony_ci ha->func.enableint = ips_enable_int_copperhead; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (IPS_USE_I2O_DELIVER(ha)) 63062306a36Sopenharmony_ci ha->func.issue = ips_issue_i2o; 63162306a36Sopenharmony_ci else 63262306a36Sopenharmony_ci ha->func.issue = ips_issue_copperhead; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/****************************************************************************/ 63762306a36Sopenharmony_ci/* */ 63862306a36Sopenharmony_ci/* Routine Name: ips_release */ 63962306a36Sopenharmony_ci/* */ 64062306a36Sopenharmony_ci/* Routine Description: */ 64162306a36Sopenharmony_ci/* */ 64262306a36Sopenharmony_ci/* Remove a driver */ 64362306a36Sopenharmony_ci/* */ 64462306a36Sopenharmony_ci/****************************************************************************/ 64562306a36Sopenharmony_cistatic void ips_release(struct Scsi_Host *sh) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci ips_scb_t *scb; 64862306a36Sopenharmony_ci ips_ha_t *ha; 64962306a36Sopenharmony_ci int i; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci METHOD_TRACE("ips_release", 1); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci scsi_remove_host(sh); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (i == IPS_MAX_ADAPTERS) { 65862306a36Sopenharmony_ci printk(KERN_WARNING 65962306a36Sopenharmony_ci "(%s) release, invalid Scsi_Host pointer.\n", ips_name); 66062306a36Sopenharmony_ci BUG(); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci ha = IPS_HA(sh); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (!ha) 66662306a36Sopenharmony_ci return; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* flush the cache on the controller */ 66962306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ips_init_scb(ha, scb); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 67462306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_FLUSH; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 67762306a36Sopenharmony_ci scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); 67862306a36Sopenharmony_ci scb->cmd.flush_cache.state = IPS_NORM_STATE; 67962306a36Sopenharmony_ci scb->cmd.flush_cache.reserved = 0; 68062306a36Sopenharmony_ci scb->cmd.flush_cache.reserved2 = 0; 68162306a36Sopenharmony_ci scb->cmd.flush_cache.reserved3 = 0; 68262306a36Sopenharmony_ci scb->cmd.flush_cache.reserved4 = 0; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* send command */ 68762306a36Sopenharmony_ci if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) 68862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n"); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ips_sh[i] = NULL; 69362306a36Sopenharmony_ci ips_ha[i] = NULL; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* free extra memory */ 69662306a36Sopenharmony_ci ips_free(ha); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* free IRQ */ 69962306a36Sopenharmony_ci free_irq(ha->pcidev->irq, ha); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci scsi_host_put(sh); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci ips_released_controllers++; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci/****************************************************************************/ 70762306a36Sopenharmony_ci/* */ 70862306a36Sopenharmony_ci/* Routine Name: ips_halt */ 70962306a36Sopenharmony_ci/* */ 71062306a36Sopenharmony_ci/* Routine Description: */ 71162306a36Sopenharmony_ci/* */ 71262306a36Sopenharmony_ci/* Perform cleanup when the system reboots */ 71362306a36Sopenharmony_ci/* */ 71462306a36Sopenharmony_ci/****************************************************************************/ 71562306a36Sopenharmony_cistatic int 71662306a36Sopenharmony_ciips_halt(struct notifier_block *nb, ulong event, void *buf) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci ips_scb_t *scb; 71962306a36Sopenharmony_ci ips_ha_t *ha; 72062306a36Sopenharmony_ci int i; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if ((event != SYS_RESTART) && (event != SYS_HALT) && 72362306a36Sopenharmony_ci (event != SYS_POWER_OFF)) 72462306a36Sopenharmony_ci return (NOTIFY_DONE); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci for (i = 0; i < ips_next_controller; i++) { 72762306a36Sopenharmony_ci ha = (ips_ha_t *) ips_ha[i]; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (!ha) 73062306a36Sopenharmony_ci continue; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (!ha->active) 73362306a36Sopenharmony_ci continue; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* flush the cache on the controller */ 73662306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci ips_init_scb(ha, scb); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 74162306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_FLUSH; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 74462306a36Sopenharmony_ci scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); 74562306a36Sopenharmony_ci scb->cmd.flush_cache.state = IPS_NORM_STATE; 74662306a36Sopenharmony_ci scb->cmd.flush_cache.reserved = 0; 74762306a36Sopenharmony_ci scb->cmd.flush_cache.reserved2 = 0; 74862306a36Sopenharmony_ci scb->cmd.flush_cache.reserved3 = 0; 74962306a36Sopenharmony_ci scb->cmd.flush_cache.reserved4 = 0; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* send command */ 75462306a36Sopenharmony_ci if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == 75562306a36Sopenharmony_ci IPS_FAILURE) 75662306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 75762306a36Sopenharmony_ci "Incomplete Flush.\n"); 75862306a36Sopenharmony_ci else 75962306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 76062306a36Sopenharmony_ci "Flushing Complete.\n"); 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci return (NOTIFY_OK); 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci/****************************************************************************/ 76762306a36Sopenharmony_ci/* */ 76862306a36Sopenharmony_ci/* Routine Name: ips_eh_abort */ 76962306a36Sopenharmony_ci/* */ 77062306a36Sopenharmony_ci/* Routine Description: */ 77162306a36Sopenharmony_ci/* */ 77262306a36Sopenharmony_ci/* Abort a command (using the new error code stuff) */ 77362306a36Sopenharmony_ci/* Note: this routine is called under the io_request_lock */ 77462306a36Sopenharmony_ci/****************************************************************************/ 77562306a36Sopenharmony_ciint ips_eh_abort(struct scsi_cmnd *SC) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci ips_ha_t *ha; 77862306a36Sopenharmony_ci ips_copp_wait_item_t *item; 77962306a36Sopenharmony_ci int ret; 78062306a36Sopenharmony_ci struct Scsi_Host *host; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci METHOD_TRACE("ips_eh_abort", 1); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (!SC) 78562306a36Sopenharmony_ci return (FAILED); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci host = SC->device->host; 78862306a36Sopenharmony_ci ha = (ips_ha_t *) SC->device->host->hostdata; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (!ha) 79162306a36Sopenharmony_ci return (FAILED); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (!ha->active) 79462306a36Sopenharmony_ci return (FAILED); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci spin_lock(host->host_lock); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* See if the command is on the copp queue */ 79962306a36Sopenharmony_ci item = ha->copp_waitlist.head; 80062306a36Sopenharmony_ci while ((item) && (item->scsi_cmd != SC)) 80162306a36Sopenharmony_ci item = item->next; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (item) { 80462306a36Sopenharmony_ci /* Found it */ 80562306a36Sopenharmony_ci ips_removeq_copp(&ha->copp_waitlist, item); 80662306a36Sopenharmony_ci ret = (SUCCESS); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* See if the command is on the wait queue */ 80962306a36Sopenharmony_ci } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) { 81062306a36Sopenharmony_ci /* command not sent yet */ 81162306a36Sopenharmony_ci ret = (SUCCESS); 81262306a36Sopenharmony_ci } else { 81362306a36Sopenharmony_ci /* command must have already been sent */ 81462306a36Sopenharmony_ci ret = (FAILED); 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci spin_unlock(host->host_lock); 81862306a36Sopenharmony_ci return ret; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci/****************************************************************************/ 82262306a36Sopenharmony_ci/* */ 82362306a36Sopenharmony_ci/* Routine Name: ips_eh_reset */ 82462306a36Sopenharmony_ci/* */ 82562306a36Sopenharmony_ci/* Routine Description: */ 82662306a36Sopenharmony_ci/* */ 82762306a36Sopenharmony_ci/* Reset the controller (with new eh error code) */ 82862306a36Sopenharmony_ci/* */ 82962306a36Sopenharmony_ci/* NOTE: this routine is called under the io_request_lock spinlock */ 83062306a36Sopenharmony_ci/* */ 83162306a36Sopenharmony_ci/****************************************************************************/ 83262306a36Sopenharmony_cistatic int __ips_eh_reset(struct scsi_cmnd *SC) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci int ret; 83562306a36Sopenharmony_ci int i; 83662306a36Sopenharmony_ci ips_ha_t *ha; 83762306a36Sopenharmony_ci ips_scb_t *scb; 83862306a36Sopenharmony_ci ips_copp_wait_item_t *item; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci METHOD_TRACE("ips_eh_reset", 1); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci#ifdef NO_IPS_RESET 84362306a36Sopenharmony_ci return (FAILED); 84462306a36Sopenharmony_ci#else 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (!SC) { 84762306a36Sopenharmony_ci DEBUG(1, "Reset called with NULL scsi command"); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return (FAILED); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci ha = (ips_ha_t *) SC->device->host->hostdata; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (!ha) { 85562306a36Sopenharmony_ci DEBUG(1, "Reset called with NULL ha struct"); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return (FAILED); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (!ha->active) 86162306a36Sopenharmony_ci return (FAILED); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* See if the command is on the copp queue */ 86462306a36Sopenharmony_ci item = ha->copp_waitlist.head; 86562306a36Sopenharmony_ci while ((item) && (item->scsi_cmd != SC)) 86662306a36Sopenharmony_ci item = item->next; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (item) { 86962306a36Sopenharmony_ci /* Found it */ 87062306a36Sopenharmony_ci ips_removeq_copp(&ha->copp_waitlist, item); 87162306a36Sopenharmony_ci return (SUCCESS); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* See if the command is on the wait queue */ 87562306a36Sopenharmony_ci if (ips_removeq_wait(&ha->scb_waitlist, SC)) { 87662306a36Sopenharmony_ci /* command not sent yet */ 87762306a36Sopenharmony_ci return (SUCCESS); 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* An explanation for the casual observer: */ 88162306a36Sopenharmony_ci /* Part of the function of a RAID controller is automatic error */ 88262306a36Sopenharmony_ci /* detection and recovery. As such, the only problem that physically */ 88362306a36Sopenharmony_ci /* resetting an adapter will ever fix is when, for some reason, */ 88462306a36Sopenharmony_ci /* the driver is not successfully communicating with the adapter. */ 88562306a36Sopenharmony_ci /* Therefore, we will attempt to flush this adapter. If that succeeds, */ 88662306a36Sopenharmony_ci /* then there's no real purpose in a physical reset. This will complete */ 88762306a36Sopenharmony_ci /* much faster and avoids any problems that might be caused by a */ 88862306a36Sopenharmony_ci /* physical reset ( such as having to fail all the outstanding I/O's ). */ 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (ha->ioctl_reset == 0) { /* IF Not an IOCTL Requested Reset */ 89162306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci ips_init_scb(ha, scb); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 89662306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_FLUSH; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 89962306a36Sopenharmony_ci scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); 90062306a36Sopenharmony_ci scb->cmd.flush_cache.state = IPS_NORM_STATE; 90162306a36Sopenharmony_ci scb->cmd.flush_cache.reserved = 0; 90262306a36Sopenharmony_ci scb->cmd.flush_cache.reserved2 = 0; 90362306a36Sopenharmony_ci scb->cmd.flush_cache.reserved3 = 0; 90462306a36Sopenharmony_ci scb->cmd.flush_cache.reserved4 = 0; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* Attempt the flush command */ 90762306a36Sopenharmony_ci ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL); 90862306a36Sopenharmony_ci if (ret == IPS_SUCCESS) { 90962306a36Sopenharmony_ci IPS_PRINTK(KERN_NOTICE, ha->pcidev, 91062306a36Sopenharmony_ci "Reset Request - Flushed Cache\n"); 91162306a36Sopenharmony_ci return (SUCCESS); 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* Either we can't communicate with the adapter or it's an IOCTL request */ 91662306a36Sopenharmony_ci /* from a utility. A physical reset is needed at this point. */ 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci ha->ioctl_reset = 0; /* Reset the IOCTL Requested Reset Flag */ 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* 92162306a36Sopenharmony_ci * command must have already been sent 92262306a36Sopenharmony_ci * reset the controller 92362306a36Sopenharmony_ci */ 92462306a36Sopenharmony_ci IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n"); 92562306a36Sopenharmony_ci ret = (*ha->func.reset) (ha); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (!ret) { 92862306a36Sopenharmony_ci struct scsi_cmnd *scsi_cmd; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci IPS_PRINTK(KERN_NOTICE, ha->pcidev, 93162306a36Sopenharmony_ci "Controller reset failed - controller now offline.\n"); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Now fail all of the active commands */ 93462306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Failing active commands", 93562306a36Sopenharmony_ci ips_name, ha->host_num); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { 93862306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 93962306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 94062306a36Sopenharmony_ci ips_freescb(ha, scb); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* Now fail all of the pending commands */ 94462306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Failing pending commands", 94562306a36Sopenharmony_ci ips_name, ha->host_num); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { 94862306a36Sopenharmony_ci scsi_cmd->result = DID_ERROR; 94962306a36Sopenharmony_ci scsi_done(scsi_cmd); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ha->active = false; 95362306a36Sopenharmony_ci return (FAILED); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { 95762306a36Sopenharmony_ci struct scsi_cmnd *scsi_cmd; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci IPS_PRINTK(KERN_NOTICE, ha->pcidev, 96062306a36Sopenharmony_ci "Controller reset failed - controller now offline.\n"); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* Now fail all of the active commands */ 96362306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Failing active commands", 96462306a36Sopenharmony_ci ips_name, ha->host_num); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { 96762306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 96862306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 96962306a36Sopenharmony_ci ips_freescb(ha, scb); 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* Now fail all of the pending commands */ 97362306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Failing pending commands", 97462306a36Sopenharmony_ci ips_name, ha->host_num); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { 97762306a36Sopenharmony_ci scsi_cmd->result = DID_ERROR << 16; 97862306a36Sopenharmony_ci scsi_done(scsi_cmd); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci ha->active = false; 98262306a36Sopenharmony_ci return (FAILED); 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* FFDC */ 98662306a36Sopenharmony_ci if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) { 98762306a36Sopenharmony_ci ha->last_ffdc = ktime_get_real_seconds(); 98862306a36Sopenharmony_ci ha->reset_count++; 98962306a36Sopenharmony_ci ips_ffdc_reset(ha, IPS_INTR_IORL); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* Now fail all of the active commands */ 99362306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { 99662306a36Sopenharmony_ci scb->scsi_cmd->result = DID_RESET << 16; 99762306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 99862306a36Sopenharmony_ci ips_freescb(ha, scb); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci /* Reset DCDB active command bits */ 100262306a36Sopenharmony_ci for (i = 1; i < ha->nbus; i++) 100362306a36Sopenharmony_ci ha->dcdb_active[i - 1] = 0; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Reset the number of active IOCTLs */ 100662306a36Sopenharmony_ci ha->num_ioctl = 0; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci ips_next(ha, IPS_INTR_IORL); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return (SUCCESS); 101162306a36Sopenharmony_ci#endif /* NO_IPS_RESET */ 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic int ips_eh_reset(struct scsi_cmnd *SC) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci int rc; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci spin_lock_irq(SC->device->host->host_lock); 102062306a36Sopenharmony_ci rc = __ips_eh_reset(SC); 102162306a36Sopenharmony_ci spin_unlock_irq(SC->device->host->host_lock); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return rc; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci/****************************************************************************/ 102762306a36Sopenharmony_ci/* */ 102862306a36Sopenharmony_ci/* Routine Name: ips_queue */ 102962306a36Sopenharmony_ci/* */ 103062306a36Sopenharmony_ci/* Routine Description: */ 103162306a36Sopenharmony_ci/* */ 103262306a36Sopenharmony_ci/* Send a command to the controller */ 103362306a36Sopenharmony_ci/* */ 103462306a36Sopenharmony_ci/* NOTE: */ 103562306a36Sopenharmony_ci/* Linux obtains io_request_lock before calling this function */ 103662306a36Sopenharmony_ci/* */ 103762306a36Sopenharmony_ci/****************************************************************************/ 103862306a36Sopenharmony_cistatic int ips_queue_lck(struct scsi_cmnd *SC) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci void (*done)(struct scsi_cmnd *) = scsi_done; 104162306a36Sopenharmony_ci ips_ha_t *ha; 104262306a36Sopenharmony_ci ips_passthru_t *pt; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci METHOD_TRACE("ips_queue", 1); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci ha = (ips_ha_t *) SC->device->host->hostdata; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (!ha) 104962306a36Sopenharmony_ci goto out_error; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (!ha->active) 105262306a36Sopenharmony_ci goto out_error; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (ips_is_passthru(SC)) { 105562306a36Sopenharmony_ci if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) { 105662306a36Sopenharmony_ci SC->result = DID_BUS_BUSY << 16; 105762306a36Sopenharmony_ci done(SC); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci return (0); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) { 106262306a36Sopenharmony_ci SC->result = DID_BUS_BUSY << 16; 106362306a36Sopenharmony_ci done(SC); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci return (0); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)", 106962306a36Sopenharmony_ci ips_name, 107062306a36Sopenharmony_ci ha->host_num, 107162306a36Sopenharmony_ci SC->cmnd[0], 107262306a36Sopenharmony_ci SC->device->channel, SC->device->id, SC->device->lun); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci /* Check for command to initiator IDs */ 107562306a36Sopenharmony_ci if ((scmd_channel(SC) > 0) 107662306a36Sopenharmony_ci && (scmd_id(SC) == ha->ha_id[scmd_channel(SC)])) { 107762306a36Sopenharmony_ci SC->result = DID_NO_CONNECT << 16; 107862306a36Sopenharmony_ci done(SC); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci return (0); 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (ips_is_passthru(SC)) { 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci ips_copp_wait_item_t *scratch; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci /* A Reset IOCTL is only sent by the boot CD in extreme cases. */ 108862306a36Sopenharmony_ci /* There can never be any system activity ( network or disk ), but check */ 108962306a36Sopenharmony_ci /* anyway just as a good practice. */ 109062306a36Sopenharmony_ci pt = (ips_passthru_t *) scsi_sglist(SC); 109162306a36Sopenharmony_ci if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) && 109262306a36Sopenharmony_ci (pt->CoppCP.cmd.reset.adapter_flag == 1)) { 109362306a36Sopenharmony_ci if (ha->scb_activelist.count != 0) { 109462306a36Sopenharmony_ci SC->result = DID_BUS_BUSY << 16; 109562306a36Sopenharmony_ci done(SC); 109662306a36Sopenharmony_ci return (0); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci ha->ioctl_reset = 1; /* This reset request is from an IOCTL */ 109962306a36Sopenharmony_ci __ips_eh_reset(SC); 110062306a36Sopenharmony_ci SC->result = DID_OK << 16; 110162306a36Sopenharmony_ci scsi_done(SC); 110262306a36Sopenharmony_ci return (0); 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* allocate space for the scribble */ 110662306a36Sopenharmony_ci scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (!scratch) { 110962306a36Sopenharmony_ci SC->result = DID_ERROR << 16; 111062306a36Sopenharmony_ci done(SC); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci return (0); 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci scratch->scsi_cmd = SC; 111662306a36Sopenharmony_ci scratch->next = NULL; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ips_putq_copp_tail(&ha->copp_waitlist, scratch); 111962306a36Sopenharmony_ci } else { 112062306a36Sopenharmony_ci ips_putq_wait_tail(&ha->scb_waitlist, SC); 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci ips_next(ha, IPS_INTR_IORL); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci return (0); 112662306a36Sopenharmony_ciout_error: 112762306a36Sopenharmony_ci SC->result = DID_ERROR << 16; 112862306a36Sopenharmony_ci done(SC); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return (0); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic DEF_SCSI_QCMD(ips_queue) 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci/****************************************************************************/ 113662306a36Sopenharmony_ci/* */ 113762306a36Sopenharmony_ci/* Routine Name: ips_biosparam */ 113862306a36Sopenharmony_ci/* */ 113962306a36Sopenharmony_ci/* Routine Description: */ 114062306a36Sopenharmony_ci/* */ 114162306a36Sopenharmony_ci/* Set bios geometry for the controller */ 114262306a36Sopenharmony_ci/* */ 114362306a36Sopenharmony_ci/****************************************************************************/ 114462306a36Sopenharmony_cistatic int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, 114562306a36Sopenharmony_ci sector_t capacity, int geom[]) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; 114862306a36Sopenharmony_ci int heads; 114962306a36Sopenharmony_ci int sectors; 115062306a36Sopenharmony_ci int cylinders; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci METHOD_TRACE("ips_biosparam", 1); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (!ha) 115562306a36Sopenharmony_ci /* ?!?! host adater info invalid */ 115662306a36Sopenharmony_ci return (0); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (!ha->active) 115962306a36Sopenharmony_ci return (0); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (!ips_read_adapter_status(ha, IPS_INTR_ON)) 116262306a36Sopenharmony_ci /* ?!?! Enquiry command failed */ 116362306a36Sopenharmony_ci return (0); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) { 116662306a36Sopenharmony_ci heads = IPS_NORM_HEADS; 116762306a36Sopenharmony_ci sectors = IPS_NORM_SECTORS; 116862306a36Sopenharmony_ci } else { 116962306a36Sopenharmony_ci heads = IPS_COMP_HEADS; 117062306a36Sopenharmony_ci sectors = IPS_COMP_SECTORS; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci cylinders = (unsigned long) capacity / (heads * sectors); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d", 117662306a36Sopenharmony_ci heads, sectors, cylinders); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci geom[0] = heads; 117962306a36Sopenharmony_ci geom[1] = sectors; 118062306a36Sopenharmony_ci geom[2] = cylinders; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci return (0); 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci/****************************************************************************/ 118662306a36Sopenharmony_ci/* */ 118762306a36Sopenharmony_ci/* Routine Name: ips_slave_configure */ 118862306a36Sopenharmony_ci/* */ 118962306a36Sopenharmony_ci/* Routine Description: */ 119062306a36Sopenharmony_ci/* */ 119162306a36Sopenharmony_ci/* Set queue depths on devices once scan is complete */ 119262306a36Sopenharmony_ci/* */ 119362306a36Sopenharmony_ci/****************************************************************************/ 119462306a36Sopenharmony_cistatic int 119562306a36Sopenharmony_ciips_slave_configure(struct scsi_device * SDptr) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci ips_ha_t *ha; 119862306a36Sopenharmony_ci int min; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci ha = IPS_HA(SDptr->host); 120162306a36Sopenharmony_ci if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) { 120262306a36Sopenharmony_ci min = ha->max_cmds / 2; 120362306a36Sopenharmony_ci if (ha->enq->ucLogDriveCount <= 2) 120462306a36Sopenharmony_ci min = ha->max_cmds - 1; 120562306a36Sopenharmony_ci scsi_change_queue_depth(SDptr, min); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci SDptr->skip_ms_page_8 = 1; 120962306a36Sopenharmony_ci SDptr->skip_ms_page_3f = 1; 121062306a36Sopenharmony_ci return 0; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci/****************************************************************************/ 121462306a36Sopenharmony_ci/* */ 121562306a36Sopenharmony_ci/* Routine Name: do_ipsintr */ 121662306a36Sopenharmony_ci/* */ 121762306a36Sopenharmony_ci/* Routine Description: */ 121862306a36Sopenharmony_ci/* */ 121962306a36Sopenharmony_ci/* Wrapper for the interrupt handler */ 122062306a36Sopenharmony_ci/* */ 122162306a36Sopenharmony_ci/****************************************************************************/ 122262306a36Sopenharmony_cistatic irqreturn_t 122362306a36Sopenharmony_cido_ipsintr(int irq, void *dev_id) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci ips_ha_t *ha; 122662306a36Sopenharmony_ci struct Scsi_Host *host; 122762306a36Sopenharmony_ci int irqstatus; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci METHOD_TRACE("do_ipsintr", 2); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci ha = (ips_ha_t *) dev_id; 123262306a36Sopenharmony_ci if (!ha) 123362306a36Sopenharmony_ci return IRQ_NONE; 123462306a36Sopenharmony_ci host = ips_sh[ha->host_num]; 123562306a36Sopenharmony_ci /* interrupt during initialization */ 123662306a36Sopenharmony_ci if (!host) { 123762306a36Sopenharmony_ci (*ha->func.intr) (ha); 123862306a36Sopenharmony_ci return IRQ_HANDLED; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci spin_lock(host->host_lock); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (!ha->active) { 124462306a36Sopenharmony_ci spin_unlock(host->host_lock); 124562306a36Sopenharmony_ci return IRQ_HANDLED; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci irqstatus = (*ha->func.intr) (ha); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci spin_unlock(host->host_lock); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* start the next command */ 125362306a36Sopenharmony_ci ips_next(ha, IPS_INTR_ON); 125462306a36Sopenharmony_ci return IRQ_RETVAL(irqstatus); 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci/****************************************************************************/ 125862306a36Sopenharmony_ci/* */ 125962306a36Sopenharmony_ci/* Routine Name: ips_intr_copperhead */ 126062306a36Sopenharmony_ci/* */ 126162306a36Sopenharmony_ci/* Routine Description: */ 126262306a36Sopenharmony_ci/* */ 126362306a36Sopenharmony_ci/* Polling interrupt handler */ 126462306a36Sopenharmony_ci/* */ 126562306a36Sopenharmony_ci/* ASSUMES interrupts are disabled */ 126662306a36Sopenharmony_ci/* */ 126762306a36Sopenharmony_ci/****************************************************************************/ 126862306a36Sopenharmony_ciint 126962306a36Sopenharmony_ciips_intr_copperhead(ips_ha_t * ha) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci ips_stat_t *sp; 127262306a36Sopenharmony_ci ips_scb_t *scb; 127362306a36Sopenharmony_ci IPS_STATUS cstatus; 127462306a36Sopenharmony_ci int intrstatus; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci METHOD_TRACE("ips_intr", 2); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (!ha) 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (!ha->active) 128262306a36Sopenharmony_ci return 0; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci intrstatus = (*ha->func.isintr) (ha); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (!intrstatus) { 128762306a36Sopenharmony_ci /* 128862306a36Sopenharmony_ci * Unexpected/Shared interrupt 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci return 0; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci while (true) { 129562306a36Sopenharmony_ci sp = &ha->sp; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci intrstatus = (*ha->func.isintr) (ha); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (!intrstatus) 130062306a36Sopenharmony_ci break; 130162306a36Sopenharmony_ci else 130262306a36Sopenharmony_ci cstatus.value = (*ha->func.statupd) (ha); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { 130562306a36Sopenharmony_ci /* Spurious Interrupt ? */ 130662306a36Sopenharmony_ci continue; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci ips_chkstatus(ha, &cstatus); 131062306a36Sopenharmony_ci scb = (ips_scb_t *) sp->scb_addr; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* 131362306a36Sopenharmony_ci * use the callback function to finish things up 131462306a36Sopenharmony_ci * NOTE: interrupts are OFF for this 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci (*scb->callback) (ha, scb); 131762306a36Sopenharmony_ci } /* end while */ 131862306a36Sopenharmony_ci return 1; 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci/****************************************************************************/ 132262306a36Sopenharmony_ci/* */ 132362306a36Sopenharmony_ci/* Routine Name: ips_intr_morpheus */ 132462306a36Sopenharmony_ci/* */ 132562306a36Sopenharmony_ci/* Routine Description: */ 132662306a36Sopenharmony_ci/* */ 132762306a36Sopenharmony_ci/* Polling interrupt handler */ 132862306a36Sopenharmony_ci/* */ 132962306a36Sopenharmony_ci/* ASSUMES interrupts are disabled */ 133062306a36Sopenharmony_ci/* */ 133162306a36Sopenharmony_ci/****************************************************************************/ 133262306a36Sopenharmony_ciint 133362306a36Sopenharmony_ciips_intr_morpheus(ips_ha_t * ha) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci ips_stat_t *sp; 133662306a36Sopenharmony_ci ips_scb_t *scb; 133762306a36Sopenharmony_ci IPS_STATUS cstatus; 133862306a36Sopenharmony_ci int intrstatus; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci METHOD_TRACE("ips_intr_morpheus", 2); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (!ha) 134362306a36Sopenharmony_ci return 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (!ha->active) 134662306a36Sopenharmony_ci return 0; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci intrstatus = (*ha->func.isintr) (ha); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (!intrstatus) { 135162306a36Sopenharmony_ci /* 135262306a36Sopenharmony_ci * Unexpected/Shared interrupt 135362306a36Sopenharmony_ci */ 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci return 0; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci while (true) { 135962306a36Sopenharmony_ci sp = &ha->sp; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci intrstatus = (*ha->func.isintr) (ha); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (!intrstatus) 136462306a36Sopenharmony_ci break; 136562306a36Sopenharmony_ci else 136662306a36Sopenharmony_ci cstatus.value = (*ha->func.statupd) (ha); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (cstatus.value == 0xffffffff) 136962306a36Sopenharmony_ci /* No more to process */ 137062306a36Sopenharmony_ci break; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { 137362306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 137462306a36Sopenharmony_ci "Spurious interrupt; no ccb.\n"); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci continue; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ips_chkstatus(ha, &cstatus); 138062306a36Sopenharmony_ci scb = (ips_scb_t *) sp->scb_addr; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci /* 138362306a36Sopenharmony_ci * use the callback function to finish things up 138462306a36Sopenharmony_ci * NOTE: interrupts are OFF for this 138562306a36Sopenharmony_ci */ 138662306a36Sopenharmony_ci (*scb->callback) (ha, scb); 138762306a36Sopenharmony_ci } /* end while */ 138862306a36Sopenharmony_ci return 1; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci/****************************************************************************/ 139262306a36Sopenharmony_ci/* */ 139362306a36Sopenharmony_ci/* Routine Name: ips_info */ 139462306a36Sopenharmony_ci/* */ 139562306a36Sopenharmony_ci/* Routine Description: */ 139662306a36Sopenharmony_ci/* */ 139762306a36Sopenharmony_ci/* Return info about the driver */ 139862306a36Sopenharmony_ci/* */ 139962306a36Sopenharmony_ci/****************************************************************************/ 140062306a36Sopenharmony_cistatic const char * 140162306a36Sopenharmony_ciips_info(struct Scsi_Host *SH) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci static char buffer[256]; 140462306a36Sopenharmony_ci char *bp; 140562306a36Sopenharmony_ci ips_ha_t *ha; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci METHOD_TRACE("ips_info", 1); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci ha = IPS_HA(SH); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (!ha) 141262306a36Sopenharmony_ci return (NULL); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci bp = &buffer[0]; 141562306a36Sopenharmony_ci memset(bp, 0, sizeof (buffer)); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ", 141862306a36Sopenharmony_ci IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) { 142162306a36Sopenharmony_ci strcat(bp, " <"); 142262306a36Sopenharmony_ci strcat(bp, ips_adapter_name[ha->ad_type - 1]); 142362306a36Sopenharmony_ci strcat(bp, ">"); 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci return (bp); 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic int 143062306a36Sopenharmony_ciips_write_info(struct Scsi_Host *host, char *buffer, int length) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci int i; 143362306a36Sopenharmony_ci ips_ha_t *ha = NULL; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* Find our host structure */ 143662306a36Sopenharmony_ci for (i = 0; i < ips_next_controller; i++) { 143762306a36Sopenharmony_ci if (ips_sh[i]) { 143862306a36Sopenharmony_ci if (ips_sh[i] == host) { 143962306a36Sopenharmony_ci ha = (ips_ha_t *) ips_sh[i]->hostdata; 144062306a36Sopenharmony_ci break; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci if (!ha) 144662306a36Sopenharmony_ci return (-EINVAL); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci return 0; 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic int 145262306a36Sopenharmony_ciips_show_info(struct seq_file *m, struct Scsi_Host *host) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci int i; 145562306a36Sopenharmony_ci ips_ha_t *ha = NULL; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* Find our host structure */ 145862306a36Sopenharmony_ci for (i = 0; i < ips_next_controller; i++) { 145962306a36Sopenharmony_ci if (ips_sh[i]) { 146062306a36Sopenharmony_ci if (ips_sh[i] == host) { 146162306a36Sopenharmony_ci ha = (ips_ha_t *) ips_sh[i]->hostdata; 146262306a36Sopenharmony_ci break; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if (!ha) 146862306a36Sopenharmony_ci return (-EINVAL); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci return ips_host_info(ha, m); 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci/*--------------------------------------------------------------------------*/ 147462306a36Sopenharmony_ci/* Helper Functions */ 147562306a36Sopenharmony_ci/*--------------------------------------------------------------------------*/ 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci/****************************************************************************/ 147862306a36Sopenharmony_ci/* */ 147962306a36Sopenharmony_ci/* Routine Name: ips_is_passthru */ 148062306a36Sopenharmony_ci/* */ 148162306a36Sopenharmony_ci/* Routine Description: */ 148262306a36Sopenharmony_ci/* */ 148362306a36Sopenharmony_ci/* Determine if the specified SCSI command is really a passthru command */ 148462306a36Sopenharmony_ci/* */ 148562306a36Sopenharmony_ci/****************************************************************************/ 148662306a36Sopenharmony_cistatic int ips_is_passthru(struct scsi_cmnd *SC) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci unsigned long flags; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci METHOD_TRACE("ips_is_passthru", 1); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (!SC) 149362306a36Sopenharmony_ci return (0); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) && 149662306a36Sopenharmony_ci (SC->device->channel == 0) && 149762306a36Sopenharmony_ci (SC->device->id == IPS_ADAPTER_ID) && 149862306a36Sopenharmony_ci (SC->device->lun == 0) && scsi_sglist(SC)) { 149962306a36Sopenharmony_ci struct scatterlist *sg = scsi_sglist(SC); 150062306a36Sopenharmony_ci char *buffer; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci /* local_irq_save() protects the KM_IRQ0 address slot. */ 150362306a36Sopenharmony_ci local_irq_save(flags); 150462306a36Sopenharmony_ci buffer = kmap_local_page(sg_page(sg)) + sg->offset; 150562306a36Sopenharmony_ci if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && 150662306a36Sopenharmony_ci buffer[2] == 'P' && buffer[3] == 'P') { 150762306a36Sopenharmony_ci kunmap_local(buffer); 150862306a36Sopenharmony_ci local_irq_restore(flags); 150962306a36Sopenharmony_ci return 1; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci kunmap_local(buffer); 151262306a36Sopenharmony_ci local_irq_restore(flags); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci return 0; 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci/****************************************************************************/ 151862306a36Sopenharmony_ci/* */ 151962306a36Sopenharmony_ci/* Routine Name: ips_alloc_passthru_buffer */ 152062306a36Sopenharmony_ci/* */ 152162306a36Sopenharmony_ci/* Routine Description: */ 152262306a36Sopenharmony_ci/* allocate a buffer large enough for the ioctl data if the ioctl buffer */ 152362306a36Sopenharmony_ci/* is too small or doesn't exist */ 152462306a36Sopenharmony_ci/****************************************************************************/ 152562306a36Sopenharmony_cistatic int 152662306a36Sopenharmony_ciips_alloc_passthru_buffer(ips_ha_t * ha, int length) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci void *bigger_buf; 152962306a36Sopenharmony_ci dma_addr_t dma_busaddr; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (ha->ioctl_data && length <= ha->ioctl_len) 153262306a36Sopenharmony_ci return 0; 153362306a36Sopenharmony_ci /* there is no buffer or it's not big enough, allocate a new one */ 153462306a36Sopenharmony_ci bigger_buf = dma_alloc_coherent(&ha->pcidev->dev, length, &dma_busaddr, 153562306a36Sopenharmony_ci GFP_KERNEL); 153662306a36Sopenharmony_ci if (bigger_buf) { 153762306a36Sopenharmony_ci /* free the old memory */ 153862306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len, 153962306a36Sopenharmony_ci ha->ioctl_data, ha->ioctl_busaddr); 154062306a36Sopenharmony_ci /* use the new memory */ 154162306a36Sopenharmony_ci ha->ioctl_data = (char *) bigger_buf; 154262306a36Sopenharmony_ci ha->ioctl_len = length; 154362306a36Sopenharmony_ci ha->ioctl_busaddr = dma_busaddr; 154462306a36Sopenharmony_ci } else { 154562306a36Sopenharmony_ci return -1; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci return 0; 154862306a36Sopenharmony_ci} 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci/****************************************************************************/ 155162306a36Sopenharmony_ci/* */ 155262306a36Sopenharmony_ci/* Routine Name: ips_make_passthru */ 155362306a36Sopenharmony_ci/* */ 155462306a36Sopenharmony_ci/* Routine Description: */ 155562306a36Sopenharmony_ci/* */ 155662306a36Sopenharmony_ci/* Make a passthru command out of the info in the Scsi block */ 155762306a36Sopenharmony_ci/* */ 155862306a36Sopenharmony_ci/****************************************************************************/ 155962306a36Sopenharmony_cistatic int 156062306a36Sopenharmony_ciips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci ips_passthru_t *pt; 156362306a36Sopenharmony_ci int length = 0; 156462306a36Sopenharmony_ci int i, ret; 156562306a36Sopenharmony_ci struct scatterlist *sg = scsi_sglist(SC); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci METHOD_TRACE("ips_make_passthru", 1); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i) 157062306a36Sopenharmony_ci length += sg->length; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (length < sizeof (ips_passthru_t)) { 157362306a36Sopenharmony_ci /* wrong size */ 157462306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", 157562306a36Sopenharmony_ci ips_name, ha->host_num); 157662306a36Sopenharmony_ci return (IPS_FAILURE); 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci if (ips_alloc_passthru_buffer(ha, length)) { 157962306a36Sopenharmony_ci /* allocation failure! If ha->ioctl_data exists, use it to return 158062306a36Sopenharmony_ci some error codes. Return a failed command to the scsi layer. */ 158162306a36Sopenharmony_ci if (ha->ioctl_data) { 158262306a36Sopenharmony_ci pt = (ips_passthru_t *) ha->ioctl_data; 158362306a36Sopenharmony_ci ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t)); 158462306a36Sopenharmony_ci pt->BasicStatus = 0x0B; 158562306a36Sopenharmony_ci pt->ExtendedStatus = 0x00; 158662306a36Sopenharmony_ci ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t)); 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci return IPS_FAILURE; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci ha->ioctl_datasize = length; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize); 159362306a36Sopenharmony_ci pt = (ips_passthru_t *) ha->ioctl_data; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci /* 159662306a36Sopenharmony_ci * Some notes about the passthru interface used 159762306a36Sopenharmony_ci * 159862306a36Sopenharmony_ci * IF the scsi op_code == 0x0d then we assume 159962306a36Sopenharmony_ci * that the data came along with/goes with the 160062306a36Sopenharmony_ci * packet we received from the sg driver. In this 160162306a36Sopenharmony_ci * case the CmdBSize field of the pt structure is 160262306a36Sopenharmony_ci * used for the size of the buffer. 160362306a36Sopenharmony_ci */ 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci switch (pt->CoppCmd) { 160662306a36Sopenharmony_ci case IPS_NUMCTRLS: 160762306a36Sopenharmony_ci memcpy(ha->ioctl_data + sizeof (ips_passthru_t), 160862306a36Sopenharmony_ci &ips_num_controllers, sizeof (int)); 160962306a36Sopenharmony_ci ips_scmd_buf_write(SC, ha->ioctl_data, 161062306a36Sopenharmony_ci sizeof (ips_passthru_t) + sizeof (int)); 161162306a36Sopenharmony_ci SC->result = DID_OK << 16; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return (IPS_SUCCESS_IMM); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci case IPS_COPPUSRCMD: 161662306a36Sopenharmony_ci case IPS_COPPIOCCMD: 161762306a36Sopenharmony_ci if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { 161862306a36Sopenharmony_ci if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) { 161962306a36Sopenharmony_ci /* wrong size */ 162062306a36Sopenharmony_ci DEBUG_VAR(1, 162162306a36Sopenharmony_ci "(%s%d) Passthru structure wrong size", 162262306a36Sopenharmony_ci ips_name, ha->host_num); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci return (IPS_FAILURE); 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && 162862306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.op_code == 162962306a36Sopenharmony_ci IPS_CMD_RW_BIOSFW) { 163062306a36Sopenharmony_ci ret = ips_flash_copperhead(ha, pt, scb); 163162306a36Sopenharmony_ci ips_scmd_buf_write(SC, ha->ioctl_data, 163262306a36Sopenharmony_ci sizeof (ips_passthru_t)); 163362306a36Sopenharmony_ci return ret; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci if (ips_usrcmd(ha, pt, scb)) 163662306a36Sopenharmony_ci return (IPS_SUCCESS); 163762306a36Sopenharmony_ci else 163862306a36Sopenharmony_ci return (IPS_FAILURE); 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci } /* end switch */ 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci return (IPS_FAILURE); 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci/****************************************************************************/ 164962306a36Sopenharmony_ci/* Routine Name: ips_flash_copperhead */ 165062306a36Sopenharmony_ci/* Routine Description: */ 165162306a36Sopenharmony_ci/* Flash the BIOS/FW on a Copperhead style controller */ 165262306a36Sopenharmony_ci/****************************************************************************/ 165362306a36Sopenharmony_cistatic int 165462306a36Sopenharmony_ciips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci int datasize; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* Trombone is the only copperhead that can do packet flash, but only 165962306a36Sopenharmony_ci * for firmware. No one said it had to make sense. */ 166062306a36Sopenharmony_ci if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { 166162306a36Sopenharmony_ci if (ips_usrcmd(ha, pt, scb)) 166262306a36Sopenharmony_ci return IPS_SUCCESS; 166362306a36Sopenharmony_ci else 166462306a36Sopenharmony_ci return IPS_FAILURE; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci pt->BasicStatus = 0x0B; 166762306a36Sopenharmony_ci pt->ExtendedStatus = 0; 166862306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 166962306a36Sopenharmony_ci /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */ 167062306a36Sopenharmony_ci /* avoid allocating a huge buffer per adapter ( which can fail ). */ 167162306a36Sopenharmony_ci if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && 167262306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { 167362306a36Sopenharmony_ci pt->BasicStatus = 0; 167462306a36Sopenharmony_ci return ips_flash_bios(ha, pt, scb); 167562306a36Sopenharmony_ci } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) { 167662306a36Sopenharmony_ci if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){ 167762306a36Sopenharmony_ci ha->flash_data = ips_FlashData; 167862306a36Sopenharmony_ci ha->flash_busaddr = ips_flashbusaddr; 167962306a36Sopenharmony_ci ha->flash_len = PAGE_SIZE << 7; 168062306a36Sopenharmony_ci ha->flash_datasize = 0; 168162306a36Sopenharmony_ci } else if (!ha->flash_data) { 168262306a36Sopenharmony_ci datasize = pt->CoppCP.cmd.flashfw.total_packets * 168362306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.count; 168462306a36Sopenharmony_ci ha->flash_data = dma_alloc_coherent(&ha->pcidev->dev, 168562306a36Sopenharmony_ci datasize, &ha->flash_busaddr, GFP_KERNEL); 168662306a36Sopenharmony_ci if (!ha->flash_data){ 168762306a36Sopenharmony_ci printk(KERN_WARNING "Unable to allocate a flash buffer\n"); 168862306a36Sopenharmony_ci return IPS_FAILURE; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci ha->flash_datasize = 0; 169162306a36Sopenharmony_ci ha->flash_len = datasize; 169262306a36Sopenharmony_ci } else 169362306a36Sopenharmony_ci return IPS_FAILURE; 169462306a36Sopenharmony_ci } else { 169562306a36Sopenharmony_ci if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize > 169662306a36Sopenharmony_ci ha->flash_len) { 169762306a36Sopenharmony_ci ips_free_flash_copperhead(ha); 169862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 169962306a36Sopenharmony_ci "failed size sanity check\n"); 170062306a36Sopenharmony_ci return IPS_FAILURE; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci if (!ha->flash_data) 170462306a36Sopenharmony_ci return IPS_FAILURE; 170562306a36Sopenharmony_ci pt->BasicStatus = 0; 170662306a36Sopenharmony_ci memcpy(&ha->flash_data[ha->flash_datasize], pt + 1, 170762306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.count); 170862306a36Sopenharmony_ci ha->flash_datasize += pt->CoppCP.cmd.flashfw.count; 170962306a36Sopenharmony_ci if (pt->CoppCP.cmd.flashfw.packet_num == 171062306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.total_packets - 1) { 171162306a36Sopenharmony_ci if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE) 171262306a36Sopenharmony_ci return ips_flash_bios(ha, pt, scb); 171362306a36Sopenharmony_ci else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) 171462306a36Sopenharmony_ci return ips_flash_firmware(ha, pt, scb); 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci return IPS_SUCCESS_IMM; 171762306a36Sopenharmony_ci} 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci/****************************************************************************/ 172062306a36Sopenharmony_ci/* Routine Name: ips_flash_bios */ 172162306a36Sopenharmony_ci/* Routine Description: */ 172262306a36Sopenharmony_ci/* flashes the bios of a copperhead adapter */ 172362306a36Sopenharmony_ci/****************************************************************************/ 172462306a36Sopenharmony_cistatic int 172562306a36Sopenharmony_ciips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 172662306a36Sopenharmony_ci{ 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && 172962306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) { 173062306a36Sopenharmony_ci if ((!ha->func.programbios) || (!ha->func.erasebios) || 173162306a36Sopenharmony_ci (!ha->func.verifybios)) 173262306a36Sopenharmony_ci goto error; 173362306a36Sopenharmony_ci if ((*ha->func.erasebios) (ha)) { 173462306a36Sopenharmony_ci DEBUG_VAR(1, 173562306a36Sopenharmony_ci "(%s%d) flash bios failed - unable to erase flash", 173662306a36Sopenharmony_ci ips_name, ha->host_num); 173762306a36Sopenharmony_ci goto error; 173862306a36Sopenharmony_ci } else 173962306a36Sopenharmony_ci if ((*ha->func.programbios) (ha, 174062306a36Sopenharmony_ci ha->flash_data + 174162306a36Sopenharmony_ci IPS_BIOS_HEADER, 174262306a36Sopenharmony_ci ha->flash_datasize - 174362306a36Sopenharmony_ci IPS_BIOS_HEADER, 0)) { 174462306a36Sopenharmony_ci DEBUG_VAR(1, 174562306a36Sopenharmony_ci "(%s%d) flash bios failed - unable to flash", 174662306a36Sopenharmony_ci ips_name, ha->host_num); 174762306a36Sopenharmony_ci goto error; 174862306a36Sopenharmony_ci } else 174962306a36Sopenharmony_ci if ((*ha->func.verifybios) (ha, 175062306a36Sopenharmony_ci ha->flash_data + 175162306a36Sopenharmony_ci IPS_BIOS_HEADER, 175262306a36Sopenharmony_ci ha->flash_datasize - 175362306a36Sopenharmony_ci IPS_BIOS_HEADER, 0)) { 175462306a36Sopenharmony_ci DEBUG_VAR(1, 175562306a36Sopenharmony_ci "(%s%d) flash bios failed - unable to verify flash", 175662306a36Sopenharmony_ci ips_name, ha->host_num); 175762306a36Sopenharmony_ci goto error; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci ips_free_flash_copperhead(ha); 176062306a36Sopenharmony_ci return IPS_SUCCESS_IMM; 176162306a36Sopenharmony_ci } else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && 176262306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { 176362306a36Sopenharmony_ci if (!ha->func.erasebios) 176462306a36Sopenharmony_ci goto error; 176562306a36Sopenharmony_ci if ((*ha->func.erasebios) (ha)) { 176662306a36Sopenharmony_ci DEBUG_VAR(1, 176762306a36Sopenharmony_ci "(%s%d) flash bios failed - unable to erase flash", 176862306a36Sopenharmony_ci ips_name, ha->host_num); 176962306a36Sopenharmony_ci goto error; 177062306a36Sopenharmony_ci } 177162306a36Sopenharmony_ci return IPS_SUCCESS_IMM; 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci error: 177462306a36Sopenharmony_ci pt->BasicStatus = 0x0B; 177562306a36Sopenharmony_ci pt->ExtendedStatus = 0x00; 177662306a36Sopenharmony_ci ips_free_flash_copperhead(ha); 177762306a36Sopenharmony_ci return IPS_FAILURE; 177862306a36Sopenharmony_ci} 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci/****************************************************************************/ 178162306a36Sopenharmony_ci/* */ 178262306a36Sopenharmony_ci/* Routine Name: ips_fill_scb_sg_single */ 178362306a36Sopenharmony_ci/* */ 178462306a36Sopenharmony_ci/* Routine Description: */ 178562306a36Sopenharmony_ci/* Fill in a single scb sg_list element from an address */ 178662306a36Sopenharmony_ci/* return a -1 if a breakup occurred */ 178762306a36Sopenharmony_ci/****************************************************************************/ 178862306a36Sopenharmony_cistatic int 178962306a36Sopenharmony_ciips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, 179062306a36Sopenharmony_ci ips_scb_t * scb, int indx, unsigned int e_len) 179162306a36Sopenharmony_ci{ 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci int ret_val = 0; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if ((scb->data_len + e_len) > ha->max_xfer) { 179662306a36Sopenharmony_ci e_len = ha->max_xfer - scb->data_len; 179762306a36Sopenharmony_ci scb->breakup = indx; 179862306a36Sopenharmony_ci ++scb->sg_break; 179962306a36Sopenharmony_ci ret_val = -1; 180062306a36Sopenharmony_ci } else { 180162306a36Sopenharmony_ci scb->breakup = 0; 180262306a36Sopenharmony_ci scb->sg_break = 0; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci if (IPS_USE_ENH_SGLIST(ha)) { 180562306a36Sopenharmony_ci scb->sg_list.enh_list[indx].address_lo = 180662306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(busaddr)); 180762306a36Sopenharmony_ci scb->sg_list.enh_list[indx].address_hi = 180862306a36Sopenharmony_ci cpu_to_le32(upper_32_bits(busaddr)); 180962306a36Sopenharmony_ci scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len); 181062306a36Sopenharmony_ci } else { 181162306a36Sopenharmony_ci scb->sg_list.std_list[indx].address = 181262306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(busaddr)); 181362306a36Sopenharmony_ci scb->sg_list.std_list[indx].length = cpu_to_le32(e_len); 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci ++scb->sg_len; 181762306a36Sopenharmony_ci scb->data_len += e_len; 181862306a36Sopenharmony_ci return ret_val; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci/****************************************************************************/ 182262306a36Sopenharmony_ci/* Routine Name: ips_flash_firmware */ 182362306a36Sopenharmony_ci/* Routine Description: */ 182462306a36Sopenharmony_ci/* flashes the firmware of a copperhead adapter */ 182562306a36Sopenharmony_ci/****************************************************************************/ 182662306a36Sopenharmony_cistatic int 182762306a36Sopenharmony_ciips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 182862306a36Sopenharmony_ci{ 182962306a36Sopenharmony_ci IPS_SG_LIST sg_list; 183062306a36Sopenharmony_ci uint32_t cmd_busaddr; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE && 183362306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) { 183462306a36Sopenharmony_ci memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND)); 183562306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD; 183662306a36Sopenharmony_ci pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize); 183762306a36Sopenharmony_ci } else { 183862306a36Sopenharmony_ci pt->BasicStatus = 0x0B; 183962306a36Sopenharmony_ci pt->ExtendedStatus = 0x00; 184062306a36Sopenharmony_ci ips_free_flash_copperhead(ha); 184162306a36Sopenharmony_ci return IPS_FAILURE; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci /* Save the S/G list pointer so it doesn't get clobbered */ 184462306a36Sopenharmony_ci sg_list.list = scb->sg_list.list; 184562306a36Sopenharmony_ci cmd_busaddr = scb->scb_busaddr; 184662306a36Sopenharmony_ci /* copy in the CP */ 184762306a36Sopenharmony_ci memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); 184862306a36Sopenharmony_ci /* FIX stuff that might be wrong */ 184962306a36Sopenharmony_ci scb->sg_list.list = sg_list.list; 185062306a36Sopenharmony_ci scb->scb_busaddr = cmd_busaddr; 185162306a36Sopenharmony_ci scb->bus = scb->scsi_cmd->device->channel; 185262306a36Sopenharmony_ci scb->target_id = scb->scsi_cmd->device->id; 185362306a36Sopenharmony_ci scb->lun = scb->scsi_cmd->device->lun; 185462306a36Sopenharmony_ci scb->sg_len = 0; 185562306a36Sopenharmony_ci scb->data_len = 0; 185662306a36Sopenharmony_ci scb->flags = 0; 185762306a36Sopenharmony_ci scb->op_code = 0; 185862306a36Sopenharmony_ci scb->callback = ipsintr_done; 185962306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci scb->data_len = ha->flash_datasize; 186262306a36Sopenharmony_ci scb->data_busaddr = 186362306a36Sopenharmony_ci dma_map_single(&ha->pcidev->dev, ha->flash_data, scb->data_len, 186462306a36Sopenharmony_ci IPS_DMA_DIR(scb)); 186562306a36Sopenharmony_ci scb->flags |= IPS_SCB_MAP_SINGLE; 186662306a36Sopenharmony_ci scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); 186762306a36Sopenharmony_ci scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr); 186862306a36Sopenharmony_ci if (pt->TimeOut) 186962306a36Sopenharmony_ci scb->timeout = pt->TimeOut; 187062306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 187162306a36Sopenharmony_ci return IPS_SUCCESS; 187262306a36Sopenharmony_ci} 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci/****************************************************************************/ 187562306a36Sopenharmony_ci/* Routine Name: ips_free_flash_copperhead */ 187662306a36Sopenharmony_ci/* Routine Description: */ 187762306a36Sopenharmony_ci/* release the memory resources used to hold the flash image */ 187862306a36Sopenharmony_ci/****************************************************************************/ 187962306a36Sopenharmony_cistatic void 188062306a36Sopenharmony_ciips_free_flash_copperhead(ips_ha_t * ha) 188162306a36Sopenharmony_ci{ 188262306a36Sopenharmony_ci if (ha->flash_data == ips_FlashData) 188362306a36Sopenharmony_ci test_and_clear_bit(0, &ips_FlashDataInUse); 188462306a36Sopenharmony_ci else if (ha->flash_data) 188562306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, ha->flash_len, 188662306a36Sopenharmony_ci ha->flash_data, ha->flash_busaddr); 188762306a36Sopenharmony_ci ha->flash_data = NULL; 188862306a36Sopenharmony_ci} 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci/****************************************************************************/ 189162306a36Sopenharmony_ci/* */ 189262306a36Sopenharmony_ci/* Routine Name: ips_usrcmd */ 189362306a36Sopenharmony_ci/* */ 189462306a36Sopenharmony_ci/* Routine Description: */ 189562306a36Sopenharmony_ci/* */ 189662306a36Sopenharmony_ci/* Process a user command and make it ready to send */ 189762306a36Sopenharmony_ci/* */ 189862306a36Sopenharmony_ci/****************************************************************************/ 189962306a36Sopenharmony_cistatic int 190062306a36Sopenharmony_ciips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) 190162306a36Sopenharmony_ci{ 190262306a36Sopenharmony_ci IPS_SG_LIST sg_list; 190362306a36Sopenharmony_ci uint32_t cmd_busaddr; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci METHOD_TRACE("ips_usrcmd", 1); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if ((!scb) || (!pt) || (!ha)) 190862306a36Sopenharmony_ci return (0); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci /* Save the S/G list pointer so it doesn't get clobbered */ 191162306a36Sopenharmony_ci sg_list.list = scb->sg_list.list; 191262306a36Sopenharmony_ci cmd_busaddr = scb->scb_busaddr; 191362306a36Sopenharmony_ci /* copy in the CP */ 191462306a36Sopenharmony_ci memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); 191562306a36Sopenharmony_ci memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE)); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci /* FIX stuff that might be wrong */ 191862306a36Sopenharmony_ci scb->sg_list.list = sg_list.list; 191962306a36Sopenharmony_ci scb->scb_busaddr = cmd_busaddr; 192062306a36Sopenharmony_ci scb->bus = scb->scsi_cmd->device->channel; 192162306a36Sopenharmony_ci scb->target_id = scb->scsi_cmd->device->id; 192262306a36Sopenharmony_ci scb->lun = scb->scsi_cmd->device->lun; 192362306a36Sopenharmony_ci scb->sg_len = 0; 192462306a36Sopenharmony_ci scb->data_len = 0; 192562306a36Sopenharmony_ci scb->flags = 0; 192662306a36Sopenharmony_ci scb->op_code = 0; 192762306a36Sopenharmony_ci scb->callback = ipsintr_done; 192862306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 192962306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci /* we don't support DCDB/READ/WRITE Scatter Gather */ 193262306a36Sopenharmony_ci if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) || 193362306a36Sopenharmony_ci (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) || 193462306a36Sopenharmony_ci (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG)) 193562306a36Sopenharmony_ci return (0); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci if (pt->CmdBSize) { 193862306a36Sopenharmony_ci scb->data_len = pt->CmdBSize; 193962306a36Sopenharmony_ci scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t); 194062306a36Sopenharmony_ci } else { 194162306a36Sopenharmony_ci scb->data_busaddr = 0L; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) 194562306a36Sopenharmony_ci scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + 194662306a36Sopenharmony_ci (unsigned long) &scb-> 194762306a36Sopenharmony_ci dcdb - 194862306a36Sopenharmony_ci (unsigned long) scb); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci if (pt->CmdBSize) { 195162306a36Sopenharmony_ci if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) 195262306a36Sopenharmony_ci scb->dcdb.buffer_pointer = 195362306a36Sopenharmony_ci cpu_to_le32(scb->data_busaddr); 195462306a36Sopenharmony_ci else 195562306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = 195662306a36Sopenharmony_ci cpu_to_le32(scb->data_busaddr); 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci /* set timeouts */ 196062306a36Sopenharmony_ci if (pt->TimeOut) { 196162306a36Sopenharmony_ci scb->timeout = pt->TimeOut; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci if (pt->TimeOut <= 10) 196462306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; 196562306a36Sopenharmony_ci else if (pt->TimeOut <= 60) 196662306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; 196762306a36Sopenharmony_ci else 196862306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; 196962306a36Sopenharmony_ci } 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci /* assume success */ 197262306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci /* success */ 197562306a36Sopenharmony_ci return (1); 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci/****************************************************************************/ 197962306a36Sopenharmony_ci/* */ 198062306a36Sopenharmony_ci/* Routine Name: ips_cleanup_passthru */ 198162306a36Sopenharmony_ci/* */ 198262306a36Sopenharmony_ci/* Routine Description: */ 198362306a36Sopenharmony_ci/* */ 198462306a36Sopenharmony_ci/* Cleanup after a passthru command */ 198562306a36Sopenharmony_ci/* */ 198662306a36Sopenharmony_ci/****************************************************************************/ 198762306a36Sopenharmony_cistatic void 198862306a36Sopenharmony_ciips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) 198962306a36Sopenharmony_ci{ 199062306a36Sopenharmony_ci ips_passthru_t *pt; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci METHOD_TRACE("ips_cleanup_passthru", 1); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci if ((!scb) || (!scb->scsi_cmd) || (!scsi_sglist(scb->scsi_cmd))) { 199562306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru", 199662306a36Sopenharmony_ci ips_name, ha->host_num); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci return; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci pt = (ips_passthru_t *) ha->ioctl_data; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci /* Copy data back to the user */ 200362306a36Sopenharmony_ci if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) /* Copy DCDB Back to Caller's Area */ 200462306a36Sopenharmony_ci memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE)); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci pt->BasicStatus = scb->basic_status; 200762306a36Sopenharmony_ci pt->ExtendedStatus = scb->extended_status; 200862306a36Sopenharmony_ci pt->AdapterType = ha->ad_type; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && 201162306a36Sopenharmony_ci (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || 201262306a36Sopenharmony_ci scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)) 201362306a36Sopenharmony_ci ips_free_flash_copperhead(ha); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize); 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci/****************************************************************************/ 201962306a36Sopenharmony_ci/* */ 202062306a36Sopenharmony_ci/* Routine Name: ips_host_info */ 202162306a36Sopenharmony_ci/* */ 202262306a36Sopenharmony_ci/* Routine Description: */ 202362306a36Sopenharmony_ci/* */ 202462306a36Sopenharmony_ci/* The passthru interface for the driver */ 202562306a36Sopenharmony_ci/* */ 202662306a36Sopenharmony_ci/****************************************************************************/ 202762306a36Sopenharmony_cistatic int 202862306a36Sopenharmony_ciips_host_info(ips_ha_t *ha, struct seq_file *m) 202962306a36Sopenharmony_ci{ 203062306a36Sopenharmony_ci METHOD_TRACE("ips_host_info", 1); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci seq_puts(m, "\nIBM ServeRAID General Information:\n\n"); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) && 203562306a36Sopenharmony_ci (le16_to_cpu(ha->nvram->adapter_type) != 0)) 203662306a36Sopenharmony_ci seq_printf(m, "\tController Type : %s\n", 203762306a36Sopenharmony_ci ips_adapter_name[ha->ad_type - 1]); 203862306a36Sopenharmony_ci else 203962306a36Sopenharmony_ci seq_puts(m, "\tController Type : Unknown\n"); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci if (ha->io_addr) 204262306a36Sopenharmony_ci seq_printf(m, 204362306a36Sopenharmony_ci "\tIO region : 0x%x (%d bytes)\n", 204462306a36Sopenharmony_ci ha->io_addr, ha->io_len); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci if (ha->mem_addr) { 204762306a36Sopenharmony_ci seq_printf(m, 204862306a36Sopenharmony_ci "\tMemory region : 0x%x (%d bytes)\n", 204962306a36Sopenharmony_ci ha->mem_addr, ha->mem_len); 205062306a36Sopenharmony_ci seq_printf(m, 205162306a36Sopenharmony_ci "\tShared memory address : 0x%lx\n", 205262306a36Sopenharmony_ci (unsigned long)ha->mem_ptr); 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci seq_printf(m, "\tIRQ number : %d\n", ha->pcidev->irq); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */ 205862306a36Sopenharmony_ci /* That keeps everything happy for "text" operations on the proc file. */ 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) { 206162306a36Sopenharmony_ci if (ha->nvram->bios_low[3] == 0) { 206262306a36Sopenharmony_ci seq_printf(m, 206362306a36Sopenharmony_ci "\tBIOS Version : %c%c%c%c%c%c%c\n", 206462306a36Sopenharmony_ci ha->nvram->bios_high[0], ha->nvram->bios_high[1], 206562306a36Sopenharmony_ci ha->nvram->bios_high[2], ha->nvram->bios_high[3], 206662306a36Sopenharmony_ci ha->nvram->bios_low[0], ha->nvram->bios_low[1], 206762306a36Sopenharmony_ci ha->nvram->bios_low[2]); 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci } else { 207062306a36Sopenharmony_ci seq_printf(m, 207162306a36Sopenharmony_ci "\tBIOS Version : %c%c%c%c%c%c%c%c\n", 207262306a36Sopenharmony_ci ha->nvram->bios_high[0], ha->nvram->bios_high[1], 207362306a36Sopenharmony_ci ha->nvram->bios_high[2], ha->nvram->bios_high[3], 207462306a36Sopenharmony_ci ha->nvram->bios_low[0], ha->nvram->bios_low[1], 207562306a36Sopenharmony_ci ha->nvram->bios_low[2], ha->nvram->bios_low[3]); 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (ha->enq->CodeBlkVersion[7] == 0) { 208162306a36Sopenharmony_ci seq_printf(m, 208262306a36Sopenharmony_ci "\tFirmware Version : %c%c%c%c%c%c%c\n", 208362306a36Sopenharmony_ci ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], 208462306a36Sopenharmony_ci ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], 208562306a36Sopenharmony_ci ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], 208662306a36Sopenharmony_ci ha->enq->CodeBlkVersion[6]); 208762306a36Sopenharmony_ci } else { 208862306a36Sopenharmony_ci seq_printf(m, 208962306a36Sopenharmony_ci "\tFirmware Version : %c%c%c%c%c%c%c%c\n", 209062306a36Sopenharmony_ci ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], 209162306a36Sopenharmony_ci ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], 209262306a36Sopenharmony_ci ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], 209362306a36Sopenharmony_ci ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]); 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci if (ha->enq->BootBlkVersion[7] == 0) { 209762306a36Sopenharmony_ci seq_printf(m, 209862306a36Sopenharmony_ci "\tBoot Block Version : %c%c%c%c%c%c%c\n", 209962306a36Sopenharmony_ci ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], 210062306a36Sopenharmony_ci ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], 210162306a36Sopenharmony_ci ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], 210262306a36Sopenharmony_ci ha->enq->BootBlkVersion[6]); 210362306a36Sopenharmony_ci } else { 210462306a36Sopenharmony_ci seq_printf(m, 210562306a36Sopenharmony_ci "\tBoot Block Version : %c%c%c%c%c%c%c%c\n", 210662306a36Sopenharmony_ci ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], 210762306a36Sopenharmony_ci ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], 210862306a36Sopenharmony_ci ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], 210962306a36Sopenharmony_ci ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]); 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci seq_printf(m, "\tDriver Version : %s%s\n", 211362306a36Sopenharmony_ci IPS_VERSION_HIGH, IPS_VERSION_LOW); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci seq_printf(m, "\tDriver Build : %d\n", 211662306a36Sopenharmony_ci IPS_BUILD_IDENT); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci seq_printf(m, "\tMax Physical Devices : %d\n", 211962306a36Sopenharmony_ci ha->enq->ucMaxPhysicalDevices); 212062306a36Sopenharmony_ci seq_printf(m, "\tMax Active Commands : %d\n", 212162306a36Sopenharmony_ci ha->max_cmds); 212262306a36Sopenharmony_ci seq_printf(m, "\tCurrent Queued Commands : %d\n", 212362306a36Sopenharmony_ci ha->scb_waitlist.count); 212462306a36Sopenharmony_ci seq_printf(m, "\tCurrent Active Commands : %d\n", 212562306a36Sopenharmony_ci ha->scb_activelist.count - ha->num_ioctl); 212662306a36Sopenharmony_ci seq_printf(m, "\tCurrent Queued PT Commands : %d\n", 212762306a36Sopenharmony_ci ha->copp_waitlist.count); 212862306a36Sopenharmony_ci seq_printf(m, "\tCurrent Active PT Commands : %d\n", 212962306a36Sopenharmony_ci ha->num_ioctl); 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci seq_putc(m, '\n'); 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci return 0; 213462306a36Sopenharmony_ci} 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci/****************************************************************************/ 213762306a36Sopenharmony_ci/* */ 213862306a36Sopenharmony_ci/* Routine Name: ips_identify_controller */ 213962306a36Sopenharmony_ci/* */ 214062306a36Sopenharmony_ci/* Routine Description: */ 214162306a36Sopenharmony_ci/* */ 214262306a36Sopenharmony_ci/* Identify this controller */ 214362306a36Sopenharmony_ci/* */ 214462306a36Sopenharmony_ci/****************************************************************************/ 214562306a36Sopenharmony_cistatic void 214662306a36Sopenharmony_ciips_identify_controller(ips_ha_t * ha) 214762306a36Sopenharmony_ci{ 214862306a36Sopenharmony_ci METHOD_TRACE("ips_identify_controller", 1); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci switch (ha->pcidev->device) { 215162306a36Sopenharmony_ci case IPS_DEVICEID_COPPERHEAD: 215262306a36Sopenharmony_ci if (ha->pcidev->revision <= IPS_REVID_SERVERAID) { 215362306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID; 215462306a36Sopenharmony_ci } else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) { 215562306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID2; 215662306a36Sopenharmony_ci } else if (ha->pcidev->revision == IPS_REVID_NAVAJO) { 215762306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_NAVAJO; 215862306a36Sopenharmony_ci } else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2) 215962306a36Sopenharmony_ci && (ha->slot_num == 0)) { 216062306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_KIOWA; 216162306a36Sopenharmony_ci } else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) && 216262306a36Sopenharmony_ci (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) { 216362306a36Sopenharmony_ci if (ha->enq->ucMaxPhysicalDevices == 15) 216462306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID3L; 216562306a36Sopenharmony_ci else 216662306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID3; 216762306a36Sopenharmony_ci } else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) && 216862306a36Sopenharmony_ci (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) { 216962306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID4H; 217062306a36Sopenharmony_ci } 217162306a36Sopenharmony_ci break; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci case IPS_DEVICEID_MORPHEUS: 217462306a36Sopenharmony_ci switch (ha->pcidev->subsystem_device) { 217562306a36Sopenharmony_ci case IPS_SUBDEVICEID_4L: 217662306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID4L; 217762306a36Sopenharmony_ci break; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci case IPS_SUBDEVICEID_4M: 218062306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID4M; 218162306a36Sopenharmony_ci break; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci case IPS_SUBDEVICEID_4MX: 218462306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID4MX; 218562306a36Sopenharmony_ci break; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci case IPS_SUBDEVICEID_4LX: 218862306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID4LX; 218962306a36Sopenharmony_ci break; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci case IPS_SUBDEVICEID_5I2: 219262306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID5I2; 219362306a36Sopenharmony_ci break; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci case IPS_SUBDEVICEID_5I1: 219662306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID5I1; 219762306a36Sopenharmony_ci break; 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci break; 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci case IPS_DEVICEID_MARCO: 220362306a36Sopenharmony_ci switch (ha->pcidev->subsystem_device) { 220462306a36Sopenharmony_ci case IPS_SUBDEVICEID_6M: 220562306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID6M; 220662306a36Sopenharmony_ci break; 220762306a36Sopenharmony_ci case IPS_SUBDEVICEID_6I: 220862306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID6I; 220962306a36Sopenharmony_ci break; 221062306a36Sopenharmony_ci case IPS_SUBDEVICEID_7k: 221162306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID7k; 221262306a36Sopenharmony_ci break; 221362306a36Sopenharmony_ci case IPS_SUBDEVICEID_7M: 221462306a36Sopenharmony_ci ha->ad_type = IPS_ADTYPE_SERVERAID7M; 221562306a36Sopenharmony_ci break; 221662306a36Sopenharmony_ci } 221762306a36Sopenharmony_ci break; 221862306a36Sopenharmony_ci } 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci/****************************************************************************/ 222262306a36Sopenharmony_ci/* */ 222362306a36Sopenharmony_ci/* Routine Name: ips_get_bios_version */ 222462306a36Sopenharmony_ci/* */ 222562306a36Sopenharmony_ci/* Routine Description: */ 222662306a36Sopenharmony_ci/* */ 222762306a36Sopenharmony_ci/* Get the BIOS revision number */ 222862306a36Sopenharmony_ci/* */ 222962306a36Sopenharmony_ci/****************************************************************************/ 223062306a36Sopenharmony_cistatic void 223162306a36Sopenharmony_ciips_get_bios_version(ips_ha_t * ha, int intr) 223262306a36Sopenharmony_ci{ 223362306a36Sopenharmony_ci ips_scb_t *scb; 223462306a36Sopenharmony_ci int ret; 223562306a36Sopenharmony_ci uint8_t major; 223662306a36Sopenharmony_ci uint8_t minor; 223762306a36Sopenharmony_ci uint8_t subminor; 223862306a36Sopenharmony_ci uint8_t *buffer; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci METHOD_TRACE("ips_get_bios_version", 1); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci major = 0; 224362306a36Sopenharmony_ci minor = 0; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci memcpy(ha->bios_version, " ?", 8); 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) { 224862306a36Sopenharmony_ci if (IPS_USE_MEMIO(ha)) { 224962306a36Sopenharmony_ci /* Memory Mapped I/O */ 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci /* test 1st byte */ 225262306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 225362306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 225462306a36Sopenharmony_ci udelay(25); /* 25 us */ 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) 225762306a36Sopenharmony_ci return; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci writel(1, ha->mem_ptr + IPS_REG_FLAP); 226062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 226162306a36Sopenharmony_ci udelay(25); /* 25 us */ 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) 226462306a36Sopenharmony_ci return; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci /* Get Major version */ 226762306a36Sopenharmony_ci writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); 226862306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 226962306a36Sopenharmony_ci udelay(25); /* 25 us */ 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci major = readb(ha->mem_ptr + IPS_REG_FLDP); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci /* Get Minor version */ 227462306a36Sopenharmony_ci writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); 227562306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 227662306a36Sopenharmony_ci udelay(25); /* 25 us */ 227762306a36Sopenharmony_ci minor = readb(ha->mem_ptr + IPS_REG_FLDP); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci /* Get SubMinor version */ 228062306a36Sopenharmony_ci writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); 228162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 228262306a36Sopenharmony_ci udelay(25); /* 25 us */ 228362306a36Sopenharmony_ci subminor = readb(ha->mem_ptr + IPS_REG_FLDP); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci } else { 228662306a36Sopenharmony_ci /* Programmed I/O */ 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci /* test 1st byte */ 228962306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 229062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 229162306a36Sopenharmony_ci udelay(25); /* 25 us */ 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) 229462306a36Sopenharmony_ci return; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci outl(1, ha->io_addr + IPS_REG_FLAP); 229762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 229862306a36Sopenharmony_ci udelay(25); /* 25 us */ 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) 230162306a36Sopenharmony_ci return; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci /* Get Major version */ 230462306a36Sopenharmony_ci outl(0x1FF, ha->io_addr + IPS_REG_FLAP); 230562306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 230662306a36Sopenharmony_ci udelay(25); /* 25 us */ 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci major = inb(ha->io_addr + IPS_REG_FLDP); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci /* Get Minor version */ 231162306a36Sopenharmony_ci outl(0x1FE, ha->io_addr + IPS_REG_FLAP); 231262306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 231362306a36Sopenharmony_ci udelay(25); /* 25 us */ 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci minor = inb(ha->io_addr + IPS_REG_FLDP); 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci /* Get SubMinor version */ 231862306a36Sopenharmony_ci outl(0x1FD, ha->io_addr + IPS_REG_FLAP); 231962306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 232062306a36Sopenharmony_ci udelay(25); /* 25 us */ 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci subminor = inb(ha->io_addr + IPS_REG_FLDP); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_ci } else { 232662306a36Sopenharmony_ci /* Morpheus Family - Send Command to the card */ 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci buffer = ha->ioctl_data; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci memset(buffer, 0, 0x1000); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci ips_init_scb(ha, scb); 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 233762306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_RW_BIOSFW; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW; 234062306a36Sopenharmony_ci scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); 234162306a36Sopenharmony_ci scb->cmd.flashfw.type = 1; 234262306a36Sopenharmony_ci scb->cmd.flashfw.direction = 0; 234362306a36Sopenharmony_ci scb->cmd.flashfw.count = cpu_to_le32(0x800); 234462306a36Sopenharmony_ci scb->cmd.flashfw.total_packets = 1; 234562306a36Sopenharmony_ci scb->cmd.flashfw.packet_num = 0; 234662306a36Sopenharmony_ci scb->data_len = 0x1000; 234762306a36Sopenharmony_ci scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr; 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci /* issue the command */ 235062306a36Sopenharmony_ci if (((ret = 235162306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, 235262306a36Sopenharmony_ci intr)) == IPS_FAILURE) 235362306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 235462306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { 235562306a36Sopenharmony_ci /* Error occurred */ 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci return; 235862306a36Sopenharmony_ci } 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) { 236162306a36Sopenharmony_ci major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */ 236262306a36Sopenharmony_ci minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */ 236362306a36Sopenharmony_ci subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fd after the header (0xc0) */ 236462306a36Sopenharmony_ci } else { 236562306a36Sopenharmony_ci return; 236662306a36Sopenharmony_ci } 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci ha->bios_version[0] = hex_asc_upper_hi(major); 237062306a36Sopenharmony_ci ha->bios_version[1] = '.'; 237162306a36Sopenharmony_ci ha->bios_version[2] = hex_asc_upper_lo(major); 237262306a36Sopenharmony_ci ha->bios_version[3] = hex_asc_upper_lo(subminor); 237362306a36Sopenharmony_ci ha->bios_version[4] = '.'; 237462306a36Sopenharmony_ci ha->bios_version[5] = hex_asc_upper_hi(minor); 237562306a36Sopenharmony_ci ha->bios_version[6] = hex_asc_upper_lo(minor); 237662306a36Sopenharmony_ci ha->bios_version[7] = 0; 237762306a36Sopenharmony_ci} 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci/****************************************************************************/ 238062306a36Sopenharmony_ci/* */ 238162306a36Sopenharmony_ci/* Routine Name: ips_hainit */ 238262306a36Sopenharmony_ci/* */ 238362306a36Sopenharmony_ci/* Routine Description: */ 238462306a36Sopenharmony_ci/* */ 238562306a36Sopenharmony_ci/* Initialize the controller */ 238662306a36Sopenharmony_ci/* */ 238762306a36Sopenharmony_ci/* NOTE: Assumes to be called from with a lock */ 238862306a36Sopenharmony_ci/* */ 238962306a36Sopenharmony_ci/****************************************************************************/ 239062306a36Sopenharmony_cistatic int 239162306a36Sopenharmony_ciips_hainit(ips_ha_t * ha) 239262306a36Sopenharmony_ci{ 239362306a36Sopenharmony_ci int i; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci METHOD_TRACE("ips_hainit", 1); 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci if (!ha) 239862306a36Sopenharmony_ci return (0); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci if (ha->func.statinit) 240162306a36Sopenharmony_ci (*ha->func.statinit) (ha); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci if (ha->func.enableint) 240462306a36Sopenharmony_ci (*ha->func.enableint) (ha); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci /* Send FFDC */ 240762306a36Sopenharmony_ci ha->reset_count = 1; 240862306a36Sopenharmony_ci ha->last_ffdc = ktime_get_real_seconds(); 240962306a36Sopenharmony_ci ips_ffdc_reset(ha, IPS_INTR_IORL); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci if (!ips_read_config(ha, IPS_INTR_IORL)) { 241262306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 241362306a36Sopenharmony_ci "unable to read config from controller.\n"); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci return (0); 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci /* end if */ 241862306a36Sopenharmony_ci if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) { 241962306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 242062306a36Sopenharmony_ci "unable to read controller status.\n"); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci return (0); 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci /* Identify this controller */ 242662306a36Sopenharmony_ci ips_identify_controller(ha); 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) { 242962306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 243062306a36Sopenharmony_ci "unable to read subsystem parameters.\n"); 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci return (0); 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci /* write nvram user page 5 */ 243662306a36Sopenharmony_ci if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { 243762306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 243862306a36Sopenharmony_ci "unable to write driver info to controller.\n"); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci return (0); 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */ 244462306a36Sopenharmony_ci if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1)) 244562306a36Sopenharmony_ci ips_clear_adapter(ha, IPS_INTR_IORL); 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci /* set limits on SID, LUN, BUS */ 244862306a36Sopenharmony_ci ha->ntargets = IPS_MAX_TARGETS + 1; 244962306a36Sopenharmony_ci ha->nlun = 1; 245062306a36Sopenharmony_ci ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1; 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci switch (ha->conf->logical_drive[0].ucStripeSize) { 245362306a36Sopenharmony_ci case 4: 245462306a36Sopenharmony_ci ha->max_xfer = 0x10000; 245562306a36Sopenharmony_ci break; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci case 5: 245862306a36Sopenharmony_ci ha->max_xfer = 0x20000; 245962306a36Sopenharmony_ci break; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci case 6: 246262306a36Sopenharmony_ci ha->max_xfer = 0x40000; 246362306a36Sopenharmony_ci break; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci case 7: 246662306a36Sopenharmony_ci default: 246762306a36Sopenharmony_ci ha->max_xfer = 0x80000; 246862306a36Sopenharmony_ci break; 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci /* setup max concurrent commands */ 247262306a36Sopenharmony_ci if (le32_to_cpu(ha->subsys->param[4]) & 0x1) { 247362306a36Sopenharmony_ci /* Use the new method */ 247462306a36Sopenharmony_ci ha->max_cmds = ha->enq->ucConcurrentCmdCount; 247562306a36Sopenharmony_ci } else { 247662306a36Sopenharmony_ci /* use the old method */ 247762306a36Sopenharmony_ci switch (ha->conf->logical_drive[0].ucStripeSize) { 247862306a36Sopenharmony_ci case 4: 247962306a36Sopenharmony_ci ha->max_cmds = 32; 248062306a36Sopenharmony_ci break; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci case 5: 248362306a36Sopenharmony_ci ha->max_cmds = 16; 248462306a36Sopenharmony_ci break; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci case 6: 248762306a36Sopenharmony_ci ha->max_cmds = 8; 248862306a36Sopenharmony_ci break; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci case 7: 249162306a36Sopenharmony_ci default: 249262306a36Sopenharmony_ci ha->max_cmds = 4; 249362306a36Sopenharmony_ci break; 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci } 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci /* Limit the Active Commands on a Lite Adapter */ 249862306a36Sopenharmony_ci if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) || 249962306a36Sopenharmony_ci (ha->ad_type == IPS_ADTYPE_SERVERAID4L) || 250062306a36Sopenharmony_ci (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) { 250162306a36Sopenharmony_ci if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) 250262306a36Sopenharmony_ci ha->max_cmds = MaxLiteCmds; 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci /* set controller IDs */ 250662306a36Sopenharmony_ci ha->ha_id[0] = IPS_ADAPTER_ID; 250762306a36Sopenharmony_ci for (i = 1; i < ha->nbus; i++) { 250862306a36Sopenharmony_ci ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f; 250962306a36Sopenharmony_ci ha->dcdb_active[i - 1] = 0; 251062306a36Sopenharmony_ci } 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci return (1); 251362306a36Sopenharmony_ci} 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci/****************************************************************************/ 251662306a36Sopenharmony_ci/* */ 251762306a36Sopenharmony_ci/* Routine Name: ips_next */ 251862306a36Sopenharmony_ci/* */ 251962306a36Sopenharmony_ci/* Routine Description: */ 252062306a36Sopenharmony_ci/* */ 252162306a36Sopenharmony_ci/* Take the next command off the queue and send it to the controller */ 252262306a36Sopenharmony_ci/* */ 252362306a36Sopenharmony_ci/****************************************************************************/ 252462306a36Sopenharmony_cistatic void 252562306a36Sopenharmony_ciips_next(ips_ha_t * ha, int intr) 252662306a36Sopenharmony_ci{ 252762306a36Sopenharmony_ci ips_scb_t *scb; 252862306a36Sopenharmony_ci struct scsi_cmnd *SC; 252962306a36Sopenharmony_ci struct scsi_cmnd *p; 253062306a36Sopenharmony_ci struct scsi_cmnd *q; 253162306a36Sopenharmony_ci ips_copp_wait_item_t *item; 253262306a36Sopenharmony_ci int ret; 253362306a36Sopenharmony_ci struct Scsi_Host *host; 253462306a36Sopenharmony_ci METHOD_TRACE("ips_next", 1); 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci if (!ha) 253762306a36Sopenharmony_ci return; 253862306a36Sopenharmony_ci host = ips_sh[ha->host_num]; 253962306a36Sopenharmony_ci /* 254062306a36Sopenharmony_ci * Block access to the queue function so 254162306a36Sopenharmony_ci * this command won't time out 254262306a36Sopenharmony_ci */ 254362306a36Sopenharmony_ci if (intr == IPS_INTR_ON) 254462306a36Sopenharmony_ci spin_lock(host->host_lock); 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci if ((ha->subsys->param[3] & 0x300000) 254762306a36Sopenharmony_ci && (ha->scb_activelist.count == 0)) { 254862306a36Sopenharmony_ci time64_t now = ktime_get_real_seconds(); 254962306a36Sopenharmony_ci if (now - ha->last_ffdc > IPS_SECS_8HOURS) { 255062306a36Sopenharmony_ci ha->last_ffdc = now; 255162306a36Sopenharmony_ci ips_ffdc_time(ha); 255262306a36Sopenharmony_ci } 255362306a36Sopenharmony_ci } 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci /* 255662306a36Sopenharmony_ci * Send passthru commands 255762306a36Sopenharmony_ci * These have priority over normal I/O 255862306a36Sopenharmony_ci * but shouldn't affect performance too much 255962306a36Sopenharmony_ci * since we limit the number that can be active 256062306a36Sopenharmony_ci * on the card at any one time 256162306a36Sopenharmony_ci */ 256262306a36Sopenharmony_ci while ((ha->num_ioctl < IPS_MAX_IOCTL) && 256362306a36Sopenharmony_ci (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) { 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci item = ips_removeq_copp_head(&ha->copp_waitlist); 256662306a36Sopenharmony_ci ha->num_ioctl++; 256762306a36Sopenharmony_ci if (intr == IPS_INTR_ON) 256862306a36Sopenharmony_ci spin_unlock(host->host_lock); 256962306a36Sopenharmony_ci scb->scsi_cmd = item->scsi_cmd; 257062306a36Sopenharmony_ci kfree(item); 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr); 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci if (intr == IPS_INTR_ON) 257562306a36Sopenharmony_ci spin_lock(host->host_lock); 257662306a36Sopenharmony_ci switch (ret) { 257762306a36Sopenharmony_ci case IPS_FAILURE: 257862306a36Sopenharmony_ci if (scb->scsi_cmd) { 257962306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 258062306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 258162306a36Sopenharmony_ci } 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci ips_freescb(ha, scb); 258462306a36Sopenharmony_ci break; 258562306a36Sopenharmony_ci case IPS_SUCCESS_IMM: 258662306a36Sopenharmony_ci if (scb->scsi_cmd) { 258762306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 258862306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 258962306a36Sopenharmony_ci } 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci ips_freescb(ha, scb); 259262306a36Sopenharmony_ci break; 259362306a36Sopenharmony_ci default: 259462306a36Sopenharmony_ci break; 259562306a36Sopenharmony_ci } /* end case */ 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci if (ret != IPS_SUCCESS) { 259862306a36Sopenharmony_ci ha->num_ioctl--; 259962306a36Sopenharmony_ci continue; 260062306a36Sopenharmony_ci } 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci ret = ips_send_cmd(ha, scb); 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci if (ret == IPS_SUCCESS) 260562306a36Sopenharmony_ci ips_putq_scb_head(&ha->scb_activelist, scb); 260662306a36Sopenharmony_ci else 260762306a36Sopenharmony_ci ha->num_ioctl--; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci switch (ret) { 261062306a36Sopenharmony_ci case IPS_FAILURE: 261162306a36Sopenharmony_ci if (scb->scsi_cmd) { 261262306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 261362306a36Sopenharmony_ci } 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci ips_freescb(ha, scb); 261662306a36Sopenharmony_ci break; 261762306a36Sopenharmony_ci case IPS_SUCCESS_IMM: 261862306a36Sopenharmony_ci ips_freescb(ha, scb); 261962306a36Sopenharmony_ci break; 262062306a36Sopenharmony_ci default: 262162306a36Sopenharmony_ci break; 262262306a36Sopenharmony_ci } /* end case */ 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci } 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci /* 262762306a36Sopenharmony_ci * Send "Normal" I/O commands 262862306a36Sopenharmony_ci */ 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci p = ha->scb_waitlist.head; 263162306a36Sopenharmony_ci while ((p) && (scb = ips_getscb(ha))) { 263262306a36Sopenharmony_ci if ((scmd_channel(p) > 0) 263362306a36Sopenharmony_ci && (ha-> 263462306a36Sopenharmony_ci dcdb_active[scmd_channel(p) - 263562306a36Sopenharmony_ci 1] & (1 << scmd_id(p)))) { 263662306a36Sopenharmony_ci ips_freescb(ha, scb); 263762306a36Sopenharmony_ci p = (struct scsi_cmnd *) p->host_scribble; 263862306a36Sopenharmony_ci continue; 263962306a36Sopenharmony_ci } 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci q = p; 264262306a36Sopenharmony_ci SC = ips_removeq_wait(&ha->scb_waitlist, q); 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ci if (intr == IPS_INTR_ON) 264562306a36Sopenharmony_ci spin_unlock(host->host_lock); /* Unlock HA after command is taken off queue */ 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci SC->result = DID_OK; 264862306a36Sopenharmony_ci SC->host_scribble = NULL; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci scb->target_id = SC->device->id; 265162306a36Sopenharmony_ci scb->lun = SC->device->lun; 265262306a36Sopenharmony_ci scb->bus = SC->device->channel; 265362306a36Sopenharmony_ci scb->scsi_cmd = SC; 265462306a36Sopenharmony_ci scb->breakup = 0; 265562306a36Sopenharmony_ci scb->data_len = 0; 265662306a36Sopenharmony_ci scb->callback = ipsintr_done; 265762306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 265862306a36Sopenharmony_ci memset(&scb->cmd, 0, 16); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci /* copy in the CDB */ 266162306a36Sopenharmony_ci memcpy(scb->cdb, SC->cmnd, SC->cmd_len); 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci scb->sg_count = scsi_dma_map(SC); 266462306a36Sopenharmony_ci BUG_ON(scb->sg_count < 0); 266562306a36Sopenharmony_ci if (scb->sg_count) { 266662306a36Sopenharmony_ci struct scatterlist *sg; 266762306a36Sopenharmony_ci int i; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci scb->flags |= IPS_SCB_MAP_SG; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci scsi_for_each_sg(SC, sg, scb->sg_count, i) { 267262306a36Sopenharmony_ci if (ips_fill_scb_sg_single 267362306a36Sopenharmony_ci (ha, sg_dma_address(sg), scb, i, 267462306a36Sopenharmony_ci sg_dma_len(sg)) < 0) 267562306a36Sopenharmony_ci break; 267662306a36Sopenharmony_ci } 267762306a36Sopenharmony_ci scb->dcdb.transfer_length = scb->data_len; 267862306a36Sopenharmony_ci } else { 267962306a36Sopenharmony_ci scb->data_busaddr = 0L; 268062306a36Sopenharmony_ci scb->sg_len = 0; 268162306a36Sopenharmony_ci scb->data_len = 0; 268262306a36Sopenharmony_ci scb->dcdb.transfer_length = 0; 268362306a36Sopenharmony_ci } 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci scb->dcdb.cmd_attribute = 268662306a36Sopenharmony_ci ips_command_direction[scb->scsi_cmd->cmnd[0]]; 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci /* Allow a WRITE BUFFER Command to Have no Data */ 268962306a36Sopenharmony_ci /* This is Used by Tape Flash Utilites */ 269062306a36Sopenharmony_ci if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && 269162306a36Sopenharmony_ci (scb->data_len == 0)) 269262306a36Sopenharmony_ci scb->dcdb.cmd_attribute = 0; 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci if (!(scb->dcdb.cmd_attribute & 0x3)) 269562306a36Sopenharmony_ci scb->dcdb.transfer_length = 0; 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci if (scb->data_len >= IPS_MAX_XFER) { 269862306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; 269962306a36Sopenharmony_ci scb->dcdb.transfer_length = 0; 270062306a36Sopenharmony_ci } 270162306a36Sopenharmony_ci if (intr == IPS_INTR_ON) 270262306a36Sopenharmony_ci spin_lock(host->host_lock); 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci ret = ips_send_cmd(ha, scb); 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci switch (ret) { 270762306a36Sopenharmony_ci case IPS_SUCCESS: 270862306a36Sopenharmony_ci ips_putq_scb_head(&ha->scb_activelist, scb); 270962306a36Sopenharmony_ci break; 271062306a36Sopenharmony_ci case IPS_FAILURE: 271162306a36Sopenharmony_ci if (scb->scsi_cmd) { 271262306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 271362306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci if (scb->bus) 271762306a36Sopenharmony_ci ha->dcdb_active[scb->bus - 1] &= 271862306a36Sopenharmony_ci ~(1 << scb->target_id); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci ips_freescb(ha, scb); 272162306a36Sopenharmony_ci break; 272262306a36Sopenharmony_ci case IPS_SUCCESS_IMM: 272362306a36Sopenharmony_ci if (scb->scsi_cmd) 272462306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci if (scb->bus) 272762306a36Sopenharmony_ci ha->dcdb_active[scb->bus - 1] &= 272862306a36Sopenharmony_ci ~(1 << scb->target_id); 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci ips_freescb(ha, scb); 273162306a36Sopenharmony_ci break; 273262306a36Sopenharmony_ci default: 273362306a36Sopenharmony_ci break; 273462306a36Sopenharmony_ci } /* end case */ 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci p = (struct scsi_cmnd *) p->host_scribble; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci } /* end while */ 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci if (intr == IPS_INTR_ON) 274162306a36Sopenharmony_ci spin_unlock(host->host_lock); 274262306a36Sopenharmony_ci} 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci/****************************************************************************/ 274562306a36Sopenharmony_ci/* */ 274662306a36Sopenharmony_ci/* Routine Name: ips_putq_scb_head */ 274762306a36Sopenharmony_ci/* */ 274862306a36Sopenharmony_ci/* Routine Description: */ 274962306a36Sopenharmony_ci/* */ 275062306a36Sopenharmony_ci/* Add an item to the head of the queue */ 275162306a36Sopenharmony_ci/* */ 275262306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 275362306a36Sopenharmony_ci/* */ 275462306a36Sopenharmony_ci/****************************************************************************/ 275562306a36Sopenharmony_cistatic void 275662306a36Sopenharmony_ciips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) 275762306a36Sopenharmony_ci{ 275862306a36Sopenharmony_ci METHOD_TRACE("ips_putq_scb_head", 1); 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci if (!item) 276162306a36Sopenharmony_ci return; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci item->q_next = queue->head; 276462306a36Sopenharmony_ci queue->head = item; 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci if (!queue->tail) 276762306a36Sopenharmony_ci queue->tail = item; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci queue->count++; 277062306a36Sopenharmony_ci} 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci/****************************************************************************/ 277362306a36Sopenharmony_ci/* */ 277462306a36Sopenharmony_ci/* Routine Name: ips_removeq_scb_head */ 277562306a36Sopenharmony_ci/* */ 277662306a36Sopenharmony_ci/* Routine Description: */ 277762306a36Sopenharmony_ci/* */ 277862306a36Sopenharmony_ci/* Remove the head of the queue */ 277962306a36Sopenharmony_ci/* */ 278062306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 278162306a36Sopenharmony_ci/* */ 278262306a36Sopenharmony_ci/****************************************************************************/ 278362306a36Sopenharmony_cistatic ips_scb_t * 278462306a36Sopenharmony_ciips_removeq_scb_head(ips_scb_queue_t * queue) 278562306a36Sopenharmony_ci{ 278662306a36Sopenharmony_ci ips_scb_t *item; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci METHOD_TRACE("ips_removeq_scb_head", 1); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci item = queue->head; 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci if (!item) { 279362306a36Sopenharmony_ci return (NULL); 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci queue->head = item->q_next; 279762306a36Sopenharmony_ci item->q_next = NULL; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci if (queue->tail == item) 280062306a36Sopenharmony_ci queue->tail = NULL; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci queue->count--; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci return (item); 280562306a36Sopenharmony_ci} 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci/****************************************************************************/ 280862306a36Sopenharmony_ci/* */ 280962306a36Sopenharmony_ci/* Routine Name: ips_removeq_scb */ 281062306a36Sopenharmony_ci/* */ 281162306a36Sopenharmony_ci/* Routine Description: */ 281262306a36Sopenharmony_ci/* */ 281362306a36Sopenharmony_ci/* Remove an item from a queue */ 281462306a36Sopenharmony_ci/* */ 281562306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 281662306a36Sopenharmony_ci/* */ 281762306a36Sopenharmony_ci/****************************************************************************/ 281862306a36Sopenharmony_cistatic ips_scb_t * 281962306a36Sopenharmony_ciips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) 282062306a36Sopenharmony_ci{ 282162306a36Sopenharmony_ci ips_scb_t *p; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci METHOD_TRACE("ips_removeq_scb", 1); 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci if (!item) 282662306a36Sopenharmony_ci return (NULL); 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci if (item == queue->head) { 282962306a36Sopenharmony_ci return (ips_removeq_scb_head(queue)); 283062306a36Sopenharmony_ci } 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci p = queue->head; 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci while ((p) && (item != p->q_next)) 283562306a36Sopenharmony_ci p = p->q_next; 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci if (p) { 283862306a36Sopenharmony_ci /* found a match */ 283962306a36Sopenharmony_ci p->q_next = item->q_next; 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci if (!item->q_next) 284262306a36Sopenharmony_ci queue->tail = p; 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci item->q_next = NULL; 284562306a36Sopenharmony_ci queue->count--; 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci return (item); 284862306a36Sopenharmony_ci } 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci return (NULL); 285162306a36Sopenharmony_ci} 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci/****************************************************************************/ 285462306a36Sopenharmony_ci/* */ 285562306a36Sopenharmony_ci/* Routine Name: ips_putq_wait_tail */ 285662306a36Sopenharmony_ci/* */ 285762306a36Sopenharmony_ci/* Routine Description: */ 285862306a36Sopenharmony_ci/* */ 285962306a36Sopenharmony_ci/* Add an item to the tail of the queue */ 286062306a36Sopenharmony_ci/* */ 286162306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 286262306a36Sopenharmony_ci/* */ 286362306a36Sopenharmony_ci/****************************************************************************/ 286462306a36Sopenharmony_cistatic void ips_putq_wait_tail(ips_wait_queue_entry_t *queue, struct scsi_cmnd *item) 286562306a36Sopenharmony_ci{ 286662306a36Sopenharmony_ci METHOD_TRACE("ips_putq_wait_tail", 1); 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci if (!item) 286962306a36Sopenharmony_ci return; 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci item->host_scribble = NULL; 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci if (queue->tail) 287462306a36Sopenharmony_ci queue->tail->host_scribble = (char *) item; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci queue->tail = item; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci if (!queue->head) 287962306a36Sopenharmony_ci queue->head = item; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci queue->count++; 288262306a36Sopenharmony_ci} 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci/****************************************************************************/ 288562306a36Sopenharmony_ci/* */ 288662306a36Sopenharmony_ci/* Routine Name: ips_removeq_wait_head */ 288762306a36Sopenharmony_ci/* */ 288862306a36Sopenharmony_ci/* Routine Description: */ 288962306a36Sopenharmony_ci/* */ 289062306a36Sopenharmony_ci/* Remove the head of the queue */ 289162306a36Sopenharmony_ci/* */ 289262306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 289362306a36Sopenharmony_ci/* */ 289462306a36Sopenharmony_ci/****************************************************************************/ 289562306a36Sopenharmony_cistatic struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_entry_t *queue) 289662306a36Sopenharmony_ci{ 289762306a36Sopenharmony_ci struct scsi_cmnd *item; 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci METHOD_TRACE("ips_removeq_wait_head", 1); 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci item = queue->head; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci if (!item) { 290462306a36Sopenharmony_ci return (NULL); 290562306a36Sopenharmony_ci } 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci queue->head = (struct scsi_cmnd *) item->host_scribble; 290862306a36Sopenharmony_ci item->host_scribble = NULL; 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci if (queue->tail == item) 291162306a36Sopenharmony_ci queue->tail = NULL; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci queue->count--; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci return (item); 291662306a36Sopenharmony_ci} 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci/****************************************************************************/ 291962306a36Sopenharmony_ci/* */ 292062306a36Sopenharmony_ci/* Routine Name: ips_removeq_wait */ 292162306a36Sopenharmony_ci/* */ 292262306a36Sopenharmony_ci/* Routine Description: */ 292362306a36Sopenharmony_ci/* */ 292462306a36Sopenharmony_ci/* Remove an item from a queue */ 292562306a36Sopenharmony_ci/* */ 292662306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 292762306a36Sopenharmony_ci/* */ 292862306a36Sopenharmony_ci/****************************************************************************/ 292962306a36Sopenharmony_cistatic struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_entry_t *queue, 293062306a36Sopenharmony_ci struct scsi_cmnd *item) 293162306a36Sopenharmony_ci{ 293262306a36Sopenharmony_ci struct scsi_cmnd *p; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci METHOD_TRACE("ips_removeq_wait", 1); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci if (!item) 293762306a36Sopenharmony_ci return (NULL); 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ci if (item == queue->head) { 294062306a36Sopenharmony_ci return (ips_removeq_wait_head(queue)); 294162306a36Sopenharmony_ci } 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci p = queue->head; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci while ((p) && (item != (struct scsi_cmnd *) p->host_scribble)) 294662306a36Sopenharmony_ci p = (struct scsi_cmnd *) p->host_scribble; 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci if (p) { 294962306a36Sopenharmony_ci /* found a match */ 295062306a36Sopenharmony_ci p->host_scribble = item->host_scribble; 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci if (!item->host_scribble) 295362306a36Sopenharmony_ci queue->tail = p; 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci item->host_scribble = NULL; 295662306a36Sopenharmony_ci queue->count--; 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci return (item); 295962306a36Sopenharmony_ci } 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci return (NULL); 296262306a36Sopenharmony_ci} 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci/****************************************************************************/ 296562306a36Sopenharmony_ci/* */ 296662306a36Sopenharmony_ci/* Routine Name: ips_putq_copp_tail */ 296762306a36Sopenharmony_ci/* */ 296862306a36Sopenharmony_ci/* Routine Description: */ 296962306a36Sopenharmony_ci/* */ 297062306a36Sopenharmony_ci/* Add an item to the tail of the queue */ 297162306a36Sopenharmony_ci/* */ 297262306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 297362306a36Sopenharmony_ci/* */ 297462306a36Sopenharmony_ci/****************************************************************************/ 297562306a36Sopenharmony_cistatic void 297662306a36Sopenharmony_ciips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) 297762306a36Sopenharmony_ci{ 297862306a36Sopenharmony_ci METHOD_TRACE("ips_putq_copp_tail", 1); 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci if (!item) 298162306a36Sopenharmony_ci return; 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci item->next = NULL; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci if (queue->tail) 298662306a36Sopenharmony_ci queue->tail->next = item; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci queue->tail = item; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci if (!queue->head) 299162306a36Sopenharmony_ci queue->head = item; 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci queue->count++; 299462306a36Sopenharmony_ci} 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci/****************************************************************************/ 299762306a36Sopenharmony_ci/* */ 299862306a36Sopenharmony_ci/* Routine Name: ips_removeq_copp_head */ 299962306a36Sopenharmony_ci/* */ 300062306a36Sopenharmony_ci/* Routine Description: */ 300162306a36Sopenharmony_ci/* */ 300262306a36Sopenharmony_ci/* Remove the head of the queue */ 300362306a36Sopenharmony_ci/* */ 300462306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 300562306a36Sopenharmony_ci/* */ 300662306a36Sopenharmony_ci/****************************************************************************/ 300762306a36Sopenharmony_cistatic ips_copp_wait_item_t * 300862306a36Sopenharmony_ciips_removeq_copp_head(ips_copp_queue_t * queue) 300962306a36Sopenharmony_ci{ 301062306a36Sopenharmony_ci ips_copp_wait_item_t *item; 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci METHOD_TRACE("ips_removeq_copp_head", 1); 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci item = queue->head; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci if (!item) { 301762306a36Sopenharmony_ci return (NULL); 301862306a36Sopenharmony_ci } 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci queue->head = item->next; 302162306a36Sopenharmony_ci item->next = NULL; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (queue->tail == item) 302462306a36Sopenharmony_ci queue->tail = NULL; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci queue->count--; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci return (item); 302962306a36Sopenharmony_ci} 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci/****************************************************************************/ 303262306a36Sopenharmony_ci/* */ 303362306a36Sopenharmony_ci/* Routine Name: ips_removeq_copp */ 303462306a36Sopenharmony_ci/* */ 303562306a36Sopenharmony_ci/* Routine Description: */ 303662306a36Sopenharmony_ci/* */ 303762306a36Sopenharmony_ci/* Remove an item from a queue */ 303862306a36Sopenharmony_ci/* */ 303962306a36Sopenharmony_ci/* ASSUMED to be called from within the HA lock */ 304062306a36Sopenharmony_ci/* */ 304162306a36Sopenharmony_ci/****************************************************************************/ 304262306a36Sopenharmony_cistatic ips_copp_wait_item_t * 304362306a36Sopenharmony_ciips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) 304462306a36Sopenharmony_ci{ 304562306a36Sopenharmony_ci ips_copp_wait_item_t *p; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci METHOD_TRACE("ips_removeq_copp", 1); 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci if (!item) 305062306a36Sopenharmony_ci return (NULL); 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci if (item == queue->head) { 305362306a36Sopenharmony_ci return (ips_removeq_copp_head(queue)); 305462306a36Sopenharmony_ci } 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci p = queue->head; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci while ((p) && (item != p->next)) 305962306a36Sopenharmony_ci p = p->next; 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci if (p) { 306262306a36Sopenharmony_ci /* found a match */ 306362306a36Sopenharmony_ci p->next = item->next; 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci if (!item->next) 306662306a36Sopenharmony_ci queue->tail = p; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci item->next = NULL; 306962306a36Sopenharmony_ci queue->count--; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci return (item); 307262306a36Sopenharmony_ci } 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci return (NULL); 307562306a36Sopenharmony_ci} 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci/****************************************************************************/ 307862306a36Sopenharmony_ci/* */ 307962306a36Sopenharmony_ci/* Routine Name: ipsintr_blocking */ 308062306a36Sopenharmony_ci/* */ 308162306a36Sopenharmony_ci/* Routine Description: */ 308262306a36Sopenharmony_ci/* */ 308362306a36Sopenharmony_ci/* Finalize an interrupt for internal commands */ 308462306a36Sopenharmony_ci/* */ 308562306a36Sopenharmony_ci/****************************************************************************/ 308662306a36Sopenharmony_cistatic void 308762306a36Sopenharmony_ciipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb) 308862306a36Sopenharmony_ci{ 308962306a36Sopenharmony_ci METHOD_TRACE("ipsintr_blocking", 2); 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci ips_freescb(ha, scb); 309262306a36Sopenharmony_ci if (ha->waitflag && ha->cmd_in_progress == scb->cdb[0]) { 309362306a36Sopenharmony_ci ha->waitflag = false; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci return; 309662306a36Sopenharmony_ci } 309762306a36Sopenharmony_ci} 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci/****************************************************************************/ 310062306a36Sopenharmony_ci/* */ 310162306a36Sopenharmony_ci/* Routine Name: ipsintr_done */ 310262306a36Sopenharmony_ci/* */ 310362306a36Sopenharmony_ci/* Routine Description: */ 310462306a36Sopenharmony_ci/* */ 310562306a36Sopenharmony_ci/* Finalize an interrupt for non-internal commands */ 310662306a36Sopenharmony_ci/* */ 310762306a36Sopenharmony_ci/****************************************************************************/ 310862306a36Sopenharmony_cistatic void 310962306a36Sopenharmony_ciipsintr_done(ips_ha_t * ha, ips_scb_t * scb) 311062306a36Sopenharmony_ci{ 311162306a36Sopenharmony_ci METHOD_TRACE("ipsintr_done", 2); 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci if (!scb) { 311462306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 311562306a36Sopenharmony_ci "Spurious interrupt; scb NULL.\n"); 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci return; 311862306a36Sopenharmony_ci } 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci if (scb->scsi_cmd == NULL) { 312162306a36Sopenharmony_ci /* unexpected interrupt */ 312262306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 312362306a36Sopenharmony_ci "Spurious interrupt; scsi_cmd not set.\n"); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci return; 312662306a36Sopenharmony_ci } 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci ips_done(ha, scb); 312962306a36Sopenharmony_ci} 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci/****************************************************************************/ 313262306a36Sopenharmony_ci/* */ 313362306a36Sopenharmony_ci/* Routine Name: ips_done */ 313462306a36Sopenharmony_ci/* */ 313562306a36Sopenharmony_ci/* Routine Description: */ 313662306a36Sopenharmony_ci/* */ 313762306a36Sopenharmony_ci/* Do housekeeping on completed commands */ 313862306a36Sopenharmony_ci/* ASSUMED to be called form within the request lock */ 313962306a36Sopenharmony_ci/****************************************************************************/ 314062306a36Sopenharmony_cistatic void 314162306a36Sopenharmony_ciips_done(ips_ha_t * ha, ips_scb_t * scb) 314262306a36Sopenharmony_ci{ 314362306a36Sopenharmony_ci int ret; 314462306a36Sopenharmony_ci 314562306a36Sopenharmony_ci METHOD_TRACE("ips_done", 1); 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci if (!scb) 314862306a36Sopenharmony_ci return; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) { 315162306a36Sopenharmony_ci ips_cleanup_passthru(ha, scb); 315262306a36Sopenharmony_ci ha->num_ioctl--; 315362306a36Sopenharmony_ci } else { 315462306a36Sopenharmony_ci /* 315562306a36Sopenharmony_ci * Check to see if this command had too much 315662306a36Sopenharmony_ci * data and had to be broke up. If so, queue 315762306a36Sopenharmony_ci * the rest of the data and continue. 315862306a36Sopenharmony_ci */ 315962306a36Sopenharmony_ci if ((scb->breakup) || (scb->sg_break)) { 316062306a36Sopenharmony_ci struct scatterlist *sg; 316162306a36Sopenharmony_ci int i, sg_dma_index, ips_sg_index = 0; 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci /* we had a data breakup */ 316462306a36Sopenharmony_ci scb->data_len = 0; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci sg = scsi_sglist(scb->scsi_cmd); 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci /* Spin forward to last dma chunk */ 316962306a36Sopenharmony_ci sg_dma_index = scb->breakup; 317062306a36Sopenharmony_ci for (i = 0; i < scb->breakup; i++) 317162306a36Sopenharmony_ci sg = sg_next(sg); 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci /* Take care of possible partial on last chunk */ 317462306a36Sopenharmony_ci ips_fill_scb_sg_single(ha, 317562306a36Sopenharmony_ci sg_dma_address(sg), 317662306a36Sopenharmony_ci scb, ips_sg_index++, 317762306a36Sopenharmony_ci sg_dma_len(sg)); 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd); 318062306a36Sopenharmony_ci sg_dma_index++, sg = sg_next(sg)) { 318162306a36Sopenharmony_ci if (ips_fill_scb_sg_single 318262306a36Sopenharmony_ci (ha, 318362306a36Sopenharmony_ci sg_dma_address(sg), 318462306a36Sopenharmony_ci scb, ips_sg_index++, 318562306a36Sopenharmony_ci sg_dma_len(sg)) < 0) 318662306a36Sopenharmony_ci break; 318762306a36Sopenharmony_ci } 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci scb->dcdb.transfer_length = scb->data_len; 319062306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= 319162306a36Sopenharmony_ci ips_command_direction[scb->scsi_cmd->cmnd[0]]; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci if (!(scb->dcdb.cmd_attribute & 0x3)) 319462306a36Sopenharmony_ci scb->dcdb.transfer_length = 0; 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci if (scb->data_len >= IPS_MAX_XFER) { 319762306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; 319862306a36Sopenharmony_ci scb->dcdb.transfer_length = 0; 319962306a36Sopenharmony_ci } 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci ret = ips_send_cmd(ha, scb); 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci switch (ret) { 320462306a36Sopenharmony_ci case IPS_FAILURE: 320562306a36Sopenharmony_ci if (scb->scsi_cmd) { 320662306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 320762306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci ips_freescb(ha, scb); 321162306a36Sopenharmony_ci break; 321262306a36Sopenharmony_ci case IPS_SUCCESS_IMM: 321362306a36Sopenharmony_ci if (scb->scsi_cmd) { 321462306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 321562306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 321662306a36Sopenharmony_ci } 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci ips_freescb(ha, scb); 321962306a36Sopenharmony_ci break; 322062306a36Sopenharmony_ci default: 322162306a36Sopenharmony_ci break; 322262306a36Sopenharmony_ci } /* end case */ 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci return; 322562306a36Sopenharmony_ci } 322662306a36Sopenharmony_ci } /* end if passthru */ 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci if (scb->bus) { 322962306a36Sopenharmony_ci ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id); 323062306a36Sopenharmony_ci } 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_ci scsi_done(scb->scsi_cmd); 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci ips_freescb(ha, scb); 323562306a36Sopenharmony_ci} 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci/****************************************************************************/ 323862306a36Sopenharmony_ci/* */ 323962306a36Sopenharmony_ci/* Routine Name: ips_map_status */ 324062306a36Sopenharmony_ci/* */ 324162306a36Sopenharmony_ci/* Routine Description: */ 324262306a36Sopenharmony_ci/* */ 324362306a36Sopenharmony_ci/* Map Controller Error codes to Linux Error Codes */ 324462306a36Sopenharmony_ci/* */ 324562306a36Sopenharmony_ci/****************************************************************************/ 324662306a36Sopenharmony_cistatic int 324762306a36Sopenharmony_ciips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) 324862306a36Sopenharmony_ci{ 324962306a36Sopenharmony_ci int errcode; 325062306a36Sopenharmony_ci int device_error; 325162306a36Sopenharmony_ci uint32_t transfer_len; 325262306a36Sopenharmony_ci IPS_DCDB_TABLE_TAPE *tapeDCDB; 325362306a36Sopenharmony_ci IPS_SCSI_INQ_DATA inquiryData; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci METHOD_TRACE("ips_map_status", 1); 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci if (scb->bus) { 325862306a36Sopenharmony_ci DEBUG_VAR(2, 325962306a36Sopenharmony_ci "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x", 326062306a36Sopenharmony_ci ips_name, ha->host_num, 326162306a36Sopenharmony_ci scb->scsi_cmd->device->channel, 326262306a36Sopenharmony_ci scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun, 326362306a36Sopenharmony_ci scb->basic_status, scb->extended_status, 326462306a36Sopenharmony_ci scb->extended_status == 326562306a36Sopenharmony_ci IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0, 326662306a36Sopenharmony_ci scb->extended_status == 326762306a36Sopenharmony_ci IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0, 326862306a36Sopenharmony_ci scb->extended_status == 326962306a36Sopenharmony_ci IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0); 327062306a36Sopenharmony_ci } 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci /* default driver error */ 327362306a36Sopenharmony_ci errcode = DID_ERROR; 327462306a36Sopenharmony_ci device_error = 0; 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci switch (scb->basic_status & IPS_GSC_STATUS_MASK) { 327762306a36Sopenharmony_ci case IPS_CMD_TIMEOUT: 327862306a36Sopenharmony_ci errcode = DID_TIME_OUT; 327962306a36Sopenharmony_ci break; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci case IPS_INVAL_OPCO: 328262306a36Sopenharmony_ci case IPS_INVAL_CMD_BLK: 328362306a36Sopenharmony_ci case IPS_INVAL_PARM_BLK: 328462306a36Sopenharmony_ci case IPS_LD_ERROR: 328562306a36Sopenharmony_ci case IPS_CMD_CMPLT_WERROR: 328662306a36Sopenharmony_ci break; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci case IPS_PHYS_DRV_ERROR: 328962306a36Sopenharmony_ci switch (scb->extended_status) { 329062306a36Sopenharmony_ci case IPS_ERR_SEL_TO: 329162306a36Sopenharmony_ci if (scb->bus) 329262306a36Sopenharmony_ci errcode = DID_NO_CONNECT; 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci break; 329562306a36Sopenharmony_ci 329662306a36Sopenharmony_ci case IPS_ERR_OU_RUN: 329762306a36Sopenharmony_ci if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) || 329862306a36Sopenharmony_ci (scb->cmd.dcdb.op_code == 329962306a36Sopenharmony_ci IPS_CMD_EXTENDED_DCDB_SG)) { 330062306a36Sopenharmony_ci tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; 330162306a36Sopenharmony_ci transfer_len = tapeDCDB->transfer_length; 330262306a36Sopenharmony_ci } else { 330362306a36Sopenharmony_ci transfer_len = 330462306a36Sopenharmony_ci (uint32_t) scb->dcdb.transfer_length; 330562306a36Sopenharmony_ci } 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci if ((scb->bus) && (transfer_len < scb->data_len)) { 330862306a36Sopenharmony_ci /* Underrun - set default to no error */ 330962306a36Sopenharmony_ci errcode = DID_OK; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci /* Restrict access to physical DASD */ 331262306a36Sopenharmony_ci if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 331362306a36Sopenharmony_ci ips_scmd_buf_read(scb->scsi_cmd, 331462306a36Sopenharmony_ci &inquiryData, sizeof (inquiryData)); 331562306a36Sopenharmony_ci if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) { 331662306a36Sopenharmony_ci errcode = DID_TIME_OUT; 331762306a36Sopenharmony_ci break; 331862306a36Sopenharmony_ci } 331962306a36Sopenharmony_ci } 332062306a36Sopenharmony_ci } else 332162306a36Sopenharmony_ci errcode = DID_ERROR; 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci break; 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci case IPS_ERR_RECOVERY: 332662306a36Sopenharmony_ci /* don't fail recovered errors */ 332762306a36Sopenharmony_ci if (scb->bus) 332862306a36Sopenharmony_ci errcode = DID_OK; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci break; 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_ci case IPS_ERR_HOST_RESET: 333362306a36Sopenharmony_ci case IPS_ERR_DEV_RESET: 333462306a36Sopenharmony_ci errcode = DID_RESET; 333562306a36Sopenharmony_ci break; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci case IPS_ERR_CKCOND: 333862306a36Sopenharmony_ci if (scb->bus) { 333962306a36Sopenharmony_ci if ((scb->cmd.dcdb.op_code == 334062306a36Sopenharmony_ci IPS_CMD_EXTENDED_DCDB) 334162306a36Sopenharmony_ci || (scb->cmd.dcdb.op_code == 334262306a36Sopenharmony_ci IPS_CMD_EXTENDED_DCDB_SG)) { 334362306a36Sopenharmony_ci tapeDCDB = 334462306a36Sopenharmony_ci (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; 334562306a36Sopenharmony_ci memcpy_and_pad(scb->scsi_cmd->sense_buffer, 334662306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 334762306a36Sopenharmony_ci tapeDCDB->sense_info, 334862306a36Sopenharmony_ci sizeof(tapeDCDB->sense_info), 0); 334962306a36Sopenharmony_ci } else { 335062306a36Sopenharmony_ci memcpy_and_pad(scb->scsi_cmd->sense_buffer, 335162306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 335262306a36Sopenharmony_ci scb->dcdb.sense_info, 335362306a36Sopenharmony_ci sizeof(scb->dcdb.sense_info), 0); 335462306a36Sopenharmony_ci } 335562306a36Sopenharmony_ci device_error = 2; /* check condition */ 335662306a36Sopenharmony_ci } 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci errcode = DID_OK; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci break; 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci default: 336362306a36Sopenharmony_ci errcode = DID_ERROR; 336462306a36Sopenharmony_ci break; 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci } /* end switch */ 336762306a36Sopenharmony_ci } /* end switch */ 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci scb->scsi_cmd->result = device_error | (errcode << 16); 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci return (1); 337262306a36Sopenharmony_ci} 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci/****************************************************************************/ 337562306a36Sopenharmony_ci/* */ 337662306a36Sopenharmony_ci/* Routine Name: ips_send_wait */ 337762306a36Sopenharmony_ci/* */ 337862306a36Sopenharmony_ci/* Routine Description: */ 337962306a36Sopenharmony_ci/* */ 338062306a36Sopenharmony_ci/* Send a command to the controller and wait for it to return */ 338162306a36Sopenharmony_ci/* */ 338262306a36Sopenharmony_ci/* The FFDC Time Stamp use this function for the callback, but doesn't */ 338362306a36Sopenharmony_ci/* actually need to wait. */ 338462306a36Sopenharmony_ci/****************************************************************************/ 338562306a36Sopenharmony_cistatic int 338662306a36Sopenharmony_ciips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) 338762306a36Sopenharmony_ci{ 338862306a36Sopenharmony_ci int ret; 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci METHOD_TRACE("ips_send_wait", 1); 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci if (intr != IPS_FFDC) { /* Won't be Waiting if this is a Time Stamp */ 339362306a36Sopenharmony_ci ha->waitflag = true; 339462306a36Sopenharmony_ci ha->cmd_in_progress = scb->cdb[0]; 339562306a36Sopenharmony_ci } 339662306a36Sopenharmony_ci scb->callback = ipsintr_blocking; 339762306a36Sopenharmony_ci ret = ips_send_cmd(ha, scb); 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) 340062306a36Sopenharmony_ci return (ret); 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci if (intr != IPS_FFDC) /* Don't Wait around if this is a Time Stamp */ 340362306a36Sopenharmony_ci ret = ips_wait(ha, timeout, intr); 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci return (ret); 340662306a36Sopenharmony_ci} 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci/****************************************************************************/ 340962306a36Sopenharmony_ci/* */ 341062306a36Sopenharmony_ci/* Routine Name: ips_scmd_buf_write */ 341162306a36Sopenharmony_ci/* */ 341262306a36Sopenharmony_ci/* Routine Description: */ 341362306a36Sopenharmony_ci/* Write data to struct scsi_cmnd request_buffer at proper offsets */ 341462306a36Sopenharmony_ci/****************************************************************************/ 341562306a36Sopenharmony_cistatic void 341662306a36Sopenharmony_ciips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) 341762306a36Sopenharmony_ci{ 341862306a36Sopenharmony_ci unsigned long flags; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci local_irq_save(flags); 342162306a36Sopenharmony_ci scsi_sg_copy_from_buffer(scmd, data, count); 342262306a36Sopenharmony_ci local_irq_restore(flags); 342362306a36Sopenharmony_ci} 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci/****************************************************************************/ 342662306a36Sopenharmony_ci/* */ 342762306a36Sopenharmony_ci/* Routine Name: ips_scmd_buf_read */ 342862306a36Sopenharmony_ci/* */ 342962306a36Sopenharmony_ci/* Routine Description: */ 343062306a36Sopenharmony_ci/* Copy data from a struct scsi_cmnd to a new, linear buffer */ 343162306a36Sopenharmony_ci/****************************************************************************/ 343262306a36Sopenharmony_cistatic void 343362306a36Sopenharmony_ciips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count) 343462306a36Sopenharmony_ci{ 343562306a36Sopenharmony_ci unsigned long flags; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci local_irq_save(flags); 343862306a36Sopenharmony_ci scsi_sg_copy_to_buffer(scmd, data, count); 343962306a36Sopenharmony_ci local_irq_restore(flags); 344062306a36Sopenharmony_ci} 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci/****************************************************************************/ 344362306a36Sopenharmony_ci/* */ 344462306a36Sopenharmony_ci/* Routine Name: ips_send_cmd */ 344562306a36Sopenharmony_ci/* */ 344662306a36Sopenharmony_ci/* Routine Description: */ 344762306a36Sopenharmony_ci/* */ 344862306a36Sopenharmony_ci/* Map SCSI commands to ServeRAID commands for logical drives */ 344962306a36Sopenharmony_ci/* */ 345062306a36Sopenharmony_ci/****************************************************************************/ 345162306a36Sopenharmony_cistatic int 345262306a36Sopenharmony_ciips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) 345362306a36Sopenharmony_ci{ 345462306a36Sopenharmony_ci int ret; 345562306a36Sopenharmony_ci char *sp; 345662306a36Sopenharmony_ci int device_error; 345762306a36Sopenharmony_ci IPS_DCDB_TABLE_TAPE *tapeDCDB; 345862306a36Sopenharmony_ci int TimeOut; 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci METHOD_TRACE("ips_send_cmd", 1); 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci ret = IPS_SUCCESS; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci if (!scb->scsi_cmd) { 346562306a36Sopenharmony_ci /* internal command */ 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci if (scb->bus > 0) { 346862306a36Sopenharmony_ci /* Controller commands can't be issued */ 346962306a36Sopenharmony_ci /* to real devices -- fail them */ 347062306a36Sopenharmony_ci if (ha->waitflag && ha->cmd_in_progress == scb->cdb[0]) 347162306a36Sopenharmony_ci ha->waitflag = false; 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_ci return (1); 347462306a36Sopenharmony_ci } 347562306a36Sopenharmony_ci } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) { 347662306a36Sopenharmony_ci /* command to logical bus -- interpret */ 347762306a36Sopenharmony_ci ret = IPS_SUCCESS_IMM; 347862306a36Sopenharmony_ci 347962306a36Sopenharmony_ci switch (scb->scsi_cmd->cmnd[0]) { 348062306a36Sopenharmony_ci case ALLOW_MEDIUM_REMOVAL: 348162306a36Sopenharmony_ci case REZERO_UNIT: 348262306a36Sopenharmony_ci case ERASE: 348362306a36Sopenharmony_ci case WRITE_FILEMARKS: 348462306a36Sopenharmony_ci case SPACE: 348562306a36Sopenharmony_ci scb->scsi_cmd->result = DID_ERROR << 16; 348662306a36Sopenharmony_ci break; 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci case START_STOP: 348962306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 349062306a36Sopenharmony_ci break; 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ci case TEST_UNIT_READY: 349362306a36Sopenharmony_ci case INQUIRY: 349462306a36Sopenharmony_ci if (scb->target_id == IPS_ADAPTER_ID) { 349562306a36Sopenharmony_ci /* 349662306a36Sopenharmony_ci * Either we have a TUR 349762306a36Sopenharmony_ci * or we have a SCSI inquiry 349862306a36Sopenharmony_ci */ 349962306a36Sopenharmony_ci if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY) 350062306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 350362306a36Sopenharmony_ci IPS_SCSI_INQ_DATA inquiry; 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci memset(&inquiry, 0, 350662306a36Sopenharmony_ci sizeof (IPS_SCSI_INQ_DATA)); 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci inquiry.DeviceType = 350962306a36Sopenharmony_ci IPS_SCSI_INQ_TYPE_PROCESSOR; 351062306a36Sopenharmony_ci inquiry.DeviceTypeQualifier = 351162306a36Sopenharmony_ci IPS_SCSI_INQ_LU_CONNECTED; 351262306a36Sopenharmony_ci inquiry.Version = IPS_SCSI_INQ_REV2; 351362306a36Sopenharmony_ci inquiry.ResponseDataFormat = 351462306a36Sopenharmony_ci IPS_SCSI_INQ_RD_REV2; 351562306a36Sopenharmony_ci inquiry.AdditionalLength = 31; 351662306a36Sopenharmony_ci inquiry.Flags[0] = 351762306a36Sopenharmony_ci IPS_SCSI_INQ_Address16; 351862306a36Sopenharmony_ci inquiry.Flags[1] = 351962306a36Sopenharmony_ci IPS_SCSI_INQ_WBus16 | 352062306a36Sopenharmony_ci IPS_SCSI_INQ_Sync; 352162306a36Sopenharmony_ci memcpy(inquiry.VendorId, "IBM ", 352262306a36Sopenharmony_ci 8); 352362306a36Sopenharmony_ci memcpy(inquiry.ProductId, 352462306a36Sopenharmony_ci "SERVERAID ", 16); 352562306a36Sopenharmony_ci memcpy(inquiry.ProductRevisionLevel, 352662306a36Sopenharmony_ci "1.00", 4); 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci ips_scmd_buf_write(scb->scsi_cmd, 352962306a36Sopenharmony_ci &inquiry, 353062306a36Sopenharmony_ci sizeof (inquiry)); 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 353362306a36Sopenharmony_ci } 353462306a36Sopenharmony_ci } else { 353562306a36Sopenharmony_ci scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; 353662306a36Sopenharmony_ci scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); 353762306a36Sopenharmony_ci scb->cmd.logical_info.reserved = 0; 353862306a36Sopenharmony_ci scb->cmd.logical_info.reserved2 = 0; 353962306a36Sopenharmony_ci scb->data_len = sizeof (IPS_LD_INFO); 354062306a36Sopenharmony_ci scb->data_busaddr = ha->logical_drive_info_dma_addr; 354162306a36Sopenharmony_ci scb->flags = 0; 354262306a36Sopenharmony_ci scb->cmd.logical_info.buffer_addr = scb->data_busaddr; 354362306a36Sopenharmony_ci ret = IPS_SUCCESS; 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci break; 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci case REQUEST_SENSE: 354962306a36Sopenharmony_ci ips_reqsen(ha, scb); 355062306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 355162306a36Sopenharmony_ci break; 355262306a36Sopenharmony_ci 355362306a36Sopenharmony_ci case READ_6: 355462306a36Sopenharmony_ci case WRITE_6: 355562306a36Sopenharmony_ci if (!scb->sg_len) { 355662306a36Sopenharmony_ci scb->cmd.basic_io.op_code = 355762306a36Sopenharmony_ci (scb->scsi_cmd->cmnd[0] == 355862306a36Sopenharmony_ci READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE; 355962306a36Sopenharmony_ci scb->cmd.basic_io.enhanced_sg = 0; 356062306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = 356162306a36Sopenharmony_ci cpu_to_le32(scb->data_busaddr); 356262306a36Sopenharmony_ci } else { 356362306a36Sopenharmony_ci scb->cmd.basic_io.op_code = 356462306a36Sopenharmony_ci (scb->scsi_cmd->cmnd[0] == 356562306a36Sopenharmony_ci READ_6) ? IPS_CMD_READ_SG : 356662306a36Sopenharmony_ci IPS_CMD_WRITE_SG; 356762306a36Sopenharmony_ci scb->cmd.basic_io.enhanced_sg = 356862306a36Sopenharmony_ci IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 356962306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = 357062306a36Sopenharmony_ci cpu_to_le32(scb->sg_busaddr); 357162306a36Sopenharmony_ci } 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci scb->cmd.basic_io.segment_4G = 0; 357462306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 357562306a36Sopenharmony_ci scb->cmd.basic_io.log_drv = scb->target_id; 357662306a36Sopenharmony_ci scb->cmd.basic_io.sg_count = scb->sg_len; 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci if (scb->cmd.basic_io.lba) 357962306a36Sopenharmony_ci le32_add_cpu(&scb->cmd.basic_io.lba, 358062306a36Sopenharmony_ci le16_to_cpu(scb->cmd.basic_io. 358162306a36Sopenharmony_ci sector_count)); 358262306a36Sopenharmony_ci else 358362306a36Sopenharmony_ci scb->cmd.basic_io.lba = 358462306a36Sopenharmony_ci (((scb->scsi_cmd-> 358562306a36Sopenharmony_ci cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd-> 358662306a36Sopenharmony_ci cmnd[2] << 8) | 358762306a36Sopenharmony_ci (scb->scsi_cmd->cmnd[3])); 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci scb->cmd.basic_io.sector_count = 359062306a36Sopenharmony_ci cpu_to_le16(scb->data_len / IPS_BLKSIZE); 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0) 359362306a36Sopenharmony_ci scb->cmd.basic_io.sector_count = 359462306a36Sopenharmony_ci cpu_to_le16(256); 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci ret = IPS_SUCCESS; 359762306a36Sopenharmony_ci break; 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_ci case READ_10: 360062306a36Sopenharmony_ci case WRITE_10: 360162306a36Sopenharmony_ci if (!scb->sg_len) { 360262306a36Sopenharmony_ci scb->cmd.basic_io.op_code = 360362306a36Sopenharmony_ci (scb->scsi_cmd->cmnd[0] == 360462306a36Sopenharmony_ci READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE; 360562306a36Sopenharmony_ci scb->cmd.basic_io.enhanced_sg = 0; 360662306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = 360762306a36Sopenharmony_ci cpu_to_le32(scb->data_busaddr); 360862306a36Sopenharmony_ci } else { 360962306a36Sopenharmony_ci scb->cmd.basic_io.op_code = 361062306a36Sopenharmony_ci (scb->scsi_cmd->cmnd[0] == 361162306a36Sopenharmony_ci READ_10) ? IPS_CMD_READ_SG : 361262306a36Sopenharmony_ci IPS_CMD_WRITE_SG; 361362306a36Sopenharmony_ci scb->cmd.basic_io.enhanced_sg = 361462306a36Sopenharmony_ci IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 361562306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = 361662306a36Sopenharmony_ci cpu_to_le32(scb->sg_busaddr); 361762306a36Sopenharmony_ci } 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci scb->cmd.basic_io.segment_4G = 0; 362062306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 362162306a36Sopenharmony_ci scb->cmd.basic_io.log_drv = scb->target_id; 362262306a36Sopenharmony_ci scb->cmd.basic_io.sg_count = scb->sg_len; 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci if (scb->cmd.basic_io.lba) 362562306a36Sopenharmony_ci le32_add_cpu(&scb->cmd.basic_io.lba, 362662306a36Sopenharmony_ci le16_to_cpu(scb->cmd.basic_io. 362762306a36Sopenharmony_ci sector_count)); 362862306a36Sopenharmony_ci else 362962306a36Sopenharmony_ci scb->cmd.basic_io.lba = 363062306a36Sopenharmony_ci ((scb->scsi_cmd->cmnd[2] << 24) | (scb-> 363162306a36Sopenharmony_ci scsi_cmd-> 363262306a36Sopenharmony_ci cmnd[3] 363362306a36Sopenharmony_ci << 16) | 363462306a36Sopenharmony_ci (scb->scsi_cmd->cmnd[4] << 8) | scb-> 363562306a36Sopenharmony_ci scsi_cmd->cmnd[5]); 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci scb->cmd.basic_io.sector_count = 363862306a36Sopenharmony_ci cpu_to_le16(scb->data_len / IPS_BLKSIZE); 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) { 364162306a36Sopenharmony_ci /* 364262306a36Sopenharmony_ci * This is a null condition 364362306a36Sopenharmony_ci * we don't have to do anything 364462306a36Sopenharmony_ci * so just return 364562306a36Sopenharmony_ci */ 364662306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 364762306a36Sopenharmony_ci } else 364862306a36Sopenharmony_ci ret = IPS_SUCCESS; 364962306a36Sopenharmony_ci 365062306a36Sopenharmony_ci break; 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci case RESERVE: 365362306a36Sopenharmony_ci case RELEASE: 365462306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 365562306a36Sopenharmony_ci break; 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci case MODE_SENSE: 365862306a36Sopenharmony_ci scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; 365962306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 366062306a36Sopenharmony_ci scb->cmd.basic_io.segment_4G = 0; 366162306a36Sopenharmony_ci scb->cmd.basic_io.enhanced_sg = 0; 366262306a36Sopenharmony_ci scb->data_len = sizeof (*ha->enq); 366362306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = ha->enq_busaddr; 366462306a36Sopenharmony_ci ret = IPS_SUCCESS; 366562306a36Sopenharmony_ci break; 366662306a36Sopenharmony_ci 366762306a36Sopenharmony_ci case READ_CAPACITY: 366862306a36Sopenharmony_ci scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; 366962306a36Sopenharmony_ci scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); 367062306a36Sopenharmony_ci scb->cmd.logical_info.reserved = 0; 367162306a36Sopenharmony_ci scb->cmd.logical_info.reserved2 = 0; 367262306a36Sopenharmony_ci scb->cmd.logical_info.reserved3 = 0; 367362306a36Sopenharmony_ci scb->data_len = sizeof (IPS_LD_INFO); 367462306a36Sopenharmony_ci scb->data_busaddr = ha->logical_drive_info_dma_addr; 367562306a36Sopenharmony_ci scb->flags = 0; 367662306a36Sopenharmony_ci scb->cmd.logical_info.buffer_addr = scb->data_busaddr; 367762306a36Sopenharmony_ci ret = IPS_SUCCESS; 367862306a36Sopenharmony_ci break; 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci case SEND_DIAGNOSTIC: 368162306a36Sopenharmony_ci case REASSIGN_BLOCKS: 368262306a36Sopenharmony_ci case FORMAT_UNIT: 368362306a36Sopenharmony_ci case SEEK_10: 368462306a36Sopenharmony_ci case VERIFY: 368562306a36Sopenharmony_ci case READ_DEFECT_DATA: 368662306a36Sopenharmony_ci case READ_BUFFER: 368762306a36Sopenharmony_ci case WRITE_BUFFER: 368862306a36Sopenharmony_ci scb->scsi_cmd->result = DID_OK << 16; 368962306a36Sopenharmony_ci break; 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci default: 369262306a36Sopenharmony_ci /* Set the Return Info to appear like the Command was */ 369362306a36Sopenharmony_ci /* attempted, a Check Condition occurred, and Sense */ 369462306a36Sopenharmony_ci /* Data indicating an Invalid CDB OpCode is returned. */ 369562306a36Sopenharmony_ci sp = (char *) scb->scsi_cmd->sense_buffer; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci sp[0] = 0x70; /* Error Code */ 369862306a36Sopenharmony_ci sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */ 369962306a36Sopenharmony_ci sp[7] = 0x0A; /* Additional Sense Length */ 370062306a36Sopenharmony_ci sp[12] = 0x20; /* ASC = Invalid OpCode */ 370162306a36Sopenharmony_ci sp[13] = 0x00; /* ASCQ */ 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci device_error = 2; /* Indicate Check Condition */ 370462306a36Sopenharmony_ci scb->scsi_cmd->result = device_error | (DID_OK << 16); 370562306a36Sopenharmony_ci break; 370662306a36Sopenharmony_ci } /* end switch */ 370762306a36Sopenharmony_ci } 370862306a36Sopenharmony_ci /* end if */ 370962306a36Sopenharmony_ci if (ret == IPS_SUCCESS_IMM) 371062306a36Sopenharmony_ci return (ret); 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci /* setup DCDB */ 371362306a36Sopenharmony_ci if (scb->bus > 0) { 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci /* If we already know the Device is Not there, no need to attempt a Command */ 371662306a36Sopenharmony_ci /* This also protects an NT FailOver Controller from getting CDB's sent to it */ 371762306a36Sopenharmony_ci if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) { 371862306a36Sopenharmony_ci scb->scsi_cmd->result = DID_NO_CONNECT << 16; 371962306a36Sopenharmony_ci return (IPS_SUCCESS_IMM); 372062306a36Sopenharmony_ci } 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id); 372362306a36Sopenharmony_ci scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); 372462306a36Sopenharmony_ci scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + 372562306a36Sopenharmony_ci (unsigned long) &scb-> 372662306a36Sopenharmony_ci dcdb - 372762306a36Sopenharmony_ci (unsigned long) scb); 372862306a36Sopenharmony_ci scb->cmd.dcdb.reserved = 0; 372962306a36Sopenharmony_ci scb->cmd.dcdb.reserved2 = 0; 373062306a36Sopenharmony_ci scb->cmd.dcdb.reserved3 = 0; 373162306a36Sopenharmony_ci scb->cmd.dcdb.segment_4G = 0; 373262306a36Sopenharmony_ci scb->cmd.dcdb.enhanced_sg = 0; 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci TimeOut = scsi_cmd_to_rq(scb->scsi_cmd)->timeout; 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci if (ha->subsys->param[4] & 0x00100000) { /* If NEW Tape DCDB is Supported */ 373762306a36Sopenharmony_ci if (!scb->sg_len) { 373862306a36Sopenharmony_ci scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB; 373962306a36Sopenharmony_ci } else { 374062306a36Sopenharmony_ci scb->cmd.dcdb.op_code = 374162306a36Sopenharmony_ci IPS_CMD_EXTENDED_DCDB_SG; 374262306a36Sopenharmony_ci scb->cmd.dcdb.enhanced_sg = 374362306a36Sopenharmony_ci IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 374462306a36Sopenharmony_ci } 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_ci tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; /* Use Same Data Area as Old DCDB Struct */ 374762306a36Sopenharmony_ci tapeDCDB->device_address = 374862306a36Sopenharmony_ci ((scb->bus - 1) << 4) | scb->target_id; 374962306a36Sopenharmony_ci tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED; 375062306a36Sopenharmony_ci tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K; /* Always Turn OFF 64K Size Flag */ 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci if (TimeOut) { 375362306a36Sopenharmony_ci if (TimeOut < (10 * HZ)) 375462306a36Sopenharmony_ci tapeDCDB->cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */ 375562306a36Sopenharmony_ci else if (TimeOut < (60 * HZ)) 375662306a36Sopenharmony_ci tapeDCDB->cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */ 375762306a36Sopenharmony_ci else if (TimeOut < (1200 * HZ)) 375862306a36Sopenharmony_ci tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */ 375962306a36Sopenharmony_ci } 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len; 376262306a36Sopenharmony_ci tapeDCDB->reserved_for_LUN = 0; 376362306a36Sopenharmony_ci tapeDCDB->transfer_length = scb->data_len; 376462306a36Sopenharmony_ci if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG) 376562306a36Sopenharmony_ci tapeDCDB->buffer_pointer = 376662306a36Sopenharmony_ci cpu_to_le32(scb->sg_busaddr); 376762306a36Sopenharmony_ci else 376862306a36Sopenharmony_ci tapeDCDB->buffer_pointer = 376962306a36Sopenharmony_ci cpu_to_le32(scb->data_busaddr); 377062306a36Sopenharmony_ci tapeDCDB->sg_count = scb->sg_len; 377162306a36Sopenharmony_ci tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info); 377262306a36Sopenharmony_ci tapeDCDB->scsi_status = 0; 377362306a36Sopenharmony_ci tapeDCDB->reserved = 0; 377462306a36Sopenharmony_ci memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, 377562306a36Sopenharmony_ci scb->scsi_cmd->cmd_len); 377662306a36Sopenharmony_ci } else { 377762306a36Sopenharmony_ci if (!scb->sg_len) { 377862306a36Sopenharmony_ci scb->cmd.dcdb.op_code = IPS_CMD_DCDB; 377962306a36Sopenharmony_ci } else { 378062306a36Sopenharmony_ci scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG; 378162306a36Sopenharmony_ci scb->cmd.dcdb.enhanced_sg = 378262306a36Sopenharmony_ci IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; 378362306a36Sopenharmony_ci } 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_ci scb->dcdb.device_address = 378662306a36Sopenharmony_ci ((scb->bus - 1) << 4) | scb->target_id; 378762306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED; 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci if (TimeOut) { 379062306a36Sopenharmony_ci if (TimeOut < (10 * HZ)) 379162306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */ 379262306a36Sopenharmony_ci else if (TimeOut < (60 * HZ)) 379362306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */ 379462306a36Sopenharmony_ci else if (TimeOut < (1200 * HZ)) 379562306a36Sopenharmony_ci scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */ 379662306a36Sopenharmony_ci } 379762306a36Sopenharmony_ci 379862306a36Sopenharmony_ci scb->dcdb.transfer_length = scb->data_len; 379962306a36Sopenharmony_ci if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K) 380062306a36Sopenharmony_ci scb->dcdb.transfer_length = 0; 380162306a36Sopenharmony_ci if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG) 380262306a36Sopenharmony_ci scb->dcdb.buffer_pointer = 380362306a36Sopenharmony_ci cpu_to_le32(scb->sg_busaddr); 380462306a36Sopenharmony_ci else 380562306a36Sopenharmony_ci scb->dcdb.buffer_pointer = 380662306a36Sopenharmony_ci cpu_to_le32(scb->data_busaddr); 380762306a36Sopenharmony_ci scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len; 380862306a36Sopenharmony_ci scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info); 380962306a36Sopenharmony_ci scb->dcdb.sg_count = scb->sg_len; 381062306a36Sopenharmony_ci scb->dcdb.reserved = 0; 381162306a36Sopenharmony_ci memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, 381262306a36Sopenharmony_ci scb->scsi_cmd->cmd_len); 381362306a36Sopenharmony_ci scb->dcdb.scsi_status = 0; 381462306a36Sopenharmony_ci scb->dcdb.reserved2[0] = 0; 381562306a36Sopenharmony_ci scb->dcdb.reserved2[1] = 0; 381662306a36Sopenharmony_ci scb->dcdb.reserved2[2] = 0; 381762306a36Sopenharmony_ci } 381862306a36Sopenharmony_ci } 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ci return ((*ha->func.issue) (ha, scb)); 382162306a36Sopenharmony_ci} 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci/****************************************************************************/ 382462306a36Sopenharmony_ci/* */ 382562306a36Sopenharmony_ci/* Routine Name: ips_chk_status */ 382662306a36Sopenharmony_ci/* */ 382762306a36Sopenharmony_ci/* Routine Description: */ 382862306a36Sopenharmony_ci/* */ 382962306a36Sopenharmony_ci/* Check the status of commands to logical drives */ 383062306a36Sopenharmony_ci/* Assumed to be called with the HA lock */ 383162306a36Sopenharmony_ci/****************************************************************************/ 383262306a36Sopenharmony_cistatic void 383362306a36Sopenharmony_ciips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) 383462306a36Sopenharmony_ci{ 383562306a36Sopenharmony_ci ips_scb_t *scb; 383662306a36Sopenharmony_ci ips_stat_t *sp; 383762306a36Sopenharmony_ci uint8_t basic_status; 383862306a36Sopenharmony_ci uint8_t ext_status; 383962306a36Sopenharmony_ci int errcode; 384062306a36Sopenharmony_ci IPS_SCSI_INQ_DATA inquiryData; 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci METHOD_TRACE("ips_chkstatus", 1); 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci scb = &ha->scbs[pstatus->fields.command_id]; 384562306a36Sopenharmony_ci scb->basic_status = basic_status = 384662306a36Sopenharmony_ci pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK; 384762306a36Sopenharmony_ci scb->extended_status = ext_status = pstatus->fields.extended_status; 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_ci sp = &ha->sp; 385062306a36Sopenharmony_ci sp->residue_len = 0; 385162306a36Sopenharmony_ci sp->scb_addr = (void *) scb; 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci /* Remove the item from the active queue */ 385462306a36Sopenharmony_ci ips_removeq_scb(&ha->scb_activelist, scb); 385562306a36Sopenharmony_ci 385662306a36Sopenharmony_ci if (!scb->scsi_cmd) 385762306a36Sopenharmony_ci /* internal commands are handled in do_ipsintr */ 385862306a36Sopenharmony_ci return; 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)", 386162306a36Sopenharmony_ci ips_name, 386262306a36Sopenharmony_ci ha->host_num, 386362306a36Sopenharmony_ci scb->cdb[0], 386462306a36Sopenharmony_ci scb->cmd.basic_io.command_id, 386562306a36Sopenharmony_ci scb->bus, scb->target_id, scb->lun); 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) 386862306a36Sopenharmony_ci /* passthru - just returns the raw result */ 386962306a36Sopenharmony_ci return; 387062306a36Sopenharmony_ci 387162306a36Sopenharmony_ci errcode = DID_OK; 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) || 387462306a36Sopenharmony_ci ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) { 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci if (scb->bus == 0) { 387762306a36Sopenharmony_ci if ((basic_status & IPS_GSC_STATUS_MASK) == 387862306a36Sopenharmony_ci IPS_CMD_RECOVERED_ERROR) { 387962306a36Sopenharmony_ci DEBUG_VAR(1, 388062306a36Sopenharmony_ci "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", 388162306a36Sopenharmony_ci ips_name, ha->host_num, 388262306a36Sopenharmony_ci scb->cmd.basic_io.op_code, 388362306a36Sopenharmony_ci basic_status, ext_status); 388462306a36Sopenharmony_ci } 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci switch (scb->scsi_cmd->cmnd[0]) { 388762306a36Sopenharmony_ci case ALLOW_MEDIUM_REMOVAL: 388862306a36Sopenharmony_ci case REZERO_UNIT: 388962306a36Sopenharmony_ci case ERASE: 389062306a36Sopenharmony_ci case WRITE_FILEMARKS: 389162306a36Sopenharmony_ci case SPACE: 389262306a36Sopenharmony_ci errcode = DID_ERROR; 389362306a36Sopenharmony_ci break; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci case START_STOP: 389662306a36Sopenharmony_ci break; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci case TEST_UNIT_READY: 389962306a36Sopenharmony_ci if (!ips_online(ha, scb)) { 390062306a36Sopenharmony_ci errcode = DID_TIME_OUT; 390162306a36Sopenharmony_ci } 390262306a36Sopenharmony_ci break; 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_ci case INQUIRY: 390562306a36Sopenharmony_ci if (ips_online(ha, scb)) { 390662306a36Sopenharmony_ci ips_inquiry(ha, scb); 390762306a36Sopenharmony_ci } else { 390862306a36Sopenharmony_ci errcode = DID_TIME_OUT; 390962306a36Sopenharmony_ci } 391062306a36Sopenharmony_ci break; 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci case REQUEST_SENSE: 391362306a36Sopenharmony_ci ips_reqsen(ha, scb); 391462306a36Sopenharmony_ci break; 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci case READ_6: 391762306a36Sopenharmony_ci case WRITE_6: 391862306a36Sopenharmony_ci case READ_10: 391962306a36Sopenharmony_ci case WRITE_10: 392062306a36Sopenharmony_ci case RESERVE: 392162306a36Sopenharmony_ci case RELEASE: 392262306a36Sopenharmony_ci break; 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci case MODE_SENSE: 392562306a36Sopenharmony_ci if (!ips_online(ha, scb) 392662306a36Sopenharmony_ci || !ips_msense(ha, scb)) { 392762306a36Sopenharmony_ci errcode = DID_ERROR; 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci break; 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci case READ_CAPACITY: 393262306a36Sopenharmony_ci if (ips_online(ha, scb)) 393362306a36Sopenharmony_ci ips_rdcap(ha, scb); 393462306a36Sopenharmony_ci else { 393562306a36Sopenharmony_ci errcode = DID_TIME_OUT; 393662306a36Sopenharmony_ci } 393762306a36Sopenharmony_ci break; 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci case SEND_DIAGNOSTIC: 394062306a36Sopenharmony_ci case REASSIGN_BLOCKS: 394162306a36Sopenharmony_ci break; 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci case FORMAT_UNIT: 394462306a36Sopenharmony_ci errcode = DID_ERROR; 394562306a36Sopenharmony_ci break; 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci case SEEK_10: 394862306a36Sopenharmony_ci case VERIFY: 394962306a36Sopenharmony_ci case READ_DEFECT_DATA: 395062306a36Sopenharmony_ci case READ_BUFFER: 395162306a36Sopenharmony_ci case WRITE_BUFFER: 395262306a36Sopenharmony_ci break; 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci default: 395562306a36Sopenharmony_ci errcode = DID_ERROR; 395662306a36Sopenharmony_ci } /* end switch */ 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci scb->scsi_cmd->result = errcode << 16; 395962306a36Sopenharmony_ci } else { /* bus == 0 */ 396062306a36Sopenharmony_ci /* restrict access to physical drives */ 396162306a36Sopenharmony_ci if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 396262306a36Sopenharmony_ci ips_scmd_buf_read(scb->scsi_cmd, 396362306a36Sopenharmony_ci &inquiryData, sizeof (inquiryData)); 396462306a36Sopenharmony_ci if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 396562306a36Sopenharmony_ci scb->scsi_cmd->result = DID_TIME_OUT << 16; 396662306a36Sopenharmony_ci } 396762306a36Sopenharmony_ci } /* else */ 396862306a36Sopenharmony_ci } else { /* recovered error / success */ 396962306a36Sopenharmony_ci if (scb->bus == 0) { 397062306a36Sopenharmony_ci DEBUG_VAR(1, 397162306a36Sopenharmony_ci "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", 397262306a36Sopenharmony_ci ips_name, ha->host_num, 397362306a36Sopenharmony_ci scb->cmd.basic_io.op_code, basic_status, 397462306a36Sopenharmony_ci ext_status); 397562306a36Sopenharmony_ci } 397662306a36Sopenharmony_ci 397762306a36Sopenharmony_ci ips_map_status(ha, scb, sp); 397862306a36Sopenharmony_ci } /* else */ 397962306a36Sopenharmony_ci} 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci/****************************************************************************/ 398262306a36Sopenharmony_ci/* */ 398362306a36Sopenharmony_ci/* Routine Name: ips_online */ 398462306a36Sopenharmony_ci/* */ 398562306a36Sopenharmony_ci/* Routine Description: */ 398662306a36Sopenharmony_ci/* */ 398762306a36Sopenharmony_ci/* Determine if a logical drive is online */ 398862306a36Sopenharmony_ci/* */ 398962306a36Sopenharmony_ci/****************************************************************************/ 399062306a36Sopenharmony_cistatic int 399162306a36Sopenharmony_ciips_online(ips_ha_t * ha, ips_scb_t * scb) 399262306a36Sopenharmony_ci{ 399362306a36Sopenharmony_ci METHOD_TRACE("ips_online", 1); 399462306a36Sopenharmony_ci 399562306a36Sopenharmony_ci if (scb->target_id >= IPS_MAX_LD) 399662306a36Sopenharmony_ci return (0); 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) { 399962306a36Sopenharmony_ci memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO)); 400062306a36Sopenharmony_ci return (0); 400162306a36Sopenharmony_ci } 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci if (ha->logical_drive_info->drive_info[scb->target_id].state != 400462306a36Sopenharmony_ci IPS_LD_OFFLINE 400562306a36Sopenharmony_ci && ha->logical_drive_info->drive_info[scb->target_id].state != 400662306a36Sopenharmony_ci IPS_LD_FREE 400762306a36Sopenharmony_ci && ha->logical_drive_info->drive_info[scb->target_id].state != 400862306a36Sopenharmony_ci IPS_LD_CRS 400962306a36Sopenharmony_ci && ha->logical_drive_info->drive_info[scb->target_id].state != 401062306a36Sopenharmony_ci IPS_LD_SYS) 401162306a36Sopenharmony_ci return (1); 401262306a36Sopenharmony_ci else 401362306a36Sopenharmony_ci return (0); 401462306a36Sopenharmony_ci} 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci/****************************************************************************/ 401762306a36Sopenharmony_ci/* */ 401862306a36Sopenharmony_ci/* Routine Name: ips_inquiry */ 401962306a36Sopenharmony_ci/* */ 402062306a36Sopenharmony_ci/* Routine Description: */ 402162306a36Sopenharmony_ci/* */ 402262306a36Sopenharmony_ci/* Simulate an inquiry command to a logical drive */ 402362306a36Sopenharmony_ci/* */ 402462306a36Sopenharmony_ci/****************************************************************************/ 402562306a36Sopenharmony_cistatic int 402662306a36Sopenharmony_ciips_inquiry(ips_ha_t * ha, ips_scb_t * scb) 402762306a36Sopenharmony_ci{ 402862306a36Sopenharmony_ci IPS_SCSI_INQ_DATA inquiry; 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci METHOD_TRACE("ips_inquiry", 1); 403162306a36Sopenharmony_ci 403262306a36Sopenharmony_ci memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA)); 403362306a36Sopenharmony_ci 403462306a36Sopenharmony_ci inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD; 403562306a36Sopenharmony_ci inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED; 403662306a36Sopenharmony_ci inquiry.Version = IPS_SCSI_INQ_REV2; 403762306a36Sopenharmony_ci inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2; 403862306a36Sopenharmony_ci inquiry.AdditionalLength = 31; 403962306a36Sopenharmony_ci inquiry.Flags[0] = IPS_SCSI_INQ_Address16; 404062306a36Sopenharmony_ci inquiry.Flags[1] = 404162306a36Sopenharmony_ci IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue; 404262306a36Sopenharmony_ci memcpy(inquiry.VendorId, "IBM ", 8); 404362306a36Sopenharmony_ci memcpy(inquiry.ProductId, "SERVERAID ", 16); 404462306a36Sopenharmony_ci memcpy(inquiry.ProductRevisionLevel, "1.00", 4); 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry)); 404762306a36Sopenharmony_ci 404862306a36Sopenharmony_ci return (1); 404962306a36Sopenharmony_ci} 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_ci/****************************************************************************/ 405262306a36Sopenharmony_ci/* */ 405362306a36Sopenharmony_ci/* Routine Name: ips_rdcap */ 405462306a36Sopenharmony_ci/* */ 405562306a36Sopenharmony_ci/* Routine Description: */ 405662306a36Sopenharmony_ci/* */ 405762306a36Sopenharmony_ci/* Simulate a read capacity command to a logical drive */ 405862306a36Sopenharmony_ci/* */ 405962306a36Sopenharmony_ci/****************************************************************************/ 406062306a36Sopenharmony_cistatic int 406162306a36Sopenharmony_ciips_rdcap(ips_ha_t * ha, ips_scb_t * scb) 406262306a36Sopenharmony_ci{ 406362306a36Sopenharmony_ci IPS_SCSI_CAPACITY cap; 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_ci METHOD_TRACE("ips_rdcap", 1); 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci if (scsi_bufflen(scb->scsi_cmd) < 8) 406862306a36Sopenharmony_ci return (0); 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci cap.lba = 407162306a36Sopenharmony_ci cpu_to_be32(le32_to_cpu 407262306a36Sopenharmony_ci (ha->logical_drive_info-> 407362306a36Sopenharmony_ci drive_info[scb->target_id].sector_count) - 1); 407462306a36Sopenharmony_ci cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE); 407562306a36Sopenharmony_ci 407662306a36Sopenharmony_ci ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap)); 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_ci return (1); 407962306a36Sopenharmony_ci} 408062306a36Sopenharmony_ci 408162306a36Sopenharmony_ci/****************************************************************************/ 408262306a36Sopenharmony_ci/* */ 408362306a36Sopenharmony_ci/* Routine Name: ips_msense */ 408462306a36Sopenharmony_ci/* */ 408562306a36Sopenharmony_ci/* Routine Description: */ 408662306a36Sopenharmony_ci/* */ 408762306a36Sopenharmony_ci/* Simulate a mode sense command to a logical drive */ 408862306a36Sopenharmony_ci/* */ 408962306a36Sopenharmony_ci/****************************************************************************/ 409062306a36Sopenharmony_cistatic int 409162306a36Sopenharmony_ciips_msense(ips_ha_t * ha, ips_scb_t * scb) 409262306a36Sopenharmony_ci{ 409362306a36Sopenharmony_ci uint16_t heads; 409462306a36Sopenharmony_ci uint16_t sectors; 409562306a36Sopenharmony_ci uint32_t cylinders; 409662306a36Sopenharmony_ci IPS_SCSI_MODE_PAGE_DATA mdata; 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ci METHOD_TRACE("ips_msense", 1); 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 && 410162306a36Sopenharmony_ci (ha->enq->ucMiscFlag & 0x8) == 0) { 410262306a36Sopenharmony_ci heads = IPS_NORM_HEADS; 410362306a36Sopenharmony_ci sectors = IPS_NORM_SECTORS; 410462306a36Sopenharmony_ci } else { 410562306a36Sopenharmony_ci heads = IPS_COMP_HEADS; 410662306a36Sopenharmony_ci sectors = IPS_COMP_SECTORS; 410762306a36Sopenharmony_ci } 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci cylinders = 411062306a36Sopenharmony_ci (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) - 411162306a36Sopenharmony_ci 1) / (heads * sectors); 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA)); 411462306a36Sopenharmony_ci 411562306a36Sopenharmony_ci mdata.hdr.BlockDescLength = 8; 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci switch (scb->scsi_cmd->cmnd[2] & 0x3f) { 411862306a36Sopenharmony_ci case 0x03: /* page 3 */ 411962306a36Sopenharmony_ci mdata.pdata.pg3.PageCode = 3; 412062306a36Sopenharmony_ci mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3); 412162306a36Sopenharmony_ci mdata.hdr.DataLength = 412262306a36Sopenharmony_ci 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength; 412362306a36Sopenharmony_ci mdata.pdata.pg3.TracksPerZone = 0; 412462306a36Sopenharmony_ci mdata.pdata.pg3.AltSectorsPerZone = 0; 412562306a36Sopenharmony_ci mdata.pdata.pg3.AltTracksPerZone = 0; 412662306a36Sopenharmony_ci mdata.pdata.pg3.AltTracksPerVolume = 0; 412762306a36Sopenharmony_ci mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors); 412862306a36Sopenharmony_ci mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE); 412962306a36Sopenharmony_ci mdata.pdata.pg3.Interleave = cpu_to_be16(1); 413062306a36Sopenharmony_ci mdata.pdata.pg3.TrackSkew = 0; 413162306a36Sopenharmony_ci mdata.pdata.pg3.CylinderSkew = 0; 413262306a36Sopenharmony_ci mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector; 413362306a36Sopenharmony_ci break; 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci case 0x4: 413662306a36Sopenharmony_ci mdata.pdata.pg4.PageCode = 4; 413762306a36Sopenharmony_ci mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4); 413862306a36Sopenharmony_ci mdata.hdr.DataLength = 413962306a36Sopenharmony_ci 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength; 414062306a36Sopenharmony_ci mdata.pdata.pg4.CylindersHigh = 414162306a36Sopenharmony_ci cpu_to_be16((cylinders >> 8) & 0xFFFF); 414262306a36Sopenharmony_ci mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF); 414362306a36Sopenharmony_ci mdata.pdata.pg4.Heads = heads; 414462306a36Sopenharmony_ci mdata.pdata.pg4.WritePrecompHigh = 0; 414562306a36Sopenharmony_ci mdata.pdata.pg4.WritePrecompLow = 0; 414662306a36Sopenharmony_ci mdata.pdata.pg4.ReducedWriteCurrentHigh = 0; 414762306a36Sopenharmony_ci mdata.pdata.pg4.ReducedWriteCurrentLow = 0; 414862306a36Sopenharmony_ci mdata.pdata.pg4.StepRate = cpu_to_be16(1); 414962306a36Sopenharmony_ci mdata.pdata.pg4.LandingZoneHigh = 0; 415062306a36Sopenharmony_ci mdata.pdata.pg4.LandingZoneLow = 0; 415162306a36Sopenharmony_ci mdata.pdata.pg4.flags = 0; 415262306a36Sopenharmony_ci mdata.pdata.pg4.RotationalOffset = 0; 415362306a36Sopenharmony_ci mdata.pdata.pg4.MediumRotationRate = 0; 415462306a36Sopenharmony_ci break; 415562306a36Sopenharmony_ci case 0x8: 415662306a36Sopenharmony_ci mdata.pdata.pg8.PageCode = 8; 415762306a36Sopenharmony_ci mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8); 415862306a36Sopenharmony_ci mdata.hdr.DataLength = 415962306a36Sopenharmony_ci 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength; 416062306a36Sopenharmony_ci /* everything else is left set to 0 */ 416162306a36Sopenharmony_ci break; 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci default: 416462306a36Sopenharmony_ci return (0); 416562306a36Sopenharmony_ci } /* end switch */ 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata)); 416862306a36Sopenharmony_ci 416962306a36Sopenharmony_ci return (1); 417062306a36Sopenharmony_ci} 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_ci/****************************************************************************/ 417362306a36Sopenharmony_ci/* */ 417462306a36Sopenharmony_ci/* Routine Name: ips_reqsen */ 417562306a36Sopenharmony_ci/* */ 417662306a36Sopenharmony_ci/* Routine Description: */ 417762306a36Sopenharmony_ci/* */ 417862306a36Sopenharmony_ci/* Simulate a request sense command to a logical drive */ 417962306a36Sopenharmony_ci/* */ 418062306a36Sopenharmony_ci/****************************************************************************/ 418162306a36Sopenharmony_cistatic int 418262306a36Sopenharmony_ciips_reqsen(ips_ha_t * ha, ips_scb_t * scb) 418362306a36Sopenharmony_ci{ 418462306a36Sopenharmony_ci IPS_SCSI_REQSEN reqsen; 418562306a36Sopenharmony_ci 418662306a36Sopenharmony_ci METHOD_TRACE("ips_reqsen", 1); 418762306a36Sopenharmony_ci 418862306a36Sopenharmony_ci memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN)); 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci reqsen.ResponseCode = 419162306a36Sopenharmony_ci IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR; 419262306a36Sopenharmony_ci reqsen.AdditionalLength = 10; 419362306a36Sopenharmony_ci reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE; 419462306a36Sopenharmony_ci reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE; 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen)); 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci return (1); 419962306a36Sopenharmony_ci} 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci/****************************************************************************/ 420262306a36Sopenharmony_ci/* */ 420362306a36Sopenharmony_ci/* Routine Name: ips_free */ 420462306a36Sopenharmony_ci/* */ 420562306a36Sopenharmony_ci/* Routine Description: */ 420662306a36Sopenharmony_ci/* */ 420762306a36Sopenharmony_ci/* Free any allocated space for this controller */ 420862306a36Sopenharmony_ci/* */ 420962306a36Sopenharmony_ci/****************************************************************************/ 421062306a36Sopenharmony_cistatic void 421162306a36Sopenharmony_ciips_free(ips_ha_t * ha) 421262306a36Sopenharmony_ci{ 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_ci METHOD_TRACE("ips_free", 1); 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci if (ha) { 421762306a36Sopenharmony_ci if (ha->enq) { 421862306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, sizeof(IPS_ENQ), 421962306a36Sopenharmony_ci ha->enq, ha->enq_busaddr); 422062306a36Sopenharmony_ci ha->enq = NULL; 422162306a36Sopenharmony_ci } 422262306a36Sopenharmony_ci 422362306a36Sopenharmony_ci kfree(ha->conf); 422462306a36Sopenharmony_ci ha->conf = NULL; 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci if (ha->adapt) { 422762306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, 422862306a36Sopenharmony_ci sizeof (IPS_ADAPTER) + 422962306a36Sopenharmony_ci sizeof (IPS_IO_CMD), ha->adapt, 423062306a36Sopenharmony_ci ha->adapt->hw_status_start); 423162306a36Sopenharmony_ci ha->adapt = NULL; 423262306a36Sopenharmony_ci } 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_ci if (ha->logical_drive_info) { 423562306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, 423662306a36Sopenharmony_ci sizeof (IPS_LD_INFO), 423762306a36Sopenharmony_ci ha->logical_drive_info, 423862306a36Sopenharmony_ci ha->logical_drive_info_dma_addr); 423962306a36Sopenharmony_ci ha->logical_drive_info = NULL; 424062306a36Sopenharmony_ci } 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci kfree(ha->nvram); 424362306a36Sopenharmony_ci ha->nvram = NULL; 424462306a36Sopenharmony_ci 424562306a36Sopenharmony_ci kfree(ha->subsys); 424662306a36Sopenharmony_ci ha->subsys = NULL; 424762306a36Sopenharmony_ci 424862306a36Sopenharmony_ci if (ha->ioctl_data) { 424962306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len, 425062306a36Sopenharmony_ci ha->ioctl_data, ha->ioctl_busaddr); 425162306a36Sopenharmony_ci ha->ioctl_data = NULL; 425262306a36Sopenharmony_ci ha->ioctl_datasize = 0; 425362306a36Sopenharmony_ci ha->ioctl_len = 0; 425462306a36Sopenharmony_ci } 425562306a36Sopenharmony_ci ips_deallocatescbs(ha, ha->max_cmds); 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_ci /* free memory mapped (if applicable) */ 425862306a36Sopenharmony_ci if (ha->mem_ptr) { 425962306a36Sopenharmony_ci iounmap(ha->ioremap_ptr); 426062306a36Sopenharmony_ci ha->ioremap_ptr = NULL; 426162306a36Sopenharmony_ci ha->mem_ptr = NULL; 426262306a36Sopenharmony_ci } 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci ha->mem_addr = 0; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ci } 426762306a36Sopenharmony_ci} 426862306a36Sopenharmony_ci 426962306a36Sopenharmony_ci/****************************************************************************/ 427062306a36Sopenharmony_ci/* */ 427162306a36Sopenharmony_ci/* Routine Name: ips_deallocatescbs */ 427262306a36Sopenharmony_ci/* */ 427362306a36Sopenharmony_ci/* Routine Description: */ 427462306a36Sopenharmony_ci/* */ 427562306a36Sopenharmony_ci/* Free the command blocks */ 427662306a36Sopenharmony_ci/* */ 427762306a36Sopenharmony_ci/****************************************************************************/ 427862306a36Sopenharmony_cistatic int 427962306a36Sopenharmony_ciips_deallocatescbs(ips_ha_t * ha, int cmds) 428062306a36Sopenharmony_ci{ 428162306a36Sopenharmony_ci if (ha->scbs) { 428262306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, 428362306a36Sopenharmony_ci IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds, 428462306a36Sopenharmony_ci ha->scbs->sg_list.list, 428562306a36Sopenharmony_ci ha->scbs->sg_busaddr); 428662306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, sizeof (ips_scb_t) * cmds, 428762306a36Sopenharmony_ci ha->scbs, ha->scbs->scb_busaddr); 428862306a36Sopenharmony_ci ha->scbs = NULL; 428962306a36Sopenharmony_ci } /* end if */ 429062306a36Sopenharmony_ci return 1; 429162306a36Sopenharmony_ci} 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci/****************************************************************************/ 429462306a36Sopenharmony_ci/* */ 429562306a36Sopenharmony_ci/* Routine Name: ips_allocatescbs */ 429662306a36Sopenharmony_ci/* */ 429762306a36Sopenharmony_ci/* Routine Description: */ 429862306a36Sopenharmony_ci/* */ 429962306a36Sopenharmony_ci/* Allocate the command blocks */ 430062306a36Sopenharmony_ci/* */ 430162306a36Sopenharmony_ci/****************************************************************************/ 430262306a36Sopenharmony_cistatic int 430362306a36Sopenharmony_ciips_allocatescbs(ips_ha_t * ha) 430462306a36Sopenharmony_ci{ 430562306a36Sopenharmony_ci ips_scb_t *scb_p; 430662306a36Sopenharmony_ci IPS_SG_LIST ips_sg; 430762306a36Sopenharmony_ci int i; 430862306a36Sopenharmony_ci dma_addr_t command_dma, sg_dma; 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci METHOD_TRACE("ips_allocatescbs", 1); 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_ci /* Allocate memory for the SCBs */ 431362306a36Sopenharmony_ci ha->scbs = dma_alloc_coherent(&ha->pcidev->dev, 431462306a36Sopenharmony_ci ha->max_cmds * sizeof (ips_scb_t), 431562306a36Sopenharmony_ci &command_dma, GFP_KERNEL); 431662306a36Sopenharmony_ci if (ha->scbs == NULL) 431762306a36Sopenharmony_ci return 0; 431862306a36Sopenharmony_ci ips_sg.list = dma_alloc_coherent(&ha->pcidev->dev, 431962306a36Sopenharmony_ci IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * ha->max_cmds, 432062306a36Sopenharmony_ci &sg_dma, GFP_KERNEL); 432162306a36Sopenharmony_ci if (ips_sg.list == NULL) { 432262306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, 432362306a36Sopenharmony_ci ha->max_cmds * sizeof (ips_scb_t), ha->scbs, 432462306a36Sopenharmony_ci command_dma); 432562306a36Sopenharmony_ci return 0; 432662306a36Sopenharmony_ci } 432762306a36Sopenharmony_ci 432862306a36Sopenharmony_ci memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t)); 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci for (i = 0; i < ha->max_cmds; i++) { 433162306a36Sopenharmony_ci scb_p = &ha->scbs[i]; 433262306a36Sopenharmony_ci scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i; 433362306a36Sopenharmony_ci /* set up S/G list */ 433462306a36Sopenharmony_ci if (IPS_USE_ENH_SGLIST(ha)) { 433562306a36Sopenharmony_ci scb_p->sg_list.enh_list = 433662306a36Sopenharmony_ci ips_sg.enh_list + i * IPS_MAX_SG; 433762306a36Sopenharmony_ci scb_p->sg_busaddr = 433862306a36Sopenharmony_ci sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; 433962306a36Sopenharmony_ci } else { 434062306a36Sopenharmony_ci scb_p->sg_list.std_list = 434162306a36Sopenharmony_ci ips_sg.std_list + i * IPS_MAX_SG; 434262306a36Sopenharmony_ci scb_p->sg_busaddr = 434362306a36Sopenharmony_ci sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; 434462306a36Sopenharmony_ci } 434562306a36Sopenharmony_ci 434662306a36Sopenharmony_ci /* add to the free list */ 434762306a36Sopenharmony_ci if (i < ha->max_cmds - 1) { 434862306a36Sopenharmony_ci scb_p->q_next = ha->scb_freelist; 434962306a36Sopenharmony_ci ha->scb_freelist = scb_p; 435062306a36Sopenharmony_ci } 435162306a36Sopenharmony_ci } 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci /* success */ 435462306a36Sopenharmony_ci return (1); 435562306a36Sopenharmony_ci} 435662306a36Sopenharmony_ci 435762306a36Sopenharmony_ci/****************************************************************************/ 435862306a36Sopenharmony_ci/* */ 435962306a36Sopenharmony_ci/* Routine Name: ips_init_scb */ 436062306a36Sopenharmony_ci/* */ 436162306a36Sopenharmony_ci/* Routine Description: */ 436262306a36Sopenharmony_ci/* */ 436362306a36Sopenharmony_ci/* Initialize a CCB to default values */ 436462306a36Sopenharmony_ci/* */ 436562306a36Sopenharmony_ci/****************************************************************************/ 436662306a36Sopenharmony_cistatic void 436762306a36Sopenharmony_ciips_init_scb(ips_ha_t * ha, ips_scb_t * scb) 436862306a36Sopenharmony_ci{ 436962306a36Sopenharmony_ci IPS_SG_LIST sg_list; 437062306a36Sopenharmony_ci uint32_t cmd_busaddr, sg_busaddr; 437162306a36Sopenharmony_ci METHOD_TRACE("ips_init_scb", 1); 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci if (scb == NULL) 437462306a36Sopenharmony_ci return; 437562306a36Sopenharmony_ci 437662306a36Sopenharmony_ci sg_list.list = scb->sg_list.list; 437762306a36Sopenharmony_ci cmd_busaddr = scb->scb_busaddr; 437862306a36Sopenharmony_ci sg_busaddr = scb->sg_busaddr; 437962306a36Sopenharmony_ci /* zero fill */ 438062306a36Sopenharmony_ci memset(scb, 0, sizeof (ips_scb_t)); 438162306a36Sopenharmony_ci memset(ha->dummy, 0, sizeof (IPS_IO_CMD)); 438262306a36Sopenharmony_ci 438362306a36Sopenharmony_ci /* Initialize dummy command bucket */ 438462306a36Sopenharmony_ci ha->dummy->op_code = 0xFF; 438562306a36Sopenharmony_ci ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start 438662306a36Sopenharmony_ci + sizeof (IPS_ADAPTER)); 438762306a36Sopenharmony_ci ha->dummy->command_id = IPS_MAX_CMDS; 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_ci /* set bus address of scb */ 439062306a36Sopenharmony_ci scb->scb_busaddr = cmd_busaddr; 439162306a36Sopenharmony_ci scb->sg_busaddr = sg_busaddr; 439262306a36Sopenharmony_ci scb->sg_list.list = sg_list.list; 439362306a36Sopenharmony_ci 439462306a36Sopenharmony_ci /* Neptune Fix */ 439562306a36Sopenharmony_ci scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE); 439662306a36Sopenharmony_ci scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start 439762306a36Sopenharmony_ci + sizeof (IPS_ADAPTER)); 439862306a36Sopenharmony_ci} 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci/****************************************************************************/ 440162306a36Sopenharmony_ci/* */ 440262306a36Sopenharmony_ci/* Routine Name: ips_get_scb */ 440362306a36Sopenharmony_ci/* */ 440462306a36Sopenharmony_ci/* Routine Description: */ 440562306a36Sopenharmony_ci/* */ 440662306a36Sopenharmony_ci/* Initialize a CCB to default values */ 440762306a36Sopenharmony_ci/* */ 440862306a36Sopenharmony_ci/* ASSUMED to be called from within a lock */ 440962306a36Sopenharmony_ci/* */ 441062306a36Sopenharmony_ci/****************************************************************************/ 441162306a36Sopenharmony_cistatic ips_scb_t * 441262306a36Sopenharmony_ciips_getscb(ips_ha_t * ha) 441362306a36Sopenharmony_ci{ 441462306a36Sopenharmony_ci ips_scb_t *scb; 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci METHOD_TRACE("ips_getscb", 1); 441762306a36Sopenharmony_ci 441862306a36Sopenharmony_ci if ((scb = ha->scb_freelist) == NULL) { 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci return (NULL); 442162306a36Sopenharmony_ci } 442262306a36Sopenharmony_ci 442362306a36Sopenharmony_ci ha->scb_freelist = scb->q_next; 442462306a36Sopenharmony_ci scb->flags = 0; 442562306a36Sopenharmony_ci scb->q_next = NULL; 442662306a36Sopenharmony_ci 442762306a36Sopenharmony_ci ips_init_scb(ha, scb); 442862306a36Sopenharmony_ci 442962306a36Sopenharmony_ci return (scb); 443062306a36Sopenharmony_ci} 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci/****************************************************************************/ 443362306a36Sopenharmony_ci/* */ 443462306a36Sopenharmony_ci/* Routine Name: ips_free_scb */ 443562306a36Sopenharmony_ci/* */ 443662306a36Sopenharmony_ci/* Routine Description: */ 443762306a36Sopenharmony_ci/* */ 443862306a36Sopenharmony_ci/* Return an unused CCB back to the free list */ 443962306a36Sopenharmony_ci/* */ 444062306a36Sopenharmony_ci/* ASSUMED to be called from within a lock */ 444162306a36Sopenharmony_ci/* */ 444262306a36Sopenharmony_ci/****************************************************************************/ 444362306a36Sopenharmony_cistatic void 444462306a36Sopenharmony_ciips_freescb(ips_ha_t * ha, ips_scb_t * scb) 444562306a36Sopenharmony_ci{ 444662306a36Sopenharmony_ci 444762306a36Sopenharmony_ci METHOD_TRACE("ips_freescb", 1); 444862306a36Sopenharmony_ci if (scb->flags & IPS_SCB_MAP_SG) 444962306a36Sopenharmony_ci scsi_dma_unmap(scb->scsi_cmd); 445062306a36Sopenharmony_ci else if (scb->flags & IPS_SCB_MAP_SINGLE) 445162306a36Sopenharmony_ci dma_unmap_single(&ha->pcidev->dev, scb->data_busaddr, 445262306a36Sopenharmony_ci scb->data_len, IPS_DMA_DIR(scb)); 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci /* check to make sure this is not our "special" scb */ 445562306a36Sopenharmony_ci if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { 445662306a36Sopenharmony_ci scb->q_next = ha->scb_freelist; 445762306a36Sopenharmony_ci ha->scb_freelist = scb; 445862306a36Sopenharmony_ci } 445962306a36Sopenharmony_ci} 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci/****************************************************************************/ 446262306a36Sopenharmony_ci/* */ 446362306a36Sopenharmony_ci/* Routine Name: ips_isinit_copperhead */ 446462306a36Sopenharmony_ci/* */ 446562306a36Sopenharmony_ci/* Routine Description: */ 446662306a36Sopenharmony_ci/* */ 446762306a36Sopenharmony_ci/* Is controller initialized ? */ 446862306a36Sopenharmony_ci/* */ 446962306a36Sopenharmony_ci/****************************************************************************/ 447062306a36Sopenharmony_cistatic int 447162306a36Sopenharmony_ciips_isinit_copperhead(ips_ha_t * ha) 447262306a36Sopenharmony_ci{ 447362306a36Sopenharmony_ci uint8_t scpr; 447462306a36Sopenharmony_ci uint8_t isr; 447562306a36Sopenharmony_ci 447662306a36Sopenharmony_ci METHOD_TRACE("ips_isinit_copperhead", 1); 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_ci isr = inb(ha->io_addr + IPS_REG_HISR); 447962306a36Sopenharmony_ci scpr = inb(ha->io_addr + IPS_REG_SCPR); 448062306a36Sopenharmony_ci 448162306a36Sopenharmony_ci if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) 448262306a36Sopenharmony_ci return (0); 448362306a36Sopenharmony_ci else 448462306a36Sopenharmony_ci return (1); 448562306a36Sopenharmony_ci} 448662306a36Sopenharmony_ci 448762306a36Sopenharmony_ci/****************************************************************************/ 448862306a36Sopenharmony_ci/* */ 448962306a36Sopenharmony_ci/* Routine Name: ips_isinit_copperhead_memio */ 449062306a36Sopenharmony_ci/* */ 449162306a36Sopenharmony_ci/* Routine Description: */ 449262306a36Sopenharmony_ci/* */ 449362306a36Sopenharmony_ci/* Is controller initialized ? */ 449462306a36Sopenharmony_ci/* */ 449562306a36Sopenharmony_ci/****************************************************************************/ 449662306a36Sopenharmony_cistatic int 449762306a36Sopenharmony_ciips_isinit_copperhead_memio(ips_ha_t * ha) 449862306a36Sopenharmony_ci{ 449962306a36Sopenharmony_ci uint8_t isr = 0; 450062306a36Sopenharmony_ci uint8_t scpr; 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci METHOD_TRACE("ips_is_init_copperhead_memio", 1); 450362306a36Sopenharmony_ci 450462306a36Sopenharmony_ci isr = readb(ha->mem_ptr + IPS_REG_HISR); 450562306a36Sopenharmony_ci scpr = readb(ha->mem_ptr + IPS_REG_SCPR); 450662306a36Sopenharmony_ci 450762306a36Sopenharmony_ci if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) 450862306a36Sopenharmony_ci return (0); 450962306a36Sopenharmony_ci else 451062306a36Sopenharmony_ci return (1); 451162306a36Sopenharmony_ci} 451262306a36Sopenharmony_ci 451362306a36Sopenharmony_ci/****************************************************************************/ 451462306a36Sopenharmony_ci/* */ 451562306a36Sopenharmony_ci/* Routine Name: ips_isinit_morpheus */ 451662306a36Sopenharmony_ci/* */ 451762306a36Sopenharmony_ci/* Routine Description: */ 451862306a36Sopenharmony_ci/* */ 451962306a36Sopenharmony_ci/* Is controller initialized ? */ 452062306a36Sopenharmony_ci/* */ 452162306a36Sopenharmony_ci/****************************************************************************/ 452262306a36Sopenharmony_cistatic int 452362306a36Sopenharmony_ciips_isinit_morpheus(ips_ha_t * ha) 452462306a36Sopenharmony_ci{ 452562306a36Sopenharmony_ci uint32_t post; 452662306a36Sopenharmony_ci uint32_t bits; 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci METHOD_TRACE("ips_is_init_morpheus", 1); 452962306a36Sopenharmony_ci 453062306a36Sopenharmony_ci if (ips_isintr_morpheus(ha)) 453162306a36Sopenharmony_ci ips_flush_and_reset(ha); 453262306a36Sopenharmony_ci 453362306a36Sopenharmony_ci post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); 453462306a36Sopenharmony_ci bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 453562306a36Sopenharmony_ci 453662306a36Sopenharmony_ci if (post == 0) 453762306a36Sopenharmony_ci return (0); 453862306a36Sopenharmony_ci else if (bits & 0x3) 453962306a36Sopenharmony_ci return (0); 454062306a36Sopenharmony_ci else 454162306a36Sopenharmony_ci return (1); 454262306a36Sopenharmony_ci} 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_ci/****************************************************************************/ 454562306a36Sopenharmony_ci/* */ 454662306a36Sopenharmony_ci/* Routine Name: ips_flush_and_reset */ 454762306a36Sopenharmony_ci/* */ 454862306a36Sopenharmony_ci/* Routine Description: */ 454962306a36Sopenharmony_ci/* */ 455062306a36Sopenharmony_ci/* Perform cleanup ( FLUSH and RESET ) when the adapter is in an unknown */ 455162306a36Sopenharmony_ci/* state ( was trying to INIT and an interrupt was already pending ) ... */ 455262306a36Sopenharmony_ci/* */ 455362306a36Sopenharmony_ci/****************************************************************************/ 455462306a36Sopenharmony_cistatic void 455562306a36Sopenharmony_ciips_flush_and_reset(ips_ha_t *ha) 455662306a36Sopenharmony_ci{ 455762306a36Sopenharmony_ci ips_scb_t *scb; 455862306a36Sopenharmony_ci int ret; 455962306a36Sopenharmony_ci int time; 456062306a36Sopenharmony_ci int done; 456162306a36Sopenharmony_ci dma_addr_t command_dma; 456262306a36Sopenharmony_ci 456362306a36Sopenharmony_ci /* Create a usuable SCB */ 456462306a36Sopenharmony_ci scb = dma_alloc_coherent(&ha->pcidev->dev, sizeof(ips_scb_t), 456562306a36Sopenharmony_ci &command_dma, GFP_KERNEL); 456662306a36Sopenharmony_ci if (scb) { 456762306a36Sopenharmony_ci memset(scb, 0, sizeof(ips_scb_t)); 456862306a36Sopenharmony_ci ips_init_scb(ha, scb); 456962306a36Sopenharmony_ci scb->scb_busaddr = command_dma; 457062306a36Sopenharmony_ci 457162306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 457262306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_FLUSH; 457362306a36Sopenharmony_ci 457462306a36Sopenharmony_ci scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; 457562306a36Sopenharmony_ci scb->cmd.flush_cache.command_id = IPS_MAX_CMDS; /* Use an ID that would otherwise not exist */ 457662306a36Sopenharmony_ci scb->cmd.flush_cache.state = IPS_NORM_STATE; 457762306a36Sopenharmony_ci scb->cmd.flush_cache.reserved = 0; 457862306a36Sopenharmony_ci scb->cmd.flush_cache.reserved2 = 0; 457962306a36Sopenharmony_ci scb->cmd.flush_cache.reserved3 = 0; 458062306a36Sopenharmony_ci scb->cmd.flush_cache.reserved4 = 0; 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci ret = ips_send_cmd(ha, scb); /* Send the Flush Command */ 458362306a36Sopenharmony_ci 458462306a36Sopenharmony_ci if (ret == IPS_SUCCESS) { 458562306a36Sopenharmony_ci time = 60 * IPS_ONE_SEC; /* Max Wait time is 60 seconds */ 458662306a36Sopenharmony_ci done = 0; 458762306a36Sopenharmony_ci 458862306a36Sopenharmony_ci while ((time > 0) && (!done)) { 458962306a36Sopenharmony_ci done = ips_poll_for_flush_complete(ha); 459062306a36Sopenharmony_ci /* This may look evil, but it's only done during extremely rare start-up conditions ! */ 459162306a36Sopenharmony_ci udelay(1000); 459262306a36Sopenharmony_ci time--; 459362306a36Sopenharmony_ci } 459462306a36Sopenharmony_ci } 459562306a36Sopenharmony_ci } 459662306a36Sopenharmony_ci 459762306a36Sopenharmony_ci /* Now RESET and INIT the adapter */ 459862306a36Sopenharmony_ci (*ha->func.reset) (ha); 459962306a36Sopenharmony_ci 460062306a36Sopenharmony_ci dma_free_coherent(&ha->pcidev->dev, sizeof(ips_scb_t), scb, command_dma); 460162306a36Sopenharmony_ci return; 460262306a36Sopenharmony_ci} 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ci/****************************************************************************/ 460562306a36Sopenharmony_ci/* */ 460662306a36Sopenharmony_ci/* Routine Name: ips_poll_for_flush_complete */ 460762306a36Sopenharmony_ci/* */ 460862306a36Sopenharmony_ci/* Routine Description: */ 460962306a36Sopenharmony_ci/* */ 461062306a36Sopenharmony_ci/* Poll for the Flush Command issued by ips_flush_and_reset() to complete */ 461162306a36Sopenharmony_ci/* All other responses are just taken off the queue and ignored */ 461262306a36Sopenharmony_ci/* */ 461362306a36Sopenharmony_ci/****************************************************************************/ 461462306a36Sopenharmony_cistatic int 461562306a36Sopenharmony_ciips_poll_for_flush_complete(ips_ha_t * ha) 461662306a36Sopenharmony_ci{ 461762306a36Sopenharmony_ci IPS_STATUS cstatus; 461862306a36Sopenharmony_ci 461962306a36Sopenharmony_ci while (true) { 462062306a36Sopenharmony_ci cstatus.value = (*ha->func.statupd) (ha); 462162306a36Sopenharmony_ci 462262306a36Sopenharmony_ci if (cstatus.value == 0xffffffff) /* If No Interrupt to process */ 462362306a36Sopenharmony_ci break; 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_ci /* Success is when we see the Flush Command ID */ 462662306a36Sopenharmony_ci if (cstatus.fields.command_id == IPS_MAX_CMDS) 462762306a36Sopenharmony_ci return 1; 462862306a36Sopenharmony_ci } 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci return 0; 463162306a36Sopenharmony_ci} 463262306a36Sopenharmony_ci 463362306a36Sopenharmony_ci/****************************************************************************/ 463462306a36Sopenharmony_ci/* */ 463562306a36Sopenharmony_ci/* Routine Name: ips_enable_int_copperhead */ 463662306a36Sopenharmony_ci/* */ 463762306a36Sopenharmony_ci/* Routine Description: */ 463862306a36Sopenharmony_ci/* Turn on interrupts */ 463962306a36Sopenharmony_ci/* */ 464062306a36Sopenharmony_ci/****************************************************************************/ 464162306a36Sopenharmony_cistatic void 464262306a36Sopenharmony_ciips_enable_int_copperhead(ips_ha_t * ha) 464362306a36Sopenharmony_ci{ 464462306a36Sopenharmony_ci METHOD_TRACE("ips_enable_int_copperhead", 1); 464562306a36Sopenharmony_ci 464662306a36Sopenharmony_ci outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI); 464762306a36Sopenharmony_ci inb(ha->io_addr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/ 464862306a36Sopenharmony_ci} 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci/****************************************************************************/ 465162306a36Sopenharmony_ci/* */ 465262306a36Sopenharmony_ci/* Routine Name: ips_enable_int_copperhead_memio */ 465362306a36Sopenharmony_ci/* */ 465462306a36Sopenharmony_ci/* Routine Description: */ 465562306a36Sopenharmony_ci/* Turn on interrupts */ 465662306a36Sopenharmony_ci/* */ 465762306a36Sopenharmony_ci/****************************************************************************/ 465862306a36Sopenharmony_cistatic void 465962306a36Sopenharmony_ciips_enable_int_copperhead_memio(ips_ha_t * ha) 466062306a36Sopenharmony_ci{ 466162306a36Sopenharmony_ci METHOD_TRACE("ips_enable_int_copperhead_memio", 1); 466262306a36Sopenharmony_ci 466362306a36Sopenharmony_ci writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); 466462306a36Sopenharmony_ci readb(ha->mem_ptr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/ 466562306a36Sopenharmony_ci} 466662306a36Sopenharmony_ci 466762306a36Sopenharmony_ci/****************************************************************************/ 466862306a36Sopenharmony_ci/* */ 466962306a36Sopenharmony_ci/* Routine Name: ips_enable_int_morpheus */ 467062306a36Sopenharmony_ci/* */ 467162306a36Sopenharmony_ci/* Routine Description: */ 467262306a36Sopenharmony_ci/* Turn on interrupts */ 467362306a36Sopenharmony_ci/* */ 467462306a36Sopenharmony_ci/****************************************************************************/ 467562306a36Sopenharmony_cistatic void 467662306a36Sopenharmony_ciips_enable_int_morpheus(ips_ha_t * ha) 467762306a36Sopenharmony_ci{ 467862306a36Sopenharmony_ci uint32_t Oimr; 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci METHOD_TRACE("ips_enable_int_morpheus", 1); 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); 468362306a36Sopenharmony_ci Oimr &= ~0x08; 468462306a36Sopenharmony_ci writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); 468562306a36Sopenharmony_ci readl(ha->mem_ptr + IPS_REG_I960_OIMR); /*Ensure PCI Posting Completes*/ 468662306a36Sopenharmony_ci} 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci/****************************************************************************/ 468962306a36Sopenharmony_ci/* */ 469062306a36Sopenharmony_ci/* Routine Name: ips_init_copperhead */ 469162306a36Sopenharmony_ci/* */ 469262306a36Sopenharmony_ci/* Routine Description: */ 469362306a36Sopenharmony_ci/* */ 469462306a36Sopenharmony_ci/* Initialize a copperhead controller */ 469562306a36Sopenharmony_ci/* */ 469662306a36Sopenharmony_ci/****************************************************************************/ 469762306a36Sopenharmony_cistatic int 469862306a36Sopenharmony_ciips_init_copperhead(ips_ha_t * ha) 469962306a36Sopenharmony_ci{ 470062306a36Sopenharmony_ci uint8_t Isr; 470162306a36Sopenharmony_ci uint8_t Cbsp; 470262306a36Sopenharmony_ci uint8_t PostByte[IPS_MAX_POST_BYTES]; 470362306a36Sopenharmony_ci int i, j; 470462306a36Sopenharmony_ci 470562306a36Sopenharmony_ci METHOD_TRACE("ips_init_copperhead", 1); 470662306a36Sopenharmony_ci 470762306a36Sopenharmony_ci for (i = 0; i < IPS_MAX_POST_BYTES; i++) { 470862306a36Sopenharmony_ci for (j = 0; j < 45; j++) { 470962306a36Sopenharmony_ci Isr = inb(ha->io_addr + IPS_REG_HISR); 471062306a36Sopenharmony_ci if (Isr & IPS_BIT_GHI) 471162306a36Sopenharmony_ci break; 471262306a36Sopenharmony_ci 471362306a36Sopenharmony_ci /* Delay for 1 Second */ 471462306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 471562306a36Sopenharmony_ci } 471662306a36Sopenharmony_ci 471762306a36Sopenharmony_ci if (j >= 45) 471862306a36Sopenharmony_ci /* error occurred */ 471962306a36Sopenharmony_ci return (0); 472062306a36Sopenharmony_ci 472162306a36Sopenharmony_ci PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); 472262306a36Sopenharmony_ci outb(Isr, ha->io_addr + IPS_REG_HISR); 472362306a36Sopenharmony_ci } 472462306a36Sopenharmony_ci 472562306a36Sopenharmony_ci if (PostByte[0] < IPS_GOOD_POST_STATUS) { 472662306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 472762306a36Sopenharmony_ci "reset controller fails (post status %x %x).\n", 472862306a36Sopenharmony_ci PostByte[0], PostByte[1]); 472962306a36Sopenharmony_ci 473062306a36Sopenharmony_ci return (0); 473162306a36Sopenharmony_ci } 473262306a36Sopenharmony_ci 473362306a36Sopenharmony_ci for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { 473462306a36Sopenharmony_ci for (j = 0; j < 240; j++) { 473562306a36Sopenharmony_ci Isr = inb(ha->io_addr + IPS_REG_HISR); 473662306a36Sopenharmony_ci if (Isr & IPS_BIT_GHI) 473762306a36Sopenharmony_ci break; 473862306a36Sopenharmony_ci 473962306a36Sopenharmony_ci /* Delay for 1 Second */ 474062306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 474162306a36Sopenharmony_ci } 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_ci if (j >= 240) 474462306a36Sopenharmony_ci /* error occurred */ 474562306a36Sopenharmony_ci return (0); 474662306a36Sopenharmony_ci 474762306a36Sopenharmony_ci inb(ha->io_addr + IPS_REG_ISPR); 474862306a36Sopenharmony_ci outb(Isr, ha->io_addr + IPS_REG_HISR); 474962306a36Sopenharmony_ci } 475062306a36Sopenharmony_ci 475162306a36Sopenharmony_ci for (i = 0; i < 240; i++) { 475262306a36Sopenharmony_ci Cbsp = inb(ha->io_addr + IPS_REG_CBSP); 475362306a36Sopenharmony_ci 475462306a36Sopenharmony_ci if ((Cbsp & IPS_BIT_OP) == 0) 475562306a36Sopenharmony_ci break; 475662306a36Sopenharmony_ci 475762306a36Sopenharmony_ci /* Delay for 1 Second */ 475862306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 475962306a36Sopenharmony_ci } 476062306a36Sopenharmony_ci 476162306a36Sopenharmony_ci if (i >= 240) 476262306a36Sopenharmony_ci /* reset failed */ 476362306a36Sopenharmony_ci return (0); 476462306a36Sopenharmony_ci 476562306a36Sopenharmony_ci /* setup CCCR */ 476662306a36Sopenharmony_ci outl(0x1010, ha->io_addr + IPS_REG_CCCR); 476762306a36Sopenharmony_ci 476862306a36Sopenharmony_ci /* Enable busmastering */ 476962306a36Sopenharmony_ci outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); 477062306a36Sopenharmony_ci 477162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 477262306a36Sopenharmony_ci /* fix for anaconda64 */ 477362306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_NDAE); 477462306a36Sopenharmony_ci 477562306a36Sopenharmony_ci /* Enable interrupts */ 477662306a36Sopenharmony_ci outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); 477762306a36Sopenharmony_ci 477862306a36Sopenharmony_ci return (1); 477962306a36Sopenharmony_ci} 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_ci/****************************************************************************/ 478262306a36Sopenharmony_ci/* */ 478362306a36Sopenharmony_ci/* Routine Name: ips_init_copperhead_memio */ 478462306a36Sopenharmony_ci/* */ 478562306a36Sopenharmony_ci/* Routine Description: */ 478662306a36Sopenharmony_ci/* */ 478762306a36Sopenharmony_ci/* Initialize a copperhead controller with memory mapped I/O */ 478862306a36Sopenharmony_ci/* */ 478962306a36Sopenharmony_ci/****************************************************************************/ 479062306a36Sopenharmony_cistatic int 479162306a36Sopenharmony_ciips_init_copperhead_memio(ips_ha_t * ha) 479262306a36Sopenharmony_ci{ 479362306a36Sopenharmony_ci uint8_t Isr = 0; 479462306a36Sopenharmony_ci uint8_t Cbsp; 479562306a36Sopenharmony_ci uint8_t PostByte[IPS_MAX_POST_BYTES]; 479662306a36Sopenharmony_ci int i, j; 479762306a36Sopenharmony_ci 479862306a36Sopenharmony_ci METHOD_TRACE("ips_init_copperhead_memio", 1); 479962306a36Sopenharmony_ci 480062306a36Sopenharmony_ci for (i = 0; i < IPS_MAX_POST_BYTES; i++) { 480162306a36Sopenharmony_ci for (j = 0; j < 45; j++) { 480262306a36Sopenharmony_ci Isr = readb(ha->mem_ptr + IPS_REG_HISR); 480362306a36Sopenharmony_ci if (Isr & IPS_BIT_GHI) 480462306a36Sopenharmony_ci break; 480562306a36Sopenharmony_ci 480662306a36Sopenharmony_ci /* Delay for 1 Second */ 480762306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 480862306a36Sopenharmony_ci } 480962306a36Sopenharmony_ci 481062306a36Sopenharmony_ci if (j >= 45) 481162306a36Sopenharmony_ci /* error occurred */ 481262306a36Sopenharmony_ci return (0); 481362306a36Sopenharmony_ci 481462306a36Sopenharmony_ci PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); 481562306a36Sopenharmony_ci writeb(Isr, ha->mem_ptr + IPS_REG_HISR); 481662306a36Sopenharmony_ci } 481762306a36Sopenharmony_ci 481862306a36Sopenharmony_ci if (PostByte[0] < IPS_GOOD_POST_STATUS) { 481962306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 482062306a36Sopenharmony_ci "reset controller fails (post status %x %x).\n", 482162306a36Sopenharmony_ci PostByte[0], PostByte[1]); 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci return (0); 482462306a36Sopenharmony_ci } 482562306a36Sopenharmony_ci 482662306a36Sopenharmony_ci for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { 482762306a36Sopenharmony_ci for (j = 0; j < 240; j++) { 482862306a36Sopenharmony_ci Isr = readb(ha->mem_ptr + IPS_REG_HISR); 482962306a36Sopenharmony_ci if (Isr & IPS_BIT_GHI) 483062306a36Sopenharmony_ci break; 483162306a36Sopenharmony_ci 483262306a36Sopenharmony_ci /* Delay for 1 Second */ 483362306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 483462306a36Sopenharmony_ci } 483562306a36Sopenharmony_ci 483662306a36Sopenharmony_ci if (j >= 240) 483762306a36Sopenharmony_ci /* error occurred */ 483862306a36Sopenharmony_ci return (0); 483962306a36Sopenharmony_ci 484062306a36Sopenharmony_ci readb(ha->mem_ptr + IPS_REG_ISPR); 484162306a36Sopenharmony_ci writeb(Isr, ha->mem_ptr + IPS_REG_HISR); 484262306a36Sopenharmony_ci } 484362306a36Sopenharmony_ci 484462306a36Sopenharmony_ci for (i = 0; i < 240; i++) { 484562306a36Sopenharmony_ci Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP); 484662306a36Sopenharmony_ci 484762306a36Sopenharmony_ci if ((Cbsp & IPS_BIT_OP) == 0) 484862306a36Sopenharmony_ci break; 484962306a36Sopenharmony_ci 485062306a36Sopenharmony_ci /* Delay for 1 Second */ 485162306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 485262306a36Sopenharmony_ci } 485362306a36Sopenharmony_ci 485462306a36Sopenharmony_ci if (i >= 240) 485562306a36Sopenharmony_ci /* error occurred */ 485662306a36Sopenharmony_ci return (0); 485762306a36Sopenharmony_ci 485862306a36Sopenharmony_ci /* setup CCCR */ 485962306a36Sopenharmony_ci writel(0x1010, ha->mem_ptr + IPS_REG_CCCR); 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci /* Enable busmastering */ 486262306a36Sopenharmony_ci writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); 486362306a36Sopenharmony_ci 486462306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 486562306a36Sopenharmony_ci /* fix for anaconda64 */ 486662306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_NDAE); 486762306a36Sopenharmony_ci 486862306a36Sopenharmony_ci /* Enable interrupts */ 486962306a36Sopenharmony_ci writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); 487062306a36Sopenharmony_ci 487162306a36Sopenharmony_ci /* if we get here then everything went OK */ 487262306a36Sopenharmony_ci return (1); 487362306a36Sopenharmony_ci} 487462306a36Sopenharmony_ci 487562306a36Sopenharmony_ci/****************************************************************************/ 487662306a36Sopenharmony_ci/* */ 487762306a36Sopenharmony_ci/* Routine Name: ips_init_morpheus */ 487862306a36Sopenharmony_ci/* */ 487962306a36Sopenharmony_ci/* Routine Description: */ 488062306a36Sopenharmony_ci/* */ 488162306a36Sopenharmony_ci/* Initialize a morpheus controller */ 488262306a36Sopenharmony_ci/* */ 488362306a36Sopenharmony_ci/****************************************************************************/ 488462306a36Sopenharmony_cistatic int 488562306a36Sopenharmony_ciips_init_morpheus(ips_ha_t * ha) 488662306a36Sopenharmony_ci{ 488762306a36Sopenharmony_ci uint32_t Post; 488862306a36Sopenharmony_ci uint32_t Config; 488962306a36Sopenharmony_ci uint32_t Isr; 489062306a36Sopenharmony_ci uint32_t Oimr; 489162306a36Sopenharmony_ci int i; 489262306a36Sopenharmony_ci 489362306a36Sopenharmony_ci METHOD_TRACE("ips_init_morpheus", 1); 489462306a36Sopenharmony_ci 489562306a36Sopenharmony_ci /* Wait up to 45 secs for Post */ 489662306a36Sopenharmony_ci for (i = 0; i < 45; i++) { 489762306a36Sopenharmony_ci Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 489862306a36Sopenharmony_ci 489962306a36Sopenharmony_ci if (Isr & IPS_BIT_I960_MSG0I) 490062306a36Sopenharmony_ci break; 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci /* Delay for 1 Second */ 490362306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 490462306a36Sopenharmony_ci } 490562306a36Sopenharmony_ci 490662306a36Sopenharmony_ci if (i >= 45) { 490762306a36Sopenharmony_ci /* error occurred */ 490862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 490962306a36Sopenharmony_ci "timeout waiting for post.\n"); 491062306a36Sopenharmony_ci 491162306a36Sopenharmony_ci return (0); 491262306a36Sopenharmony_ci } 491362306a36Sopenharmony_ci 491462306a36Sopenharmony_ci Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); 491562306a36Sopenharmony_ci 491662306a36Sopenharmony_ci if (Post == 0x4F00) { /* If Flashing the Battery PIC */ 491762306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 491862306a36Sopenharmony_ci "Flashing Battery PIC, Please wait ...\n"); 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_ci /* Clear the interrupt bit */ 492162306a36Sopenharmony_ci Isr = (uint32_t) IPS_BIT_I960_MSG0I; 492262306a36Sopenharmony_ci writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); 492362306a36Sopenharmony_ci 492462306a36Sopenharmony_ci for (i = 0; i < 120; i++) { /* Wait Up to 2 Min. for Completion */ 492562306a36Sopenharmony_ci Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); 492662306a36Sopenharmony_ci if (Post != 0x4F00) 492762306a36Sopenharmony_ci break; 492862306a36Sopenharmony_ci /* Delay for 1 Second */ 492962306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 493062306a36Sopenharmony_ci } 493162306a36Sopenharmony_ci 493262306a36Sopenharmony_ci if (i >= 120) { 493362306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 493462306a36Sopenharmony_ci "timeout waiting for Battery PIC Flash\n"); 493562306a36Sopenharmony_ci return (0); 493662306a36Sopenharmony_ci } 493762306a36Sopenharmony_ci 493862306a36Sopenharmony_ci } 493962306a36Sopenharmony_ci 494062306a36Sopenharmony_ci /* Clear the interrupt bit */ 494162306a36Sopenharmony_ci Isr = (uint32_t) IPS_BIT_I960_MSG0I; 494262306a36Sopenharmony_ci writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci if (Post < (IPS_GOOD_POST_STATUS << 8)) { 494562306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 494662306a36Sopenharmony_ci "reset controller fails (post status %x).\n", Post); 494762306a36Sopenharmony_ci 494862306a36Sopenharmony_ci return (0); 494962306a36Sopenharmony_ci } 495062306a36Sopenharmony_ci 495162306a36Sopenharmony_ci /* Wait up to 240 secs for config bytes */ 495262306a36Sopenharmony_ci for (i = 0; i < 240; i++) { 495362306a36Sopenharmony_ci Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 495462306a36Sopenharmony_ci 495562306a36Sopenharmony_ci if (Isr & IPS_BIT_I960_MSG1I) 495662306a36Sopenharmony_ci break; 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci /* Delay for 1 Second */ 495962306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 496062306a36Sopenharmony_ci } 496162306a36Sopenharmony_ci 496262306a36Sopenharmony_ci if (i >= 240) { 496362306a36Sopenharmony_ci /* error occurred */ 496462306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 496562306a36Sopenharmony_ci "timeout waiting for config.\n"); 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci return (0); 496862306a36Sopenharmony_ci } 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1); 497162306a36Sopenharmony_ci 497262306a36Sopenharmony_ci /* Clear interrupt bit */ 497362306a36Sopenharmony_ci Isr = (uint32_t) IPS_BIT_I960_MSG1I; 497462306a36Sopenharmony_ci writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ci /* Turn on the interrupts */ 497762306a36Sopenharmony_ci Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); 497862306a36Sopenharmony_ci Oimr &= ~0x8; 497962306a36Sopenharmony_ci writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); 498062306a36Sopenharmony_ci 498162306a36Sopenharmony_ci /* if we get here then everything went OK */ 498262306a36Sopenharmony_ci 498362306a36Sopenharmony_ci /* Since we did a RESET, an EraseStripeLock may be needed */ 498462306a36Sopenharmony_ci if (Post == 0xEF10) { 498562306a36Sopenharmony_ci if ((Config == 0x000F) || (Config == 0x0009)) 498662306a36Sopenharmony_ci ha->requires_esl = 1; 498762306a36Sopenharmony_ci } 498862306a36Sopenharmony_ci 498962306a36Sopenharmony_ci return (1); 499062306a36Sopenharmony_ci} 499162306a36Sopenharmony_ci 499262306a36Sopenharmony_ci/****************************************************************************/ 499362306a36Sopenharmony_ci/* */ 499462306a36Sopenharmony_ci/* Routine Name: ips_reset_copperhead */ 499562306a36Sopenharmony_ci/* */ 499662306a36Sopenharmony_ci/* Routine Description: */ 499762306a36Sopenharmony_ci/* */ 499862306a36Sopenharmony_ci/* Reset the controller */ 499962306a36Sopenharmony_ci/* */ 500062306a36Sopenharmony_ci/****************************************************************************/ 500162306a36Sopenharmony_cistatic int 500262306a36Sopenharmony_ciips_reset_copperhead(ips_ha_t * ha) 500362306a36Sopenharmony_ci{ 500462306a36Sopenharmony_ci int reset_counter; 500562306a36Sopenharmony_ci 500662306a36Sopenharmony_ci METHOD_TRACE("ips_reset_copperhead", 1); 500762306a36Sopenharmony_ci 500862306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", 500962306a36Sopenharmony_ci ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq); 501062306a36Sopenharmony_ci 501162306a36Sopenharmony_ci reset_counter = 0; 501262306a36Sopenharmony_ci 501362306a36Sopenharmony_ci while (reset_counter < 2) { 501462306a36Sopenharmony_ci reset_counter++; 501562306a36Sopenharmony_ci 501662306a36Sopenharmony_ci outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR); 501762306a36Sopenharmony_ci 501862306a36Sopenharmony_ci /* Delay for 1 Second */ 501962306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 502062306a36Sopenharmony_ci 502162306a36Sopenharmony_ci outb(0, ha->io_addr + IPS_REG_SCPR); 502262306a36Sopenharmony_ci 502362306a36Sopenharmony_ci /* Delay for 1 Second */ 502462306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 502562306a36Sopenharmony_ci 502662306a36Sopenharmony_ci if ((*ha->func.init) (ha)) 502762306a36Sopenharmony_ci break; 502862306a36Sopenharmony_ci else if (reset_counter >= 2) { 502962306a36Sopenharmony_ci 503062306a36Sopenharmony_ci return (0); 503162306a36Sopenharmony_ci } 503262306a36Sopenharmony_ci } 503362306a36Sopenharmony_ci 503462306a36Sopenharmony_ci return (1); 503562306a36Sopenharmony_ci} 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci/****************************************************************************/ 503862306a36Sopenharmony_ci/* */ 503962306a36Sopenharmony_ci/* Routine Name: ips_reset_copperhead_memio */ 504062306a36Sopenharmony_ci/* */ 504162306a36Sopenharmony_ci/* Routine Description: */ 504262306a36Sopenharmony_ci/* */ 504362306a36Sopenharmony_ci/* Reset the controller */ 504462306a36Sopenharmony_ci/* */ 504562306a36Sopenharmony_ci/****************************************************************************/ 504662306a36Sopenharmony_cistatic int 504762306a36Sopenharmony_ciips_reset_copperhead_memio(ips_ha_t * ha) 504862306a36Sopenharmony_ci{ 504962306a36Sopenharmony_ci int reset_counter; 505062306a36Sopenharmony_ci 505162306a36Sopenharmony_ci METHOD_TRACE("ips_reset_copperhead_memio", 1); 505262306a36Sopenharmony_ci 505362306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", 505462306a36Sopenharmony_ci ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci reset_counter = 0; 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci while (reset_counter < 2) { 505962306a36Sopenharmony_ci reset_counter++; 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); 506262306a36Sopenharmony_ci 506362306a36Sopenharmony_ci /* Delay for 1 Second */ 506462306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 506562306a36Sopenharmony_ci 506662306a36Sopenharmony_ci writeb(0, ha->mem_ptr + IPS_REG_SCPR); 506762306a36Sopenharmony_ci 506862306a36Sopenharmony_ci /* Delay for 1 Second */ 506962306a36Sopenharmony_ci MDELAY(IPS_ONE_SEC); 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ci if ((*ha->func.init) (ha)) 507262306a36Sopenharmony_ci break; 507362306a36Sopenharmony_ci else if (reset_counter >= 2) { 507462306a36Sopenharmony_ci 507562306a36Sopenharmony_ci return (0); 507662306a36Sopenharmony_ci } 507762306a36Sopenharmony_ci } 507862306a36Sopenharmony_ci 507962306a36Sopenharmony_ci return (1); 508062306a36Sopenharmony_ci} 508162306a36Sopenharmony_ci 508262306a36Sopenharmony_ci/****************************************************************************/ 508362306a36Sopenharmony_ci/* */ 508462306a36Sopenharmony_ci/* Routine Name: ips_reset_morpheus */ 508562306a36Sopenharmony_ci/* */ 508662306a36Sopenharmony_ci/* Routine Description: */ 508762306a36Sopenharmony_ci/* */ 508862306a36Sopenharmony_ci/* Reset the controller */ 508962306a36Sopenharmony_ci/* */ 509062306a36Sopenharmony_ci/****************************************************************************/ 509162306a36Sopenharmony_cistatic int 509262306a36Sopenharmony_ciips_reset_morpheus(ips_ha_t * ha) 509362306a36Sopenharmony_ci{ 509462306a36Sopenharmony_ci int reset_counter; 509562306a36Sopenharmony_ci uint8_t junk; 509662306a36Sopenharmony_ci 509762306a36Sopenharmony_ci METHOD_TRACE("ips_reset_morpheus", 1); 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", 510062306a36Sopenharmony_ci ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); 510162306a36Sopenharmony_ci 510262306a36Sopenharmony_ci reset_counter = 0; 510362306a36Sopenharmony_ci 510462306a36Sopenharmony_ci while (reset_counter < 2) { 510562306a36Sopenharmony_ci reset_counter++; 510662306a36Sopenharmony_ci 510762306a36Sopenharmony_ci writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); 510862306a36Sopenharmony_ci 510962306a36Sopenharmony_ci /* Delay for 5 Seconds */ 511062306a36Sopenharmony_ci MDELAY(5 * IPS_ONE_SEC); 511162306a36Sopenharmony_ci 511262306a36Sopenharmony_ci /* Do a PCI config read to wait for adapter */ 511362306a36Sopenharmony_ci pci_read_config_byte(ha->pcidev, 4, &junk); 511462306a36Sopenharmony_ci 511562306a36Sopenharmony_ci if ((*ha->func.init) (ha)) 511662306a36Sopenharmony_ci break; 511762306a36Sopenharmony_ci else if (reset_counter >= 2) { 511862306a36Sopenharmony_ci 511962306a36Sopenharmony_ci return (0); 512062306a36Sopenharmony_ci } 512162306a36Sopenharmony_ci } 512262306a36Sopenharmony_ci 512362306a36Sopenharmony_ci return (1); 512462306a36Sopenharmony_ci} 512562306a36Sopenharmony_ci 512662306a36Sopenharmony_ci/****************************************************************************/ 512762306a36Sopenharmony_ci/* */ 512862306a36Sopenharmony_ci/* Routine Name: ips_statinit */ 512962306a36Sopenharmony_ci/* */ 513062306a36Sopenharmony_ci/* Routine Description: */ 513162306a36Sopenharmony_ci/* */ 513262306a36Sopenharmony_ci/* Initialize the status queues on the controller */ 513362306a36Sopenharmony_ci/* */ 513462306a36Sopenharmony_ci/****************************************************************************/ 513562306a36Sopenharmony_cistatic void 513662306a36Sopenharmony_ciips_statinit(ips_ha_t * ha) 513762306a36Sopenharmony_ci{ 513862306a36Sopenharmony_ci uint32_t phys_status_start; 513962306a36Sopenharmony_ci 514062306a36Sopenharmony_ci METHOD_TRACE("ips_statinit", 1); 514162306a36Sopenharmony_ci 514262306a36Sopenharmony_ci ha->adapt->p_status_start = ha->adapt->status; 514362306a36Sopenharmony_ci ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; 514462306a36Sopenharmony_ci ha->adapt->p_status_tail = ha->adapt->status; 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci phys_status_start = ha->adapt->hw_status_start; 514762306a36Sopenharmony_ci outl(phys_status_start, ha->io_addr + IPS_REG_SQSR); 514862306a36Sopenharmony_ci outl(phys_status_start + IPS_STATUS_Q_SIZE, 514962306a36Sopenharmony_ci ha->io_addr + IPS_REG_SQER); 515062306a36Sopenharmony_ci outl(phys_status_start + IPS_STATUS_SIZE, 515162306a36Sopenharmony_ci ha->io_addr + IPS_REG_SQHR); 515262306a36Sopenharmony_ci outl(phys_status_start, ha->io_addr + IPS_REG_SQTR); 515362306a36Sopenharmony_ci 515462306a36Sopenharmony_ci ha->adapt->hw_status_tail = phys_status_start; 515562306a36Sopenharmony_ci} 515662306a36Sopenharmony_ci 515762306a36Sopenharmony_ci/****************************************************************************/ 515862306a36Sopenharmony_ci/* */ 515962306a36Sopenharmony_ci/* Routine Name: ips_statinit_memio */ 516062306a36Sopenharmony_ci/* */ 516162306a36Sopenharmony_ci/* Routine Description: */ 516262306a36Sopenharmony_ci/* */ 516362306a36Sopenharmony_ci/* Initialize the status queues on the controller */ 516462306a36Sopenharmony_ci/* */ 516562306a36Sopenharmony_ci/****************************************************************************/ 516662306a36Sopenharmony_cistatic void 516762306a36Sopenharmony_ciips_statinit_memio(ips_ha_t * ha) 516862306a36Sopenharmony_ci{ 516962306a36Sopenharmony_ci uint32_t phys_status_start; 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ci METHOD_TRACE("ips_statinit_memio", 1); 517262306a36Sopenharmony_ci 517362306a36Sopenharmony_ci ha->adapt->p_status_start = ha->adapt->status; 517462306a36Sopenharmony_ci ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; 517562306a36Sopenharmony_ci ha->adapt->p_status_tail = ha->adapt->status; 517662306a36Sopenharmony_ci 517762306a36Sopenharmony_ci phys_status_start = ha->adapt->hw_status_start; 517862306a36Sopenharmony_ci writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); 517962306a36Sopenharmony_ci writel(phys_status_start + IPS_STATUS_Q_SIZE, 518062306a36Sopenharmony_ci ha->mem_ptr + IPS_REG_SQER); 518162306a36Sopenharmony_ci writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); 518262306a36Sopenharmony_ci writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR); 518362306a36Sopenharmony_ci 518462306a36Sopenharmony_ci ha->adapt->hw_status_tail = phys_status_start; 518562306a36Sopenharmony_ci} 518662306a36Sopenharmony_ci 518762306a36Sopenharmony_ci/****************************************************************************/ 518862306a36Sopenharmony_ci/* */ 518962306a36Sopenharmony_ci/* Routine Name: ips_statupd_copperhead */ 519062306a36Sopenharmony_ci/* */ 519162306a36Sopenharmony_ci/* Routine Description: */ 519262306a36Sopenharmony_ci/* */ 519362306a36Sopenharmony_ci/* Remove an element from the status queue */ 519462306a36Sopenharmony_ci/* */ 519562306a36Sopenharmony_ci/****************************************************************************/ 519662306a36Sopenharmony_cistatic uint32_t 519762306a36Sopenharmony_ciips_statupd_copperhead(ips_ha_t * ha) 519862306a36Sopenharmony_ci{ 519962306a36Sopenharmony_ci METHOD_TRACE("ips_statupd_copperhead", 1); 520062306a36Sopenharmony_ci 520162306a36Sopenharmony_ci if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { 520262306a36Sopenharmony_ci ha->adapt->p_status_tail++; 520362306a36Sopenharmony_ci ha->adapt->hw_status_tail += sizeof (IPS_STATUS); 520462306a36Sopenharmony_ci } else { 520562306a36Sopenharmony_ci ha->adapt->p_status_tail = ha->adapt->p_status_start; 520662306a36Sopenharmony_ci ha->adapt->hw_status_tail = ha->adapt->hw_status_start; 520762306a36Sopenharmony_ci } 520862306a36Sopenharmony_ci 520962306a36Sopenharmony_ci outl(ha->adapt->hw_status_tail, 521062306a36Sopenharmony_ci ha->io_addr + IPS_REG_SQTR); 521162306a36Sopenharmony_ci 521262306a36Sopenharmony_ci return (ha->adapt->p_status_tail->value); 521362306a36Sopenharmony_ci} 521462306a36Sopenharmony_ci 521562306a36Sopenharmony_ci/****************************************************************************/ 521662306a36Sopenharmony_ci/* */ 521762306a36Sopenharmony_ci/* Routine Name: ips_statupd_copperhead_memio */ 521862306a36Sopenharmony_ci/* */ 521962306a36Sopenharmony_ci/* Routine Description: */ 522062306a36Sopenharmony_ci/* */ 522162306a36Sopenharmony_ci/* Remove an element from the status queue */ 522262306a36Sopenharmony_ci/* */ 522362306a36Sopenharmony_ci/****************************************************************************/ 522462306a36Sopenharmony_cistatic uint32_t 522562306a36Sopenharmony_ciips_statupd_copperhead_memio(ips_ha_t * ha) 522662306a36Sopenharmony_ci{ 522762306a36Sopenharmony_ci METHOD_TRACE("ips_statupd_copperhead_memio", 1); 522862306a36Sopenharmony_ci 522962306a36Sopenharmony_ci if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { 523062306a36Sopenharmony_ci ha->adapt->p_status_tail++; 523162306a36Sopenharmony_ci ha->adapt->hw_status_tail += sizeof (IPS_STATUS); 523262306a36Sopenharmony_ci } else { 523362306a36Sopenharmony_ci ha->adapt->p_status_tail = ha->adapt->p_status_start; 523462306a36Sopenharmony_ci ha->adapt->hw_status_tail = ha->adapt->hw_status_start; 523562306a36Sopenharmony_ci } 523662306a36Sopenharmony_ci 523762306a36Sopenharmony_ci writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR); 523862306a36Sopenharmony_ci 523962306a36Sopenharmony_ci return (ha->adapt->p_status_tail->value); 524062306a36Sopenharmony_ci} 524162306a36Sopenharmony_ci 524262306a36Sopenharmony_ci/****************************************************************************/ 524362306a36Sopenharmony_ci/* */ 524462306a36Sopenharmony_ci/* Routine Name: ips_statupd_morpheus */ 524562306a36Sopenharmony_ci/* */ 524662306a36Sopenharmony_ci/* Routine Description: */ 524762306a36Sopenharmony_ci/* */ 524862306a36Sopenharmony_ci/* Remove an element from the status queue */ 524962306a36Sopenharmony_ci/* */ 525062306a36Sopenharmony_ci/****************************************************************************/ 525162306a36Sopenharmony_cistatic uint32_t 525262306a36Sopenharmony_ciips_statupd_morpheus(ips_ha_t * ha) 525362306a36Sopenharmony_ci{ 525462306a36Sopenharmony_ci uint32_t val; 525562306a36Sopenharmony_ci 525662306a36Sopenharmony_ci METHOD_TRACE("ips_statupd_morpheus", 1); 525762306a36Sopenharmony_ci 525862306a36Sopenharmony_ci val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ); 525962306a36Sopenharmony_ci 526062306a36Sopenharmony_ci return (val); 526162306a36Sopenharmony_ci} 526262306a36Sopenharmony_ci 526362306a36Sopenharmony_ci/****************************************************************************/ 526462306a36Sopenharmony_ci/* */ 526562306a36Sopenharmony_ci/* Routine Name: ips_issue_copperhead */ 526662306a36Sopenharmony_ci/* */ 526762306a36Sopenharmony_ci/* Routine Description: */ 526862306a36Sopenharmony_ci/* */ 526962306a36Sopenharmony_ci/* Send a command down to the controller */ 527062306a36Sopenharmony_ci/* */ 527162306a36Sopenharmony_ci/****************************************************************************/ 527262306a36Sopenharmony_cistatic int 527362306a36Sopenharmony_ciips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) 527462306a36Sopenharmony_ci{ 527562306a36Sopenharmony_ci uint32_t TimeOut; 527662306a36Sopenharmony_ci uint32_t val; 527762306a36Sopenharmony_ci 527862306a36Sopenharmony_ci METHOD_TRACE("ips_issue_copperhead", 1); 527962306a36Sopenharmony_ci 528062306a36Sopenharmony_ci if (scb->scsi_cmd) { 528162306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 528262306a36Sopenharmony_ci ips_name, 528362306a36Sopenharmony_ci ha->host_num, 528462306a36Sopenharmony_ci scb->cdb[0], 528562306a36Sopenharmony_ci scb->cmd.basic_io.command_id, 528662306a36Sopenharmony_ci scb->bus, scb->target_id, scb->lun); 528762306a36Sopenharmony_ci } else { 528862306a36Sopenharmony_ci DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", 528962306a36Sopenharmony_ci ips_name, ha->host_num, scb->cmd.basic_io.command_id); 529062306a36Sopenharmony_ci } 529162306a36Sopenharmony_ci 529262306a36Sopenharmony_ci TimeOut = 0; 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci while ((val = 529562306a36Sopenharmony_ci le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) { 529662306a36Sopenharmony_ci udelay(1000); 529762306a36Sopenharmony_ci 529862306a36Sopenharmony_ci if (++TimeOut >= IPS_SEM_TIMEOUT) { 529962306a36Sopenharmony_ci if (!(val & IPS_BIT_START_STOP)) 530062306a36Sopenharmony_ci break; 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 530362306a36Sopenharmony_ci "ips_issue val [0x%x].\n", val); 530462306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 530562306a36Sopenharmony_ci "ips_issue semaphore chk timeout.\n"); 530662306a36Sopenharmony_ci 530762306a36Sopenharmony_ci return (IPS_FAILURE); 530862306a36Sopenharmony_ci } /* end if */ 530962306a36Sopenharmony_ci } /* end while */ 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci outl(scb->scb_busaddr, ha->io_addr + IPS_REG_CCSAR); 531262306a36Sopenharmony_ci outw(IPS_BIT_START_CMD, ha->io_addr + IPS_REG_CCCR); 531362306a36Sopenharmony_ci 531462306a36Sopenharmony_ci return (IPS_SUCCESS); 531562306a36Sopenharmony_ci} 531662306a36Sopenharmony_ci 531762306a36Sopenharmony_ci/****************************************************************************/ 531862306a36Sopenharmony_ci/* */ 531962306a36Sopenharmony_ci/* Routine Name: ips_issue_copperhead_memio */ 532062306a36Sopenharmony_ci/* */ 532162306a36Sopenharmony_ci/* Routine Description: */ 532262306a36Sopenharmony_ci/* */ 532362306a36Sopenharmony_ci/* Send a command down to the controller */ 532462306a36Sopenharmony_ci/* */ 532562306a36Sopenharmony_ci/****************************************************************************/ 532662306a36Sopenharmony_cistatic int 532762306a36Sopenharmony_ciips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) 532862306a36Sopenharmony_ci{ 532962306a36Sopenharmony_ci uint32_t TimeOut; 533062306a36Sopenharmony_ci uint32_t val; 533162306a36Sopenharmony_ci 533262306a36Sopenharmony_ci METHOD_TRACE("ips_issue_copperhead_memio", 1); 533362306a36Sopenharmony_ci 533462306a36Sopenharmony_ci if (scb->scsi_cmd) { 533562306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 533662306a36Sopenharmony_ci ips_name, 533762306a36Sopenharmony_ci ha->host_num, 533862306a36Sopenharmony_ci scb->cdb[0], 533962306a36Sopenharmony_ci scb->cmd.basic_io.command_id, 534062306a36Sopenharmony_ci scb->bus, scb->target_id, scb->lun); 534162306a36Sopenharmony_ci } else { 534262306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", 534362306a36Sopenharmony_ci ips_name, ha->host_num, scb->cmd.basic_io.command_id); 534462306a36Sopenharmony_ci } 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci TimeOut = 0; 534762306a36Sopenharmony_ci 534862306a36Sopenharmony_ci while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { 534962306a36Sopenharmony_ci udelay(1000); 535062306a36Sopenharmony_ci 535162306a36Sopenharmony_ci if (++TimeOut >= IPS_SEM_TIMEOUT) { 535262306a36Sopenharmony_ci if (!(val & IPS_BIT_START_STOP)) 535362306a36Sopenharmony_ci break; 535462306a36Sopenharmony_ci 535562306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 535662306a36Sopenharmony_ci "ips_issue val [0x%x].\n", val); 535762306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 535862306a36Sopenharmony_ci "ips_issue semaphore chk timeout.\n"); 535962306a36Sopenharmony_ci 536062306a36Sopenharmony_ci return (IPS_FAILURE); 536162306a36Sopenharmony_ci } /* end if */ 536262306a36Sopenharmony_ci } /* end while */ 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_ci writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); 536562306a36Sopenharmony_ci writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR); 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci return (IPS_SUCCESS); 536862306a36Sopenharmony_ci} 536962306a36Sopenharmony_ci 537062306a36Sopenharmony_ci/****************************************************************************/ 537162306a36Sopenharmony_ci/* */ 537262306a36Sopenharmony_ci/* Routine Name: ips_issue_i2o */ 537362306a36Sopenharmony_ci/* */ 537462306a36Sopenharmony_ci/* Routine Description: */ 537562306a36Sopenharmony_ci/* */ 537662306a36Sopenharmony_ci/* Send a command down to the controller */ 537762306a36Sopenharmony_ci/* */ 537862306a36Sopenharmony_ci/****************************************************************************/ 537962306a36Sopenharmony_cistatic int 538062306a36Sopenharmony_ciips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) 538162306a36Sopenharmony_ci{ 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci METHOD_TRACE("ips_issue_i2o", 1); 538462306a36Sopenharmony_ci 538562306a36Sopenharmony_ci if (scb->scsi_cmd) { 538662306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 538762306a36Sopenharmony_ci ips_name, 538862306a36Sopenharmony_ci ha->host_num, 538962306a36Sopenharmony_ci scb->cdb[0], 539062306a36Sopenharmony_ci scb->cmd.basic_io.command_id, 539162306a36Sopenharmony_ci scb->bus, scb->target_id, scb->lun); 539262306a36Sopenharmony_ci } else { 539362306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", 539462306a36Sopenharmony_ci ips_name, ha->host_num, scb->cmd.basic_io.command_id); 539562306a36Sopenharmony_ci } 539662306a36Sopenharmony_ci 539762306a36Sopenharmony_ci outl(scb->scb_busaddr, ha->io_addr + IPS_REG_I2O_INMSGQ); 539862306a36Sopenharmony_ci 539962306a36Sopenharmony_ci return (IPS_SUCCESS); 540062306a36Sopenharmony_ci} 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_ci/****************************************************************************/ 540362306a36Sopenharmony_ci/* */ 540462306a36Sopenharmony_ci/* Routine Name: ips_issue_i2o_memio */ 540562306a36Sopenharmony_ci/* */ 540662306a36Sopenharmony_ci/* Routine Description: */ 540762306a36Sopenharmony_ci/* */ 540862306a36Sopenharmony_ci/* Send a command down to the controller */ 540962306a36Sopenharmony_ci/* */ 541062306a36Sopenharmony_ci/****************************************************************************/ 541162306a36Sopenharmony_cistatic int 541262306a36Sopenharmony_ciips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) 541362306a36Sopenharmony_ci{ 541462306a36Sopenharmony_ci 541562306a36Sopenharmony_ci METHOD_TRACE("ips_issue_i2o_memio", 1); 541662306a36Sopenharmony_ci 541762306a36Sopenharmony_ci if (scb->scsi_cmd) { 541862306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", 541962306a36Sopenharmony_ci ips_name, 542062306a36Sopenharmony_ci ha->host_num, 542162306a36Sopenharmony_ci scb->cdb[0], 542262306a36Sopenharmony_ci scb->cmd.basic_io.command_id, 542362306a36Sopenharmony_ci scb->bus, scb->target_id, scb->lun); 542462306a36Sopenharmony_ci } else { 542562306a36Sopenharmony_ci DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", 542662306a36Sopenharmony_ci ips_name, ha->host_num, scb->cmd.basic_io.command_id); 542762306a36Sopenharmony_ci } 542862306a36Sopenharmony_ci 542962306a36Sopenharmony_ci writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ); 543062306a36Sopenharmony_ci 543162306a36Sopenharmony_ci return (IPS_SUCCESS); 543262306a36Sopenharmony_ci} 543362306a36Sopenharmony_ci 543462306a36Sopenharmony_ci/****************************************************************************/ 543562306a36Sopenharmony_ci/* */ 543662306a36Sopenharmony_ci/* Routine Name: ips_isintr_copperhead */ 543762306a36Sopenharmony_ci/* */ 543862306a36Sopenharmony_ci/* Routine Description: */ 543962306a36Sopenharmony_ci/* */ 544062306a36Sopenharmony_ci/* Test to see if an interrupt is for us */ 544162306a36Sopenharmony_ci/* */ 544262306a36Sopenharmony_ci/****************************************************************************/ 544362306a36Sopenharmony_cistatic int 544462306a36Sopenharmony_ciips_isintr_copperhead(ips_ha_t * ha) 544562306a36Sopenharmony_ci{ 544662306a36Sopenharmony_ci uint8_t Isr; 544762306a36Sopenharmony_ci 544862306a36Sopenharmony_ci METHOD_TRACE("ips_isintr_copperhead", 2); 544962306a36Sopenharmony_ci 545062306a36Sopenharmony_ci Isr = inb(ha->io_addr + IPS_REG_HISR); 545162306a36Sopenharmony_ci 545262306a36Sopenharmony_ci if (Isr == 0xFF) 545362306a36Sopenharmony_ci /* ?!?! Nothing really there */ 545462306a36Sopenharmony_ci return (0); 545562306a36Sopenharmony_ci 545662306a36Sopenharmony_ci if (Isr & IPS_BIT_SCE) 545762306a36Sopenharmony_ci return (1); 545862306a36Sopenharmony_ci else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { 545962306a36Sopenharmony_ci /* status queue overflow or GHI */ 546062306a36Sopenharmony_ci /* just clear the interrupt */ 546162306a36Sopenharmony_ci outb(Isr, ha->io_addr + IPS_REG_HISR); 546262306a36Sopenharmony_ci } 546362306a36Sopenharmony_ci 546462306a36Sopenharmony_ci return (0); 546562306a36Sopenharmony_ci} 546662306a36Sopenharmony_ci 546762306a36Sopenharmony_ci/****************************************************************************/ 546862306a36Sopenharmony_ci/* */ 546962306a36Sopenharmony_ci/* Routine Name: ips_isintr_copperhead_memio */ 547062306a36Sopenharmony_ci/* */ 547162306a36Sopenharmony_ci/* Routine Description: */ 547262306a36Sopenharmony_ci/* */ 547362306a36Sopenharmony_ci/* Test to see if an interrupt is for us */ 547462306a36Sopenharmony_ci/* */ 547562306a36Sopenharmony_ci/****************************************************************************/ 547662306a36Sopenharmony_cistatic int 547762306a36Sopenharmony_ciips_isintr_copperhead_memio(ips_ha_t * ha) 547862306a36Sopenharmony_ci{ 547962306a36Sopenharmony_ci uint8_t Isr; 548062306a36Sopenharmony_ci 548162306a36Sopenharmony_ci METHOD_TRACE("ips_isintr_memio", 2); 548262306a36Sopenharmony_ci 548362306a36Sopenharmony_ci Isr = readb(ha->mem_ptr + IPS_REG_HISR); 548462306a36Sopenharmony_ci 548562306a36Sopenharmony_ci if (Isr == 0xFF) 548662306a36Sopenharmony_ci /* ?!?! Nothing really there */ 548762306a36Sopenharmony_ci return (0); 548862306a36Sopenharmony_ci 548962306a36Sopenharmony_ci if (Isr & IPS_BIT_SCE) 549062306a36Sopenharmony_ci return (1); 549162306a36Sopenharmony_ci else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { 549262306a36Sopenharmony_ci /* status queue overflow or GHI */ 549362306a36Sopenharmony_ci /* just clear the interrupt */ 549462306a36Sopenharmony_ci writeb(Isr, ha->mem_ptr + IPS_REG_HISR); 549562306a36Sopenharmony_ci } 549662306a36Sopenharmony_ci 549762306a36Sopenharmony_ci return (0); 549862306a36Sopenharmony_ci} 549962306a36Sopenharmony_ci 550062306a36Sopenharmony_ci/****************************************************************************/ 550162306a36Sopenharmony_ci/* */ 550262306a36Sopenharmony_ci/* Routine Name: ips_isintr_morpheus */ 550362306a36Sopenharmony_ci/* */ 550462306a36Sopenharmony_ci/* Routine Description: */ 550562306a36Sopenharmony_ci/* */ 550662306a36Sopenharmony_ci/* Test to see if an interrupt is for us */ 550762306a36Sopenharmony_ci/* */ 550862306a36Sopenharmony_ci/****************************************************************************/ 550962306a36Sopenharmony_cistatic int 551062306a36Sopenharmony_ciips_isintr_morpheus(ips_ha_t * ha) 551162306a36Sopenharmony_ci{ 551262306a36Sopenharmony_ci uint32_t Isr; 551362306a36Sopenharmony_ci 551462306a36Sopenharmony_ci METHOD_TRACE("ips_isintr_morpheus", 2); 551562306a36Sopenharmony_ci 551662306a36Sopenharmony_ci Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); 551762306a36Sopenharmony_ci 551862306a36Sopenharmony_ci if (Isr & IPS_BIT_I2O_OPQI) 551962306a36Sopenharmony_ci return (1); 552062306a36Sopenharmony_ci else 552162306a36Sopenharmony_ci return (0); 552262306a36Sopenharmony_ci} 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_ci/****************************************************************************/ 552562306a36Sopenharmony_ci/* */ 552662306a36Sopenharmony_ci/* Routine Name: ips_wait */ 552762306a36Sopenharmony_ci/* */ 552862306a36Sopenharmony_ci/* Routine Description: */ 552962306a36Sopenharmony_ci/* */ 553062306a36Sopenharmony_ci/* Wait for a command to complete */ 553162306a36Sopenharmony_ci/* */ 553262306a36Sopenharmony_ci/****************************************************************************/ 553362306a36Sopenharmony_cistatic int 553462306a36Sopenharmony_ciips_wait(ips_ha_t * ha, int time, int intr) 553562306a36Sopenharmony_ci{ 553662306a36Sopenharmony_ci int ret; 553762306a36Sopenharmony_ci int done; 553862306a36Sopenharmony_ci 553962306a36Sopenharmony_ci METHOD_TRACE("ips_wait", 1); 554062306a36Sopenharmony_ci 554162306a36Sopenharmony_ci ret = IPS_FAILURE; 554262306a36Sopenharmony_ci done = false; 554362306a36Sopenharmony_ci 554462306a36Sopenharmony_ci time *= IPS_ONE_SEC; /* convert seconds */ 554562306a36Sopenharmony_ci 554662306a36Sopenharmony_ci while ((time > 0) && (!done)) { 554762306a36Sopenharmony_ci if (intr == IPS_INTR_ON) { 554862306a36Sopenharmony_ci if (!ha->waitflag) { 554962306a36Sopenharmony_ci ret = IPS_SUCCESS; 555062306a36Sopenharmony_ci done = true; 555162306a36Sopenharmony_ci break; 555262306a36Sopenharmony_ci } 555362306a36Sopenharmony_ci } else if (intr == IPS_INTR_IORL) { 555462306a36Sopenharmony_ci if (!ha->waitflag) { 555562306a36Sopenharmony_ci /* 555662306a36Sopenharmony_ci * controller generated an interrupt to 555762306a36Sopenharmony_ci * acknowledge completion of the command 555862306a36Sopenharmony_ci * and ips_intr() has serviced the interrupt. 555962306a36Sopenharmony_ci */ 556062306a36Sopenharmony_ci ret = IPS_SUCCESS; 556162306a36Sopenharmony_ci done = true; 556262306a36Sopenharmony_ci break; 556362306a36Sopenharmony_ci } 556462306a36Sopenharmony_ci 556562306a36Sopenharmony_ci /* 556662306a36Sopenharmony_ci * NOTE: we already have the io_request_lock so 556762306a36Sopenharmony_ci * even if we get an interrupt it won't get serviced 556862306a36Sopenharmony_ci * until after we finish. 556962306a36Sopenharmony_ci */ 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_ci (*ha->func.intr) (ha); 557262306a36Sopenharmony_ci } 557362306a36Sopenharmony_ci 557462306a36Sopenharmony_ci /* This looks like a very evil loop, but it only does this during start-up */ 557562306a36Sopenharmony_ci udelay(1000); 557662306a36Sopenharmony_ci time--; 557762306a36Sopenharmony_ci } 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ci return (ret); 558062306a36Sopenharmony_ci} 558162306a36Sopenharmony_ci 558262306a36Sopenharmony_ci/****************************************************************************/ 558362306a36Sopenharmony_ci/* */ 558462306a36Sopenharmony_ci/* Routine Name: ips_write_driver_status */ 558562306a36Sopenharmony_ci/* */ 558662306a36Sopenharmony_ci/* Routine Description: */ 558762306a36Sopenharmony_ci/* */ 558862306a36Sopenharmony_ci/* Write OS/Driver version to Page 5 of the nvram on the controller */ 558962306a36Sopenharmony_ci/* */ 559062306a36Sopenharmony_ci/****************************************************************************/ 559162306a36Sopenharmony_cistatic int 559262306a36Sopenharmony_ciips_write_driver_status(ips_ha_t * ha, int intr) 559362306a36Sopenharmony_ci{ 559462306a36Sopenharmony_ci METHOD_TRACE("ips_write_driver_status", 1); 559562306a36Sopenharmony_ci 559662306a36Sopenharmony_ci if (!ips_readwrite_page5(ha, false, intr)) { 559762306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 559862306a36Sopenharmony_ci "unable to read NVRAM page 5.\n"); 559962306a36Sopenharmony_ci 560062306a36Sopenharmony_ci return (0); 560162306a36Sopenharmony_ci } 560262306a36Sopenharmony_ci 560362306a36Sopenharmony_ci /* check to make sure the page has a valid */ 560462306a36Sopenharmony_ci /* signature */ 560562306a36Sopenharmony_ci if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) { 560662306a36Sopenharmony_ci DEBUG_VAR(1, 560762306a36Sopenharmony_ci "(%s%d) NVRAM page 5 has an invalid signature: %X.", 560862306a36Sopenharmony_ci ips_name, ha->host_num, ha->nvram->signature); 560962306a36Sopenharmony_ci ha->nvram->signature = IPS_NVRAM_P5_SIG; 561062306a36Sopenharmony_ci } 561162306a36Sopenharmony_ci 561262306a36Sopenharmony_ci DEBUG_VAR(2, 561362306a36Sopenharmony_ci "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", 561462306a36Sopenharmony_ci ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type), 561562306a36Sopenharmony_ci ha->nvram->adapter_slot, ha->nvram->bios_high[0], 561662306a36Sopenharmony_ci ha->nvram->bios_high[1], ha->nvram->bios_high[2], 561762306a36Sopenharmony_ci ha->nvram->bios_high[3], ha->nvram->bios_low[0], 561862306a36Sopenharmony_ci ha->nvram->bios_low[1], ha->nvram->bios_low[2], 561962306a36Sopenharmony_ci ha->nvram->bios_low[3]); 562062306a36Sopenharmony_ci 562162306a36Sopenharmony_ci ips_get_bios_version(ha, intr); 562262306a36Sopenharmony_ci 562362306a36Sopenharmony_ci /* change values (as needed) */ 562462306a36Sopenharmony_ci ha->nvram->operating_system = IPS_OS_LINUX; 562562306a36Sopenharmony_ci ha->nvram->adapter_type = ha->ad_type; 562662306a36Sopenharmony_ci memcpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); 562762306a36Sopenharmony_ci memcpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); 562862306a36Sopenharmony_ci memcpy((char *) ha->nvram->bios_high, ha->bios_version, 4); 562962306a36Sopenharmony_ci memcpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4); 563062306a36Sopenharmony_ci 563162306a36Sopenharmony_ci ha->nvram->versioning = 0; /* Indicate the Driver Does Not Support Versioning */ 563262306a36Sopenharmony_ci 563362306a36Sopenharmony_ci /* now update the page */ 563462306a36Sopenharmony_ci if (!ips_readwrite_page5(ha, true, intr)) { 563562306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 563662306a36Sopenharmony_ci "unable to write NVRAM page 5.\n"); 563762306a36Sopenharmony_ci 563862306a36Sopenharmony_ci return (0); 563962306a36Sopenharmony_ci } 564062306a36Sopenharmony_ci 564162306a36Sopenharmony_ci /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ 564262306a36Sopenharmony_ci ha->slot_num = ha->nvram->adapter_slot; 564362306a36Sopenharmony_ci 564462306a36Sopenharmony_ci return (1); 564562306a36Sopenharmony_ci} 564662306a36Sopenharmony_ci 564762306a36Sopenharmony_ci/****************************************************************************/ 564862306a36Sopenharmony_ci/* */ 564962306a36Sopenharmony_ci/* Routine Name: ips_read_adapter_status */ 565062306a36Sopenharmony_ci/* */ 565162306a36Sopenharmony_ci/* Routine Description: */ 565262306a36Sopenharmony_ci/* */ 565362306a36Sopenharmony_ci/* Do an Inquiry command to the adapter */ 565462306a36Sopenharmony_ci/* */ 565562306a36Sopenharmony_ci/****************************************************************************/ 565662306a36Sopenharmony_cistatic int 565762306a36Sopenharmony_ciips_read_adapter_status(ips_ha_t * ha, int intr) 565862306a36Sopenharmony_ci{ 565962306a36Sopenharmony_ci ips_scb_t *scb; 566062306a36Sopenharmony_ci int ret; 566162306a36Sopenharmony_ci 566262306a36Sopenharmony_ci METHOD_TRACE("ips_read_adapter_status", 1); 566362306a36Sopenharmony_ci 566462306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 566562306a36Sopenharmony_ci 566662306a36Sopenharmony_ci ips_init_scb(ha, scb); 566762306a36Sopenharmony_ci 566862306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 566962306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_ENQUIRY; 567062306a36Sopenharmony_ci 567162306a36Sopenharmony_ci scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; 567262306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 567362306a36Sopenharmony_ci scb->cmd.basic_io.sg_count = 0; 567462306a36Sopenharmony_ci scb->cmd.basic_io.lba = 0; 567562306a36Sopenharmony_ci scb->cmd.basic_io.sector_count = 0; 567662306a36Sopenharmony_ci scb->cmd.basic_io.log_drv = 0; 567762306a36Sopenharmony_ci scb->data_len = sizeof (*ha->enq); 567862306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = ha->enq_busaddr; 567962306a36Sopenharmony_ci 568062306a36Sopenharmony_ci /* send command */ 568162306a36Sopenharmony_ci if (((ret = 568262306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 568362306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 568462306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 568562306a36Sopenharmony_ci return (0); 568662306a36Sopenharmony_ci 568762306a36Sopenharmony_ci return (1); 568862306a36Sopenharmony_ci} 568962306a36Sopenharmony_ci 569062306a36Sopenharmony_ci/****************************************************************************/ 569162306a36Sopenharmony_ci/* */ 569262306a36Sopenharmony_ci/* Routine Name: ips_read_subsystem_parameters */ 569362306a36Sopenharmony_ci/* */ 569462306a36Sopenharmony_ci/* Routine Description: */ 569562306a36Sopenharmony_ci/* */ 569662306a36Sopenharmony_ci/* Read subsystem parameters from the adapter */ 569762306a36Sopenharmony_ci/* */ 569862306a36Sopenharmony_ci/****************************************************************************/ 569962306a36Sopenharmony_cistatic int 570062306a36Sopenharmony_ciips_read_subsystem_parameters(ips_ha_t * ha, int intr) 570162306a36Sopenharmony_ci{ 570262306a36Sopenharmony_ci ips_scb_t *scb; 570362306a36Sopenharmony_ci int ret; 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci METHOD_TRACE("ips_read_subsystem_parameters", 1); 570662306a36Sopenharmony_ci 570762306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 570862306a36Sopenharmony_ci 570962306a36Sopenharmony_ci ips_init_scb(ha, scb); 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 571262306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_GET_SUBSYS; 571362306a36Sopenharmony_ci 571462306a36Sopenharmony_ci scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS; 571562306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 571662306a36Sopenharmony_ci scb->cmd.basic_io.sg_count = 0; 571762306a36Sopenharmony_ci scb->cmd.basic_io.lba = 0; 571862306a36Sopenharmony_ci scb->cmd.basic_io.sector_count = 0; 571962306a36Sopenharmony_ci scb->cmd.basic_io.log_drv = 0; 572062306a36Sopenharmony_ci scb->data_len = sizeof (*ha->subsys); 572162306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; 572262306a36Sopenharmony_ci 572362306a36Sopenharmony_ci /* send command */ 572462306a36Sopenharmony_ci if (((ret = 572562306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 572662306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 572762306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 572862306a36Sopenharmony_ci return (0); 572962306a36Sopenharmony_ci 573062306a36Sopenharmony_ci memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys)); 573162306a36Sopenharmony_ci return (1); 573262306a36Sopenharmony_ci} 573362306a36Sopenharmony_ci 573462306a36Sopenharmony_ci/****************************************************************************/ 573562306a36Sopenharmony_ci/* */ 573662306a36Sopenharmony_ci/* Routine Name: ips_read_config */ 573762306a36Sopenharmony_ci/* */ 573862306a36Sopenharmony_ci/* Routine Description: */ 573962306a36Sopenharmony_ci/* */ 574062306a36Sopenharmony_ci/* Read the configuration on the adapter */ 574162306a36Sopenharmony_ci/* */ 574262306a36Sopenharmony_ci/****************************************************************************/ 574362306a36Sopenharmony_cistatic int 574462306a36Sopenharmony_ciips_read_config(ips_ha_t * ha, int intr) 574562306a36Sopenharmony_ci{ 574662306a36Sopenharmony_ci ips_scb_t *scb; 574762306a36Sopenharmony_ci int i; 574862306a36Sopenharmony_ci int ret; 574962306a36Sopenharmony_ci 575062306a36Sopenharmony_ci METHOD_TRACE("ips_read_config", 1); 575162306a36Sopenharmony_ci 575262306a36Sopenharmony_ci /* set defaults for initiator IDs */ 575362306a36Sopenharmony_ci for (i = 0; i < 4; i++) 575462306a36Sopenharmony_ci ha->conf->init_id[i] = 7; 575562306a36Sopenharmony_ci 575662306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 575762306a36Sopenharmony_ci 575862306a36Sopenharmony_ci ips_init_scb(ha, scb); 575962306a36Sopenharmony_ci 576062306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 576162306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_READ_CONF; 576262306a36Sopenharmony_ci 576362306a36Sopenharmony_ci scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF; 576462306a36Sopenharmony_ci scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); 576562306a36Sopenharmony_ci scb->data_len = sizeof (*ha->conf); 576662306a36Sopenharmony_ci scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; 576762306a36Sopenharmony_ci 576862306a36Sopenharmony_ci /* send command */ 576962306a36Sopenharmony_ci if (((ret = 577062306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 577162306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 577262306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { 577362306a36Sopenharmony_ci 577462306a36Sopenharmony_ci memset(ha->conf, 0, sizeof (IPS_CONF)); 577562306a36Sopenharmony_ci 577662306a36Sopenharmony_ci /* reset initiator IDs */ 577762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 577862306a36Sopenharmony_ci ha->conf->init_id[i] = 7; 577962306a36Sopenharmony_ci 578062306a36Sopenharmony_ci /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */ 578162306a36Sopenharmony_ci if ((scb->basic_status & IPS_GSC_STATUS_MASK) == 578262306a36Sopenharmony_ci IPS_CMD_CMPLT_WERROR) 578362306a36Sopenharmony_ci return (1); 578462306a36Sopenharmony_ci 578562306a36Sopenharmony_ci return (0); 578662306a36Sopenharmony_ci } 578762306a36Sopenharmony_ci 578862306a36Sopenharmony_ci memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); 578962306a36Sopenharmony_ci return (1); 579062306a36Sopenharmony_ci} 579162306a36Sopenharmony_ci 579262306a36Sopenharmony_ci/****************************************************************************/ 579362306a36Sopenharmony_ci/* */ 579462306a36Sopenharmony_ci/* Routine Name: ips_readwrite_page5 */ 579562306a36Sopenharmony_ci/* */ 579662306a36Sopenharmony_ci/* Routine Description: */ 579762306a36Sopenharmony_ci/* */ 579862306a36Sopenharmony_ci/* Read nvram page 5 from the adapter */ 579962306a36Sopenharmony_ci/* */ 580062306a36Sopenharmony_ci/****************************************************************************/ 580162306a36Sopenharmony_cistatic int 580262306a36Sopenharmony_ciips_readwrite_page5(ips_ha_t * ha, int write, int intr) 580362306a36Sopenharmony_ci{ 580462306a36Sopenharmony_ci ips_scb_t *scb; 580562306a36Sopenharmony_ci int ret; 580662306a36Sopenharmony_ci 580762306a36Sopenharmony_ci METHOD_TRACE("ips_readwrite_page5", 1); 580862306a36Sopenharmony_ci 580962306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 581062306a36Sopenharmony_ci 581162306a36Sopenharmony_ci ips_init_scb(ha, scb); 581262306a36Sopenharmony_ci 581362306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 581462306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE; 581562306a36Sopenharmony_ci 581662306a36Sopenharmony_ci scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE; 581762306a36Sopenharmony_ci scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); 581862306a36Sopenharmony_ci scb->cmd.nvram.page = 5; 581962306a36Sopenharmony_ci scb->cmd.nvram.write = write; 582062306a36Sopenharmony_ci scb->cmd.nvram.reserved = 0; 582162306a36Sopenharmony_ci scb->cmd.nvram.reserved2 = 0; 582262306a36Sopenharmony_ci scb->data_len = sizeof (*ha->nvram); 582362306a36Sopenharmony_ci scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; 582462306a36Sopenharmony_ci if (write) 582562306a36Sopenharmony_ci memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram)); 582662306a36Sopenharmony_ci 582762306a36Sopenharmony_ci /* issue the command */ 582862306a36Sopenharmony_ci if (((ret = 582962306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 583062306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 583162306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { 583262306a36Sopenharmony_ci 583362306a36Sopenharmony_ci memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5)); 583462306a36Sopenharmony_ci 583562306a36Sopenharmony_ci return (0); 583662306a36Sopenharmony_ci } 583762306a36Sopenharmony_ci if (!write) 583862306a36Sopenharmony_ci memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram)); 583962306a36Sopenharmony_ci return (1); 584062306a36Sopenharmony_ci} 584162306a36Sopenharmony_ci 584262306a36Sopenharmony_ci/****************************************************************************/ 584362306a36Sopenharmony_ci/* */ 584462306a36Sopenharmony_ci/* Routine Name: ips_clear_adapter */ 584562306a36Sopenharmony_ci/* */ 584662306a36Sopenharmony_ci/* Routine Description: */ 584762306a36Sopenharmony_ci/* */ 584862306a36Sopenharmony_ci/* Clear the stripe lock tables */ 584962306a36Sopenharmony_ci/* */ 585062306a36Sopenharmony_ci/****************************************************************************/ 585162306a36Sopenharmony_cistatic int 585262306a36Sopenharmony_ciips_clear_adapter(ips_ha_t * ha, int intr) 585362306a36Sopenharmony_ci{ 585462306a36Sopenharmony_ci ips_scb_t *scb; 585562306a36Sopenharmony_ci int ret; 585662306a36Sopenharmony_ci 585762306a36Sopenharmony_ci METHOD_TRACE("ips_clear_adapter", 1); 585862306a36Sopenharmony_ci 585962306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 586062306a36Sopenharmony_ci 586162306a36Sopenharmony_ci ips_init_scb(ha, scb); 586262306a36Sopenharmony_ci 586362306a36Sopenharmony_ci scb->timeout = ips_reset_timeout; 586462306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_CONFIG_SYNC; 586562306a36Sopenharmony_ci 586662306a36Sopenharmony_ci scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC; 586762306a36Sopenharmony_ci scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); 586862306a36Sopenharmony_ci scb->cmd.config_sync.channel = 0; 586962306a36Sopenharmony_ci scb->cmd.config_sync.source_target = IPS_POCL; 587062306a36Sopenharmony_ci scb->cmd.config_sync.reserved = 0; 587162306a36Sopenharmony_ci scb->cmd.config_sync.reserved2 = 0; 587262306a36Sopenharmony_ci scb->cmd.config_sync.reserved3 = 0; 587362306a36Sopenharmony_ci 587462306a36Sopenharmony_ci /* issue command */ 587562306a36Sopenharmony_ci if (((ret = 587662306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) 587762306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 587862306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 587962306a36Sopenharmony_ci return (0); 588062306a36Sopenharmony_ci 588162306a36Sopenharmony_ci /* send unlock stripe command */ 588262306a36Sopenharmony_ci ips_init_scb(ha, scb); 588362306a36Sopenharmony_ci 588462306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_ERROR_TABLE; 588562306a36Sopenharmony_ci scb->timeout = ips_reset_timeout; 588662306a36Sopenharmony_ci 588762306a36Sopenharmony_ci scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE; 588862306a36Sopenharmony_ci scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); 588962306a36Sopenharmony_ci scb->cmd.unlock_stripe.log_drv = 0; 589062306a36Sopenharmony_ci scb->cmd.unlock_stripe.control = IPS_CSL; 589162306a36Sopenharmony_ci scb->cmd.unlock_stripe.reserved = 0; 589262306a36Sopenharmony_ci scb->cmd.unlock_stripe.reserved2 = 0; 589362306a36Sopenharmony_ci scb->cmd.unlock_stripe.reserved3 = 0; 589462306a36Sopenharmony_ci 589562306a36Sopenharmony_ci /* issue command */ 589662306a36Sopenharmony_ci if (((ret = 589762306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) 589862306a36Sopenharmony_ci || (ret == IPS_SUCCESS_IMM) 589962306a36Sopenharmony_ci || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) 590062306a36Sopenharmony_ci return (0); 590162306a36Sopenharmony_ci 590262306a36Sopenharmony_ci return (1); 590362306a36Sopenharmony_ci} 590462306a36Sopenharmony_ci 590562306a36Sopenharmony_ci/****************************************************************************/ 590662306a36Sopenharmony_ci/* */ 590762306a36Sopenharmony_ci/* Routine Name: ips_ffdc_reset */ 590862306a36Sopenharmony_ci/* */ 590962306a36Sopenharmony_ci/* Routine Description: */ 591062306a36Sopenharmony_ci/* */ 591162306a36Sopenharmony_ci/* FFDC: write reset info */ 591262306a36Sopenharmony_ci/* */ 591362306a36Sopenharmony_ci/****************************************************************************/ 591462306a36Sopenharmony_cistatic void 591562306a36Sopenharmony_ciips_ffdc_reset(ips_ha_t * ha, int intr) 591662306a36Sopenharmony_ci{ 591762306a36Sopenharmony_ci ips_scb_t *scb; 591862306a36Sopenharmony_ci 591962306a36Sopenharmony_ci METHOD_TRACE("ips_ffdc_reset", 1); 592062306a36Sopenharmony_ci 592162306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 592262306a36Sopenharmony_ci 592362306a36Sopenharmony_ci ips_init_scb(ha, scb); 592462306a36Sopenharmony_ci 592562306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 592662306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_FFDC; 592762306a36Sopenharmony_ci scb->cmd.ffdc.op_code = IPS_CMD_FFDC; 592862306a36Sopenharmony_ci scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); 592962306a36Sopenharmony_ci scb->cmd.ffdc.reset_count = ha->reset_count; 593062306a36Sopenharmony_ci scb->cmd.ffdc.reset_type = 0x80; 593162306a36Sopenharmony_ci 593262306a36Sopenharmony_ci /* convert time to what the card wants */ 593362306a36Sopenharmony_ci ips_fix_ffdc_time(ha, scb, ha->last_ffdc); 593462306a36Sopenharmony_ci 593562306a36Sopenharmony_ci /* issue command */ 593662306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, intr); 593762306a36Sopenharmony_ci} 593862306a36Sopenharmony_ci 593962306a36Sopenharmony_ci/****************************************************************************/ 594062306a36Sopenharmony_ci/* */ 594162306a36Sopenharmony_ci/* Routine Name: ips_ffdc_time */ 594262306a36Sopenharmony_ci/* */ 594362306a36Sopenharmony_ci/* Routine Description: */ 594462306a36Sopenharmony_ci/* */ 594562306a36Sopenharmony_ci/* FFDC: write time info */ 594662306a36Sopenharmony_ci/* */ 594762306a36Sopenharmony_ci/****************************************************************************/ 594862306a36Sopenharmony_cistatic void 594962306a36Sopenharmony_ciips_ffdc_time(ips_ha_t * ha) 595062306a36Sopenharmony_ci{ 595162306a36Sopenharmony_ci ips_scb_t *scb; 595262306a36Sopenharmony_ci 595362306a36Sopenharmony_ci METHOD_TRACE("ips_ffdc_time", 1); 595462306a36Sopenharmony_ci 595562306a36Sopenharmony_ci DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num); 595662306a36Sopenharmony_ci 595762306a36Sopenharmony_ci scb = &ha->scbs[ha->max_cmds - 1]; 595862306a36Sopenharmony_ci 595962306a36Sopenharmony_ci ips_init_scb(ha, scb); 596062306a36Sopenharmony_ci 596162306a36Sopenharmony_ci scb->timeout = ips_cmd_timeout; 596262306a36Sopenharmony_ci scb->cdb[0] = IPS_CMD_FFDC; 596362306a36Sopenharmony_ci scb->cmd.ffdc.op_code = IPS_CMD_FFDC; 596462306a36Sopenharmony_ci scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); 596562306a36Sopenharmony_ci scb->cmd.ffdc.reset_count = 0; 596662306a36Sopenharmony_ci scb->cmd.ffdc.reset_type = 0; 596762306a36Sopenharmony_ci 596862306a36Sopenharmony_ci /* convert time to what the card wants */ 596962306a36Sopenharmony_ci ips_fix_ffdc_time(ha, scb, ha->last_ffdc); 597062306a36Sopenharmony_ci 597162306a36Sopenharmony_ci /* issue command */ 597262306a36Sopenharmony_ci ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC); 597362306a36Sopenharmony_ci} 597462306a36Sopenharmony_ci 597562306a36Sopenharmony_ci/****************************************************************************/ 597662306a36Sopenharmony_ci/* */ 597762306a36Sopenharmony_ci/* Routine Name: ips_fix_ffdc_time */ 597862306a36Sopenharmony_ci/* */ 597962306a36Sopenharmony_ci/* Routine Description: */ 598062306a36Sopenharmony_ci/* Adjust time_t to what the card wants */ 598162306a36Sopenharmony_ci/* */ 598262306a36Sopenharmony_ci/****************************************************************************/ 598362306a36Sopenharmony_cistatic void 598462306a36Sopenharmony_ciips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time64_t current_time) 598562306a36Sopenharmony_ci{ 598662306a36Sopenharmony_ci struct tm tm; 598762306a36Sopenharmony_ci 598862306a36Sopenharmony_ci METHOD_TRACE("ips_fix_ffdc_time", 1); 598962306a36Sopenharmony_ci 599062306a36Sopenharmony_ci time64_to_tm(current_time, 0, &tm); 599162306a36Sopenharmony_ci 599262306a36Sopenharmony_ci scb->cmd.ffdc.hour = tm.tm_hour; 599362306a36Sopenharmony_ci scb->cmd.ffdc.minute = tm.tm_min; 599462306a36Sopenharmony_ci scb->cmd.ffdc.second = tm.tm_sec; 599562306a36Sopenharmony_ci scb->cmd.ffdc.yearH = (tm.tm_year + 1900) / 100; 599662306a36Sopenharmony_ci scb->cmd.ffdc.yearL = tm.tm_year % 100; 599762306a36Sopenharmony_ci scb->cmd.ffdc.month = tm.tm_mon + 1; 599862306a36Sopenharmony_ci scb->cmd.ffdc.day = tm.tm_mday; 599962306a36Sopenharmony_ci} 600062306a36Sopenharmony_ci 600162306a36Sopenharmony_ci/**************************************************************************** 600262306a36Sopenharmony_ci * BIOS Flash Routines * 600362306a36Sopenharmony_ci ****************************************************************************/ 600462306a36Sopenharmony_ci 600562306a36Sopenharmony_ci/****************************************************************************/ 600662306a36Sopenharmony_ci/* */ 600762306a36Sopenharmony_ci/* Routine Name: ips_erase_bios */ 600862306a36Sopenharmony_ci/* */ 600962306a36Sopenharmony_ci/* Routine Description: */ 601062306a36Sopenharmony_ci/* Erase the BIOS on the adapter */ 601162306a36Sopenharmony_ci/* */ 601262306a36Sopenharmony_ci/****************************************************************************/ 601362306a36Sopenharmony_cistatic int 601462306a36Sopenharmony_ciips_erase_bios(ips_ha_t * ha) 601562306a36Sopenharmony_ci{ 601662306a36Sopenharmony_ci int timeout; 601762306a36Sopenharmony_ci uint8_t status = 0; 601862306a36Sopenharmony_ci 601962306a36Sopenharmony_ci METHOD_TRACE("ips_erase_bios", 1); 602062306a36Sopenharmony_ci 602162306a36Sopenharmony_ci status = 0; 602262306a36Sopenharmony_ci 602362306a36Sopenharmony_ci /* Clear the status register */ 602462306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 602562306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 602662306a36Sopenharmony_ci udelay(25); /* 25 us */ 602762306a36Sopenharmony_ci 602862306a36Sopenharmony_ci outb(0x50, ha->io_addr + IPS_REG_FLDP); 602962306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 603062306a36Sopenharmony_ci udelay(25); /* 25 us */ 603162306a36Sopenharmony_ci 603262306a36Sopenharmony_ci /* Erase Setup */ 603362306a36Sopenharmony_ci outb(0x20, ha->io_addr + IPS_REG_FLDP); 603462306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 603562306a36Sopenharmony_ci udelay(25); /* 25 us */ 603662306a36Sopenharmony_ci 603762306a36Sopenharmony_ci /* Erase Confirm */ 603862306a36Sopenharmony_ci outb(0xD0, ha->io_addr + IPS_REG_FLDP); 603962306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 604062306a36Sopenharmony_ci udelay(25); /* 25 us */ 604162306a36Sopenharmony_ci 604262306a36Sopenharmony_ci /* Erase Status */ 604362306a36Sopenharmony_ci outb(0x70, ha->io_addr + IPS_REG_FLDP); 604462306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 604562306a36Sopenharmony_ci udelay(25); /* 25 us */ 604662306a36Sopenharmony_ci 604762306a36Sopenharmony_ci timeout = 80000; /* 80 seconds */ 604862306a36Sopenharmony_ci 604962306a36Sopenharmony_ci while (timeout > 0) { 605062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { 605162306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 605262306a36Sopenharmony_ci udelay(25); /* 25 us */ 605362306a36Sopenharmony_ci } 605462306a36Sopenharmony_ci 605562306a36Sopenharmony_ci status = inb(ha->io_addr + IPS_REG_FLDP); 605662306a36Sopenharmony_ci 605762306a36Sopenharmony_ci if (status & 0x80) 605862306a36Sopenharmony_ci break; 605962306a36Sopenharmony_ci 606062306a36Sopenharmony_ci MDELAY(1); 606162306a36Sopenharmony_ci timeout--; 606262306a36Sopenharmony_ci } 606362306a36Sopenharmony_ci 606462306a36Sopenharmony_ci /* check for timeout */ 606562306a36Sopenharmony_ci if (timeout <= 0) { 606662306a36Sopenharmony_ci /* timeout */ 606762306a36Sopenharmony_ci 606862306a36Sopenharmony_ci /* try to suspend the erase */ 606962306a36Sopenharmony_ci outb(0xB0, ha->io_addr + IPS_REG_FLDP); 607062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 607162306a36Sopenharmony_ci udelay(25); /* 25 us */ 607262306a36Sopenharmony_ci 607362306a36Sopenharmony_ci /* wait for 10 seconds */ 607462306a36Sopenharmony_ci timeout = 10000; 607562306a36Sopenharmony_ci while (timeout > 0) { 607662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { 607762306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 607862306a36Sopenharmony_ci udelay(25); /* 25 us */ 607962306a36Sopenharmony_ci } 608062306a36Sopenharmony_ci 608162306a36Sopenharmony_ci status = inb(ha->io_addr + IPS_REG_FLDP); 608262306a36Sopenharmony_ci 608362306a36Sopenharmony_ci if (status & 0xC0) 608462306a36Sopenharmony_ci break; 608562306a36Sopenharmony_ci 608662306a36Sopenharmony_ci MDELAY(1); 608762306a36Sopenharmony_ci timeout--; 608862306a36Sopenharmony_ci } 608962306a36Sopenharmony_ci 609062306a36Sopenharmony_ci return (1); 609162306a36Sopenharmony_ci } 609262306a36Sopenharmony_ci 609362306a36Sopenharmony_ci /* check for valid VPP */ 609462306a36Sopenharmony_ci if (status & 0x08) 609562306a36Sopenharmony_ci /* VPP failure */ 609662306a36Sopenharmony_ci return (1); 609762306a36Sopenharmony_ci 609862306a36Sopenharmony_ci /* check for successful flash */ 609962306a36Sopenharmony_ci if (status & 0x30) 610062306a36Sopenharmony_ci /* sequence error */ 610162306a36Sopenharmony_ci return (1); 610262306a36Sopenharmony_ci 610362306a36Sopenharmony_ci /* Otherwise, we were successful */ 610462306a36Sopenharmony_ci /* clear status */ 610562306a36Sopenharmony_ci outb(0x50, ha->io_addr + IPS_REG_FLDP); 610662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 610762306a36Sopenharmony_ci udelay(25); /* 25 us */ 610862306a36Sopenharmony_ci 610962306a36Sopenharmony_ci /* enable reads */ 611062306a36Sopenharmony_ci outb(0xFF, ha->io_addr + IPS_REG_FLDP); 611162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 611262306a36Sopenharmony_ci udelay(25); /* 25 us */ 611362306a36Sopenharmony_ci 611462306a36Sopenharmony_ci return (0); 611562306a36Sopenharmony_ci} 611662306a36Sopenharmony_ci 611762306a36Sopenharmony_ci/****************************************************************************/ 611862306a36Sopenharmony_ci/* */ 611962306a36Sopenharmony_ci/* Routine Name: ips_erase_bios_memio */ 612062306a36Sopenharmony_ci/* */ 612162306a36Sopenharmony_ci/* Routine Description: */ 612262306a36Sopenharmony_ci/* Erase the BIOS on the adapter */ 612362306a36Sopenharmony_ci/* */ 612462306a36Sopenharmony_ci/****************************************************************************/ 612562306a36Sopenharmony_cistatic int 612662306a36Sopenharmony_ciips_erase_bios_memio(ips_ha_t * ha) 612762306a36Sopenharmony_ci{ 612862306a36Sopenharmony_ci int timeout; 612962306a36Sopenharmony_ci uint8_t status; 613062306a36Sopenharmony_ci 613162306a36Sopenharmony_ci METHOD_TRACE("ips_erase_bios_memio", 1); 613262306a36Sopenharmony_ci 613362306a36Sopenharmony_ci status = 0; 613462306a36Sopenharmony_ci 613562306a36Sopenharmony_ci /* Clear the status register */ 613662306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 613762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 613862306a36Sopenharmony_ci udelay(25); /* 25 us */ 613962306a36Sopenharmony_ci 614062306a36Sopenharmony_ci writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); 614162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 614262306a36Sopenharmony_ci udelay(25); /* 25 us */ 614362306a36Sopenharmony_ci 614462306a36Sopenharmony_ci /* Erase Setup */ 614562306a36Sopenharmony_ci writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); 614662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 614762306a36Sopenharmony_ci udelay(25); /* 25 us */ 614862306a36Sopenharmony_ci 614962306a36Sopenharmony_ci /* Erase Confirm */ 615062306a36Sopenharmony_ci writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); 615162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 615262306a36Sopenharmony_ci udelay(25); /* 25 us */ 615362306a36Sopenharmony_ci 615462306a36Sopenharmony_ci /* Erase Status */ 615562306a36Sopenharmony_ci writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); 615662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 615762306a36Sopenharmony_ci udelay(25); /* 25 us */ 615862306a36Sopenharmony_ci 615962306a36Sopenharmony_ci timeout = 80000; /* 80 seconds */ 616062306a36Sopenharmony_ci 616162306a36Sopenharmony_ci while (timeout > 0) { 616262306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { 616362306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 616462306a36Sopenharmony_ci udelay(25); /* 25 us */ 616562306a36Sopenharmony_ci } 616662306a36Sopenharmony_ci 616762306a36Sopenharmony_ci status = readb(ha->mem_ptr + IPS_REG_FLDP); 616862306a36Sopenharmony_ci 616962306a36Sopenharmony_ci if (status & 0x80) 617062306a36Sopenharmony_ci break; 617162306a36Sopenharmony_ci 617262306a36Sopenharmony_ci MDELAY(1); 617362306a36Sopenharmony_ci timeout--; 617462306a36Sopenharmony_ci } 617562306a36Sopenharmony_ci 617662306a36Sopenharmony_ci /* check for timeout */ 617762306a36Sopenharmony_ci if (timeout <= 0) { 617862306a36Sopenharmony_ci /* timeout */ 617962306a36Sopenharmony_ci 618062306a36Sopenharmony_ci /* try to suspend the erase */ 618162306a36Sopenharmony_ci writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); 618262306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 618362306a36Sopenharmony_ci udelay(25); /* 25 us */ 618462306a36Sopenharmony_ci 618562306a36Sopenharmony_ci /* wait for 10 seconds */ 618662306a36Sopenharmony_ci timeout = 10000; 618762306a36Sopenharmony_ci while (timeout > 0) { 618862306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { 618962306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 619062306a36Sopenharmony_ci udelay(25); /* 25 us */ 619162306a36Sopenharmony_ci } 619262306a36Sopenharmony_ci 619362306a36Sopenharmony_ci status = readb(ha->mem_ptr + IPS_REG_FLDP); 619462306a36Sopenharmony_ci 619562306a36Sopenharmony_ci if (status & 0xC0) 619662306a36Sopenharmony_ci break; 619762306a36Sopenharmony_ci 619862306a36Sopenharmony_ci MDELAY(1); 619962306a36Sopenharmony_ci timeout--; 620062306a36Sopenharmony_ci } 620162306a36Sopenharmony_ci 620262306a36Sopenharmony_ci return (1); 620362306a36Sopenharmony_ci } 620462306a36Sopenharmony_ci 620562306a36Sopenharmony_ci /* check for valid VPP */ 620662306a36Sopenharmony_ci if (status & 0x08) 620762306a36Sopenharmony_ci /* VPP failure */ 620862306a36Sopenharmony_ci return (1); 620962306a36Sopenharmony_ci 621062306a36Sopenharmony_ci /* check for successful flash */ 621162306a36Sopenharmony_ci if (status & 0x30) 621262306a36Sopenharmony_ci /* sequence error */ 621362306a36Sopenharmony_ci return (1); 621462306a36Sopenharmony_ci 621562306a36Sopenharmony_ci /* Otherwise, we were successful */ 621662306a36Sopenharmony_ci /* clear status */ 621762306a36Sopenharmony_ci writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); 621862306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 621962306a36Sopenharmony_ci udelay(25); /* 25 us */ 622062306a36Sopenharmony_ci 622162306a36Sopenharmony_ci /* enable reads */ 622262306a36Sopenharmony_ci writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 622362306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 622462306a36Sopenharmony_ci udelay(25); /* 25 us */ 622562306a36Sopenharmony_ci 622662306a36Sopenharmony_ci return (0); 622762306a36Sopenharmony_ci} 622862306a36Sopenharmony_ci 622962306a36Sopenharmony_ci/****************************************************************************/ 623062306a36Sopenharmony_ci/* */ 623162306a36Sopenharmony_ci/* Routine Name: ips_program_bios */ 623262306a36Sopenharmony_ci/* */ 623362306a36Sopenharmony_ci/* Routine Description: */ 623462306a36Sopenharmony_ci/* Program the BIOS on the adapter */ 623562306a36Sopenharmony_ci/* */ 623662306a36Sopenharmony_ci/****************************************************************************/ 623762306a36Sopenharmony_cistatic int 623862306a36Sopenharmony_ciips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, 623962306a36Sopenharmony_ci uint32_t offset) 624062306a36Sopenharmony_ci{ 624162306a36Sopenharmony_ci int i; 624262306a36Sopenharmony_ci int timeout; 624362306a36Sopenharmony_ci uint8_t status = 0; 624462306a36Sopenharmony_ci 624562306a36Sopenharmony_ci METHOD_TRACE("ips_program_bios", 1); 624662306a36Sopenharmony_ci 624762306a36Sopenharmony_ci status = 0; 624862306a36Sopenharmony_ci 624962306a36Sopenharmony_ci for (i = 0; i < buffersize; i++) { 625062306a36Sopenharmony_ci /* write a byte */ 625162306a36Sopenharmony_ci outl(i + offset, ha->io_addr + IPS_REG_FLAP); 625262306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 625362306a36Sopenharmony_ci udelay(25); /* 25 us */ 625462306a36Sopenharmony_ci 625562306a36Sopenharmony_ci outb(0x40, ha->io_addr + IPS_REG_FLDP); 625662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 625762306a36Sopenharmony_ci udelay(25); /* 25 us */ 625862306a36Sopenharmony_ci 625962306a36Sopenharmony_ci outb(buffer[i], ha->io_addr + IPS_REG_FLDP); 626062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 626162306a36Sopenharmony_ci udelay(25); /* 25 us */ 626262306a36Sopenharmony_ci 626362306a36Sopenharmony_ci /* wait up to one second */ 626462306a36Sopenharmony_ci timeout = 1000; 626562306a36Sopenharmony_ci while (timeout > 0) { 626662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { 626762306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 626862306a36Sopenharmony_ci udelay(25); /* 25 us */ 626962306a36Sopenharmony_ci } 627062306a36Sopenharmony_ci 627162306a36Sopenharmony_ci status = inb(ha->io_addr + IPS_REG_FLDP); 627262306a36Sopenharmony_ci 627362306a36Sopenharmony_ci if (status & 0x80) 627462306a36Sopenharmony_ci break; 627562306a36Sopenharmony_ci 627662306a36Sopenharmony_ci MDELAY(1); 627762306a36Sopenharmony_ci timeout--; 627862306a36Sopenharmony_ci } 627962306a36Sopenharmony_ci 628062306a36Sopenharmony_ci if (timeout == 0) { 628162306a36Sopenharmony_ci /* timeout error */ 628262306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 628362306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 628462306a36Sopenharmony_ci udelay(25); /* 25 us */ 628562306a36Sopenharmony_ci 628662306a36Sopenharmony_ci outb(0xFF, ha->io_addr + IPS_REG_FLDP); 628762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 628862306a36Sopenharmony_ci udelay(25); /* 25 us */ 628962306a36Sopenharmony_ci 629062306a36Sopenharmony_ci return (1); 629162306a36Sopenharmony_ci } 629262306a36Sopenharmony_ci 629362306a36Sopenharmony_ci /* check the status */ 629462306a36Sopenharmony_ci if (status & 0x18) { 629562306a36Sopenharmony_ci /* programming error */ 629662306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 629762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 629862306a36Sopenharmony_ci udelay(25); /* 25 us */ 629962306a36Sopenharmony_ci 630062306a36Sopenharmony_ci outb(0xFF, ha->io_addr + IPS_REG_FLDP); 630162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 630262306a36Sopenharmony_ci udelay(25); /* 25 us */ 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci return (1); 630562306a36Sopenharmony_ci } 630662306a36Sopenharmony_ci } /* end for */ 630762306a36Sopenharmony_ci 630862306a36Sopenharmony_ci /* Enable reading */ 630962306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 631062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 631162306a36Sopenharmony_ci udelay(25); /* 25 us */ 631262306a36Sopenharmony_ci 631362306a36Sopenharmony_ci outb(0xFF, ha->io_addr + IPS_REG_FLDP); 631462306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 631562306a36Sopenharmony_ci udelay(25); /* 25 us */ 631662306a36Sopenharmony_ci 631762306a36Sopenharmony_ci return (0); 631862306a36Sopenharmony_ci} 631962306a36Sopenharmony_ci 632062306a36Sopenharmony_ci/****************************************************************************/ 632162306a36Sopenharmony_ci/* */ 632262306a36Sopenharmony_ci/* Routine Name: ips_program_bios_memio */ 632362306a36Sopenharmony_ci/* */ 632462306a36Sopenharmony_ci/* Routine Description: */ 632562306a36Sopenharmony_ci/* Program the BIOS on the adapter */ 632662306a36Sopenharmony_ci/* */ 632762306a36Sopenharmony_ci/****************************************************************************/ 632862306a36Sopenharmony_cistatic int 632962306a36Sopenharmony_ciips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, 633062306a36Sopenharmony_ci uint32_t offset) 633162306a36Sopenharmony_ci{ 633262306a36Sopenharmony_ci int i; 633362306a36Sopenharmony_ci int timeout; 633462306a36Sopenharmony_ci uint8_t status = 0; 633562306a36Sopenharmony_ci 633662306a36Sopenharmony_ci METHOD_TRACE("ips_program_bios_memio", 1); 633762306a36Sopenharmony_ci 633862306a36Sopenharmony_ci status = 0; 633962306a36Sopenharmony_ci 634062306a36Sopenharmony_ci for (i = 0; i < buffersize; i++) { 634162306a36Sopenharmony_ci /* write a byte */ 634262306a36Sopenharmony_ci writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); 634362306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 634462306a36Sopenharmony_ci udelay(25); /* 25 us */ 634562306a36Sopenharmony_ci 634662306a36Sopenharmony_ci writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); 634762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 634862306a36Sopenharmony_ci udelay(25); /* 25 us */ 634962306a36Sopenharmony_ci 635062306a36Sopenharmony_ci writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); 635162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 635262306a36Sopenharmony_ci udelay(25); /* 25 us */ 635362306a36Sopenharmony_ci 635462306a36Sopenharmony_ci /* wait up to one second */ 635562306a36Sopenharmony_ci timeout = 1000; 635662306a36Sopenharmony_ci while (timeout > 0) { 635762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { 635862306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 635962306a36Sopenharmony_ci udelay(25); /* 25 us */ 636062306a36Sopenharmony_ci } 636162306a36Sopenharmony_ci 636262306a36Sopenharmony_ci status = readb(ha->mem_ptr + IPS_REG_FLDP); 636362306a36Sopenharmony_ci 636462306a36Sopenharmony_ci if (status & 0x80) 636562306a36Sopenharmony_ci break; 636662306a36Sopenharmony_ci 636762306a36Sopenharmony_ci MDELAY(1); 636862306a36Sopenharmony_ci timeout--; 636962306a36Sopenharmony_ci } 637062306a36Sopenharmony_ci 637162306a36Sopenharmony_ci if (timeout == 0) { 637262306a36Sopenharmony_ci /* timeout error */ 637362306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 637462306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 637562306a36Sopenharmony_ci udelay(25); /* 25 us */ 637662306a36Sopenharmony_ci 637762306a36Sopenharmony_ci writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 637862306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 637962306a36Sopenharmony_ci udelay(25); /* 25 us */ 638062306a36Sopenharmony_ci 638162306a36Sopenharmony_ci return (1); 638262306a36Sopenharmony_ci } 638362306a36Sopenharmony_ci 638462306a36Sopenharmony_ci /* check the status */ 638562306a36Sopenharmony_ci if (status & 0x18) { 638662306a36Sopenharmony_ci /* programming error */ 638762306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 638862306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 638962306a36Sopenharmony_ci udelay(25); /* 25 us */ 639062306a36Sopenharmony_ci 639162306a36Sopenharmony_ci writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 639262306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 639362306a36Sopenharmony_ci udelay(25); /* 25 us */ 639462306a36Sopenharmony_ci 639562306a36Sopenharmony_ci return (1); 639662306a36Sopenharmony_ci } 639762306a36Sopenharmony_ci } /* end for */ 639862306a36Sopenharmony_ci 639962306a36Sopenharmony_ci /* Enable reading */ 640062306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 640162306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 640262306a36Sopenharmony_ci udelay(25); /* 25 us */ 640362306a36Sopenharmony_ci 640462306a36Sopenharmony_ci writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); 640562306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 640662306a36Sopenharmony_ci udelay(25); /* 25 us */ 640762306a36Sopenharmony_ci 640862306a36Sopenharmony_ci return (0); 640962306a36Sopenharmony_ci} 641062306a36Sopenharmony_ci 641162306a36Sopenharmony_ci/****************************************************************************/ 641262306a36Sopenharmony_ci/* */ 641362306a36Sopenharmony_ci/* Routine Name: ips_verify_bios */ 641462306a36Sopenharmony_ci/* */ 641562306a36Sopenharmony_ci/* Routine Description: */ 641662306a36Sopenharmony_ci/* Verify the BIOS on the adapter */ 641762306a36Sopenharmony_ci/* */ 641862306a36Sopenharmony_ci/****************************************************************************/ 641962306a36Sopenharmony_cistatic int 642062306a36Sopenharmony_ciips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, 642162306a36Sopenharmony_ci uint32_t offset) 642262306a36Sopenharmony_ci{ 642362306a36Sopenharmony_ci uint8_t checksum; 642462306a36Sopenharmony_ci int i; 642562306a36Sopenharmony_ci 642662306a36Sopenharmony_ci METHOD_TRACE("ips_verify_bios", 1); 642762306a36Sopenharmony_ci 642862306a36Sopenharmony_ci /* test 1st byte */ 642962306a36Sopenharmony_ci outl(0, ha->io_addr + IPS_REG_FLAP); 643062306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 643162306a36Sopenharmony_ci udelay(25); /* 25 us */ 643262306a36Sopenharmony_ci 643362306a36Sopenharmony_ci if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) 643462306a36Sopenharmony_ci return (1); 643562306a36Sopenharmony_ci 643662306a36Sopenharmony_ci outl(1, ha->io_addr + IPS_REG_FLAP); 643762306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 643862306a36Sopenharmony_ci udelay(25); /* 25 us */ 643962306a36Sopenharmony_ci if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) 644062306a36Sopenharmony_ci return (1); 644162306a36Sopenharmony_ci 644262306a36Sopenharmony_ci checksum = 0xff; 644362306a36Sopenharmony_ci for (i = 2; i < buffersize; i++) { 644462306a36Sopenharmony_ci 644562306a36Sopenharmony_ci outl(i + offset, ha->io_addr + IPS_REG_FLAP); 644662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 644762306a36Sopenharmony_ci udelay(25); /* 25 us */ 644862306a36Sopenharmony_ci 644962306a36Sopenharmony_ci checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); 645062306a36Sopenharmony_ci } 645162306a36Sopenharmony_ci 645262306a36Sopenharmony_ci if (checksum != 0) 645362306a36Sopenharmony_ci /* failure */ 645462306a36Sopenharmony_ci return (1); 645562306a36Sopenharmony_ci else 645662306a36Sopenharmony_ci /* success */ 645762306a36Sopenharmony_ci return (0); 645862306a36Sopenharmony_ci} 645962306a36Sopenharmony_ci 646062306a36Sopenharmony_ci/****************************************************************************/ 646162306a36Sopenharmony_ci/* */ 646262306a36Sopenharmony_ci/* Routine Name: ips_verify_bios_memio */ 646362306a36Sopenharmony_ci/* */ 646462306a36Sopenharmony_ci/* Routine Description: */ 646562306a36Sopenharmony_ci/* Verify the BIOS on the adapter */ 646662306a36Sopenharmony_ci/* */ 646762306a36Sopenharmony_ci/****************************************************************************/ 646862306a36Sopenharmony_cistatic int 646962306a36Sopenharmony_ciips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, 647062306a36Sopenharmony_ci uint32_t offset) 647162306a36Sopenharmony_ci{ 647262306a36Sopenharmony_ci uint8_t checksum; 647362306a36Sopenharmony_ci int i; 647462306a36Sopenharmony_ci 647562306a36Sopenharmony_ci METHOD_TRACE("ips_verify_bios_memio", 1); 647662306a36Sopenharmony_ci 647762306a36Sopenharmony_ci /* test 1st byte */ 647862306a36Sopenharmony_ci writel(0, ha->mem_ptr + IPS_REG_FLAP); 647962306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 648062306a36Sopenharmony_ci udelay(25); /* 25 us */ 648162306a36Sopenharmony_ci 648262306a36Sopenharmony_ci if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) 648362306a36Sopenharmony_ci return (1); 648462306a36Sopenharmony_ci 648562306a36Sopenharmony_ci writel(1, ha->mem_ptr + IPS_REG_FLAP); 648662306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 648762306a36Sopenharmony_ci udelay(25); /* 25 us */ 648862306a36Sopenharmony_ci if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) 648962306a36Sopenharmony_ci return (1); 649062306a36Sopenharmony_ci 649162306a36Sopenharmony_ci checksum = 0xff; 649262306a36Sopenharmony_ci for (i = 2; i < buffersize; i++) { 649362306a36Sopenharmony_ci 649462306a36Sopenharmony_ci writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); 649562306a36Sopenharmony_ci if (ha->pcidev->revision == IPS_REVID_TROMBONE64) 649662306a36Sopenharmony_ci udelay(25); /* 25 us */ 649762306a36Sopenharmony_ci 649862306a36Sopenharmony_ci checksum = 649962306a36Sopenharmony_ci (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); 650062306a36Sopenharmony_ci } 650162306a36Sopenharmony_ci 650262306a36Sopenharmony_ci if (checksum != 0) 650362306a36Sopenharmony_ci /* failure */ 650462306a36Sopenharmony_ci return (1); 650562306a36Sopenharmony_ci else 650662306a36Sopenharmony_ci /* success */ 650762306a36Sopenharmony_ci return (0); 650862306a36Sopenharmony_ci} 650962306a36Sopenharmony_ci 651062306a36Sopenharmony_ci/****************************************************************************/ 651162306a36Sopenharmony_ci/* */ 651262306a36Sopenharmony_ci/* Routine Name: ips_abort_init */ 651362306a36Sopenharmony_ci/* */ 651462306a36Sopenharmony_ci/* Routine Description: */ 651562306a36Sopenharmony_ci/* cleanup routine for a failed adapter initialization */ 651662306a36Sopenharmony_ci/****************************************************************************/ 651762306a36Sopenharmony_cistatic int 651862306a36Sopenharmony_ciips_abort_init(ips_ha_t * ha, int index) 651962306a36Sopenharmony_ci{ 652062306a36Sopenharmony_ci ha->active = 0; 652162306a36Sopenharmony_ci ips_free(ha); 652262306a36Sopenharmony_ci ips_ha[index] = NULL; 652362306a36Sopenharmony_ci ips_sh[index] = NULL; 652462306a36Sopenharmony_ci return -1; 652562306a36Sopenharmony_ci} 652662306a36Sopenharmony_ci 652762306a36Sopenharmony_ci/****************************************************************************/ 652862306a36Sopenharmony_ci/* */ 652962306a36Sopenharmony_ci/* Routine Name: ips_shift_controllers */ 653062306a36Sopenharmony_ci/* */ 653162306a36Sopenharmony_ci/* Routine Description: */ 653262306a36Sopenharmony_ci/* helper function for ordering adapters */ 653362306a36Sopenharmony_ci/****************************************************************************/ 653462306a36Sopenharmony_cistatic void 653562306a36Sopenharmony_ciips_shift_controllers(int lowindex, int highindex) 653662306a36Sopenharmony_ci{ 653762306a36Sopenharmony_ci ips_ha_t *ha_sav = ips_ha[highindex]; 653862306a36Sopenharmony_ci struct Scsi_Host *sh_sav = ips_sh[highindex]; 653962306a36Sopenharmony_ci int i; 654062306a36Sopenharmony_ci 654162306a36Sopenharmony_ci for (i = highindex; i > lowindex; i--) { 654262306a36Sopenharmony_ci ips_ha[i] = ips_ha[i - 1]; 654362306a36Sopenharmony_ci ips_sh[i] = ips_sh[i - 1]; 654462306a36Sopenharmony_ci ips_ha[i]->host_num = i; 654562306a36Sopenharmony_ci } 654662306a36Sopenharmony_ci ha_sav->host_num = lowindex; 654762306a36Sopenharmony_ci ips_ha[lowindex] = ha_sav; 654862306a36Sopenharmony_ci ips_sh[lowindex] = sh_sav; 654962306a36Sopenharmony_ci} 655062306a36Sopenharmony_ci 655162306a36Sopenharmony_ci/****************************************************************************/ 655262306a36Sopenharmony_ci/* */ 655362306a36Sopenharmony_ci/* Routine Name: ips_order_controllers */ 655462306a36Sopenharmony_ci/* */ 655562306a36Sopenharmony_ci/* Routine Description: */ 655662306a36Sopenharmony_ci/* place controllers is the "proper" boot order */ 655762306a36Sopenharmony_ci/****************************************************************************/ 655862306a36Sopenharmony_cistatic void 655962306a36Sopenharmony_ciips_order_controllers(void) 656062306a36Sopenharmony_ci{ 656162306a36Sopenharmony_ci int i, j, tmp, position = 0; 656262306a36Sopenharmony_ci IPS_NVRAM_P5 *nvram; 656362306a36Sopenharmony_ci if (!ips_ha[0]) 656462306a36Sopenharmony_ci return; 656562306a36Sopenharmony_ci nvram = ips_ha[0]->nvram; 656662306a36Sopenharmony_ci 656762306a36Sopenharmony_ci if (nvram->adapter_order[0]) { 656862306a36Sopenharmony_ci for (i = 1; i <= nvram->adapter_order[0]; i++) { 656962306a36Sopenharmony_ci for (j = position; j < ips_num_controllers; j++) { 657062306a36Sopenharmony_ci switch (ips_ha[j]->ad_type) { 657162306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID6M: 657262306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID7M: 657362306a36Sopenharmony_ci if (nvram->adapter_order[i] == 'M') { 657462306a36Sopenharmony_ci ips_shift_controllers(position, 657562306a36Sopenharmony_ci j); 657662306a36Sopenharmony_ci position++; 657762306a36Sopenharmony_ci } 657862306a36Sopenharmony_ci break; 657962306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID4L: 658062306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID4M: 658162306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID4MX: 658262306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID4LX: 658362306a36Sopenharmony_ci if (nvram->adapter_order[i] == 'N') { 658462306a36Sopenharmony_ci ips_shift_controllers(position, 658562306a36Sopenharmony_ci j); 658662306a36Sopenharmony_ci position++; 658762306a36Sopenharmony_ci } 658862306a36Sopenharmony_ci break; 658962306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID6I: 659062306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID5I2: 659162306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID5I1: 659262306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID7k: 659362306a36Sopenharmony_ci if (nvram->adapter_order[i] == 'S') { 659462306a36Sopenharmony_ci ips_shift_controllers(position, 659562306a36Sopenharmony_ci j); 659662306a36Sopenharmony_ci position++; 659762306a36Sopenharmony_ci } 659862306a36Sopenharmony_ci break; 659962306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID: 660062306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID2: 660162306a36Sopenharmony_ci case IPS_ADTYPE_NAVAJO: 660262306a36Sopenharmony_ci case IPS_ADTYPE_KIOWA: 660362306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID3L: 660462306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID3: 660562306a36Sopenharmony_ci case IPS_ADTYPE_SERVERAID4H: 660662306a36Sopenharmony_ci if (nvram->adapter_order[i] == 'A') { 660762306a36Sopenharmony_ci ips_shift_controllers(position, 660862306a36Sopenharmony_ci j); 660962306a36Sopenharmony_ci position++; 661062306a36Sopenharmony_ci } 661162306a36Sopenharmony_ci break; 661262306a36Sopenharmony_ci default: 661362306a36Sopenharmony_ci break; 661462306a36Sopenharmony_ci } 661562306a36Sopenharmony_ci } 661662306a36Sopenharmony_ci } 661762306a36Sopenharmony_ci /* if adapter_order[0], then ordering is complete */ 661862306a36Sopenharmony_ci return; 661962306a36Sopenharmony_ci } 662062306a36Sopenharmony_ci /* old bios, use older ordering */ 662162306a36Sopenharmony_ci tmp = 0; 662262306a36Sopenharmony_ci for (i = position; i < ips_num_controllers; i++) { 662362306a36Sopenharmony_ci if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 || 662462306a36Sopenharmony_ci ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) { 662562306a36Sopenharmony_ci ips_shift_controllers(position, i); 662662306a36Sopenharmony_ci position++; 662762306a36Sopenharmony_ci tmp = 1; 662862306a36Sopenharmony_ci } 662962306a36Sopenharmony_ci } 663062306a36Sopenharmony_ci /* if there were no 5I cards, then don't do any extra ordering */ 663162306a36Sopenharmony_ci if (!tmp) 663262306a36Sopenharmony_ci return; 663362306a36Sopenharmony_ci for (i = position; i < ips_num_controllers; i++) { 663462306a36Sopenharmony_ci if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L || 663562306a36Sopenharmony_ci ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M || 663662306a36Sopenharmony_ci ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX || 663762306a36Sopenharmony_ci ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) { 663862306a36Sopenharmony_ci ips_shift_controllers(position, i); 663962306a36Sopenharmony_ci position++; 664062306a36Sopenharmony_ci } 664162306a36Sopenharmony_ci } 664262306a36Sopenharmony_ci 664362306a36Sopenharmony_ci return; 664462306a36Sopenharmony_ci} 664562306a36Sopenharmony_ci 664662306a36Sopenharmony_ci/****************************************************************************/ 664762306a36Sopenharmony_ci/* */ 664862306a36Sopenharmony_ci/* Routine Name: ips_register_scsi */ 664962306a36Sopenharmony_ci/* */ 665062306a36Sopenharmony_ci/* Routine Description: */ 665162306a36Sopenharmony_ci/* perform any registration and setup with the scsi layer */ 665262306a36Sopenharmony_ci/****************************************************************************/ 665362306a36Sopenharmony_cistatic int 665462306a36Sopenharmony_ciips_register_scsi(int index) 665562306a36Sopenharmony_ci{ 665662306a36Sopenharmony_ci struct Scsi_Host *sh; 665762306a36Sopenharmony_ci ips_ha_t *ha, *oldha = ips_ha[index]; 665862306a36Sopenharmony_ci sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t)); 665962306a36Sopenharmony_ci if (!sh) { 666062306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, oldha->pcidev, 666162306a36Sopenharmony_ci "Unable to register controller with SCSI subsystem\n"); 666262306a36Sopenharmony_ci return -1; 666362306a36Sopenharmony_ci } 666462306a36Sopenharmony_ci ha = IPS_HA(sh); 666562306a36Sopenharmony_ci memcpy(ha, oldha, sizeof (ips_ha_t)); 666662306a36Sopenharmony_ci free_irq(oldha->pcidev->irq, oldha); 666762306a36Sopenharmony_ci /* Install the interrupt handler with the new ha */ 666862306a36Sopenharmony_ci if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { 666962306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 667062306a36Sopenharmony_ci "Unable to install interrupt handler\n"); 667162306a36Sopenharmony_ci goto err_out_sh; 667262306a36Sopenharmony_ci } 667362306a36Sopenharmony_ci 667462306a36Sopenharmony_ci kfree(oldha); 667562306a36Sopenharmony_ci 667662306a36Sopenharmony_ci /* Store away needed values for later use */ 667762306a36Sopenharmony_ci sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; 667862306a36Sopenharmony_ci sh->sg_tablesize = sh->hostt->sg_tablesize; 667962306a36Sopenharmony_ci sh->can_queue = sh->hostt->can_queue; 668062306a36Sopenharmony_ci sh->cmd_per_lun = sh->hostt->cmd_per_lun; 668162306a36Sopenharmony_ci sh->max_sectors = 128; 668262306a36Sopenharmony_ci 668362306a36Sopenharmony_ci sh->max_id = ha->ntargets; 668462306a36Sopenharmony_ci sh->max_lun = ha->nlun; 668562306a36Sopenharmony_ci sh->max_channel = ha->nbus - 1; 668662306a36Sopenharmony_ci sh->can_queue = ha->max_cmds - 1; 668762306a36Sopenharmony_ci 668862306a36Sopenharmony_ci if (scsi_add_host(sh, &ha->pcidev->dev)) 668962306a36Sopenharmony_ci goto err_out; 669062306a36Sopenharmony_ci 669162306a36Sopenharmony_ci ips_sh[index] = sh; 669262306a36Sopenharmony_ci ips_ha[index] = ha; 669362306a36Sopenharmony_ci 669462306a36Sopenharmony_ci scsi_scan_host(sh); 669562306a36Sopenharmony_ci 669662306a36Sopenharmony_ci return 0; 669762306a36Sopenharmony_ci 669862306a36Sopenharmony_cierr_out: 669962306a36Sopenharmony_ci free_irq(ha->pcidev->irq, ha); 670062306a36Sopenharmony_cierr_out_sh: 670162306a36Sopenharmony_ci scsi_host_put(sh); 670262306a36Sopenharmony_ci return -1; 670362306a36Sopenharmony_ci} 670462306a36Sopenharmony_ci 670562306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 670662306a36Sopenharmony_ci/* Routine Name: ips_remove_device */ 670762306a36Sopenharmony_ci/* */ 670862306a36Sopenharmony_ci/* Routine Description: */ 670962306a36Sopenharmony_ci/* Remove one Adapter ( Hot Plugging ) */ 671062306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 671162306a36Sopenharmony_cistatic void 671262306a36Sopenharmony_ciips_remove_device(struct pci_dev *pci_dev) 671362306a36Sopenharmony_ci{ 671462306a36Sopenharmony_ci struct Scsi_Host *sh = pci_get_drvdata(pci_dev); 671562306a36Sopenharmony_ci 671662306a36Sopenharmony_ci pci_set_drvdata(pci_dev, NULL); 671762306a36Sopenharmony_ci 671862306a36Sopenharmony_ci ips_release(sh); 671962306a36Sopenharmony_ci 672062306a36Sopenharmony_ci pci_release_regions(pci_dev); 672162306a36Sopenharmony_ci pci_disable_device(pci_dev); 672262306a36Sopenharmony_ci} 672362306a36Sopenharmony_ci 672462306a36Sopenharmony_ci/****************************************************************************/ 672562306a36Sopenharmony_ci/* */ 672662306a36Sopenharmony_ci/* Routine Name: ips_module_init */ 672762306a36Sopenharmony_ci/* */ 672862306a36Sopenharmony_ci/* Routine Description: */ 672962306a36Sopenharmony_ci/* function called on module load */ 673062306a36Sopenharmony_ci/****************************************************************************/ 673162306a36Sopenharmony_cistatic int __init 673262306a36Sopenharmony_ciips_module_init(void) 673362306a36Sopenharmony_ci{ 673462306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) 673562306a36Sopenharmony_ci printk(KERN_ERR "ips: This driver has only been tested on the x86/ia64/x86_64 platforms\n"); 673662306a36Sopenharmony_ci add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); 673762306a36Sopenharmony_ci#endif 673862306a36Sopenharmony_ci 673962306a36Sopenharmony_ci if (pci_register_driver(&ips_pci_driver) < 0) 674062306a36Sopenharmony_ci return -ENODEV; 674162306a36Sopenharmony_ci ips_driver_template.module = THIS_MODULE; 674262306a36Sopenharmony_ci ips_order_controllers(); 674362306a36Sopenharmony_ci if (!ips_detect(&ips_driver_template)) { 674462306a36Sopenharmony_ci pci_unregister_driver(&ips_pci_driver); 674562306a36Sopenharmony_ci return -ENODEV; 674662306a36Sopenharmony_ci } 674762306a36Sopenharmony_ci register_reboot_notifier(&ips_notifier); 674862306a36Sopenharmony_ci return 0; 674962306a36Sopenharmony_ci} 675062306a36Sopenharmony_ci 675162306a36Sopenharmony_ci/****************************************************************************/ 675262306a36Sopenharmony_ci/* */ 675362306a36Sopenharmony_ci/* Routine Name: ips_module_exit */ 675462306a36Sopenharmony_ci/* */ 675562306a36Sopenharmony_ci/* Routine Description: */ 675662306a36Sopenharmony_ci/* function called on module unload */ 675762306a36Sopenharmony_ci/****************************************************************************/ 675862306a36Sopenharmony_cistatic void __exit 675962306a36Sopenharmony_ciips_module_exit(void) 676062306a36Sopenharmony_ci{ 676162306a36Sopenharmony_ci pci_unregister_driver(&ips_pci_driver); 676262306a36Sopenharmony_ci unregister_reboot_notifier(&ips_notifier); 676362306a36Sopenharmony_ci} 676462306a36Sopenharmony_ci 676562306a36Sopenharmony_cimodule_init(ips_module_init); 676662306a36Sopenharmony_cimodule_exit(ips_module_exit); 676762306a36Sopenharmony_ci 676862306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 676962306a36Sopenharmony_ci/* Routine Name: ips_insert_device */ 677062306a36Sopenharmony_ci/* */ 677162306a36Sopenharmony_ci/* Routine Description: */ 677262306a36Sopenharmony_ci/* Add One Adapter ( Hot Plug ) */ 677362306a36Sopenharmony_ci/* */ 677462306a36Sopenharmony_ci/* Return Value: */ 677562306a36Sopenharmony_ci/* 0 if Successful, else non-zero */ 677662306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 677762306a36Sopenharmony_cistatic int 677862306a36Sopenharmony_ciips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) 677962306a36Sopenharmony_ci{ 678062306a36Sopenharmony_ci int index = -1; 678162306a36Sopenharmony_ci int rc; 678262306a36Sopenharmony_ci 678362306a36Sopenharmony_ci METHOD_TRACE("ips_insert_device", 1); 678462306a36Sopenharmony_ci rc = pci_enable_device(pci_dev); 678562306a36Sopenharmony_ci if (rc) 678662306a36Sopenharmony_ci return rc; 678762306a36Sopenharmony_ci 678862306a36Sopenharmony_ci rc = pci_request_regions(pci_dev, "ips"); 678962306a36Sopenharmony_ci if (rc) 679062306a36Sopenharmony_ci goto err_out; 679162306a36Sopenharmony_ci 679262306a36Sopenharmony_ci rc = ips_init_phase1(pci_dev, &index); 679362306a36Sopenharmony_ci if (rc == SUCCESS) 679462306a36Sopenharmony_ci rc = ips_init_phase2(index); 679562306a36Sopenharmony_ci 679662306a36Sopenharmony_ci if (ips_hotplug) 679762306a36Sopenharmony_ci if (ips_register_scsi(index)) { 679862306a36Sopenharmony_ci ips_free(ips_ha[index]); 679962306a36Sopenharmony_ci rc = -1; 680062306a36Sopenharmony_ci } 680162306a36Sopenharmony_ci 680262306a36Sopenharmony_ci if (rc == SUCCESS) 680362306a36Sopenharmony_ci ips_num_controllers++; 680462306a36Sopenharmony_ci 680562306a36Sopenharmony_ci ips_next_controller = ips_num_controllers; 680662306a36Sopenharmony_ci 680762306a36Sopenharmony_ci if (rc < 0) { 680862306a36Sopenharmony_ci rc = -ENODEV; 680962306a36Sopenharmony_ci goto err_out_regions; 681062306a36Sopenharmony_ci } 681162306a36Sopenharmony_ci 681262306a36Sopenharmony_ci pci_set_drvdata(pci_dev, ips_sh[index]); 681362306a36Sopenharmony_ci return 0; 681462306a36Sopenharmony_ci 681562306a36Sopenharmony_cierr_out_regions: 681662306a36Sopenharmony_ci pci_release_regions(pci_dev); 681762306a36Sopenharmony_cierr_out: 681862306a36Sopenharmony_ci pci_disable_device(pci_dev); 681962306a36Sopenharmony_ci return rc; 682062306a36Sopenharmony_ci} 682162306a36Sopenharmony_ci 682262306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 682362306a36Sopenharmony_ci/* Routine Name: ips_init_phase1 */ 682462306a36Sopenharmony_ci/* */ 682562306a36Sopenharmony_ci/* Routine Description: */ 682662306a36Sopenharmony_ci/* Adapter Initialization */ 682762306a36Sopenharmony_ci/* */ 682862306a36Sopenharmony_ci/* Return Value: */ 682962306a36Sopenharmony_ci/* 0 if Successful, else non-zero */ 683062306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 683162306a36Sopenharmony_cistatic int 683262306a36Sopenharmony_ciips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) 683362306a36Sopenharmony_ci{ 683462306a36Sopenharmony_ci ips_ha_t *ha; 683562306a36Sopenharmony_ci uint32_t io_addr; 683662306a36Sopenharmony_ci uint32_t mem_addr; 683762306a36Sopenharmony_ci uint32_t io_len; 683862306a36Sopenharmony_ci uint32_t mem_len; 683962306a36Sopenharmony_ci int j; 684062306a36Sopenharmony_ci int index; 684162306a36Sopenharmony_ci dma_addr_t dma_address; 684262306a36Sopenharmony_ci char __iomem *ioremap_ptr; 684362306a36Sopenharmony_ci char __iomem *mem_ptr; 684462306a36Sopenharmony_ci uint32_t IsDead; 684562306a36Sopenharmony_ci 684662306a36Sopenharmony_ci METHOD_TRACE("ips_init_phase1", 1); 684762306a36Sopenharmony_ci index = IPS_MAX_ADAPTERS; 684862306a36Sopenharmony_ci for (j = 0; j < IPS_MAX_ADAPTERS; j++) { 684962306a36Sopenharmony_ci if (ips_ha[j] == NULL) { 685062306a36Sopenharmony_ci index = j; 685162306a36Sopenharmony_ci break; 685262306a36Sopenharmony_ci } 685362306a36Sopenharmony_ci } 685462306a36Sopenharmony_ci 685562306a36Sopenharmony_ci if (index >= IPS_MAX_ADAPTERS) 685662306a36Sopenharmony_ci return -1; 685762306a36Sopenharmony_ci 685862306a36Sopenharmony_ci /* Init MEM/IO addresses to 0 */ 685962306a36Sopenharmony_ci mem_addr = 0; 686062306a36Sopenharmony_ci io_addr = 0; 686162306a36Sopenharmony_ci mem_len = 0; 686262306a36Sopenharmony_ci io_len = 0; 686362306a36Sopenharmony_ci 686462306a36Sopenharmony_ci for (j = 0; j < 2; j++) { 686562306a36Sopenharmony_ci if (!pci_resource_start(pci_dev, j)) 686662306a36Sopenharmony_ci break; 686762306a36Sopenharmony_ci 686862306a36Sopenharmony_ci if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) { 686962306a36Sopenharmony_ci io_addr = pci_resource_start(pci_dev, j); 687062306a36Sopenharmony_ci io_len = pci_resource_len(pci_dev, j); 687162306a36Sopenharmony_ci } else { 687262306a36Sopenharmony_ci mem_addr = pci_resource_start(pci_dev, j); 687362306a36Sopenharmony_ci mem_len = pci_resource_len(pci_dev, j); 687462306a36Sopenharmony_ci } 687562306a36Sopenharmony_ci } 687662306a36Sopenharmony_ci 687762306a36Sopenharmony_ci /* setup memory mapped area (if applicable) */ 687862306a36Sopenharmony_ci if (mem_addr) { 687962306a36Sopenharmony_ci uint32_t base; 688062306a36Sopenharmony_ci uint32_t offs; 688162306a36Sopenharmony_ci 688262306a36Sopenharmony_ci base = mem_addr & PAGE_MASK; 688362306a36Sopenharmony_ci offs = mem_addr - base; 688462306a36Sopenharmony_ci ioremap_ptr = ioremap(base, PAGE_SIZE); 688562306a36Sopenharmony_ci if (!ioremap_ptr) 688662306a36Sopenharmony_ci return -1; 688762306a36Sopenharmony_ci mem_ptr = ioremap_ptr + offs; 688862306a36Sopenharmony_ci } else { 688962306a36Sopenharmony_ci ioremap_ptr = NULL; 689062306a36Sopenharmony_ci mem_ptr = NULL; 689162306a36Sopenharmony_ci } 689262306a36Sopenharmony_ci 689362306a36Sopenharmony_ci /* found a controller */ 689462306a36Sopenharmony_ci ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL); 689562306a36Sopenharmony_ci if (ha == NULL) { 689662306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 689762306a36Sopenharmony_ci "Unable to allocate temporary ha struct\n"); 689862306a36Sopenharmony_ci return -1; 689962306a36Sopenharmony_ci } 690062306a36Sopenharmony_ci 690162306a36Sopenharmony_ci ips_sh[index] = NULL; 690262306a36Sopenharmony_ci ips_ha[index] = ha; 690362306a36Sopenharmony_ci ha->active = 1; 690462306a36Sopenharmony_ci 690562306a36Sopenharmony_ci /* Store info in HA structure */ 690662306a36Sopenharmony_ci ha->io_addr = io_addr; 690762306a36Sopenharmony_ci ha->io_len = io_len; 690862306a36Sopenharmony_ci ha->mem_addr = mem_addr; 690962306a36Sopenharmony_ci ha->mem_len = mem_len; 691062306a36Sopenharmony_ci ha->mem_ptr = mem_ptr; 691162306a36Sopenharmony_ci ha->ioremap_ptr = ioremap_ptr; 691262306a36Sopenharmony_ci ha->host_num = (uint32_t) index; 691362306a36Sopenharmony_ci ha->slot_num = PCI_SLOT(pci_dev->devfn); 691462306a36Sopenharmony_ci ha->pcidev = pci_dev; 691562306a36Sopenharmony_ci 691662306a36Sopenharmony_ci /* 691762306a36Sopenharmony_ci * Set the pci_dev's dma_mask. Not all adapters support 64bit 691862306a36Sopenharmony_ci * addressing so don't enable it if the adapter can't support 691962306a36Sopenharmony_ci * it! Also, don't use 64bit addressing if dma addresses 692062306a36Sopenharmony_ci * are guaranteed to be < 4G. 692162306a36Sopenharmony_ci */ 692262306a36Sopenharmony_ci if (sizeof(dma_addr_t) > 4 && IPS_HAS_ENH_SGLIST(ha) && 692362306a36Sopenharmony_ci !dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(64))) { 692462306a36Sopenharmony_ci (ha)->flags |= IPS_HA_ENH_SG; 692562306a36Sopenharmony_ci } else { 692662306a36Sopenharmony_ci if (dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(32)) != 0) { 692762306a36Sopenharmony_ci printk(KERN_WARNING "Unable to set DMA Mask\n"); 692862306a36Sopenharmony_ci return ips_abort_init(ha, index); 692962306a36Sopenharmony_ci } 693062306a36Sopenharmony_ci } 693162306a36Sopenharmony_ci if(ips_cd_boot && !ips_FlashData){ 693262306a36Sopenharmony_ci ips_FlashData = dma_alloc_coherent(&pci_dev->dev, 693362306a36Sopenharmony_ci PAGE_SIZE << 7, &ips_flashbusaddr, GFP_KERNEL); 693462306a36Sopenharmony_ci } 693562306a36Sopenharmony_ci 693662306a36Sopenharmony_ci ha->enq = dma_alloc_coherent(&pci_dev->dev, sizeof (IPS_ENQ), 693762306a36Sopenharmony_ci &ha->enq_busaddr, GFP_KERNEL); 693862306a36Sopenharmony_ci if (!ha->enq) { 693962306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 694062306a36Sopenharmony_ci "Unable to allocate host inquiry structure\n"); 694162306a36Sopenharmony_ci return ips_abort_init(ha, index); 694262306a36Sopenharmony_ci } 694362306a36Sopenharmony_ci 694462306a36Sopenharmony_ci ha->adapt = dma_alloc_coherent(&pci_dev->dev, 694562306a36Sopenharmony_ci sizeof (IPS_ADAPTER) + sizeof (IPS_IO_CMD), 694662306a36Sopenharmony_ci &dma_address, GFP_KERNEL); 694762306a36Sopenharmony_ci if (!ha->adapt) { 694862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 694962306a36Sopenharmony_ci "Unable to allocate host adapt & dummy structures\n"); 695062306a36Sopenharmony_ci return ips_abort_init(ha, index); 695162306a36Sopenharmony_ci } 695262306a36Sopenharmony_ci ha->adapt->hw_status_start = dma_address; 695362306a36Sopenharmony_ci ha->dummy = (void *) (ha->adapt + 1); 695462306a36Sopenharmony_ci 695562306a36Sopenharmony_ci 695662306a36Sopenharmony_ci 695762306a36Sopenharmony_ci ha->logical_drive_info = dma_alloc_coherent(&pci_dev->dev, 695862306a36Sopenharmony_ci sizeof (IPS_LD_INFO), &dma_address, GFP_KERNEL); 695962306a36Sopenharmony_ci if (!ha->logical_drive_info) { 696062306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 696162306a36Sopenharmony_ci "Unable to allocate logical drive info structure\n"); 696262306a36Sopenharmony_ci return ips_abort_init(ha, index); 696362306a36Sopenharmony_ci } 696462306a36Sopenharmony_ci ha->logical_drive_info_dma_addr = dma_address; 696562306a36Sopenharmony_ci 696662306a36Sopenharmony_ci 696762306a36Sopenharmony_ci ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL); 696862306a36Sopenharmony_ci 696962306a36Sopenharmony_ci if (!ha->conf) { 697062306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 697162306a36Sopenharmony_ci "Unable to allocate host conf structure\n"); 697262306a36Sopenharmony_ci return ips_abort_init(ha, index); 697362306a36Sopenharmony_ci } 697462306a36Sopenharmony_ci 697562306a36Sopenharmony_ci ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL); 697662306a36Sopenharmony_ci 697762306a36Sopenharmony_ci if (!ha->nvram) { 697862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 697962306a36Sopenharmony_ci "Unable to allocate host NVRAM structure\n"); 698062306a36Sopenharmony_ci return ips_abort_init(ha, index); 698162306a36Sopenharmony_ci } 698262306a36Sopenharmony_ci 698362306a36Sopenharmony_ci ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL); 698462306a36Sopenharmony_ci 698562306a36Sopenharmony_ci if (!ha->subsys) { 698662306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 698762306a36Sopenharmony_ci "Unable to allocate host subsystem structure\n"); 698862306a36Sopenharmony_ci return ips_abort_init(ha, index); 698962306a36Sopenharmony_ci } 699062306a36Sopenharmony_ci 699162306a36Sopenharmony_ci /* the ioctl buffer is now used during adapter initialization, so its 699262306a36Sopenharmony_ci * successful allocation is now required */ 699362306a36Sopenharmony_ci if (ips_ioctlsize < PAGE_SIZE) 699462306a36Sopenharmony_ci ips_ioctlsize = PAGE_SIZE; 699562306a36Sopenharmony_ci 699662306a36Sopenharmony_ci ha->ioctl_data = dma_alloc_coherent(&pci_dev->dev, ips_ioctlsize, 699762306a36Sopenharmony_ci &ha->ioctl_busaddr, GFP_KERNEL); 699862306a36Sopenharmony_ci ha->ioctl_len = ips_ioctlsize; 699962306a36Sopenharmony_ci if (!ha->ioctl_data) { 700062306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 700162306a36Sopenharmony_ci "Unable to allocate IOCTL data\n"); 700262306a36Sopenharmony_ci return ips_abort_init(ha, index); 700362306a36Sopenharmony_ci } 700462306a36Sopenharmony_ci 700562306a36Sopenharmony_ci /* 700662306a36Sopenharmony_ci * Setup Functions 700762306a36Sopenharmony_ci */ 700862306a36Sopenharmony_ci ips_setup_funclist(ha); 700962306a36Sopenharmony_ci 701062306a36Sopenharmony_ci if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) { 701162306a36Sopenharmony_ci /* If Morpheus appears dead, reset it */ 701262306a36Sopenharmony_ci IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1); 701362306a36Sopenharmony_ci if (IsDead == 0xDEADBEEF) { 701462306a36Sopenharmony_ci ips_reset_morpheus(ha); 701562306a36Sopenharmony_ci } 701662306a36Sopenharmony_ci } 701762306a36Sopenharmony_ci 701862306a36Sopenharmony_ci /* 701962306a36Sopenharmony_ci * Initialize the card if it isn't already 702062306a36Sopenharmony_ci */ 702162306a36Sopenharmony_ci 702262306a36Sopenharmony_ci if (!(*ha->func.isinit) (ha)) { 702362306a36Sopenharmony_ci if (!(*ha->func.init) (ha)) { 702462306a36Sopenharmony_ci /* 702562306a36Sopenharmony_ci * Initialization failed 702662306a36Sopenharmony_ci */ 702762306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, pci_dev, 702862306a36Sopenharmony_ci "Unable to initialize controller\n"); 702962306a36Sopenharmony_ci return ips_abort_init(ha, index); 703062306a36Sopenharmony_ci } 703162306a36Sopenharmony_ci } 703262306a36Sopenharmony_ci 703362306a36Sopenharmony_ci *indexPtr = index; 703462306a36Sopenharmony_ci return SUCCESS; 703562306a36Sopenharmony_ci} 703662306a36Sopenharmony_ci 703762306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 703862306a36Sopenharmony_ci/* Routine Name: ips_init_phase2 */ 703962306a36Sopenharmony_ci/* */ 704062306a36Sopenharmony_ci/* Routine Description: */ 704162306a36Sopenharmony_ci/* Adapter Initialization Phase 2 */ 704262306a36Sopenharmony_ci/* */ 704362306a36Sopenharmony_ci/* Return Value: */ 704462306a36Sopenharmony_ci/* 0 if Successful, else non-zero */ 704562306a36Sopenharmony_ci/*---------------------------------------------------------------------------*/ 704662306a36Sopenharmony_cistatic int 704762306a36Sopenharmony_ciips_init_phase2(int index) 704862306a36Sopenharmony_ci{ 704962306a36Sopenharmony_ci ips_ha_t *ha; 705062306a36Sopenharmony_ci 705162306a36Sopenharmony_ci ha = ips_ha[index]; 705262306a36Sopenharmony_ci 705362306a36Sopenharmony_ci METHOD_TRACE("ips_init_phase2", 1); 705462306a36Sopenharmony_ci if (!ha->active) { 705562306a36Sopenharmony_ci ips_ha[index] = NULL; 705662306a36Sopenharmony_ci return -1; 705762306a36Sopenharmony_ci } 705862306a36Sopenharmony_ci 705962306a36Sopenharmony_ci /* Install the interrupt handler */ 706062306a36Sopenharmony_ci if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { 706162306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 706262306a36Sopenharmony_ci "Unable to install interrupt handler\n"); 706362306a36Sopenharmony_ci return ips_abort_init(ha, index); 706462306a36Sopenharmony_ci } 706562306a36Sopenharmony_ci 706662306a36Sopenharmony_ci /* 706762306a36Sopenharmony_ci * Allocate a temporary SCB for initialization 706862306a36Sopenharmony_ci */ 706962306a36Sopenharmony_ci ha->max_cmds = 1; 707062306a36Sopenharmony_ci if (!ips_allocatescbs(ha)) { 707162306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 707262306a36Sopenharmony_ci "Unable to allocate a CCB\n"); 707362306a36Sopenharmony_ci free_irq(ha->pcidev->irq, ha); 707462306a36Sopenharmony_ci return ips_abort_init(ha, index); 707562306a36Sopenharmony_ci } 707662306a36Sopenharmony_ci 707762306a36Sopenharmony_ci if (!ips_hainit(ha)) { 707862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 707962306a36Sopenharmony_ci "Unable to initialize controller\n"); 708062306a36Sopenharmony_ci free_irq(ha->pcidev->irq, ha); 708162306a36Sopenharmony_ci return ips_abort_init(ha, index); 708262306a36Sopenharmony_ci } 708362306a36Sopenharmony_ci /* Free the temporary SCB */ 708462306a36Sopenharmony_ci ips_deallocatescbs(ha, 1); 708562306a36Sopenharmony_ci 708662306a36Sopenharmony_ci /* allocate CCBs */ 708762306a36Sopenharmony_ci if (!ips_allocatescbs(ha)) { 708862306a36Sopenharmony_ci IPS_PRINTK(KERN_WARNING, ha->pcidev, 708962306a36Sopenharmony_ci "Unable to allocate CCBs\n"); 709062306a36Sopenharmony_ci free_irq(ha->pcidev->irq, ha); 709162306a36Sopenharmony_ci return ips_abort_init(ha, index); 709262306a36Sopenharmony_ci } 709362306a36Sopenharmony_ci 709462306a36Sopenharmony_ci return SUCCESS; 709562306a36Sopenharmony_ci} 709662306a36Sopenharmony_ci 709762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 709862306a36Sopenharmony_ciMODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING); 709962306a36Sopenharmony_ciMODULE_VERSION(IPS_VER_STRING); 7100