diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/message/fusion/mptsas.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/message/fusion/mptsas.c | 5451 |
1 files changed, 0 insertions, 5451 deletions
diff --git a/ANDROID_3.4.5/drivers/message/fusion/mptsas.c b/ANDROID_3.4.5/drivers/message/fusion/mptsas.c deleted file mode 100644 index 551262e4..00000000 --- a/ANDROID_3.4.5/drivers/message/fusion/mptsas.c +++ /dev/null @@ -1,5451 +0,0 @@ -/* - * linux/drivers/message/fusion/mptsas.c - * For use with LSI PCI chip/adapter(s) - * running LSI Fusion MPT (Message Passing Technology) firmware. - * - * Copyright (c) 1999-2008 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - 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; version 2 of the License. - - 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 -*/ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/jiffies.h> -#include <linux/workqueue.h> -#include <linux/delay.h> /* for mdelay */ - -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_transport_sas.h> -#include <scsi/scsi_transport.h> -#include <scsi/scsi_dbg.h> - -#include "mptbase.h" -#include "mptscsih.h" -#include "mptsas.h" - - -#define my_NAME "Fusion MPT SAS Host driver" -#define my_VERSION MPT_LINUX_VERSION_COMMON -#define MYNAM "mptsas" - -/* - * Reserved channel for integrated raid - */ -#define MPTSAS_RAID_CHANNEL 1 - -#define SAS_CONFIG_PAGE_TIMEOUT 30 -MODULE_AUTHOR(MODULEAUTHOR); -MODULE_DESCRIPTION(my_NAME); -MODULE_LICENSE("GPL"); -MODULE_VERSION(my_VERSION); - -static int mpt_pt_clear; -module_param(mpt_pt_clear, int, 0); -MODULE_PARM_DESC(mpt_pt_clear, - " Clear persistency table: enable=1 " - "(default=MPTSCSIH_PT_CLEAR=0)"); - -/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ -#define MPTSAS_MAX_LUN (16895) -static int max_lun = MPTSAS_MAX_LUN; -module_param(max_lun, int, 0); -MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); - -static int mpt_loadtime_max_sectors = 8192; -module_param(mpt_loadtime_max_sectors, int, 0); -MODULE_PARM_DESC(mpt_loadtime_max_sectors, - " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192"); - -static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; -static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; -static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ -static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; -static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; - -static void mptsas_firmware_event_work(struct work_struct *work); -static void mptsas_send_sas_event(struct fw_event_work *fw_event); -static void mptsas_send_raid_event(struct fw_event_work *fw_event); -static void mptsas_send_ir2_event(struct fw_event_work *fw_event); -static void mptsas_parse_device_info(struct sas_identify *identify, - struct mptsas_devinfo *device_info); -static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, - struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); -static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address - (MPT_ADAPTER *ioc, u64 sas_address); -static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, - struct mptsas_devinfo *device_info, u32 form, u32 form_specific); -static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, - struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); -static int mptsas_add_end_device(MPT_ADAPTER *ioc, - struct mptsas_phyinfo *phy_info); -static void mptsas_del_end_device(MPT_ADAPTER *ioc, - struct mptsas_phyinfo *phy_info); -static void mptsas_send_link_status_event(struct fw_event_work *fw_event); -static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address - (MPT_ADAPTER *ioc, u64 sas_address); -static void mptsas_expander_delete(MPT_ADAPTER *ioc, - struct mptsas_portinfo *port_info, u8 force); -static void mptsas_send_expander_event(struct fw_event_work *fw_event); -static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); -static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); -static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); -static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); -static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); -void mptsas_schedule_target_reset(void *ioc); - -static void mptsas_print_phy_data(MPT_ADAPTER *ioc, - MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) -{ - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "---- IO UNIT PAGE 0 ------------\n", ioc->name)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", - ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n", - ioc->name, le16_to_cpu(phy_data->ControllerDevHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n", - ioc->name, phy_data->Port)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n", - ioc->name, phy_data->PortFlags)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n", - ioc->name, phy_data->PhyFlags)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", - ioc->name, phy_data->NegotiatedLinkRate)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Controller PHY Device Info=0x%X\n", ioc->name, - le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n", - ioc->name, le32_to_cpu(phy_data->DiscoveryStatus))); -} - -static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) -{ - __le64 sas_address; - - memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); - - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "---- SAS PHY PAGE 0 ------------\n", ioc->name)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Attached Device Handle=0x%X\n", ioc->name, - le16_to_cpu(pg0->AttachedDevHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", - ioc->name, (unsigned long long)le64_to_cpu(sas_address))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Attached PHY Identifier=0x%X\n", ioc->name, - pg0->AttachedPhyIdentifier)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n", - ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", - ioc->name, pg0->ProgrammedLinkRate)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n", - ioc->name, pg0->ChangeCount)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n", - ioc->name, le32_to_cpu(pg0->PhyInfo))); -} - -static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1) -{ - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "---- SAS PHY PAGE 1 ------------\n", ioc->name)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n", - ioc->name, pg1->InvalidDwordCount)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Running Disparity Error Count=0x%x\n", ioc->name, - pg1->RunningDisparityErrorCount)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Loss Dword Synch Count=0x%x\n", ioc->name, - pg1->LossDwordSynchCount)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "PHY Reset Problem Count=0x%x\n\n", ioc->name, - pg1->PhyResetProblemCount)); -} - -static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) -{ - __le64 sas_address; - - memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); - - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "---- SAS DEVICE PAGE 0 ---------\n", ioc->name)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", - ioc->name, le16_to_cpu(pg0->DevHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n", - ioc->name, le16_to_cpu(pg0->ParentDevHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n", - ioc->name, le16_to_cpu(pg0->EnclosureHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n", - ioc->name, le16_to_cpu(pg0->Slot))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", - ioc->name, (unsigned long long)le64_to_cpu(sas_address))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n", - ioc->name, pg0->TargetID)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n", - ioc->name, pg0->Bus)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n", - ioc->name, pg0->PhyNum)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n", - ioc->name, le16_to_cpu(pg0->AccessStatus))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n", - ioc->name, le32_to_cpu(pg0->DeviceInfo))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n", - ioc->name, le16_to_cpu(pg0->Flags))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n", - ioc->name, pg0->PhysicalPort)); -} - -static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) -{ - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n", - ioc->name, pg1->PhysicalPort)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n", - ioc->name, pg1->PhyIdentifier)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", - ioc->name, pg1->NegotiatedLinkRate)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", - ioc->name, pg1->ProgrammedLinkRate)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n", - ioc->name, pg1->HwLinkRate)); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n", - ioc->name, le16_to_cpu(pg1->OwnerDevHandle))); - dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Attached Device Handle=0x%X\n\n", ioc->name, - le16_to_cpu(pg1->AttachedDevHandle))); -} - -/* inhibit sas firmware event handling */ -static void -mptsas_fw_event_off(MPT_ADAPTER *ioc) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - ioc->fw_events_off = 1; - ioc->sas_discovery_quiesce_io = 0; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - -} - -/* enable sas firmware event handling */ -static void -mptsas_fw_event_on(MPT_ADAPTER *ioc) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - ioc->fw_events_off = 0; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/* queue a sas firmware event */ -static void -mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, - unsigned long delay) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_add_tail(&fw_event->list, &ioc->fw_event_list); - INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" - "on cpuid %d\n", ioc->name, __func__, - fw_event, smp_processor_id())); - queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, - &fw_event->work, delay); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/* requeue a sas firmware event */ -static void -mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, - unsigned long delay) -{ - unsigned long flags; - spin_lock_irqsave(&ioc->fw_event_lock, flags); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " - "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__, - fw_event, smp_processor_id())); - fw_event->retries++; - queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, - &fw_event->work, msecs_to_jiffies(delay)); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/* free memory associated to a sas firmware event */ -static void -mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", - ioc->name, __func__, fw_event)); - list_del(&fw_event->list); - kfree(fw_event); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/* walk the firmware event queue, and either stop or wait for - * outstanding events to complete */ -static void -mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) -{ - struct fw_event_work *fw_event, *next; - struct mptsas_target_reset_event *target_reset_list, *n; - MPT_SCSI_HOST *hd = shost_priv(ioc->sh); - - /* flush the target_reset_list */ - if (!list_empty(&hd->target_reset_list)) { - list_for_each_entry_safe(target_reset_list, n, - &hd->target_reset_list, list) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: removing target reset for id=%d\n", - ioc->name, __func__, - target_reset_list->sas_event_data.TargetID)); - list_del(&target_reset_list->list); - kfree(target_reset_list); - } - } - - if (list_empty(&ioc->fw_event_list) || - !ioc->fw_event_q || in_interrupt()) - return; - - list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { - if (cancel_delayed_work(&fw_event->work)) - mptsas_free_fw_event(ioc, fw_event); - } -} - - -static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) -{ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; -} - -static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) -{ - struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); - return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; -} - -/* - * mptsas_find_portinfo_by_handle - * - * This function should be called with the sas_topology_mutex already held - */ -static struct mptsas_portinfo * -mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) -{ - struct mptsas_portinfo *port_info, *rc=NULL; - int i; - - list_for_each_entry(port_info, &ioc->sas_topology, list) - for (i = 0; i < port_info->num_phys; i++) - if (port_info->phy_info[i].identify.handle == handle) { - rc = port_info; - goto out; - } - out: - return rc; -} - -/** - * mptsas_find_portinfo_by_sas_address - - * @ioc: Pointer to MPT_ADAPTER structure - * @handle: - * - * This function should be called with the sas_topology_mutex already held - * - **/ -static struct mptsas_portinfo * -mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) -{ - struct mptsas_portinfo *port_info, *rc = NULL; - int i; - - if (sas_address >= ioc->hba_port_sas_addr && - sas_address < (ioc->hba_port_sas_addr + - ioc->hba_port_num_phy)) - return ioc->hba_port_info; - - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(port_info, &ioc->sas_topology, list) - for (i = 0; i < port_info->num_phys; i++) - if (port_info->phy_info[i].identify.sas_address == - sas_address) { - rc = port_info; - goto out; - } - out: - mutex_unlock(&ioc->sas_topology_mutex); - return rc; -} - -/* - * Returns true if there is a scsi end device - */ -static inline int -mptsas_is_end_device(struct mptsas_devinfo * attached) -{ - if ((attached->sas_address) && - (attached->device_info & - MPI_SAS_DEVICE_INFO_END_DEVICE) && - ((attached->device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) | - (attached->device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) | - (attached->device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE))) - return 1; - else - return 0; -} - -/* no mutex */ -static void -mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) -{ - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info; - u8 i; - - if (!port_details) - return; - - port_info = port_details->port_info; - phy_info = port_info->phy_info; - - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " - "bitmask=0x%016llX\n", ioc->name, __func__, port_details, - port_details->num_phys, (unsigned long long) - port_details->phy_bitmask)); - - for (i = 0; i < port_info->num_phys; i++, phy_info++) { - if(phy_info->port_details != port_details) - continue; - memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); - mptsas_set_rphy(ioc, phy_info, NULL); - phy_info->port_details = NULL; - } - kfree(port_details); -} - -static inline struct sas_rphy * -mptsas_get_rphy(struct mptsas_phyinfo *phy_info) -{ - if (phy_info->port_details) - return phy_info->port_details->rphy; - else - return NULL; -} - -static inline void -mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) -{ - if (phy_info->port_details) { - phy_info->port_details->rphy = rphy; - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", - ioc->name, rphy)); - } - - if (rphy) { - dsaswideprintk(ioc, dev_printk(KERN_DEBUG, - &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", - ioc->name, rphy, rphy->dev.release)); - } -} - -static inline struct sas_port * -mptsas_get_port(struct mptsas_phyinfo *phy_info) -{ - if (phy_info->port_details) - return phy_info->port_details->port; - else - return NULL; -} - -static inline void -mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port) -{ - if (phy_info->port_details) - phy_info->port_details->port = port; - - if (port) { - dsaswideprintk(ioc, dev_printk(KERN_DEBUG, - &port->dev, MYIOC_s_FMT "add:", ioc->name)); - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n", - ioc->name, port, port->dev.release)); - } -} - -static inline struct scsi_target * -mptsas_get_starget(struct mptsas_phyinfo *phy_info) -{ - if (phy_info->port_details) - return phy_info->port_details->starget; - else - return NULL; -} - -static inline void -mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * -starget) -{ - if (phy_info->port_details) - phy_info->port_details->starget = starget; -} - -/** - * mptsas_add_device_component - - * @ioc: Pointer to MPT_ADAPTER structure - * @channel: fw mapped id's - * @id: - * @sas_address: - * @device_info: - * - **/ -static void -mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, - u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) -{ - struct mptsas_device_info *sas_info, *next; - struct scsi_device *sdev; - struct scsi_target *starget; - struct sas_rphy *rphy; - - /* - * Delete all matching devices out of the list - */ - mutex_lock(&ioc->sas_device_info_mutex); - list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, - list) { - if (!sas_info->is_logical_volume && - (sas_info->sas_address == sas_address || - (sas_info->fw.channel == channel && - sas_info->fw.id == id))) { - list_del(&sas_info->list); - kfree(sas_info); - } - } - - sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); - if (!sas_info) - goto out; - - /* - * Set Firmware mapping - */ - sas_info->fw.id = id; - sas_info->fw.channel = channel; - - sas_info->sas_address = sas_address; - sas_info->device_info = device_info; - sas_info->slot = slot; - sas_info->enclosure_logical_id = enclosure_logical_id; - INIT_LIST_HEAD(&sas_info->list); - list_add_tail(&sas_info->list, &ioc->sas_device_info_list); - - /* - * Set OS mapping - */ - shost_for_each_device(sdev, ioc->sh) { - starget = scsi_target(sdev); - rphy = dev_to_rphy(starget->dev.parent); - if (rphy->identify.sas_address == sas_address) { - sas_info->os.id = starget->id; - sas_info->os.channel = starget->channel; - } - } - - out: - mutex_unlock(&ioc->sas_device_info_mutex); - return; -} - -/** - * mptsas_add_device_component_by_fw - - * @ioc: Pointer to MPT_ADAPTER structure - * @channel: fw mapped id's - * @id: - * - **/ -static void -mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - struct mptsas_devinfo sas_device; - struct mptsas_enclosure enclosure_info; - int rc; - - rc = mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (channel << 8) + id); - if (rc) - return; - - memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); - mptsas_sas_enclosure_pg0(ioc, &enclosure_info, - (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << - MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), - sas_device.handle_enclosure); - - mptsas_add_device_component(ioc, sas_device.channel, - sas_device.id, sas_device.sas_address, sas_device.device_info, - sas_device.slot, enclosure_info.enclosure_logical_id); -} - -/** - * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list - * @ioc: Pointer to MPT_ADAPTER structure - * @channel: fw mapped id's - * @id: - * - **/ -static void -mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, - struct scsi_target *starget) -{ - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; - dma_addr_t dma_handle; - pRaidVolumePage0_t buffer = NULL; - int i; - RaidPhysDiskPage0_t phys_disk; - struct mptsas_device_info *sas_info, *next; - - memset(&cfg, 0 , sizeof(CONFIGPARMS)); - memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); - hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; - /* assumption that all volumes on channel = 0 */ - cfg.pageAddr = starget->id; - cfg.cfghdr.hdr = &hdr; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - if (mpt_config(ioc, &cfg) != 0) - goto out; - - if (!hdr.PageLength) - goto out; - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, - &dma_handle); - - if (!buffer) - goto out; - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - if (mpt_config(ioc, &cfg) != 0) - goto out; - - if (!buffer->NumPhysDisks) - goto out; - - /* - * Adding entry for hidden components - */ - for (i = 0; i < buffer->NumPhysDisks; i++) { - - if (mpt_raid_phys_disk_pg0(ioc, - buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) - continue; - - mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, - phys_disk.PhysDiskID); - - mutex_lock(&ioc->sas_device_info_mutex); - list_for_each_entry(sas_info, &ioc->sas_device_info_list, - list) { - if (!sas_info->is_logical_volume && - (sas_info->fw.channel == phys_disk.PhysDiskBus && - sas_info->fw.id == phys_disk.PhysDiskID)) { - sas_info->is_hidden_raid_component = 1; - sas_info->volume_id = starget->id; - } - } - mutex_unlock(&ioc->sas_device_info_mutex); - - } - - /* - * Delete all matching devices out of the list - */ - mutex_lock(&ioc->sas_device_info_mutex); - list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, - list) { - if (sas_info->is_logical_volume && sas_info->fw.id == - starget->id) { - list_del(&sas_info->list); - kfree(sas_info); - } - } - - sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); - if (sas_info) { - sas_info->fw.id = starget->id; - sas_info->os.id = starget->id; - sas_info->os.channel = starget->channel; - sas_info->is_logical_volume = 1; - INIT_LIST_HEAD(&sas_info->list); - list_add_tail(&sas_info->list, &ioc->sas_device_info_list); - } - mutex_unlock(&ioc->sas_device_info_mutex); - - out: - if (buffer) - pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, - dma_handle); -} - -/** - * mptsas_add_device_component_starget - - * @ioc: Pointer to MPT_ADAPTER structure - * @starget: - * - **/ -static void -mptsas_add_device_component_starget(MPT_ADAPTER *ioc, - struct scsi_target *starget) -{ - VirtTarget *vtarget; - struct sas_rphy *rphy; - struct mptsas_phyinfo *phy_info = NULL; - struct mptsas_enclosure enclosure_info; - - rphy = dev_to_rphy(starget->dev.parent); - vtarget = starget->hostdata; - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - rphy->identify.sas_address); - if (!phy_info) - return; - - memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); - mptsas_sas_enclosure_pg0(ioc, &enclosure_info, - (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << - MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), - phy_info->attached.handle_enclosure); - - mptsas_add_device_component(ioc, phy_info->attached.channel, - phy_info->attached.id, phy_info->attached.sas_address, - phy_info->attached.device_info, - phy_info->attached.slot, enclosure_info.enclosure_logical_id); -} - -/** - * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached - * @ioc: Pointer to MPT_ADAPTER structure - * @channel: os mapped id's - * @id: - * - **/ -static void -mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - struct mptsas_device_info *sas_info, *next; - - /* - * Set is_cached flag - */ - list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, - list) { - if (sas_info->os.channel == channel && sas_info->os.id == id) - sas_info->is_cached = 1; - } -} - -/** - * mptsas_del_device_components - Cleaning the list - * @ioc: Pointer to MPT_ADAPTER structure - * - **/ -static void -mptsas_del_device_components(MPT_ADAPTER *ioc) -{ - struct mptsas_device_info *sas_info, *next; - - mutex_lock(&ioc->sas_device_info_mutex); - list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, - list) { - list_del(&sas_info->list); - kfree(sas_info); - } - mutex_unlock(&ioc->sas_device_info_mutex); -} - - -/* - * mptsas_setup_wide_ports - * - * Updates for new and existing narrow/wide port configuration - * in the sas_topology - */ -static void -mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) -{ - struct mptsas_portinfo_details * port_details; - struct mptsas_phyinfo *phy_info, *phy_info_cmp; - u64 sas_address; - int i, j; - - mutex_lock(&ioc->sas_topology_mutex); - - phy_info = port_info->phy_info; - for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { - if (phy_info->attached.handle) - continue; - port_details = phy_info->port_details; - if (!port_details) - continue; - if (port_details->num_phys < 2) - continue; - /* - * Removing a phy from a port, letting the last - * phy be removed by firmware events. - */ - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: [%p]: deleting phy = %d\n", - ioc->name, __func__, port_details, i)); - port_details->num_phys--; - port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); - memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); - if (phy_info->phy) { - devtprintk(ioc, dev_printk(KERN_DEBUG, - &phy_info->phy->dev, MYIOC_s_FMT - "delete phy %d, phy-obj (0x%p)\n", ioc->name, - phy_info->phy_id, phy_info->phy)); - sas_port_delete_phy(port_details->port, phy_info->phy); - } - phy_info->port_details = NULL; - } - - /* - * Populate and refresh the tree - */ - phy_info = port_info->phy_info; - for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { - sas_address = phy_info->attached.sas_address; - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", - ioc->name, i, (unsigned long long)sas_address)); - if (!sas_address) - continue; - port_details = phy_info->port_details; - /* - * Forming a port - */ - if (!port_details) { - port_details = kzalloc(sizeof(struct - mptsas_portinfo_details), GFP_KERNEL); - if (!port_details) - goto out; - port_details->num_phys = 1; - port_details->port_info = port_info; - if (phy_info->phy_id < 64 ) - port_details->phy_bitmask |= - (1 << phy_info->phy_id); - phy_info->sas_port_add_phy=1; - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" - "phy_id=%d sas_address=0x%018llX\n", - ioc->name, i, (unsigned long long)sas_address)); - phy_info->port_details = port_details; - } - - if (i == port_info->num_phys - 1) - continue; - phy_info_cmp = &port_info->phy_info[i + 1]; - for (j = i + 1 ; j < port_info->num_phys ; j++, - phy_info_cmp++) { - if (!phy_info_cmp->attached.sas_address) - continue; - if (sas_address != phy_info_cmp->attached.sas_address) - continue; - if (phy_info_cmp->port_details == port_details ) - continue; - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "\t\tphy_id=%d sas_address=0x%018llX\n", - ioc->name, j, (unsigned long long) - phy_info_cmp->attached.sas_address)); - if (phy_info_cmp->port_details) { - port_details->rphy = - mptsas_get_rphy(phy_info_cmp); - port_details->port = - mptsas_get_port(phy_info_cmp); - port_details->starget = - mptsas_get_starget(phy_info_cmp); - port_details->num_phys = - phy_info_cmp->port_details->num_phys; - if (!phy_info_cmp->port_details->num_phys) - kfree(phy_info_cmp->port_details); - } else - phy_info_cmp->sas_port_add_phy=1; - /* - * Adding a phy to a port - */ - phy_info_cmp->port_details = port_details; - if (phy_info_cmp->phy_id < 64 ) - port_details->phy_bitmask |= - (1 << phy_info_cmp->phy_id); - port_details->num_phys++; - } - } - - out: - - for (i = 0; i < port_info->num_phys; i++) { - port_details = port_info->phy_info[i].port_details; - if (!port_details) - continue; - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: [%p]: phy_id=%02d num_phys=%02d " - "bitmask=0x%016llX\n", ioc->name, __func__, - port_details, i, port_details->num_phys, - (unsigned long long)port_details->phy_bitmask)); - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", - ioc->name, port_details->port, port_details->rphy)); - } - dsaswideprintk(ioc, printk("\n")); - mutex_unlock(&ioc->sas_topology_mutex); -} - -/** - * csmisas_find_vtarget - * - * @ioc - * @volume_id - * @volume_bus - * - **/ -static VirtTarget * -mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - struct scsi_device *sdev; - VirtDevice *vdevice; - VirtTarget *vtarget = NULL; - - shost_for_each_device(sdev, ioc->sh) { - vdevice = sdev->hostdata; - if ((vdevice == NULL) || - (vdevice->vtarget == NULL)) - continue; - if ((vdevice->vtarget->tflags & - MPT_TARGET_FLAGS_RAID_COMPONENT || - vdevice->vtarget->raidVolume)) - continue; - if (vdevice->vtarget->id == id && - vdevice->vtarget->channel == channel) - vtarget = vdevice->vtarget; - } - return vtarget; -} - -static void -mptsas_queue_device_delete(MPT_ADAPTER *ioc, - MpiEventDataSasDeviceStatusChange_t *sas_event_data) -{ - struct fw_event_work *fw_event; - int sz; - - sz = offsetof(struct fw_event_work, event_data) + - sizeof(MpiEventDataSasDeviceStatusChange_t); - fw_event = kzalloc(sz, GFP_ATOMIC); - if (!fw_event) { - printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", - ioc->name, __func__, __LINE__); - return; - } - memcpy(fw_event->event_data, sas_event_data, - sizeof(MpiEventDataSasDeviceStatusChange_t)); - fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; - fw_event->ioc = ioc; - mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); -} - -static void -mptsas_queue_rescan(MPT_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - int sz; - - sz = offsetof(struct fw_event_work, event_data); - fw_event = kzalloc(sz, GFP_ATOMIC); - if (!fw_event) { - printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", - ioc->name, __func__, __LINE__); - return; - } - fw_event->event = -1; - fw_event->ioc = ioc; - mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); -} - - -/** - * mptsas_target_reset - * - * Issues TARGET_RESET to end device using handshaking method - * - * @ioc - * @channel - * @id - * - * Returns (1) success - * (0) failure - * - **/ -static int -mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; - if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) - return 0; - - - mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); - if (mf == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT - "%s, no msg frames @%d!!\n", ioc->name, - __func__, __LINE__)); - goto out_fail; - } - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", - ioc->name, mf)); - - /* Format the Request - */ - pScsiTm = (SCSITaskMgmt_t *) mf; - memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); - pScsiTm->TargetID = id; - pScsiTm->Bus = channel; - pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; - pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; - - DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", - ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); - - mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); - - return 1; - - out_fail: - - mpt_clear_taskmgmt_in_progress_flag(ioc); - return 0; -} - -static void -mptsas_block_io_sdev(struct scsi_device *sdev, void *data) -{ - scsi_device_set_state(sdev, SDEV_BLOCK); -} - -static void -mptsas_block_io_starget(struct scsi_target *starget) -{ - if (starget) - starget_for_each_device(starget, NULL, mptsas_block_io_sdev); -} - -/** - * mptsas_target_reset_queue - * - * Receive request for TARGET_RESET after receiving an firmware - * event NOT_RESPONDING_EVENT, then put command in link list - * and queue if task_queue already in use. - * - * @ioc - * @sas_event_data - * - **/ -static void -mptsas_target_reset_queue(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) -{ - MPT_SCSI_HOST *hd = shost_priv(ioc->sh); - VirtTarget *vtarget = NULL; - struct mptsas_target_reset_event *target_reset_list; - u8 id, channel; - - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; - - vtarget = mptsas_find_vtarget(ioc, channel, id); - if (vtarget) { - mptsas_block_io_starget(vtarget->starget); - vtarget->deleted = 1; /* block IO */ - } - - target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), - GFP_ATOMIC); - if (!target_reset_list) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT - "%s, failed to allocate mem @%d..!!\n", - ioc->name, __func__, __LINE__)); - return; - } - - memcpy(&target_reset_list->sas_event_data, sas_event_data, - sizeof(*sas_event_data)); - list_add_tail(&target_reset_list->list, &hd->target_reset_list); - - target_reset_list->time_count = jiffies; - - if (mptsas_target_reset(ioc, channel, id)) { - target_reset_list->target_reset_issued = 1; - } -} - -/** - * mptsas_schedule_target_reset- send pending target reset - * @iocp: per adapter object - * - * This function will delete scheduled target reset from the list and - * try to send next target reset. This will be called from completion - * context of any Task management command. - */ - -void -mptsas_schedule_target_reset(void *iocp) -{ - MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp); - MPT_SCSI_HOST *hd = shost_priv(ioc->sh); - struct list_head *head = &hd->target_reset_list; - struct mptsas_target_reset_event *target_reset_list; - u8 id, channel; - /* - * issue target reset to next device in the queue - */ - - head = &hd->target_reset_list; - if (list_empty(head)) - return; - - target_reset_list = list_entry(head->next, - struct mptsas_target_reset_event, list); - - id = target_reset_list->sas_event_data.TargetID; - channel = target_reset_list->sas_event_data.Bus; - target_reset_list->time_count = jiffies; - - if (mptsas_target_reset(ioc, channel, id)) - target_reset_list->target_reset_issued = 1; - return; -} - - -/** - * mptsas_taskmgmt_complete - complete SAS task management function - * @ioc: Pointer to MPT_ADAPTER structure - * - * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work - * queue to finish off removing device from upper layers. then send next - * TARGET_RESET in the queue. - **/ -static int -mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) -{ - MPT_SCSI_HOST *hd = shost_priv(ioc->sh); - struct list_head *head = &hd->target_reset_list; - u8 id, channel; - struct mptsas_target_reset_event *target_reset_list; - SCSITaskMgmtReply_t *pScsiTmReply; - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " - "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); - - pScsiTmReply = (SCSITaskMgmtReply_t *)mr; - if (pScsiTmReply) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" - "\ttask_type = 0x%02X, iocstatus = 0x%04X " - "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " - "term_cmnds = %d\n", ioc->name, - pScsiTmReply->Bus, pScsiTmReply->TargetID, - pScsiTmReply->TaskType, - le16_to_cpu(pScsiTmReply->IOCStatus), - le32_to_cpu(pScsiTmReply->IOCLogInfo), - pScsiTmReply->ResponseCode, - le32_to_cpu(pScsiTmReply->TerminationCount))); - - if (pScsiTmReply->ResponseCode) - mptscsih_taskmgmt_response_code(ioc, - pScsiTmReply->ResponseCode); - } - - if (pScsiTmReply && (pScsiTmReply->TaskType == - MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == - MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) { - ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; - memcpy(ioc->taskmgmt_cmds.reply, mr, - min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); - if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { - ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; - complete(&ioc->taskmgmt_cmds.done); - return 1; - } - return 0; - } - - mpt_clear_taskmgmt_in_progress_flag(ioc); - - if (list_empty(head)) - return 1; - - target_reset_list = list_entry(head->next, - struct mptsas_target_reset_event, list); - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TaskMgmt: completed (%d seconds)\n", - ioc->name, jiffies_to_msecs(jiffies - - target_reset_list->time_count)/1000)); - - id = pScsiTmReply->TargetID; - channel = pScsiTmReply->Bus; - target_reset_list->time_count = jiffies; - - /* - * retry target reset - */ - if (!target_reset_list->target_reset_issued) { - if (mptsas_target_reset(ioc, channel, id)) - target_reset_list->target_reset_issued = 1; - return 1; - } - - /* - * enable work queue to remove device from upper layers - */ - list_del(&target_reset_list->list); - if (!ioc->fw_events_off) - mptsas_queue_device_delete(ioc, - &target_reset_list->sas_event_data); - - - ioc->schedule_target_reset(ioc); - - return 1; -} - -/** - * mptscsih_ioc_reset - * - * @ioc - * @reset_phase - * - **/ -static int -mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) -{ - MPT_SCSI_HOST *hd; - int rc; - - rc = mptscsih_ioc_reset(ioc, reset_phase); - if ((ioc->bus_type != SAS) || (!rc)) - return rc; - - hd = shost_priv(ioc->sh); - if (!hd->ioc) - goto out; - - switch (reset_phase) { - case MPT_IOC_SETUP_RESET: - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); - mptsas_fw_event_off(ioc); - break; - case MPT_IOC_PRE_RESET: - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT_IOC_POST_RESET: - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { - ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; - complete(&ioc->sas_mgmt.done); - } - mptsas_cleanup_fw_event_q(ioc); - mptsas_queue_rescan(ioc); - break; - default: - break; - } - - out: - return rc; -} - - -/** - * enum device_state - - * @DEVICE_RETRY: need to retry the TUR - * @DEVICE_ERROR: TUR return error, don't add device - * @DEVICE_READY: device can be added - * - */ -enum device_state{ - DEVICE_RETRY, - DEVICE_ERROR, - DEVICE_READY, -}; - -static int -mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, - u32 form, u32 form_specific) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasEnclosurePage0_t *buffer; - dma_addr_t dma_handle; - int error; - __le64 le_identifier; - - memset(&hdr, 0, sizeof(hdr)); - hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; - hdr.PageNumber = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; - - cfg.cfghdr.ehdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = form + form_specific; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out; - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out_free_consistent; - - /* save config data */ - memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); - enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); - enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); - enclosure->flags = le16_to_cpu(buffer->Flags); - enclosure->num_slot = le16_to_cpu(buffer->NumSlots); - enclosure->start_slot = le16_to_cpu(buffer->StartSlot); - enclosure->start_id = buffer->StartTargetID; - enclosure->start_channel = buffer->StartBus; - enclosure->sep_id = buffer->SEPTargetID; - enclosure->sep_channel = buffer->SEPBus; - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -/** - * mptsas_add_end_device - report a new end device to sas transport layer - * @ioc: Pointer to MPT_ADAPTER structure - * @phy_info: describes attached device - * - * return (0) success (1) failure - * - **/ -static int -mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) -{ - struct sas_rphy *rphy; - struct sas_port *port; - struct sas_identify identify; - char *ds = NULL; - u8 fw_id; - - if (!phy_info) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - return 1; - } - - fw_id = phy_info->attached.id; - - if (mptsas_get_rphy(phy_info)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - return 2; - } - - port = mptsas_get_port(phy_info); - if (!port) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - return 3; - } - - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," - " phy %d, sas_addr 0x%llx\n", ioc->name, ds, - phy_info->attached.channel, phy_info->attached.id, - phy_info->attached.phy_id, (unsigned long long) - phy_info->attached.sas_address); - - mptsas_parse_device_info(&identify, &phy_info->attached); - rphy = sas_end_device_alloc(port); - if (!rphy) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - return 5; /* non-fatal: an rphy can be added later */ - } - - rphy->identify = identify; - if (sas_rphy_add(rphy)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - sas_rphy_free(rphy); - return 6; - } - mptsas_set_rphy(ioc, phy_info, rphy); - return 0; -} - -/** - * mptsas_del_end_device - report a deleted end device to sas transport layer - * @ioc: Pointer to MPT_ADAPTER structure - * @phy_info: describes attached device - * - **/ -static void -mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) -{ - struct sas_rphy *rphy; - struct sas_port *port; - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info_parent; - int i; - char *ds = NULL; - u8 fw_id; - u64 sas_address; - - if (!phy_info) - return; - - fw_id = phy_info->attached.id; - sas_address = phy_info->attached.sas_address; - - if (!phy_info->port_details) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - return; - } - rphy = mptsas_get_rphy(phy_info); - if (!rphy) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - return; - } - - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR - || phy_info->attached.device_info - & MPI_SAS_DEVICE_INFO_SMP_INITIATOR - || phy_info->attached.device_info - & MPI_SAS_DEVICE_INFO_STP_INITIATOR) - ds = "initiator"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT - "removing %s device: fw_channel %d, fw_id %d, phy %d," - "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, - phy_info->attached.id, phy_info->attached.phy_id, - (unsigned long long) sas_address); - - port = mptsas_get_port(phy_info); - if (!port) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, fw_id, __LINE__)); - return; - } - port_info = phy_info->portinfo; - phy_info_parent = port_info->phy_info; - for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { - if (!phy_info_parent->phy) - continue; - if (phy_info_parent->attached.sas_address != - sas_address) - continue; - dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, - MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", - ioc->name, phy_info_parent->phy_id, - phy_info_parent->phy); - sas_port_delete_phy(port, phy_info_parent->phy); - } - - dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT - "delete port %d, sas_addr (0x%llx)\n", ioc->name, - port->port_identifier, (unsigned long long)sas_address); - sas_port_delete(port); - mptsas_set_port(ioc, phy_info, NULL); - mptsas_port_delete(ioc, phy_info->port_details); -} - -struct mptsas_phyinfo * -mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, - struct mptsas_devinfo *sas_device) -{ - struct mptsas_phyinfo *phy_info; - struct mptsas_portinfo *port_info; - int i; - - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_device->sas_address); - if (!phy_info) - goto out; - port_info = phy_info->portinfo; - if (!port_info) - goto out; - mutex_lock(&ioc->sas_topology_mutex); - for (i = 0; i < port_info->num_phys; i++) { - if (port_info->phy_info[i].attached.sas_address != - sas_device->sas_address) - continue; - port_info->phy_info[i].attached.channel = sas_device->channel; - port_info->phy_info[i].attached.id = sas_device->id; - port_info->phy_info[i].attached.sas_address = - sas_device->sas_address; - port_info->phy_info[i].attached.handle = sas_device->handle; - port_info->phy_info[i].attached.handle_parent = - sas_device->handle_parent; - port_info->phy_info[i].attached.handle_enclosure = - sas_device->handle_enclosure; - } - mutex_unlock(&ioc->sas_topology_mutex); - out: - return phy_info; -} - -/** - * mptsas_firmware_event_work - work thread for processing fw events - * @work: work queue payload containing info describing the event - * Context: user - * - */ -static void -mptsas_firmware_event_work(struct work_struct *work) -{ - struct fw_event_work *fw_event = - container_of(work, struct fw_event_work, work.work); - MPT_ADAPTER *ioc = fw_event->ioc; - - /* special rescan topology handling */ - if (fw_event->event == -1) { - if (ioc->in_rescan) { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: rescan ignored as it is in progress\n", - ioc->name, __func__)); - return; - } - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " - "reset\n", ioc->name, __func__)); - ioc->in_rescan = 1; - mptsas_not_responding_devices(ioc); - mptsas_scan_sas_topology(ioc); - ioc->in_rescan = 0; - mptsas_free_fw_event(ioc, fw_event); - mptsas_fw_event_on(ioc); - return; - } - - /* events handling turned off during host reset */ - if (ioc->fw_events_off) { - mptsas_free_fw_event(ioc, fw_event); - return; - } - - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " - "event = (0x%02x)\n", ioc->name, __func__, fw_event, - (fw_event->event & 0xFF))); - - switch (fw_event->event) { - case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - mptsas_send_sas_event(fw_event); - break; - case MPI_EVENT_INTEGRATED_RAID: - mptsas_send_raid_event(fw_event); - break; - case MPI_EVENT_IR2: - mptsas_send_ir2_event(fw_event); - break; - case MPI_EVENT_PERSISTENT_TABLE_FULL: - mptbase_sas_persist_operation(ioc, - MPI_SAS_OP_CLEAR_NOT_PRESENT); - mptsas_free_fw_event(ioc, fw_event); - break; - case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: - mptsas_broadcast_primative_work(fw_event); - break; - case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: - mptsas_send_expander_event(fw_event); - break; - case MPI_EVENT_SAS_PHY_LINK_STATUS: - mptsas_send_link_status_event(fw_event); - break; - case MPI_EVENT_QUEUE_FULL: - mptsas_handle_queue_full_event(fw_event); - break; - } -} - - - -static int -mptsas_slave_configure(struct scsi_device *sdev) -{ - struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = shost_priv(host); - MPT_ADAPTER *ioc = hd->ioc; - VirtDevice *vdevice = sdev->hostdata; - - if (vdevice->vtarget->deleted) { - sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); - vdevice->vtarget->deleted = 0; - } - - /* - * RAID volumes placed beyond the last expected port. - * Ignore sending sas mode pages in that case.. - */ - if (sdev->channel == MPTSAS_RAID_CHANNEL) { - mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); - goto out; - } - - sas_read_port_mode_page(sdev); - - mptsas_add_device_component_starget(ioc, scsi_target(sdev)); - - out: - return mptscsih_slave_configure(sdev); -} - -static int -mptsas_target_alloc(struct scsi_target *starget) -{ - struct Scsi_Host *host = dev_to_shost(&starget->dev); - MPT_SCSI_HOST *hd = shost_priv(host); - VirtTarget *vtarget; - u8 id, channel; - struct sas_rphy *rphy; - struct mptsas_portinfo *p; - int i; - MPT_ADAPTER *ioc = hd->ioc; - - vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); - if (!vtarget) - return -ENOMEM; - - vtarget->starget = starget; - vtarget->ioc_id = ioc->id; - vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; - id = starget->id; - channel = 0; - - /* - * RAID volumes placed beyond the last expected port. - */ - if (starget->channel == MPTSAS_RAID_CHANNEL) { - if (!ioc->raid_data.pIocPg2) { - kfree(vtarget); - return -ENXIO; - } - for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { - if (id == ioc->raid_data.pIocPg2-> - RaidVolume[i].VolumeID) { - channel = ioc->raid_data.pIocPg2-> - RaidVolume[i].VolumeBus; - } - } - vtarget->raidVolume = 1; - goto out; - } - - rphy = dev_to_rphy(starget->dev.parent); - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address != - rphy->identify.sas_address) - continue; - id = p->phy_info[i].attached.id; - channel = p->phy_info[i].attached.channel; - mptsas_set_starget(&p->phy_info[i], starget); - - /* - * Exposing hidden raid components - */ - if (mptscsih_is_phys_disk(ioc, channel, id)) { - id = mptscsih_raid_id_to_num(ioc, - channel, id); - vtarget->tflags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - p->phy_info[i].attached.phys_disk_num = id; - } - mutex_unlock(&ioc->sas_topology_mutex); - goto out; - } - } - mutex_unlock(&ioc->sas_topology_mutex); - - kfree(vtarget); - return -ENXIO; - - out: - vtarget->id = id; - vtarget->channel = channel; - starget->hostdata = vtarget; - return 0; -} - -static void -mptsas_target_destroy(struct scsi_target *starget) -{ - struct Scsi_Host *host = dev_to_shost(&starget->dev); - MPT_SCSI_HOST *hd = shost_priv(host); - struct sas_rphy *rphy; - struct mptsas_portinfo *p; - int i; - MPT_ADAPTER *ioc = hd->ioc; - VirtTarget *vtarget; - - if (!starget->hostdata) - return; - - vtarget = starget->hostdata; - - mptsas_del_device_component_by_os(ioc, starget->channel, - starget->id); - - - if (starget->channel == MPTSAS_RAID_CHANNEL) - goto out; - - rphy = dev_to_rphy(starget->dev.parent); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address != - rphy->identify.sas_address) - continue; - - starget_printk(KERN_INFO, starget, MYIOC_s_FMT - "delete device: fw_channel %d, fw_id %d, phy %d, " - "sas_addr 0x%llx\n", ioc->name, - p->phy_info[i].attached.channel, - p->phy_info[i].attached.id, - p->phy_info[i].attached.phy_id, (unsigned long long) - p->phy_info[i].attached.sas_address); - - mptsas_set_starget(&p->phy_info[i], NULL); - } - } - - out: - vtarget->starget = NULL; - kfree(starget->hostdata); - starget->hostdata = NULL; -} - - -static int -mptsas_slave_alloc(struct scsi_device *sdev) -{ - struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = shost_priv(host); - struct sas_rphy *rphy; - struct mptsas_portinfo *p; - VirtDevice *vdevice; - struct scsi_target *starget; - int i; - MPT_ADAPTER *ioc = hd->ioc; - - vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdevice) { - printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", - ioc->name, sizeof(VirtDevice)); - return -ENOMEM; - } - starget = scsi_target(sdev); - vdevice->vtarget = starget->hostdata; - - if (sdev->channel == MPTSAS_RAID_CHANNEL) - goto out; - - rphy = dev_to_rphy(sdev->sdev_target->dev.parent); - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address != - rphy->identify.sas_address) - continue; - vdevice->lun = sdev->lun; - /* - * Exposing hidden raid components - */ - if (mptscsih_is_phys_disk(ioc, - p->phy_info[i].attached.channel, - p->phy_info[i].attached.id)) - sdev->no_uld_attach = 1; - mutex_unlock(&ioc->sas_topology_mutex); - goto out; - } - } - mutex_unlock(&ioc->sas_topology_mutex); - - kfree(vdevice); - return -ENXIO; - - out: - vdevice->vtarget->num_luns++; - sdev->hostdata = vdevice; - return 0; -} - -static int -mptsas_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; - VirtDevice *vdevice = SCpnt->device->hostdata; - - if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - } - - hd = shost_priv(SCpnt->device->host); - ioc = hd->ioc; - - if (ioc->sas_discovery_quiesce_io) - return SCSI_MLQUEUE_HOST_BUSY; - - if (ioc->debug_level & MPT_DEBUG_SCSI) - scsi_print_command(SCpnt); - - return mptscsih_qcmd(SCpnt,done); -} - -static DEF_SCSI_QCMD(mptsas_qcmd) - -/** - * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout - * if the device under question is currently in the - * device removal delay. - * @sc: scsi command that the midlayer is about to time out - * - **/ -static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) -{ - MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; - VirtDevice *vdevice; - enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; - - hd = shost_priv(sc->device->host); - if (hd == NULL) { - printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n", - __func__, sc); - goto done; - } - - ioc = hd->ioc; - if (ioc->bus_type != SAS) { - printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n", - __func__, sc); - goto done; - } - - /* In case if IOC is in reset from internal context. - * Do not execute EEH for the same IOC. SML should to reset timer. - */ - if (ioc->ioc_reset_in_progress) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," - "SML need to reset the timer (sc=%p)\n", - ioc->name, __func__, sc)); - rc = BLK_EH_RESET_TIMER; - } - vdevice = sc->device->hostdata; - if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD - || vdevice->vtarget->deleted)) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " - "or in device removal delay (sc=%p)\n", - ioc->name, __func__, sc)); - rc = BLK_EH_RESET_TIMER; - goto done; - } - -done: - return rc; -} - - -static struct scsi_host_template mptsas_driver_template = { - .module = THIS_MODULE, - .proc_name = "mptsas", - .proc_info = mptscsih_proc_info, - .name = "MPT SAS Host", - .info = mptscsih_info, - .queuecommand = mptsas_qcmd, - .target_alloc = mptsas_target_alloc, - .slave_alloc = mptsas_slave_alloc, - .slave_configure = mptsas_slave_configure, - .target_destroy = mptsas_target_destroy, - .slave_destroy = mptscsih_slave_destroy, - .change_queue_depth = mptscsih_change_queue_depth, - .eh_abort_handler = mptscsih_abort, - .eh_device_reset_handler = mptscsih_dev_reset, - .eh_host_reset_handler = mptscsih_host_reset, - .bios_param = mptscsih_bios_param, - .can_queue = MPT_SAS_CAN_QUEUE, - .this_id = -1, - .sg_tablesize = MPT_SCSI_SG_DEPTH, - .max_sectors = 8192, - .cmd_per_lun = 7, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = mptscsih_host_attrs, -}; - -static int mptsas_get_linkerrors(struct sas_phy *phy) -{ - MPT_ADAPTER *ioc = phy_to_ioc(phy); - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasPhyPage1_t *buffer; - dma_addr_t dma_handle; - int error; - - /* FIXME: only have link errors on local phys */ - if (!scsi_is_sas_phy_local(phy)) - return -EINVAL; - - hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; - hdr.ExtPageLength = 0; - hdr.PageNumber = 1 /* page number 1*/; - hdr.Reserved1 = 0; - hdr.Reserved2 = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; - - cfg.cfghdr.ehdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = phy->identify.phy_identifier; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - error = mpt_config(ioc, &cfg); - if (error) - return error; - if (!hdr.ExtPageLength) - return -ENXIO; - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) - return -ENOMEM; - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out_free_consistent; - - mptsas_print_phy_pg1(ioc, buffer); - - phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); - phy->running_disparity_error_count = - le32_to_cpu(buffer->RunningDisparityErrorCount); - phy->loss_of_dword_sync_count = - le32_to_cpu(buffer->LossDwordSynchCount); - phy->phy_reset_problem_count = - le32_to_cpu(buffer->PhyResetProblemCount); - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - return error; -} - -static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, - MPT_FRAME_HDR *reply) -{ - ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - if (reply != NULL) { - ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; - memcpy(ioc->sas_mgmt.reply, reply, - min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); - } - - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { - ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; - complete(&ioc->sas_mgmt.done); - return 1; - } - return 0; -} - -static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) -{ - MPT_ADAPTER *ioc = phy_to_ioc(phy); - SasIoUnitControlRequest_t *req; - SasIoUnitControlReply_t *reply; - MPT_FRAME_HDR *mf; - MPIHeader_t *hdr; - unsigned long timeleft; - int error = -ERESTARTSYS; - - /* FIXME: fusion doesn't allow non-local phy reset */ - if (!scsi_is_sas_phy_local(phy)) - return -EINVAL; - - /* not implemented for expanders */ - if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) - return -ENXIO; - - if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) - goto out; - - mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); - if (!mf) { - error = -ENOMEM; - goto out_unlock; - } - - hdr = (MPIHeader_t *) mf; - req = (SasIoUnitControlRequest_t *)mf; - memset(req, 0, sizeof(SasIoUnitControlRequest_t)); - req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; - req->MsgContext = hdr->MsgContext; - req->Operation = hard_reset ? - MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; - req->PhyNum = phy->identify.phy_identifier; - - INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) - mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); - - timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, - 10 * HZ); - if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { - error = -ETIME; - mpt_free_msg_frame(ioc, mf); - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) - goto out_unlock; - if (!timeleft) - mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); - goto out_unlock; - } - - /* a reply frame is expected */ - if ((ioc->sas_mgmt.status & - MPT_MGMT_STATUS_RF_VALID) == 0) { - error = -ENXIO; - goto out_unlock; - } - - /* process the completed Reply Message Frame */ - reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; - if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { - printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); - error = -ENXIO; - goto out_unlock; - } - - error = 0; - - out_unlock: - CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) - mutex_unlock(&ioc->sas_mgmt.mutex); - out: - return error; -} - -static int -mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) -{ - MPT_ADAPTER *ioc = rphy_to_ioc(rphy); - int i, error; - struct mptsas_portinfo *p; - struct mptsas_enclosure enclosure_info; - u64 enclosure_handle; - - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address == - rphy->identify.sas_address) { - enclosure_handle = p->phy_info[i]. - attached.handle_enclosure; - goto found_info; - } - } - } - mutex_unlock(&ioc->sas_topology_mutex); - return -ENXIO; - - found_info: - mutex_unlock(&ioc->sas_topology_mutex); - memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); - error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, - (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << - MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); - if (!error) - *identifier = enclosure_info.enclosure_logical_id; - return error; -} - -static int -mptsas_get_bay_identifier(struct sas_rphy *rphy) -{ - MPT_ADAPTER *ioc = rphy_to_ioc(rphy); - struct mptsas_portinfo *p; - int i, rc; - - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address == - rphy->identify.sas_address) { - rc = p->phy_info[i].attached.slot; - goto out; - } - } - } - rc = -ENXIO; - out: - mutex_unlock(&ioc->sas_topology_mutex); - return rc; -} - -static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, - struct request *req) -{ - MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; - MPT_FRAME_HDR *mf; - SmpPassthroughRequest_t *smpreq; - struct request *rsp = req->next_rq; - int ret; - int flagsLength; - unsigned long timeleft; - char *psge; - dma_addr_t dma_addr_in = 0; - dma_addr_t dma_addr_out = 0; - u64 sas_address = 0; - - if (!rsp) { - printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", - ioc->name, __func__); - return -EINVAL; - } - - /* do we need to support multiple segments? */ - if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { - printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", - ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req), - rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); - if (ret) - goto out; - - mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); - if (!mf) { - ret = -ENOMEM; - goto out_unlock; - } - - smpreq = (SmpPassthroughRequest_t *)mf; - memset(smpreq, 0, sizeof(*smpreq)); - - smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); - smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; - - if (rphy) - sas_address = rphy->identify.sas_address; - else { - struct mptsas_portinfo *port_info; - - mutex_lock(&ioc->sas_topology_mutex); - port_info = ioc->hba_port_info; - if (port_info && port_info->phy_info) - sas_address = - port_info->phy_info[0].phy->identify.sas_address; - mutex_unlock(&ioc->sas_topology_mutex); - } - - *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); - - psge = (char *) - (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); - - /* request */ - flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION) - << MPI_SGE_FLAGS_SHIFT; - flagsLength |= (blk_rq_bytes(req) - 4); - - dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), - blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_out) - goto put_mf; - ioc->add_sge(psge, flagsLength, dma_addr_out); - psge += ioc->SGE_size; - - /* response */ - flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_IOC_TO_HOST | - MPI_SGE_FLAGS_END_OF_BUFFER; - - flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; - flagsLength |= blk_rq_bytes(rsp) + 4; - dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), - blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_in) - goto unmap; - ioc->add_sge(psge, flagsLength, dma_addr_in); - - INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) - mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); - - timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); - if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { - ret = -ETIME; - mpt_free_msg_frame(ioc, mf); - mf = NULL; - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) - goto unmap; - if (!timeleft) - mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); - goto unmap; - } - mf = NULL; - - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { - SmpPassthroughReply_t *smprep; - - smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; - memcpy(req->sense, smprep, sizeof(*smprep)); - req->sense_len = sizeof(*smprep); - req->resid_len = 0; - rsp->resid_len -= smprep->ResponseDataLength; - } else { - printk(MYIOC_s_ERR_FMT - "%s: smp passthru reply failed to be returned\n", - ioc->name, __func__); - ret = -ENXIO; - } -unmap: - if (dma_addr_out) - pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req), - PCI_DMA_BIDIRECTIONAL); - if (dma_addr_in) - pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp), - PCI_DMA_BIDIRECTIONAL); -put_mf: - if (mf) - mpt_free_msg_frame(ioc, mf); -out_unlock: - CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) - mutex_unlock(&ioc->sas_mgmt.mutex); -out: - return ret; -} - -static struct sas_function_template mptsas_transport_functions = { - .get_linkerrors = mptsas_get_linkerrors, - .get_enclosure_identifier = mptsas_get_enclosure_identifier, - .get_bay_identifier = mptsas_get_bay_identifier, - .phy_reset = mptsas_phy_reset, - .smp_handler = mptsas_smp_handler, -}; - -static struct scsi_transport_template *mptsas_transport_template; - -static int -mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasIOUnitPage0_t *buffer; - dma_addr_t dma_handle; - int error, i; - - hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; - hdr.ExtPageLength = 0; - hdr.PageNumber = 0; - hdr.Reserved1 = 0; - hdr.Reserved2 = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - - cfg.cfghdr.ehdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = 0; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out; - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out_free_consistent; - - port_info->num_phys = buffer->NumPhys; - port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo), GFP_KERNEL); - if (!port_info->phy_info) { - error = -ENOMEM; - goto out_free_consistent; - } - - ioc->nvdata_version_persistent = - le16_to_cpu(buffer->NvdataVersionPersistent); - ioc->nvdata_version_default = - le16_to_cpu(buffer->NvdataVersionDefault); - - for (i = 0; i < port_info->num_phys; i++) { - mptsas_print_phy_data(ioc, &buffer->PhyData[i]); - port_info->phy_info[i].phy_id = i; - port_info->phy_info[i].port_id = - buffer->PhyData[i].Port; - port_info->phy_info[i].negotiated_link_rate = - buffer->PhyData[i].NegotiatedLinkRate; - port_info->phy_info[i].portinfo = port_info; - port_info->phy_info[i].handle = - le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); - } - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -static int -mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasIOUnitPage1_t *buffer; - dma_addr_t dma_handle; - int error; - u8 device_missing_delay; - - memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); - memset(&cfg, 0, sizeof(CONFIGPARMS)); - - cfg.cfghdr.ehdr = &hdr; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; - cfg.cfghdr.ehdr->PageNumber = 1; - - error = mpt_config(ioc, &cfg); - if (error) - goto out; - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out_free_consistent; - - ioc->io_missing_delay = - le16_to_cpu(buffer->IODeviceMissingDelay); - device_missing_delay = buffer->ReportDeviceMissingDelay; - ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? - (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : - device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -static int -mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, - u32 form, u32 form_specific) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasPhyPage0_t *buffer; - dma_addr_t dma_handle; - int error; - - hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; - hdr.ExtPageLength = 0; - hdr.PageNumber = 0; - hdr.Reserved1 = 0; - hdr.Reserved2 = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; - - cfg.cfghdr.ehdr = &hdr; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - /* Get Phy Pg 0 for each Phy. */ - cfg.physAddr = -1; - cfg.pageAddr = form + form_specific; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - - error = mpt_config(ioc, &cfg); - if (error) - goto out; - - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out_free_consistent; - - mptsas_print_phy_pg0(ioc, buffer); - - phy_info->hw_link_rate = buffer->HwLinkRate; - phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; - phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); - phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -static int -mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, - u32 form, u32 form_specific) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasDevicePage0_t *buffer; - dma_addr_t dma_handle; - __le64 sas_address; - int error=0; - - hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; - hdr.ExtPageLength = 0; - hdr.PageNumber = 0; - hdr.Reserved1 = 0; - hdr.Reserved2 = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; - - cfg.cfghdr.ehdr = &hdr; - cfg.pageAddr = form + form_specific; - cfg.physAddr = -1; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - memset(device_info, 0, sizeof(struct mptsas_devinfo)); - error = mpt_config(ioc, &cfg); - if (error) - goto out; - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - - if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { - error = -ENODEV; - goto out_free_consistent; - } - - if (error) - goto out_free_consistent; - - mptsas_print_device_pg0(ioc, buffer); - - memset(device_info, 0, sizeof(struct mptsas_devinfo)); - device_info->handle = le16_to_cpu(buffer->DevHandle); - device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); - device_info->handle_enclosure = - le16_to_cpu(buffer->EnclosureHandle); - device_info->slot = le16_to_cpu(buffer->Slot); - device_info->phy_id = buffer->PhyNum; - device_info->port_id = buffer->PhysicalPort; - device_info->id = buffer->TargetID; - device_info->phys_disk_num = ~0; - device_info->channel = buffer->Bus; - memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); - device_info->sas_address = le64_to_cpu(sas_address); - device_info->device_info = - le32_to_cpu(buffer->DeviceInfo); - device_info->flags = le16_to_cpu(buffer->Flags); - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -static int -mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, - u32 form, u32 form_specific) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasExpanderPage0_t *buffer; - dma_addr_t dma_handle; - int i, error; - __le64 sas_address; - - memset(port_info, 0, sizeof(struct mptsas_portinfo)); - hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; - hdr.ExtPageLength = 0; - hdr.PageNumber = 0; - hdr.Reserved1 = 0; - hdr.Reserved2 = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; - - cfg.cfghdr.ehdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = form + form_specific; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - memset(port_info, 0, sizeof(struct mptsas_portinfo)); - error = mpt_config(ioc, &cfg); - if (error) - goto out; - - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { - error = -ENODEV; - goto out_free_consistent; - } - - if (error) - goto out_free_consistent; - - /* save config data */ - port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; - port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo), GFP_KERNEL); - if (!port_info->phy_info) { - error = -ENOMEM; - goto out_free_consistent; - } - - memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); - for (i = 0; i < port_info->num_phys; i++) { - port_info->phy_info[i].portinfo = port_info; - port_info->phy_info[i].handle = - le16_to_cpu(buffer->DevHandle); - port_info->phy_info[i].identify.sas_address = - le64_to_cpu(sas_address); - port_info->phy_info[i].identify.handle_parent = - le16_to_cpu(buffer->ParentDevHandle); - } - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -static int -mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, - u32 form, u32 form_specific) -{ - ConfigExtendedPageHeader_t hdr; - CONFIGPARMS cfg; - SasExpanderPage1_t *buffer; - dma_addr_t dma_handle; - int error=0; - - hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; - hdr.ExtPageLength = 0; - hdr.PageNumber = 1; - hdr.Reserved1 = 0; - hdr.Reserved2 = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; - - cfg.cfghdr.ehdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = form + form_specific; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - error = mpt_config(ioc, &cfg); - if (error) - goto out; - - if (!hdr.ExtPageLength) { - error = -ENXIO; - goto out; - } - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - &dma_handle); - if (!buffer) { - error = -ENOMEM; - goto out; - } - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - error = mpt_config(ioc, &cfg); - - if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { - error = -ENODEV; - goto out_free_consistent; - } - - if (error) - goto out_free_consistent; - - - mptsas_print_expander_pg1(ioc, buffer); - - /* save config data */ - phy_info->phy_id = buffer->PhyIdentifier; - phy_info->port_id = buffer->PhysicalPort; - phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; - phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; - phy_info->hw_link_rate = buffer->HwLinkRate; - phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); - phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); - - out_free_consistent: - pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, - buffer, dma_handle); - out: - return error; -} - -struct rep_manu_request{ - u8 smp_frame_type; - u8 function; - u8 reserved; - u8 request_length; -}; - -struct rep_manu_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x01 */ - u8 function_result; - u8 response_length; - u16 expander_change_count; - u8 reserved0[2]; - u8 sas_format:1; - u8 reserved1:7; - u8 reserved2[3]; - u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; - u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; - u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; - u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; - u16 component_id; - u8 component_revision_id; - u8 reserved3; - u8 vendor_specific[8]; -}; - -/** - * mptsas_exp_repmanufacture_info - - * @ioc: per adapter object - * @sas_address: expander sas address - * @edev: the sas_expander_device object - * - * Fills in the sas_expander_device object when SMP port is created. - * - * Returns 0 for success, non-zero for failure. - */ -static int -mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, - u64 sas_address, struct sas_expander_device *edev) -{ - MPT_FRAME_HDR *mf; - SmpPassthroughRequest_t *smpreq; - SmpPassthroughReply_t *smprep; - struct rep_manu_reply *manufacture_reply; - struct rep_manu_request *manufacture_request; - int ret; - int flagsLength; - unsigned long timeleft; - char *psge; - unsigned long flags; - void *data_out = NULL; - dma_addr_t data_out_dma = 0; - u32 sz; - - spin_lock_irqsave(&ioc->taskmgmt_lock, flags); - if (ioc->ioc_reset_in_progress) { - spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - - ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); - if (ret) - goto out; - - mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); - if (!mf) { - ret = -ENOMEM; - goto out_unlock; - } - - smpreq = (SmpPassthroughRequest_t *)mf; - memset(smpreq, 0, sizeof(*smpreq)); - - sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); - - data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - ret = -ENOMEM; - goto put_mf; - } - - manufacture_request = data_out; - manufacture_request->smp_frame_type = 0x40; - manufacture_request->function = 1; - manufacture_request->reserved = 0; - manufacture_request->request_length = 0; - - smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; - smpreq->PhysicalPort = 0xFF; - *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); - smpreq->RequestDataLength = sizeof(struct rep_manu_request); - - psge = (char *) - (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); - - flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_HOST_TO_IOC | - MPI_SGE_FLAGS_END_OF_BUFFER; - flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; - flagsLength |= sizeof(struct rep_manu_request); - - ioc->add_sge(psge, flagsLength, data_out_dma); - psge += ioc->SGE_size; - - flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | - MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_IOC_TO_HOST | - MPI_SGE_FLAGS_END_OF_BUFFER; - flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; - flagsLength |= sizeof(struct rep_manu_reply); - ioc->add_sge(psge, flagsLength, data_out_dma + - sizeof(struct rep_manu_request)); - - INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) - mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); - - timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); - if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { - ret = -ETIME; - mpt_free_msg_frame(ioc, mf); - mf = NULL; - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) - goto out_free; - if (!timeleft) - mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); - goto out_free; - } - - mf = NULL; - - if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { - u8 *tmp; - - smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; - if (le16_to_cpu(smprep->ResponseDataLength) != - sizeof(struct rep_manu_reply)) - goto out_free; - - manufacture_reply = data_out + sizeof(struct rep_manu_request); - strncpy(edev->vendor_id, manufacture_reply->vendor_id, - SAS_EXPANDER_VENDOR_ID_LEN); - strncpy(edev->product_id, manufacture_reply->product_id, - SAS_EXPANDER_PRODUCT_ID_LEN); - strncpy(edev->product_rev, manufacture_reply->product_rev, - SAS_EXPANDER_PRODUCT_REV_LEN); - edev->level = manufacture_reply->sas_format; - if (manufacture_reply->sas_format) { - strncpy(edev->component_vendor_id, - manufacture_reply->component_vendor_id, - SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); - tmp = (u8 *)&manufacture_reply->component_id; - edev->component_id = tmp[0] << 8 | tmp[1]; - edev->component_revision_id = - manufacture_reply->component_revision_id; - } - } else { - printk(MYIOC_s_ERR_FMT - "%s: smp passthru reply failed to be returned\n", - ioc->name, __func__); - ret = -ENXIO; - } -out_free: - if (data_out_dma) - pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); -put_mf: - if (mf) - mpt_free_msg_frame(ioc, mf); -out_unlock: - CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) - mutex_unlock(&ioc->sas_mgmt.mutex); -out: - return ret; - } - -static void -mptsas_parse_device_info(struct sas_identify *identify, - struct mptsas_devinfo *device_info) -{ - u16 protocols; - - identify->sas_address = device_info->sas_address; - identify->phy_identifier = device_info->phy_id; - - /* - * Fill in Phy Initiator Port Protocol. - * Bits 6:3, more than one bit can be set, fall through cases. - */ - protocols = device_info->device_info & 0x78; - identify->initiator_port_protocols = 0; - if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; - if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_STP; - if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; - if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) - identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; - - /* - * Fill in Phy Target Port Protocol. - * Bits 10:7, more than one bit can be set, fall through cases. - */ - protocols = device_info->device_info & 0x780; - identify->target_port_protocols = 0; - if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_SSP; - if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_STP; - if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_SMP; - if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) - identify->target_port_protocols |= SAS_PROTOCOL_SATA; - - /* - * Fill in Attached device type. - */ - switch (device_info->device_info & - MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { - case MPI_SAS_DEVICE_INFO_NO_DEVICE: - identify->device_type = SAS_PHY_UNUSED; - break; - case MPI_SAS_DEVICE_INFO_END_DEVICE: - identify->device_type = SAS_END_DEVICE; - break; - case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: - identify->device_type = SAS_EDGE_EXPANDER_DEVICE; - break; - case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: - identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; - break; - } -} - -static int mptsas_probe_one_phy(struct device *dev, - struct mptsas_phyinfo *phy_info, int index, int local) -{ - MPT_ADAPTER *ioc; - struct sas_phy *phy; - struct sas_port *port; - int error = 0; - VirtTarget *vtarget; - - if (!dev) { - error = -ENODEV; - goto out; - } - - if (!phy_info->phy) { - phy = sas_phy_alloc(dev, index); - if (!phy) { - error = -ENOMEM; - goto out; - } - } else - phy = phy_info->phy; - - mptsas_parse_device_info(&phy->identify, &phy_info->identify); - - /* - * Set Negotiated link rate. - */ - switch (phy_info->negotiated_link_rate) { - case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: - phy->negotiated_linkrate = SAS_PHY_DISABLED; - break; - case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: - phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; - break; - case MPI_SAS_IOUNIT0_RATE_1_5: - phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI_SAS_IOUNIT0_RATE_3_0: - phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; - break; - case MPI_SAS_IOUNIT0_RATE_6_0: - phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; - break; - case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: - case MPI_SAS_IOUNIT0_RATE_UNKNOWN: - default: - phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; - break; - } - - /* - * Set Max hardware link rate. - */ - switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { - case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: - phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: - phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; - break; - default: - break; - } - - /* - * Set Max programmed link rate. - */ - switch (phy_info->programmed_link_rate & - MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { - case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: - phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: - phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; - break; - default: - break; - } - - /* - * Set Min hardware link rate. - */ - switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { - case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: - phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: - phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; - break; - default: - break; - } - - /* - * Set Min programmed link rate. - */ - switch (phy_info->programmed_link_rate & - MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { - case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: - phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: - phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; - break; - default: - break; - } - - if (!phy_info->phy) { - - error = sas_phy_add(phy); - if (error) { - sas_phy_free(phy); - goto out; - } - phy_info->phy = phy; - } - - if (!phy_info->attached.handle || - !phy_info->port_details) - goto out; - - port = mptsas_get_port(phy_info); - ioc = phy_to_ioc(phy_info->phy); - - if (phy_info->sas_port_add_phy) { - - if (!port) { - port = sas_port_alloc_num(dev); - if (!port) { - error = -ENOMEM; - goto out; - } - error = sas_port_add(port); - if (error) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - goto out; - } - mptsas_set_port(ioc, phy_info, port); - devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, - MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", - ioc->name, port->port_identifier, - (unsigned long long)phy_info-> - attached.sas_address)); - } - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "sas_port_add_phy: phy_id=%d\n", - ioc->name, phy_info->phy_id)); - sas_port_add_phy(port, phy_info->phy); - phy_info->sas_port_add_phy = 0; - devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, - MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, - phy_info->phy_id, phy_info->phy)); - } - if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { - - struct sas_rphy *rphy; - struct device *parent; - struct sas_identify identify; - - parent = dev->parent->parent; - /* - * Let the hotplug_work thread handle processing - * the adding/removing of devices that occur - * after start of day. - */ - if (mptsas_is_end_device(&phy_info->attached) && - phy_info->attached.handle_parent) { - goto out; - } - - mptsas_parse_device_info(&identify, &phy_info->attached); - if (scsi_is_host_device(parent)) { - struct mptsas_portinfo *port_info; - int i; - - port_info = ioc->hba_port_info; - - for (i = 0; i < port_info->num_phys; i++) - if (port_info->phy_info[i].identify.sas_address == - identify.sas_address) { - sas_port_mark_backlink(port); - goto out; - } - - } else if (scsi_is_sas_rphy(parent)) { - struct sas_rphy *parent_rphy = dev_to_rphy(parent); - if (identify.sas_address == - parent_rphy->identify.sas_address) { - sas_port_mark_backlink(port); - goto out; - } - } - - switch (identify.device_type) { - case SAS_END_DEVICE: - rphy = sas_end_device_alloc(port); - break; - case SAS_EDGE_EXPANDER_DEVICE: - case SAS_FANOUT_EXPANDER_DEVICE: - rphy = sas_expander_alloc(port, identify.device_type); - break; - default: - rphy = NULL; - break; - } - if (!rphy) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - goto out; - } - - rphy->identify = identify; - error = sas_rphy_add(rphy); - if (error) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - sas_rphy_free(rphy); - goto out; - } - mptsas_set_rphy(ioc, phy_info, rphy); - if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || - identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) - mptsas_exp_repmanufacture_info(ioc, - identify.sas_address, - rphy_to_expander_device(rphy)); - } - - /* If the device exists,verify it wasn't previously flagged - as a missing device. If so, clear it */ - vtarget = mptsas_find_vtarget(ioc, - phy_info->attached.channel, - phy_info->attached.id); - if (vtarget && vtarget->inDMD) { - printk(KERN_INFO "Device returned, unsetting inDMD\n"); - vtarget->inDMD = 0; - } - - out: - return error; -} - -static int -mptsas_probe_hba_phys(MPT_ADAPTER *ioc) -{ - struct mptsas_portinfo *port_info, *hba; - int error = -ENOMEM, i; - - hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); - if (! hba) - goto out; - - error = mptsas_sas_io_unit_pg0(ioc, hba); - if (error) - goto out_free_port_info; - - mptsas_sas_io_unit_pg1(ioc); - mutex_lock(&ioc->sas_topology_mutex); - port_info = ioc->hba_port_info; - if (!port_info) { - ioc->hba_port_info = port_info = hba; - ioc->hba_port_num_phy = port_info->num_phys; - list_add_tail(&port_info->list, &ioc->sas_topology); - } else { - for (i = 0; i < hba->num_phys; i++) { - port_info->phy_info[i].negotiated_link_rate = - hba->phy_info[i].negotiated_link_rate; - port_info->phy_info[i].handle = - hba->phy_info[i].handle; - port_info->phy_info[i].port_id = - hba->phy_info[i].port_id; - } - kfree(hba->phy_info); - kfree(hba); - hba = NULL; - } - mutex_unlock(&ioc->sas_topology_mutex); -#if defined(CPQ_CIM) - ioc->num_ports = port_info->num_phys; -#endif - for (i = 0; i < port_info->num_phys; i++) { - mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], - (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << - MPI_SAS_PHY_PGAD_FORM_SHIFT), i); - port_info->phy_info[i].identify.handle = - port_info->phy_info[i].handle; - mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].identify.handle); - if (!ioc->hba_port_sas_addr) - ioc->hba_port_sas_addr = - port_info->phy_info[i].identify.sas_address; - port_info->phy_info[i].identify.phy_id = - port_info->phy_info[i].phy_id = i; - if (port_info->phy_info[i].attached.handle) - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].attached, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].attached.handle); - } - - mptsas_setup_wide_ports(ioc, port_info); - - for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) - mptsas_probe_one_phy(&ioc->sh->shost_gendev, - &port_info->phy_info[i], ioc->sas_index, 1); - - return 0; - - out_free_port_info: - kfree(hba); - out: - return error; -} - -static void -mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) -{ - struct mptsas_portinfo *parent; - struct device *parent_dev; - struct sas_rphy *rphy; - int i; - u64 sas_address; /* expander sas address */ - u32 handle; - - handle = port_info->phy_info[0].handle; - sas_address = port_info->phy_info[0].identify.sas_address; - for (i = 0; i < port_info->num_phys; i++) { - mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); - - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].identify, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].identify.handle); - port_info->phy_info[i].identify.phy_id = - port_info->phy_info[i].phy_id; - - if (port_info->phy_info[i].attached.handle) { - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].attached, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].attached.handle); - port_info->phy_info[i].attached.phy_id = - port_info->phy_info[i].phy_id; - } - } - - mutex_lock(&ioc->sas_topology_mutex); - parent = mptsas_find_portinfo_by_handle(ioc, - port_info->phy_info[0].identify.handle_parent); - if (!parent) { - mutex_unlock(&ioc->sas_topology_mutex); - return; - } - for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; - i++) { - if (parent->phy_info[i].attached.sas_address == sas_address) { - rphy = mptsas_get_rphy(&parent->phy_info[i]); - parent_dev = &rphy->dev; - } - } - mutex_unlock(&ioc->sas_topology_mutex); - - mptsas_setup_wide_ports(ioc, port_info); - for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) - mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], - ioc->sas_index, 0); -} - -static void -mptsas_expander_event_add(MPT_ADAPTER *ioc, - MpiEventDataSasExpanderStatusChange_t *expander_data) -{ - struct mptsas_portinfo *port_info; - int i; - __le64 sas_address; - - port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); - if (!port_info) - BUG(); - port_info->num_phys = (expander_data->NumPhys) ? - expander_data->NumPhys : 1; - port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo), GFP_KERNEL); - if (!port_info->phy_info) - BUG(); - memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); - for (i = 0; i < port_info->num_phys; i++) { - port_info->phy_info[i].portinfo = port_info; - port_info->phy_info[i].handle = - le16_to_cpu(expander_data->DevHandle); - port_info->phy_info[i].identify.sas_address = - le64_to_cpu(sas_address); - port_info->phy_info[i].identify.handle_parent = - le16_to_cpu(expander_data->ParentDevHandle); - } - - mutex_lock(&ioc->sas_topology_mutex); - list_add_tail(&port_info->list, &ioc->sas_topology); - mutex_unlock(&ioc->sas_topology_mutex); - - printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " - "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, - (unsigned long long)sas_address); - - mptsas_expander_refresh(ioc, port_info); -} - -/** - * mptsas_delete_expander_siblings - remove siblings attached to expander - * @ioc: Pointer to MPT_ADAPTER structure - * @parent: the parent port_info object - * @expander: the expander port_info object - **/ -static void -mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo - *parent, struct mptsas_portinfo *expander) -{ - struct mptsas_phyinfo *phy_info; - struct mptsas_portinfo *port_info; - struct sas_rphy *rphy; - int i; - - phy_info = expander->phy_info; - for (i = 0; i < expander->num_phys; i++, phy_info++) { - rphy = mptsas_get_rphy(phy_info); - if (!rphy) - continue; - if (rphy->identify.device_type == SAS_END_DEVICE) - mptsas_del_end_device(ioc, phy_info); - } - - phy_info = expander->phy_info; - for (i = 0; i < expander->num_phys; i++, phy_info++) { - rphy = mptsas_get_rphy(phy_info); - if (!rphy) - continue; - if (rphy->identify.device_type == - MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || - rphy->identify.device_type == - MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { - port_info = mptsas_find_portinfo_by_sas_address(ioc, - rphy->identify.sas_address); - if (!port_info) - continue; - if (port_info == parent) /* backlink rphy */ - continue; - /* - Delete this expander even if the expdevpage is exists - because the parent expander is already deleted - */ - mptsas_expander_delete(ioc, port_info, 1); - } - } -} - - -/** - * mptsas_expander_delete - remove this expander - * @ioc: Pointer to MPT_ADAPTER structure - * @port_info: expander port_info struct - * @force: Flag to forcefully delete the expander - * - **/ - -static void mptsas_expander_delete(MPT_ADAPTER *ioc, - struct mptsas_portinfo *port_info, u8 force) -{ - - struct mptsas_portinfo *parent; - int i; - u64 expander_sas_address; - struct mptsas_phyinfo *phy_info; - struct mptsas_portinfo buffer; - struct mptsas_portinfo_details *port_details; - struct sas_port *port; - - if (!port_info) - return; - - /* see if expander is still there before deleting */ - mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), - port_info->phy_info[0].identify.handle); - - if (buffer.num_phys) { - kfree(buffer.phy_info); - if (!force) - return; - } - - - /* - * Obtain the port_info instance to the parent port - */ - port_details = NULL; - expander_sas_address = - port_info->phy_info[0].identify.sas_address; - parent = mptsas_find_portinfo_by_handle(ioc, - port_info->phy_info[0].identify.handle_parent); - mptsas_delete_expander_siblings(ioc, parent, port_info); - if (!parent) - goto out; - - /* - * Delete rphys in the parent that point - * to this expander. - */ - phy_info = parent->phy_info; - port = NULL; - for (i = 0; i < parent->num_phys; i++, phy_info++) { - if (!phy_info->phy) - continue; - if (phy_info->attached.sas_address != - expander_sas_address) - continue; - if (!port) { - port = mptsas_get_port(phy_info); - port_details = phy_info->port_details; - } - dev_printk(KERN_DEBUG, &phy_info->phy->dev, - MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, - phy_info->phy_id, phy_info->phy); - sas_port_delete_phy(port, phy_info->phy); - } - if (port) { - dev_printk(KERN_DEBUG, &port->dev, - MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", - ioc->name, port->port_identifier, - (unsigned long long)expander_sas_address); - sas_port_delete(port); - mptsas_port_delete(ioc, port_details); - } - out: - - printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " - "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, - (unsigned long long)expander_sas_address); - - /* - * free link - */ - list_del(&port_info->list); - kfree(port_info->phy_info); - kfree(port_info); -} - - -/** - * mptsas_send_expander_event - expanders events - * @ioc: Pointer to MPT_ADAPTER structure - * @expander_data: event data - * - * - * This function handles adding, removing, and refreshing - * device handles within the expander objects. - */ -static void -mptsas_send_expander_event(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc; - MpiEventDataSasExpanderStatusChange_t *expander_data; - struct mptsas_portinfo *port_info; - __le64 sas_address; - int i; - - ioc = fw_event->ioc; - expander_data = (MpiEventDataSasExpanderStatusChange_t *) - fw_event->event_data; - memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); - sas_address = le64_to_cpu(sas_address); - port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); - - if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { - if (port_info) { - for (i = 0; i < port_info->num_phys; i++) { - port_info->phy_info[i].portinfo = port_info; - port_info->phy_info[i].handle = - le16_to_cpu(expander_data->DevHandle); - port_info->phy_info[i].identify.sas_address = - le64_to_cpu(sas_address); - port_info->phy_info[i].identify.handle_parent = - le16_to_cpu(expander_data->ParentDevHandle); - } - mptsas_expander_refresh(ioc, port_info); - } else if (!port_info && expander_data->NumPhys) - mptsas_expander_event_add(ioc, expander_data); - } else if (expander_data->ReasonCode == - MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) - mptsas_expander_delete(ioc, port_info, 0); - - mptsas_free_fw_event(ioc, fw_event); -} - - -/** - * mptsas_expander_add - - * @ioc: Pointer to MPT_ADAPTER structure - * @handle: - * - */ -struct mptsas_portinfo * -mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) -{ - struct mptsas_portinfo buffer, *port_info; - int i; - - if ((mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) - return NULL; - - port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); - if (!port_info) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - return NULL; - } - port_info->num_phys = buffer.num_phys; - port_info->phy_info = buffer.phy_info; - for (i = 0; i < port_info->num_phys; i++) - port_info->phy_info[i].portinfo = port_info; - mutex_lock(&ioc->sas_topology_mutex); - list_add_tail(&port_info->list, &ioc->sas_topology); - mutex_unlock(&ioc->sas_topology_mutex); - printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " - "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, - (unsigned long long)buffer.phy_info[0].identify.sas_address); - mptsas_expander_refresh(ioc, port_info); - return port_info; -} - -static void -mptsas_send_link_status_event(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc; - MpiEventDataSasPhyLinkStatus_t *link_data; - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info = NULL; - __le64 sas_address; - u8 phy_num; - u8 link_rate; - - ioc = fw_event->ioc; - link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; - - memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); - sas_address = le64_to_cpu(sas_address); - link_rate = link_data->LinkRates >> 4; - phy_num = link_data->PhyNum; - - port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); - if (port_info) { - phy_info = &port_info->phy_info[phy_num]; - if (phy_info) - phy_info->negotiated_link_rate = link_rate; - } - - if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || - link_rate == MPI_SAS_IOUNIT0_RATE_3_0 || - link_rate == MPI_SAS_IOUNIT0_RATE_6_0) { - - if (!port_info) { - if (ioc->old_sas_discovery_protocal) { - port_info = mptsas_expander_add(ioc, - le16_to_cpu(link_data->DevHandle)); - if (port_info) - goto out; - } - goto out; - } - - if (port_info == ioc->hba_port_info) - mptsas_probe_hba_phys(ioc); - else - mptsas_expander_refresh(ioc, port_info); - } else if (phy_info && phy_info->phy) { - if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) - phy_info->phy->negotiated_linkrate = - SAS_PHY_DISABLED; - else if (link_rate == - MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) - phy_info->phy->negotiated_linkrate = - SAS_LINK_RATE_FAILED; - else { - phy_info->phy->negotiated_linkrate = - SAS_LINK_RATE_UNKNOWN; - if (ioc->device_missing_delay && - mptsas_is_end_device(&phy_info->attached)) { - struct scsi_device *sdev; - VirtDevice *vdevice; - u8 channel, id; - id = phy_info->attached.id; - channel = phy_info->attached.channel; - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Link down for fw_id %d:fw_channel %d\n", - ioc->name, phy_info->attached.id, - phy_info->attached.channel)); - - shost_for_each_device(sdev, ioc->sh) { - vdevice = sdev->hostdata; - if ((vdevice == NULL) || - (vdevice->vtarget == NULL)) - continue; - if ((vdevice->vtarget->tflags & - MPT_TARGET_FLAGS_RAID_COMPONENT || - vdevice->vtarget->raidVolume)) - continue; - if (vdevice->vtarget->id == id && - vdevice->vtarget->channel == - channel) - devtprintk(ioc, - printk(MYIOC_s_DEBUG_FMT - "SDEV OUTSTANDING CMDS" - "%d\n", ioc->name, - sdev->device_busy)); - } - - } - } - } - out: - mptsas_free_fw_event(ioc, fw_event); -} - -static void -mptsas_not_responding_devices(MPT_ADAPTER *ioc) -{ - struct mptsas_portinfo buffer, *port_info; - struct mptsas_device_info *sas_info; - struct mptsas_devinfo sas_device; - u32 handle; - VirtTarget *vtarget = NULL; - struct mptsas_phyinfo *phy_info; - u8 found_expander; - int retval, retry_count; - unsigned long flags; - - mpt_findImVolumes(ioc); - - spin_lock_irqsave(&ioc->taskmgmt_lock, flags); - if (ioc->ioc_reset_in_progress) { - dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: exiting due to a parallel reset \n", ioc->name, - __func__)); - spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - return; - } - spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - - /* devices, logical volumes */ - mutex_lock(&ioc->sas_device_info_mutex); - redo_device_scan: - list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { - if (sas_info->is_cached) - continue; - if (!sas_info->is_logical_volume) { - sas_device.handle = 0; - retry_count = 0; -retry_page: - retval = mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID - << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (sas_info->fw.channel << 8) + - sas_info->fw.id); - - if (sas_device.handle) - continue; - if (retval == -EBUSY) { - spin_lock_irqsave(&ioc->taskmgmt_lock, flags); - if (ioc->ioc_reset_in_progress) { - dfailprintk(ioc, - printk(MYIOC_s_DEBUG_FMT - "%s: exiting due to reset\n", - ioc->name, __func__)); - spin_unlock_irqrestore - (&ioc->taskmgmt_lock, flags); - mutex_unlock(&ioc-> - sas_device_info_mutex); - return; - } - spin_unlock_irqrestore(&ioc->taskmgmt_lock, - flags); - } - - if (retval && (retval != -ENODEV)) { - if (retry_count < 10) { - retry_count++; - goto retry_page; - } else { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s: Config page retry exceeded retry " - "count deleting device 0x%llx\n", - ioc->name, __func__, - sas_info->sas_address)); - } - } - - /* delete device */ - vtarget = mptsas_find_vtarget(ioc, - sas_info->fw.channel, sas_info->fw.id); - - if (vtarget) - vtarget->deleted = 1; - - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_info->sas_address); - - if (phy_info) { - mptsas_del_end_device(ioc, phy_info); - goto redo_device_scan; - } - } else - mptsas_volume_delete(ioc, sas_info->fw.id); - } - mutex_unlock(&ioc->sas_device_info_mutex); - - /* expanders */ - mutex_lock(&ioc->sas_topology_mutex); - redo_expander_scan: - list_for_each_entry(port_info, &ioc->sas_topology, list) { - - if (port_info->phy_info && - (!(port_info->phy_info[0].identify.device_info & - MPI_SAS_DEVICE_INFO_SMP_TARGET))) - continue; - found_expander = 0; - handle = 0xFFFF; - while (!mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && - !found_expander) { - - handle = buffer.phy_info[0].handle; - if (buffer.phy_info[0].identify.sas_address == - port_info->phy_info[0].identify.sas_address) { - found_expander = 1; - } - kfree(buffer.phy_info); - } - - if (!found_expander) { - mptsas_expander_delete(ioc, port_info, 0); - goto redo_expander_scan; - } - } - mutex_unlock(&ioc->sas_topology_mutex); -} - -/** - * mptsas_probe_expanders - adding expanders - * @ioc: Pointer to MPT_ADAPTER structure - * - **/ -static void -mptsas_probe_expanders(MPT_ADAPTER *ioc) -{ - struct mptsas_portinfo buffer, *port_info; - u32 handle; - int i; - - handle = 0xFFFF; - while (!mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { - - handle = buffer.phy_info[0].handle; - port_info = mptsas_find_portinfo_by_sas_address(ioc, - buffer.phy_info[0].identify.sas_address); - - if (port_info) { - /* refreshing handles */ - for (i = 0; i < buffer.num_phys; i++) { - port_info->phy_info[i].handle = handle; - port_info->phy_info[i].identify.handle_parent = - buffer.phy_info[0].identify.handle_parent; - } - mptsas_expander_refresh(ioc, port_info); - kfree(buffer.phy_info); - continue; - } - - port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); - if (!port_info) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - return; - } - port_info->num_phys = buffer.num_phys; - port_info->phy_info = buffer.phy_info; - for (i = 0; i < port_info->num_phys; i++) - port_info->phy_info[i].portinfo = port_info; - mutex_lock(&ioc->sas_topology_mutex); - list_add_tail(&port_info->list, &ioc->sas_topology); - mutex_unlock(&ioc->sas_topology_mutex); - printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " - "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, - (unsigned long long)buffer.phy_info[0].identify.sas_address); - mptsas_expander_refresh(ioc, port_info); - } -} - -static void -mptsas_probe_devices(MPT_ADAPTER *ioc) -{ - u16 handle; - struct mptsas_devinfo sas_device; - struct mptsas_phyinfo *phy_info; - - handle = 0xFFFF; - while (!(mptsas_sas_device_pg0(ioc, &sas_device, - MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - - handle = sas_device.handle; - - if ((sas_device.device_info & - (MPI_SAS_DEVICE_INFO_SSP_TARGET | - MPI_SAS_DEVICE_INFO_STP_TARGET | - MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) - continue; - - /* If there is no FW B_T mapping for this device then continue - * */ - if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) - || !(sas_device.flags & - MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) - continue; - - phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); - if (!phy_info) - continue; - - if (mptsas_get_rphy(phy_info)) - continue; - - mptsas_add_end_device(ioc, phy_info); - } -} - -/** - * mptsas_scan_sas_topology - - * @ioc: Pointer to MPT_ADAPTER structure - * @sas_address: - * - **/ -static void -mptsas_scan_sas_topology(MPT_ADAPTER *ioc) -{ - struct scsi_device *sdev; - int i; - - mptsas_probe_hba_phys(ioc); - mptsas_probe_expanders(ioc); - mptsas_probe_devices(ioc); - - /* - Reporting RAID volumes. - */ - if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || - !ioc->raid_data.pIocPg2->NumActiveVolumes) - return; - for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); - if (sdev) { - scsi_device_put(sdev); - continue; - } - printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " - "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, - ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); - scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, - ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); - } -} - - -static void -mptsas_handle_queue_full_event(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc; - EventDataQueueFull_t *qfull_data; - struct mptsas_device_info *sas_info; - struct scsi_device *sdev; - int depth; - int id = -1; - int channel = -1; - int fw_id, fw_channel; - u16 current_depth; - - - ioc = fw_event->ioc; - qfull_data = (EventDataQueueFull_t *)fw_event->event_data; - fw_id = qfull_data->TargetID; - fw_channel = qfull_data->Bus; - current_depth = le16_to_cpu(qfull_data->CurrentDepth); - - /* if hidden raid component, look for the volume id */ - mutex_lock(&ioc->sas_device_info_mutex); - if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { - list_for_each_entry(sas_info, &ioc->sas_device_info_list, - list) { - if (sas_info->is_cached || - sas_info->is_logical_volume) - continue; - if (sas_info->is_hidden_raid_component && - (sas_info->fw.channel == fw_channel && - sas_info->fw.id == fw_id)) { - id = sas_info->volume_id; - channel = MPTSAS_RAID_CHANNEL; - goto out; - } - } - } else { - list_for_each_entry(sas_info, &ioc->sas_device_info_list, - list) { - if (sas_info->is_cached || - sas_info->is_hidden_raid_component || - sas_info->is_logical_volume) - continue; - if (sas_info->fw.channel == fw_channel && - sas_info->fw.id == fw_id) { - id = sas_info->os.id; - channel = sas_info->os.channel; - goto out; - } - } - - } - - out: - mutex_unlock(&ioc->sas_device_info_mutex); - - if (id != -1) { - shost_for_each_device(sdev, ioc->sh) { - if (sdev->id == id && sdev->channel == channel) { - if (current_depth > sdev->queue_depth) { - sdev_printk(KERN_INFO, sdev, - "strange observation, the queue " - "depth is (%d) meanwhile fw queue " - "depth (%d)\n", sdev->queue_depth, - current_depth); - continue; - } - depth = scsi_track_queue_full(sdev, - current_depth - 1); - if (depth > 0) - sdev_printk(KERN_INFO, sdev, - "Queue depth reduced to (%d)\n", - depth); - else if (depth < 0) - sdev_printk(KERN_INFO, sdev, - "Tagged Command Queueing is being " - "disabled\n"); - else if (depth == 0) - sdev_printk(KERN_INFO, sdev, - "Queue depth not changed yet\n"); - } - } - } - - mptsas_free_fw_event(ioc, fw_event); -} - - -static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) -{ - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info = NULL; - int i; - - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { - if (!mptsas_is_end_device( - &port_info->phy_info[i].attached)) - continue; - if (port_info->phy_info[i].attached.sas_address - != sas_address) - continue; - phy_info = &port_info->phy_info[i]; - break; - } - } - mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; -} - -/** - * mptsas_find_phyinfo_by_phys_disk_num - - * @ioc: Pointer to MPT_ADAPTER structure - * @phys_disk_num: - * @channel: - * @id: - * - **/ -static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, - u8 channel, u8 id) -{ - struct mptsas_phyinfo *phy_info = NULL; - struct mptsas_portinfo *port_info; - RaidPhysDiskPage1_t *phys_disk = NULL; - int num_paths; - u64 sas_address = 0; - int i; - - phy_info = NULL; - if (!ioc->raid_data.pIocPg3) - return NULL; - /* dual port support */ - num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); - if (!num_paths) - goto out; - phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + - (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); - if (!phys_disk) - goto out; - mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); - for (i = 0; i < num_paths; i++) { - if ((phys_disk->Path[i].Flags & 1) != 0) - /* entry no longer valid */ - continue; - if ((id == phys_disk->Path[i].PhysDiskID) && - (channel == phys_disk->Path[i].PhysDiskBus)) { - memcpy(&sas_address, &phys_disk->Path[i].WWID, - sizeof(u64)); - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_address); - goto out; - } - } - - out: - kfree(phys_disk); - if (phy_info) - return phy_info; - - /* - * Extra code to handle RAID0 case, where the sas_address is not updated - * in phys_disk_page_1 when hotswapped - */ - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys && !phy_info; i++) { - if (!mptsas_is_end_device( - &port_info->phy_info[i].attached)) - continue; - if (port_info->phy_info[i].attached.phys_disk_num == ~0) - continue; - if ((port_info->phy_info[i].attached.phys_disk_num == - phys_disk_num) && - (port_info->phy_info[i].attached.id == id) && - (port_info->phy_info[i].attached.channel == - channel)) - phy_info = &port_info->phy_info[i]; - } - } - mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; -} - -static void -mptsas_reprobe_lun(struct scsi_device *sdev, void *data) -{ - int rc; - - sdev->no_uld_attach = data ? 1 : 0; - rc = scsi_device_reprobe(sdev); -} - -static void -mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) -{ - starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, - mptsas_reprobe_lun); -} - -static void -mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; - dma_addr_t dma_handle; - pRaidVolumePage0_t buffer = NULL; - RaidPhysDiskPage0_t phys_disk; - int i; - struct mptsas_phyinfo *phy_info; - struct mptsas_devinfo sas_device; - - memset(&cfg, 0 , sizeof(CONFIGPARMS)); - memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); - hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; - cfg.pageAddr = (channel << 8) + id; - cfg.cfghdr.hdr = &hdr; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; - - if (mpt_config(ioc, &cfg) != 0) - goto out; - - if (!hdr.PageLength) - goto out; - - buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, - &dma_handle); - - if (!buffer) - goto out; - - cfg.physAddr = dma_handle; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - if (mpt_config(ioc, &cfg) != 0) - goto out; - - if (!(buffer->VolumeStatus.Flags & - MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) - goto out; - - if (!buffer->NumPhysDisks) - goto out; - - for (i = 0; i < buffer->NumPhysDisks; i++) { - - if (mpt_raid_phys_disk_pg0(ioc, - buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) - continue; - - if (mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (phys_disk.PhysDiskBus << 8) + - phys_disk.PhysDiskID)) - continue; - - /* If there is no FW B_T mapping for this device then continue - * */ - if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) - || !(sas_device.flags & - MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) - continue; - - - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_device.sas_address); - mptsas_add_end_device(ioc, phy_info); - } - - out: - if (buffer) - pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, - dma_handle); -} -/* - * Work queue thread to handle SAS hotplug events - */ -static void -mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, - struct mptsas_hotplug_event *hot_plug_info) -{ - struct mptsas_phyinfo *phy_info; - struct scsi_target * starget; - struct mptsas_devinfo sas_device; - VirtTarget *vtarget; - int i; - struct mptsas_portinfo *port_info; - - switch (hot_plug_info->event_type) { - - case MPTSAS_ADD_PHYSDISK: - - if (!ioc->raid_data.pIocPg2) - break; - - for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { - if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == - hot_plug_info->id) { - printk(MYIOC_s_WARN_FMT "firmware bug: unable " - "to add hidden disk - target_id matchs " - "volume_id\n", ioc->name); - mptsas_free_fw_event(ioc, fw_event); - return; - } - } - mpt_findImVolumes(ioc); - - case MPTSAS_ADD_DEVICE: - memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); - mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (hot_plug_info->channel << 8) + - hot_plug_info->id); - - /* If there is no FW B_T mapping for this device then break - * */ - if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) - || !(sas_device.flags & - MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) - break; - - if (!sas_device.handle) - return; - - phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); - /* Only For SATA Device ADD */ - if (!phy_info && (sas_device.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE)) { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s %d SATA HOT PLUG: " - "parent handle of device %x\n", ioc->name, - __func__, __LINE__, sas_device.handle_parent)); - port_info = mptsas_find_portinfo_by_handle(ioc, - sas_device.handle_parent); - - if (port_info == ioc->hba_port_info) - mptsas_probe_hba_phys(ioc); - else if (port_info) - mptsas_expander_refresh(ioc, port_info); - else { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s %d port info is NULL\n", - ioc->name, __func__, __LINE__)); - break; - } - phy_info = mptsas_refreshing_device_handles - (ioc, &sas_device); - } - - if (!phy_info) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s %d phy info is NULL\n", - ioc->name, __func__, __LINE__)); - break; - } - - if (mptsas_get_rphy(phy_info)) - break; - - mptsas_add_end_device(ioc, phy_info); - break; - - case MPTSAS_DEL_DEVICE: - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - hot_plug_info->sas_address); - mptsas_del_end_device(ioc, phy_info); - break; - - case MPTSAS_DEL_PHYSDISK: - - mpt_findImVolumes(ioc); - - phy_info = mptsas_find_phyinfo_by_phys_disk_num( - ioc, hot_plug_info->phys_disk_num, - hot_plug_info->channel, - hot_plug_info->id); - mptsas_del_end_device(ioc, phy_info); - break; - - case MPTSAS_ADD_PHYSDISK_REPROBE: - - if (mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (hot_plug_info->channel << 8) + hot_plug_info->id)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - /* If there is no FW B_T mapping for this device then break - * */ - if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) - || !(sas_device.flags & - MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) - break; - - phy_info = mptsas_find_phyinfo_by_sas_address( - ioc, sas_device.sas_address); - - if (!phy_info) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - starget = mptsas_get_starget(phy_info); - if (!starget) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - vtarget = starget->hostdata; - if (!vtarget) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - mpt_findImVolumes(ioc); - - starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " - "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", - ioc->name, hot_plug_info->channel, hot_plug_info->id, - hot_plug_info->phys_disk_num, (unsigned long long) - sas_device.sas_address); - - vtarget->id = hot_plug_info->phys_disk_num; - vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; - phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; - mptsas_reprobe_target(starget, 1); - break; - - case MPTSAS_DEL_PHYSDISK_REPROBE: - - if (mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (hot_plug_info->channel << 8) + hot_plug_info->id)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", - ioc->name, __func__, - hot_plug_info->id, __LINE__)); - break; - } - - /* If there is no FW B_T mapping for this device then break - * */ - if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) - || !(sas_device.flags & - MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) - break; - - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_device.sas_address); - if (!phy_info) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - starget = mptsas_get_starget(phy_info); - if (!starget) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - vtarget = starget->hostdata; - if (!vtarget) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: fw_id=%d exit at line=%d\n", ioc->name, - __func__, hot_plug_info->id, __LINE__)); - break; - } - - mpt_findImVolumes(ioc); - - starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" - " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", - ioc->name, hot_plug_info->channel, hot_plug_info->id, - hot_plug_info->phys_disk_num, (unsigned long long) - sas_device.sas_address); - - vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; - vtarget->id = hot_plug_info->id; - phy_info->attached.phys_disk_num = ~0; - mptsas_reprobe_target(starget, 0); - mptsas_add_device_component_by_fw(ioc, - hot_plug_info->channel, hot_plug_info->id); - break; - - case MPTSAS_ADD_RAID: - - mpt_findImVolumes(ioc); - printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " - "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, - hot_plug_info->id); - scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, - hot_plug_info->id, 0); - break; - - case MPTSAS_DEL_RAID: - - mpt_findImVolumes(ioc); - printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " - "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, - hot_plug_info->id); - scsi_remove_device(hot_plug_info->sdev); - scsi_device_put(hot_plug_info->sdev); - break; - - case MPTSAS_ADD_INACTIVE_VOLUME: - - mpt_findImVolumes(ioc); - mptsas_adding_inactive_raid_components(ioc, - hot_plug_info->channel, hot_plug_info->id); - break; - - default: - break; - } - - mptsas_free_fw_event(ioc, fw_event); -} - -static void -mptsas_send_sas_event(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc; - struct mptsas_hotplug_event hot_plug_info; - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; - u32 device_info; - u64 sas_address; - - ioc = fw_event->ioc; - sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) - fw_event->event_data; - device_info = le32_to_cpu(sas_event_data->DeviceInfo); - - if ((device_info & - (MPI_SAS_DEVICE_INFO_SSP_TARGET | - MPI_SAS_DEVICE_INFO_STP_TARGET | - MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { - mptsas_free_fw_event(ioc, fw_event); - return; - } - - if (sas_event_data->ReasonCode == - MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { - mptbase_sas_persist_operation(ioc, - MPI_SAS_OP_CLEAR_NOT_PRESENT); - mptsas_free_fw_event(ioc, fw_event); - return; - } - - switch (sas_event_data->ReasonCode) { - case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: - memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); - hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); - hot_plug_info.channel = sas_event_data->Bus; - hot_plug_info.id = sas_event_data->TargetID; - hot_plug_info.phy_id = sas_event_data->PhyNum; - memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(u64)); - hot_plug_info.sas_address = le64_to_cpu(sas_address); - hot_plug_info.device_info = device_info; - if (sas_event_data->ReasonCode & - MPI_EVENT_SAS_DEV_STAT_RC_ADDED) - hot_plug_info.event_type = MPTSAS_ADD_DEVICE; - else - hot_plug_info.event_type = MPTSAS_DEL_DEVICE; - mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); - break; - - case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: - mptbase_sas_persist_operation(ioc, - MPI_SAS_OP_CLEAR_NOT_PRESENT); - mptsas_free_fw_event(ioc, fw_event); - break; - - case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - /* TODO */ - case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - /* TODO */ - default: - mptsas_free_fw_event(ioc, fw_event); - break; - } -} - -static void -mptsas_send_raid_event(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc; - EVENT_DATA_RAID *raid_event_data; - struct mptsas_hotplug_event hot_plug_info; - int status; - int state; - struct scsi_device *sdev = NULL; - VirtDevice *vdevice = NULL; - RaidPhysDiskPage0_t phys_disk; - - ioc = fw_event->ioc; - raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; - status = le32_to_cpu(raid_event_data->SettingsStatus); - state = (status >> 8) & 0xff; - - memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); - hot_plug_info.id = raid_event_data->VolumeID; - hot_plug_info.channel = raid_event_data->VolumeBus; - hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; - - if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || - raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || - raid_event_data->ReasonCode == - MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - hot_plug_info.id, 0); - hot_plug_info.sdev = sdev; - if (sdev) - vdevice = sdev->hostdata; - } - - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " - "ReasonCode=%02x\n", ioc->name, __func__, - raid_event_data->ReasonCode)); - - switch (raid_event_data->ReasonCode) { - case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: - hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; - break; - case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: - hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; - break; - case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: - switch (state) { - case MPI_PD_STATE_ONLINE: - case MPI_PD_STATE_NOT_COMPATIBLE: - mpt_raid_phys_disk_pg0(ioc, - raid_event_data->PhysDiskNum, &phys_disk); - hot_plug_info.id = phys_disk.PhysDiskID; - hot_plug_info.channel = phys_disk.PhysDiskBus; - hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; - break; - case MPI_PD_STATE_FAILED: - case MPI_PD_STATE_MISSING: - case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: - case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: - case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: - hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; - break; - default: - break; - } - break; - case MPI_EVENT_RAID_RC_VOLUME_DELETED: - if (!sdev) - break; - vdevice->vtarget->deleted = 1; /* block IO */ - hot_plug_info.event_type = MPTSAS_DEL_RAID; - break; - case MPI_EVENT_RAID_RC_VOLUME_CREATED: - if (sdev) { - scsi_device_put(sdev); - break; - } - hot_plug_info.event_type = MPTSAS_ADD_RAID; - break; - case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: - if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { - if (!sdev) - break; - vdevice->vtarget->deleted = 1; /* block IO */ - hot_plug_info.event_type = MPTSAS_DEL_RAID; - break; - } - switch (state) { - case MPI_RAIDVOL0_STATUS_STATE_FAILED: - case MPI_RAIDVOL0_STATUS_STATE_MISSING: - if (!sdev) - break; - vdevice->vtarget->deleted = 1; /* block IO */ - hot_plug_info.event_type = MPTSAS_DEL_RAID; - break; - case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: - case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: - if (sdev) { - scsi_device_put(sdev); - break; - } - hot_plug_info.event_type = MPTSAS_ADD_RAID; - break; - default: - break; - } - break; - default: - break; - } - - if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) - mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); - else - mptsas_free_fw_event(ioc, fw_event); -} - -/** - * mptsas_issue_tm - send mptsas internal tm request - * @ioc: Pointer to MPT_ADAPTER structure - * @type: Task Management type - * @channel: channel number for task management - * @id: Logical Target ID for reset (if appropriate) - * @lun: Logical unit for reset (if appropriate) - * @task_context: Context for the task to be aborted - * @timeout: timeout for task management control - * - * return 0 on success and -1 on failure: - * - */ -static int -mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, - int task_context, ulong timeout, u8 *issue_reset) -{ - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; - int retval; - unsigned long timeleft; - - *issue_reset = 0; - mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); - if (mf == NULL) { - retval = -1; /* return failure */ - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " - "msg frames!!\n", ioc->name)); - goto out; - } - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " - "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " - "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, - type, timeout, channel, id, (unsigned long long)lun, - task_context)); - - pScsiTm = (SCSITaskMgmt_t *) mf; - memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); - pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; - pScsiTm->TaskType = type; - pScsiTm->MsgFlags = 0; - pScsiTm->TargetID = id; - pScsiTm->Bus = channel; - pScsiTm->ChainOffset = 0; - pScsiTm->Reserved = 0; - pScsiTm->Reserved1 = 0; - pScsiTm->TaskMsgContext = task_context; - int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); - - INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) - CLEAR_MGMT_STATUS(ioc->internal_cmds.status) - retval = 0; - mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); - - /* Now wait for the command to complete */ - timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, - timeout*HZ); - if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { - retval = -1; /* return failure */ - dtmprintk(ioc, printk(MYIOC_s_ERR_FMT - "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); - mpt_free_msg_frame(ioc, mf); - if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) - goto out; - *issue_reset = 1; - goto out; - } - - if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { - retval = -1; /* return failure */ - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TaskMgmt request: failed with no reply\n", ioc->name)); - goto out; - } - - out: - CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) - return retval; -} - -/** - * mptsas_broadcast_primative_work - Handle broadcast primitives - * @work: work queue payload containing info describing the event - * - * this will be handled in workqueue context. - */ -static void -mptsas_broadcast_primative_work(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc = fw_event->ioc; - MPT_FRAME_HDR *mf; - VirtDevice *vdevice; - int ii; - struct scsi_cmnd *sc; - SCSITaskMgmtReply_t *pScsiTmReply; - u8 issue_reset; - int task_context; - u8 channel, id; - int lun; - u32 termination_count; - u32 query_count; - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s - enter\n", ioc->name, __func__)); - - mutex_lock(&ioc->taskmgmt_cmds.mutex); - if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { - mutex_unlock(&ioc->taskmgmt_cmds.mutex); - mptsas_requeue_fw_event(ioc, fw_event, 1000); - return; - } - - issue_reset = 0; - termination_count = 0; - query_count = 0; - mpt_findImVolumes(ioc); - pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; - - for (ii = 0; ii < ioc->req_depth; ii++) { - if (ioc->fw_events_off) - goto out; - sc = mptscsih_get_scsi_lookup(ioc, ii); - if (!sc) - continue; - mf = MPT_INDEX_2_MFPTR(ioc, ii); - if (!mf) - continue; - task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; - vdevice = sc->device->hostdata; - if (!vdevice || !vdevice->vtarget) - continue; - if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) - continue; /* skip hidden raid components */ - if (vdevice->vtarget->raidVolume) - continue; /* skip hidden raid components */ - channel = vdevice->vtarget->channel; - id = vdevice->vtarget->id; - lun = vdevice->lun; - if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, - channel, id, (u64)lun, task_context, 30, &issue_reset)) - goto out; - query_count++; - termination_count += - le32_to_cpu(pScsiTmReply->TerminationCount); - if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && - (pScsiTmReply->ResponseCode == - MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || - pScsiTmReply->ResponseCode == - MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) - continue; - if (mptsas_issue_tm(ioc, - MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, - channel, id, (u64)lun, 0, 30, &issue_reset)) - goto out; - termination_count += - le32_to_cpu(pScsiTmReply->TerminationCount); - } - - out: - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "%s - exit, query_count = %d termination_count = %d\n", - ioc->name, __func__, query_count, termination_count)); - - ioc->broadcast_aen_busy = 0; - mpt_clear_taskmgmt_in_progress_flag(ioc); - mutex_unlock(&ioc->taskmgmt_cmds.mutex); - - if (issue_reset) { - printk(MYIOC_s_WARN_FMT - "Issuing Reset from %s!! doorbell=0x%08x\n", - ioc->name, __func__, mpt_GetIocState(ioc, 0)); - mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); - } - mptsas_free_fw_event(ioc, fw_event); -} - -/* - * mptsas_send_ir2_event - handle exposing hidden disk when - * an inactive raid volume is added - * - * @ioc: Pointer to MPT_ADAPTER structure - * @ir2_data - * - */ -static void -mptsas_send_ir2_event(struct fw_event_work *fw_event) -{ - MPT_ADAPTER *ioc; - struct mptsas_hotplug_event hot_plug_info; - MPI_EVENT_DATA_IR2 *ir2_data; - u8 reasonCode; - RaidPhysDiskPage0_t phys_disk; - - ioc = fw_event->ioc; - ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; - reasonCode = ir2_data->ReasonCode; - - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " - "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); - - memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); - hot_plug_info.id = ir2_data->TargetID; - hot_plug_info.channel = ir2_data->Bus; - switch (reasonCode) { - case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: - hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; - break; - case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: - hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; - hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; - break; - case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: - hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; - mpt_raid_phys_disk_pg0(ioc, - ir2_data->PhysDiskNum, &phys_disk); - hot_plug_info.id = phys_disk.PhysDiskID; - hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; - break; - default: - mptsas_free_fw_event(ioc, fw_event); - return; - } - mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); -} - -static int -mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) -{ - u32 event = le32_to_cpu(reply->Event); - int sz, event_data_sz; - struct fw_event_work *fw_event; - unsigned long delay; - - if (ioc->bus_type != SAS) - return 0; - - /* events turned off due to host reset or driver unloading */ - if (ioc->fw_events_off) - return 0; - - delay = msecs_to_jiffies(1); - switch (event) { - case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: - { - EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = - (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; - if (broadcast_event_data->Primitive != - MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) - return 0; - if (ioc->broadcast_aen_busy) - return 0; - ioc->broadcast_aen_busy = 1; - break; - } - case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - { - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = - (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; - u16 ioc_stat; - ioc_stat = le16_to_cpu(reply->IOCStatus); - - if (sas_event_data->ReasonCode == - MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { - mptsas_target_reset_queue(ioc, sas_event_data); - return 0; - } - if (sas_event_data->ReasonCode == - MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && - ioc->device_missing_delay && - (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { - VirtTarget *vtarget = NULL; - u8 id, channel; - - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; - - vtarget = mptsas_find_vtarget(ioc, channel, id); - if (vtarget) { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "LogInfo (0x%x) available for " - "INTERNAL_DEVICE_RESET" - "fw_id %d fw_channel %d\n", ioc->name, - le32_to_cpu(reply->IOCLogInfo), - id, channel)); - if (vtarget->raidVolume) { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Skipping Raid Volume for inDMD\n", - ioc->name)); - } else { - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Setting device flag inDMD\n", - ioc->name)); - vtarget->inDMD = 1; - } - - } - - } - - break; - } - case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: - { - MpiEventDataSasExpanderStatusChange_t *expander_data = - (MpiEventDataSasExpanderStatusChange_t *)reply->Data; - - if (ioc->old_sas_discovery_protocal) - return 0; - - if (expander_data->ReasonCode == - MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && - ioc->device_missing_delay) - delay = HZ * ioc->device_missing_delay; - break; - } - case MPI_EVENT_SAS_DISCOVERY: - { - u32 discovery_status; - EventDataSasDiscovery_t *discovery_data = - (EventDataSasDiscovery_t *)reply->Data; - - discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); - ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; - if (ioc->old_sas_discovery_protocal && !discovery_status) - mptsas_queue_rescan(ioc); - return 0; - } - case MPI_EVENT_INTEGRATED_RAID: - case MPI_EVENT_PERSISTENT_TABLE_FULL: - case MPI_EVENT_IR2: - case MPI_EVENT_SAS_PHY_LINK_STATUS: - case MPI_EVENT_QUEUE_FULL: - break; - default: - return 0; - } - - event_data_sz = ((reply->MsgLength * 4) - - offsetof(EventNotificationReply_t, Data)); - sz = offsetof(struct fw_event_work, event_data) + event_data_sz; - fw_event = kzalloc(sz, GFP_ATOMIC); - if (!fw_event) { - printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, - __func__, __LINE__); - return 0; - } - memcpy(fw_event->event_data, reply->Data, event_data_sz); - fw_event->event = event; - fw_event->ioc = ioc; - mptsas_add_fw_event(ioc, fw_event, delay); - return 0; -} - -/* Delete a volume when no longer listed in ioc pg2 - */ -static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) -{ - struct scsi_device *sdev; - int i; - - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); - if (!sdev) - return; - if (!ioc->raid_data.pIocPg2) - goto out; - if (!ioc->raid_data.pIocPg2->NumActiveVolumes) - goto out; - for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) - if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) - goto release_sdev; - out: - printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " - "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); - scsi_remove_device(sdev); - release_sdev: - scsi_device_put(sdev); -} - -static int -mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct Scsi_Host *sh; - MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; - unsigned long flags; - int ii; - int numSGE = 0; - int scale; - int ioc_cap; - int error=0; - int r; - - r = mpt_attach(pdev,id); - if (r) - return r; - - ioc = pci_get_drvdata(pdev); - mptsas_fw_event_off(ioc); - ioc->DoneCtx = mptsasDoneCtx; - ioc->TaskCtx = mptsasTaskCtx; - ioc->InternalCtx = mptsasInternalCtx; - ioc->schedule_target_reset = &mptsas_schedule_target_reset; - ioc->schedule_dead_ioc_flush_running_cmds = - &mptscsih_flush_running_cmds; - /* Added sanity check on readiness of the MPT adapter. - */ - if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { - printk(MYIOC_s_WARN_FMT - "Skipping because it's not operational!\n", - ioc->name); - error = -ENODEV; - goto out_mptsas_probe; - } - - if (!ioc->active) { - printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", - ioc->name); - error = -ENODEV; - goto out_mptsas_probe; - } - - /* Sanity check - ensure at least 1 port is INITIATOR capable - */ - ioc_cap = 0; - for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) { - if (ioc->pfacts[ii].ProtocolFlags & - MPI_PORTFACTS_PROTOCOL_INITIATOR) - ioc_cap++; - } - - if (!ioc_cap) { - printk(MYIOC_s_WARN_FMT - "Skipping ioc=%p because SCSI Initiator mode " - "is NOT enabled!\n", ioc->name, ioc); - return 0; - } - - sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST)); - if (!sh) { - printk(MYIOC_s_WARN_FMT - "Unable to register controller with SCSI subsystem\n", - ioc->name); - error = -1; - goto out_mptsas_probe; - } - - spin_lock_irqsave(&ioc->FreeQlock, flags); - - /* Attach the SCSI Host to the IOC structure - */ - ioc->sh = sh; - - sh->io_port = 0; - sh->n_io_port = 0; - sh->irq = 0; - - /* set 16 byte cdb's */ - sh->max_cmd_len = 16; - sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); - sh->max_id = -1; - sh->max_lun = max_lun; - sh->transportt = mptsas_transport_template; - - /* Required entry. - */ - sh->unique_id = ioc->id; - - INIT_LIST_HEAD(&ioc->sas_topology); - mutex_init(&ioc->sas_topology_mutex); - mutex_init(&ioc->sas_discovery_mutex); - mutex_init(&ioc->sas_mgmt.mutex); - init_completion(&ioc->sas_mgmt.done); - - /* Verify that we won't exceed the maximum - * number of chain buffers - * We can optimize: ZZ = req_sz/sizeof(SGE) - * For 32bit SGE's: - * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ - * + (req_sz - 64)/sizeof(SGE) - * A slightly different algorithm is required for - * 64bit SGEs. - */ - scale = ioc->req_sz/ioc->SGE_size; - if (ioc->sg_addr_size == sizeof(u64)) { - numSGE = (scale - 1) * - (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / ioc->SGE_size; - } else { - numSGE = 1 + (scale - 1) * - (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / ioc->SGE_size; - } - - if (numSGE < sh->sg_tablesize) { - /* Reset this value */ - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Resetting sg_tablesize to %d from %d\n", - ioc->name, numSGE, sh->sg_tablesize)); - sh->sg_tablesize = numSGE; - } - - if (mpt_loadtime_max_sectors) { - if (mpt_loadtime_max_sectors < 64 || - mpt_loadtime_max_sectors > 8192) { - printk(MYIOC_s_INFO_FMT "Invalid value passed for" - "mpt_loadtime_max_sectors %d." - "Range from 64 to 8192\n", ioc->name, - mpt_loadtime_max_sectors); - } - mpt_loadtime_max_sectors &= 0xFFFFFFFE; - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Resetting max sector to %d from %d\n", - ioc->name, mpt_loadtime_max_sectors, sh->max_sectors)); - sh->max_sectors = mpt_loadtime_max_sectors; - } - - hd = shost_priv(sh); - hd->ioc = ioc; - - /* SCSI needs scsi_cmnd lookup table! - * (with size equal to req_depth*PtrSz!) - */ - ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); - if (!ioc->ScsiLookup) { - error = -ENOMEM; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - goto out_mptsas_probe; - } - spin_lock_init(&ioc->scsi_lookup_lock); - - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", - ioc->name, ioc->ScsiLookup)); - - ioc->sas_data.ptClear = mpt_pt_clear; - - hd->last_queue_full = 0; - INIT_LIST_HEAD(&hd->target_reset_list); - INIT_LIST_HEAD(&ioc->sas_device_info_list); - mutex_init(&ioc->sas_device_info_mutex); - - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - if (ioc->sas_data.ptClear==1) { - mptbase_sas_persist_operation( - ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); - } - - error = scsi_add_host(sh, &ioc->pcidev->dev); - if (error) { - dprintk(ioc, printk(MYIOC_s_ERR_FMT - "scsi_add_host failed\n", ioc->name)); - goto out_mptsas_probe; - } - - /* older firmware doesn't support expander events */ - if ((ioc->facts.HeaderVersion >> 8) < 0xE) - ioc->old_sas_discovery_protocal = 1; - mptsas_scan_sas_topology(ioc); - mptsas_fw_event_on(ioc); - return 0; - - out_mptsas_probe: - - mptscsih_remove(pdev); - return error; -} - -void -mptsas_shutdown(struct pci_dev *pdev) -{ - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - - mptsas_fw_event_off(ioc); - mptsas_cleanup_fw_event_q(ioc); -} - -static void __devexit mptsas_remove(struct pci_dev *pdev) -{ - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct mptsas_portinfo *p, *n; - int i; - - if (!ioc->sh) { - printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name); - mpt_detach(pdev); - return; - } - - mptsas_shutdown(pdev); - - mptsas_del_device_components(ioc); - - ioc->sas_discovery_ignore_events = 1; - sas_remove_host(ioc->sh); - - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { - list_del(&p->list); - for (i = 0 ; i < p->num_phys ; i++) - mptsas_port_delete(ioc, p->phy_info[i].port_details); - - kfree(p->phy_info); - kfree(p); - } - mutex_unlock(&ioc->sas_topology_mutex); - ioc->hba_port_info = NULL; - mptscsih_remove(pdev); -} - -static struct pci_device_id mptsas_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP, - PCI_ANY_ID, PCI_ANY_ID }, - {0} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, mptsas_pci_table); - - -static struct pci_driver mptsas_driver = { - .name = "mptsas", - .id_table = mptsas_pci_table, - .probe = mptsas_probe, - .remove = __devexit_p(mptsas_remove), - .shutdown = mptsas_shutdown, -#ifdef CONFIG_PM - .suspend = mptscsih_suspend, - .resume = mptscsih_resume, -#endif -}; - -static int __init -mptsas_init(void) -{ - int error; - - show_mptmod_ver(my_NAME, my_VERSION); - - mptsas_transport_template = - sas_attach_transport(&mptsas_transport_functions); - if (!mptsas_transport_template) - return -ENODEV; - mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out; - - mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER, - "mptscsih_io_done"); - mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER, - "mptscsih_taskmgmt_complete"); - mptsasInternalCtx = - mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER, - "mptscsih_scandv_complete"); - mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER, - "mptsas_mgmt_done"); - mptsasDeviceResetCtx = - mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER, - "mptsas_taskmgmt_complete"); - - mpt_event_register(mptsasDoneCtx, mptsas_event_process); - mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); - - error = pci_register_driver(&mptsas_driver); - if (error) - sas_release_transport(mptsas_transport_template); - - return error; -} - -static void __exit -mptsas_exit(void) -{ - pci_unregister_driver(&mptsas_driver); - sas_release_transport(mptsas_transport_template); - - mpt_reset_deregister(mptsasDoneCtx); - mpt_event_deregister(mptsasDoneCtx); - - mpt_deregister(mptsasMgmtCtx); - mpt_deregister(mptsasInternalCtx); - mpt_deregister(mptsasTaskCtx); - mpt_deregister(mptsasDoneCtx); - mpt_deregister(mptsasDeviceResetCtx); -} - -module_init(mptsas_init); -module_exit(mptsas_exit); |