/*****************************************************************************/ /* ips.c -- driver for the Adaptec / IBM ServeRAID controller */ /* */ /* Written By: Keith Mitchell, IBM Corporation */ /* Jack Hammer, Adaptec, Inc. */ /* David Jeffery, Adaptec, Inc. */ /* */ /* Copyright (C) 2000 IBM Corporation */ /* Copyright (C) 2002,2003 Adaptec, Inc. */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* NO WARRANTY */ /* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ /* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ /* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ /* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ /* solely responsible for determining the appropriateness of using and */ /* distributing the Program and assumes all risks associated with its */ /* exercise of rights under this Agreement, including but not limited to */ /* the risks and costs of program errors, damage to or loss of data, */ /* programs or equipment, and unavailability or interruption of operations. */ /* */ /* DISCLAIMER OF LIABILITY */ /* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ /* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ /* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ /* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ /* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ /* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* Bugs/Comments/Suggestions about this driver should be mailed to: */ /* [email protected] */ /* */ /* For system support issues, contact your local IBM Customer support. */ /* Directions to find IBM Customer Support for each country can be found at: */ /* http://www.ibm.com/planetwide/ */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* Change Log */ /* */ /* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size */ /* 0.99.03 - Make interrupt routine handle all completed request on the */ /* adapter not just the first one */ /* - Make sure passthru commands get woken up if we run out of */ /* SCBs */ /* - Send all of the commands on the queue at once rather than */ /* one at a time since the card will support it. */ /* 0.99.04 - Fix race condition in the passthru mechanism -- this required */ /* the interface to the utilities to change */ /* - Fix error recovery code */ /* 0.99.05 - Fix an oops when we get certain passthru commands */ /* 1.00.00 - Initial Public Release */ /* Functionally equivalent to 0.99.05 */ /* 3.60.00 - Bump max commands to 128 for use with firmware 3.60 */ /* - Change version to 3.60 to coincide with release numbering. */ /* 3.60.01 - Remove bogus error check in passthru routine */ /* 3.60.02 - Make DCDB direction based on lookup table */ /* - Only allow one DCDB command to a SCSI ID at a time */ /* 4.00.00 - Add support for ServeRAID 4 */ /* 4.00.01 - Add support for First Failure Data Capture */ /* 4.00.02 - Fix problem with PT DCDB with no buffer */ /* 4.00.03 - Add alternative passthru interface */ /* - Add ability to flash BIOS */ /* 4.00.04 - Rename structures/constants to be prefixed with IPS_ */ /* 4.00.05 - Remove wish_block from init routine */ /* - Use linux/spinlock.h instead of asm/spinlock.h for kernels */ /* 2.3.18 and later */ /* - Sync with other changes from the 2.3 kernels */ /* 4.00.06 - Fix timeout with initial FFDC command */ /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <[email protected]> */ /* 4.10.00 - Add support for ServeRAID 4M/4L */ /* 4.10.13 - Fix for dynamic unload and proc file system */ /* 4.20.03 - Rename version to coincide with new release schedules */ /* Performance fixes */ /* Fix truncation of /proc files with cat */ /* Merge in changes through kernel 2.4.0test1ac21 */ /* 4.20.13 - Fix some failure cases / reset code */ /* - Hook into the reboot_notifier to flush the controller cache */ /* 4.50.01 - Fix problem when there is a hole in logical drive numbering */ /* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */ /* - Add IPSSEND Flash Support */ /* - Set Sense Data for Unknown SCSI Command */ /* - Use Slot Number from NVRAM Page 5 */ /* - Restore caller's DCDB Structure */ /* 4.70.12 - Corrective actions for bad controller ( during initialization )*/ /* 4.70.13 - Don't Send CDB's if we already know the device is not present */ /* - Don't release HA Lock in ips_next() until SC taken off queue */ /* - Unregister SCSI device in ips_release() */ /* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */ /* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */ /* Code Clean-Up for 2.4.x kernel */ /* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */ /* 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) */ /* - Don't Issue Internal FFDC Command if there are Active Commands */ /* - Close Window for getting too many IOCTL's active */ /* 4.80.00 - Make ia64 Safe */ /* 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater */ /* - Adjustments to Device Queue Depth */ /* 4.80.14 - Take all semaphores off stack */ /* - Clean Up New_IOCTL path */ /* 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) */ /* - 5 second delay needed after resetting an i960 adapter */ /* 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) */ /* 4.90.01 - Version Matching for FirmWare, BIOS, and Driver */ /* 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development */ /* 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) */ /* 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K */ /* 4.90.11 - Don't actually RESET unless it's physically required */ /* - Remove unused compile options */ /* 5.00.01 - Sarasota ( 5i ) adapters must always be scanned first */ /* - Get rid on IOCTL_NEW_COMMAND code */ /* - Add Extended DCDB Commands for Tape Support in 5I */ /* 5.10.12 - use pci_dma interfaces, update for 2.5 kernel changes */ /* 5.10.15 - remove unused code (sem, macros, etc.) */ /* 5.30.00 - use __devexit_p() */ /* 6.00.00 - Add 6x Adapters and Battery Flash */ /* 6.10.00 - Remove 1G Addressing Limitations */ /* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */ /* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */ /* 7.10.18 - Add highmem_io flag in SCSI Templete for 2.4 kernels */ /* - Fix path/name for scsi_hosts.h include for 2.6 kernels */ /* - Fix sort order of 7k */ /* - Remove 3 unused "inline" functions */ /* 7.12.xx - Use STATIC functions wherever possible */ /* - Clean up deprecated MODULE_PARM calls */ /* 7.12.05 - Remove Version Matching per IBM request */ /*****************************************************************************/ /* * Conditional Compilation directives for this driver: * * IPS_DEBUG - Turn on debugging info * * Parameters: * * debug:<number> - Set debug level to <number> * NOTE: only works when IPS_DEBUG compile directive is used. * 1 - Normal debug messages * 2 - Verbose debug messages * 11 - Method trace (non interrupt) * 12 - Method trace (includes interrupt) * * noi2o - Don't use I2O Queues (ServeRAID 4 only) * nommap - Don't use memory mapped I/O * ioctlsize - Initial size of the IOCTL buffer */ #include <asm/io.h> #include <asm/byteorder.h> #include <asm/page.h> #include <linux/stddef.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/reboot.h> #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/types.h> #include <linux/dma-mapping.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/sg.h> #include "ips.h" #include <linux/module.h> #include <linux/stat.h> #include <linux/spinlock.h> #include <linux/init.h> #include <linux/smp.h> #ifdef MODULE static char *ips = NULL; module_param(ips, charp, 0); #endif /* * DRIVER_VER */ #define IPS_VERSION_HIGH … #define IPS_VERSION_LOW … #define IPS_DMA_DIR(scb) … #ifdef IPS_DEBUG #define METHOD_TRACE … #define DEBUG … #define DEBUG_VAR … #else #define METHOD_TRACE(s, i) … #define DEBUG(i, s) … #define DEBUG_VAR(i, s, v...) … #endif /* * Function prototypes */ static int ips_eh_abort(struct scsi_cmnd *); static int ips_eh_reset(struct scsi_cmnd *); static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); static const char *ips_info(struct Scsi_Host *); static irqreturn_t do_ipsintr(int, void *); static int ips_hainit(ips_ha_t *); static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); static int ips_send_cmd(ips_ha_t *, ips_scb_t *); static int ips_online(ips_ha_t *, ips_scb_t *); static int ips_inquiry(ips_ha_t *, ips_scb_t *); static int ips_rdcap(ips_ha_t *, ips_scb_t *); static int ips_msense(ips_ha_t *, ips_scb_t *); static int ips_reqsen(ips_ha_t *, ips_scb_t *); static int ips_deallocatescbs(ips_ha_t *, int); static int ips_allocatescbs(ips_ha_t *); static int ips_reset_copperhead(ips_ha_t *); static int ips_reset_copperhead_memio(ips_ha_t *); static int ips_reset_morpheus(ips_ha_t *); static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); static int ips_issue_i2o(ips_ha_t *, ips_scb_t *); static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); static int ips_isintr_copperhead(ips_ha_t *); static int ips_isintr_copperhead_memio(ips_ha_t *); static int ips_isintr_morpheus(ips_ha_t *); static int ips_wait(ips_ha_t *, int, int); static int ips_write_driver_status(ips_ha_t *, int); static int ips_read_adapter_status(ips_ha_t *, int); static int ips_read_subsystem_parameters(ips_ha_t *, int); static int ips_read_config(ips_ha_t *, int); static int ips_clear_adapter(ips_ha_t *, int); static int ips_readwrite_page5(ips_ha_t *, int, int); static int ips_init_copperhead(ips_ha_t *); static int ips_init_copperhead_memio(ips_ha_t *); static int ips_init_morpheus(ips_ha_t *); static int ips_isinit_copperhead(ips_ha_t *); static int ips_isinit_copperhead_memio(ips_ha_t *); static int ips_isinit_morpheus(ips_ha_t *); static int ips_erase_bios(ips_ha_t *); static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t); static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t); static int ips_erase_bios_memio(ips_ha_t *); static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static void ips_free_flash_copperhead(ips_ha_t * ha); static void ips_get_bios_version(ips_ha_t *, int); static void ips_identify_controller(ips_ha_t *); static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); static void ips_enable_int_copperhead(ips_ha_t *); static void ips_enable_int_copperhead_memio(ips_ha_t *); static void ips_enable_int_morpheus(ips_ha_t *); static int ips_intr_copperhead(ips_ha_t *); static int ips_intr_morpheus(ips_ha_t *); static void ips_next(ips_ha_t *, int); static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); static void ipsintr_done(ips_ha_t *, struct ips_scb *); static void ips_done(ips_ha_t *, ips_scb_t *); static void ips_free(ips_ha_t *); static void ips_init_scb(ips_ha_t *, ips_scb_t *); static void ips_freescb(ips_ha_t *, ips_scb_t *); static void ips_setup_funclist(ips_ha_t *); static void ips_statinit(ips_ha_t *); static void ips_statinit_memio(ips_ha_t *); static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time64_t); static void ips_ffdc_reset(ips_ha_t *, int); static void ips_ffdc_time(ips_ha_t *); static uint32_t ips_statupd_copperhead(ips_ha_t *); static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); static uint32_t ips_statupd_morpheus(ips_ha_t *); static ips_scb_t *ips_getscb(ips_ha_t *); static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); static void ips_putq_wait_tail(ips_wait_queue_entry_t *, struct scsi_cmnd *); static void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *); static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_entry_t *); static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_entry_t *, struct scsi_cmnd *); static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); static int ips_is_passthru(struct scsi_cmnd *); static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int); static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data, unsigned int count); static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data, unsigned int count); static int ips_write_info(struct Scsi_Host *, char *, int); static int ips_show_info(struct seq_file *, struct Scsi_Host *); static int ips_host_info(ips_ha_t *, struct seq_file *); static int ips_abort_init(ips_ha_t * ha, int index); static int ips_init_phase2(int index); static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr); static int ips_register_scsi(int index); static int ips_poll_for_flush_complete(ips_ha_t * ha); static void ips_flush_and_reset(ips_ha_t *ha); /* * global variables */ static const char ips_name[] = …; static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */ static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */ static unsigned int ips_next_controller; static unsigned int ips_num_controllers; static unsigned int ips_released_controllers; static int ips_hotplug; static int ips_cmd_timeout = …; static int ips_reset_timeout = …; static int ips_force_memio = …; /* Always use Memory Mapped I/O */ static int ips_force_i2o = …; /* Always use I2O command delivery */ static int ips_ioctlsize = …; /* Size of the ioctl buffer */ static int ips_cd_boot; /* Booting from Manager CD */ static char *ips_FlashData = …; /* CD Boot - Flash Data Buffer */ static dma_addr_t ips_flashbusaddr; static long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */ static uint32_t MaxLiteCmds = …; /* Max Active Cmds for a Lite Adapter */ static struct scsi_host_template ips_driver_template = …; /* This table describes all ServeRAID Adapters */ static struct pci_device_id ips_pci_table[] = …; MODULE_DEVICE_TABLE( pci, ips_pci_table ); static char ips_hot_plug_name[] = …; static int ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); static void ips_remove_device(struct pci_dev *pci_dev); static struct pci_driver ips_pci_driver = …; /* * Necessary forward function protoypes */ static int ips_halt(struct notifier_block *nb, ulong event, void *buf); #define MAX_ADAPTER_NAME … static char ips_adapter_name[][30] = …; static struct notifier_block ips_notifier = …; /* * Direction table */ static char ips_command_direction[] = …; /****************************************************************************/ /* */ /* Routine Name: ips_setup */ /* */ /* Routine Description: */ /* */ /* setup parameters to the driver */ /* */ /****************************************************************************/ static int ips_setup(char *ips_str) { … } __setup(…); /****************************************************************************/ /* */ /* Routine Name: ips_detect */ /* */ /* Routine Description: */ /* */ /* Detect and initialize the driver */ /* */ /* NOTE: this routine is called under the io_request_lock spinlock */ /* */ /****************************************************************************/ static int ips_detect(struct scsi_host_template * SHT) { … } /****************************************************************************/ /* configure the function pointers to use the functions that will work */ /* with the found version of the adapter */ /****************************************************************************/ static void ips_setup_funclist(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_release */ /* */ /* Routine Description: */ /* */ /* Remove a driver */ /* */ /****************************************************************************/ static void ips_release(struct Scsi_Host *sh) { … } /****************************************************************************/ /* */ /* Routine Name: ips_halt */ /* */ /* Routine Description: */ /* */ /* Perform cleanup when the system reboots */ /* */ /****************************************************************************/ static int ips_halt(struct notifier_block *nb, ulong event, void *buf) { … } /****************************************************************************/ /* */ /* Routine Name: ips_eh_abort */ /* */ /* Routine Description: */ /* */ /* Abort a command (using the new error code stuff) */ /* Note: this routine is called under the io_request_lock */ /****************************************************************************/ int ips_eh_abort(struct scsi_cmnd *SC) { … } /****************************************************************************/ /* */ /* Routine Name: ips_eh_reset */ /* */ /* Routine Description: */ /* */ /* Reset the controller (with new eh error code) */ /* */ /* NOTE: this routine is called under the io_request_lock spinlock */ /* */ /****************************************************************************/ static int __ips_eh_reset(struct scsi_cmnd *SC) { … } static int ips_eh_reset(struct scsi_cmnd *SC) { … } /****************************************************************************/ /* */ /* Routine Name: ips_queue */ /* */ /* Routine Description: */ /* */ /* Send a command to the controller */ /* */ /* NOTE: */ /* Linux obtains io_request_lock before calling this function */ /* */ /****************************************************************************/ static int ips_queue_lck(struct scsi_cmnd *SC) { … } static DEF_SCSI_QCMD(ips_queue) /****************************************************************************/ /* */ /* Routine Name: ips_biosparam */ /* */ /* Routine Description: */ /* */ /* Set bios geometry for the controller */ /* */ /****************************************************************************/ static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { … } /****************************************************************************/ /* */ /* Routine Name: ips_slave_configure */ /* */ /* Routine Description: */ /* */ /* Set queue depths on devices once scan is complete */ /* */ /****************************************************************************/ static int ips_slave_configure(struct scsi_device * SDptr) { … } /****************************************************************************/ /* */ /* Routine Name: do_ipsintr */ /* */ /* Routine Description: */ /* */ /* Wrapper for the interrupt handler */ /* */ /****************************************************************************/ static irqreturn_t do_ipsintr(int irq, void *dev_id) { … } /****************************************************************************/ /* */ /* Routine Name: ips_intr_copperhead */ /* */ /* Routine Description: */ /* */ /* Polling interrupt handler */ /* */ /* ASSUMES interrupts are disabled */ /* */ /****************************************************************************/ int ips_intr_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_intr_morpheus */ /* */ /* Routine Description: */ /* */ /* Polling interrupt handler */ /* */ /* ASSUMES interrupts are disabled */ /* */ /****************************************************************************/ int ips_intr_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_info */ /* */ /* Routine Description: */ /* */ /* Return info about the driver */ /* */ /****************************************************************************/ static const char * ips_info(struct Scsi_Host *SH) { … } static int ips_write_info(struct Scsi_Host *host, char *buffer, int length) { … } static int ips_show_info(struct seq_file *m, struct Scsi_Host *host) { … } /*--------------------------------------------------------------------------*/ /* Helper Functions */ /*--------------------------------------------------------------------------*/ /****************************************************************************/ /* */ /* Routine Name: ips_is_passthru */ /* */ /* Routine Description: */ /* */ /* Determine if the specified SCSI command is really a passthru command */ /* */ /****************************************************************************/ static int ips_is_passthru(struct scsi_cmnd *SC) { … } /****************************************************************************/ /* */ /* Routine Name: ips_alloc_passthru_buffer */ /* */ /* Routine Description: */ /* allocate a buffer large enough for the ioctl data if the ioctl buffer */ /* is too small or doesn't exist */ /****************************************************************************/ static int ips_alloc_passthru_buffer(ips_ha_t * ha, int length) { … } /****************************************************************************/ /* */ /* Routine Name: ips_make_passthru */ /* */ /* Routine Description: */ /* */ /* Make a passthru command out of the info in the Scsi block */ /* */ /****************************************************************************/ static int ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr) { … } /****************************************************************************/ /* Routine Name: ips_flash_copperhead */ /* Routine Description: */ /* Flash the BIOS/FW on a Copperhead style controller */ /****************************************************************************/ static int ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) { … } /****************************************************************************/ /* Routine Name: ips_flash_bios */ /* Routine Description: */ /* flashes the bios of a copperhead adapter */ /****************************************************************************/ static int ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_fill_scb_sg_single */ /* */ /* Routine Description: */ /* Fill in a single scb sg_list element from an address */ /* return a -1 if a breakup occurred */ /****************************************************************************/ static int ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, ips_scb_t * scb, int indx, unsigned int e_len) { … } /****************************************************************************/ /* Routine Name: ips_flash_firmware */ /* Routine Description: */ /* flashes the firmware of a copperhead adapter */ /****************************************************************************/ static int ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) { … } /****************************************************************************/ /* Routine Name: ips_free_flash_copperhead */ /* Routine Description: */ /* release the memory resources used to hold the flash image */ /****************************************************************************/ static void ips_free_flash_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_usrcmd */ /* */ /* Routine Description: */ /* */ /* Process a user command and make it ready to send */ /* */ /****************************************************************************/ static int ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_cleanup_passthru */ /* */ /* Routine Description: */ /* */ /* Cleanup after a passthru command */ /* */ /****************************************************************************/ static void ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_host_info */ /* */ /* Routine Description: */ /* */ /* The passthru interface for the driver */ /* */ /****************************************************************************/ static int ips_host_info(ips_ha_t *ha, struct seq_file *m) { … } /****************************************************************************/ /* */ /* Routine Name: ips_identify_controller */ /* */ /* Routine Description: */ /* */ /* Identify this controller */ /* */ /****************************************************************************/ static void ips_identify_controller(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_get_bios_version */ /* */ /* Routine Description: */ /* */ /* Get the BIOS revision number */ /* */ /****************************************************************************/ static void ips_get_bios_version(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_hainit */ /* */ /* Routine Description: */ /* */ /* Initialize the controller */ /* */ /* NOTE: Assumes to be called from with a lock */ /* */ /****************************************************************************/ static int ips_hainit(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_next */ /* */ /* Routine Description: */ /* */ /* Take the next command off the queue and send it to the controller */ /* */ /****************************************************************************/ static void ips_next(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_putq_scb_head */ /* */ /* Routine Description: */ /* */ /* Add an item to the head of the queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static void ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) { … } /****************************************************************************/ /* */ /* Routine Name: ips_removeq_scb_head */ /* */ /* Routine Description: */ /* */ /* Remove the head of the queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t * queue) { … } /****************************************************************************/ /* */ /* Routine Name: ips_removeq_scb */ /* */ /* Routine Description: */ /* */ /* Remove an item from a queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static ips_scb_t * ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) { … } /****************************************************************************/ /* */ /* Routine Name: ips_putq_wait_tail */ /* */ /* Routine Description: */ /* */ /* Add an item to the tail of the queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static void ips_putq_wait_tail(ips_wait_queue_entry_t *queue, struct scsi_cmnd *item) { … } /****************************************************************************/ /* */ /* Routine Name: ips_removeq_wait_head */ /* */ /* Routine Description: */ /* */ /* Remove the head of the queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_entry_t *queue) { … } /****************************************************************************/ /* */ /* Routine Name: ips_removeq_wait */ /* */ /* Routine Description: */ /* */ /* Remove an item from a queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_entry_t *queue, struct scsi_cmnd *item) { … } /****************************************************************************/ /* */ /* Routine Name: ips_putq_copp_tail */ /* */ /* Routine Description: */ /* */ /* Add an item to the tail of the queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static void ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { … } /****************************************************************************/ /* */ /* Routine Name: ips_removeq_copp_head */ /* */ /* Routine Description: */ /* */ /* Remove the head of the queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t * queue) { … } /****************************************************************************/ /* */ /* Routine Name: ips_removeq_copp */ /* */ /* Routine Description: */ /* */ /* Remove an item from a queue */ /* */ /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ static ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { … } /****************************************************************************/ /* */ /* Routine Name: ipsintr_blocking */ /* */ /* Routine Description: */ /* */ /* Finalize an interrupt for internal commands */ /* */ /****************************************************************************/ static void ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ipsintr_done */ /* */ /* Routine Description: */ /* */ /* Finalize an interrupt for non-internal commands */ /* */ /****************************************************************************/ static void ipsintr_done(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_done */ /* */ /* Routine Description: */ /* */ /* Do housekeeping on completed commands */ /* ASSUMED to be called form within the request lock */ /****************************************************************************/ static void ips_done(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_map_status */ /* */ /* Routine Description: */ /* */ /* Map Controller Error codes to Linux Error Codes */ /* */ /****************************************************************************/ static int ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) { … } /****************************************************************************/ /* */ /* Routine Name: ips_send_wait */ /* */ /* Routine Description: */ /* */ /* Send a command to the controller and wait for it to return */ /* */ /* The FFDC Time Stamp use this function for the callback, but doesn't */ /* actually need to wait. */ /****************************************************************************/ static int ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_scmd_buf_write */ /* */ /* Routine Description: */ /* Write data to struct scsi_cmnd request_buffer at proper offsets */ /****************************************************************************/ static void ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) { … } /****************************************************************************/ /* */ /* Routine Name: ips_scmd_buf_read */ /* */ /* Routine Description: */ /* Copy data from a struct scsi_cmnd to a new, linear buffer */ /****************************************************************************/ static void ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count) { … } /****************************************************************************/ /* */ /* Routine Name: ips_send_cmd */ /* */ /* Routine Description: */ /* */ /* Map SCSI commands to ServeRAID commands for logical drives */ /* */ /****************************************************************************/ static int ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_chk_status */ /* */ /* Routine Description: */ /* */ /* Check the status of commands to logical drives */ /* Assumed to be called with the HA lock */ /****************************************************************************/ static void ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) { … } /****************************************************************************/ /* */ /* Routine Name: ips_online */ /* */ /* Routine Description: */ /* */ /* Determine if a logical drive is online */ /* */ /****************************************************************************/ static int ips_online(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_inquiry */ /* */ /* Routine Description: */ /* */ /* Simulate an inquiry command to a logical drive */ /* */ /****************************************************************************/ static int ips_inquiry(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_rdcap */ /* */ /* Routine Description: */ /* */ /* Simulate a read capacity command to a logical drive */ /* */ /****************************************************************************/ static int ips_rdcap(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_msense */ /* */ /* Routine Description: */ /* */ /* Simulate a mode sense command to a logical drive */ /* */ /****************************************************************************/ static int ips_msense(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_reqsen */ /* */ /* Routine Description: */ /* */ /* Simulate a request sense command to a logical drive */ /* */ /****************************************************************************/ static int ips_reqsen(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_free */ /* */ /* Routine Description: */ /* */ /* Free any allocated space for this controller */ /* */ /****************************************************************************/ static void ips_free(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_deallocatescbs */ /* */ /* Routine Description: */ /* */ /* Free the command blocks */ /* */ /****************************************************************************/ static int ips_deallocatescbs(ips_ha_t * ha, int cmds) { … } /****************************************************************************/ /* */ /* Routine Name: ips_allocatescbs */ /* */ /* Routine Description: */ /* */ /* Allocate the command blocks */ /* */ /****************************************************************************/ static int ips_allocatescbs(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_init_scb */ /* */ /* Routine Description: */ /* */ /* Initialize a CCB to default values */ /* */ /****************************************************************************/ static void ips_init_scb(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_get_scb */ /* */ /* Routine Description: */ /* */ /* Initialize a CCB to default values */ /* */ /* ASSUMED to be called from within a lock */ /* */ /****************************************************************************/ static ips_scb_t * ips_getscb(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_free_scb */ /* */ /* Routine Description: */ /* */ /* Return an unused CCB back to the free list */ /* */ /* ASSUMED to be called from within a lock */ /* */ /****************************************************************************/ static void ips_freescb(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_isinit_copperhead */ /* */ /* Routine Description: */ /* */ /* Is controller initialized ? */ /* */ /****************************************************************************/ static int ips_isinit_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_isinit_copperhead_memio */ /* */ /* Routine Description: */ /* */ /* Is controller initialized ? */ /* */ /****************************************************************************/ static int ips_isinit_copperhead_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_isinit_morpheus */ /* */ /* Routine Description: */ /* */ /* Is controller initialized ? */ /* */ /****************************************************************************/ static int ips_isinit_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_flush_and_reset */ /* */ /* Routine Description: */ /* */ /* Perform cleanup ( FLUSH and RESET ) when the adapter is in an unknown */ /* state ( was trying to INIT and an interrupt was already pending ) ... */ /* */ /****************************************************************************/ static void ips_flush_and_reset(ips_ha_t *ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_poll_for_flush_complete */ /* */ /* Routine Description: */ /* */ /* Poll for the Flush Command issued by ips_flush_and_reset() to complete */ /* All other responses are just taken off the queue and ignored */ /* */ /****************************************************************************/ static int ips_poll_for_flush_complete(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_enable_int_copperhead */ /* */ /* Routine Description: */ /* Turn on interrupts */ /* */ /****************************************************************************/ static void ips_enable_int_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_enable_int_copperhead_memio */ /* */ /* Routine Description: */ /* Turn on interrupts */ /* */ /****************************************************************************/ static void ips_enable_int_copperhead_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_enable_int_morpheus */ /* */ /* Routine Description: */ /* Turn on interrupts */ /* */ /****************************************************************************/ static void ips_enable_int_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_init_copperhead */ /* */ /* Routine Description: */ /* */ /* Initialize a copperhead controller */ /* */ /****************************************************************************/ static int ips_init_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_init_copperhead_memio */ /* */ /* Routine Description: */ /* */ /* Initialize a copperhead controller with memory mapped I/O */ /* */ /****************************************************************************/ static int ips_init_copperhead_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_init_morpheus */ /* */ /* Routine Description: */ /* */ /* Initialize a morpheus controller */ /* */ /****************************************************************************/ static int ips_init_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_reset_copperhead */ /* */ /* Routine Description: */ /* */ /* Reset the controller */ /* */ /****************************************************************************/ static int ips_reset_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_reset_copperhead_memio */ /* */ /* Routine Description: */ /* */ /* Reset the controller */ /* */ /****************************************************************************/ static int ips_reset_copperhead_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_reset_morpheus */ /* */ /* Routine Description: */ /* */ /* Reset the controller */ /* */ /****************************************************************************/ static int ips_reset_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_statinit */ /* */ /* Routine Description: */ /* */ /* Initialize the status queues on the controller */ /* */ /****************************************************************************/ static void ips_statinit(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_statinit_memio */ /* */ /* Routine Description: */ /* */ /* Initialize the status queues on the controller */ /* */ /****************************************************************************/ static void ips_statinit_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_statupd_copperhead */ /* */ /* Routine Description: */ /* */ /* Remove an element from the status queue */ /* */ /****************************************************************************/ static uint32_t ips_statupd_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_statupd_copperhead_memio */ /* */ /* Routine Description: */ /* */ /* Remove an element from the status queue */ /* */ /****************************************************************************/ static uint32_t ips_statupd_copperhead_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_statupd_morpheus */ /* */ /* Routine Description: */ /* */ /* Remove an element from the status queue */ /* */ /****************************************************************************/ static uint32_t ips_statupd_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_issue_copperhead */ /* */ /* Routine Description: */ /* */ /* Send a command down to the controller */ /* */ /****************************************************************************/ static int ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_issue_copperhead_memio */ /* */ /* Routine Description: */ /* */ /* Send a command down to the controller */ /* */ /****************************************************************************/ static int ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_issue_i2o */ /* */ /* Routine Description: */ /* */ /* Send a command down to the controller */ /* */ /****************************************************************************/ static int ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_issue_i2o_memio */ /* */ /* Routine Description: */ /* */ /* Send a command down to the controller */ /* */ /****************************************************************************/ static int ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) { … } /****************************************************************************/ /* */ /* Routine Name: ips_isintr_copperhead */ /* */ /* Routine Description: */ /* */ /* Test to see if an interrupt is for us */ /* */ /****************************************************************************/ static int ips_isintr_copperhead(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_isintr_copperhead_memio */ /* */ /* Routine Description: */ /* */ /* Test to see if an interrupt is for us */ /* */ /****************************************************************************/ static int ips_isintr_copperhead_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_isintr_morpheus */ /* */ /* Routine Description: */ /* */ /* Test to see if an interrupt is for us */ /* */ /****************************************************************************/ static int ips_isintr_morpheus(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_wait */ /* */ /* Routine Description: */ /* */ /* Wait for a command to complete */ /* */ /****************************************************************************/ static int ips_wait(ips_ha_t * ha, int time, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_write_driver_status */ /* */ /* Routine Description: */ /* */ /* Write OS/Driver version to Page 5 of the nvram on the controller */ /* */ /****************************************************************************/ static int ips_write_driver_status(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_read_adapter_status */ /* */ /* Routine Description: */ /* */ /* Do an Inquiry command to the adapter */ /* */ /****************************************************************************/ static int ips_read_adapter_status(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_read_subsystem_parameters */ /* */ /* Routine Description: */ /* */ /* Read subsystem parameters from the adapter */ /* */ /****************************************************************************/ static int ips_read_subsystem_parameters(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_read_config */ /* */ /* Routine Description: */ /* */ /* Read the configuration on the adapter */ /* */ /****************************************************************************/ static int ips_read_config(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_readwrite_page5 */ /* */ /* Routine Description: */ /* */ /* Read nvram page 5 from the adapter */ /* */ /****************************************************************************/ static int ips_readwrite_page5(ips_ha_t * ha, int write, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_clear_adapter */ /* */ /* Routine Description: */ /* */ /* Clear the stripe lock tables */ /* */ /****************************************************************************/ static int ips_clear_adapter(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_ffdc_reset */ /* */ /* Routine Description: */ /* */ /* FFDC: write reset info */ /* */ /****************************************************************************/ static void ips_ffdc_reset(ips_ha_t * ha, int intr) { … } /****************************************************************************/ /* */ /* Routine Name: ips_ffdc_time */ /* */ /* Routine Description: */ /* */ /* FFDC: write time info */ /* */ /****************************************************************************/ static void ips_ffdc_time(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_fix_ffdc_time */ /* */ /* Routine Description: */ /* Adjust time_t to what the card wants */ /* */ /****************************************************************************/ static void ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time64_t current_time) { … } /**************************************************************************** * BIOS Flash Routines * ****************************************************************************/ /****************************************************************************/ /* */ /* Routine Name: ips_erase_bios */ /* */ /* Routine Description: */ /* Erase the BIOS on the adapter */ /* */ /****************************************************************************/ static int ips_erase_bios(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_erase_bios_memio */ /* */ /* Routine Description: */ /* Erase the BIOS on the adapter */ /* */ /****************************************************************************/ static int ips_erase_bios_memio(ips_ha_t * ha) { … } /****************************************************************************/ /* */ /* Routine Name: ips_program_bios */ /* */ /* Routine Description: */ /* Program the BIOS on the adapter */ /* */ /****************************************************************************/ static int ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { … } /****************************************************************************/ /* */ /* Routine Name: ips_program_bios_memio */ /* */ /* Routine Description: */ /* Program the BIOS on the adapter */ /* */ /****************************************************************************/ static int ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { … } /****************************************************************************/ /* */ /* Routine Name: ips_verify_bios */ /* */ /* Routine Description: */ /* Verify the BIOS on the adapter */ /* */ /****************************************************************************/ static int ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { … } /****************************************************************************/ /* */ /* Routine Name: ips_verify_bios_memio */ /* */ /* Routine Description: */ /* Verify the BIOS on the adapter */ /* */ /****************************************************************************/ static int ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, uint32_t offset) { … } /****************************************************************************/ /* */ /* Routine Name: ips_abort_init */ /* */ /* Routine Description: */ /* cleanup routine for a failed adapter initialization */ /****************************************************************************/ static int ips_abort_init(ips_ha_t * ha, int index) { … } /****************************************************************************/ /* */ /* Routine Name: ips_shift_controllers */ /* */ /* Routine Description: */ /* helper function for ordering adapters */ /****************************************************************************/ static void ips_shift_controllers(int lowindex, int highindex) { … } /****************************************************************************/ /* */ /* Routine Name: ips_order_controllers */ /* */ /* Routine Description: */ /* place controllers is the "proper" boot order */ /****************************************************************************/ static void ips_order_controllers(void) { … } /****************************************************************************/ /* */ /* Routine Name: ips_register_scsi */ /* */ /* Routine Description: */ /* perform any registration and setup with the scsi layer */ /****************************************************************************/ static int ips_register_scsi(int index) { … } /*---------------------------------------------------------------------------*/ /* Routine Name: ips_remove_device */ /* */ /* Routine Description: */ /* Remove one Adapter ( Hot Plugging ) */ /*---------------------------------------------------------------------------*/ static void ips_remove_device(struct pci_dev *pci_dev) { … } /****************************************************************************/ /* */ /* Routine Name: ips_module_init */ /* */ /* Routine Description: */ /* function called on module load */ /****************************************************************************/ static int __init ips_module_init(void) { … } /****************************************************************************/ /* */ /* Routine Name: ips_module_exit */ /* */ /* Routine Description: */ /* function called on module unload */ /****************************************************************************/ static void __exit ips_module_exit(void) { … } module_init(…) …; module_exit(ips_module_exit); /*---------------------------------------------------------------------------*/ /* Routine Name: ips_insert_device */ /* */ /* Routine Description: */ /* Add One Adapter ( Hot Plug ) */ /* */ /* Return Value: */ /* 0 if Successful, else non-zero */ /*---------------------------------------------------------------------------*/ static int ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) { … } /*---------------------------------------------------------------------------*/ /* Routine Name: ips_init_phase1 */ /* */ /* Routine Description: */ /* Adapter Initialization */ /* */ /* Return Value: */ /* 0 if Successful, else non-zero */ /*---------------------------------------------------------------------------*/ static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) { … } /*---------------------------------------------------------------------------*/ /* Routine Name: ips_init_phase2 */ /* */ /* Routine Description: */ /* Adapter Initialization Phase 2 */ /* */ /* Return Value: */ /* 0 if Successful, else non-zero */ /*---------------------------------------------------------------------------*/ static int ips_init_phase2(int index) { … } MODULE_LICENSE(…) …; MODULE_DESCRIPTION(…) …; MODULE_VERSION(…);