162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/message/fusion/mptsas.c 362306a36Sopenharmony_ci * For use with LSI PCI chip/adapter(s) 462306a36Sopenharmony_ci * running LSI Fusion MPT (Message Passing Technology) firmware. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 1999-2008 LSI Corporation 762306a36Sopenharmony_ci * (mailto:DL-MPTFusionLinux@lsi.com) 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 1262306a36Sopenharmony_ci it under the terms of the GNU General Public License as published by 1362306a36Sopenharmony_ci the Free Software Foundation; version 2 of the License. 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci This program is distributed in the hope that it will be useful, 1662306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 1762306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1862306a36Sopenharmony_ci GNU General Public License for more details. 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci NO WARRANTY 2162306a36Sopenharmony_ci THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2262306a36Sopenharmony_ci CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2362306a36Sopenharmony_ci LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2462306a36Sopenharmony_ci MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2562306a36Sopenharmony_ci solely responsible for determining the appropriateness of using and 2662306a36Sopenharmony_ci distributing the Program and assumes all risks associated with its 2762306a36Sopenharmony_ci exercise of rights under this Agreement, including but not limited to 2862306a36Sopenharmony_ci the risks and costs of program errors, damage to or loss of data, 2962306a36Sopenharmony_ci programs or equipment, and unavailability or interruption of operations. 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci DISCLAIMER OF LIABILITY 3262306a36Sopenharmony_ci NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3362306a36Sopenharmony_ci DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3462306a36Sopenharmony_ci DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3562306a36Sopenharmony_ci ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3662306a36Sopenharmony_ci TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 3762306a36Sopenharmony_ci USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 3862306a36Sopenharmony_ci HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci You should have received a copy of the GNU General Public License 4162306a36Sopenharmony_ci along with this program; if not, write to the Free Software 4262306a36Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4362306a36Sopenharmony_ci*/ 4462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <linux/module.h> 4762306a36Sopenharmony_ci#include <linux/kernel.h> 4862306a36Sopenharmony_ci#include <linux/slab.h> 4962306a36Sopenharmony_ci#include <linux/init.h> 5062306a36Sopenharmony_ci#include <linux/errno.h> 5162306a36Sopenharmony_ci#include <linux/jiffies.h> 5262306a36Sopenharmony_ci#include <linux/workqueue.h> 5362306a36Sopenharmony_ci#include <linux/delay.h> /* for mdelay */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include <scsi/scsi.h> 5662306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 5762306a36Sopenharmony_ci#include <scsi/scsi_device.h> 5862306a36Sopenharmony_ci#include <scsi/scsi_host.h> 5962306a36Sopenharmony_ci#include <scsi/scsi_transport_sas.h> 6062306a36Sopenharmony_ci#include <scsi/scsi_transport.h> 6162306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#include "mptbase.h" 6462306a36Sopenharmony_ci#include "mptscsih.h" 6562306a36Sopenharmony_ci#include "mptsas.h" 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define my_NAME "Fusion MPT SAS Host driver" 6962306a36Sopenharmony_ci#define my_VERSION MPT_LINUX_VERSION_COMMON 7062306a36Sopenharmony_ci#define MYNAM "mptsas" 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * Reserved channel for integrated raid 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci#define MPTSAS_RAID_CHANNEL 1 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define SAS_CONFIG_PAGE_TIMEOUT 30 7862306a36Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR); 7962306a36Sopenharmony_ciMODULE_DESCRIPTION(my_NAME); 8062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 8162306a36Sopenharmony_ciMODULE_VERSION(my_VERSION); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int mpt_pt_clear; 8462306a36Sopenharmony_cimodule_param(mpt_pt_clear, int, 0); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_pt_clear, 8662306a36Sopenharmony_ci " Clear persistency table: enable=1 " 8762306a36Sopenharmony_ci "(default=MPTSCSIH_PT_CLEAR=0)"); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* scsi-mid layer global parameter is max_report_luns, which is 511 */ 9062306a36Sopenharmony_ci#define MPTSAS_MAX_LUN (16895) 9162306a36Sopenharmony_cistatic int max_lun = MPTSAS_MAX_LUN; 9262306a36Sopenharmony_cimodule_param(max_lun, int, 0); 9362306a36Sopenharmony_ciMODULE_PARM_DESC(max_lun, " max lun, default=16895 "); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int mpt_loadtime_max_sectors = 8192; 9662306a36Sopenharmony_cimodule_param(mpt_loadtime_max_sectors, int, 0); 9762306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_loadtime_max_sectors, 9862306a36Sopenharmony_ci " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192"); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; 10162306a36Sopenharmony_cistatic u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; 10262306a36Sopenharmony_cistatic u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ 10362306a36Sopenharmony_cistatic u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; 10462306a36Sopenharmony_cistatic u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void mptsas_firmware_event_work(struct work_struct *work); 10762306a36Sopenharmony_cistatic void mptsas_send_sas_event(struct fw_event_work *fw_event); 10862306a36Sopenharmony_cistatic void mptsas_send_raid_event(struct fw_event_work *fw_event); 10962306a36Sopenharmony_cistatic void mptsas_send_ir2_event(struct fw_event_work *fw_event); 11062306a36Sopenharmony_cistatic void mptsas_parse_device_info(struct sas_identify *identify, 11162306a36Sopenharmony_ci struct mptsas_devinfo *device_info); 11262306a36Sopenharmony_cistatic inline void mptsas_set_rphy(MPT_ADAPTER *ioc, 11362306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); 11462306a36Sopenharmony_cistatic struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address 11562306a36Sopenharmony_ci (MPT_ADAPTER *ioc, u64 sas_address); 11662306a36Sopenharmony_cistatic int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, 11762306a36Sopenharmony_ci struct mptsas_devinfo *device_info, u32 form, u32 form_specific); 11862306a36Sopenharmony_cistatic int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, 11962306a36Sopenharmony_ci struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); 12062306a36Sopenharmony_cistatic int mptsas_add_end_device(MPT_ADAPTER *ioc, 12162306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info); 12262306a36Sopenharmony_cistatic void mptsas_del_end_device(MPT_ADAPTER *ioc, 12362306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info); 12462306a36Sopenharmony_cistatic void mptsas_send_link_status_event(struct fw_event_work *fw_event); 12562306a36Sopenharmony_cistatic struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address 12662306a36Sopenharmony_ci (MPT_ADAPTER *ioc, u64 sas_address); 12762306a36Sopenharmony_cistatic void mptsas_expander_delete(MPT_ADAPTER *ioc, 12862306a36Sopenharmony_ci struct mptsas_portinfo *port_info, u8 force); 12962306a36Sopenharmony_cistatic void mptsas_send_expander_event(struct fw_event_work *fw_event); 13062306a36Sopenharmony_cistatic void mptsas_not_responding_devices(MPT_ADAPTER *ioc); 13162306a36Sopenharmony_cistatic void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); 13262306a36Sopenharmony_cistatic void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event); 13362306a36Sopenharmony_cistatic void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); 13462306a36Sopenharmony_cistatic void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); 13562306a36Sopenharmony_civoid mptsas_schedule_target_reset(void *ioc); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void mptsas_print_phy_data(MPT_ADAPTER *ioc, 13862306a36Sopenharmony_ci MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 14162306a36Sopenharmony_ci "---- IO UNIT PAGE 0 ------------\n", ioc->name)); 14262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", 14362306a36Sopenharmony_ci ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle))); 14462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n", 14562306a36Sopenharmony_ci ioc->name, le16_to_cpu(phy_data->ControllerDevHandle))); 14662306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n", 14762306a36Sopenharmony_ci ioc->name, phy_data->Port)); 14862306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n", 14962306a36Sopenharmony_ci ioc->name, phy_data->PortFlags)); 15062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n", 15162306a36Sopenharmony_ci ioc->name, phy_data->PhyFlags)); 15262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", 15362306a36Sopenharmony_ci ioc->name, phy_data->NegotiatedLinkRate)); 15462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 15562306a36Sopenharmony_ci "Controller PHY Device Info=0x%X\n", ioc->name, 15662306a36Sopenharmony_ci le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); 15762306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n", 15862306a36Sopenharmony_ci ioc->name, le32_to_cpu(phy_data->DiscoveryStatus))); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci __le64 sas_address; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 16862306a36Sopenharmony_ci "---- SAS PHY PAGE 0 ------------\n", ioc->name)); 16962306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 17062306a36Sopenharmony_ci "Attached Device Handle=0x%X\n", ioc->name, 17162306a36Sopenharmony_ci le16_to_cpu(pg0->AttachedDevHandle))); 17262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", 17362306a36Sopenharmony_ci ioc->name, (unsigned long long)le64_to_cpu(sas_address))); 17462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 17562306a36Sopenharmony_ci "Attached PHY Identifier=0x%X\n", ioc->name, 17662306a36Sopenharmony_ci pg0->AttachedPhyIdentifier)); 17762306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n", 17862306a36Sopenharmony_ci ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo))); 17962306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", 18062306a36Sopenharmony_ci ioc->name, pg0->ProgrammedLinkRate)); 18162306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n", 18262306a36Sopenharmony_ci ioc->name, pg0->ChangeCount)); 18362306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n", 18462306a36Sopenharmony_ci ioc->name, le32_to_cpu(pg0->PhyInfo))); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 19062306a36Sopenharmony_ci "---- SAS PHY PAGE 1 ------------\n", ioc->name)); 19162306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n", 19262306a36Sopenharmony_ci ioc->name, pg1->InvalidDwordCount)); 19362306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 19462306a36Sopenharmony_ci "Running Disparity Error Count=0x%x\n", ioc->name, 19562306a36Sopenharmony_ci pg1->RunningDisparityErrorCount)); 19662306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 19762306a36Sopenharmony_ci "Loss Dword Synch Count=0x%x\n", ioc->name, 19862306a36Sopenharmony_ci pg1->LossDwordSynchCount)); 19962306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 20062306a36Sopenharmony_ci "PHY Reset Problem Count=0x%x\n\n", ioc->name, 20162306a36Sopenharmony_ci pg1->PhyResetProblemCount)); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci __le64 sas_address; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 21162306a36Sopenharmony_ci "---- SAS DEVICE PAGE 0 ---------\n", ioc->name)); 21262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", 21362306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg0->DevHandle))); 21462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n", 21562306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg0->ParentDevHandle))); 21662306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n", 21762306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg0->EnclosureHandle))); 21862306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n", 21962306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg0->Slot))); 22062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", 22162306a36Sopenharmony_ci ioc->name, (unsigned long long)le64_to_cpu(sas_address))); 22262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n", 22362306a36Sopenharmony_ci ioc->name, pg0->TargetID)); 22462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n", 22562306a36Sopenharmony_ci ioc->name, pg0->Bus)); 22662306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n", 22762306a36Sopenharmony_ci ioc->name, pg0->PhyNum)); 22862306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n", 22962306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg0->AccessStatus))); 23062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n", 23162306a36Sopenharmony_ci ioc->name, le32_to_cpu(pg0->DeviceInfo))); 23262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n", 23362306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg0->Flags))); 23462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n", 23562306a36Sopenharmony_ci ioc->name, pg0->PhysicalPort)); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 24162306a36Sopenharmony_ci "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name)); 24262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n", 24362306a36Sopenharmony_ci ioc->name, pg1->PhysicalPort)); 24462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n", 24562306a36Sopenharmony_ci ioc->name, pg1->PhyIdentifier)); 24662306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", 24762306a36Sopenharmony_ci ioc->name, pg1->NegotiatedLinkRate)); 24862306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", 24962306a36Sopenharmony_ci ioc->name, pg1->ProgrammedLinkRate)); 25062306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n", 25162306a36Sopenharmony_ci ioc->name, pg1->HwLinkRate)); 25262306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n", 25362306a36Sopenharmony_ci ioc->name, le16_to_cpu(pg1->OwnerDevHandle))); 25462306a36Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 25562306a36Sopenharmony_ci "Attached Device Handle=0x%X\n\n", ioc->name, 25662306a36Sopenharmony_ci le16_to_cpu(pg1->AttachedDevHandle))); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/* inhibit sas firmware event handling */ 26062306a36Sopenharmony_cistatic void 26162306a36Sopenharmony_cimptsas_fw_event_off(MPT_ADAPTER *ioc) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci unsigned long flags; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 26662306a36Sopenharmony_ci ioc->fw_events_off = 1; 26762306a36Sopenharmony_ci ioc->sas_discovery_quiesce_io = 0; 26862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* enable sas firmware event handling */ 27362306a36Sopenharmony_cistatic void 27462306a36Sopenharmony_cimptsas_fw_event_on(MPT_ADAPTER *ioc) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci unsigned long flags; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 27962306a36Sopenharmony_ci ioc->fw_events_off = 0; 28062306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* queue a sas firmware event */ 28462306a36Sopenharmony_cistatic void 28562306a36Sopenharmony_cimptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, 28662306a36Sopenharmony_ci unsigned long delay) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci unsigned long flags; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 29162306a36Sopenharmony_ci list_add_tail(&fw_event->list, &ioc->fw_event_list); 29262306a36Sopenharmony_ci fw_event->users = 1; 29362306a36Sopenharmony_ci INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); 29462306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" 29562306a36Sopenharmony_ci "on cpuid %d\n", ioc->name, __func__, 29662306a36Sopenharmony_ci fw_event, smp_processor_id())); 29762306a36Sopenharmony_ci queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, 29862306a36Sopenharmony_ci &fw_event->work, delay); 29962306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* requeue a sas firmware event */ 30362306a36Sopenharmony_cistatic void 30462306a36Sopenharmony_cimptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, 30562306a36Sopenharmony_ci unsigned long delay) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci unsigned long flags; 30862306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 30962306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " 31062306a36Sopenharmony_ci "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__, 31162306a36Sopenharmony_ci fw_event, smp_processor_id())); 31262306a36Sopenharmony_ci fw_event->retries++; 31362306a36Sopenharmony_ci queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, 31462306a36Sopenharmony_ci &fw_event->work, msecs_to_jiffies(delay)); 31562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void __mptsas_free_fw_event(MPT_ADAPTER *ioc, 31962306a36Sopenharmony_ci struct fw_event_work *fw_event) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", 32262306a36Sopenharmony_ci ioc->name, __func__, fw_event)); 32362306a36Sopenharmony_ci list_del(&fw_event->list); 32462306a36Sopenharmony_ci kfree(fw_event); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* free memory associated to a sas firmware event */ 32862306a36Sopenharmony_cistatic void 32962306a36Sopenharmony_cimptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci unsigned long flags; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 33462306a36Sopenharmony_ci fw_event->users--; 33562306a36Sopenharmony_ci if (!fw_event->users) 33662306a36Sopenharmony_ci __mptsas_free_fw_event(ioc, fw_event); 33762306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* walk the firmware event queue, and either stop or wait for 34162306a36Sopenharmony_ci * outstanding events to complete */ 34262306a36Sopenharmony_cistatic void 34362306a36Sopenharmony_cimptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct fw_event_work *fw_event; 34662306a36Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list, *n; 34762306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 34862306a36Sopenharmony_ci unsigned long flags; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* flush the target_reset_list */ 35162306a36Sopenharmony_ci if (!list_empty(&hd->target_reset_list)) { 35262306a36Sopenharmony_ci list_for_each_entry_safe(target_reset_list, n, 35362306a36Sopenharmony_ci &hd->target_reset_list, list) { 35462306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 35562306a36Sopenharmony_ci "%s: removing target reset for id=%d\n", 35662306a36Sopenharmony_ci ioc->name, __func__, 35762306a36Sopenharmony_ci target_reset_list->sas_event_data.TargetID)); 35862306a36Sopenharmony_ci list_del(&target_reset_list->list); 35962306a36Sopenharmony_ci kfree(target_reset_list); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (list_empty(&ioc->fw_event_list) || !ioc->fw_event_q) 36462306a36Sopenharmony_ci return; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci while (!list_empty(&ioc->fw_event_list)) { 36962306a36Sopenharmony_ci bool canceled = false; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci fw_event = list_first_entry(&ioc->fw_event_list, 37262306a36Sopenharmony_ci struct fw_event_work, list); 37362306a36Sopenharmony_ci fw_event->users++; 37462306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 37562306a36Sopenharmony_ci if (cancel_delayed_work_sync(&fw_event->work)) 37662306a36Sopenharmony_ci canceled = true; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 37962306a36Sopenharmony_ci if (canceled) 38062306a36Sopenharmony_ci fw_event->users--; 38162306a36Sopenharmony_ci fw_event->users--; 38262306a36Sopenharmony_ci WARN_ON_ONCE(fw_event->users); 38362306a36Sopenharmony_ci __mptsas_free_fw_event(ioc, fw_event); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 39262306a36Sopenharmony_ci return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 39862306a36Sopenharmony_ci return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* 40262306a36Sopenharmony_ci * mptsas_find_portinfo_by_handle 40362306a36Sopenharmony_ci * 40462306a36Sopenharmony_ci * This function should be called with the sas_topology_mutex already held 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cistatic struct mptsas_portinfo * 40762306a36Sopenharmony_cimptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct mptsas_portinfo *port_info, *rc=NULL; 41062306a36Sopenharmony_ci int i; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) 41362306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 41462306a36Sopenharmony_ci if (port_info->phy_info[i].identify.handle == handle) { 41562306a36Sopenharmony_ci rc = port_info; 41662306a36Sopenharmony_ci goto out; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci out: 41962306a36Sopenharmony_ci return rc; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/** 42362306a36Sopenharmony_ci * mptsas_find_portinfo_by_sas_address - find and return portinfo for 42462306a36Sopenharmony_ci * this sas_address 42562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 42662306a36Sopenharmony_ci * @sas_address: expander sas address 42762306a36Sopenharmony_ci * 42862306a36Sopenharmony_ci * This function should be called with the sas_topology_mutex already held. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * Return: %NULL if not found. 43162306a36Sopenharmony_ci **/ 43262306a36Sopenharmony_cistatic struct mptsas_portinfo * 43362306a36Sopenharmony_cimptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct mptsas_portinfo *port_info, *rc = NULL; 43662306a36Sopenharmony_ci int i; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (sas_address >= ioc->hba_port_sas_addr && 43962306a36Sopenharmony_ci sas_address < (ioc->hba_port_sas_addr + 44062306a36Sopenharmony_ci ioc->hba_port_num_phy)) 44162306a36Sopenharmony_ci return ioc->hba_port_info; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 44462306a36Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) 44562306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 44662306a36Sopenharmony_ci if (port_info->phy_info[i].identify.sas_address == 44762306a36Sopenharmony_ci sas_address) { 44862306a36Sopenharmony_ci rc = port_info; 44962306a36Sopenharmony_ci goto out; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci out: 45262306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 45362306a36Sopenharmony_ci return rc; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* 45762306a36Sopenharmony_ci * Returns true if there is a scsi end device 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_cistatic inline int 46062306a36Sopenharmony_cimptsas_is_end_device(struct mptsas_devinfo * attached) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci if ((attached->sas_address) && 46362306a36Sopenharmony_ci (attached->device_info & 46462306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_END_DEVICE) && 46562306a36Sopenharmony_ci ((attached->device_info & 46662306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SSP_TARGET) | 46762306a36Sopenharmony_ci (attached->device_info & 46862306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET) | 46962306a36Sopenharmony_ci (attached->device_info & 47062306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE))) 47162306a36Sopenharmony_ci return 1; 47262306a36Sopenharmony_ci else 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/* no mutex */ 47762306a36Sopenharmony_cistatic void 47862306a36Sopenharmony_cimptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 48162306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 48262306a36Sopenharmony_ci u8 i; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (!port_details) 48562306a36Sopenharmony_ci return; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci port_info = port_details->port_info; 48862306a36Sopenharmony_ci phy_info = port_info->phy_info; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " 49162306a36Sopenharmony_ci "bitmask=0x%016llX\n", ioc->name, __func__, port_details, 49262306a36Sopenharmony_ci port_details->num_phys, (unsigned long long) 49362306a36Sopenharmony_ci port_details->phy_bitmask)); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, phy_info++) { 49662306a36Sopenharmony_ci if(phy_info->port_details != port_details) 49762306a36Sopenharmony_ci continue; 49862306a36Sopenharmony_ci memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); 49962306a36Sopenharmony_ci mptsas_set_rphy(ioc, phy_info, NULL); 50062306a36Sopenharmony_ci phy_info->port_details = NULL; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci kfree(port_details); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic inline struct sas_rphy * 50662306a36Sopenharmony_cimptsas_get_rphy(struct mptsas_phyinfo *phy_info) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci if (phy_info->port_details) 50962306a36Sopenharmony_ci return phy_info->port_details->rphy; 51062306a36Sopenharmony_ci else 51162306a36Sopenharmony_ci return NULL; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic inline void 51562306a36Sopenharmony_cimptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci if (phy_info->port_details) { 51862306a36Sopenharmony_ci phy_info->port_details->rphy = rphy; 51962306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", 52062306a36Sopenharmony_ci ioc->name, rphy)); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (rphy) { 52462306a36Sopenharmony_ci dsaswideprintk(ioc, dev_printk(KERN_DEBUG, 52562306a36Sopenharmony_ci &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); 52662306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", 52762306a36Sopenharmony_ci ioc->name, rphy, rphy->dev.release)); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic inline struct sas_port * 53262306a36Sopenharmony_cimptsas_get_port(struct mptsas_phyinfo *phy_info) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci if (phy_info->port_details) 53562306a36Sopenharmony_ci return phy_info->port_details->port; 53662306a36Sopenharmony_ci else 53762306a36Sopenharmony_ci return NULL; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic inline void 54162306a36Sopenharmony_cimptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci if (phy_info->port_details) 54462306a36Sopenharmony_ci phy_info->port_details->port = port; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (port) { 54762306a36Sopenharmony_ci dsaswideprintk(ioc, dev_printk(KERN_DEBUG, 54862306a36Sopenharmony_ci &port->dev, MYIOC_s_FMT "add:", ioc->name)); 54962306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n", 55062306a36Sopenharmony_ci ioc->name, port, port->dev.release)); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic inline struct scsi_target * 55562306a36Sopenharmony_cimptsas_get_starget(struct mptsas_phyinfo *phy_info) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci if (phy_info->port_details) 55862306a36Sopenharmony_ci return phy_info->port_details->starget; 55962306a36Sopenharmony_ci else 56062306a36Sopenharmony_ci return NULL; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic inline void 56462306a36Sopenharmony_cimptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * 56562306a36Sopenharmony_cistarget) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci if (phy_info->port_details) 56862306a36Sopenharmony_ci phy_info->port_details->starget = starget; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/** 57262306a36Sopenharmony_ci * mptsas_add_device_component - adds a new device component to our lists 57362306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 57462306a36Sopenharmony_ci * @channel: channel number 57562306a36Sopenharmony_ci * @id: Logical Target ID for reset (if appropriate) 57662306a36Sopenharmony_ci * @sas_address: expander sas address 57762306a36Sopenharmony_ci * @device_info: specific bits (flags) for devices 57862306a36Sopenharmony_ci * @slot: enclosure slot ID 57962306a36Sopenharmony_ci * @enclosure_logical_id: enclosure WWN 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci **/ 58262306a36Sopenharmony_cistatic void 58362306a36Sopenharmony_cimptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, 58462306a36Sopenharmony_ci u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 58762306a36Sopenharmony_ci struct scsi_device *sdev; 58862306a36Sopenharmony_ci struct scsi_target *starget; 58962306a36Sopenharmony_ci struct sas_rphy *rphy; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* 59262306a36Sopenharmony_ci * Delete all matching devices out of the list 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 59562306a36Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 59662306a36Sopenharmony_ci list) { 59762306a36Sopenharmony_ci if (!sas_info->is_logical_volume && 59862306a36Sopenharmony_ci (sas_info->sas_address == sas_address || 59962306a36Sopenharmony_ci (sas_info->fw.channel == channel && 60062306a36Sopenharmony_ci sas_info->fw.id == id))) { 60162306a36Sopenharmony_ci list_del(&sas_info->list); 60262306a36Sopenharmony_ci kfree(sas_info); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); 60762306a36Sopenharmony_ci if (!sas_info) 60862306a36Sopenharmony_ci goto out; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* 61162306a36Sopenharmony_ci * Set Firmware mapping 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_ci sas_info->fw.id = id; 61462306a36Sopenharmony_ci sas_info->fw.channel = channel; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci sas_info->sas_address = sas_address; 61762306a36Sopenharmony_ci sas_info->device_info = device_info; 61862306a36Sopenharmony_ci sas_info->slot = slot; 61962306a36Sopenharmony_ci sas_info->enclosure_logical_id = enclosure_logical_id; 62062306a36Sopenharmony_ci INIT_LIST_HEAD(&sas_info->list); 62162306a36Sopenharmony_ci list_add_tail(&sas_info->list, &ioc->sas_device_info_list); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * Set OS mapping 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 62762306a36Sopenharmony_ci starget = scsi_target(sdev); 62862306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 62962306a36Sopenharmony_ci if (rphy->identify.sas_address == sas_address) { 63062306a36Sopenharmony_ci sas_info->os.id = starget->id; 63162306a36Sopenharmony_ci sas_info->os.channel = starget->channel; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci out: 63662306a36Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 63762306a36Sopenharmony_ci return; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/** 64162306a36Sopenharmony_ci * mptsas_add_device_component_by_fw - adds a new device component by FW ID 64262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 64362306a36Sopenharmony_ci * @channel: channel number 64462306a36Sopenharmony_ci * @id: Logical Target ID 64562306a36Sopenharmony_ci * 64662306a36Sopenharmony_ci **/ 64762306a36Sopenharmony_cistatic void 64862306a36Sopenharmony_cimptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct mptsas_devinfo sas_device; 65162306a36Sopenharmony_ci struct mptsas_enclosure enclosure_info; 65262306a36Sopenharmony_ci int rc; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci rc = mptsas_sas_device_pg0(ioc, &sas_device, 65562306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 65662306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 65762306a36Sopenharmony_ci (channel << 8) + id); 65862306a36Sopenharmony_ci if (rc) 65962306a36Sopenharmony_ci return; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); 66262306a36Sopenharmony_ci mptsas_sas_enclosure_pg0(ioc, &enclosure_info, 66362306a36Sopenharmony_ci (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << 66462306a36Sopenharmony_ci MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), 66562306a36Sopenharmony_ci sas_device.handle_enclosure); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci mptsas_add_device_component(ioc, sas_device.channel, 66862306a36Sopenharmony_ci sas_device.id, sas_device.sas_address, sas_device.device_info, 66962306a36Sopenharmony_ci sas_device.slot, enclosure_info.enclosure_logical_id); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/** 67362306a36Sopenharmony_ci * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list 67462306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 67562306a36Sopenharmony_ci * @starget: SCSI target for this SCSI device 67662306a36Sopenharmony_ci * 67762306a36Sopenharmony_ci **/ 67862306a36Sopenharmony_cistatic void 67962306a36Sopenharmony_cimptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, 68062306a36Sopenharmony_ci struct scsi_target *starget) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci CONFIGPARMS cfg; 68362306a36Sopenharmony_ci ConfigPageHeader_t hdr; 68462306a36Sopenharmony_ci dma_addr_t dma_handle; 68562306a36Sopenharmony_ci pRaidVolumePage0_t buffer = NULL; 68662306a36Sopenharmony_ci int i; 68762306a36Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 68862306a36Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 69162306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 69262306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; 69362306a36Sopenharmony_ci /* assumption that all volumes on channel = 0 */ 69462306a36Sopenharmony_ci cfg.pageAddr = starget->id; 69562306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 69662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 69762306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 70062306a36Sopenharmony_ci goto out; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (!hdr.PageLength) 70362306a36Sopenharmony_ci goto out; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 70662306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (!buffer) 70962306a36Sopenharmony_ci goto out; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci cfg.physAddr = dma_handle; 71262306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 71562306a36Sopenharmony_ci goto out; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (!buffer->NumPhysDisks) 71862306a36Sopenharmony_ci goto out; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* 72162306a36Sopenharmony_ci * Adding entry for hidden components 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci for (i = 0; i < buffer->NumPhysDisks; i++) { 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (mpt_raid_phys_disk_pg0(ioc, 72662306a36Sopenharmony_ci buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) 72762306a36Sopenharmony_ci continue; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, 73062306a36Sopenharmony_ci phys_disk.PhysDiskID); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 73362306a36Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, 73462306a36Sopenharmony_ci list) { 73562306a36Sopenharmony_ci if (!sas_info->is_logical_volume && 73662306a36Sopenharmony_ci (sas_info->fw.channel == phys_disk.PhysDiskBus && 73762306a36Sopenharmony_ci sas_info->fw.id == phys_disk.PhysDiskID)) { 73862306a36Sopenharmony_ci sas_info->is_hidden_raid_component = 1; 73962306a36Sopenharmony_ci sas_info->volume_id = starget->id; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * Delete all matching devices out of the list 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 75062306a36Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 75162306a36Sopenharmony_ci list) { 75262306a36Sopenharmony_ci if (sas_info->is_logical_volume && sas_info->fw.id == 75362306a36Sopenharmony_ci starget->id) { 75462306a36Sopenharmony_ci list_del(&sas_info->list); 75562306a36Sopenharmony_ci kfree(sas_info); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); 76062306a36Sopenharmony_ci if (sas_info) { 76162306a36Sopenharmony_ci sas_info->fw.id = starget->id; 76262306a36Sopenharmony_ci sas_info->os.id = starget->id; 76362306a36Sopenharmony_ci sas_info->os.channel = starget->channel; 76462306a36Sopenharmony_ci sas_info->is_logical_volume = 1; 76562306a36Sopenharmony_ci INIT_LIST_HEAD(&sas_info->list); 76662306a36Sopenharmony_ci list_add_tail(&sas_info->list, &ioc->sas_device_info_list); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci out: 77162306a36Sopenharmony_ci if (buffer) 77262306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 77362306a36Sopenharmony_ci buffer, dma_handle); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/** 77762306a36Sopenharmony_ci * mptsas_add_device_component_starget - adds a SCSI target device component 77862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 77962306a36Sopenharmony_ci * @starget: SCSI target for this SCSI device 78062306a36Sopenharmony_ci * 78162306a36Sopenharmony_ci **/ 78262306a36Sopenharmony_cistatic void 78362306a36Sopenharmony_cimptsas_add_device_component_starget(MPT_ADAPTER *ioc, 78462306a36Sopenharmony_ci struct scsi_target *starget) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct sas_rphy *rphy; 78762306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 78862306a36Sopenharmony_ci struct mptsas_enclosure enclosure_info; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 79162306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 79262306a36Sopenharmony_ci rphy->identify.sas_address); 79362306a36Sopenharmony_ci if (!phy_info) 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); 79762306a36Sopenharmony_ci mptsas_sas_enclosure_pg0(ioc, &enclosure_info, 79862306a36Sopenharmony_ci (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << 79962306a36Sopenharmony_ci MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), 80062306a36Sopenharmony_ci phy_info->attached.handle_enclosure); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci mptsas_add_device_component(ioc, phy_info->attached.channel, 80362306a36Sopenharmony_ci phy_info->attached.id, phy_info->attached.sas_address, 80462306a36Sopenharmony_ci phy_info->attached.device_info, 80562306a36Sopenharmony_ci phy_info->attached.slot, enclosure_info.enclosure_logical_id); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/** 80962306a36Sopenharmony_ci * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached 81062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 81162306a36Sopenharmony_ci * @channel: os mapped id's 81262306a36Sopenharmony_ci * @id: Logical Target ID 81362306a36Sopenharmony_ci * 81462306a36Sopenharmony_ci **/ 81562306a36Sopenharmony_cistatic void 81662306a36Sopenharmony_cimptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* 82162306a36Sopenharmony_ci * Set is_cached flag 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 82462306a36Sopenharmony_ci list) { 82562306a36Sopenharmony_ci if (sas_info->os.channel == channel && sas_info->os.id == id) 82662306a36Sopenharmony_ci sas_info->is_cached = 1; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci/** 83162306a36Sopenharmony_ci * mptsas_del_device_components - Cleaning the list 83262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 83362306a36Sopenharmony_ci * 83462306a36Sopenharmony_ci **/ 83562306a36Sopenharmony_cistatic void 83662306a36Sopenharmony_cimptsas_del_device_components(MPT_ADAPTER *ioc) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 84162306a36Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 84262306a36Sopenharmony_ci list) { 84362306a36Sopenharmony_ci list_del(&sas_info->list); 84462306a36Sopenharmony_ci kfree(sas_info); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/* 85162306a36Sopenharmony_ci * mptsas_setup_wide_ports 85262306a36Sopenharmony_ci * 85362306a36Sopenharmony_ci * Updates for new and existing narrow/wide port configuration 85462306a36Sopenharmony_ci * in the sas_topology 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_cistatic void 85762306a36Sopenharmony_cimptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct mptsas_portinfo_details * port_details; 86062306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info, *phy_info_cmp; 86162306a36Sopenharmony_ci u64 sas_address; 86262306a36Sopenharmony_ci int i, j; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci phy_info = port_info->phy_info; 86762306a36Sopenharmony_ci for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { 86862306a36Sopenharmony_ci if (phy_info->attached.handle) 86962306a36Sopenharmony_ci continue; 87062306a36Sopenharmony_ci port_details = phy_info->port_details; 87162306a36Sopenharmony_ci if (!port_details) 87262306a36Sopenharmony_ci continue; 87362306a36Sopenharmony_ci if (port_details->num_phys < 2) 87462306a36Sopenharmony_ci continue; 87562306a36Sopenharmony_ci /* 87662306a36Sopenharmony_ci * Removing a phy from a port, letting the last 87762306a36Sopenharmony_ci * phy be removed by firmware events. 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 88062306a36Sopenharmony_ci "%s: [%p]: deleting phy = %d\n", 88162306a36Sopenharmony_ci ioc->name, __func__, port_details, i)); 88262306a36Sopenharmony_ci port_details->num_phys--; 88362306a36Sopenharmony_ci port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); 88462306a36Sopenharmony_ci memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); 88562306a36Sopenharmony_ci if (phy_info->phy) { 88662306a36Sopenharmony_ci devtprintk(ioc, dev_printk(KERN_DEBUG, 88762306a36Sopenharmony_ci &phy_info->phy->dev, MYIOC_s_FMT 88862306a36Sopenharmony_ci "delete phy %d, phy-obj (0x%p)\n", ioc->name, 88962306a36Sopenharmony_ci phy_info->phy_id, phy_info->phy)); 89062306a36Sopenharmony_ci sas_port_delete_phy(port_details->port, phy_info->phy); 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci phy_info->port_details = NULL; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* 89662306a36Sopenharmony_ci * Populate and refresh the tree 89762306a36Sopenharmony_ci */ 89862306a36Sopenharmony_ci phy_info = port_info->phy_info; 89962306a36Sopenharmony_ci for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { 90062306a36Sopenharmony_ci sas_address = phy_info->attached.sas_address; 90162306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", 90262306a36Sopenharmony_ci ioc->name, i, (unsigned long long)sas_address)); 90362306a36Sopenharmony_ci if (!sas_address) 90462306a36Sopenharmony_ci continue; 90562306a36Sopenharmony_ci port_details = phy_info->port_details; 90662306a36Sopenharmony_ci /* 90762306a36Sopenharmony_ci * Forming a port 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_ci if (!port_details) { 91062306a36Sopenharmony_ci port_details = kzalloc(sizeof(struct 91162306a36Sopenharmony_ci mptsas_portinfo_details), GFP_KERNEL); 91262306a36Sopenharmony_ci if (!port_details) 91362306a36Sopenharmony_ci goto out; 91462306a36Sopenharmony_ci port_details->num_phys = 1; 91562306a36Sopenharmony_ci port_details->port_info = port_info; 91662306a36Sopenharmony_ci if (phy_info->phy_id < 64 ) 91762306a36Sopenharmony_ci port_details->phy_bitmask |= 91862306a36Sopenharmony_ci (1 << phy_info->phy_id); 91962306a36Sopenharmony_ci phy_info->sas_port_add_phy=1; 92062306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" 92162306a36Sopenharmony_ci "phy_id=%d sas_address=0x%018llX\n", 92262306a36Sopenharmony_ci ioc->name, i, (unsigned long long)sas_address)); 92362306a36Sopenharmony_ci phy_info->port_details = port_details; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (i == port_info->num_phys - 1) 92762306a36Sopenharmony_ci continue; 92862306a36Sopenharmony_ci phy_info_cmp = &port_info->phy_info[i + 1]; 92962306a36Sopenharmony_ci for (j = i + 1 ; j < port_info->num_phys ; j++, 93062306a36Sopenharmony_ci phy_info_cmp++) { 93162306a36Sopenharmony_ci if (!phy_info_cmp->attached.sas_address) 93262306a36Sopenharmony_ci continue; 93362306a36Sopenharmony_ci if (sas_address != phy_info_cmp->attached.sas_address) 93462306a36Sopenharmony_ci continue; 93562306a36Sopenharmony_ci if (phy_info_cmp->port_details == port_details ) 93662306a36Sopenharmony_ci continue; 93762306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 93862306a36Sopenharmony_ci "\t\tphy_id=%d sas_address=0x%018llX\n", 93962306a36Sopenharmony_ci ioc->name, j, (unsigned long long) 94062306a36Sopenharmony_ci phy_info_cmp->attached.sas_address)); 94162306a36Sopenharmony_ci if (phy_info_cmp->port_details) { 94262306a36Sopenharmony_ci port_details->rphy = 94362306a36Sopenharmony_ci mptsas_get_rphy(phy_info_cmp); 94462306a36Sopenharmony_ci port_details->port = 94562306a36Sopenharmony_ci mptsas_get_port(phy_info_cmp); 94662306a36Sopenharmony_ci port_details->starget = 94762306a36Sopenharmony_ci mptsas_get_starget(phy_info_cmp); 94862306a36Sopenharmony_ci port_details->num_phys = 94962306a36Sopenharmony_ci phy_info_cmp->port_details->num_phys; 95062306a36Sopenharmony_ci if (!phy_info_cmp->port_details->num_phys) 95162306a36Sopenharmony_ci kfree(phy_info_cmp->port_details); 95262306a36Sopenharmony_ci } else 95362306a36Sopenharmony_ci phy_info_cmp->sas_port_add_phy=1; 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * Adding a phy to a port 95662306a36Sopenharmony_ci */ 95762306a36Sopenharmony_ci phy_info_cmp->port_details = port_details; 95862306a36Sopenharmony_ci if (phy_info_cmp->phy_id < 64 ) 95962306a36Sopenharmony_ci port_details->phy_bitmask |= 96062306a36Sopenharmony_ci (1 << phy_info_cmp->phy_id); 96162306a36Sopenharmony_ci port_details->num_phys++; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci out: 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 96862306a36Sopenharmony_ci port_details = port_info->phy_info[i].port_details; 96962306a36Sopenharmony_ci if (!port_details) 97062306a36Sopenharmony_ci continue; 97162306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 97262306a36Sopenharmony_ci "%s: [%p]: phy_id=%02d num_phys=%02d " 97362306a36Sopenharmony_ci "bitmask=0x%016llX\n", ioc->name, __func__, 97462306a36Sopenharmony_ci port_details, i, port_details->num_phys, 97562306a36Sopenharmony_ci (unsigned long long)port_details->phy_bitmask)); 97662306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", 97762306a36Sopenharmony_ci ioc->name, port_details->port, port_details->rphy)); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci dsaswideprintk(ioc, printk("\n")); 98062306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci/** 98462306a36Sopenharmony_ci * mptsas_find_vtarget - find a virtual target device (FC LUN device or 98562306a36Sopenharmony_ci * SCSI target device) 98662306a36Sopenharmony_ci * 98762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 98862306a36Sopenharmony_ci * @channel: channel number 98962306a36Sopenharmony_ci * @id: Logical Target ID 99062306a36Sopenharmony_ci * 99162306a36Sopenharmony_ci **/ 99262306a36Sopenharmony_cistatic VirtTarget * 99362306a36Sopenharmony_cimptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct scsi_device *sdev; 99662306a36Sopenharmony_ci VirtDevice *vdevice; 99762306a36Sopenharmony_ci VirtTarget *vtarget = NULL; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 100062306a36Sopenharmony_ci vdevice = sdev->hostdata; 100162306a36Sopenharmony_ci if ((vdevice == NULL) || 100262306a36Sopenharmony_ci (vdevice->vtarget == NULL)) 100362306a36Sopenharmony_ci continue; 100462306a36Sopenharmony_ci if ((vdevice->vtarget->tflags & 100562306a36Sopenharmony_ci MPT_TARGET_FLAGS_RAID_COMPONENT || 100662306a36Sopenharmony_ci vdevice->vtarget->raidVolume)) 100762306a36Sopenharmony_ci continue; 100862306a36Sopenharmony_ci if (vdevice->vtarget->id == id && 100962306a36Sopenharmony_ci vdevice->vtarget->channel == channel) 101062306a36Sopenharmony_ci vtarget = vdevice->vtarget; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci return vtarget; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic void 101662306a36Sopenharmony_cimptsas_queue_device_delete(MPT_ADAPTER *ioc, 101762306a36Sopenharmony_ci MpiEventDataSasDeviceStatusChange_t *sas_event_data) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct fw_event_work *fw_event; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci fw_event = kzalloc(sizeof(*fw_event) + 102262306a36Sopenharmony_ci sizeof(MpiEventDataSasDeviceStatusChange_t), 102362306a36Sopenharmony_ci GFP_ATOMIC); 102462306a36Sopenharmony_ci if (!fw_event) { 102562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", 102662306a36Sopenharmony_ci ioc->name, __func__, __LINE__); 102762306a36Sopenharmony_ci return; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci memcpy(fw_event->event_data, sas_event_data, 103062306a36Sopenharmony_ci sizeof(MpiEventDataSasDeviceStatusChange_t)); 103162306a36Sopenharmony_ci fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; 103262306a36Sopenharmony_ci fw_event->ioc = ioc; 103362306a36Sopenharmony_ci mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic void 103762306a36Sopenharmony_cimptsas_queue_rescan(MPT_ADAPTER *ioc) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct fw_event_work *fw_event; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci fw_event = kzalloc(sizeof(*fw_event), GFP_ATOMIC); 104262306a36Sopenharmony_ci if (!fw_event) { 104362306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", 104462306a36Sopenharmony_ci ioc->name, __func__, __LINE__); 104562306a36Sopenharmony_ci return; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci fw_event->event = -1; 104862306a36Sopenharmony_ci fw_event->ioc = ioc; 104962306a36Sopenharmony_ci mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci/** 105462306a36Sopenharmony_ci * mptsas_target_reset - Issues TARGET_RESET to end device using 105562306a36Sopenharmony_ci * handshaking method 105662306a36Sopenharmony_ci * 105762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 105862306a36Sopenharmony_ci * @channel: channel number 105962306a36Sopenharmony_ci * @id: Logical Target ID for reset 106062306a36Sopenharmony_ci * 106162306a36Sopenharmony_ci * Return: (1) success 106262306a36Sopenharmony_ci * (0) failure 106362306a36Sopenharmony_ci * 106462306a36Sopenharmony_ci **/ 106562306a36Sopenharmony_cistatic int 106662306a36Sopenharmony_cimptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 106962306a36Sopenharmony_ci SCSITaskMgmt_t *pScsiTm; 107062306a36Sopenharmony_ci if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) 107162306a36Sopenharmony_ci return 0; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); 107562306a36Sopenharmony_ci if (mf == NULL) { 107662306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT 107762306a36Sopenharmony_ci "%s, no msg frames @%d!!\n", ioc->name, 107862306a36Sopenharmony_ci __func__, __LINE__)); 107962306a36Sopenharmony_ci goto out_fail; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", 108362306a36Sopenharmony_ci ioc->name, mf)); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* Format the Request 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci pScsiTm = (SCSITaskMgmt_t *) mf; 108862306a36Sopenharmony_ci memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); 108962306a36Sopenharmony_ci pScsiTm->TargetID = id; 109062306a36Sopenharmony_ci pScsiTm->Bus = channel; 109162306a36Sopenharmony_ci pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 109262306a36Sopenharmony_ci pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 109362306a36Sopenharmony_ci pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 109862306a36Sopenharmony_ci "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", 109962306a36Sopenharmony_ci ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return 1; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci out_fail: 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci mpt_clear_taskmgmt_in_progress_flag(ioc); 110862306a36Sopenharmony_ci return 0; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic void 111262306a36Sopenharmony_cimptsas_block_io_sdev(struct scsi_device *sdev, void *data) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci scsi_device_set_state(sdev, SDEV_BLOCK); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic void 111862306a36Sopenharmony_cimptsas_block_io_starget(struct scsi_target *starget) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci if (starget) 112162306a36Sopenharmony_ci starget_for_each_device(starget, NULL, mptsas_block_io_sdev); 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci/** 112562306a36Sopenharmony_ci * mptsas_target_reset_queue - queue a target reset 112662306a36Sopenharmony_ci * 112762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 112862306a36Sopenharmony_ci * @sas_event_data: SAS Device Status Change Event data 112962306a36Sopenharmony_ci * 113062306a36Sopenharmony_ci * Receive request for TARGET_RESET after receiving a firmware 113162306a36Sopenharmony_ci * event NOT_RESPONDING_EVENT, then put command in link list 113262306a36Sopenharmony_ci * and queue if task_queue already in use. 113362306a36Sopenharmony_ci * 113462306a36Sopenharmony_ci **/ 113562306a36Sopenharmony_cistatic void 113662306a36Sopenharmony_cimptsas_target_reset_queue(MPT_ADAPTER *ioc, 113762306a36Sopenharmony_ci EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 114062306a36Sopenharmony_ci VirtTarget *vtarget = NULL; 114162306a36Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list; 114262306a36Sopenharmony_ci u8 id, channel; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci id = sas_event_data->TargetID; 114562306a36Sopenharmony_ci channel = sas_event_data->Bus; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, channel, id); 114862306a36Sopenharmony_ci if (vtarget) { 114962306a36Sopenharmony_ci mptsas_block_io_starget(vtarget->starget); 115062306a36Sopenharmony_ci vtarget->deleted = 1; /* block IO */ 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), 115462306a36Sopenharmony_ci GFP_ATOMIC); 115562306a36Sopenharmony_ci if (!target_reset_list) { 115662306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT 115762306a36Sopenharmony_ci "%s, failed to allocate mem @%d..!!\n", 115862306a36Sopenharmony_ci ioc->name, __func__, __LINE__)); 115962306a36Sopenharmony_ci return; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci memcpy(&target_reset_list->sas_event_data, sas_event_data, 116362306a36Sopenharmony_ci sizeof(*sas_event_data)); 116462306a36Sopenharmony_ci list_add_tail(&target_reset_list->list, &hd->target_reset_list); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci target_reset_list->time_count = jiffies; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (mptsas_target_reset(ioc, channel, id)) { 116962306a36Sopenharmony_ci target_reset_list->target_reset_issued = 1; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci/** 117462306a36Sopenharmony_ci * mptsas_schedule_target_reset- send pending target reset 117562306a36Sopenharmony_ci * @iocp: per adapter object 117662306a36Sopenharmony_ci * 117762306a36Sopenharmony_ci * This function will delete scheduled target reset from the list and 117862306a36Sopenharmony_ci * try to send next target reset. This will be called from completion 117962306a36Sopenharmony_ci * context of any Task management command. 118062306a36Sopenharmony_ci */ 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_civoid 118362306a36Sopenharmony_cimptsas_schedule_target_reset(void *iocp) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp); 118662306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 118762306a36Sopenharmony_ci struct list_head *head = &hd->target_reset_list; 118862306a36Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list; 118962306a36Sopenharmony_ci u8 id, channel; 119062306a36Sopenharmony_ci /* 119162306a36Sopenharmony_ci * issue target reset to next device in the queue 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (list_empty(head)) 119562306a36Sopenharmony_ci return; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci target_reset_list = list_entry(head->next, 119862306a36Sopenharmony_ci struct mptsas_target_reset_event, list); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci id = target_reset_list->sas_event_data.TargetID; 120162306a36Sopenharmony_ci channel = target_reset_list->sas_event_data.Bus; 120262306a36Sopenharmony_ci target_reset_list->time_count = jiffies; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (mptsas_target_reset(ioc, channel, id)) 120562306a36Sopenharmony_ci target_reset_list->target_reset_issued = 1; 120662306a36Sopenharmony_ci return; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci/** 121162306a36Sopenharmony_ci * mptsas_taskmgmt_complete - complete SAS task management function 121262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 121362306a36Sopenharmony_ci * @mf: MPT message frame 121462306a36Sopenharmony_ci * @mr: SCSI Task Management Reply structure ptr (may be %NULL) 121562306a36Sopenharmony_ci * 121662306a36Sopenharmony_ci * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work 121762306a36Sopenharmony_ci * queue to finish off removing device from upper layers, then send next 121862306a36Sopenharmony_ci * TARGET_RESET in the queue. 121962306a36Sopenharmony_ci **/ 122062306a36Sopenharmony_cistatic int 122162306a36Sopenharmony_cimptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 122462306a36Sopenharmony_ci struct list_head *head = &hd->target_reset_list; 122562306a36Sopenharmony_ci u8 id, channel; 122662306a36Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list; 122762306a36Sopenharmony_ci SCSITaskMgmtReply_t *pScsiTmReply; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " 123062306a36Sopenharmony_ci "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci pScsiTmReply = (SCSITaskMgmtReply_t *)mr; 123362306a36Sopenharmony_ci if (!pScsiTmReply) 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 123762306a36Sopenharmony_ci "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" 123862306a36Sopenharmony_ci "\ttask_type = 0x%02X, iocstatus = 0x%04X " 123962306a36Sopenharmony_ci "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " 124062306a36Sopenharmony_ci "term_cmnds = %d\n", ioc->name, 124162306a36Sopenharmony_ci pScsiTmReply->Bus, pScsiTmReply->TargetID, 124262306a36Sopenharmony_ci pScsiTmReply->TaskType, 124362306a36Sopenharmony_ci le16_to_cpu(pScsiTmReply->IOCStatus), 124462306a36Sopenharmony_ci le32_to_cpu(pScsiTmReply->IOCLogInfo), 124562306a36Sopenharmony_ci pScsiTmReply->ResponseCode, 124662306a36Sopenharmony_ci le32_to_cpu(pScsiTmReply->TerminationCount))); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (pScsiTmReply->ResponseCode) 124962306a36Sopenharmony_ci mptscsih_taskmgmt_response_code(ioc, 125062306a36Sopenharmony_ci pScsiTmReply->ResponseCode); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (pScsiTmReply->TaskType == 125362306a36Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == 125462306a36Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) { 125562306a36Sopenharmony_ci ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; 125662306a36Sopenharmony_ci ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; 125762306a36Sopenharmony_ci memcpy(ioc->taskmgmt_cmds.reply, mr, 125862306a36Sopenharmony_ci min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); 125962306a36Sopenharmony_ci if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { 126062306a36Sopenharmony_ci ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; 126162306a36Sopenharmony_ci complete(&ioc->taskmgmt_cmds.done); 126262306a36Sopenharmony_ci return 1; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci return 0; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci mpt_clear_taskmgmt_in_progress_flag(ioc); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (list_empty(head)) 127062306a36Sopenharmony_ci return 1; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci target_reset_list = list_entry(head->next, 127362306a36Sopenharmony_ci struct mptsas_target_reset_event, list); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 127662306a36Sopenharmony_ci "TaskMgmt: completed (%d seconds)\n", 127762306a36Sopenharmony_ci ioc->name, jiffies_to_msecs(jiffies - 127862306a36Sopenharmony_ci target_reset_list->time_count)/1000)); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci id = pScsiTmReply->TargetID; 128162306a36Sopenharmony_ci channel = pScsiTmReply->Bus; 128262306a36Sopenharmony_ci target_reset_list->time_count = jiffies; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci /* 128562306a36Sopenharmony_ci * retry target reset 128662306a36Sopenharmony_ci */ 128762306a36Sopenharmony_ci if (!target_reset_list->target_reset_issued) { 128862306a36Sopenharmony_ci if (mptsas_target_reset(ioc, channel, id)) 128962306a36Sopenharmony_ci target_reset_list->target_reset_issued = 1; 129062306a36Sopenharmony_ci return 1; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci /* 129462306a36Sopenharmony_ci * enable work queue to remove device from upper layers 129562306a36Sopenharmony_ci */ 129662306a36Sopenharmony_ci list_del(&target_reset_list->list); 129762306a36Sopenharmony_ci if (!ioc->fw_events_off) 129862306a36Sopenharmony_ci mptsas_queue_device_delete(ioc, 129962306a36Sopenharmony_ci &target_reset_list->sas_event_data); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci ioc->schedule_target_reset(ioc); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci return 1; 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci/** 130862306a36Sopenharmony_ci * mptsas_ioc_reset - issue an IOC reset for this reset phase 130962306a36Sopenharmony_ci * 131062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 131162306a36Sopenharmony_ci * @reset_phase: id of phase of reset 131262306a36Sopenharmony_ci * 131362306a36Sopenharmony_ci **/ 131462306a36Sopenharmony_cistatic int 131562306a36Sopenharmony_cimptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci MPT_SCSI_HOST *hd; 131862306a36Sopenharmony_ci int rc; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci rc = mptscsih_ioc_reset(ioc, reset_phase); 132162306a36Sopenharmony_ci if ((ioc->bus_type != SAS) || (!rc)) 132262306a36Sopenharmony_ci return rc; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci hd = shost_priv(ioc->sh); 132562306a36Sopenharmony_ci if (!hd->ioc) 132662306a36Sopenharmony_ci goto out; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci switch (reset_phase) { 132962306a36Sopenharmony_ci case MPT_IOC_SETUP_RESET: 133062306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 133162306a36Sopenharmony_ci "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); 133262306a36Sopenharmony_ci mptsas_fw_event_off(ioc); 133362306a36Sopenharmony_ci break; 133462306a36Sopenharmony_ci case MPT_IOC_PRE_RESET: 133562306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 133662306a36Sopenharmony_ci "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); 133762306a36Sopenharmony_ci break; 133862306a36Sopenharmony_ci case MPT_IOC_POST_RESET: 133962306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 134062306a36Sopenharmony_ci "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); 134162306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { 134262306a36Sopenharmony_ci ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; 134362306a36Sopenharmony_ci complete(&ioc->sas_mgmt.done); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci mptsas_cleanup_fw_event_q(ioc); 134662306a36Sopenharmony_ci mptsas_queue_rescan(ioc); 134762306a36Sopenharmony_ci break; 134862306a36Sopenharmony_ci default: 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci out: 135362306a36Sopenharmony_ci return rc; 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci/** 135862306a36Sopenharmony_ci * enum device_state - TUR device state 135962306a36Sopenharmony_ci * @DEVICE_RETRY: need to retry the TUR 136062306a36Sopenharmony_ci * @DEVICE_ERROR: TUR return error, don't add device 136162306a36Sopenharmony_ci * @DEVICE_READY: device can be added 136262306a36Sopenharmony_ci * 136362306a36Sopenharmony_ci */ 136462306a36Sopenharmony_cienum device_state{ 136562306a36Sopenharmony_ci DEVICE_RETRY, 136662306a36Sopenharmony_ci DEVICE_ERROR, 136762306a36Sopenharmony_ci DEVICE_READY, 136862306a36Sopenharmony_ci}; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic int 137162306a36Sopenharmony_cimptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, 137262306a36Sopenharmony_ci u32 form, u32 form_specific) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 137562306a36Sopenharmony_ci CONFIGPARMS cfg; 137662306a36Sopenharmony_ci SasEnclosurePage0_t *buffer; 137762306a36Sopenharmony_ci dma_addr_t dma_handle; 137862306a36Sopenharmony_ci int error; 137962306a36Sopenharmony_ci __le64 le_identifier; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 138262306a36Sopenharmony_ci hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; 138362306a36Sopenharmony_ci hdr.PageNumber = 0; 138462306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 138562306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 138862306a36Sopenharmony_ci cfg.physAddr = -1; 138962306a36Sopenharmony_ci cfg.pageAddr = form + form_specific; 139062306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 139162306a36Sopenharmony_ci cfg.dir = 0; /* read */ 139262306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 139562306a36Sopenharmony_ci if (error) 139662306a36Sopenharmony_ci goto out; 139762306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 139862306a36Sopenharmony_ci error = -ENXIO; 139962306a36Sopenharmony_ci goto out; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 140362306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 140462306a36Sopenharmony_ci if (!buffer) { 140562306a36Sopenharmony_ci error = -ENOMEM; 140662306a36Sopenharmony_ci goto out; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci cfg.physAddr = dma_handle; 141062306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 141362306a36Sopenharmony_ci if (error) 141462306a36Sopenharmony_ci goto out_free_consistent; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* save config data */ 141762306a36Sopenharmony_ci memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); 141862306a36Sopenharmony_ci enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); 141962306a36Sopenharmony_ci enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); 142062306a36Sopenharmony_ci enclosure->flags = le16_to_cpu(buffer->Flags); 142162306a36Sopenharmony_ci enclosure->num_slot = le16_to_cpu(buffer->NumSlots); 142262306a36Sopenharmony_ci enclosure->start_slot = le16_to_cpu(buffer->StartSlot); 142362306a36Sopenharmony_ci enclosure->start_id = buffer->StartTargetID; 142462306a36Sopenharmony_ci enclosure->start_channel = buffer->StartBus; 142562306a36Sopenharmony_ci enclosure->sep_id = buffer->SEPTargetID; 142662306a36Sopenharmony_ci enclosure->sep_channel = buffer->SEPBus; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci out_free_consistent: 142962306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 143062306a36Sopenharmony_ci dma_handle); 143162306a36Sopenharmony_ci out: 143262306a36Sopenharmony_ci return error; 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci/** 143662306a36Sopenharmony_ci * mptsas_add_end_device - report a new end device to sas transport layer 143762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 143862306a36Sopenharmony_ci * @phy_info: describes attached device 143962306a36Sopenharmony_ci * 144062306a36Sopenharmony_ci * return (0) success (1) failure 144162306a36Sopenharmony_ci * 144262306a36Sopenharmony_ci **/ 144362306a36Sopenharmony_cistatic int 144462306a36Sopenharmony_cimptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci struct sas_rphy *rphy; 144762306a36Sopenharmony_ci struct sas_port *port; 144862306a36Sopenharmony_ci struct sas_identify identify; 144962306a36Sopenharmony_ci char *ds = NULL; 145062306a36Sopenharmony_ci u8 fw_id; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (!phy_info) { 145362306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 145462306a36Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 145562306a36Sopenharmony_ci __func__, __LINE__)); 145662306a36Sopenharmony_ci return 1; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci fw_id = phy_info->attached.id; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (mptsas_get_rphy(phy_info)) { 146262306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 146362306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 146462306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 146562306a36Sopenharmony_ci return 2; 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci port = mptsas_get_port(phy_info); 146962306a36Sopenharmony_ci if (!port) { 147062306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 147162306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 147262306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 147362306a36Sopenharmony_ci return 3; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if (phy_info->attached.device_info & 147762306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SSP_TARGET) 147862306a36Sopenharmony_ci ds = "ssp"; 147962306a36Sopenharmony_ci if (phy_info->attached.device_info & 148062306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET) 148162306a36Sopenharmony_ci ds = "stp"; 148262306a36Sopenharmony_ci if (phy_info->attached.device_info & 148362306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE) 148462306a36Sopenharmony_ci ds = "sata"; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," 148762306a36Sopenharmony_ci " phy %d, sas_addr 0x%llx\n", ioc->name, ds, 148862306a36Sopenharmony_ci phy_info->attached.channel, phy_info->attached.id, 148962306a36Sopenharmony_ci phy_info->attached.phy_id, (unsigned long long) 149062306a36Sopenharmony_ci phy_info->attached.sas_address); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci mptsas_parse_device_info(&identify, &phy_info->attached); 149362306a36Sopenharmony_ci rphy = sas_end_device_alloc(port); 149462306a36Sopenharmony_ci if (!rphy) { 149562306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 149662306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 149762306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 149862306a36Sopenharmony_ci return 5; /* non-fatal: an rphy can be added later */ 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci rphy->identify = identify; 150262306a36Sopenharmony_ci if (sas_rphy_add(rphy)) { 150362306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 150462306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 150562306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 150662306a36Sopenharmony_ci sas_rphy_free(rphy); 150762306a36Sopenharmony_ci return 6; 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci mptsas_set_rphy(ioc, phy_info, rphy); 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci/** 151462306a36Sopenharmony_ci * mptsas_del_end_device - report a deleted end device to sas transport layer 151562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 151662306a36Sopenharmony_ci * @phy_info: describes attached device 151762306a36Sopenharmony_ci * 151862306a36Sopenharmony_ci **/ 151962306a36Sopenharmony_cistatic void 152062306a36Sopenharmony_cimptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci struct sas_rphy *rphy; 152362306a36Sopenharmony_ci struct sas_port *port; 152462306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 152562306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info_parent; 152662306a36Sopenharmony_ci int i; 152762306a36Sopenharmony_ci char *ds = NULL; 152862306a36Sopenharmony_ci u8 fw_id; 152962306a36Sopenharmony_ci u64 sas_address; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (!phy_info) 153262306a36Sopenharmony_ci return; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci fw_id = phy_info->attached.id; 153562306a36Sopenharmony_ci sas_address = phy_info->attached.sas_address; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci if (!phy_info->port_details) { 153862306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 153962306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 154062306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 154162306a36Sopenharmony_ci return; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci rphy = mptsas_get_rphy(phy_info); 154462306a36Sopenharmony_ci if (!rphy) { 154562306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 154662306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 154762306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 154862306a36Sopenharmony_ci return; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR 155262306a36Sopenharmony_ci || phy_info->attached.device_info 155362306a36Sopenharmony_ci & MPI_SAS_DEVICE_INFO_SMP_INITIATOR 155462306a36Sopenharmony_ci || phy_info->attached.device_info 155562306a36Sopenharmony_ci & MPI_SAS_DEVICE_INFO_STP_INITIATOR) 155662306a36Sopenharmony_ci ds = "initiator"; 155762306a36Sopenharmony_ci if (phy_info->attached.device_info & 155862306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SSP_TARGET) 155962306a36Sopenharmony_ci ds = "ssp"; 156062306a36Sopenharmony_ci if (phy_info->attached.device_info & 156162306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET) 156262306a36Sopenharmony_ci ds = "stp"; 156362306a36Sopenharmony_ci if (phy_info->attached.device_info & 156462306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE) 156562306a36Sopenharmony_ci ds = "sata"; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT 156862306a36Sopenharmony_ci "removing %s device: fw_channel %d, fw_id %d, phy %d," 156962306a36Sopenharmony_ci "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, 157062306a36Sopenharmony_ci phy_info->attached.id, phy_info->attached.phy_id, 157162306a36Sopenharmony_ci (unsigned long long) sas_address); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci port = mptsas_get_port(phy_info); 157462306a36Sopenharmony_ci if (!port) { 157562306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 157662306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 157762306a36Sopenharmony_ci __func__, fw_id, __LINE__)); 157862306a36Sopenharmony_ci return; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci port_info = phy_info->portinfo; 158162306a36Sopenharmony_ci phy_info_parent = port_info->phy_info; 158262306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { 158362306a36Sopenharmony_ci if (!phy_info_parent->phy) 158462306a36Sopenharmony_ci continue; 158562306a36Sopenharmony_ci if (phy_info_parent->attached.sas_address != 158662306a36Sopenharmony_ci sas_address) 158762306a36Sopenharmony_ci continue; 158862306a36Sopenharmony_ci dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, 158962306a36Sopenharmony_ci MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", 159062306a36Sopenharmony_ci ioc->name, phy_info_parent->phy_id, 159162306a36Sopenharmony_ci phy_info_parent->phy); 159262306a36Sopenharmony_ci sas_port_delete_phy(port, phy_info_parent->phy); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT 159662306a36Sopenharmony_ci "delete port %d, sas_addr (0x%llx)\n", ioc->name, 159762306a36Sopenharmony_ci port->port_identifier, (unsigned long long)sas_address); 159862306a36Sopenharmony_ci sas_port_delete(port); 159962306a36Sopenharmony_ci mptsas_set_port(ioc, phy_info, NULL); 160062306a36Sopenharmony_ci mptsas_port_delete(ioc, phy_info->port_details); 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic struct mptsas_phyinfo * 160462306a36Sopenharmony_cimptsas_refreshing_device_handles(MPT_ADAPTER *ioc, 160562306a36Sopenharmony_ci struct mptsas_devinfo *sas_device) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 160862306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 160962306a36Sopenharmony_ci int i; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 161262306a36Sopenharmony_ci sas_device->sas_address); 161362306a36Sopenharmony_ci if (!phy_info) 161462306a36Sopenharmony_ci goto out; 161562306a36Sopenharmony_ci port_info = phy_info->portinfo; 161662306a36Sopenharmony_ci if (!port_info) 161762306a36Sopenharmony_ci goto out; 161862306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 161962306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 162062306a36Sopenharmony_ci if (port_info->phy_info[i].attached.sas_address != 162162306a36Sopenharmony_ci sas_device->sas_address) 162262306a36Sopenharmony_ci continue; 162362306a36Sopenharmony_ci port_info->phy_info[i].attached.channel = sas_device->channel; 162462306a36Sopenharmony_ci port_info->phy_info[i].attached.id = sas_device->id; 162562306a36Sopenharmony_ci port_info->phy_info[i].attached.sas_address = 162662306a36Sopenharmony_ci sas_device->sas_address; 162762306a36Sopenharmony_ci port_info->phy_info[i].attached.handle = sas_device->handle; 162862306a36Sopenharmony_ci port_info->phy_info[i].attached.handle_parent = 162962306a36Sopenharmony_ci sas_device->handle_parent; 163062306a36Sopenharmony_ci port_info->phy_info[i].attached.handle_enclosure = 163162306a36Sopenharmony_ci sas_device->handle_enclosure; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 163462306a36Sopenharmony_ci out: 163562306a36Sopenharmony_ci return phy_info; 163662306a36Sopenharmony_ci} 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci/** 163962306a36Sopenharmony_ci * mptsas_firmware_event_work - work thread for processing fw events 164062306a36Sopenharmony_ci * @work: work queue payload containing info describing the event 164162306a36Sopenharmony_ci * Context: user 164262306a36Sopenharmony_ci * 164362306a36Sopenharmony_ci */ 164462306a36Sopenharmony_cistatic void 164562306a36Sopenharmony_cimptsas_firmware_event_work(struct work_struct *work) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci struct fw_event_work *fw_event = 164862306a36Sopenharmony_ci container_of(work, struct fw_event_work, work.work); 164962306a36Sopenharmony_ci MPT_ADAPTER *ioc = fw_event->ioc; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* special rescan topology handling */ 165262306a36Sopenharmony_ci if (fw_event->event == -1) { 165362306a36Sopenharmony_ci if (ioc->in_rescan) { 165462306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 165562306a36Sopenharmony_ci "%s: rescan ignored as it is in progress\n", 165662306a36Sopenharmony_ci ioc->name, __func__)); 165762306a36Sopenharmony_ci return; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " 166062306a36Sopenharmony_ci "reset\n", ioc->name, __func__)); 166162306a36Sopenharmony_ci ioc->in_rescan = 1; 166262306a36Sopenharmony_ci mptsas_not_responding_devices(ioc); 166362306a36Sopenharmony_ci mptsas_scan_sas_topology(ioc); 166462306a36Sopenharmony_ci ioc->in_rescan = 0; 166562306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 166662306a36Sopenharmony_ci mptsas_fw_event_on(ioc); 166762306a36Sopenharmony_ci return; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* events handling turned off during host reset */ 167162306a36Sopenharmony_ci if (ioc->fw_events_off) { 167262306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 167362306a36Sopenharmony_ci return; 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " 167762306a36Sopenharmony_ci "event = (0x%02x)\n", ioc->name, __func__, fw_event, 167862306a36Sopenharmony_ci (fw_event->event & 0xFF))); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci switch (fw_event->event) { 168162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 168262306a36Sopenharmony_ci mptsas_send_sas_event(fw_event); 168362306a36Sopenharmony_ci break; 168462306a36Sopenharmony_ci case MPI_EVENT_INTEGRATED_RAID: 168562306a36Sopenharmony_ci mptsas_send_raid_event(fw_event); 168662306a36Sopenharmony_ci break; 168762306a36Sopenharmony_ci case MPI_EVENT_IR2: 168862306a36Sopenharmony_ci mptsas_send_ir2_event(fw_event); 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci case MPI_EVENT_PERSISTENT_TABLE_FULL: 169162306a36Sopenharmony_ci mptbase_sas_persist_operation(ioc, 169262306a36Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 169362306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 169462306a36Sopenharmony_ci break; 169562306a36Sopenharmony_ci case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: 169662306a36Sopenharmony_ci mptsas_broadcast_primitive_work(fw_event); 169762306a36Sopenharmony_ci break; 169862306a36Sopenharmony_ci case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: 169962306a36Sopenharmony_ci mptsas_send_expander_event(fw_event); 170062306a36Sopenharmony_ci break; 170162306a36Sopenharmony_ci case MPI_EVENT_SAS_PHY_LINK_STATUS: 170262306a36Sopenharmony_ci mptsas_send_link_status_event(fw_event); 170362306a36Sopenharmony_ci break; 170462306a36Sopenharmony_ci case MPI_EVENT_QUEUE_FULL: 170562306a36Sopenharmony_ci mptsas_handle_queue_full_event(fw_event); 170662306a36Sopenharmony_ci break; 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic int 171362306a36Sopenharmony_cimptsas_slave_configure(struct scsi_device *sdev) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct Scsi_Host *host = sdev->host; 171662306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 171762306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 171862306a36Sopenharmony_ci VirtDevice *vdevice = sdev->hostdata; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (vdevice->vtarget->deleted) { 172162306a36Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); 172262306a36Sopenharmony_ci vdevice->vtarget->deleted = 0; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* 172662306a36Sopenharmony_ci * RAID volumes placed beyond the last expected port. 172762306a36Sopenharmony_ci * Ignore sending sas mode pages in that case.. 172862306a36Sopenharmony_ci */ 172962306a36Sopenharmony_ci if (sdev->channel == MPTSAS_RAID_CHANNEL) { 173062306a36Sopenharmony_ci mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); 173162306a36Sopenharmony_ci goto out; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci sas_read_port_mode_page(sdev); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci mptsas_add_device_component_starget(ioc, scsi_target(sdev)); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci out: 173962306a36Sopenharmony_ci return mptscsih_slave_configure(sdev); 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic int 174362306a36Sopenharmony_cimptsas_target_alloc(struct scsi_target *starget) 174462306a36Sopenharmony_ci{ 174562306a36Sopenharmony_ci struct Scsi_Host *host = dev_to_shost(&starget->dev); 174662306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 174762306a36Sopenharmony_ci VirtTarget *vtarget; 174862306a36Sopenharmony_ci u8 id, channel; 174962306a36Sopenharmony_ci struct sas_rphy *rphy; 175062306a36Sopenharmony_ci struct mptsas_portinfo *p; 175162306a36Sopenharmony_ci int i; 175262306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); 175562306a36Sopenharmony_ci if (!vtarget) 175662306a36Sopenharmony_ci return -ENOMEM; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci vtarget->starget = starget; 175962306a36Sopenharmony_ci vtarget->ioc_id = ioc->id; 176062306a36Sopenharmony_ci vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; 176162306a36Sopenharmony_ci id = starget->id; 176262306a36Sopenharmony_ci channel = 0; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci /* 176562306a36Sopenharmony_ci * RAID volumes placed beyond the last expected port. 176662306a36Sopenharmony_ci */ 176762306a36Sopenharmony_ci if (starget->channel == MPTSAS_RAID_CHANNEL) { 176862306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg2) { 176962306a36Sopenharmony_ci kfree(vtarget); 177062306a36Sopenharmony_ci return -ENXIO; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 177362306a36Sopenharmony_ci if (id == ioc->raid_data.pIocPg2-> 177462306a36Sopenharmony_ci RaidVolume[i].VolumeID) { 177562306a36Sopenharmony_ci channel = ioc->raid_data.pIocPg2-> 177662306a36Sopenharmony_ci RaidVolume[i].VolumeBus; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci vtarget->raidVolume = 1; 178062306a36Sopenharmony_ci goto out; 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 178462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 178562306a36Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 178662306a36Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 178762306a36Sopenharmony_ci if (p->phy_info[i].attached.sas_address != 178862306a36Sopenharmony_ci rphy->identify.sas_address) 178962306a36Sopenharmony_ci continue; 179062306a36Sopenharmony_ci id = p->phy_info[i].attached.id; 179162306a36Sopenharmony_ci channel = p->phy_info[i].attached.channel; 179262306a36Sopenharmony_ci mptsas_set_starget(&p->phy_info[i], starget); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci /* 179562306a36Sopenharmony_ci * Exposing hidden raid components 179662306a36Sopenharmony_ci */ 179762306a36Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, channel, id)) { 179862306a36Sopenharmony_ci id = mptscsih_raid_id_to_num(ioc, 179962306a36Sopenharmony_ci channel, id); 180062306a36Sopenharmony_ci vtarget->tflags |= 180162306a36Sopenharmony_ci MPT_TARGET_FLAGS_RAID_COMPONENT; 180262306a36Sopenharmony_ci p->phy_info[i].attached.phys_disk_num = id; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 180562306a36Sopenharmony_ci goto out; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci kfree(vtarget); 181162306a36Sopenharmony_ci return -ENXIO; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci out: 181462306a36Sopenharmony_ci vtarget->id = id; 181562306a36Sopenharmony_ci vtarget->channel = channel; 181662306a36Sopenharmony_ci starget->hostdata = vtarget; 181762306a36Sopenharmony_ci return 0; 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic void 182162306a36Sopenharmony_cimptsas_target_destroy(struct scsi_target *starget) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci struct Scsi_Host *host = dev_to_shost(&starget->dev); 182462306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 182562306a36Sopenharmony_ci struct sas_rphy *rphy; 182662306a36Sopenharmony_ci struct mptsas_portinfo *p; 182762306a36Sopenharmony_ci int i; 182862306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 182962306a36Sopenharmony_ci VirtTarget *vtarget; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (!starget->hostdata) 183262306a36Sopenharmony_ci return; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci vtarget = starget->hostdata; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci mptsas_del_device_component_by_os(ioc, starget->channel, 183762306a36Sopenharmony_ci starget->id); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (starget->channel == MPTSAS_RAID_CHANNEL) 184162306a36Sopenharmony_ci goto out; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 184462306a36Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 184562306a36Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 184662306a36Sopenharmony_ci if (p->phy_info[i].attached.sas_address != 184762306a36Sopenharmony_ci rphy->identify.sas_address) 184862306a36Sopenharmony_ci continue; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci starget_printk(KERN_INFO, starget, MYIOC_s_FMT 185162306a36Sopenharmony_ci "delete device: fw_channel %d, fw_id %d, phy %d, " 185262306a36Sopenharmony_ci "sas_addr 0x%llx\n", ioc->name, 185362306a36Sopenharmony_ci p->phy_info[i].attached.channel, 185462306a36Sopenharmony_ci p->phy_info[i].attached.id, 185562306a36Sopenharmony_ci p->phy_info[i].attached.phy_id, (unsigned long long) 185662306a36Sopenharmony_ci p->phy_info[i].attached.sas_address); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci mptsas_set_starget(&p->phy_info[i], NULL); 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci out: 186362306a36Sopenharmony_ci vtarget->starget = NULL; 186462306a36Sopenharmony_ci kfree(starget->hostdata); 186562306a36Sopenharmony_ci starget->hostdata = NULL; 186662306a36Sopenharmony_ci} 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_cistatic int 187062306a36Sopenharmony_cimptsas_slave_alloc(struct scsi_device *sdev) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci struct Scsi_Host *host = sdev->host; 187362306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 187462306a36Sopenharmony_ci struct sas_rphy *rphy; 187562306a36Sopenharmony_ci struct mptsas_portinfo *p; 187662306a36Sopenharmony_ci VirtDevice *vdevice; 187762306a36Sopenharmony_ci struct scsi_target *starget; 187862306a36Sopenharmony_ci int i; 187962306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); 188262306a36Sopenharmony_ci if (!vdevice) { 188362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", 188462306a36Sopenharmony_ci ioc->name, sizeof(VirtDevice)); 188562306a36Sopenharmony_ci return -ENOMEM; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci starget = scsi_target(sdev); 188862306a36Sopenharmony_ci vdevice->vtarget = starget->hostdata; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci if (sdev->channel == MPTSAS_RAID_CHANNEL) 189162306a36Sopenharmony_ci goto out; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci rphy = dev_to_rphy(sdev->sdev_target->dev.parent); 189462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 189562306a36Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 189662306a36Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 189762306a36Sopenharmony_ci if (p->phy_info[i].attached.sas_address != 189862306a36Sopenharmony_ci rphy->identify.sas_address) 189962306a36Sopenharmony_ci continue; 190062306a36Sopenharmony_ci vdevice->lun = sdev->lun; 190162306a36Sopenharmony_ci /* 190262306a36Sopenharmony_ci * Exposing hidden raid components 190362306a36Sopenharmony_ci */ 190462306a36Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, 190562306a36Sopenharmony_ci p->phy_info[i].attached.channel, 190662306a36Sopenharmony_ci p->phy_info[i].attached.id)) 190762306a36Sopenharmony_ci sdev->no_uld_attach = 1; 190862306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 190962306a36Sopenharmony_ci goto out; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci kfree(vdevice); 191562306a36Sopenharmony_ci return -ENXIO; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci out: 191862306a36Sopenharmony_ci vdevice->vtarget->num_luns++; 191962306a36Sopenharmony_ci sdev->hostdata = vdevice; 192062306a36Sopenharmony_ci return 0; 192162306a36Sopenharmony_ci} 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_cistatic int 192462306a36Sopenharmony_cimptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) 192562306a36Sopenharmony_ci{ 192662306a36Sopenharmony_ci MPT_SCSI_HOST *hd; 192762306a36Sopenharmony_ci MPT_ADAPTER *ioc; 192862306a36Sopenharmony_ci VirtDevice *vdevice = SCpnt->device->hostdata; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { 193162306a36Sopenharmony_ci SCpnt->result = DID_NO_CONNECT << 16; 193262306a36Sopenharmony_ci scsi_done(SCpnt); 193362306a36Sopenharmony_ci return 0; 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci hd = shost_priv(shost); 193762306a36Sopenharmony_ci ioc = hd->ioc; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci if (ioc->sas_discovery_quiesce_io) 194062306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (ioc->debug_level & MPT_DEBUG_SCSI) 194362306a36Sopenharmony_ci scsi_print_command(SCpnt); 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci return mptscsih_qcmd(SCpnt); 194662306a36Sopenharmony_ci} 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci/** 194962306a36Sopenharmony_ci * mptsas_eh_timed_out - resets the scsi_cmnd timeout 195062306a36Sopenharmony_ci * if the device under question is currently in the 195162306a36Sopenharmony_ci * device removal delay. 195262306a36Sopenharmony_ci * @sc: scsi command that the midlayer is about to time out 195362306a36Sopenharmony_ci * 195462306a36Sopenharmony_ci **/ 195562306a36Sopenharmony_cistatic enum scsi_timeout_action mptsas_eh_timed_out(struct scsi_cmnd *sc) 195662306a36Sopenharmony_ci{ 195762306a36Sopenharmony_ci MPT_SCSI_HOST *hd; 195862306a36Sopenharmony_ci MPT_ADAPTER *ioc; 195962306a36Sopenharmony_ci VirtDevice *vdevice; 196062306a36Sopenharmony_ci enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci hd = shost_priv(sc->device->host); 196362306a36Sopenharmony_ci if (hd == NULL) { 196462306a36Sopenharmony_ci printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n", 196562306a36Sopenharmony_ci __func__, sc); 196662306a36Sopenharmony_ci goto done; 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci ioc = hd->ioc; 197062306a36Sopenharmony_ci if (ioc->bus_type != SAS) { 197162306a36Sopenharmony_ci printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n", 197262306a36Sopenharmony_ci __func__, sc); 197362306a36Sopenharmony_ci goto done; 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci /* In case if IOC is in reset from internal context. 197762306a36Sopenharmony_ci * Do not execute EEH for the same IOC. SML should to reset timer. 197862306a36Sopenharmony_ci */ 197962306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 198062306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," 198162306a36Sopenharmony_ci "SML need to reset the timer (sc=%p)\n", 198262306a36Sopenharmony_ci ioc->name, __func__, sc)); 198362306a36Sopenharmony_ci rc = SCSI_EH_RESET_TIMER; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci vdevice = sc->device->hostdata; 198662306a36Sopenharmony_ci if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD 198762306a36Sopenharmony_ci || vdevice->vtarget->deleted)) { 198862306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " 198962306a36Sopenharmony_ci "or in device removal delay (sc=%p)\n", 199062306a36Sopenharmony_ci ioc->name, __func__, sc)); 199162306a36Sopenharmony_ci rc = SCSI_EH_RESET_TIMER; 199262306a36Sopenharmony_ci goto done; 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_cidone: 199662306a36Sopenharmony_ci return rc; 199762306a36Sopenharmony_ci} 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cistatic const struct scsi_host_template mptsas_driver_template = { 200162306a36Sopenharmony_ci .module = THIS_MODULE, 200262306a36Sopenharmony_ci .proc_name = "mptsas", 200362306a36Sopenharmony_ci .show_info = mptscsih_show_info, 200462306a36Sopenharmony_ci .name = "MPT SAS Host", 200562306a36Sopenharmony_ci .info = mptscsih_info, 200662306a36Sopenharmony_ci .queuecommand = mptsas_qcmd, 200762306a36Sopenharmony_ci .target_alloc = mptsas_target_alloc, 200862306a36Sopenharmony_ci .slave_alloc = mptsas_slave_alloc, 200962306a36Sopenharmony_ci .slave_configure = mptsas_slave_configure, 201062306a36Sopenharmony_ci .target_destroy = mptsas_target_destroy, 201162306a36Sopenharmony_ci .slave_destroy = mptscsih_slave_destroy, 201262306a36Sopenharmony_ci .change_queue_depth = mptscsih_change_queue_depth, 201362306a36Sopenharmony_ci .eh_timed_out = mptsas_eh_timed_out, 201462306a36Sopenharmony_ci .eh_abort_handler = mptscsih_abort, 201562306a36Sopenharmony_ci .eh_device_reset_handler = mptscsih_dev_reset, 201662306a36Sopenharmony_ci .eh_host_reset_handler = mptscsih_host_reset, 201762306a36Sopenharmony_ci .bios_param = mptscsih_bios_param, 201862306a36Sopenharmony_ci .can_queue = MPT_SAS_CAN_QUEUE, 201962306a36Sopenharmony_ci .this_id = -1, 202062306a36Sopenharmony_ci .sg_tablesize = MPT_SCSI_SG_DEPTH, 202162306a36Sopenharmony_ci .max_sectors = 8192, 202262306a36Sopenharmony_ci .cmd_per_lun = 7, 202362306a36Sopenharmony_ci .shost_groups = mptscsih_host_attr_groups, 202462306a36Sopenharmony_ci .no_write_same = 1, 202562306a36Sopenharmony_ci}; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_cistatic int mptsas_get_linkerrors(struct sas_phy *phy) 202862306a36Sopenharmony_ci{ 202962306a36Sopenharmony_ci MPT_ADAPTER *ioc = phy_to_ioc(phy); 203062306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 203162306a36Sopenharmony_ci CONFIGPARMS cfg; 203262306a36Sopenharmony_ci SasPhyPage1_t *buffer; 203362306a36Sopenharmony_ci dma_addr_t dma_handle; 203462306a36Sopenharmony_ci int error; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci /* FIXME: only have link errors on local phys */ 203762306a36Sopenharmony_ci if (!scsi_is_sas_phy_local(phy)) 203862306a36Sopenharmony_ci return -EINVAL; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; 204162306a36Sopenharmony_ci hdr.ExtPageLength = 0; 204262306a36Sopenharmony_ci hdr.PageNumber = 1 /* page number 1*/; 204362306a36Sopenharmony_ci hdr.Reserved1 = 0; 204462306a36Sopenharmony_ci hdr.Reserved2 = 0; 204562306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 204662306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 204962306a36Sopenharmony_ci cfg.physAddr = -1; 205062306a36Sopenharmony_ci cfg.pageAddr = phy->identify.phy_identifier; 205162306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 205262306a36Sopenharmony_ci cfg.dir = 0; /* read */ 205362306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 205662306a36Sopenharmony_ci if (error) 205762306a36Sopenharmony_ci return error; 205862306a36Sopenharmony_ci if (!hdr.ExtPageLength) 205962306a36Sopenharmony_ci return -ENXIO; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 206262306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 206362306a36Sopenharmony_ci if (!buffer) 206462306a36Sopenharmony_ci return -ENOMEM; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci cfg.physAddr = dma_handle; 206762306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 207062306a36Sopenharmony_ci if (error) 207162306a36Sopenharmony_ci goto out_free_consistent; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci mptsas_print_phy_pg1(ioc, buffer); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); 207662306a36Sopenharmony_ci phy->running_disparity_error_count = 207762306a36Sopenharmony_ci le32_to_cpu(buffer->RunningDisparityErrorCount); 207862306a36Sopenharmony_ci phy->loss_of_dword_sync_count = 207962306a36Sopenharmony_ci le32_to_cpu(buffer->LossDwordSynchCount); 208062306a36Sopenharmony_ci phy->phy_reset_problem_count = 208162306a36Sopenharmony_ci le32_to_cpu(buffer->PhyResetProblemCount); 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci out_free_consistent: 208462306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 208562306a36Sopenharmony_ci dma_handle); 208662306a36Sopenharmony_ci return error; 208762306a36Sopenharmony_ci} 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_cistatic int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, 209062306a36Sopenharmony_ci MPT_FRAME_HDR *reply) 209162306a36Sopenharmony_ci{ 209262306a36Sopenharmony_ci ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; 209362306a36Sopenharmony_ci if (reply != NULL) { 209462306a36Sopenharmony_ci ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; 209562306a36Sopenharmony_ci memcpy(ioc->sas_mgmt.reply, reply, 209662306a36Sopenharmony_ci min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { 210062306a36Sopenharmony_ci ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; 210162306a36Sopenharmony_ci complete(&ioc->sas_mgmt.done); 210262306a36Sopenharmony_ci return 1; 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci return 0; 210562306a36Sopenharmony_ci} 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_cistatic int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) 210862306a36Sopenharmony_ci{ 210962306a36Sopenharmony_ci MPT_ADAPTER *ioc = phy_to_ioc(phy); 211062306a36Sopenharmony_ci SasIoUnitControlRequest_t *req; 211162306a36Sopenharmony_ci SasIoUnitControlReply_t *reply; 211262306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 211362306a36Sopenharmony_ci MPIHeader_t *hdr; 211462306a36Sopenharmony_ci unsigned long timeleft; 211562306a36Sopenharmony_ci int error = -ERESTARTSYS; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci /* FIXME: fusion doesn't allow non-local phy reset */ 211862306a36Sopenharmony_ci if (!scsi_is_sas_phy_local(phy)) 211962306a36Sopenharmony_ci return -EINVAL; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci /* not implemented for expanders */ 212262306a36Sopenharmony_ci if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) 212362306a36Sopenharmony_ci return -ENXIO; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) 212662306a36Sopenharmony_ci goto out; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); 212962306a36Sopenharmony_ci if (!mf) { 213062306a36Sopenharmony_ci error = -ENOMEM; 213162306a36Sopenharmony_ci goto out_unlock; 213262306a36Sopenharmony_ci } 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci hdr = (MPIHeader_t *) mf; 213562306a36Sopenharmony_ci req = (SasIoUnitControlRequest_t *)mf; 213662306a36Sopenharmony_ci memset(req, 0, sizeof(SasIoUnitControlRequest_t)); 213762306a36Sopenharmony_ci req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; 213862306a36Sopenharmony_ci req->MsgContext = hdr->MsgContext; 213962306a36Sopenharmony_ci req->Operation = hard_reset ? 214062306a36Sopenharmony_ci MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; 214162306a36Sopenharmony_ci req->PhyNum = phy->identify.phy_identifier; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) 214462306a36Sopenharmony_ci mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 214762306a36Sopenharmony_ci 10 * HZ); 214862306a36Sopenharmony_ci if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 214962306a36Sopenharmony_ci error = -ETIME; 215062306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 215162306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) 215262306a36Sopenharmony_ci goto out_unlock; 215362306a36Sopenharmony_ci if (!timeleft) 215462306a36Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 215562306a36Sopenharmony_ci goto out_unlock; 215662306a36Sopenharmony_ci } 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci /* a reply frame is expected */ 215962306a36Sopenharmony_ci if ((ioc->sas_mgmt.status & 216062306a36Sopenharmony_ci MPT_MGMT_STATUS_RF_VALID) == 0) { 216162306a36Sopenharmony_ci error = -ENXIO; 216262306a36Sopenharmony_ci goto out_unlock; 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci /* process the completed Reply Message Frame */ 216662306a36Sopenharmony_ci reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; 216762306a36Sopenharmony_ci if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { 216862306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", 216962306a36Sopenharmony_ci ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); 217062306a36Sopenharmony_ci error = -ENXIO; 217162306a36Sopenharmony_ci goto out_unlock; 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci error = 0; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci out_unlock: 217762306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) 217862306a36Sopenharmony_ci mutex_unlock(&ioc->sas_mgmt.mutex); 217962306a36Sopenharmony_ci out: 218062306a36Sopenharmony_ci return error; 218162306a36Sopenharmony_ci} 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_cistatic int 218462306a36Sopenharmony_cimptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) 218562306a36Sopenharmony_ci{ 218662306a36Sopenharmony_ci MPT_ADAPTER *ioc = rphy_to_ioc(rphy); 218762306a36Sopenharmony_ci int i, error; 218862306a36Sopenharmony_ci struct mptsas_portinfo *p; 218962306a36Sopenharmony_ci struct mptsas_enclosure enclosure_info; 219062306a36Sopenharmony_ci u64 enclosure_handle; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 219362306a36Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 219462306a36Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 219562306a36Sopenharmony_ci if (p->phy_info[i].attached.sas_address == 219662306a36Sopenharmony_ci rphy->identify.sas_address) { 219762306a36Sopenharmony_ci enclosure_handle = p->phy_info[i]. 219862306a36Sopenharmony_ci attached.handle_enclosure; 219962306a36Sopenharmony_ci goto found_info; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 220462306a36Sopenharmony_ci return -ENXIO; 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci found_info: 220762306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 220862306a36Sopenharmony_ci memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); 220962306a36Sopenharmony_ci error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, 221062306a36Sopenharmony_ci (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << 221162306a36Sopenharmony_ci MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); 221262306a36Sopenharmony_ci if (!error) 221362306a36Sopenharmony_ci *identifier = enclosure_info.enclosure_logical_id; 221462306a36Sopenharmony_ci return error; 221562306a36Sopenharmony_ci} 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_cistatic int 221862306a36Sopenharmony_cimptsas_get_bay_identifier(struct sas_rphy *rphy) 221962306a36Sopenharmony_ci{ 222062306a36Sopenharmony_ci MPT_ADAPTER *ioc = rphy_to_ioc(rphy); 222162306a36Sopenharmony_ci struct mptsas_portinfo *p; 222262306a36Sopenharmony_ci int i, rc; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 222562306a36Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 222662306a36Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 222762306a36Sopenharmony_ci if (p->phy_info[i].attached.sas_address == 222862306a36Sopenharmony_ci rphy->identify.sas_address) { 222962306a36Sopenharmony_ci rc = p->phy_info[i].attached.slot; 223062306a36Sopenharmony_ci goto out; 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci } 223362306a36Sopenharmony_ci } 223462306a36Sopenharmony_ci rc = -ENXIO; 223562306a36Sopenharmony_ci out: 223662306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 223762306a36Sopenharmony_ci return rc; 223862306a36Sopenharmony_ci} 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_cistatic void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, 224162306a36Sopenharmony_ci struct sas_rphy *rphy) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; 224462306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 224562306a36Sopenharmony_ci SmpPassthroughRequest_t *smpreq; 224662306a36Sopenharmony_ci int flagsLength; 224762306a36Sopenharmony_ci unsigned long timeleft; 224862306a36Sopenharmony_ci char *psge; 224962306a36Sopenharmony_ci u64 sas_address = 0; 225062306a36Sopenharmony_ci unsigned int reslen = 0; 225162306a36Sopenharmony_ci int ret = -EINVAL; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci /* do we need to support multiple segments? */ 225462306a36Sopenharmony_ci if (job->request_payload.sg_cnt > 1 || 225562306a36Sopenharmony_ci job->reply_payload.sg_cnt > 1) { 225662306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n", 225762306a36Sopenharmony_ci ioc->name, __func__, job->request_payload.payload_len, 225862306a36Sopenharmony_ci job->reply_payload.payload_len); 225962306a36Sopenharmony_ci goto out; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); 226362306a36Sopenharmony_ci if (ret) 226462306a36Sopenharmony_ci goto out; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); 226762306a36Sopenharmony_ci if (!mf) { 226862306a36Sopenharmony_ci ret = -ENOMEM; 226962306a36Sopenharmony_ci goto out_unlock; 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci smpreq = (SmpPassthroughRequest_t *)mf; 227362306a36Sopenharmony_ci memset(smpreq, 0, sizeof(*smpreq)); 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci smpreq->RequestDataLength = 227662306a36Sopenharmony_ci cpu_to_le16(job->request_payload.payload_len - 4); 227762306a36Sopenharmony_ci smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci if (rphy) 228062306a36Sopenharmony_ci sas_address = rphy->identify.sas_address; 228162306a36Sopenharmony_ci else { 228262306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 228562306a36Sopenharmony_ci port_info = ioc->hba_port_info; 228662306a36Sopenharmony_ci if (port_info && port_info->phy_info) 228762306a36Sopenharmony_ci sas_address = 228862306a36Sopenharmony_ci port_info->phy_info[0].phy->identify.sas_address; 228962306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci psge = (char *) 229562306a36Sopenharmony_ci (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci /* request */ 229862306a36Sopenharmony_ci flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 229962306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER | 230062306a36Sopenharmony_ci MPI_SGE_FLAGS_DIRECTION) 230162306a36Sopenharmony_ci << MPI_SGE_FLAGS_SHIFT; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 230462306a36Sopenharmony_ci 1, DMA_BIDIRECTIONAL)) 230562306a36Sopenharmony_ci goto put_mf; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4); 230862306a36Sopenharmony_ci ioc->add_sge(psge, flagsLength, 230962306a36Sopenharmony_ci sg_dma_address(job->request_payload.sg_list)); 231062306a36Sopenharmony_ci psge += ioc->SGE_size; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci /* response */ 231362306a36Sopenharmony_ci flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 231462306a36Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 231562306a36Sopenharmony_ci MPI_SGE_FLAGS_IOC_TO_HOST | 231662306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 232162306a36Sopenharmony_ci 1, DMA_BIDIRECTIONAL)) 232262306a36Sopenharmony_ci goto unmap_out; 232362306a36Sopenharmony_ci flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4; 232462306a36Sopenharmony_ci ioc->add_sge(psge, flagsLength, 232562306a36Sopenharmony_ci sg_dma_address(job->reply_payload.sg_list)); 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) 232862306a36Sopenharmony_ci mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); 233162306a36Sopenharmony_ci if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 233262306a36Sopenharmony_ci ret = -ETIME; 233362306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 233462306a36Sopenharmony_ci mf = NULL; 233562306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) 233662306a36Sopenharmony_ci goto unmap_in; 233762306a36Sopenharmony_ci if (!timeleft) 233862306a36Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 233962306a36Sopenharmony_ci goto unmap_in; 234062306a36Sopenharmony_ci } 234162306a36Sopenharmony_ci mf = NULL; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { 234462306a36Sopenharmony_ci SmpPassthroughReply_t *smprep; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; 234762306a36Sopenharmony_ci memcpy(job->reply, smprep, sizeof(*smprep)); 234862306a36Sopenharmony_ci job->reply_len = sizeof(*smprep); 234962306a36Sopenharmony_ci reslen = smprep->ResponseDataLength; 235062306a36Sopenharmony_ci } else { 235162306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 235262306a36Sopenharmony_ci "%s: smp passthru reply failed to be returned\n", 235362306a36Sopenharmony_ci ioc->name, __func__); 235462306a36Sopenharmony_ci ret = -ENXIO; 235562306a36Sopenharmony_ci } 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ciunmap_in: 235862306a36Sopenharmony_ci dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1, 235962306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 236062306a36Sopenharmony_ciunmap_out: 236162306a36Sopenharmony_ci dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1, 236262306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 236362306a36Sopenharmony_ciput_mf: 236462306a36Sopenharmony_ci if (mf) 236562306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 236662306a36Sopenharmony_ciout_unlock: 236762306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) 236862306a36Sopenharmony_ci mutex_unlock(&ioc->sas_mgmt.mutex); 236962306a36Sopenharmony_ciout: 237062306a36Sopenharmony_ci bsg_job_done(job, ret, reslen); 237162306a36Sopenharmony_ci} 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_cistatic struct sas_function_template mptsas_transport_functions = { 237462306a36Sopenharmony_ci .get_linkerrors = mptsas_get_linkerrors, 237562306a36Sopenharmony_ci .get_enclosure_identifier = mptsas_get_enclosure_identifier, 237662306a36Sopenharmony_ci .get_bay_identifier = mptsas_get_bay_identifier, 237762306a36Sopenharmony_ci .phy_reset = mptsas_phy_reset, 237862306a36Sopenharmony_ci .smp_handler = mptsas_smp_handler, 237962306a36Sopenharmony_ci}; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_cistatic struct scsi_transport_template *mptsas_transport_template; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_cistatic int 238462306a36Sopenharmony_cimptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 238762306a36Sopenharmony_ci CONFIGPARMS cfg; 238862306a36Sopenharmony_ci SasIOUnitPage0_t *buffer; 238962306a36Sopenharmony_ci dma_addr_t dma_handle; 239062306a36Sopenharmony_ci int error, i; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; 239362306a36Sopenharmony_ci hdr.ExtPageLength = 0; 239462306a36Sopenharmony_ci hdr.PageNumber = 0; 239562306a36Sopenharmony_ci hdr.Reserved1 = 0; 239662306a36Sopenharmony_ci hdr.Reserved2 = 0; 239762306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 239862306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 240162306a36Sopenharmony_ci cfg.physAddr = -1; 240262306a36Sopenharmony_ci cfg.pageAddr = 0; 240362306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 240462306a36Sopenharmony_ci cfg.dir = 0; /* read */ 240562306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 240862306a36Sopenharmony_ci if (error) 240962306a36Sopenharmony_ci goto out; 241062306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 241162306a36Sopenharmony_ci error = -ENXIO; 241262306a36Sopenharmony_ci goto out; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 241662306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 241762306a36Sopenharmony_ci if (!buffer) { 241862306a36Sopenharmony_ci error = -ENOMEM; 241962306a36Sopenharmony_ci goto out; 242062306a36Sopenharmony_ci } 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci cfg.physAddr = dma_handle; 242362306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 242662306a36Sopenharmony_ci if (error) 242762306a36Sopenharmony_ci goto out_free_consistent; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci port_info->num_phys = buffer->NumPhys; 243062306a36Sopenharmony_ci port_info->phy_info = kcalloc(port_info->num_phys, 243162306a36Sopenharmony_ci sizeof(struct mptsas_phyinfo), GFP_KERNEL); 243262306a36Sopenharmony_ci if (!port_info->phy_info) { 243362306a36Sopenharmony_ci error = -ENOMEM; 243462306a36Sopenharmony_ci goto out_free_consistent; 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci ioc->nvdata_version_persistent = 243862306a36Sopenharmony_ci le16_to_cpu(buffer->NvdataVersionPersistent); 243962306a36Sopenharmony_ci ioc->nvdata_version_default = 244062306a36Sopenharmony_ci le16_to_cpu(buffer->NvdataVersionDefault); 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 244362306a36Sopenharmony_ci mptsas_print_phy_data(ioc, &buffer->PhyData[i]); 244462306a36Sopenharmony_ci port_info->phy_info[i].phy_id = i; 244562306a36Sopenharmony_ci port_info->phy_info[i].port_id = 244662306a36Sopenharmony_ci buffer->PhyData[i].Port; 244762306a36Sopenharmony_ci port_info->phy_info[i].negotiated_link_rate = 244862306a36Sopenharmony_ci buffer->PhyData[i].NegotiatedLinkRate; 244962306a36Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 245062306a36Sopenharmony_ci port_info->phy_info[i].handle = 245162306a36Sopenharmony_ci le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); 245262306a36Sopenharmony_ci } 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci out_free_consistent: 245562306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 245662306a36Sopenharmony_ci dma_handle); 245762306a36Sopenharmony_ci out: 245862306a36Sopenharmony_ci return error; 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_cistatic int 246262306a36Sopenharmony_cimptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 246562306a36Sopenharmony_ci CONFIGPARMS cfg; 246662306a36Sopenharmony_ci SasIOUnitPage1_t *buffer; 246762306a36Sopenharmony_ci dma_addr_t dma_handle; 246862306a36Sopenharmony_ci int error; 246962306a36Sopenharmony_ci u8 device_missing_delay; 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); 247262306a36Sopenharmony_ci memset(&cfg, 0, sizeof(CONFIGPARMS)); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 247562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 247662306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 247762306a36Sopenharmony_ci cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 247862306a36Sopenharmony_ci cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; 247962306a36Sopenharmony_ci cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; 248062306a36Sopenharmony_ci cfg.cfghdr.ehdr->PageNumber = 1; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 248362306a36Sopenharmony_ci if (error) 248462306a36Sopenharmony_ci goto out; 248562306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 248662306a36Sopenharmony_ci error = -ENXIO; 248762306a36Sopenharmony_ci goto out; 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 249162306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 249262306a36Sopenharmony_ci if (!buffer) { 249362306a36Sopenharmony_ci error = -ENOMEM; 249462306a36Sopenharmony_ci goto out; 249562306a36Sopenharmony_ci } 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci cfg.physAddr = dma_handle; 249862306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 250162306a36Sopenharmony_ci if (error) 250262306a36Sopenharmony_ci goto out_free_consistent; 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci ioc->io_missing_delay = 250562306a36Sopenharmony_ci le16_to_cpu(buffer->IODeviceMissingDelay); 250662306a36Sopenharmony_ci device_missing_delay = buffer->ReportDeviceMissingDelay; 250762306a36Sopenharmony_ci ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? 250862306a36Sopenharmony_ci (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : 250962306a36Sopenharmony_ci device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci out_free_consistent: 251262306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 251362306a36Sopenharmony_ci dma_handle); 251462306a36Sopenharmony_ci out: 251562306a36Sopenharmony_ci return error; 251662306a36Sopenharmony_ci} 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_cistatic int 251962306a36Sopenharmony_cimptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, 252062306a36Sopenharmony_ci u32 form, u32 form_specific) 252162306a36Sopenharmony_ci{ 252262306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 252362306a36Sopenharmony_ci CONFIGPARMS cfg; 252462306a36Sopenharmony_ci SasPhyPage0_t *buffer; 252562306a36Sopenharmony_ci dma_addr_t dma_handle; 252662306a36Sopenharmony_ci int error; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; 252962306a36Sopenharmony_ci hdr.ExtPageLength = 0; 253062306a36Sopenharmony_ci hdr.PageNumber = 0; 253162306a36Sopenharmony_ci hdr.Reserved1 = 0; 253262306a36Sopenharmony_ci hdr.Reserved2 = 0; 253362306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 253462306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 253762306a36Sopenharmony_ci cfg.dir = 0; /* read */ 253862306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci /* Get Phy Pg 0 for each Phy. */ 254162306a36Sopenharmony_ci cfg.physAddr = -1; 254262306a36Sopenharmony_ci cfg.pageAddr = form + form_specific; 254362306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 254662306a36Sopenharmony_ci if (error) 254762306a36Sopenharmony_ci goto out; 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 255062306a36Sopenharmony_ci error = -ENXIO; 255162306a36Sopenharmony_ci goto out; 255262306a36Sopenharmony_ci } 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 255562306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 255662306a36Sopenharmony_ci if (!buffer) { 255762306a36Sopenharmony_ci error = -ENOMEM; 255862306a36Sopenharmony_ci goto out; 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci cfg.physAddr = dma_handle; 256262306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 256562306a36Sopenharmony_ci if (error) 256662306a36Sopenharmony_ci goto out_free_consistent; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci mptsas_print_phy_pg0(ioc, buffer); 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci phy_info->hw_link_rate = buffer->HwLinkRate; 257162306a36Sopenharmony_ci phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; 257262306a36Sopenharmony_ci phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); 257362306a36Sopenharmony_ci phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci out_free_consistent: 257662306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 257762306a36Sopenharmony_ci dma_handle); 257862306a36Sopenharmony_ci out: 257962306a36Sopenharmony_ci return error; 258062306a36Sopenharmony_ci} 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_cistatic int 258362306a36Sopenharmony_cimptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, 258462306a36Sopenharmony_ci u32 form, u32 form_specific) 258562306a36Sopenharmony_ci{ 258662306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 258762306a36Sopenharmony_ci CONFIGPARMS cfg; 258862306a36Sopenharmony_ci SasDevicePage0_t *buffer; 258962306a36Sopenharmony_ci dma_addr_t dma_handle; 259062306a36Sopenharmony_ci __le64 sas_address; 259162306a36Sopenharmony_ci int error=0; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; 259462306a36Sopenharmony_ci hdr.ExtPageLength = 0; 259562306a36Sopenharmony_ci hdr.PageNumber = 0; 259662306a36Sopenharmony_ci hdr.Reserved1 = 0; 259762306a36Sopenharmony_ci hdr.Reserved2 = 0; 259862306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 259962306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 260262306a36Sopenharmony_ci cfg.pageAddr = form + form_specific; 260362306a36Sopenharmony_ci cfg.physAddr = -1; 260462306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 260562306a36Sopenharmony_ci cfg.dir = 0; /* read */ 260662306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci memset(device_info, 0, sizeof(struct mptsas_devinfo)); 260962306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 261062306a36Sopenharmony_ci if (error) 261162306a36Sopenharmony_ci goto out; 261262306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 261362306a36Sopenharmony_ci error = -ENXIO; 261462306a36Sopenharmony_ci goto out; 261562306a36Sopenharmony_ci } 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 261862306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 261962306a36Sopenharmony_ci if (!buffer) { 262062306a36Sopenharmony_ci error = -ENOMEM; 262162306a36Sopenharmony_ci goto out; 262262306a36Sopenharmony_ci } 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci cfg.physAddr = dma_handle; 262562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 263062306a36Sopenharmony_ci error = -ENODEV; 263162306a36Sopenharmony_ci goto out_free_consistent; 263262306a36Sopenharmony_ci } 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci if (error) 263562306a36Sopenharmony_ci goto out_free_consistent; 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci mptsas_print_device_pg0(ioc, buffer); 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci memset(device_info, 0, sizeof(struct mptsas_devinfo)); 264062306a36Sopenharmony_ci device_info->handle = le16_to_cpu(buffer->DevHandle); 264162306a36Sopenharmony_ci device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); 264262306a36Sopenharmony_ci device_info->handle_enclosure = 264362306a36Sopenharmony_ci le16_to_cpu(buffer->EnclosureHandle); 264462306a36Sopenharmony_ci device_info->slot = le16_to_cpu(buffer->Slot); 264562306a36Sopenharmony_ci device_info->phy_id = buffer->PhyNum; 264662306a36Sopenharmony_ci device_info->port_id = buffer->PhysicalPort; 264762306a36Sopenharmony_ci device_info->id = buffer->TargetID; 264862306a36Sopenharmony_ci device_info->phys_disk_num = ~0; 264962306a36Sopenharmony_ci device_info->channel = buffer->Bus; 265062306a36Sopenharmony_ci memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); 265162306a36Sopenharmony_ci device_info->sas_address = le64_to_cpu(sas_address); 265262306a36Sopenharmony_ci device_info->device_info = 265362306a36Sopenharmony_ci le32_to_cpu(buffer->DeviceInfo); 265462306a36Sopenharmony_ci device_info->flags = le16_to_cpu(buffer->Flags); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci out_free_consistent: 265762306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 265862306a36Sopenharmony_ci dma_handle); 265962306a36Sopenharmony_ci out: 266062306a36Sopenharmony_ci return error; 266162306a36Sopenharmony_ci} 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_cistatic int 266462306a36Sopenharmony_cimptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, 266562306a36Sopenharmony_ci u32 form, u32 form_specific) 266662306a36Sopenharmony_ci{ 266762306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 266862306a36Sopenharmony_ci CONFIGPARMS cfg; 266962306a36Sopenharmony_ci SasExpanderPage0_t *buffer; 267062306a36Sopenharmony_ci dma_addr_t dma_handle; 267162306a36Sopenharmony_ci int i, error; 267262306a36Sopenharmony_ci __le64 sas_address; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci memset(port_info, 0, sizeof(struct mptsas_portinfo)); 267562306a36Sopenharmony_ci hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; 267662306a36Sopenharmony_ci hdr.ExtPageLength = 0; 267762306a36Sopenharmony_ci hdr.PageNumber = 0; 267862306a36Sopenharmony_ci hdr.Reserved1 = 0; 267962306a36Sopenharmony_ci hdr.Reserved2 = 0; 268062306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 268162306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 268462306a36Sopenharmony_ci cfg.physAddr = -1; 268562306a36Sopenharmony_ci cfg.pageAddr = form + form_specific; 268662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 268762306a36Sopenharmony_ci cfg.dir = 0; /* read */ 268862306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci memset(port_info, 0, sizeof(struct mptsas_portinfo)); 269162306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 269262306a36Sopenharmony_ci if (error) 269362306a36Sopenharmony_ci goto out; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 269662306a36Sopenharmony_ci error = -ENXIO; 269762306a36Sopenharmony_ci goto out; 269862306a36Sopenharmony_ci } 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 270162306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 270262306a36Sopenharmony_ci if (!buffer) { 270362306a36Sopenharmony_ci error = -ENOMEM; 270462306a36Sopenharmony_ci goto out; 270562306a36Sopenharmony_ci } 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci cfg.physAddr = dma_handle; 270862306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 271162306a36Sopenharmony_ci if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 271262306a36Sopenharmony_ci error = -ENODEV; 271362306a36Sopenharmony_ci goto out_free_consistent; 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci if (error) 271762306a36Sopenharmony_ci goto out_free_consistent; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci /* save config data */ 272062306a36Sopenharmony_ci port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; 272162306a36Sopenharmony_ci port_info->phy_info = kcalloc(port_info->num_phys, 272262306a36Sopenharmony_ci sizeof(struct mptsas_phyinfo), GFP_KERNEL); 272362306a36Sopenharmony_ci if (!port_info->phy_info) { 272462306a36Sopenharmony_ci error = -ENOMEM; 272562306a36Sopenharmony_ci goto out_free_consistent; 272662306a36Sopenharmony_ci } 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); 272962306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 273062306a36Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 273162306a36Sopenharmony_ci port_info->phy_info[i].handle = 273262306a36Sopenharmony_ci le16_to_cpu(buffer->DevHandle); 273362306a36Sopenharmony_ci port_info->phy_info[i].identify.sas_address = 273462306a36Sopenharmony_ci le64_to_cpu(sas_address); 273562306a36Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 273662306a36Sopenharmony_ci le16_to_cpu(buffer->ParentDevHandle); 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci out_free_consistent: 274062306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 274162306a36Sopenharmony_ci dma_handle); 274262306a36Sopenharmony_ci out: 274362306a36Sopenharmony_ci return error; 274462306a36Sopenharmony_ci} 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_cistatic int 274762306a36Sopenharmony_cimptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, 274862306a36Sopenharmony_ci u32 form, u32 form_specific) 274962306a36Sopenharmony_ci{ 275062306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 275162306a36Sopenharmony_ci CONFIGPARMS cfg; 275262306a36Sopenharmony_ci SasExpanderPage1_t *buffer; 275362306a36Sopenharmony_ci dma_addr_t dma_handle; 275462306a36Sopenharmony_ci int error=0; 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; 275762306a36Sopenharmony_ci hdr.ExtPageLength = 0; 275862306a36Sopenharmony_ci hdr.PageNumber = 1; 275962306a36Sopenharmony_ci hdr.Reserved1 = 0; 276062306a36Sopenharmony_ci hdr.Reserved2 = 0; 276162306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 276262306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 276562306a36Sopenharmony_ci cfg.physAddr = -1; 276662306a36Sopenharmony_ci cfg.pageAddr = form + form_specific; 276762306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 276862306a36Sopenharmony_ci cfg.dir = 0; /* read */ 276962306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 277262306a36Sopenharmony_ci if (error) 277362306a36Sopenharmony_ci goto out; 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci if (!hdr.ExtPageLength) { 277662306a36Sopenharmony_ci error = -ENXIO; 277762306a36Sopenharmony_ci goto out; 277862306a36Sopenharmony_ci } 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 278162306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 278262306a36Sopenharmony_ci if (!buffer) { 278362306a36Sopenharmony_ci error = -ENOMEM; 278462306a36Sopenharmony_ci goto out; 278562306a36Sopenharmony_ci } 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci cfg.physAddr = dma_handle; 278862306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci error = mpt_config(ioc, &cfg); 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 279362306a36Sopenharmony_ci error = -ENODEV; 279462306a36Sopenharmony_ci goto out_free_consistent; 279562306a36Sopenharmony_ci } 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci if (error) 279862306a36Sopenharmony_ci goto out_free_consistent; 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci mptsas_print_expander_pg1(ioc, buffer); 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci /* save config data */ 280462306a36Sopenharmony_ci phy_info->phy_id = buffer->PhyIdentifier; 280562306a36Sopenharmony_ci phy_info->port_id = buffer->PhysicalPort; 280662306a36Sopenharmony_ci phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; 280762306a36Sopenharmony_ci phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; 280862306a36Sopenharmony_ci phy_info->hw_link_rate = buffer->HwLinkRate; 280962306a36Sopenharmony_ci phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); 281062306a36Sopenharmony_ci phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci out_free_consistent: 281362306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 281462306a36Sopenharmony_ci dma_handle); 281562306a36Sopenharmony_ci out: 281662306a36Sopenharmony_ci return error; 281762306a36Sopenharmony_ci} 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_cistruct rep_manu_request{ 282062306a36Sopenharmony_ci u8 smp_frame_type; 282162306a36Sopenharmony_ci u8 function; 282262306a36Sopenharmony_ci u8 reserved; 282362306a36Sopenharmony_ci u8 request_length; 282462306a36Sopenharmony_ci}; 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_cistruct rep_manu_reply{ 282762306a36Sopenharmony_ci u8 smp_frame_type; /* 0x41 */ 282862306a36Sopenharmony_ci u8 function; /* 0x01 */ 282962306a36Sopenharmony_ci u8 function_result; 283062306a36Sopenharmony_ci u8 response_length; 283162306a36Sopenharmony_ci u16 expander_change_count; 283262306a36Sopenharmony_ci u8 reserved0[2]; 283362306a36Sopenharmony_ci u8 sas_format:1; 283462306a36Sopenharmony_ci u8 reserved1:7; 283562306a36Sopenharmony_ci u8 reserved2[3]; 283662306a36Sopenharmony_ci u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; 283762306a36Sopenharmony_ci u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; 283862306a36Sopenharmony_ci u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; 283962306a36Sopenharmony_ci u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; 284062306a36Sopenharmony_ci u16 component_id; 284162306a36Sopenharmony_ci u8 component_revision_id; 284262306a36Sopenharmony_ci u8 reserved3; 284362306a36Sopenharmony_ci u8 vendor_specific[8]; 284462306a36Sopenharmony_ci}; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci/** 284762306a36Sopenharmony_ci * mptsas_exp_repmanufacture_info - sets expander manufacturer info 284862306a36Sopenharmony_ci * @ioc: per adapter object 284962306a36Sopenharmony_ci * @sas_address: expander sas address 285062306a36Sopenharmony_ci * @edev: the sas_expander_device object 285162306a36Sopenharmony_ci * 285262306a36Sopenharmony_ci * For an edge expander or a fanout expander: 285362306a36Sopenharmony_ci * fills in the sas_expander_device object when SMP port is created. 285462306a36Sopenharmony_ci * 285562306a36Sopenharmony_ci * Return: 0 for success, non-zero for failure. 285662306a36Sopenharmony_ci */ 285762306a36Sopenharmony_cistatic int 285862306a36Sopenharmony_cimptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, 285962306a36Sopenharmony_ci u64 sas_address, struct sas_expander_device *edev) 286062306a36Sopenharmony_ci{ 286162306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 286262306a36Sopenharmony_ci SmpPassthroughRequest_t *smpreq; 286362306a36Sopenharmony_ci SmpPassthroughReply_t *smprep; 286462306a36Sopenharmony_ci struct rep_manu_reply *manufacture_reply; 286562306a36Sopenharmony_ci struct rep_manu_request *manufacture_request; 286662306a36Sopenharmony_ci int ret; 286762306a36Sopenharmony_ci int flagsLength; 286862306a36Sopenharmony_ci unsigned long timeleft; 286962306a36Sopenharmony_ci char *psge; 287062306a36Sopenharmony_ci unsigned long flags; 287162306a36Sopenharmony_ci void *data_out = NULL; 287262306a36Sopenharmony_ci dma_addr_t data_out_dma = 0; 287362306a36Sopenharmony_ci u32 sz; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 287662306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 287762306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 287862306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", 287962306a36Sopenharmony_ci __func__, ioc->name); 288062306a36Sopenharmony_ci return -EFAULT; 288162306a36Sopenharmony_ci } 288262306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); 288562306a36Sopenharmony_ci if (ret) 288662306a36Sopenharmony_ci goto out; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); 288962306a36Sopenharmony_ci if (!mf) { 289062306a36Sopenharmony_ci ret = -ENOMEM; 289162306a36Sopenharmony_ci goto out_unlock; 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci smpreq = (SmpPassthroughRequest_t *)mf; 289562306a36Sopenharmony_ci memset(smpreq, 0, sizeof(*smpreq)); 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci data_out = dma_alloc_coherent(&ioc->pcidev->dev, sz, &data_out_dma, 290062306a36Sopenharmony_ci GFP_KERNEL); 290162306a36Sopenharmony_ci if (!data_out) { 290262306a36Sopenharmony_ci printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", 290362306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 290462306a36Sopenharmony_ci ret = -ENOMEM; 290562306a36Sopenharmony_ci goto put_mf; 290662306a36Sopenharmony_ci } 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci manufacture_request = data_out; 290962306a36Sopenharmony_ci manufacture_request->smp_frame_type = 0x40; 291062306a36Sopenharmony_ci manufacture_request->function = 1; 291162306a36Sopenharmony_ci manufacture_request->reserved = 0; 291262306a36Sopenharmony_ci manufacture_request->request_length = 0; 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; 291562306a36Sopenharmony_ci smpreq->PhysicalPort = 0xFF; 291662306a36Sopenharmony_ci *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); 291762306a36Sopenharmony_ci smpreq->RequestDataLength = sizeof(struct rep_manu_request); 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci psge = (char *) 292062306a36Sopenharmony_ci (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 292362306a36Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 292462306a36Sopenharmony_ci MPI_SGE_FLAGS_HOST_TO_IOC | 292562306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 292662306a36Sopenharmony_ci flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; 292762306a36Sopenharmony_ci flagsLength |= sizeof(struct rep_manu_request); 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci ioc->add_sge(psge, flagsLength, data_out_dma); 293062306a36Sopenharmony_ci psge += ioc->SGE_size; 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 293362306a36Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 293462306a36Sopenharmony_ci MPI_SGE_FLAGS_IOC_TO_HOST | 293562306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 293662306a36Sopenharmony_ci flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; 293762306a36Sopenharmony_ci flagsLength |= sizeof(struct rep_manu_reply); 293862306a36Sopenharmony_ci ioc->add_sge(psge, flagsLength, data_out_dma + 293962306a36Sopenharmony_ci sizeof(struct rep_manu_request)); 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) 294262306a36Sopenharmony_ci mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); 294562306a36Sopenharmony_ci if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 294662306a36Sopenharmony_ci ret = -ETIME; 294762306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 294862306a36Sopenharmony_ci mf = NULL; 294962306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) 295062306a36Sopenharmony_ci goto out_free; 295162306a36Sopenharmony_ci if (!timeleft) 295262306a36Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 295362306a36Sopenharmony_ci goto out_free; 295462306a36Sopenharmony_ci } 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci mf = NULL; 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { 295962306a36Sopenharmony_ci u8 *tmp; 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; 296262306a36Sopenharmony_ci if (le16_to_cpu(smprep->ResponseDataLength) != 296362306a36Sopenharmony_ci sizeof(struct rep_manu_reply)) 296462306a36Sopenharmony_ci goto out_free; 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_ci manufacture_reply = data_out + sizeof(struct rep_manu_request); 296762306a36Sopenharmony_ci strncpy(edev->vendor_id, manufacture_reply->vendor_id, 296862306a36Sopenharmony_ci SAS_EXPANDER_VENDOR_ID_LEN); 296962306a36Sopenharmony_ci strncpy(edev->product_id, manufacture_reply->product_id, 297062306a36Sopenharmony_ci SAS_EXPANDER_PRODUCT_ID_LEN); 297162306a36Sopenharmony_ci strncpy(edev->product_rev, manufacture_reply->product_rev, 297262306a36Sopenharmony_ci SAS_EXPANDER_PRODUCT_REV_LEN); 297362306a36Sopenharmony_ci edev->level = manufacture_reply->sas_format; 297462306a36Sopenharmony_ci if (manufacture_reply->sas_format) { 297562306a36Sopenharmony_ci strncpy(edev->component_vendor_id, 297662306a36Sopenharmony_ci manufacture_reply->component_vendor_id, 297762306a36Sopenharmony_ci SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); 297862306a36Sopenharmony_ci tmp = (u8 *)&manufacture_reply->component_id; 297962306a36Sopenharmony_ci edev->component_id = tmp[0] << 8 | tmp[1]; 298062306a36Sopenharmony_ci edev->component_revision_id = 298162306a36Sopenharmony_ci manufacture_reply->component_revision_id; 298262306a36Sopenharmony_ci } 298362306a36Sopenharmony_ci } else { 298462306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 298562306a36Sopenharmony_ci "%s: smp passthru reply failed to be returned\n", 298662306a36Sopenharmony_ci ioc->name, __func__); 298762306a36Sopenharmony_ci ret = -ENXIO; 298862306a36Sopenharmony_ci } 298962306a36Sopenharmony_ciout_free: 299062306a36Sopenharmony_ci if (data_out_dma) 299162306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, data_out, 299262306a36Sopenharmony_ci data_out_dma); 299362306a36Sopenharmony_ciput_mf: 299462306a36Sopenharmony_ci if (mf) 299562306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 299662306a36Sopenharmony_ciout_unlock: 299762306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) 299862306a36Sopenharmony_ci mutex_unlock(&ioc->sas_mgmt.mutex); 299962306a36Sopenharmony_ciout: 300062306a36Sopenharmony_ci return ret; 300162306a36Sopenharmony_ci} 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_cistatic void 300462306a36Sopenharmony_cimptsas_parse_device_info(struct sas_identify *identify, 300562306a36Sopenharmony_ci struct mptsas_devinfo *device_info) 300662306a36Sopenharmony_ci{ 300762306a36Sopenharmony_ci u16 protocols; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci identify->sas_address = device_info->sas_address; 301062306a36Sopenharmony_ci identify->phy_identifier = device_info->phy_id; 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci /* 301362306a36Sopenharmony_ci * Fill in Phy Initiator Port Protocol. 301462306a36Sopenharmony_ci * Bits 6:3, more than one bit can be set, fall through cases. 301562306a36Sopenharmony_ci */ 301662306a36Sopenharmony_ci protocols = device_info->device_info & 0x78; 301762306a36Sopenharmony_ci identify->initiator_port_protocols = 0; 301862306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) 301962306a36Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; 302062306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) 302162306a36Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_STP; 302262306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) 302362306a36Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; 302462306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) 302562306a36Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci /* 302862306a36Sopenharmony_ci * Fill in Phy Target Port Protocol. 302962306a36Sopenharmony_ci * Bits 10:7, more than one bit can be set, fall through cases. 303062306a36Sopenharmony_ci */ 303162306a36Sopenharmony_ci protocols = device_info->device_info & 0x780; 303262306a36Sopenharmony_ci identify->target_port_protocols = 0; 303362306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) 303462306a36Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_SSP; 303562306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) 303662306a36Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_STP; 303762306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) 303862306a36Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_SMP; 303962306a36Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) 304062306a36Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_SATA; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci /* 304362306a36Sopenharmony_ci * Fill in Attached device type. 304462306a36Sopenharmony_ci */ 304562306a36Sopenharmony_ci switch (device_info->device_info & 304662306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { 304762306a36Sopenharmony_ci case MPI_SAS_DEVICE_INFO_NO_DEVICE: 304862306a36Sopenharmony_ci identify->device_type = SAS_PHY_UNUSED; 304962306a36Sopenharmony_ci break; 305062306a36Sopenharmony_ci case MPI_SAS_DEVICE_INFO_END_DEVICE: 305162306a36Sopenharmony_ci identify->device_type = SAS_END_DEVICE; 305262306a36Sopenharmony_ci break; 305362306a36Sopenharmony_ci case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: 305462306a36Sopenharmony_ci identify->device_type = SAS_EDGE_EXPANDER_DEVICE; 305562306a36Sopenharmony_ci break; 305662306a36Sopenharmony_ci case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: 305762306a36Sopenharmony_ci identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; 305862306a36Sopenharmony_ci break; 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci} 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_cistatic int mptsas_probe_one_phy(struct device *dev, 306362306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info, int index, int local) 306462306a36Sopenharmony_ci{ 306562306a36Sopenharmony_ci MPT_ADAPTER *ioc; 306662306a36Sopenharmony_ci struct sas_phy *phy; 306762306a36Sopenharmony_ci struct sas_port *port; 306862306a36Sopenharmony_ci int error = 0; 306962306a36Sopenharmony_ci VirtTarget *vtarget; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci if (!dev) { 307262306a36Sopenharmony_ci error = -ENODEV; 307362306a36Sopenharmony_ci goto out; 307462306a36Sopenharmony_ci } 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci if (!phy_info->phy) { 307762306a36Sopenharmony_ci phy = sas_phy_alloc(dev, index); 307862306a36Sopenharmony_ci if (!phy) { 307962306a36Sopenharmony_ci error = -ENOMEM; 308062306a36Sopenharmony_ci goto out; 308162306a36Sopenharmony_ci } 308262306a36Sopenharmony_ci } else 308362306a36Sopenharmony_ci phy = phy_info->phy; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci mptsas_parse_device_info(&phy->identify, &phy_info->identify); 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci /* 308862306a36Sopenharmony_ci * Set Negotiated link rate. 308962306a36Sopenharmony_ci */ 309062306a36Sopenharmony_ci switch (phy_info->negotiated_link_rate) { 309162306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: 309262306a36Sopenharmony_ci phy->negotiated_linkrate = SAS_PHY_DISABLED; 309362306a36Sopenharmony_ci break; 309462306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: 309562306a36Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; 309662306a36Sopenharmony_ci break; 309762306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_1_5: 309862306a36Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; 309962306a36Sopenharmony_ci break; 310062306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_3_0: 310162306a36Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; 310262306a36Sopenharmony_ci break; 310362306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_6_0: 310462306a36Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; 310562306a36Sopenharmony_ci break; 310662306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: 310762306a36Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_UNKNOWN: 310862306a36Sopenharmony_ci default: 310962306a36Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 311062306a36Sopenharmony_ci break; 311162306a36Sopenharmony_ci } 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci /* 311462306a36Sopenharmony_ci * Set Max hardware link rate. 311562306a36Sopenharmony_ci */ 311662306a36Sopenharmony_ci switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { 311762306a36Sopenharmony_ci case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: 311862306a36Sopenharmony_ci phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 311962306a36Sopenharmony_ci break; 312062306a36Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: 312162306a36Sopenharmony_ci phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; 312262306a36Sopenharmony_ci break; 312362306a36Sopenharmony_ci default: 312462306a36Sopenharmony_ci break; 312562306a36Sopenharmony_ci } 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci /* 312862306a36Sopenharmony_ci * Set Max programmed link rate. 312962306a36Sopenharmony_ci */ 313062306a36Sopenharmony_ci switch (phy_info->programmed_link_rate & 313162306a36Sopenharmony_ci MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { 313262306a36Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: 313362306a36Sopenharmony_ci phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; 313462306a36Sopenharmony_ci break; 313562306a36Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: 313662306a36Sopenharmony_ci phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; 313762306a36Sopenharmony_ci break; 313862306a36Sopenharmony_ci default: 313962306a36Sopenharmony_ci break; 314062306a36Sopenharmony_ci } 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci /* 314362306a36Sopenharmony_ci * Set Min hardware link rate. 314462306a36Sopenharmony_ci */ 314562306a36Sopenharmony_ci switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { 314662306a36Sopenharmony_ci case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: 314762306a36Sopenharmony_ci phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 314862306a36Sopenharmony_ci break; 314962306a36Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: 315062306a36Sopenharmony_ci phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; 315162306a36Sopenharmony_ci break; 315262306a36Sopenharmony_ci default: 315362306a36Sopenharmony_ci break; 315462306a36Sopenharmony_ci } 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci /* 315762306a36Sopenharmony_ci * Set Min programmed link rate. 315862306a36Sopenharmony_ci */ 315962306a36Sopenharmony_ci switch (phy_info->programmed_link_rate & 316062306a36Sopenharmony_ci MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { 316162306a36Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: 316262306a36Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; 316362306a36Sopenharmony_ci break; 316462306a36Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: 316562306a36Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; 316662306a36Sopenharmony_ci break; 316762306a36Sopenharmony_ci default: 316862306a36Sopenharmony_ci break; 316962306a36Sopenharmony_ci } 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci if (!phy_info->phy) { 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci error = sas_phy_add(phy); 317462306a36Sopenharmony_ci if (error) { 317562306a36Sopenharmony_ci sas_phy_free(phy); 317662306a36Sopenharmony_ci goto out; 317762306a36Sopenharmony_ci } 317862306a36Sopenharmony_ci phy_info->phy = phy; 317962306a36Sopenharmony_ci } 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci if (!phy_info->attached.handle || 318262306a36Sopenharmony_ci !phy_info->port_details) 318362306a36Sopenharmony_ci goto out; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci port = mptsas_get_port(phy_info); 318662306a36Sopenharmony_ci ioc = phy_to_ioc(phy_info->phy); 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci if (phy_info->sas_port_add_phy) { 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci if (!port) { 319162306a36Sopenharmony_ci port = sas_port_alloc_num(dev); 319262306a36Sopenharmony_ci if (!port) { 319362306a36Sopenharmony_ci error = -ENOMEM; 319462306a36Sopenharmony_ci goto out; 319562306a36Sopenharmony_ci } 319662306a36Sopenharmony_ci error = sas_port_add(port); 319762306a36Sopenharmony_ci if (error) { 319862306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 319962306a36Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 320062306a36Sopenharmony_ci __func__, __LINE__)); 320162306a36Sopenharmony_ci goto out; 320262306a36Sopenharmony_ci } 320362306a36Sopenharmony_ci mptsas_set_port(ioc, phy_info, port); 320462306a36Sopenharmony_ci devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, 320562306a36Sopenharmony_ci MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", 320662306a36Sopenharmony_ci ioc->name, port->port_identifier, 320762306a36Sopenharmony_ci (unsigned long long)phy_info-> 320862306a36Sopenharmony_ci attached.sas_address)); 320962306a36Sopenharmony_ci } 321062306a36Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 321162306a36Sopenharmony_ci "sas_port_add_phy: phy_id=%d\n", 321262306a36Sopenharmony_ci ioc->name, phy_info->phy_id)); 321362306a36Sopenharmony_ci sas_port_add_phy(port, phy_info->phy); 321462306a36Sopenharmony_ci phy_info->sas_port_add_phy = 0; 321562306a36Sopenharmony_ci devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, 321662306a36Sopenharmony_ci MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, 321762306a36Sopenharmony_ci phy_info->phy_id, phy_info->phy)); 321862306a36Sopenharmony_ci } 321962306a36Sopenharmony_ci if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci struct sas_rphy *rphy; 322262306a36Sopenharmony_ci struct device *parent; 322362306a36Sopenharmony_ci struct sas_identify identify; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci parent = dev->parent->parent; 322662306a36Sopenharmony_ci /* 322762306a36Sopenharmony_ci * Let the hotplug_work thread handle processing 322862306a36Sopenharmony_ci * the adding/removing of devices that occur 322962306a36Sopenharmony_ci * after start of day. 323062306a36Sopenharmony_ci */ 323162306a36Sopenharmony_ci if (mptsas_is_end_device(&phy_info->attached) && 323262306a36Sopenharmony_ci phy_info->attached.handle_parent) { 323362306a36Sopenharmony_ci goto out; 323462306a36Sopenharmony_ci } 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci mptsas_parse_device_info(&identify, &phy_info->attached); 323762306a36Sopenharmony_ci if (scsi_is_host_device(parent)) { 323862306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 323962306a36Sopenharmony_ci int i; 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci port_info = ioc->hba_port_info; 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 324462306a36Sopenharmony_ci if (port_info->phy_info[i].identify.sas_address == 324562306a36Sopenharmony_ci identify.sas_address) { 324662306a36Sopenharmony_ci sas_port_mark_backlink(port); 324762306a36Sopenharmony_ci goto out; 324862306a36Sopenharmony_ci } 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_ci } else if (scsi_is_sas_rphy(parent)) { 325162306a36Sopenharmony_ci struct sas_rphy *parent_rphy = dev_to_rphy(parent); 325262306a36Sopenharmony_ci if (identify.sas_address == 325362306a36Sopenharmony_ci parent_rphy->identify.sas_address) { 325462306a36Sopenharmony_ci sas_port_mark_backlink(port); 325562306a36Sopenharmony_ci goto out; 325662306a36Sopenharmony_ci } 325762306a36Sopenharmony_ci } 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci switch (identify.device_type) { 326062306a36Sopenharmony_ci case SAS_END_DEVICE: 326162306a36Sopenharmony_ci rphy = sas_end_device_alloc(port); 326262306a36Sopenharmony_ci break; 326362306a36Sopenharmony_ci case SAS_EDGE_EXPANDER_DEVICE: 326462306a36Sopenharmony_ci case SAS_FANOUT_EXPANDER_DEVICE: 326562306a36Sopenharmony_ci rphy = sas_expander_alloc(port, identify.device_type); 326662306a36Sopenharmony_ci break; 326762306a36Sopenharmony_ci default: 326862306a36Sopenharmony_ci rphy = NULL; 326962306a36Sopenharmony_ci break; 327062306a36Sopenharmony_ci } 327162306a36Sopenharmony_ci if (!rphy) { 327262306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 327362306a36Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 327462306a36Sopenharmony_ci __func__, __LINE__)); 327562306a36Sopenharmony_ci goto out; 327662306a36Sopenharmony_ci } 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci rphy->identify = identify; 327962306a36Sopenharmony_ci error = sas_rphy_add(rphy); 328062306a36Sopenharmony_ci if (error) { 328162306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 328262306a36Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 328362306a36Sopenharmony_ci __func__, __LINE__)); 328462306a36Sopenharmony_ci sas_rphy_free(rphy); 328562306a36Sopenharmony_ci goto out; 328662306a36Sopenharmony_ci } 328762306a36Sopenharmony_ci mptsas_set_rphy(ioc, phy_info, rphy); 328862306a36Sopenharmony_ci if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || 328962306a36Sopenharmony_ci identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) 329062306a36Sopenharmony_ci mptsas_exp_repmanufacture_info(ioc, 329162306a36Sopenharmony_ci identify.sas_address, 329262306a36Sopenharmony_ci rphy_to_expander_device(rphy)); 329362306a36Sopenharmony_ci } 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci /* If the device exists, verify it wasn't previously flagged 329662306a36Sopenharmony_ci as a missing device. If so, clear it */ 329762306a36Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, 329862306a36Sopenharmony_ci phy_info->attached.channel, 329962306a36Sopenharmony_ci phy_info->attached.id); 330062306a36Sopenharmony_ci if (vtarget && vtarget->inDMD) { 330162306a36Sopenharmony_ci printk(KERN_INFO "Device returned, unsetting inDMD\n"); 330262306a36Sopenharmony_ci vtarget->inDMD = 0; 330362306a36Sopenharmony_ci } 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci out: 330662306a36Sopenharmony_ci return error; 330762306a36Sopenharmony_ci} 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_cistatic int 331062306a36Sopenharmony_cimptsas_probe_hba_phys(MPT_ADAPTER *ioc) 331162306a36Sopenharmony_ci{ 331262306a36Sopenharmony_ci struct mptsas_portinfo *port_info, *hba; 331362306a36Sopenharmony_ci int error = -ENOMEM, i; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 331662306a36Sopenharmony_ci if (! hba) 331762306a36Sopenharmony_ci goto out; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci error = mptsas_sas_io_unit_pg0(ioc, hba); 332062306a36Sopenharmony_ci if (error) 332162306a36Sopenharmony_ci goto out_free_port_info; 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci mptsas_sas_io_unit_pg1(ioc); 332462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 332562306a36Sopenharmony_ci port_info = ioc->hba_port_info; 332662306a36Sopenharmony_ci if (!port_info) { 332762306a36Sopenharmony_ci ioc->hba_port_info = port_info = hba; 332862306a36Sopenharmony_ci ioc->hba_port_num_phy = port_info->num_phys; 332962306a36Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 333062306a36Sopenharmony_ci } else { 333162306a36Sopenharmony_ci for (i = 0; i < hba->num_phys; i++) { 333262306a36Sopenharmony_ci port_info->phy_info[i].negotiated_link_rate = 333362306a36Sopenharmony_ci hba->phy_info[i].negotiated_link_rate; 333462306a36Sopenharmony_ci port_info->phy_info[i].handle = 333562306a36Sopenharmony_ci hba->phy_info[i].handle; 333662306a36Sopenharmony_ci port_info->phy_info[i].port_id = 333762306a36Sopenharmony_ci hba->phy_info[i].port_id; 333862306a36Sopenharmony_ci } 333962306a36Sopenharmony_ci kfree(hba->phy_info); 334062306a36Sopenharmony_ci kfree(hba); 334162306a36Sopenharmony_ci hba = NULL; 334262306a36Sopenharmony_ci } 334362306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 334462306a36Sopenharmony_ci#if defined(CPQ_CIM) 334562306a36Sopenharmony_ci ioc->num_ports = port_info->num_phys; 334662306a36Sopenharmony_ci#endif 334762306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 334862306a36Sopenharmony_ci mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], 334962306a36Sopenharmony_ci (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << 335062306a36Sopenharmony_ci MPI_SAS_PHY_PGAD_FORM_SHIFT), i); 335162306a36Sopenharmony_ci port_info->phy_info[i].identify.handle = 335262306a36Sopenharmony_ci port_info->phy_info[i].handle; 335362306a36Sopenharmony_ci mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, 335462306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 335562306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 335662306a36Sopenharmony_ci port_info->phy_info[i].identify.handle); 335762306a36Sopenharmony_ci if (!ioc->hba_port_sas_addr) 335862306a36Sopenharmony_ci ioc->hba_port_sas_addr = 335962306a36Sopenharmony_ci port_info->phy_info[i].identify.sas_address; 336062306a36Sopenharmony_ci port_info->phy_info[i].identify.phy_id = 336162306a36Sopenharmony_ci port_info->phy_info[i].phy_id = i; 336262306a36Sopenharmony_ci if (port_info->phy_info[i].attached.handle) 336362306a36Sopenharmony_ci mptsas_sas_device_pg0(ioc, 336462306a36Sopenharmony_ci &port_info->phy_info[i].attached, 336562306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 336662306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 336762306a36Sopenharmony_ci port_info->phy_info[i].attached.handle); 336862306a36Sopenharmony_ci } 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci mptsas_setup_wide_ports(ioc, port_info); 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) 337362306a36Sopenharmony_ci mptsas_probe_one_phy(&ioc->sh->shost_gendev, 337462306a36Sopenharmony_ci &port_info->phy_info[i], ioc->sas_index, 1); 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci return 0; 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci out_free_port_info: 337962306a36Sopenharmony_ci kfree(hba); 338062306a36Sopenharmony_ci out: 338162306a36Sopenharmony_ci return error; 338262306a36Sopenharmony_ci} 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_cistatic void 338562306a36Sopenharmony_cimptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) 338662306a36Sopenharmony_ci{ 338762306a36Sopenharmony_ci struct mptsas_portinfo *parent; 338862306a36Sopenharmony_ci struct device *parent_dev; 338962306a36Sopenharmony_ci struct sas_rphy *rphy; 339062306a36Sopenharmony_ci int i; 339162306a36Sopenharmony_ci u64 sas_address; /* expander sas address */ 339262306a36Sopenharmony_ci u32 handle; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci handle = port_info->phy_info[0].handle; 339562306a36Sopenharmony_ci sas_address = port_info->phy_info[0].identify.sas_address; 339662306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 339762306a36Sopenharmony_ci mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], 339862306a36Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << 339962306a36Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci mptsas_sas_device_pg0(ioc, 340262306a36Sopenharmony_ci &port_info->phy_info[i].identify, 340362306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 340462306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 340562306a36Sopenharmony_ci port_info->phy_info[i].identify.handle); 340662306a36Sopenharmony_ci port_info->phy_info[i].identify.phy_id = 340762306a36Sopenharmony_ci port_info->phy_info[i].phy_id; 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci if (port_info->phy_info[i].attached.handle) { 341062306a36Sopenharmony_ci mptsas_sas_device_pg0(ioc, 341162306a36Sopenharmony_ci &port_info->phy_info[i].attached, 341262306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 341362306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 341462306a36Sopenharmony_ci port_info->phy_info[i].attached.handle); 341562306a36Sopenharmony_ci port_info->phy_info[i].attached.phy_id = 341662306a36Sopenharmony_ci port_info->phy_info[i].phy_id; 341762306a36Sopenharmony_ci } 341862306a36Sopenharmony_ci } 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 342162306a36Sopenharmony_ci parent = mptsas_find_portinfo_by_handle(ioc, 342262306a36Sopenharmony_ci port_info->phy_info[0].identify.handle_parent); 342362306a36Sopenharmony_ci if (!parent) { 342462306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 342562306a36Sopenharmony_ci return; 342662306a36Sopenharmony_ci } 342762306a36Sopenharmony_ci for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; 342862306a36Sopenharmony_ci i++) { 342962306a36Sopenharmony_ci if (parent->phy_info[i].attached.sas_address == sas_address) { 343062306a36Sopenharmony_ci rphy = mptsas_get_rphy(&parent->phy_info[i]); 343162306a36Sopenharmony_ci parent_dev = &rphy->dev; 343262306a36Sopenharmony_ci } 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci mptsas_setup_wide_ports(ioc, port_info); 343762306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) 343862306a36Sopenharmony_ci mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], 343962306a36Sopenharmony_ci ioc->sas_index, 0); 344062306a36Sopenharmony_ci} 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_cistatic void 344362306a36Sopenharmony_cimptsas_expander_event_add(MPT_ADAPTER *ioc, 344462306a36Sopenharmony_ci MpiEventDataSasExpanderStatusChange_t *expander_data) 344562306a36Sopenharmony_ci{ 344662306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 344762306a36Sopenharmony_ci int i; 344862306a36Sopenharmony_ci __le64 sas_address; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 345162306a36Sopenharmony_ci BUG_ON(!port_info); 345262306a36Sopenharmony_ci port_info->num_phys = (expander_data->NumPhys) ? 345362306a36Sopenharmony_ci expander_data->NumPhys : 1; 345462306a36Sopenharmony_ci port_info->phy_info = kcalloc(port_info->num_phys, 345562306a36Sopenharmony_ci sizeof(struct mptsas_phyinfo), GFP_KERNEL); 345662306a36Sopenharmony_ci BUG_ON(!port_info->phy_info); 345762306a36Sopenharmony_ci memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); 345862306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 345962306a36Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 346062306a36Sopenharmony_ci port_info->phy_info[i].handle = 346162306a36Sopenharmony_ci le16_to_cpu(expander_data->DevHandle); 346262306a36Sopenharmony_ci port_info->phy_info[i].identify.sas_address = 346362306a36Sopenharmony_ci le64_to_cpu(sas_address); 346462306a36Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 346562306a36Sopenharmony_ci le16_to_cpu(expander_data->ParentDevHandle); 346662306a36Sopenharmony_ci } 346762306a36Sopenharmony_ci 346862306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 346962306a36Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 347062306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " 347362306a36Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 347462306a36Sopenharmony_ci (unsigned long long)sas_address); 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 347762306a36Sopenharmony_ci} 347862306a36Sopenharmony_ci 347962306a36Sopenharmony_ci/** 348062306a36Sopenharmony_ci * mptsas_delete_expander_siblings - remove siblings attached to expander 348162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 348262306a36Sopenharmony_ci * @parent: the parent port_info object 348362306a36Sopenharmony_ci * @expander: the expander port_info object 348462306a36Sopenharmony_ci **/ 348562306a36Sopenharmony_cistatic void 348662306a36Sopenharmony_cimptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo 348762306a36Sopenharmony_ci *parent, struct mptsas_portinfo *expander) 348862306a36Sopenharmony_ci{ 348962306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 349062306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 349162306a36Sopenharmony_ci struct sas_rphy *rphy; 349262306a36Sopenharmony_ci int i; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci phy_info = expander->phy_info; 349562306a36Sopenharmony_ci for (i = 0; i < expander->num_phys; i++, phy_info++) { 349662306a36Sopenharmony_ci rphy = mptsas_get_rphy(phy_info); 349762306a36Sopenharmony_ci if (!rphy) 349862306a36Sopenharmony_ci continue; 349962306a36Sopenharmony_ci if (rphy->identify.device_type == SAS_END_DEVICE) 350062306a36Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 350162306a36Sopenharmony_ci } 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci phy_info = expander->phy_info; 350462306a36Sopenharmony_ci for (i = 0; i < expander->num_phys; i++, phy_info++) { 350562306a36Sopenharmony_ci rphy = mptsas_get_rphy(phy_info); 350662306a36Sopenharmony_ci if (!rphy) 350762306a36Sopenharmony_ci continue; 350862306a36Sopenharmony_ci if (rphy->identify.device_type == 350962306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || 351062306a36Sopenharmony_ci rphy->identify.device_type == 351162306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { 351262306a36Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, 351362306a36Sopenharmony_ci rphy->identify.sas_address); 351462306a36Sopenharmony_ci if (!port_info) 351562306a36Sopenharmony_ci continue; 351662306a36Sopenharmony_ci if (port_info == parent) /* backlink rphy */ 351762306a36Sopenharmony_ci continue; 351862306a36Sopenharmony_ci /* 351962306a36Sopenharmony_ci Delete this expander even if the expdevpage is exists 352062306a36Sopenharmony_ci because the parent expander is already deleted 352162306a36Sopenharmony_ci */ 352262306a36Sopenharmony_ci mptsas_expander_delete(ioc, port_info, 1); 352362306a36Sopenharmony_ci } 352462306a36Sopenharmony_ci } 352562306a36Sopenharmony_ci} 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci/** 352962306a36Sopenharmony_ci * mptsas_expander_delete - remove this expander 353062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 353162306a36Sopenharmony_ci * @port_info: expander port_info struct 353262306a36Sopenharmony_ci * @force: Flag to forcefully delete the expander 353362306a36Sopenharmony_ci * 353462306a36Sopenharmony_ci **/ 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_cistatic void mptsas_expander_delete(MPT_ADAPTER *ioc, 353762306a36Sopenharmony_ci struct mptsas_portinfo *port_info, u8 force) 353862306a36Sopenharmony_ci{ 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci struct mptsas_portinfo *parent; 354162306a36Sopenharmony_ci int i; 354262306a36Sopenharmony_ci u64 expander_sas_address; 354362306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 354462306a36Sopenharmony_ci struct mptsas_portinfo buffer; 354562306a36Sopenharmony_ci struct mptsas_portinfo_details *port_details; 354662306a36Sopenharmony_ci struct sas_port *port; 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci if (!port_info) 354962306a36Sopenharmony_ci return; 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci /* see if expander is still there before deleting */ 355262306a36Sopenharmony_ci mptsas_sas_expander_pg0(ioc, &buffer, 355362306a36Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << 355462306a36Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), 355562306a36Sopenharmony_ci port_info->phy_info[0].identify.handle); 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci if (buffer.num_phys) { 355862306a36Sopenharmony_ci kfree(buffer.phy_info); 355962306a36Sopenharmony_ci if (!force) 356062306a36Sopenharmony_ci return; 356162306a36Sopenharmony_ci } 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci /* 356562306a36Sopenharmony_ci * Obtain the port_info instance to the parent port 356662306a36Sopenharmony_ci */ 356762306a36Sopenharmony_ci port_details = NULL; 356862306a36Sopenharmony_ci expander_sas_address = 356962306a36Sopenharmony_ci port_info->phy_info[0].identify.sas_address; 357062306a36Sopenharmony_ci parent = mptsas_find_portinfo_by_handle(ioc, 357162306a36Sopenharmony_ci port_info->phy_info[0].identify.handle_parent); 357262306a36Sopenharmony_ci mptsas_delete_expander_siblings(ioc, parent, port_info); 357362306a36Sopenharmony_ci if (!parent) 357462306a36Sopenharmony_ci goto out; 357562306a36Sopenharmony_ci 357662306a36Sopenharmony_ci /* 357762306a36Sopenharmony_ci * Delete rphys in the parent that point 357862306a36Sopenharmony_ci * to this expander. 357962306a36Sopenharmony_ci */ 358062306a36Sopenharmony_ci phy_info = parent->phy_info; 358162306a36Sopenharmony_ci port = NULL; 358262306a36Sopenharmony_ci for (i = 0; i < parent->num_phys; i++, phy_info++) { 358362306a36Sopenharmony_ci if (!phy_info->phy) 358462306a36Sopenharmony_ci continue; 358562306a36Sopenharmony_ci if (phy_info->attached.sas_address != 358662306a36Sopenharmony_ci expander_sas_address) 358762306a36Sopenharmony_ci continue; 358862306a36Sopenharmony_ci if (!port) { 358962306a36Sopenharmony_ci port = mptsas_get_port(phy_info); 359062306a36Sopenharmony_ci port_details = phy_info->port_details; 359162306a36Sopenharmony_ci } 359262306a36Sopenharmony_ci dev_printk(KERN_DEBUG, &phy_info->phy->dev, 359362306a36Sopenharmony_ci MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, 359462306a36Sopenharmony_ci phy_info->phy_id, phy_info->phy); 359562306a36Sopenharmony_ci sas_port_delete_phy(port, phy_info->phy); 359662306a36Sopenharmony_ci } 359762306a36Sopenharmony_ci if (port) { 359862306a36Sopenharmony_ci dev_printk(KERN_DEBUG, &port->dev, 359962306a36Sopenharmony_ci MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", 360062306a36Sopenharmony_ci ioc->name, port->port_identifier, 360162306a36Sopenharmony_ci (unsigned long long)expander_sas_address); 360262306a36Sopenharmony_ci sas_port_delete(port); 360362306a36Sopenharmony_ci mptsas_port_delete(ioc, port_details); 360462306a36Sopenharmony_ci } 360562306a36Sopenharmony_ci out: 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " 360862306a36Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 360962306a36Sopenharmony_ci (unsigned long long)expander_sas_address); 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci /* 361262306a36Sopenharmony_ci * free link 361362306a36Sopenharmony_ci */ 361462306a36Sopenharmony_ci list_del(&port_info->list); 361562306a36Sopenharmony_ci kfree(port_info->phy_info); 361662306a36Sopenharmony_ci kfree(port_info); 361762306a36Sopenharmony_ci} 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci/** 362162306a36Sopenharmony_ci * mptsas_send_expander_event - expanders events 362262306a36Sopenharmony_ci * @fw_event: event data 362362306a36Sopenharmony_ci * 362462306a36Sopenharmony_ci * 362562306a36Sopenharmony_ci * This function handles adding, removing, and refreshing 362662306a36Sopenharmony_ci * device handles within the expander objects. 362762306a36Sopenharmony_ci */ 362862306a36Sopenharmony_cistatic void 362962306a36Sopenharmony_cimptsas_send_expander_event(struct fw_event_work *fw_event) 363062306a36Sopenharmony_ci{ 363162306a36Sopenharmony_ci MPT_ADAPTER *ioc; 363262306a36Sopenharmony_ci MpiEventDataSasExpanderStatusChange_t *expander_data; 363362306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 363462306a36Sopenharmony_ci __le64 sas_address; 363562306a36Sopenharmony_ci int i; 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci ioc = fw_event->ioc; 363862306a36Sopenharmony_ci expander_data = (MpiEventDataSasExpanderStatusChange_t *) 363962306a36Sopenharmony_ci fw_event->event_data; 364062306a36Sopenharmony_ci memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); 364162306a36Sopenharmony_ci sas_address = le64_to_cpu(sas_address); 364262306a36Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { 364562306a36Sopenharmony_ci if (port_info) { 364662306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 364762306a36Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 364862306a36Sopenharmony_ci port_info->phy_info[i].handle = 364962306a36Sopenharmony_ci le16_to_cpu(expander_data->DevHandle); 365062306a36Sopenharmony_ci port_info->phy_info[i].identify.sas_address = 365162306a36Sopenharmony_ci le64_to_cpu(sas_address); 365262306a36Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 365362306a36Sopenharmony_ci le16_to_cpu(expander_data->ParentDevHandle); 365462306a36Sopenharmony_ci } 365562306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 365662306a36Sopenharmony_ci } else if (!port_info && expander_data->NumPhys) 365762306a36Sopenharmony_ci mptsas_expander_event_add(ioc, expander_data); 365862306a36Sopenharmony_ci } else if (expander_data->ReasonCode == 365962306a36Sopenharmony_ci MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) 366062306a36Sopenharmony_ci mptsas_expander_delete(ioc, port_info, 0); 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 366362306a36Sopenharmony_ci} 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci/** 366762306a36Sopenharmony_ci * mptsas_expander_add - adds a newly discovered expander 366862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 366962306a36Sopenharmony_ci * @handle: device handle 367062306a36Sopenharmony_ci * 367162306a36Sopenharmony_ci */ 367262306a36Sopenharmony_cistatic struct mptsas_portinfo * 367362306a36Sopenharmony_cimptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) 367462306a36Sopenharmony_ci{ 367562306a36Sopenharmony_ci struct mptsas_portinfo buffer, *port_info; 367662306a36Sopenharmony_ci int i; 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ci if ((mptsas_sas_expander_pg0(ioc, &buffer, 367962306a36Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << 368062306a36Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) 368162306a36Sopenharmony_ci return NULL; 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 368462306a36Sopenharmony_ci if (!port_info) { 368562306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 368662306a36Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 368762306a36Sopenharmony_ci __func__, __LINE__)); 368862306a36Sopenharmony_ci return NULL; 368962306a36Sopenharmony_ci } 369062306a36Sopenharmony_ci port_info->num_phys = buffer.num_phys; 369162306a36Sopenharmony_ci port_info->phy_info = buffer.phy_info; 369262306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 369362306a36Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 369462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 369562306a36Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 369662306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 369762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " 369862306a36Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 369962306a36Sopenharmony_ci (unsigned long long)buffer.phy_info[0].identify.sas_address); 370062306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 370162306a36Sopenharmony_ci return port_info; 370262306a36Sopenharmony_ci} 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_cistatic void 370562306a36Sopenharmony_cimptsas_send_link_status_event(struct fw_event_work *fw_event) 370662306a36Sopenharmony_ci{ 370762306a36Sopenharmony_ci MPT_ADAPTER *ioc; 370862306a36Sopenharmony_ci MpiEventDataSasPhyLinkStatus_t *link_data; 370962306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 371062306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 371162306a36Sopenharmony_ci __le64 sas_address; 371262306a36Sopenharmony_ci u8 phy_num; 371362306a36Sopenharmony_ci u8 link_rate; 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci ioc = fw_event->ioc; 371662306a36Sopenharmony_ci link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); 371962306a36Sopenharmony_ci sas_address = le64_to_cpu(sas_address); 372062306a36Sopenharmony_ci link_rate = link_data->LinkRates >> 4; 372162306a36Sopenharmony_ci phy_num = link_data->PhyNum; 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); 372462306a36Sopenharmony_ci if (port_info) { 372562306a36Sopenharmony_ci phy_info = &port_info->phy_info[phy_num]; 372662306a36Sopenharmony_ci if (phy_info) 372762306a36Sopenharmony_ci phy_info->negotiated_link_rate = link_rate; 372862306a36Sopenharmony_ci } 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || 373162306a36Sopenharmony_ci link_rate == MPI_SAS_IOUNIT0_RATE_3_0 || 373262306a36Sopenharmony_ci link_rate == MPI_SAS_IOUNIT0_RATE_6_0) { 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci if (!port_info) { 373562306a36Sopenharmony_ci if (ioc->old_sas_discovery_protocal) { 373662306a36Sopenharmony_ci port_info = mptsas_expander_add(ioc, 373762306a36Sopenharmony_ci le16_to_cpu(link_data->DevHandle)); 373862306a36Sopenharmony_ci if (port_info) 373962306a36Sopenharmony_ci goto out; 374062306a36Sopenharmony_ci } 374162306a36Sopenharmony_ci goto out; 374262306a36Sopenharmony_ci } 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci if (port_info == ioc->hba_port_info) 374562306a36Sopenharmony_ci mptsas_probe_hba_phys(ioc); 374662306a36Sopenharmony_ci else 374762306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 374862306a36Sopenharmony_ci } else if (phy_info && phy_info->phy) { 374962306a36Sopenharmony_ci if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) 375062306a36Sopenharmony_ci phy_info->phy->negotiated_linkrate = 375162306a36Sopenharmony_ci SAS_PHY_DISABLED; 375262306a36Sopenharmony_ci else if (link_rate == 375362306a36Sopenharmony_ci MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) 375462306a36Sopenharmony_ci phy_info->phy->negotiated_linkrate = 375562306a36Sopenharmony_ci SAS_LINK_RATE_FAILED; 375662306a36Sopenharmony_ci else { 375762306a36Sopenharmony_ci phy_info->phy->negotiated_linkrate = 375862306a36Sopenharmony_ci SAS_LINK_RATE_UNKNOWN; 375962306a36Sopenharmony_ci if (ioc->device_missing_delay && 376062306a36Sopenharmony_ci mptsas_is_end_device(&phy_info->attached)) { 376162306a36Sopenharmony_ci struct scsi_device *sdev; 376262306a36Sopenharmony_ci VirtDevice *vdevice; 376362306a36Sopenharmony_ci u8 channel, id; 376462306a36Sopenharmony_ci id = phy_info->attached.id; 376562306a36Sopenharmony_ci channel = phy_info->attached.channel; 376662306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 376762306a36Sopenharmony_ci "Link down for fw_id %d:fw_channel %d\n", 376862306a36Sopenharmony_ci ioc->name, phy_info->attached.id, 376962306a36Sopenharmony_ci phy_info->attached.channel)); 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 377262306a36Sopenharmony_ci vdevice = sdev->hostdata; 377362306a36Sopenharmony_ci if ((vdevice == NULL) || 377462306a36Sopenharmony_ci (vdevice->vtarget == NULL)) 377562306a36Sopenharmony_ci continue; 377662306a36Sopenharmony_ci if ((vdevice->vtarget->tflags & 377762306a36Sopenharmony_ci MPT_TARGET_FLAGS_RAID_COMPONENT || 377862306a36Sopenharmony_ci vdevice->vtarget->raidVolume)) 377962306a36Sopenharmony_ci continue; 378062306a36Sopenharmony_ci if (vdevice->vtarget->id == id && 378162306a36Sopenharmony_ci vdevice->vtarget->channel == 378262306a36Sopenharmony_ci channel) 378362306a36Sopenharmony_ci devtprintk(ioc, 378462306a36Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT 378562306a36Sopenharmony_ci "SDEV OUTSTANDING CMDS" 378662306a36Sopenharmony_ci "%d\n", ioc->name, 378762306a36Sopenharmony_ci scsi_device_busy(sdev))); 378862306a36Sopenharmony_ci } 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci } 379162306a36Sopenharmony_ci } 379262306a36Sopenharmony_ci } 379362306a36Sopenharmony_ci out: 379462306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 379562306a36Sopenharmony_ci} 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_cistatic void 379862306a36Sopenharmony_cimptsas_not_responding_devices(MPT_ADAPTER *ioc) 379962306a36Sopenharmony_ci{ 380062306a36Sopenharmony_ci struct mptsas_portinfo buffer, *port_info; 380162306a36Sopenharmony_ci struct mptsas_device_info *sas_info; 380262306a36Sopenharmony_ci struct mptsas_devinfo sas_device; 380362306a36Sopenharmony_ci u32 handle; 380462306a36Sopenharmony_ci VirtTarget *vtarget = NULL; 380562306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 380662306a36Sopenharmony_ci u8 found_expander; 380762306a36Sopenharmony_ci int retval, retry_count; 380862306a36Sopenharmony_ci unsigned long flags; 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci mpt_findImVolumes(ioc); 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 381362306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 381462306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT 381562306a36Sopenharmony_ci "%s: exiting due to a parallel reset \n", ioc->name, 381662306a36Sopenharmony_ci __func__)); 381762306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 381862306a36Sopenharmony_ci return; 381962306a36Sopenharmony_ci } 382062306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci /* devices, logical volumes */ 382362306a36Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 382462306a36Sopenharmony_ci redo_device_scan: 382562306a36Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { 382662306a36Sopenharmony_ci if (sas_info->is_cached) 382762306a36Sopenharmony_ci continue; 382862306a36Sopenharmony_ci if (!sas_info->is_logical_volume) { 382962306a36Sopenharmony_ci sas_device.handle = 0; 383062306a36Sopenharmony_ci retry_count = 0; 383162306a36Sopenharmony_ciretry_page: 383262306a36Sopenharmony_ci retval = mptsas_sas_device_pg0(ioc, &sas_device, 383362306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID 383462306a36Sopenharmony_ci << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 383562306a36Sopenharmony_ci (sas_info->fw.channel << 8) + 383662306a36Sopenharmony_ci sas_info->fw.id); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci if (sas_device.handle) 383962306a36Sopenharmony_ci continue; 384062306a36Sopenharmony_ci if (retval == -EBUSY) { 384162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 384262306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 384362306a36Sopenharmony_ci dfailprintk(ioc, 384462306a36Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT 384562306a36Sopenharmony_ci "%s: exiting due to reset\n", 384662306a36Sopenharmony_ci ioc->name, __func__)); 384762306a36Sopenharmony_ci spin_unlock_irqrestore 384862306a36Sopenharmony_ci (&ioc->taskmgmt_lock, flags); 384962306a36Sopenharmony_ci mutex_unlock(&ioc-> 385062306a36Sopenharmony_ci sas_device_info_mutex); 385162306a36Sopenharmony_ci return; 385262306a36Sopenharmony_ci } 385362306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, 385462306a36Sopenharmony_ci flags); 385562306a36Sopenharmony_ci } 385662306a36Sopenharmony_ci 385762306a36Sopenharmony_ci if (retval && (retval != -ENODEV)) { 385862306a36Sopenharmony_ci if (retry_count < 10) { 385962306a36Sopenharmony_ci retry_count++; 386062306a36Sopenharmony_ci goto retry_page; 386162306a36Sopenharmony_ci } else { 386262306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 386362306a36Sopenharmony_ci "%s: Config page retry exceeded retry " 386462306a36Sopenharmony_ci "count deleting device 0x%llx\n", 386562306a36Sopenharmony_ci ioc->name, __func__, 386662306a36Sopenharmony_ci sas_info->sas_address)); 386762306a36Sopenharmony_ci } 386862306a36Sopenharmony_ci } 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci /* delete device */ 387162306a36Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, 387262306a36Sopenharmony_ci sas_info->fw.channel, sas_info->fw.id); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci if (vtarget) 387562306a36Sopenharmony_ci vtarget->deleted = 1; 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 387862306a36Sopenharmony_ci sas_info->sas_address); 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 388162306a36Sopenharmony_ci goto redo_device_scan; 388262306a36Sopenharmony_ci } else 388362306a36Sopenharmony_ci mptsas_volume_delete(ioc, sas_info->fw.id); 388462306a36Sopenharmony_ci } 388562306a36Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci /* expanders */ 388862306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 388962306a36Sopenharmony_ci redo_expander_scan: 389062306a36Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) { 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci if (!(port_info->phy_info[0].identify.device_info & 389362306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SMP_TARGET)) 389462306a36Sopenharmony_ci continue; 389562306a36Sopenharmony_ci found_expander = 0; 389662306a36Sopenharmony_ci handle = 0xFFFF; 389762306a36Sopenharmony_ci while (!mptsas_sas_expander_pg0(ioc, &buffer, 389862306a36Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << 389962306a36Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && 390062306a36Sopenharmony_ci !found_expander) { 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci handle = buffer.phy_info[0].handle; 390362306a36Sopenharmony_ci if (buffer.phy_info[0].identify.sas_address == 390462306a36Sopenharmony_ci port_info->phy_info[0].identify.sas_address) { 390562306a36Sopenharmony_ci found_expander = 1; 390662306a36Sopenharmony_ci } 390762306a36Sopenharmony_ci kfree(buffer.phy_info); 390862306a36Sopenharmony_ci } 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci if (!found_expander) { 391162306a36Sopenharmony_ci mptsas_expander_delete(ioc, port_info, 0); 391262306a36Sopenharmony_ci goto redo_expander_scan; 391362306a36Sopenharmony_ci } 391462306a36Sopenharmony_ci } 391562306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 391662306a36Sopenharmony_ci} 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci/** 391962306a36Sopenharmony_ci * mptsas_probe_expanders - adding expanders 392062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 392162306a36Sopenharmony_ci * 392262306a36Sopenharmony_ci **/ 392362306a36Sopenharmony_cistatic void 392462306a36Sopenharmony_cimptsas_probe_expanders(MPT_ADAPTER *ioc) 392562306a36Sopenharmony_ci{ 392662306a36Sopenharmony_ci struct mptsas_portinfo buffer, *port_info; 392762306a36Sopenharmony_ci u32 handle; 392862306a36Sopenharmony_ci int i; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci handle = 0xFFFF; 393162306a36Sopenharmony_ci while (!mptsas_sas_expander_pg0(ioc, &buffer, 393262306a36Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << 393362306a36Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { 393462306a36Sopenharmony_ci 393562306a36Sopenharmony_ci handle = buffer.phy_info[0].handle; 393662306a36Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, 393762306a36Sopenharmony_ci buffer.phy_info[0].identify.sas_address); 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci if (port_info) { 394062306a36Sopenharmony_ci /* refreshing handles */ 394162306a36Sopenharmony_ci for (i = 0; i < buffer.num_phys; i++) { 394262306a36Sopenharmony_ci port_info->phy_info[i].handle = handle; 394362306a36Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 394462306a36Sopenharmony_ci buffer.phy_info[0].identify.handle_parent; 394562306a36Sopenharmony_ci } 394662306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 394762306a36Sopenharmony_ci kfree(buffer.phy_info); 394862306a36Sopenharmony_ci continue; 394962306a36Sopenharmony_ci } 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_ci port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 395262306a36Sopenharmony_ci if (!port_info) { 395362306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 395462306a36Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 395562306a36Sopenharmony_ci __func__, __LINE__)); 395662306a36Sopenharmony_ci return; 395762306a36Sopenharmony_ci } 395862306a36Sopenharmony_ci port_info->num_phys = buffer.num_phys; 395962306a36Sopenharmony_ci port_info->phy_info = buffer.phy_info; 396062306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 396162306a36Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 396262306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 396362306a36Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 396462306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 396562306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " 396662306a36Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 396762306a36Sopenharmony_ci (unsigned long long)buffer.phy_info[0].identify.sas_address); 396862306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 396962306a36Sopenharmony_ci } 397062306a36Sopenharmony_ci} 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_cistatic void 397362306a36Sopenharmony_cimptsas_probe_devices(MPT_ADAPTER *ioc) 397462306a36Sopenharmony_ci{ 397562306a36Sopenharmony_ci u16 handle; 397662306a36Sopenharmony_ci struct mptsas_devinfo sas_device; 397762306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci handle = 0xFFFF; 398062306a36Sopenharmony_ci while (!(mptsas_sas_device_pg0(ioc, &sas_device, 398162306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci handle = sas_device.handle; 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci if ((sas_device.device_info & 398662306a36Sopenharmony_ci (MPI_SAS_DEVICE_INFO_SSP_TARGET | 398762306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET | 398862306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) 398962306a36Sopenharmony_ci continue; 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci /* If there is no FW B_T mapping for this device then continue 399262306a36Sopenharmony_ci * */ 399362306a36Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 399462306a36Sopenharmony_ci || !(sas_device.flags & 399562306a36Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 399662306a36Sopenharmony_ci continue; 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); 399962306a36Sopenharmony_ci if (!phy_info) 400062306a36Sopenharmony_ci continue; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci if (mptsas_get_rphy(phy_info)) 400362306a36Sopenharmony_ci continue; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci mptsas_add_end_device(ioc, phy_info); 400662306a36Sopenharmony_ci } 400762306a36Sopenharmony_ci} 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_ci/** 401062306a36Sopenharmony_ci * mptsas_scan_sas_topology - scans new SAS topology 401162306a36Sopenharmony_ci * (part of probe or rescan) 401262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 401362306a36Sopenharmony_ci * 401462306a36Sopenharmony_ci **/ 401562306a36Sopenharmony_cistatic void 401662306a36Sopenharmony_cimptsas_scan_sas_topology(MPT_ADAPTER *ioc) 401762306a36Sopenharmony_ci{ 401862306a36Sopenharmony_ci struct scsi_device *sdev; 401962306a36Sopenharmony_ci int i; 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci mptsas_probe_hba_phys(ioc); 402262306a36Sopenharmony_ci mptsas_probe_expanders(ioc); 402362306a36Sopenharmony_ci mptsas_probe_devices(ioc); 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci /* 402662306a36Sopenharmony_ci Reporting RAID volumes. 402762306a36Sopenharmony_ci */ 402862306a36Sopenharmony_ci if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || 402962306a36Sopenharmony_ci !ioc->raid_data.pIocPg2->NumActiveVolumes) 403062306a36Sopenharmony_ci return; 403162306a36Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 403262306a36Sopenharmony_ci sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, 403362306a36Sopenharmony_ci ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); 403462306a36Sopenharmony_ci if (sdev) { 403562306a36Sopenharmony_ci scsi_device_put(sdev); 403662306a36Sopenharmony_ci continue; 403762306a36Sopenharmony_ci } 403862306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " 403962306a36Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, 404062306a36Sopenharmony_ci ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); 404162306a36Sopenharmony_ci scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, 404262306a36Sopenharmony_ci ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); 404362306a36Sopenharmony_ci } 404462306a36Sopenharmony_ci} 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_cistatic void 404862306a36Sopenharmony_cimptsas_handle_queue_full_event(struct fw_event_work *fw_event) 404962306a36Sopenharmony_ci{ 405062306a36Sopenharmony_ci MPT_ADAPTER *ioc; 405162306a36Sopenharmony_ci EventDataQueueFull_t *qfull_data; 405262306a36Sopenharmony_ci struct mptsas_device_info *sas_info; 405362306a36Sopenharmony_ci struct scsi_device *sdev; 405462306a36Sopenharmony_ci int depth; 405562306a36Sopenharmony_ci int id = -1; 405662306a36Sopenharmony_ci int channel = -1; 405762306a36Sopenharmony_ci int fw_id, fw_channel; 405862306a36Sopenharmony_ci u16 current_depth; 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci ioc = fw_event->ioc; 406262306a36Sopenharmony_ci qfull_data = (EventDataQueueFull_t *)fw_event->event_data; 406362306a36Sopenharmony_ci fw_id = qfull_data->TargetID; 406462306a36Sopenharmony_ci fw_channel = qfull_data->Bus; 406562306a36Sopenharmony_ci current_depth = le16_to_cpu(qfull_data->CurrentDepth); 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci /* if hidden raid component, look for the volume id */ 406862306a36Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 406962306a36Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { 407062306a36Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, 407162306a36Sopenharmony_ci list) { 407262306a36Sopenharmony_ci if (sas_info->is_cached || 407362306a36Sopenharmony_ci sas_info->is_logical_volume) 407462306a36Sopenharmony_ci continue; 407562306a36Sopenharmony_ci if (sas_info->is_hidden_raid_component && 407662306a36Sopenharmony_ci (sas_info->fw.channel == fw_channel && 407762306a36Sopenharmony_ci sas_info->fw.id == fw_id)) { 407862306a36Sopenharmony_ci id = sas_info->volume_id; 407962306a36Sopenharmony_ci channel = MPTSAS_RAID_CHANNEL; 408062306a36Sopenharmony_ci goto out; 408162306a36Sopenharmony_ci } 408262306a36Sopenharmony_ci } 408362306a36Sopenharmony_ci } else { 408462306a36Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, 408562306a36Sopenharmony_ci list) { 408662306a36Sopenharmony_ci if (sas_info->is_cached || 408762306a36Sopenharmony_ci sas_info->is_hidden_raid_component || 408862306a36Sopenharmony_ci sas_info->is_logical_volume) 408962306a36Sopenharmony_ci continue; 409062306a36Sopenharmony_ci if (sas_info->fw.channel == fw_channel && 409162306a36Sopenharmony_ci sas_info->fw.id == fw_id) { 409262306a36Sopenharmony_ci id = sas_info->os.id; 409362306a36Sopenharmony_ci channel = sas_info->os.channel; 409462306a36Sopenharmony_ci goto out; 409562306a36Sopenharmony_ci } 409662306a36Sopenharmony_ci } 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ci } 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci out: 410162306a36Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci if (id != -1) { 410462306a36Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 410562306a36Sopenharmony_ci if (sdev->id == id && sdev->channel == channel) { 410662306a36Sopenharmony_ci if (current_depth > sdev->queue_depth) { 410762306a36Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 410862306a36Sopenharmony_ci "strange observation, the queue " 410962306a36Sopenharmony_ci "depth is (%d) meanwhile fw queue " 411062306a36Sopenharmony_ci "depth (%d)\n", sdev->queue_depth, 411162306a36Sopenharmony_ci current_depth); 411262306a36Sopenharmony_ci continue; 411362306a36Sopenharmony_ci } 411462306a36Sopenharmony_ci depth = scsi_track_queue_full(sdev, 411562306a36Sopenharmony_ci sdev->queue_depth - 1); 411662306a36Sopenharmony_ci if (depth > 0) 411762306a36Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 411862306a36Sopenharmony_ci "Queue depth reduced to (%d)\n", 411962306a36Sopenharmony_ci depth); 412062306a36Sopenharmony_ci else if (depth < 0) 412162306a36Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 412262306a36Sopenharmony_ci "Tagged Command Queueing is being " 412362306a36Sopenharmony_ci "disabled\n"); 412462306a36Sopenharmony_ci else if (depth == 0) 412562306a36Sopenharmony_ci sdev_printk(KERN_DEBUG, sdev, 412662306a36Sopenharmony_ci "Queue depth not changed yet\n"); 412762306a36Sopenharmony_ci } 412862306a36Sopenharmony_ci } 412962306a36Sopenharmony_ci } 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 413262306a36Sopenharmony_ci} 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_cistatic struct mptsas_phyinfo * 413662306a36Sopenharmony_cimptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) 413762306a36Sopenharmony_ci{ 413862306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 413962306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 414062306a36Sopenharmony_ci int i; 414162306a36Sopenharmony_ci 414262306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 414362306a36Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) { 414462306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 414562306a36Sopenharmony_ci if (!mptsas_is_end_device( 414662306a36Sopenharmony_ci &port_info->phy_info[i].attached)) 414762306a36Sopenharmony_ci continue; 414862306a36Sopenharmony_ci if (port_info->phy_info[i].attached.sas_address 414962306a36Sopenharmony_ci != sas_address) 415062306a36Sopenharmony_ci continue; 415162306a36Sopenharmony_ci phy_info = &port_info->phy_info[i]; 415262306a36Sopenharmony_ci break; 415362306a36Sopenharmony_ci } 415462306a36Sopenharmony_ci } 415562306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 415662306a36Sopenharmony_ci return phy_info; 415762306a36Sopenharmony_ci} 415862306a36Sopenharmony_ci 415962306a36Sopenharmony_ci/** 416062306a36Sopenharmony_ci * mptsas_find_phyinfo_by_phys_disk_num - find phyinfo for the 416162306a36Sopenharmony_ci * specified @phys_disk_num 416262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 416362306a36Sopenharmony_ci * @phys_disk_num: (hot plug) physical disk number (for RAID support) 416462306a36Sopenharmony_ci * @channel: channel number 416562306a36Sopenharmony_ci * @id: Logical Target ID 416662306a36Sopenharmony_ci * 416762306a36Sopenharmony_ci **/ 416862306a36Sopenharmony_cistatic struct mptsas_phyinfo * 416962306a36Sopenharmony_cimptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, 417062306a36Sopenharmony_ci u8 channel, u8 id) 417162306a36Sopenharmony_ci{ 417262306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 417362306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 417462306a36Sopenharmony_ci RaidPhysDiskPage1_t *phys_disk = NULL; 417562306a36Sopenharmony_ci int num_paths; 417662306a36Sopenharmony_ci u64 sas_address = 0; 417762306a36Sopenharmony_ci int i; 417862306a36Sopenharmony_ci 417962306a36Sopenharmony_ci phy_info = NULL; 418062306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg3) 418162306a36Sopenharmony_ci return NULL; 418262306a36Sopenharmony_ci /* dual port support */ 418362306a36Sopenharmony_ci num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); 418462306a36Sopenharmony_ci if (!num_paths) 418562306a36Sopenharmony_ci goto out; 418662306a36Sopenharmony_ci phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + 418762306a36Sopenharmony_ci (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); 418862306a36Sopenharmony_ci if (!phys_disk) 418962306a36Sopenharmony_ci goto out; 419062306a36Sopenharmony_ci mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); 419162306a36Sopenharmony_ci for (i = 0; i < num_paths; i++) { 419262306a36Sopenharmony_ci if ((phys_disk->Path[i].Flags & 1) != 0) 419362306a36Sopenharmony_ci /* entry no longer valid */ 419462306a36Sopenharmony_ci continue; 419562306a36Sopenharmony_ci if ((id == phys_disk->Path[i].PhysDiskID) && 419662306a36Sopenharmony_ci (channel == phys_disk->Path[i].PhysDiskBus)) { 419762306a36Sopenharmony_ci memcpy(&sas_address, &phys_disk->Path[i].WWID, 419862306a36Sopenharmony_ci sizeof(u64)); 419962306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 420062306a36Sopenharmony_ci sas_address); 420162306a36Sopenharmony_ci goto out; 420262306a36Sopenharmony_ci } 420362306a36Sopenharmony_ci } 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_ci out: 420662306a36Sopenharmony_ci kfree(phys_disk); 420762306a36Sopenharmony_ci if (phy_info) 420862306a36Sopenharmony_ci return phy_info; 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_ci /* 421162306a36Sopenharmony_ci * Extra code to handle RAID0 case, where the sas_address is not updated 421262306a36Sopenharmony_ci * in phys_disk_page_1 when hotswapped 421362306a36Sopenharmony_ci */ 421462306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 421562306a36Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) { 421662306a36Sopenharmony_ci for (i = 0; i < port_info->num_phys && !phy_info; i++) { 421762306a36Sopenharmony_ci if (!mptsas_is_end_device( 421862306a36Sopenharmony_ci &port_info->phy_info[i].attached)) 421962306a36Sopenharmony_ci continue; 422062306a36Sopenharmony_ci if (port_info->phy_info[i].attached.phys_disk_num == ~0) 422162306a36Sopenharmony_ci continue; 422262306a36Sopenharmony_ci if ((port_info->phy_info[i].attached.phys_disk_num == 422362306a36Sopenharmony_ci phys_disk_num) && 422462306a36Sopenharmony_ci (port_info->phy_info[i].attached.id == id) && 422562306a36Sopenharmony_ci (port_info->phy_info[i].attached.channel == 422662306a36Sopenharmony_ci channel)) 422762306a36Sopenharmony_ci phy_info = &port_info->phy_info[i]; 422862306a36Sopenharmony_ci } 422962306a36Sopenharmony_ci } 423062306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 423162306a36Sopenharmony_ci return phy_info; 423262306a36Sopenharmony_ci} 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_cistatic void 423562306a36Sopenharmony_cimptsas_reprobe_lun(struct scsi_device *sdev, void *data) 423662306a36Sopenharmony_ci{ 423762306a36Sopenharmony_ci int rc; 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci sdev->no_uld_attach = data ? 1 : 0; 424062306a36Sopenharmony_ci rc = scsi_device_reprobe(sdev); 424162306a36Sopenharmony_ci} 424262306a36Sopenharmony_ci 424362306a36Sopenharmony_cistatic void 424462306a36Sopenharmony_cimptsas_reprobe_target(struct scsi_target *starget, int uld_attach) 424562306a36Sopenharmony_ci{ 424662306a36Sopenharmony_ci starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, 424762306a36Sopenharmony_ci mptsas_reprobe_lun); 424862306a36Sopenharmony_ci} 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_cistatic void 425162306a36Sopenharmony_cimptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) 425262306a36Sopenharmony_ci{ 425362306a36Sopenharmony_ci CONFIGPARMS cfg; 425462306a36Sopenharmony_ci ConfigPageHeader_t hdr; 425562306a36Sopenharmony_ci dma_addr_t dma_handle; 425662306a36Sopenharmony_ci pRaidVolumePage0_t buffer = NULL; 425762306a36Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 425862306a36Sopenharmony_ci int i; 425962306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 426062306a36Sopenharmony_ci struct mptsas_devinfo sas_device; 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 426362306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 426462306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; 426562306a36Sopenharmony_ci cfg.pageAddr = (channel << 8) + id; 426662306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 426762306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 426862306a36Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 426962306a36Sopenharmony_ci 427062306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 427162306a36Sopenharmony_ci goto out; 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_ci if (!hdr.PageLength) 427462306a36Sopenharmony_ci goto out; 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 427762306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 427862306a36Sopenharmony_ci 427962306a36Sopenharmony_ci if (!buffer) 428062306a36Sopenharmony_ci goto out; 428162306a36Sopenharmony_ci 428262306a36Sopenharmony_ci cfg.physAddr = dma_handle; 428362306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 428462306a36Sopenharmony_ci 428562306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 428662306a36Sopenharmony_ci goto out; 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci if (!(buffer->VolumeStatus.Flags & 428962306a36Sopenharmony_ci MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) 429062306a36Sopenharmony_ci goto out; 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_ci if (!buffer->NumPhysDisks) 429362306a36Sopenharmony_ci goto out; 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci for (i = 0; i < buffer->NumPhysDisks; i++) { 429662306a36Sopenharmony_ci 429762306a36Sopenharmony_ci if (mpt_raid_phys_disk_pg0(ioc, 429862306a36Sopenharmony_ci buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) 429962306a36Sopenharmony_ci continue; 430062306a36Sopenharmony_ci 430162306a36Sopenharmony_ci if (mptsas_sas_device_pg0(ioc, &sas_device, 430262306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 430362306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 430462306a36Sopenharmony_ci (phys_disk.PhysDiskBus << 8) + 430562306a36Sopenharmony_ci phys_disk.PhysDiskID)) 430662306a36Sopenharmony_ci continue; 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci /* If there is no FW B_T mapping for this device then continue 430962306a36Sopenharmony_ci * */ 431062306a36Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 431162306a36Sopenharmony_ci || !(sas_device.flags & 431262306a36Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 431362306a36Sopenharmony_ci continue; 431462306a36Sopenharmony_ci 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 431762306a36Sopenharmony_ci sas_device.sas_address); 431862306a36Sopenharmony_ci mptsas_add_end_device(ioc, phy_info); 431962306a36Sopenharmony_ci } 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci out: 432262306a36Sopenharmony_ci if (buffer) 432362306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 432462306a36Sopenharmony_ci buffer, dma_handle); 432562306a36Sopenharmony_ci} 432662306a36Sopenharmony_ci/* 432762306a36Sopenharmony_ci * Work queue thread to handle SAS hotplug events 432862306a36Sopenharmony_ci */ 432962306a36Sopenharmony_cistatic void 433062306a36Sopenharmony_cimptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, 433162306a36Sopenharmony_ci struct mptsas_hotplug_event *hot_plug_info) 433262306a36Sopenharmony_ci{ 433362306a36Sopenharmony_ci struct mptsas_phyinfo *phy_info; 433462306a36Sopenharmony_ci struct scsi_target * starget; 433562306a36Sopenharmony_ci struct mptsas_devinfo sas_device; 433662306a36Sopenharmony_ci VirtTarget *vtarget; 433762306a36Sopenharmony_ci int i; 433862306a36Sopenharmony_ci struct mptsas_portinfo *port_info; 433962306a36Sopenharmony_ci 434062306a36Sopenharmony_ci switch (hot_plug_info->event_type) { 434162306a36Sopenharmony_ci 434262306a36Sopenharmony_ci case MPTSAS_ADD_PHYSDISK: 434362306a36Sopenharmony_ci 434462306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg2) 434562306a36Sopenharmony_ci break; 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 434862306a36Sopenharmony_ci if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == 434962306a36Sopenharmony_ci hot_plug_info->id) { 435062306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "firmware bug: unable " 435162306a36Sopenharmony_ci "to add hidden disk - target_id matches " 435262306a36Sopenharmony_ci "volume_id\n", ioc->name); 435362306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 435462306a36Sopenharmony_ci return; 435562306a36Sopenharmony_ci } 435662306a36Sopenharmony_ci } 435762306a36Sopenharmony_ci mpt_findImVolumes(ioc); 435862306a36Sopenharmony_ci fallthrough; 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_ci case MPTSAS_ADD_DEVICE: 436162306a36Sopenharmony_ci memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); 436262306a36Sopenharmony_ci mptsas_sas_device_pg0(ioc, &sas_device, 436362306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 436462306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 436562306a36Sopenharmony_ci (hot_plug_info->channel << 8) + 436662306a36Sopenharmony_ci hot_plug_info->id); 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci /* If there is no FW B_T mapping for this device then break 436962306a36Sopenharmony_ci * */ 437062306a36Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 437162306a36Sopenharmony_ci || !(sas_device.flags & 437262306a36Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 437362306a36Sopenharmony_ci break; 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_ci if (!sas_device.handle) 437662306a36Sopenharmony_ci return; 437762306a36Sopenharmony_ci 437862306a36Sopenharmony_ci phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); 437962306a36Sopenharmony_ci /* Device hot plug */ 438062306a36Sopenharmony_ci if (!phy_info) { 438162306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 438262306a36Sopenharmony_ci "%s %d HOT PLUG: " 438362306a36Sopenharmony_ci "parent handle of device %x\n", ioc->name, 438462306a36Sopenharmony_ci __func__, __LINE__, sas_device.handle_parent)); 438562306a36Sopenharmony_ci port_info = mptsas_find_portinfo_by_handle(ioc, 438662306a36Sopenharmony_ci sas_device.handle_parent); 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_ci if (port_info == ioc->hba_port_info) 438962306a36Sopenharmony_ci mptsas_probe_hba_phys(ioc); 439062306a36Sopenharmony_ci else if (port_info) 439162306a36Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 439262306a36Sopenharmony_ci else { 439362306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 439462306a36Sopenharmony_ci "%s %d port info is NULL\n", 439562306a36Sopenharmony_ci ioc->name, __func__, __LINE__)); 439662306a36Sopenharmony_ci break; 439762306a36Sopenharmony_ci } 439862306a36Sopenharmony_ci phy_info = mptsas_refreshing_device_handles 439962306a36Sopenharmony_ci (ioc, &sas_device); 440062306a36Sopenharmony_ci } 440162306a36Sopenharmony_ci 440262306a36Sopenharmony_ci if (!phy_info) { 440362306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 440462306a36Sopenharmony_ci "%s %d phy info is NULL\n", 440562306a36Sopenharmony_ci ioc->name, __func__, __LINE__)); 440662306a36Sopenharmony_ci break; 440762306a36Sopenharmony_ci } 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ci if (mptsas_get_rphy(phy_info)) 441062306a36Sopenharmony_ci break; 441162306a36Sopenharmony_ci 441262306a36Sopenharmony_ci mptsas_add_end_device(ioc, phy_info); 441362306a36Sopenharmony_ci break; 441462306a36Sopenharmony_ci 441562306a36Sopenharmony_ci case MPTSAS_DEL_DEVICE: 441662306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 441762306a36Sopenharmony_ci hot_plug_info->sas_address); 441862306a36Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 441962306a36Sopenharmony_ci break; 442062306a36Sopenharmony_ci 442162306a36Sopenharmony_ci case MPTSAS_DEL_PHYSDISK: 442262306a36Sopenharmony_ci 442362306a36Sopenharmony_ci mpt_findImVolumes(ioc); 442462306a36Sopenharmony_ci 442562306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_phys_disk_num( 442662306a36Sopenharmony_ci ioc, hot_plug_info->phys_disk_num, 442762306a36Sopenharmony_ci hot_plug_info->channel, 442862306a36Sopenharmony_ci hot_plug_info->id); 442962306a36Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 443062306a36Sopenharmony_ci break; 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci case MPTSAS_ADD_PHYSDISK_REPROBE: 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_ci if (mptsas_sas_device_pg0(ioc, &sas_device, 443562306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 443662306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 443762306a36Sopenharmony_ci (hot_plug_info->channel << 8) + hot_plug_info->id)) { 443862306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 443962306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 444062306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 444162306a36Sopenharmony_ci break; 444262306a36Sopenharmony_ci } 444362306a36Sopenharmony_ci 444462306a36Sopenharmony_ci /* If there is no FW B_T mapping for this device then break 444562306a36Sopenharmony_ci * */ 444662306a36Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 444762306a36Sopenharmony_ci || !(sas_device.flags & 444862306a36Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 444962306a36Sopenharmony_ci break; 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address( 445262306a36Sopenharmony_ci ioc, sas_device.sas_address); 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci if (!phy_info) { 445562306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 445662306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 445762306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 445862306a36Sopenharmony_ci break; 445962306a36Sopenharmony_ci } 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci starget = mptsas_get_starget(phy_info); 446262306a36Sopenharmony_ci if (!starget) { 446362306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 446462306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 446562306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 446662306a36Sopenharmony_ci break; 446762306a36Sopenharmony_ci } 446862306a36Sopenharmony_ci 446962306a36Sopenharmony_ci vtarget = starget->hostdata; 447062306a36Sopenharmony_ci if (!vtarget) { 447162306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 447262306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 447362306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 447462306a36Sopenharmony_ci break; 447562306a36Sopenharmony_ci } 447662306a36Sopenharmony_ci 447762306a36Sopenharmony_ci mpt_findImVolumes(ioc); 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " 448062306a36Sopenharmony_ci "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", 448162306a36Sopenharmony_ci ioc->name, hot_plug_info->channel, hot_plug_info->id, 448262306a36Sopenharmony_ci hot_plug_info->phys_disk_num, (unsigned long long) 448362306a36Sopenharmony_ci sas_device.sas_address); 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_ci vtarget->id = hot_plug_info->phys_disk_num; 448662306a36Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; 448762306a36Sopenharmony_ci phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; 448862306a36Sopenharmony_ci mptsas_reprobe_target(starget, 1); 448962306a36Sopenharmony_ci break; 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_ci case MPTSAS_DEL_PHYSDISK_REPROBE: 449262306a36Sopenharmony_ci 449362306a36Sopenharmony_ci if (mptsas_sas_device_pg0(ioc, &sas_device, 449462306a36Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 449562306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 449662306a36Sopenharmony_ci (hot_plug_info->channel << 8) + hot_plug_info->id)) { 449762306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 449862306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", 449962306a36Sopenharmony_ci ioc->name, __func__, 450062306a36Sopenharmony_ci hot_plug_info->id, __LINE__)); 450162306a36Sopenharmony_ci break; 450262306a36Sopenharmony_ci } 450362306a36Sopenharmony_ci 450462306a36Sopenharmony_ci /* If there is no FW B_T mapping for this device then break 450562306a36Sopenharmony_ci * */ 450662306a36Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 450762306a36Sopenharmony_ci || !(sas_device.flags & 450862306a36Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 450962306a36Sopenharmony_ci break; 451062306a36Sopenharmony_ci 451162306a36Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 451262306a36Sopenharmony_ci sas_device.sas_address); 451362306a36Sopenharmony_ci if (!phy_info) { 451462306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 451562306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 451662306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 451762306a36Sopenharmony_ci break; 451862306a36Sopenharmony_ci } 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci starget = mptsas_get_starget(phy_info); 452162306a36Sopenharmony_ci if (!starget) { 452262306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 452362306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 452462306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 452562306a36Sopenharmony_ci break; 452662306a36Sopenharmony_ci } 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci vtarget = starget->hostdata; 452962306a36Sopenharmony_ci if (!vtarget) { 453062306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 453162306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 453262306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 453362306a36Sopenharmony_ci break; 453462306a36Sopenharmony_ci } 453562306a36Sopenharmony_ci 453662306a36Sopenharmony_ci if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { 453762306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 453862306a36Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 453962306a36Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 454062306a36Sopenharmony_ci break; 454162306a36Sopenharmony_ci } 454262306a36Sopenharmony_ci 454362306a36Sopenharmony_ci mpt_findImVolumes(ioc); 454462306a36Sopenharmony_ci 454562306a36Sopenharmony_ci starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" 454662306a36Sopenharmony_ci " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", 454762306a36Sopenharmony_ci ioc->name, hot_plug_info->channel, hot_plug_info->id, 454862306a36Sopenharmony_ci hot_plug_info->phys_disk_num, (unsigned long long) 454962306a36Sopenharmony_ci sas_device.sas_address); 455062306a36Sopenharmony_ci 455162306a36Sopenharmony_ci vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; 455262306a36Sopenharmony_ci vtarget->id = hot_plug_info->id; 455362306a36Sopenharmony_ci phy_info->attached.phys_disk_num = ~0; 455462306a36Sopenharmony_ci mptsas_reprobe_target(starget, 0); 455562306a36Sopenharmony_ci mptsas_add_device_component_by_fw(ioc, 455662306a36Sopenharmony_ci hot_plug_info->channel, hot_plug_info->id); 455762306a36Sopenharmony_ci break; 455862306a36Sopenharmony_ci 455962306a36Sopenharmony_ci case MPTSAS_ADD_RAID: 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci mpt_findImVolumes(ioc); 456262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " 456362306a36Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, 456462306a36Sopenharmony_ci hot_plug_info->id); 456562306a36Sopenharmony_ci scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, 456662306a36Sopenharmony_ci hot_plug_info->id, 0); 456762306a36Sopenharmony_ci break; 456862306a36Sopenharmony_ci 456962306a36Sopenharmony_ci case MPTSAS_DEL_RAID: 457062306a36Sopenharmony_ci 457162306a36Sopenharmony_ci mpt_findImVolumes(ioc); 457262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " 457362306a36Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, 457462306a36Sopenharmony_ci hot_plug_info->id); 457562306a36Sopenharmony_ci scsi_remove_device(hot_plug_info->sdev); 457662306a36Sopenharmony_ci scsi_device_put(hot_plug_info->sdev); 457762306a36Sopenharmony_ci break; 457862306a36Sopenharmony_ci 457962306a36Sopenharmony_ci case MPTSAS_ADD_INACTIVE_VOLUME: 458062306a36Sopenharmony_ci 458162306a36Sopenharmony_ci mpt_findImVolumes(ioc); 458262306a36Sopenharmony_ci mptsas_adding_inactive_raid_components(ioc, 458362306a36Sopenharmony_ci hot_plug_info->channel, hot_plug_info->id); 458462306a36Sopenharmony_ci break; 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci default: 458762306a36Sopenharmony_ci break; 458862306a36Sopenharmony_ci } 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 459162306a36Sopenharmony_ci} 459262306a36Sopenharmony_ci 459362306a36Sopenharmony_cistatic void 459462306a36Sopenharmony_cimptsas_send_sas_event(struct fw_event_work *fw_event) 459562306a36Sopenharmony_ci{ 459662306a36Sopenharmony_ci MPT_ADAPTER *ioc; 459762306a36Sopenharmony_ci struct mptsas_hotplug_event hot_plug_info; 459862306a36Sopenharmony_ci EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; 459962306a36Sopenharmony_ci u32 device_info; 460062306a36Sopenharmony_ci u64 sas_address; 460162306a36Sopenharmony_ci 460262306a36Sopenharmony_ci ioc = fw_event->ioc; 460362306a36Sopenharmony_ci sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) 460462306a36Sopenharmony_ci fw_event->event_data; 460562306a36Sopenharmony_ci device_info = le32_to_cpu(sas_event_data->DeviceInfo); 460662306a36Sopenharmony_ci 460762306a36Sopenharmony_ci if ((device_info & 460862306a36Sopenharmony_ci (MPI_SAS_DEVICE_INFO_SSP_TARGET | 460962306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET | 461062306a36Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { 461162306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 461262306a36Sopenharmony_ci return; 461362306a36Sopenharmony_ci } 461462306a36Sopenharmony_ci 461562306a36Sopenharmony_ci if (sas_event_data->ReasonCode == 461662306a36Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { 461762306a36Sopenharmony_ci mptbase_sas_persist_operation(ioc, 461862306a36Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 461962306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 462062306a36Sopenharmony_ci return; 462162306a36Sopenharmony_ci } 462262306a36Sopenharmony_ci 462362306a36Sopenharmony_ci switch (sas_event_data->ReasonCode) { 462462306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: 462562306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: 462662306a36Sopenharmony_ci memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); 462762306a36Sopenharmony_ci hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); 462862306a36Sopenharmony_ci hot_plug_info.channel = sas_event_data->Bus; 462962306a36Sopenharmony_ci hot_plug_info.id = sas_event_data->TargetID; 463062306a36Sopenharmony_ci hot_plug_info.phy_id = sas_event_data->PhyNum; 463162306a36Sopenharmony_ci memcpy(&sas_address, &sas_event_data->SASAddress, 463262306a36Sopenharmony_ci sizeof(u64)); 463362306a36Sopenharmony_ci hot_plug_info.sas_address = le64_to_cpu(sas_address); 463462306a36Sopenharmony_ci hot_plug_info.device_info = device_info; 463562306a36Sopenharmony_ci if (sas_event_data->ReasonCode & 463662306a36Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_ADDED) 463762306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_DEVICE; 463862306a36Sopenharmony_ci else 463962306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_DEVICE; 464062306a36Sopenharmony_ci mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); 464162306a36Sopenharmony_ci break; 464262306a36Sopenharmony_ci 464362306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: 464462306a36Sopenharmony_ci mptbase_sas_persist_operation(ioc, 464562306a36Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 464662306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 464762306a36Sopenharmony_ci break; 464862306a36Sopenharmony_ci 464962306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: 465062306a36Sopenharmony_ci /* TODO */ 465162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: 465262306a36Sopenharmony_ci /* TODO */ 465362306a36Sopenharmony_ci default: 465462306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 465562306a36Sopenharmony_ci break; 465662306a36Sopenharmony_ci } 465762306a36Sopenharmony_ci} 465862306a36Sopenharmony_ci 465962306a36Sopenharmony_cistatic void 466062306a36Sopenharmony_cimptsas_send_raid_event(struct fw_event_work *fw_event) 466162306a36Sopenharmony_ci{ 466262306a36Sopenharmony_ci MPT_ADAPTER *ioc; 466362306a36Sopenharmony_ci EVENT_DATA_RAID *raid_event_data; 466462306a36Sopenharmony_ci struct mptsas_hotplug_event hot_plug_info; 466562306a36Sopenharmony_ci int status; 466662306a36Sopenharmony_ci int state; 466762306a36Sopenharmony_ci struct scsi_device *sdev = NULL; 466862306a36Sopenharmony_ci VirtDevice *vdevice = NULL; 466962306a36Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci ioc = fw_event->ioc; 467262306a36Sopenharmony_ci raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; 467362306a36Sopenharmony_ci status = le32_to_cpu(raid_event_data->SettingsStatus); 467462306a36Sopenharmony_ci state = (status >> 8) & 0xff; 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_ci memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); 467762306a36Sopenharmony_ci hot_plug_info.id = raid_event_data->VolumeID; 467862306a36Sopenharmony_ci hot_plug_info.channel = raid_event_data->VolumeBus; 467962306a36Sopenharmony_ci hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; 468062306a36Sopenharmony_ci 468162306a36Sopenharmony_ci if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || 468262306a36Sopenharmony_ci raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || 468362306a36Sopenharmony_ci raid_event_data->ReasonCode == 468462306a36Sopenharmony_ci MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { 468562306a36Sopenharmony_ci sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, 468662306a36Sopenharmony_ci hot_plug_info.id, 0); 468762306a36Sopenharmony_ci hot_plug_info.sdev = sdev; 468862306a36Sopenharmony_ci if (sdev) 468962306a36Sopenharmony_ci vdevice = sdev->hostdata; 469062306a36Sopenharmony_ci } 469162306a36Sopenharmony_ci 469262306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " 469362306a36Sopenharmony_ci "ReasonCode=%02x\n", ioc->name, __func__, 469462306a36Sopenharmony_ci raid_event_data->ReasonCode)); 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci switch (raid_event_data->ReasonCode) { 469762306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: 469862306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; 469962306a36Sopenharmony_ci break; 470062306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: 470162306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; 470262306a36Sopenharmony_ci break; 470362306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: 470462306a36Sopenharmony_ci switch (state) { 470562306a36Sopenharmony_ci case MPI_PD_STATE_ONLINE: 470662306a36Sopenharmony_ci case MPI_PD_STATE_NOT_COMPATIBLE: 470762306a36Sopenharmony_ci mpt_raid_phys_disk_pg0(ioc, 470862306a36Sopenharmony_ci raid_event_data->PhysDiskNum, &phys_disk); 470962306a36Sopenharmony_ci hot_plug_info.id = phys_disk.PhysDiskID; 471062306a36Sopenharmony_ci hot_plug_info.channel = phys_disk.PhysDiskBus; 471162306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; 471262306a36Sopenharmony_ci break; 471362306a36Sopenharmony_ci case MPI_PD_STATE_FAILED: 471462306a36Sopenharmony_ci case MPI_PD_STATE_MISSING: 471562306a36Sopenharmony_ci case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: 471662306a36Sopenharmony_ci case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: 471762306a36Sopenharmony_ci case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: 471862306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; 471962306a36Sopenharmony_ci break; 472062306a36Sopenharmony_ci default: 472162306a36Sopenharmony_ci break; 472262306a36Sopenharmony_ci } 472362306a36Sopenharmony_ci break; 472462306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_DELETED: 472562306a36Sopenharmony_ci if (!sdev) 472662306a36Sopenharmony_ci break; 472762306a36Sopenharmony_ci vdevice->vtarget->deleted = 1; /* block IO */ 472862306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_RAID; 472962306a36Sopenharmony_ci break; 473062306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_CREATED: 473162306a36Sopenharmony_ci if (sdev) { 473262306a36Sopenharmony_ci scsi_device_put(sdev); 473362306a36Sopenharmony_ci break; 473462306a36Sopenharmony_ci } 473562306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_RAID; 473662306a36Sopenharmony_ci break; 473762306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: 473862306a36Sopenharmony_ci if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { 473962306a36Sopenharmony_ci if (!sdev) 474062306a36Sopenharmony_ci break; 474162306a36Sopenharmony_ci vdevice->vtarget->deleted = 1; /* block IO */ 474262306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_RAID; 474362306a36Sopenharmony_ci break; 474462306a36Sopenharmony_ci } 474562306a36Sopenharmony_ci switch (state) { 474662306a36Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_FAILED: 474762306a36Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_MISSING: 474862306a36Sopenharmony_ci if (!sdev) 474962306a36Sopenharmony_ci break; 475062306a36Sopenharmony_ci vdevice->vtarget->deleted = 1; /* block IO */ 475162306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_RAID; 475262306a36Sopenharmony_ci break; 475362306a36Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: 475462306a36Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: 475562306a36Sopenharmony_ci if (sdev) { 475662306a36Sopenharmony_ci scsi_device_put(sdev); 475762306a36Sopenharmony_ci break; 475862306a36Sopenharmony_ci } 475962306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_RAID; 476062306a36Sopenharmony_ci break; 476162306a36Sopenharmony_ci default: 476262306a36Sopenharmony_ci break; 476362306a36Sopenharmony_ci } 476462306a36Sopenharmony_ci break; 476562306a36Sopenharmony_ci default: 476662306a36Sopenharmony_ci break; 476762306a36Sopenharmony_ci } 476862306a36Sopenharmony_ci 476962306a36Sopenharmony_ci if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) 477062306a36Sopenharmony_ci mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); 477162306a36Sopenharmony_ci else 477262306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 477362306a36Sopenharmony_ci} 477462306a36Sopenharmony_ci 477562306a36Sopenharmony_ci/** 477662306a36Sopenharmony_ci * mptsas_issue_tm - send mptsas internal tm request 477762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 477862306a36Sopenharmony_ci * @type: Task Management type 477962306a36Sopenharmony_ci * @channel: channel number for task management 478062306a36Sopenharmony_ci * @id: Logical Target ID for reset (if appropriate) 478162306a36Sopenharmony_ci * @lun: Logical unit for reset (if appropriate) 478262306a36Sopenharmony_ci * @task_context: Context for the task to be aborted 478362306a36Sopenharmony_ci * @timeout: timeout for task management control 478462306a36Sopenharmony_ci * @issue_reset: set to 1 on return if reset is needed, else 0 478562306a36Sopenharmony_ci * 478662306a36Sopenharmony_ci * Return: 0 on success or -1 on failure. 478762306a36Sopenharmony_ci * 478862306a36Sopenharmony_ci */ 478962306a36Sopenharmony_cistatic int 479062306a36Sopenharmony_cimptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, 479162306a36Sopenharmony_ci int task_context, ulong timeout, u8 *issue_reset) 479262306a36Sopenharmony_ci{ 479362306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 479462306a36Sopenharmony_ci SCSITaskMgmt_t *pScsiTm; 479562306a36Sopenharmony_ci int retval; 479662306a36Sopenharmony_ci unsigned long timeleft; 479762306a36Sopenharmony_ci 479862306a36Sopenharmony_ci *issue_reset = 0; 479962306a36Sopenharmony_ci mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); 480062306a36Sopenharmony_ci if (mf == NULL) { 480162306a36Sopenharmony_ci retval = -1; /* return failure */ 480262306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " 480362306a36Sopenharmony_ci "msg frames!!\n", ioc->name)); 480462306a36Sopenharmony_ci goto out; 480562306a36Sopenharmony_ci } 480662306a36Sopenharmony_ci 480762306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " 480862306a36Sopenharmony_ci "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " 480962306a36Sopenharmony_ci "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, 481062306a36Sopenharmony_ci type, timeout, channel, id, (unsigned long long)lun, 481162306a36Sopenharmony_ci task_context)); 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci pScsiTm = (SCSITaskMgmt_t *) mf; 481462306a36Sopenharmony_ci memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); 481562306a36Sopenharmony_ci pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 481662306a36Sopenharmony_ci pScsiTm->TaskType = type; 481762306a36Sopenharmony_ci pScsiTm->MsgFlags = 0; 481862306a36Sopenharmony_ci pScsiTm->TargetID = id; 481962306a36Sopenharmony_ci pScsiTm->Bus = channel; 482062306a36Sopenharmony_ci pScsiTm->ChainOffset = 0; 482162306a36Sopenharmony_ci pScsiTm->Reserved = 0; 482262306a36Sopenharmony_ci pScsiTm->Reserved1 = 0; 482362306a36Sopenharmony_ci pScsiTm->TaskMsgContext = task_context; 482462306a36Sopenharmony_ci int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); 482562306a36Sopenharmony_ci 482662306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) 482762306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->internal_cmds.status) 482862306a36Sopenharmony_ci retval = 0; 482962306a36Sopenharmony_ci mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); 483062306a36Sopenharmony_ci 483162306a36Sopenharmony_ci /* Now wait for the command to complete */ 483262306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, 483362306a36Sopenharmony_ci timeout*HZ); 483462306a36Sopenharmony_ci if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 483562306a36Sopenharmony_ci retval = -1; /* return failure */ 483662306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_ERR_FMT 483762306a36Sopenharmony_ci "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); 483862306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 483962306a36Sopenharmony_ci if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) 484062306a36Sopenharmony_ci goto out; 484162306a36Sopenharmony_ci *issue_reset = 1; 484262306a36Sopenharmony_ci goto out; 484362306a36Sopenharmony_ci } 484462306a36Sopenharmony_ci 484562306a36Sopenharmony_ci if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { 484662306a36Sopenharmony_ci retval = -1; /* return failure */ 484762306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 484862306a36Sopenharmony_ci "TaskMgmt request: failed with no reply\n", ioc->name)); 484962306a36Sopenharmony_ci goto out; 485062306a36Sopenharmony_ci } 485162306a36Sopenharmony_ci 485262306a36Sopenharmony_ci out: 485362306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) 485462306a36Sopenharmony_ci return retval; 485562306a36Sopenharmony_ci} 485662306a36Sopenharmony_ci 485762306a36Sopenharmony_ci/** 485862306a36Sopenharmony_ci * mptsas_broadcast_primitive_work - Handle broadcast primitives 485962306a36Sopenharmony_ci * @fw_event: work queue payload containing info describing the event 486062306a36Sopenharmony_ci * 486162306a36Sopenharmony_ci * This will be handled in workqueue context. 486262306a36Sopenharmony_ci */ 486362306a36Sopenharmony_cistatic void 486462306a36Sopenharmony_cimptsas_broadcast_primitive_work(struct fw_event_work *fw_event) 486562306a36Sopenharmony_ci{ 486662306a36Sopenharmony_ci MPT_ADAPTER *ioc = fw_event->ioc; 486762306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 486862306a36Sopenharmony_ci VirtDevice *vdevice; 486962306a36Sopenharmony_ci int ii; 487062306a36Sopenharmony_ci struct scsi_cmnd *sc; 487162306a36Sopenharmony_ci SCSITaskMgmtReply_t *pScsiTmReply; 487262306a36Sopenharmony_ci u8 issue_reset; 487362306a36Sopenharmony_ci int task_context; 487462306a36Sopenharmony_ci u8 channel, id; 487562306a36Sopenharmony_ci int lun; 487662306a36Sopenharmony_ci u32 termination_count; 487762306a36Sopenharmony_ci u32 query_count; 487862306a36Sopenharmony_ci 487962306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 488062306a36Sopenharmony_ci "%s - enter\n", ioc->name, __func__)); 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci mutex_lock(&ioc->taskmgmt_cmds.mutex); 488362306a36Sopenharmony_ci if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { 488462306a36Sopenharmony_ci mutex_unlock(&ioc->taskmgmt_cmds.mutex); 488562306a36Sopenharmony_ci mptsas_requeue_fw_event(ioc, fw_event, 1000); 488662306a36Sopenharmony_ci return; 488762306a36Sopenharmony_ci } 488862306a36Sopenharmony_ci 488962306a36Sopenharmony_ci issue_reset = 0; 489062306a36Sopenharmony_ci termination_count = 0; 489162306a36Sopenharmony_ci query_count = 0; 489262306a36Sopenharmony_ci mpt_findImVolumes(ioc); 489362306a36Sopenharmony_ci pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; 489462306a36Sopenharmony_ci 489562306a36Sopenharmony_ci for (ii = 0; ii < ioc->req_depth; ii++) { 489662306a36Sopenharmony_ci if (ioc->fw_events_off) 489762306a36Sopenharmony_ci goto out; 489862306a36Sopenharmony_ci sc = mptscsih_get_scsi_lookup(ioc, ii); 489962306a36Sopenharmony_ci if (!sc) 490062306a36Sopenharmony_ci continue; 490162306a36Sopenharmony_ci mf = MPT_INDEX_2_MFPTR(ioc, ii); 490262306a36Sopenharmony_ci if (!mf) 490362306a36Sopenharmony_ci continue; 490462306a36Sopenharmony_ci task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; 490562306a36Sopenharmony_ci vdevice = sc->device->hostdata; 490662306a36Sopenharmony_ci if (!vdevice || !vdevice->vtarget) 490762306a36Sopenharmony_ci continue; 490862306a36Sopenharmony_ci if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) 490962306a36Sopenharmony_ci continue; /* skip hidden raid components */ 491062306a36Sopenharmony_ci if (vdevice->vtarget->raidVolume) 491162306a36Sopenharmony_ci continue; /* skip hidden raid components */ 491262306a36Sopenharmony_ci channel = vdevice->vtarget->channel; 491362306a36Sopenharmony_ci id = vdevice->vtarget->id; 491462306a36Sopenharmony_ci lun = vdevice->lun; 491562306a36Sopenharmony_ci if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, 491662306a36Sopenharmony_ci channel, id, (u64)lun, task_context, 30, &issue_reset)) 491762306a36Sopenharmony_ci goto out; 491862306a36Sopenharmony_ci query_count++; 491962306a36Sopenharmony_ci termination_count += 492062306a36Sopenharmony_ci le32_to_cpu(pScsiTmReply->TerminationCount); 492162306a36Sopenharmony_ci if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && 492262306a36Sopenharmony_ci (pScsiTmReply->ResponseCode == 492362306a36Sopenharmony_ci MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || 492462306a36Sopenharmony_ci pScsiTmReply->ResponseCode == 492562306a36Sopenharmony_ci MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) 492662306a36Sopenharmony_ci continue; 492762306a36Sopenharmony_ci if (mptsas_issue_tm(ioc, 492862306a36Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 492962306a36Sopenharmony_ci channel, id, (u64)lun, 0, 30, &issue_reset)) 493062306a36Sopenharmony_ci goto out; 493162306a36Sopenharmony_ci termination_count += 493262306a36Sopenharmony_ci le32_to_cpu(pScsiTmReply->TerminationCount); 493362306a36Sopenharmony_ci } 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_ci out: 493662306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 493762306a36Sopenharmony_ci "%s - exit, query_count = %d termination_count = %d\n", 493862306a36Sopenharmony_ci ioc->name, __func__, query_count, termination_count)); 493962306a36Sopenharmony_ci 494062306a36Sopenharmony_ci ioc->broadcast_aen_busy = 0; 494162306a36Sopenharmony_ci mpt_clear_taskmgmt_in_progress_flag(ioc); 494262306a36Sopenharmony_ci mutex_unlock(&ioc->taskmgmt_cmds.mutex); 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci if (issue_reset) { 494562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 494662306a36Sopenharmony_ci "Issuing Reset from %s!! doorbell=0x%08x\n", 494762306a36Sopenharmony_ci ioc->name, __func__, mpt_GetIocState(ioc, 0)); 494862306a36Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 494962306a36Sopenharmony_ci } 495062306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 495162306a36Sopenharmony_ci} 495262306a36Sopenharmony_ci 495362306a36Sopenharmony_ci/* 495462306a36Sopenharmony_ci * mptsas_send_ir2_event - handle exposing hidden disk when 495562306a36Sopenharmony_ci * an inactive raid volume is added 495662306a36Sopenharmony_ci * 495762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 495862306a36Sopenharmony_ci * @ir2_data 495962306a36Sopenharmony_ci * 496062306a36Sopenharmony_ci */ 496162306a36Sopenharmony_cistatic void 496262306a36Sopenharmony_cimptsas_send_ir2_event(struct fw_event_work *fw_event) 496362306a36Sopenharmony_ci{ 496462306a36Sopenharmony_ci MPT_ADAPTER *ioc; 496562306a36Sopenharmony_ci struct mptsas_hotplug_event hot_plug_info; 496662306a36Sopenharmony_ci MPI_EVENT_DATA_IR2 *ir2_data; 496762306a36Sopenharmony_ci u8 reasonCode; 496862306a36Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci ioc = fw_event->ioc; 497162306a36Sopenharmony_ci ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; 497262306a36Sopenharmony_ci reasonCode = ir2_data->ReasonCode; 497362306a36Sopenharmony_ci 497462306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " 497562306a36Sopenharmony_ci "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); 497862306a36Sopenharmony_ci hot_plug_info.id = ir2_data->TargetID; 497962306a36Sopenharmony_ci hot_plug_info.channel = ir2_data->Bus; 498062306a36Sopenharmony_ci switch (reasonCode) { 498162306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: 498262306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; 498362306a36Sopenharmony_ci break; 498462306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: 498562306a36Sopenharmony_ci hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; 498662306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; 498762306a36Sopenharmony_ci break; 498862306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: 498962306a36Sopenharmony_ci hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; 499062306a36Sopenharmony_ci mpt_raid_phys_disk_pg0(ioc, 499162306a36Sopenharmony_ci ir2_data->PhysDiskNum, &phys_disk); 499262306a36Sopenharmony_ci hot_plug_info.id = phys_disk.PhysDiskID; 499362306a36Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; 499462306a36Sopenharmony_ci break; 499562306a36Sopenharmony_ci default: 499662306a36Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 499762306a36Sopenharmony_ci return; 499862306a36Sopenharmony_ci } 499962306a36Sopenharmony_ci mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); 500062306a36Sopenharmony_ci} 500162306a36Sopenharmony_ci 500262306a36Sopenharmony_cistatic int 500362306a36Sopenharmony_cimptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) 500462306a36Sopenharmony_ci{ 500562306a36Sopenharmony_ci u32 event = le32_to_cpu(reply->Event); 500662306a36Sopenharmony_ci int event_data_sz; 500762306a36Sopenharmony_ci struct fw_event_work *fw_event; 500862306a36Sopenharmony_ci unsigned long delay; 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci if (ioc->bus_type != SAS) 501162306a36Sopenharmony_ci return 0; 501262306a36Sopenharmony_ci 501362306a36Sopenharmony_ci /* events turned off due to host reset or driver unloading */ 501462306a36Sopenharmony_ci if (ioc->fw_events_off) 501562306a36Sopenharmony_ci return 0; 501662306a36Sopenharmony_ci 501762306a36Sopenharmony_ci delay = msecs_to_jiffies(1); 501862306a36Sopenharmony_ci switch (event) { 501962306a36Sopenharmony_ci case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: 502062306a36Sopenharmony_ci { 502162306a36Sopenharmony_ci EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = 502262306a36Sopenharmony_ci (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; 502362306a36Sopenharmony_ci if (broadcast_event_data->Primitive != 502462306a36Sopenharmony_ci MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) 502562306a36Sopenharmony_ci return 0; 502662306a36Sopenharmony_ci if (ioc->broadcast_aen_busy) 502762306a36Sopenharmony_ci return 0; 502862306a36Sopenharmony_ci ioc->broadcast_aen_busy = 1; 502962306a36Sopenharmony_ci break; 503062306a36Sopenharmony_ci } 503162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 503262306a36Sopenharmony_ci { 503362306a36Sopenharmony_ci EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = 503462306a36Sopenharmony_ci (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; 503562306a36Sopenharmony_ci u16 ioc_stat; 503662306a36Sopenharmony_ci ioc_stat = le16_to_cpu(reply->IOCStatus); 503762306a36Sopenharmony_ci 503862306a36Sopenharmony_ci if (sas_event_data->ReasonCode == 503962306a36Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { 504062306a36Sopenharmony_ci mptsas_target_reset_queue(ioc, sas_event_data); 504162306a36Sopenharmony_ci return 0; 504262306a36Sopenharmony_ci } 504362306a36Sopenharmony_ci if (sas_event_data->ReasonCode == 504462306a36Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && 504562306a36Sopenharmony_ci ioc->device_missing_delay && 504662306a36Sopenharmony_ci (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { 504762306a36Sopenharmony_ci VirtTarget *vtarget = NULL; 504862306a36Sopenharmony_ci u8 id, channel; 504962306a36Sopenharmony_ci 505062306a36Sopenharmony_ci id = sas_event_data->TargetID; 505162306a36Sopenharmony_ci channel = sas_event_data->Bus; 505262306a36Sopenharmony_ci 505362306a36Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, channel, id); 505462306a36Sopenharmony_ci if (vtarget) { 505562306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 505662306a36Sopenharmony_ci "LogInfo (0x%x) available for " 505762306a36Sopenharmony_ci "INTERNAL_DEVICE_RESET" 505862306a36Sopenharmony_ci "fw_id %d fw_channel %d\n", ioc->name, 505962306a36Sopenharmony_ci le32_to_cpu(reply->IOCLogInfo), 506062306a36Sopenharmony_ci id, channel)); 506162306a36Sopenharmony_ci if (vtarget->raidVolume) { 506262306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 506362306a36Sopenharmony_ci "Skipping Raid Volume for inDMD\n", 506462306a36Sopenharmony_ci ioc->name)); 506562306a36Sopenharmony_ci } else { 506662306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 506762306a36Sopenharmony_ci "Setting device flag inDMD\n", 506862306a36Sopenharmony_ci ioc->name)); 506962306a36Sopenharmony_ci vtarget->inDMD = 1; 507062306a36Sopenharmony_ci } 507162306a36Sopenharmony_ci 507262306a36Sopenharmony_ci } 507362306a36Sopenharmony_ci 507462306a36Sopenharmony_ci } 507562306a36Sopenharmony_ci 507662306a36Sopenharmony_ci break; 507762306a36Sopenharmony_ci } 507862306a36Sopenharmony_ci case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: 507962306a36Sopenharmony_ci { 508062306a36Sopenharmony_ci MpiEventDataSasExpanderStatusChange_t *expander_data = 508162306a36Sopenharmony_ci (MpiEventDataSasExpanderStatusChange_t *)reply->Data; 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci if (ioc->old_sas_discovery_protocal) 508462306a36Sopenharmony_ci return 0; 508562306a36Sopenharmony_ci 508662306a36Sopenharmony_ci if (expander_data->ReasonCode == 508762306a36Sopenharmony_ci MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && 508862306a36Sopenharmony_ci ioc->device_missing_delay) 508962306a36Sopenharmony_ci delay = HZ * ioc->device_missing_delay; 509062306a36Sopenharmony_ci break; 509162306a36Sopenharmony_ci } 509262306a36Sopenharmony_ci case MPI_EVENT_SAS_DISCOVERY: 509362306a36Sopenharmony_ci { 509462306a36Sopenharmony_ci u32 discovery_status; 509562306a36Sopenharmony_ci EventDataSasDiscovery_t *discovery_data = 509662306a36Sopenharmony_ci (EventDataSasDiscovery_t *)reply->Data; 509762306a36Sopenharmony_ci 509862306a36Sopenharmony_ci discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); 509962306a36Sopenharmony_ci ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; 510062306a36Sopenharmony_ci if (ioc->old_sas_discovery_protocal && !discovery_status) 510162306a36Sopenharmony_ci mptsas_queue_rescan(ioc); 510262306a36Sopenharmony_ci return 0; 510362306a36Sopenharmony_ci } 510462306a36Sopenharmony_ci case MPI_EVENT_INTEGRATED_RAID: 510562306a36Sopenharmony_ci case MPI_EVENT_PERSISTENT_TABLE_FULL: 510662306a36Sopenharmony_ci case MPI_EVENT_IR2: 510762306a36Sopenharmony_ci case MPI_EVENT_SAS_PHY_LINK_STATUS: 510862306a36Sopenharmony_ci case MPI_EVENT_QUEUE_FULL: 510962306a36Sopenharmony_ci break; 511062306a36Sopenharmony_ci default: 511162306a36Sopenharmony_ci return 0; 511262306a36Sopenharmony_ci } 511362306a36Sopenharmony_ci 511462306a36Sopenharmony_ci event_data_sz = ((reply->MsgLength * 4) - 511562306a36Sopenharmony_ci offsetof(EventNotificationReply_t, Data)); 511662306a36Sopenharmony_ci fw_event = kzalloc(sizeof(*fw_event) + event_data_sz, GFP_ATOMIC); 511762306a36Sopenharmony_ci if (!fw_event) { 511862306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, 511962306a36Sopenharmony_ci __func__, __LINE__); 512062306a36Sopenharmony_ci return 0; 512162306a36Sopenharmony_ci } 512262306a36Sopenharmony_ci memcpy(fw_event->event_data, reply->Data, event_data_sz); 512362306a36Sopenharmony_ci fw_event->event = event; 512462306a36Sopenharmony_ci fw_event->ioc = ioc; 512562306a36Sopenharmony_ci mptsas_add_fw_event(ioc, fw_event, delay); 512662306a36Sopenharmony_ci return 0; 512762306a36Sopenharmony_ci} 512862306a36Sopenharmony_ci 512962306a36Sopenharmony_ci/* Delete a volume when no longer listed in ioc pg2 513062306a36Sopenharmony_ci */ 513162306a36Sopenharmony_cistatic void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) 513262306a36Sopenharmony_ci{ 513362306a36Sopenharmony_ci struct scsi_device *sdev; 513462306a36Sopenharmony_ci int i; 513562306a36Sopenharmony_ci 513662306a36Sopenharmony_ci sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); 513762306a36Sopenharmony_ci if (!sdev) 513862306a36Sopenharmony_ci return; 513962306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg2) 514062306a36Sopenharmony_ci goto out; 514162306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg2->NumActiveVolumes) 514262306a36Sopenharmony_ci goto out; 514362306a36Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) 514462306a36Sopenharmony_ci if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) 514562306a36Sopenharmony_ci goto release_sdev; 514662306a36Sopenharmony_ci out: 514762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " 514862306a36Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); 514962306a36Sopenharmony_ci scsi_remove_device(sdev); 515062306a36Sopenharmony_ci release_sdev: 515162306a36Sopenharmony_ci scsi_device_put(sdev); 515262306a36Sopenharmony_ci} 515362306a36Sopenharmony_ci 515462306a36Sopenharmony_cistatic int 515562306a36Sopenharmony_cimptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) 515662306a36Sopenharmony_ci{ 515762306a36Sopenharmony_ci struct Scsi_Host *sh; 515862306a36Sopenharmony_ci MPT_SCSI_HOST *hd; 515962306a36Sopenharmony_ci MPT_ADAPTER *ioc; 516062306a36Sopenharmony_ci unsigned long flags; 516162306a36Sopenharmony_ci int ii; 516262306a36Sopenharmony_ci int numSGE = 0; 516362306a36Sopenharmony_ci int scale; 516462306a36Sopenharmony_ci int ioc_cap; 516562306a36Sopenharmony_ci int error=0; 516662306a36Sopenharmony_ci int r; 516762306a36Sopenharmony_ci 516862306a36Sopenharmony_ci r = mpt_attach(pdev,id); 516962306a36Sopenharmony_ci if (r) 517062306a36Sopenharmony_ci return r; 517162306a36Sopenharmony_ci 517262306a36Sopenharmony_ci ioc = pci_get_drvdata(pdev); 517362306a36Sopenharmony_ci mptsas_fw_event_off(ioc); 517462306a36Sopenharmony_ci ioc->DoneCtx = mptsasDoneCtx; 517562306a36Sopenharmony_ci ioc->TaskCtx = mptsasTaskCtx; 517662306a36Sopenharmony_ci ioc->InternalCtx = mptsasInternalCtx; 517762306a36Sopenharmony_ci ioc->schedule_target_reset = &mptsas_schedule_target_reset; 517862306a36Sopenharmony_ci ioc->schedule_dead_ioc_flush_running_cmds = 517962306a36Sopenharmony_ci &mptscsih_flush_running_cmds; 518062306a36Sopenharmony_ci /* Added sanity check on readiness of the MPT adapter. 518162306a36Sopenharmony_ci */ 518262306a36Sopenharmony_ci if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { 518362306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 518462306a36Sopenharmony_ci "Skipping because it's not operational!\n", 518562306a36Sopenharmony_ci ioc->name); 518662306a36Sopenharmony_ci error = -ENODEV; 518762306a36Sopenharmony_ci goto out_mptsas_probe; 518862306a36Sopenharmony_ci } 518962306a36Sopenharmony_ci 519062306a36Sopenharmony_ci if (!ioc->active) { 519162306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", 519262306a36Sopenharmony_ci ioc->name); 519362306a36Sopenharmony_ci error = -ENODEV; 519462306a36Sopenharmony_ci goto out_mptsas_probe; 519562306a36Sopenharmony_ci } 519662306a36Sopenharmony_ci 519762306a36Sopenharmony_ci /* Sanity check - ensure at least 1 port is INITIATOR capable 519862306a36Sopenharmony_ci */ 519962306a36Sopenharmony_ci ioc_cap = 0; 520062306a36Sopenharmony_ci for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) { 520162306a36Sopenharmony_ci if (ioc->pfacts[ii].ProtocolFlags & 520262306a36Sopenharmony_ci MPI_PORTFACTS_PROTOCOL_INITIATOR) 520362306a36Sopenharmony_ci ioc_cap++; 520462306a36Sopenharmony_ci } 520562306a36Sopenharmony_ci 520662306a36Sopenharmony_ci if (!ioc_cap) { 520762306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 520862306a36Sopenharmony_ci "Skipping ioc=%p because SCSI Initiator mode " 520962306a36Sopenharmony_ci "is NOT enabled!\n", ioc->name, ioc); 521062306a36Sopenharmony_ci return 0; 521162306a36Sopenharmony_ci } 521262306a36Sopenharmony_ci 521362306a36Sopenharmony_ci sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST)); 521462306a36Sopenharmony_ci if (!sh) { 521562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 521662306a36Sopenharmony_ci "Unable to register controller with SCSI subsystem\n", 521762306a36Sopenharmony_ci ioc->name); 521862306a36Sopenharmony_ci error = -1; 521962306a36Sopenharmony_ci goto out_mptsas_probe; 522062306a36Sopenharmony_ci } 522162306a36Sopenharmony_ci 522262306a36Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 522362306a36Sopenharmony_ci 522462306a36Sopenharmony_ci /* Attach the SCSI Host to the IOC structure 522562306a36Sopenharmony_ci */ 522662306a36Sopenharmony_ci ioc->sh = sh; 522762306a36Sopenharmony_ci 522862306a36Sopenharmony_ci sh->io_port = 0; 522962306a36Sopenharmony_ci sh->n_io_port = 0; 523062306a36Sopenharmony_ci sh->irq = 0; 523162306a36Sopenharmony_ci 523262306a36Sopenharmony_ci /* set 16 byte cdb's */ 523362306a36Sopenharmony_ci sh->max_cmd_len = 16; 523462306a36Sopenharmony_ci sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); 523562306a36Sopenharmony_ci sh->max_id = -1; 523662306a36Sopenharmony_ci sh->max_lun = max_lun; 523762306a36Sopenharmony_ci sh->transportt = mptsas_transport_template; 523862306a36Sopenharmony_ci 523962306a36Sopenharmony_ci /* Required entry. 524062306a36Sopenharmony_ci */ 524162306a36Sopenharmony_ci sh->unique_id = ioc->id; 524262306a36Sopenharmony_ci 524362306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->sas_topology); 524462306a36Sopenharmony_ci mutex_init(&ioc->sas_topology_mutex); 524562306a36Sopenharmony_ci mutex_init(&ioc->sas_discovery_mutex); 524662306a36Sopenharmony_ci mutex_init(&ioc->sas_mgmt.mutex); 524762306a36Sopenharmony_ci init_completion(&ioc->sas_mgmt.done); 524862306a36Sopenharmony_ci 524962306a36Sopenharmony_ci /* Verify that we won't exceed the maximum 525062306a36Sopenharmony_ci * number of chain buffers 525162306a36Sopenharmony_ci * We can optimize: ZZ = req_sz/sizeof(SGE) 525262306a36Sopenharmony_ci * For 32bit SGE's: 525362306a36Sopenharmony_ci * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ 525462306a36Sopenharmony_ci * + (req_sz - 64)/sizeof(SGE) 525562306a36Sopenharmony_ci * A slightly different algorithm is required for 525662306a36Sopenharmony_ci * 64bit SGEs. 525762306a36Sopenharmony_ci */ 525862306a36Sopenharmony_ci scale = ioc->req_sz/ioc->SGE_size; 525962306a36Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) { 526062306a36Sopenharmony_ci numSGE = (scale - 1) * 526162306a36Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 526262306a36Sopenharmony_ci (ioc->req_sz - 60) / ioc->SGE_size; 526362306a36Sopenharmony_ci } else { 526462306a36Sopenharmony_ci numSGE = 1 + (scale - 1) * 526562306a36Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 526662306a36Sopenharmony_ci (ioc->req_sz - 64) / ioc->SGE_size; 526762306a36Sopenharmony_ci } 526862306a36Sopenharmony_ci 526962306a36Sopenharmony_ci if (numSGE < sh->sg_tablesize) { 527062306a36Sopenharmony_ci /* Reset this value */ 527162306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 527262306a36Sopenharmony_ci "Resetting sg_tablesize to %d from %d\n", 527362306a36Sopenharmony_ci ioc->name, numSGE, sh->sg_tablesize)); 527462306a36Sopenharmony_ci sh->sg_tablesize = numSGE; 527562306a36Sopenharmony_ci } 527662306a36Sopenharmony_ci 527762306a36Sopenharmony_ci if (mpt_loadtime_max_sectors) { 527862306a36Sopenharmony_ci if (mpt_loadtime_max_sectors < 64 || 527962306a36Sopenharmony_ci mpt_loadtime_max_sectors > 8192) { 528062306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "Invalid value passed for" 528162306a36Sopenharmony_ci "mpt_loadtime_max_sectors %d." 528262306a36Sopenharmony_ci "Range from 64 to 8192\n", ioc->name, 528362306a36Sopenharmony_ci mpt_loadtime_max_sectors); 528462306a36Sopenharmony_ci } 528562306a36Sopenharmony_ci mpt_loadtime_max_sectors &= 0xFFFFFFFE; 528662306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 528762306a36Sopenharmony_ci "Resetting max sector to %d from %d\n", 528862306a36Sopenharmony_ci ioc->name, mpt_loadtime_max_sectors, sh->max_sectors)); 528962306a36Sopenharmony_ci sh->max_sectors = mpt_loadtime_max_sectors; 529062306a36Sopenharmony_ci } 529162306a36Sopenharmony_ci 529262306a36Sopenharmony_ci hd = shost_priv(sh); 529362306a36Sopenharmony_ci hd->ioc = ioc; 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci /* SCSI needs scsi_cmnd lookup table! 529662306a36Sopenharmony_ci * (with size equal to req_depth*PtrSz!) 529762306a36Sopenharmony_ci */ 529862306a36Sopenharmony_ci ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); 529962306a36Sopenharmony_ci if (!ioc->ScsiLookup) { 530062306a36Sopenharmony_ci error = -ENOMEM; 530162306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 530262306a36Sopenharmony_ci goto out_mptsas_probe; 530362306a36Sopenharmony_ci } 530462306a36Sopenharmony_ci spin_lock_init(&ioc->scsi_lookup_lock); 530562306a36Sopenharmony_ci 530662306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", 530762306a36Sopenharmony_ci ioc->name, ioc->ScsiLookup)); 530862306a36Sopenharmony_ci 530962306a36Sopenharmony_ci ioc->sas_data.ptClear = mpt_pt_clear; 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci hd->last_queue_full = 0; 531262306a36Sopenharmony_ci INIT_LIST_HEAD(&hd->target_reset_list); 531362306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->sas_device_info_list); 531462306a36Sopenharmony_ci mutex_init(&ioc->sas_device_info_mutex); 531562306a36Sopenharmony_ci 531662306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 531762306a36Sopenharmony_ci 531862306a36Sopenharmony_ci if (ioc->sas_data.ptClear==1) { 531962306a36Sopenharmony_ci mptbase_sas_persist_operation( 532062306a36Sopenharmony_ci ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); 532162306a36Sopenharmony_ci } 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_ci error = scsi_add_host(sh, &ioc->pcidev->dev); 532462306a36Sopenharmony_ci if (error) { 532562306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_ERR_FMT 532662306a36Sopenharmony_ci "scsi_add_host failed\n", ioc->name)); 532762306a36Sopenharmony_ci goto out_mptsas_probe; 532862306a36Sopenharmony_ci } 532962306a36Sopenharmony_ci 533062306a36Sopenharmony_ci /* older firmware doesn't support expander events */ 533162306a36Sopenharmony_ci if ((ioc->facts.HeaderVersion >> 8) < 0xE) 533262306a36Sopenharmony_ci ioc->old_sas_discovery_protocal = 1; 533362306a36Sopenharmony_ci mptsas_scan_sas_topology(ioc); 533462306a36Sopenharmony_ci mptsas_fw_event_on(ioc); 533562306a36Sopenharmony_ci return 0; 533662306a36Sopenharmony_ci 533762306a36Sopenharmony_ci out_mptsas_probe: 533862306a36Sopenharmony_ci 533962306a36Sopenharmony_ci mptscsih_remove(pdev); 534062306a36Sopenharmony_ci return error; 534162306a36Sopenharmony_ci} 534262306a36Sopenharmony_ci 534362306a36Sopenharmony_cistatic void 534462306a36Sopenharmony_cimptsas_shutdown(struct pci_dev *pdev) 534562306a36Sopenharmony_ci{ 534662306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 534762306a36Sopenharmony_ci 534862306a36Sopenharmony_ci mptsas_fw_event_off(ioc); 534962306a36Sopenharmony_ci mptsas_cleanup_fw_event_q(ioc); 535062306a36Sopenharmony_ci} 535162306a36Sopenharmony_ci 535262306a36Sopenharmony_cistatic void mptsas_remove(struct pci_dev *pdev) 535362306a36Sopenharmony_ci{ 535462306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 535562306a36Sopenharmony_ci struct mptsas_portinfo *p, *n; 535662306a36Sopenharmony_ci int i; 535762306a36Sopenharmony_ci 535862306a36Sopenharmony_ci if (!ioc->sh) { 535962306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name); 536062306a36Sopenharmony_ci mpt_detach(pdev); 536162306a36Sopenharmony_ci return; 536262306a36Sopenharmony_ci } 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_ci mptsas_shutdown(pdev); 536562306a36Sopenharmony_ci 536662306a36Sopenharmony_ci mptsas_del_device_components(ioc); 536762306a36Sopenharmony_ci 536862306a36Sopenharmony_ci ioc->sas_discovery_ignore_events = 1; 536962306a36Sopenharmony_ci sas_remove_host(ioc->sh); 537062306a36Sopenharmony_ci 537162306a36Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 537262306a36Sopenharmony_ci list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { 537362306a36Sopenharmony_ci list_del(&p->list); 537462306a36Sopenharmony_ci for (i = 0 ; i < p->num_phys ; i++) 537562306a36Sopenharmony_ci mptsas_port_delete(ioc, p->phy_info[i].port_details); 537662306a36Sopenharmony_ci 537762306a36Sopenharmony_ci kfree(p->phy_info); 537862306a36Sopenharmony_ci kfree(p); 537962306a36Sopenharmony_ci } 538062306a36Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 538162306a36Sopenharmony_ci ioc->hba_port_info = NULL; 538262306a36Sopenharmony_ci mptscsih_remove(pdev); 538362306a36Sopenharmony_ci} 538462306a36Sopenharmony_ci 538562306a36Sopenharmony_cistatic struct pci_device_id mptsas_pci_table[] = { 538662306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, 538762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 538862306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, 538962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 539062306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E, 539162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 539262306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E, 539362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 539462306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, 539562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 539662306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP, 539762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 539862306a36Sopenharmony_ci {0} /* Terminating entry */ 539962306a36Sopenharmony_ci}; 540062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mptsas_pci_table); 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_ci 540362306a36Sopenharmony_cistatic struct pci_driver mptsas_driver = { 540462306a36Sopenharmony_ci .name = "mptsas", 540562306a36Sopenharmony_ci .id_table = mptsas_pci_table, 540662306a36Sopenharmony_ci .probe = mptsas_probe, 540762306a36Sopenharmony_ci .remove = mptsas_remove, 540862306a36Sopenharmony_ci .shutdown = mptsas_shutdown, 540962306a36Sopenharmony_ci#ifdef CONFIG_PM 541062306a36Sopenharmony_ci .suspend = mptscsih_suspend, 541162306a36Sopenharmony_ci .resume = mptscsih_resume, 541262306a36Sopenharmony_ci#endif 541362306a36Sopenharmony_ci}; 541462306a36Sopenharmony_ci 541562306a36Sopenharmony_cistatic int __init 541662306a36Sopenharmony_cimptsas_init(void) 541762306a36Sopenharmony_ci{ 541862306a36Sopenharmony_ci int error; 541962306a36Sopenharmony_ci 542062306a36Sopenharmony_ci show_mptmod_ver(my_NAME, my_VERSION); 542162306a36Sopenharmony_ci 542262306a36Sopenharmony_ci mptsas_transport_template = 542362306a36Sopenharmony_ci sas_attach_transport(&mptsas_transport_functions); 542462306a36Sopenharmony_ci if (!mptsas_transport_template) 542562306a36Sopenharmony_ci return -ENODEV; 542662306a36Sopenharmony_ci 542762306a36Sopenharmony_ci mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER, 542862306a36Sopenharmony_ci "mptscsih_io_done"); 542962306a36Sopenharmony_ci mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER, 543062306a36Sopenharmony_ci "mptscsih_taskmgmt_complete"); 543162306a36Sopenharmony_ci mptsasInternalCtx = 543262306a36Sopenharmony_ci mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER, 543362306a36Sopenharmony_ci "mptscsih_scandv_complete"); 543462306a36Sopenharmony_ci mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER, 543562306a36Sopenharmony_ci "mptsas_mgmt_done"); 543662306a36Sopenharmony_ci mptsasDeviceResetCtx = 543762306a36Sopenharmony_ci mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER, 543862306a36Sopenharmony_ci "mptsas_taskmgmt_complete"); 543962306a36Sopenharmony_ci 544062306a36Sopenharmony_ci mpt_event_register(mptsasDoneCtx, mptsas_event_process); 544162306a36Sopenharmony_ci mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); 544262306a36Sopenharmony_ci 544362306a36Sopenharmony_ci error = pci_register_driver(&mptsas_driver); 544462306a36Sopenharmony_ci if (error) 544562306a36Sopenharmony_ci sas_release_transport(mptsas_transport_template); 544662306a36Sopenharmony_ci 544762306a36Sopenharmony_ci return error; 544862306a36Sopenharmony_ci} 544962306a36Sopenharmony_ci 545062306a36Sopenharmony_cistatic void __exit 545162306a36Sopenharmony_cimptsas_exit(void) 545262306a36Sopenharmony_ci{ 545362306a36Sopenharmony_ci pci_unregister_driver(&mptsas_driver); 545462306a36Sopenharmony_ci sas_release_transport(mptsas_transport_template); 545562306a36Sopenharmony_ci 545662306a36Sopenharmony_ci mpt_reset_deregister(mptsasDoneCtx); 545762306a36Sopenharmony_ci mpt_event_deregister(mptsasDoneCtx); 545862306a36Sopenharmony_ci 545962306a36Sopenharmony_ci mpt_deregister(mptsasMgmtCtx); 546062306a36Sopenharmony_ci mpt_deregister(mptsasInternalCtx); 546162306a36Sopenharmony_ci mpt_deregister(mptsasTaskCtx); 546262306a36Sopenharmony_ci mpt_deregister(mptsasDoneCtx); 546362306a36Sopenharmony_ci mpt_deregister(mptsasDeviceResetCtx); 546462306a36Sopenharmony_ci} 546562306a36Sopenharmony_ci 546662306a36Sopenharmony_cimodule_init(mptsas_init); 546762306a36Sopenharmony_cimodule_exit(mptsas_exit); 5468