18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/message/fusion/mptsas.c 38c2ecf20Sopenharmony_ci * For use with LSI PCI chip/adapter(s) 48c2ecf20Sopenharmony_ci * running LSI Fusion MPT (Message Passing Technology) firmware. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 1999-2008 LSI Corporation 78c2ecf20Sopenharmony_ci * (mailto:DL-MPTFusionLinux@lsi.com) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci This program is free software; you can redistribute it and/or modify 128c2ecf20Sopenharmony_ci it under the terms of the GNU General Public License as published by 138c2ecf20Sopenharmony_ci the Free Software Foundation; version 2 of the License. 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci This program is distributed in the hope that it will be useful, 168c2ecf20Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 178c2ecf20Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 188c2ecf20Sopenharmony_ci GNU General Public License for more details. 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci NO WARRANTY 218c2ecf20Sopenharmony_ci THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 228c2ecf20Sopenharmony_ci CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 238c2ecf20Sopenharmony_ci LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 248c2ecf20Sopenharmony_ci MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 258c2ecf20Sopenharmony_ci solely responsible for determining the appropriateness of using and 268c2ecf20Sopenharmony_ci distributing the Program and assumes all risks associated with its 278c2ecf20Sopenharmony_ci exercise of rights under this Agreement, including but not limited to 288c2ecf20Sopenharmony_ci the risks and costs of program errors, damage to or loss of data, 298c2ecf20Sopenharmony_ci programs or equipment, and unavailability or interruption of operations. 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci DISCLAIMER OF LIABILITY 328c2ecf20Sopenharmony_ci NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 338c2ecf20Sopenharmony_ci DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 348c2ecf20Sopenharmony_ci DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 358c2ecf20Sopenharmony_ci ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 368c2ecf20Sopenharmony_ci TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 378c2ecf20Sopenharmony_ci USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 388c2ecf20Sopenharmony_ci HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci You should have received a copy of the GNU General Public License 418c2ecf20Sopenharmony_ci along with this program; if not, write to the Free Software 428c2ecf20Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 438c2ecf20Sopenharmony_ci*/ 448c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <linux/module.h> 478c2ecf20Sopenharmony_ci#include <linux/kernel.h> 488c2ecf20Sopenharmony_ci#include <linux/slab.h> 498c2ecf20Sopenharmony_ci#include <linux/init.h> 508c2ecf20Sopenharmony_ci#include <linux/errno.h> 518c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 528c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 538c2ecf20Sopenharmony_ci#include <linux/delay.h> /* for mdelay */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 568c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 578c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 588c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 598c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_sas.h> 608c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h> 618c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#include "mptbase.h" 648c2ecf20Sopenharmony_ci#include "mptscsih.h" 658c2ecf20Sopenharmony_ci#include "mptsas.h" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define my_NAME "Fusion MPT SAS Host driver" 698c2ecf20Sopenharmony_ci#define my_VERSION MPT_LINUX_VERSION_COMMON 708c2ecf20Sopenharmony_ci#define MYNAM "mptsas" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Reserved channel for integrated raid 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci#define MPTSAS_RAID_CHANNEL 1 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define SAS_CONFIG_PAGE_TIMEOUT 30 788c2ecf20Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR); 798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(my_NAME); 808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 818c2ecf20Sopenharmony_ciMODULE_VERSION(my_VERSION); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int mpt_pt_clear; 848c2ecf20Sopenharmony_cimodule_param(mpt_pt_clear, int, 0); 858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_pt_clear, 868c2ecf20Sopenharmony_ci " Clear persistency table: enable=1 " 878c2ecf20Sopenharmony_ci "(default=MPTSCSIH_PT_CLEAR=0)"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ 908c2ecf20Sopenharmony_ci#define MPTSAS_MAX_LUN (16895) 918c2ecf20Sopenharmony_cistatic int max_lun = MPTSAS_MAX_LUN; 928c2ecf20Sopenharmony_cimodule_param(max_lun, int, 0); 938c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_lun, " max lun, default=16895 "); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int mpt_loadtime_max_sectors = 8192; 968c2ecf20Sopenharmony_cimodule_param(mpt_loadtime_max_sectors, int, 0); 978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_loadtime_max_sectors, 988c2ecf20Sopenharmony_ci " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; 1018c2ecf20Sopenharmony_cistatic u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; 1028c2ecf20Sopenharmony_cistatic u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ 1038c2ecf20Sopenharmony_cistatic u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; 1048c2ecf20Sopenharmony_cistatic u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void mptsas_firmware_event_work(struct work_struct *work); 1078c2ecf20Sopenharmony_cistatic void mptsas_send_sas_event(struct fw_event_work *fw_event); 1088c2ecf20Sopenharmony_cistatic void mptsas_send_raid_event(struct fw_event_work *fw_event); 1098c2ecf20Sopenharmony_cistatic void mptsas_send_ir2_event(struct fw_event_work *fw_event); 1108c2ecf20Sopenharmony_cistatic void mptsas_parse_device_info(struct sas_identify *identify, 1118c2ecf20Sopenharmony_ci struct mptsas_devinfo *device_info); 1128c2ecf20Sopenharmony_cistatic inline void mptsas_set_rphy(MPT_ADAPTER *ioc, 1138c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); 1148c2ecf20Sopenharmony_cistatic struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address 1158c2ecf20Sopenharmony_ci (MPT_ADAPTER *ioc, u64 sas_address); 1168c2ecf20Sopenharmony_cistatic int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, 1178c2ecf20Sopenharmony_ci struct mptsas_devinfo *device_info, u32 form, u32 form_specific); 1188c2ecf20Sopenharmony_cistatic int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, 1198c2ecf20Sopenharmony_ci struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); 1208c2ecf20Sopenharmony_cistatic int mptsas_add_end_device(MPT_ADAPTER *ioc, 1218c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info); 1228c2ecf20Sopenharmony_cistatic void mptsas_del_end_device(MPT_ADAPTER *ioc, 1238c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info); 1248c2ecf20Sopenharmony_cistatic void mptsas_send_link_status_event(struct fw_event_work *fw_event); 1258c2ecf20Sopenharmony_cistatic struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address 1268c2ecf20Sopenharmony_ci (MPT_ADAPTER *ioc, u64 sas_address); 1278c2ecf20Sopenharmony_cistatic void mptsas_expander_delete(MPT_ADAPTER *ioc, 1288c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info, u8 force); 1298c2ecf20Sopenharmony_cistatic void mptsas_send_expander_event(struct fw_event_work *fw_event); 1308c2ecf20Sopenharmony_cistatic void mptsas_not_responding_devices(MPT_ADAPTER *ioc); 1318c2ecf20Sopenharmony_cistatic void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); 1328c2ecf20Sopenharmony_cistatic void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event); 1338c2ecf20Sopenharmony_cistatic void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); 1348c2ecf20Sopenharmony_cistatic void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); 1358c2ecf20Sopenharmony_civoid mptsas_schedule_target_reset(void *ioc); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void mptsas_print_phy_data(MPT_ADAPTER *ioc, 1388c2ecf20Sopenharmony_ci MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1418c2ecf20Sopenharmony_ci "---- IO UNIT PAGE 0 ------------\n", ioc->name)); 1428c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", 1438c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle))); 1448c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n", 1458c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(phy_data->ControllerDevHandle))); 1468c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n", 1478c2ecf20Sopenharmony_ci ioc->name, phy_data->Port)); 1488c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n", 1498c2ecf20Sopenharmony_ci ioc->name, phy_data->PortFlags)); 1508c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n", 1518c2ecf20Sopenharmony_ci ioc->name, phy_data->PhyFlags)); 1528c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", 1538c2ecf20Sopenharmony_ci ioc->name, phy_data->NegotiatedLinkRate)); 1548c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1558c2ecf20Sopenharmony_ci "Controller PHY Device Info=0x%X\n", ioc->name, 1568c2ecf20Sopenharmony_ci le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); 1578c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n", 1588c2ecf20Sopenharmony_ci ioc->name, le32_to_cpu(phy_data->DiscoveryStatus))); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci __le64 sas_address; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1688c2ecf20Sopenharmony_ci "---- SAS PHY PAGE 0 ------------\n", ioc->name)); 1698c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1708c2ecf20Sopenharmony_ci "Attached Device Handle=0x%X\n", ioc->name, 1718c2ecf20Sopenharmony_ci le16_to_cpu(pg0->AttachedDevHandle))); 1728c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", 1738c2ecf20Sopenharmony_ci ioc->name, (unsigned long long)le64_to_cpu(sas_address))); 1748c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1758c2ecf20Sopenharmony_ci "Attached PHY Identifier=0x%X\n", ioc->name, 1768c2ecf20Sopenharmony_ci pg0->AttachedPhyIdentifier)); 1778c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n", 1788c2ecf20Sopenharmony_ci ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo))); 1798c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", 1808c2ecf20Sopenharmony_ci ioc->name, pg0->ProgrammedLinkRate)); 1818c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n", 1828c2ecf20Sopenharmony_ci ioc->name, pg0->ChangeCount)); 1838c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n", 1848c2ecf20Sopenharmony_ci ioc->name, le32_to_cpu(pg0->PhyInfo))); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1908c2ecf20Sopenharmony_ci "---- SAS PHY PAGE 1 ------------\n", ioc->name)); 1918c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n", 1928c2ecf20Sopenharmony_ci ioc->name, pg1->InvalidDwordCount)); 1938c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1948c2ecf20Sopenharmony_ci "Running Disparity Error Count=0x%x\n", ioc->name, 1958c2ecf20Sopenharmony_ci pg1->RunningDisparityErrorCount)); 1968c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 1978c2ecf20Sopenharmony_ci "Loss Dword Synch Count=0x%x\n", ioc->name, 1988c2ecf20Sopenharmony_ci pg1->LossDwordSynchCount)); 1998c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 2008c2ecf20Sopenharmony_ci "PHY Reset Problem Count=0x%x\n\n", ioc->name, 2018c2ecf20Sopenharmony_ci pg1->PhyResetProblemCount)); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci __le64 sas_address; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 2118c2ecf20Sopenharmony_ci "---- SAS DEVICE PAGE 0 ---------\n", ioc->name)); 2128c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n", 2138c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg0->DevHandle))); 2148c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n", 2158c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg0->ParentDevHandle))); 2168c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n", 2178c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg0->EnclosureHandle))); 2188c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n", 2198c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg0->Slot))); 2208c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n", 2218c2ecf20Sopenharmony_ci ioc->name, (unsigned long long)le64_to_cpu(sas_address))); 2228c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n", 2238c2ecf20Sopenharmony_ci ioc->name, pg0->TargetID)); 2248c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n", 2258c2ecf20Sopenharmony_ci ioc->name, pg0->Bus)); 2268c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n", 2278c2ecf20Sopenharmony_ci ioc->name, pg0->PhyNum)); 2288c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n", 2298c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg0->AccessStatus))); 2308c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n", 2318c2ecf20Sopenharmony_ci ioc->name, le32_to_cpu(pg0->DeviceInfo))); 2328c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n", 2338c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg0->Flags))); 2348c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n", 2358c2ecf20Sopenharmony_ci ioc->name, pg0->PhysicalPort)); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 2418c2ecf20Sopenharmony_ci "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name)); 2428c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n", 2438c2ecf20Sopenharmony_ci ioc->name, pg1->PhysicalPort)); 2448c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n", 2458c2ecf20Sopenharmony_ci ioc->name, pg1->PhyIdentifier)); 2468c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n", 2478c2ecf20Sopenharmony_ci ioc->name, pg1->NegotiatedLinkRate)); 2488c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n", 2498c2ecf20Sopenharmony_ci ioc->name, pg1->ProgrammedLinkRate)); 2508c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n", 2518c2ecf20Sopenharmony_ci ioc->name, pg1->HwLinkRate)); 2528c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n", 2538c2ecf20Sopenharmony_ci ioc->name, le16_to_cpu(pg1->OwnerDevHandle))); 2548c2ecf20Sopenharmony_ci dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT 2558c2ecf20Sopenharmony_ci "Attached Device Handle=0x%X\n\n", ioc->name, 2568c2ecf20Sopenharmony_ci le16_to_cpu(pg1->AttachedDevHandle))); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* inhibit sas firmware event handling */ 2608c2ecf20Sopenharmony_cistatic void 2618c2ecf20Sopenharmony_cimptsas_fw_event_off(MPT_ADAPTER *ioc) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci unsigned long flags; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 2668c2ecf20Sopenharmony_ci ioc->fw_events_off = 1; 2678c2ecf20Sopenharmony_ci ioc->sas_discovery_quiesce_io = 0; 2688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* enable sas firmware event handling */ 2738c2ecf20Sopenharmony_cistatic void 2748c2ecf20Sopenharmony_cimptsas_fw_event_on(MPT_ADAPTER *ioc) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci unsigned long flags; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 2798c2ecf20Sopenharmony_ci ioc->fw_events_off = 0; 2808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* queue a sas firmware event */ 2848c2ecf20Sopenharmony_cistatic void 2858c2ecf20Sopenharmony_cimptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, 2868c2ecf20Sopenharmony_ci unsigned long delay) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci unsigned long flags; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 2918c2ecf20Sopenharmony_ci list_add_tail(&fw_event->list, &ioc->fw_event_list); 2928c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); 2938c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" 2948c2ecf20Sopenharmony_ci "on cpuid %d\n", ioc->name, __func__, 2958c2ecf20Sopenharmony_ci fw_event, smp_processor_id())); 2968c2ecf20Sopenharmony_ci queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, 2978c2ecf20Sopenharmony_ci &fw_event->work, delay); 2988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* requeue a sas firmware event */ 3028c2ecf20Sopenharmony_cistatic void 3038c2ecf20Sopenharmony_cimptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, 3048c2ecf20Sopenharmony_ci unsigned long delay) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci unsigned long flags; 3078c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 3088c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " 3098c2ecf20Sopenharmony_ci "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__, 3108c2ecf20Sopenharmony_ci fw_event, smp_processor_id())); 3118c2ecf20Sopenharmony_ci fw_event->retries++; 3128c2ecf20Sopenharmony_ci queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, 3138c2ecf20Sopenharmony_ci &fw_event->work, msecs_to_jiffies(delay)); 3148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* free memory associated to a sas firmware event */ 3188c2ecf20Sopenharmony_cistatic void 3198c2ecf20Sopenharmony_cimptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci unsigned long flags; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 3248c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", 3258c2ecf20Sopenharmony_ci ioc->name, __func__, fw_event)); 3268c2ecf20Sopenharmony_ci list_del(&fw_event->list); 3278c2ecf20Sopenharmony_ci kfree(fw_event); 3288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* walk the firmware event queue, and either stop or wait for 3328c2ecf20Sopenharmony_ci * outstanding events to complete */ 3338c2ecf20Sopenharmony_cistatic void 3348c2ecf20Sopenharmony_cimptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct fw_event_work *fw_event, *next; 3378c2ecf20Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list, *n; 3388c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* flush the target_reset_list */ 3418c2ecf20Sopenharmony_ci if (!list_empty(&hd->target_reset_list)) { 3428c2ecf20Sopenharmony_ci list_for_each_entry_safe(target_reset_list, n, 3438c2ecf20Sopenharmony_ci &hd->target_reset_list, list) { 3448c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 3458c2ecf20Sopenharmony_ci "%s: removing target reset for id=%d\n", 3468c2ecf20Sopenharmony_ci ioc->name, __func__, 3478c2ecf20Sopenharmony_ci target_reset_list->sas_event_data.TargetID)); 3488c2ecf20Sopenharmony_ci list_del(&target_reset_list->list); 3498c2ecf20Sopenharmony_ci kfree(target_reset_list); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (list_empty(&ioc->fw_event_list) || 3548c2ecf20Sopenharmony_ci !ioc->fw_event_q || in_interrupt()) 3558c2ecf20Sopenharmony_ci return; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { 3588c2ecf20Sopenharmony_ci if (cancel_delayed_work(&fw_event->work)) 3598c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 3678c2ecf20Sopenharmony_ci return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 3738c2ecf20Sopenharmony_ci return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* 3778c2ecf20Sopenharmony_ci * mptsas_find_portinfo_by_handle 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * This function should be called with the sas_topology_mutex already held 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_cistatic struct mptsas_portinfo * 3828c2ecf20Sopenharmony_cimptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info, *rc=NULL; 3858c2ecf20Sopenharmony_ci int i; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) 3888c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 3898c2ecf20Sopenharmony_ci if (port_info->phy_info[i].identify.handle == handle) { 3908c2ecf20Sopenharmony_ci rc = port_info; 3918c2ecf20Sopenharmony_ci goto out; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci out: 3948c2ecf20Sopenharmony_ci return rc; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * mptsas_find_portinfo_by_sas_address - 3998c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 4008c2ecf20Sopenharmony_ci * @handle: 4018c2ecf20Sopenharmony_ci * 4028c2ecf20Sopenharmony_ci * This function should be called with the sas_topology_mutex already held 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci **/ 4058c2ecf20Sopenharmony_cistatic struct mptsas_portinfo * 4068c2ecf20Sopenharmony_cimptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info, *rc = NULL; 4098c2ecf20Sopenharmony_ci int i; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (sas_address >= ioc->hba_port_sas_addr && 4128c2ecf20Sopenharmony_ci sas_address < (ioc->hba_port_sas_addr + 4138c2ecf20Sopenharmony_ci ioc->hba_port_num_phy)) 4148c2ecf20Sopenharmony_ci return ioc->hba_port_info; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 4178c2ecf20Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) 4188c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 4198c2ecf20Sopenharmony_ci if (port_info->phy_info[i].identify.sas_address == 4208c2ecf20Sopenharmony_ci sas_address) { 4218c2ecf20Sopenharmony_ci rc = port_info; 4228c2ecf20Sopenharmony_ci goto out; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci out: 4258c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 4268c2ecf20Sopenharmony_ci return rc; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* 4308c2ecf20Sopenharmony_ci * Returns true if there is a scsi end device 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_cistatic inline int 4338c2ecf20Sopenharmony_cimptsas_is_end_device(struct mptsas_devinfo * attached) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci if ((attached->sas_address) && 4368c2ecf20Sopenharmony_ci (attached->device_info & 4378c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_END_DEVICE) && 4388c2ecf20Sopenharmony_ci ((attached->device_info & 4398c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SSP_TARGET) | 4408c2ecf20Sopenharmony_ci (attached->device_info & 4418c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET) | 4428c2ecf20Sopenharmony_ci (attached->device_info & 4438c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE))) 4448c2ecf20Sopenharmony_ci return 1; 4458c2ecf20Sopenharmony_ci else 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci/* no mutex */ 4508c2ecf20Sopenharmony_cistatic void 4518c2ecf20Sopenharmony_cimptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 4548c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 4558c2ecf20Sopenharmony_ci u8 i; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (!port_details) 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci port_info = port_details->port_info; 4618c2ecf20Sopenharmony_ci phy_info = port_info->phy_info; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " 4648c2ecf20Sopenharmony_ci "bitmask=0x%016llX\n", ioc->name, __func__, port_details, 4658c2ecf20Sopenharmony_ci port_details->num_phys, (unsigned long long) 4668c2ecf20Sopenharmony_ci port_details->phy_bitmask)); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, phy_info++) { 4698c2ecf20Sopenharmony_ci if(phy_info->port_details != port_details) 4708c2ecf20Sopenharmony_ci continue; 4718c2ecf20Sopenharmony_ci memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); 4728c2ecf20Sopenharmony_ci mptsas_set_rphy(ioc, phy_info, NULL); 4738c2ecf20Sopenharmony_ci phy_info->port_details = NULL; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci kfree(port_details); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic inline struct sas_rphy * 4798c2ecf20Sopenharmony_cimptsas_get_rphy(struct mptsas_phyinfo *phy_info) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci if (phy_info->port_details) 4828c2ecf20Sopenharmony_ci return phy_info->port_details->rphy; 4838c2ecf20Sopenharmony_ci else 4848c2ecf20Sopenharmony_ci return NULL; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic inline void 4888c2ecf20Sopenharmony_cimptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci if (phy_info->port_details) { 4918c2ecf20Sopenharmony_ci phy_info->port_details->rphy = rphy; 4928c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", 4938c2ecf20Sopenharmony_ci ioc->name, rphy)); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (rphy) { 4978c2ecf20Sopenharmony_ci dsaswideprintk(ioc, dev_printk(KERN_DEBUG, 4988c2ecf20Sopenharmony_ci &rphy->dev, MYIOC_s_FMT "add:", ioc->name)); 4998c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n", 5008c2ecf20Sopenharmony_ci ioc->name, rphy, rphy->dev.release)); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic inline struct sas_port * 5058c2ecf20Sopenharmony_cimptsas_get_port(struct mptsas_phyinfo *phy_info) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci if (phy_info->port_details) 5088c2ecf20Sopenharmony_ci return phy_info->port_details->port; 5098c2ecf20Sopenharmony_ci else 5108c2ecf20Sopenharmony_ci return NULL; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic inline void 5148c2ecf20Sopenharmony_cimptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci if (phy_info->port_details) 5178c2ecf20Sopenharmony_ci phy_info->port_details->port = port; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (port) { 5208c2ecf20Sopenharmony_ci dsaswideprintk(ioc, dev_printk(KERN_DEBUG, 5218c2ecf20Sopenharmony_ci &port->dev, MYIOC_s_FMT "add:", ioc->name)); 5228c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n", 5238c2ecf20Sopenharmony_ci ioc->name, port, port->dev.release)); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic inline struct scsi_target * 5288c2ecf20Sopenharmony_cimptsas_get_starget(struct mptsas_phyinfo *phy_info) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci if (phy_info->port_details) 5318c2ecf20Sopenharmony_ci return phy_info->port_details->starget; 5328c2ecf20Sopenharmony_ci else 5338c2ecf20Sopenharmony_ci return NULL; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic inline void 5378c2ecf20Sopenharmony_cimptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * 5388c2ecf20Sopenharmony_cistarget) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci if (phy_info->port_details) 5418c2ecf20Sopenharmony_ci phy_info->port_details->starget = starget; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci/** 5458c2ecf20Sopenharmony_ci * mptsas_add_device_component - 5468c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 5478c2ecf20Sopenharmony_ci * @channel: fw mapped id's 5488c2ecf20Sopenharmony_ci * @id: 5498c2ecf20Sopenharmony_ci * @sas_address: 5508c2ecf20Sopenharmony_ci * @device_info: 5518c2ecf20Sopenharmony_ci * 5528c2ecf20Sopenharmony_ci **/ 5538c2ecf20Sopenharmony_cistatic void 5548c2ecf20Sopenharmony_cimptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, 5558c2ecf20Sopenharmony_ci u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 5588c2ecf20Sopenharmony_ci struct scsi_device *sdev; 5598c2ecf20Sopenharmony_ci struct scsi_target *starget; 5608c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* 5638c2ecf20Sopenharmony_ci * Delete all matching devices out of the list 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 5668c2ecf20Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 5678c2ecf20Sopenharmony_ci list) { 5688c2ecf20Sopenharmony_ci if (!sas_info->is_logical_volume && 5698c2ecf20Sopenharmony_ci (sas_info->sas_address == sas_address || 5708c2ecf20Sopenharmony_ci (sas_info->fw.channel == channel && 5718c2ecf20Sopenharmony_ci sas_info->fw.id == id))) { 5728c2ecf20Sopenharmony_ci list_del(&sas_info->list); 5738c2ecf20Sopenharmony_ci kfree(sas_info); 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); 5788c2ecf20Sopenharmony_ci if (!sas_info) 5798c2ecf20Sopenharmony_ci goto out; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* 5828c2ecf20Sopenharmony_ci * Set Firmware mapping 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci sas_info->fw.id = id; 5858c2ecf20Sopenharmony_ci sas_info->fw.channel = channel; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci sas_info->sas_address = sas_address; 5888c2ecf20Sopenharmony_ci sas_info->device_info = device_info; 5898c2ecf20Sopenharmony_ci sas_info->slot = slot; 5908c2ecf20Sopenharmony_ci sas_info->enclosure_logical_id = enclosure_logical_id; 5918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sas_info->list); 5928c2ecf20Sopenharmony_ci list_add_tail(&sas_info->list, &ioc->sas_device_info_list); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* 5958c2ecf20Sopenharmony_ci * Set OS mapping 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 5988c2ecf20Sopenharmony_ci starget = scsi_target(sdev); 5998c2ecf20Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 6008c2ecf20Sopenharmony_ci if (rphy->identify.sas_address == sas_address) { 6018c2ecf20Sopenharmony_ci sas_info->os.id = starget->id; 6028c2ecf20Sopenharmony_ci sas_info->os.channel = starget->channel; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci out: 6078c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 6088c2ecf20Sopenharmony_ci return; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/** 6128c2ecf20Sopenharmony_ci * mptsas_add_device_component_by_fw - 6138c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 6148c2ecf20Sopenharmony_ci * @channel: fw mapped id's 6158c2ecf20Sopenharmony_ci * @id: 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci **/ 6188c2ecf20Sopenharmony_cistatic void 6198c2ecf20Sopenharmony_cimptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct mptsas_devinfo sas_device; 6228c2ecf20Sopenharmony_ci struct mptsas_enclosure enclosure_info; 6238c2ecf20Sopenharmony_ci int rc; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci rc = mptsas_sas_device_pg0(ioc, &sas_device, 6268c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 6278c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 6288c2ecf20Sopenharmony_ci (channel << 8) + id); 6298c2ecf20Sopenharmony_ci if (rc) 6308c2ecf20Sopenharmony_ci return; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); 6338c2ecf20Sopenharmony_ci mptsas_sas_enclosure_pg0(ioc, &enclosure_info, 6348c2ecf20Sopenharmony_ci (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << 6358c2ecf20Sopenharmony_ci MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), 6368c2ecf20Sopenharmony_ci sas_device.handle_enclosure); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci mptsas_add_device_component(ioc, sas_device.channel, 6398c2ecf20Sopenharmony_ci sas_device.id, sas_device.sas_address, sas_device.device_info, 6408c2ecf20Sopenharmony_ci sas_device.slot, enclosure_info.enclosure_logical_id); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list 6458c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 6468c2ecf20Sopenharmony_ci * @channel: fw mapped id's 6478c2ecf20Sopenharmony_ci * @id: 6488c2ecf20Sopenharmony_ci * 6498c2ecf20Sopenharmony_ci **/ 6508c2ecf20Sopenharmony_cistatic void 6518c2ecf20Sopenharmony_cimptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, 6528c2ecf20Sopenharmony_ci struct scsi_target *starget) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 6558c2ecf20Sopenharmony_ci ConfigPageHeader_t hdr; 6568c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 6578c2ecf20Sopenharmony_ci pRaidVolumePage0_t buffer = NULL; 6588c2ecf20Sopenharmony_ci int i; 6598c2ecf20Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 6608c2ecf20Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 6638c2ecf20Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 6648c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; 6658c2ecf20Sopenharmony_ci /* assumption that all volumes on channel = 0 */ 6668c2ecf20Sopenharmony_ci cfg.pageAddr = starget->id; 6678c2ecf20Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 6688c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 6698c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 6728c2ecf20Sopenharmony_ci goto out; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (!hdr.PageLength) 6758c2ecf20Sopenharmony_ci goto out; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, 6788c2ecf20Sopenharmony_ci &dma_handle); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!buffer) 6818c2ecf20Sopenharmony_ci goto out; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 6848c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 6878c2ecf20Sopenharmony_ci goto out; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (!buffer->NumPhysDisks) 6908c2ecf20Sopenharmony_ci goto out; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* 6938c2ecf20Sopenharmony_ci * Adding entry for hidden components 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci for (i = 0; i < buffer->NumPhysDisks; i++) { 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (mpt_raid_phys_disk_pg0(ioc, 6988c2ecf20Sopenharmony_ci buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) 6998c2ecf20Sopenharmony_ci continue; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, 7028c2ecf20Sopenharmony_ci phys_disk.PhysDiskID); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 7058c2ecf20Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, 7068c2ecf20Sopenharmony_ci list) { 7078c2ecf20Sopenharmony_ci if (!sas_info->is_logical_volume && 7088c2ecf20Sopenharmony_ci (sas_info->fw.channel == phys_disk.PhysDiskBus && 7098c2ecf20Sopenharmony_ci sas_info->fw.id == phys_disk.PhysDiskID)) { 7108c2ecf20Sopenharmony_ci sas_info->is_hidden_raid_component = 1; 7118c2ecf20Sopenharmony_ci sas_info->volume_id = starget->id; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * Delete all matching devices out of the list 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 7228c2ecf20Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 7238c2ecf20Sopenharmony_ci list) { 7248c2ecf20Sopenharmony_ci if (sas_info->is_logical_volume && sas_info->fw.id == 7258c2ecf20Sopenharmony_ci starget->id) { 7268c2ecf20Sopenharmony_ci list_del(&sas_info->list); 7278c2ecf20Sopenharmony_ci kfree(sas_info); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); 7328c2ecf20Sopenharmony_ci if (sas_info) { 7338c2ecf20Sopenharmony_ci sas_info->fw.id = starget->id; 7348c2ecf20Sopenharmony_ci sas_info->os.id = starget->id; 7358c2ecf20Sopenharmony_ci sas_info->os.channel = starget->channel; 7368c2ecf20Sopenharmony_ci sas_info->is_logical_volume = 1; 7378c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sas_info->list); 7388c2ecf20Sopenharmony_ci list_add_tail(&sas_info->list, &ioc->sas_device_info_list); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci out: 7438c2ecf20Sopenharmony_ci if (buffer) 7448c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, 7458c2ecf20Sopenharmony_ci dma_handle); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci/** 7498c2ecf20Sopenharmony_ci * mptsas_add_device_component_starget - 7508c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 7518c2ecf20Sopenharmony_ci * @starget: 7528c2ecf20Sopenharmony_ci * 7538c2ecf20Sopenharmony_ci **/ 7548c2ecf20Sopenharmony_cistatic void 7558c2ecf20Sopenharmony_cimptsas_add_device_component_starget(MPT_ADAPTER *ioc, 7568c2ecf20Sopenharmony_ci struct scsi_target *starget) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci VirtTarget *vtarget; 7598c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 7608c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 7618c2ecf20Sopenharmony_ci struct mptsas_enclosure enclosure_info; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 7648c2ecf20Sopenharmony_ci vtarget = starget->hostdata; 7658c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 7668c2ecf20Sopenharmony_ci rphy->identify.sas_address); 7678c2ecf20Sopenharmony_ci if (!phy_info) 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); 7718c2ecf20Sopenharmony_ci mptsas_sas_enclosure_pg0(ioc, &enclosure_info, 7728c2ecf20Sopenharmony_ci (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << 7738c2ecf20Sopenharmony_ci MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), 7748c2ecf20Sopenharmony_ci phy_info->attached.handle_enclosure); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci mptsas_add_device_component(ioc, phy_info->attached.channel, 7778c2ecf20Sopenharmony_ci phy_info->attached.id, phy_info->attached.sas_address, 7788c2ecf20Sopenharmony_ci phy_info->attached.device_info, 7798c2ecf20Sopenharmony_ci phy_info->attached.slot, enclosure_info.enclosure_logical_id); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/** 7838c2ecf20Sopenharmony_ci * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached 7848c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 7858c2ecf20Sopenharmony_ci * @channel: os mapped id's 7868c2ecf20Sopenharmony_ci * @id: 7878c2ecf20Sopenharmony_ci * 7888c2ecf20Sopenharmony_ci **/ 7898c2ecf20Sopenharmony_cistatic void 7908c2ecf20Sopenharmony_cimptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * Set is_cached flag 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 7988c2ecf20Sopenharmony_ci list) { 7998c2ecf20Sopenharmony_ci if (sas_info->os.channel == channel && sas_info->os.id == id) 8008c2ecf20Sopenharmony_ci sas_info->is_cached = 1; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/** 8058c2ecf20Sopenharmony_ci * mptsas_del_device_components - Cleaning the list 8068c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci **/ 8098c2ecf20Sopenharmony_cistatic void 8108c2ecf20Sopenharmony_cimptsas_del_device_components(MPT_ADAPTER *ioc) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct mptsas_device_info *sas_info, *next; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 8158c2ecf20Sopenharmony_ci list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, 8168c2ecf20Sopenharmony_ci list) { 8178c2ecf20Sopenharmony_ci list_del(&sas_info->list); 8188c2ecf20Sopenharmony_ci kfree(sas_info); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci/* 8258c2ecf20Sopenharmony_ci * mptsas_setup_wide_ports 8268c2ecf20Sopenharmony_ci * 8278c2ecf20Sopenharmony_ci * Updates for new and existing narrow/wide port configuration 8288c2ecf20Sopenharmony_ci * in the sas_topology 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_cistatic void 8318c2ecf20Sopenharmony_cimptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct mptsas_portinfo_details * port_details; 8348c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info, *phy_info_cmp; 8358c2ecf20Sopenharmony_ci u64 sas_address; 8368c2ecf20Sopenharmony_ci int i, j; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci phy_info = port_info->phy_info; 8418c2ecf20Sopenharmony_ci for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { 8428c2ecf20Sopenharmony_ci if (phy_info->attached.handle) 8438c2ecf20Sopenharmony_ci continue; 8448c2ecf20Sopenharmony_ci port_details = phy_info->port_details; 8458c2ecf20Sopenharmony_ci if (!port_details) 8468c2ecf20Sopenharmony_ci continue; 8478c2ecf20Sopenharmony_ci if (port_details->num_phys < 2) 8488c2ecf20Sopenharmony_ci continue; 8498c2ecf20Sopenharmony_ci /* 8508c2ecf20Sopenharmony_ci * Removing a phy from a port, letting the last 8518c2ecf20Sopenharmony_ci * phy be removed by firmware events. 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 8548c2ecf20Sopenharmony_ci "%s: [%p]: deleting phy = %d\n", 8558c2ecf20Sopenharmony_ci ioc->name, __func__, port_details, i)); 8568c2ecf20Sopenharmony_ci port_details->num_phys--; 8578c2ecf20Sopenharmony_ci port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); 8588c2ecf20Sopenharmony_ci memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); 8598c2ecf20Sopenharmony_ci if (phy_info->phy) { 8608c2ecf20Sopenharmony_ci devtprintk(ioc, dev_printk(KERN_DEBUG, 8618c2ecf20Sopenharmony_ci &phy_info->phy->dev, MYIOC_s_FMT 8628c2ecf20Sopenharmony_ci "delete phy %d, phy-obj (0x%p)\n", ioc->name, 8638c2ecf20Sopenharmony_ci phy_info->phy_id, phy_info->phy)); 8648c2ecf20Sopenharmony_ci sas_port_delete_phy(port_details->port, phy_info->phy); 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci phy_info->port_details = NULL; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* 8708c2ecf20Sopenharmony_ci * Populate and refresh the tree 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci phy_info = port_info->phy_info; 8738c2ecf20Sopenharmony_ci for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { 8748c2ecf20Sopenharmony_ci sas_address = phy_info->attached.sas_address; 8758c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", 8768c2ecf20Sopenharmony_ci ioc->name, i, (unsigned long long)sas_address)); 8778c2ecf20Sopenharmony_ci if (!sas_address) 8788c2ecf20Sopenharmony_ci continue; 8798c2ecf20Sopenharmony_ci port_details = phy_info->port_details; 8808c2ecf20Sopenharmony_ci /* 8818c2ecf20Sopenharmony_ci * Forming a port 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_ci if (!port_details) { 8848c2ecf20Sopenharmony_ci port_details = kzalloc(sizeof(struct 8858c2ecf20Sopenharmony_ci mptsas_portinfo_details), GFP_KERNEL); 8868c2ecf20Sopenharmony_ci if (!port_details) 8878c2ecf20Sopenharmony_ci goto out; 8888c2ecf20Sopenharmony_ci port_details->num_phys = 1; 8898c2ecf20Sopenharmony_ci port_details->port_info = port_info; 8908c2ecf20Sopenharmony_ci if (phy_info->phy_id < 64 ) 8918c2ecf20Sopenharmony_ci port_details->phy_bitmask |= 8928c2ecf20Sopenharmony_ci (1 << phy_info->phy_id); 8938c2ecf20Sopenharmony_ci phy_info->sas_port_add_phy=1; 8948c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" 8958c2ecf20Sopenharmony_ci "phy_id=%d sas_address=0x%018llX\n", 8968c2ecf20Sopenharmony_ci ioc->name, i, (unsigned long long)sas_address)); 8978c2ecf20Sopenharmony_ci phy_info->port_details = port_details; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (i == port_info->num_phys - 1) 9018c2ecf20Sopenharmony_ci continue; 9028c2ecf20Sopenharmony_ci phy_info_cmp = &port_info->phy_info[i + 1]; 9038c2ecf20Sopenharmony_ci for (j = i + 1 ; j < port_info->num_phys ; j++, 9048c2ecf20Sopenharmony_ci phy_info_cmp++) { 9058c2ecf20Sopenharmony_ci if (!phy_info_cmp->attached.sas_address) 9068c2ecf20Sopenharmony_ci continue; 9078c2ecf20Sopenharmony_ci if (sas_address != phy_info_cmp->attached.sas_address) 9088c2ecf20Sopenharmony_ci continue; 9098c2ecf20Sopenharmony_ci if (phy_info_cmp->port_details == port_details ) 9108c2ecf20Sopenharmony_ci continue; 9118c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 9128c2ecf20Sopenharmony_ci "\t\tphy_id=%d sas_address=0x%018llX\n", 9138c2ecf20Sopenharmony_ci ioc->name, j, (unsigned long long) 9148c2ecf20Sopenharmony_ci phy_info_cmp->attached.sas_address)); 9158c2ecf20Sopenharmony_ci if (phy_info_cmp->port_details) { 9168c2ecf20Sopenharmony_ci port_details->rphy = 9178c2ecf20Sopenharmony_ci mptsas_get_rphy(phy_info_cmp); 9188c2ecf20Sopenharmony_ci port_details->port = 9198c2ecf20Sopenharmony_ci mptsas_get_port(phy_info_cmp); 9208c2ecf20Sopenharmony_ci port_details->starget = 9218c2ecf20Sopenharmony_ci mptsas_get_starget(phy_info_cmp); 9228c2ecf20Sopenharmony_ci port_details->num_phys = 9238c2ecf20Sopenharmony_ci phy_info_cmp->port_details->num_phys; 9248c2ecf20Sopenharmony_ci if (!phy_info_cmp->port_details->num_phys) 9258c2ecf20Sopenharmony_ci kfree(phy_info_cmp->port_details); 9268c2ecf20Sopenharmony_ci } else 9278c2ecf20Sopenharmony_ci phy_info_cmp->sas_port_add_phy=1; 9288c2ecf20Sopenharmony_ci /* 9298c2ecf20Sopenharmony_ci * Adding a phy to a port 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_ci phy_info_cmp->port_details = port_details; 9328c2ecf20Sopenharmony_ci if (phy_info_cmp->phy_id < 64 ) 9338c2ecf20Sopenharmony_ci port_details->phy_bitmask |= 9348c2ecf20Sopenharmony_ci (1 << phy_info_cmp->phy_id); 9358c2ecf20Sopenharmony_ci port_details->num_phys++; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci out: 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 9428c2ecf20Sopenharmony_ci port_details = port_info->phy_info[i].port_details; 9438c2ecf20Sopenharmony_ci if (!port_details) 9448c2ecf20Sopenharmony_ci continue; 9458c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 9468c2ecf20Sopenharmony_ci "%s: [%p]: phy_id=%02d num_phys=%02d " 9478c2ecf20Sopenharmony_ci "bitmask=0x%016llX\n", ioc->name, __func__, 9488c2ecf20Sopenharmony_ci port_details, i, port_details->num_phys, 9498c2ecf20Sopenharmony_ci (unsigned long long)port_details->phy_bitmask)); 9508c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", 9518c2ecf20Sopenharmony_ci ioc->name, port_details->port, port_details->rphy)); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk("\n")); 9548c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/** 9588c2ecf20Sopenharmony_ci * csmisas_find_vtarget 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * @ioc 9618c2ecf20Sopenharmony_ci * @volume_id 9628c2ecf20Sopenharmony_ci * @volume_bus 9638c2ecf20Sopenharmony_ci * 9648c2ecf20Sopenharmony_ci **/ 9658c2ecf20Sopenharmony_cistatic VirtTarget * 9668c2ecf20Sopenharmony_cimptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) 9678c2ecf20Sopenharmony_ci{ 9688c2ecf20Sopenharmony_ci struct scsi_device *sdev; 9698c2ecf20Sopenharmony_ci VirtDevice *vdevice; 9708c2ecf20Sopenharmony_ci VirtTarget *vtarget = NULL; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 9738c2ecf20Sopenharmony_ci vdevice = sdev->hostdata; 9748c2ecf20Sopenharmony_ci if ((vdevice == NULL) || 9758c2ecf20Sopenharmony_ci (vdevice->vtarget == NULL)) 9768c2ecf20Sopenharmony_ci continue; 9778c2ecf20Sopenharmony_ci if ((vdevice->vtarget->tflags & 9788c2ecf20Sopenharmony_ci MPT_TARGET_FLAGS_RAID_COMPONENT || 9798c2ecf20Sopenharmony_ci vdevice->vtarget->raidVolume)) 9808c2ecf20Sopenharmony_ci continue; 9818c2ecf20Sopenharmony_ci if (vdevice->vtarget->id == id && 9828c2ecf20Sopenharmony_ci vdevice->vtarget->channel == channel) 9838c2ecf20Sopenharmony_ci vtarget = vdevice->vtarget; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci return vtarget; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic void 9898c2ecf20Sopenharmony_cimptsas_queue_device_delete(MPT_ADAPTER *ioc, 9908c2ecf20Sopenharmony_ci MpiEventDataSasDeviceStatusChange_t *sas_event_data) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct fw_event_work *fw_event; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci fw_event = kzalloc(sizeof(*fw_event) + 9958c2ecf20Sopenharmony_ci sizeof(MpiEventDataSasDeviceStatusChange_t), 9968c2ecf20Sopenharmony_ci GFP_ATOMIC); 9978c2ecf20Sopenharmony_ci if (!fw_event) { 9988c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", 9998c2ecf20Sopenharmony_ci ioc->name, __func__, __LINE__); 10008c2ecf20Sopenharmony_ci return; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci memcpy(fw_event->event_data, sas_event_data, 10038c2ecf20Sopenharmony_ci sizeof(MpiEventDataSasDeviceStatusChange_t)); 10048c2ecf20Sopenharmony_ci fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; 10058c2ecf20Sopenharmony_ci fw_event->ioc = ioc; 10068c2ecf20Sopenharmony_ci mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic void 10108c2ecf20Sopenharmony_cimptsas_queue_rescan(MPT_ADAPTER *ioc) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci struct fw_event_work *fw_event; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci fw_event = kzalloc(sizeof(*fw_event), GFP_ATOMIC); 10158c2ecf20Sopenharmony_ci if (!fw_event) { 10168c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", 10178c2ecf20Sopenharmony_ci ioc->name, __func__, __LINE__); 10188c2ecf20Sopenharmony_ci return; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci fw_event->event = -1; 10218c2ecf20Sopenharmony_ci fw_event->ioc = ioc; 10228c2ecf20Sopenharmony_ci mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci/** 10278c2ecf20Sopenharmony_ci * mptsas_target_reset 10288c2ecf20Sopenharmony_ci * 10298c2ecf20Sopenharmony_ci * Issues TARGET_RESET to end device using handshaking method 10308c2ecf20Sopenharmony_ci * 10318c2ecf20Sopenharmony_ci * @ioc 10328c2ecf20Sopenharmony_ci * @channel 10338c2ecf20Sopenharmony_ci * @id 10348c2ecf20Sopenharmony_ci * 10358c2ecf20Sopenharmony_ci * Returns (1) success 10368c2ecf20Sopenharmony_ci * (0) failure 10378c2ecf20Sopenharmony_ci * 10388c2ecf20Sopenharmony_ci **/ 10398c2ecf20Sopenharmony_cistatic int 10408c2ecf20Sopenharmony_cimptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 10438c2ecf20Sopenharmony_ci SCSITaskMgmt_t *pScsiTm; 10448c2ecf20Sopenharmony_ci if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); 10498c2ecf20Sopenharmony_ci if (mf == NULL) { 10508c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT 10518c2ecf20Sopenharmony_ci "%s, no msg frames @%d!!\n", ioc->name, 10528c2ecf20Sopenharmony_ci __func__, __LINE__)); 10538c2ecf20Sopenharmony_ci goto out_fail; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", 10578c2ecf20Sopenharmony_ci ioc->name, mf)); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* Format the Request 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_ci pScsiTm = (SCSITaskMgmt_t *) mf; 10628c2ecf20Sopenharmony_ci memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); 10638c2ecf20Sopenharmony_ci pScsiTm->TargetID = id; 10648c2ecf20Sopenharmony_ci pScsiTm->Bus = channel; 10658c2ecf20Sopenharmony_ci pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 10668c2ecf20Sopenharmony_ci pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 10678c2ecf20Sopenharmony_ci pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 10728c2ecf20Sopenharmony_ci "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", 10738c2ecf20Sopenharmony_ci ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return 1; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci out_fail: 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci mpt_clear_taskmgmt_in_progress_flag(ioc); 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic void 10868c2ecf20Sopenharmony_cimptsas_block_io_sdev(struct scsi_device *sdev, void *data) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci scsi_device_set_state(sdev, SDEV_BLOCK); 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic void 10928c2ecf20Sopenharmony_cimptsas_block_io_starget(struct scsi_target *starget) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci if (starget) 10958c2ecf20Sopenharmony_ci starget_for_each_device(starget, NULL, mptsas_block_io_sdev); 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci/** 10998c2ecf20Sopenharmony_ci * mptsas_target_reset_queue 11008c2ecf20Sopenharmony_ci * 11018c2ecf20Sopenharmony_ci * Receive request for TARGET_RESET after receiving an firmware 11028c2ecf20Sopenharmony_ci * event NOT_RESPONDING_EVENT, then put command in link list 11038c2ecf20Sopenharmony_ci * and queue if task_queue already in use. 11048c2ecf20Sopenharmony_ci * 11058c2ecf20Sopenharmony_ci * @ioc 11068c2ecf20Sopenharmony_ci * @sas_event_data 11078c2ecf20Sopenharmony_ci * 11088c2ecf20Sopenharmony_ci **/ 11098c2ecf20Sopenharmony_cistatic void 11108c2ecf20Sopenharmony_cimptsas_target_reset_queue(MPT_ADAPTER *ioc, 11118c2ecf20Sopenharmony_ci EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 11148c2ecf20Sopenharmony_ci VirtTarget *vtarget = NULL; 11158c2ecf20Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list; 11168c2ecf20Sopenharmony_ci u8 id, channel; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci id = sas_event_data->TargetID; 11198c2ecf20Sopenharmony_ci channel = sas_event_data->Bus; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, channel, id); 11228c2ecf20Sopenharmony_ci if (vtarget) { 11238c2ecf20Sopenharmony_ci mptsas_block_io_starget(vtarget->starget); 11248c2ecf20Sopenharmony_ci vtarget->deleted = 1; /* block IO */ 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), 11288c2ecf20Sopenharmony_ci GFP_ATOMIC); 11298c2ecf20Sopenharmony_ci if (!target_reset_list) { 11308c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT 11318c2ecf20Sopenharmony_ci "%s, failed to allocate mem @%d..!!\n", 11328c2ecf20Sopenharmony_ci ioc->name, __func__, __LINE__)); 11338c2ecf20Sopenharmony_ci return; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci memcpy(&target_reset_list->sas_event_data, sas_event_data, 11378c2ecf20Sopenharmony_ci sizeof(*sas_event_data)); 11388c2ecf20Sopenharmony_ci list_add_tail(&target_reset_list->list, &hd->target_reset_list); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci target_reset_list->time_count = jiffies; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (mptsas_target_reset(ioc, channel, id)) { 11438c2ecf20Sopenharmony_ci target_reset_list->target_reset_issued = 1; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci/** 11488c2ecf20Sopenharmony_ci * mptsas_schedule_target_reset- send pending target reset 11498c2ecf20Sopenharmony_ci * @iocp: per adapter object 11508c2ecf20Sopenharmony_ci * 11518c2ecf20Sopenharmony_ci * This function will delete scheduled target reset from the list and 11528c2ecf20Sopenharmony_ci * try to send next target reset. This will be called from completion 11538c2ecf20Sopenharmony_ci * context of any Task management command. 11548c2ecf20Sopenharmony_ci */ 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_civoid 11578c2ecf20Sopenharmony_cimptsas_schedule_target_reset(void *iocp) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp); 11608c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 11618c2ecf20Sopenharmony_ci struct list_head *head = &hd->target_reset_list; 11628c2ecf20Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list; 11638c2ecf20Sopenharmony_ci u8 id, channel; 11648c2ecf20Sopenharmony_ci /* 11658c2ecf20Sopenharmony_ci * issue target reset to next device in the queue 11668c2ecf20Sopenharmony_ci */ 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (list_empty(head)) 11698c2ecf20Sopenharmony_ci return; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci target_reset_list = list_entry(head->next, 11728c2ecf20Sopenharmony_ci struct mptsas_target_reset_event, list); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci id = target_reset_list->sas_event_data.TargetID; 11758c2ecf20Sopenharmony_ci channel = target_reset_list->sas_event_data.Bus; 11768c2ecf20Sopenharmony_ci target_reset_list->time_count = jiffies; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (mptsas_target_reset(ioc, channel, id)) 11798c2ecf20Sopenharmony_ci target_reset_list->target_reset_issued = 1; 11808c2ecf20Sopenharmony_ci return; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci/** 11858c2ecf20Sopenharmony_ci * mptsas_taskmgmt_complete - complete SAS task management function 11868c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 11878c2ecf20Sopenharmony_ci * 11888c2ecf20Sopenharmony_ci * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work 11898c2ecf20Sopenharmony_ci * queue to finish off removing device from upper layers. then send next 11908c2ecf20Sopenharmony_ci * TARGET_RESET in the queue. 11918c2ecf20Sopenharmony_ci **/ 11928c2ecf20Sopenharmony_cistatic int 11938c2ecf20Sopenharmony_cimptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 11968c2ecf20Sopenharmony_ci struct list_head *head = &hd->target_reset_list; 11978c2ecf20Sopenharmony_ci u8 id, channel; 11988c2ecf20Sopenharmony_ci struct mptsas_target_reset_event *target_reset_list; 11998c2ecf20Sopenharmony_ci SCSITaskMgmtReply_t *pScsiTmReply; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " 12028c2ecf20Sopenharmony_ci "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci pScsiTmReply = (SCSITaskMgmtReply_t *)mr; 12058c2ecf20Sopenharmony_ci if (!pScsiTmReply) 12068c2ecf20Sopenharmony_ci return 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 12098c2ecf20Sopenharmony_ci "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" 12108c2ecf20Sopenharmony_ci "\ttask_type = 0x%02X, iocstatus = 0x%04X " 12118c2ecf20Sopenharmony_ci "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " 12128c2ecf20Sopenharmony_ci "term_cmnds = %d\n", ioc->name, 12138c2ecf20Sopenharmony_ci pScsiTmReply->Bus, pScsiTmReply->TargetID, 12148c2ecf20Sopenharmony_ci pScsiTmReply->TaskType, 12158c2ecf20Sopenharmony_ci le16_to_cpu(pScsiTmReply->IOCStatus), 12168c2ecf20Sopenharmony_ci le32_to_cpu(pScsiTmReply->IOCLogInfo), 12178c2ecf20Sopenharmony_ci pScsiTmReply->ResponseCode, 12188c2ecf20Sopenharmony_ci le32_to_cpu(pScsiTmReply->TerminationCount))); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (pScsiTmReply->ResponseCode) 12218c2ecf20Sopenharmony_ci mptscsih_taskmgmt_response_code(ioc, 12228c2ecf20Sopenharmony_ci pScsiTmReply->ResponseCode); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (pScsiTmReply->TaskType == 12258c2ecf20Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == 12268c2ecf20Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) { 12278c2ecf20Sopenharmony_ci ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; 12288c2ecf20Sopenharmony_ci ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; 12298c2ecf20Sopenharmony_ci memcpy(ioc->taskmgmt_cmds.reply, mr, 12308c2ecf20Sopenharmony_ci min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); 12318c2ecf20Sopenharmony_ci if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { 12328c2ecf20Sopenharmony_ci ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; 12338c2ecf20Sopenharmony_ci complete(&ioc->taskmgmt_cmds.done); 12348c2ecf20Sopenharmony_ci return 1; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci mpt_clear_taskmgmt_in_progress_flag(ioc); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (list_empty(head)) 12428c2ecf20Sopenharmony_ci return 1; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci target_reset_list = list_entry(head->next, 12458c2ecf20Sopenharmony_ci struct mptsas_target_reset_event, list); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 12488c2ecf20Sopenharmony_ci "TaskMgmt: completed (%d seconds)\n", 12498c2ecf20Sopenharmony_ci ioc->name, jiffies_to_msecs(jiffies - 12508c2ecf20Sopenharmony_ci target_reset_list->time_count)/1000)); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci id = pScsiTmReply->TargetID; 12538c2ecf20Sopenharmony_ci channel = pScsiTmReply->Bus; 12548c2ecf20Sopenharmony_ci target_reset_list->time_count = jiffies; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* 12578c2ecf20Sopenharmony_ci * retry target reset 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_ci if (!target_reset_list->target_reset_issued) { 12608c2ecf20Sopenharmony_ci if (mptsas_target_reset(ioc, channel, id)) 12618c2ecf20Sopenharmony_ci target_reset_list->target_reset_issued = 1; 12628c2ecf20Sopenharmony_ci return 1; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* 12668c2ecf20Sopenharmony_ci * enable work queue to remove device from upper layers 12678c2ecf20Sopenharmony_ci */ 12688c2ecf20Sopenharmony_ci list_del(&target_reset_list->list); 12698c2ecf20Sopenharmony_ci if (!ioc->fw_events_off) 12708c2ecf20Sopenharmony_ci mptsas_queue_device_delete(ioc, 12718c2ecf20Sopenharmony_ci &target_reset_list->sas_event_data); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci ioc->schedule_target_reset(ioc); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return 1; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci/** 12808c2ecf20Sopenharmony_ci * mptscsih_ioc_reset 12818c2ecf20Sopenharmony_ci * 12828c2ecf20Sopenharmony_ci * @ioc 12838c2ecf20Sopenharmony_ci * @reset_phase 12848c2ecf20Sopenharmony_ci * 12858c2ecf20Sopenharmony_ci **/ 12868c2ecf20Sopenharmony_cistatic int 12878c2ecf20Sopenharmony_cimptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd; 12908c2ecf20Sopenharmony_ci int rc; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci rc = mptscsih_ioc_reset(ioc, reset_phase); 12938c2ecf20Sopenharmony_ci if ((ioc->bus_type != SAS) || (!rc)) 12948c2ecf20Sopenharmony_ci return rc; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci hd = shost_priv(ioc->sh); 12978c2ecf20Sopenharmony_ci if (!hd->ioc) 12988c2ecf20Sopenharmony_ci goto out; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci switch (reset_phase) { 13018c2ecf20Sopenharmony_ci case MPT_IOC_SETUP_RESET: 13028c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 13038c2ecf20Sopenharmony_ci "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); 13048c2ecf20Sopenharmony_ci mptsas_fw_event_off(ioc); 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci case MPT_IOC_PRE_RESET: 13078c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 13088c2ecf20Sopenharmony_ci "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); 13098c2ecf20Sopenharmony_ci break; 13108c2ecf20Sopenharmony_ci case MPT_IOC_POST_RESET: 13118c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 13128c2ecf20Sopenharmony_ci "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); 13138c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { 13148c2ecf20Sopenharmony_ci ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; 13158c2ecf20Sopenharmony_ci complete(&ioc->sas_mgmt.done); 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci mptsas_cleanup_fw_event_q(ioc); 13188c2ecf20Sopenharmony_ci mptsas_queue_rescan(ioc); 13198c2ecf20Sopenharmony_ci break; 13208c2ecf20Sopenharmony_ci default: 13218c2ecf20Sopenharmony_ci break; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci out: 13258c2ecf20Sopenharmony_ci return rc; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci/** 13308c2ecf20Sopenharmony_ci * enum device_state - 13318c2ecf20Sopenharmony_ci * @DEVICE_RETRY: need to retry the TUR 13328c2ecf20Sopenharmony_ci * @DEVICE_ERROR: TUR return error, don't add device 13338c2ecf20Sopenharmony_ci * @DEVICE_READY: device can be added 13348c2ecf20Sopenharmony_ci * 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_cienum device_state{ 13378c2ecf20Sopenharmony_ci DEVICE_RETRY, 13388c2ecf20Sopenharmony_ci DEVICE_ERROR, 13398c2ecf20Sopenharmony_ci DEVICE_READY, 13408c2ecf20Sopenharmony_ci}; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic int 13438c2ecf20Sopenharmony_cimptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, 13448c2ecf20Sopenharmony_ci u32 form, u32 form_specific) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 13478c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 13488c2ecf20Sopenharmony_ci SasEnclosurePage0_t *buffer; 13498c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 13508c2ecf20Sopenharmony_ci int error; 13518c2ecf20Sopenharmony_ci __le64 le_identifier; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 13548c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; 13558c2ecf20Sopenharmony_ci hdr.PageNumber = 0; 13568c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 13578c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 13608c2ecf20Sopenharmony_ci cfg.physAddr = -1; 13618c2ecf20Sopenharmony_ci cfg.pageAddr = form + form_specific; 13628c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 13638c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 13648c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 13678c2ecf20Sopenharmony_ci if (error) 13688c2ecf20Sopenharmony_ci goto out; 13698c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 13708c2ecf20Sopenharmony_ci error = -ENXIO; 13718c2ecf20Sopenharmony_ci goto out; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 13758c2ecf20Sopenharmony_ci &dma_handle); 13768c2ecf20Sopenharmony_ci if (!buffer) { 13778c2ecf20Sopenharmony_ci error = -ENOMEM; 13788c2ecf20Sopenharmony_ci goto out; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 13828c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 13858c2ecf20Sopenharmony_ci if (error) 13868c2ecf20Sopenharmony_ci goto out_free_consistent; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* save config data */ 13898c2ecf20Sopenharmony_ci memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); 13908c2ecf20Sopenharmony_ci enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); 13918c2ecf20Sopenharmony_ci enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); 13928c2ecf20Sopenharmony_ci enclosure->flags = le16_to_cpu(buffer->Flags); 13938c2ecf20Sopenharmony_ci enclosure->num_slot = le16_to_cpu(buffer->NumSlots); 13948c2ecf20Sopenharmony_ci enclosure->start_slot = le16_to_cpu(buffer->StartSlot); 13958c2ecf20Sopenharmony_ci enclosure->start_id = buffer->StartTargetID; 13968c2ecf20Sopenharmony_ci enclosure->start_channel = buffer->StartBus; 13978c2ecf20Sopenharmony_ci enclosure->sep_id = buffer->SEPTargetID; 13988c2ecf20Sopenharmony_ci enclosure->sep_channel = buffer->SEPBus; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci out_free_consistent: 14018c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 14028c2ecf20Sopenharmony_ci buffer, dma_handle); 14038c2ecf20Sopenharmony_ci out: 14048c2ecf20Sopenharmony_ci return error; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci/** 14088c2ecf20Sopenharmony_ci * mptsas_add_end_device - report a new end device to sas transport layer 14098c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 14108c2ecf20Sopenharmony_ci * @phy_info: describes attached device 14118c2ecf20Sopenharmony_ci * 14128c2ecf20Sopenharmony_ci * return (0) success (1) failure 14138c2ecf20Sopenharmony_ci * 14148c2ecf20Sopenharmony_ci **/ 14158c2ecf20Sopenharmony_cistatic int 14168c2ecf20Sopenharmony_cimptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 14198c2ecf20Sopenharmony_ci struct sas_port *port; 14208c2ecf20Sopenharmony_ci struct sas_identify identify; 14218c2ecf20Sopenharmony_ci char *ds = NULL; 14228c2ecf20Sopenharmony_ci u8 fw_id; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (!phy_info) { 14258c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 14268c2ecf20Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 14278c2ecf20Sopenharmony_ci __func__, __LINE__)); 14288c2ecf20Sopenharmony_ci return 1; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci fw_id = phy_info->attached.id; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci if (mptsas_get_rphy(phy_info)) { 14348c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 14358c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 14368c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 14378c2ecf20Sopenharmony_ci return 2; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci port = mptsas_get_port(phy_info); 14418c2ecf20Sopenharmony_ci if (!port) { 14428c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 14438c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 14448c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 14458c2ecf20Sopenharmony_ci return 3; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & 14498c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SSP_TARGET) 14508c2ecf20Sopenharmony_ci ds = "ssp"; 14518c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & 14528c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET) 14538c2ecf20Sopenharmony_ci ds = "stp"; 14548c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & 14558c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE) 14568c2ecf20Sopenharmony_ci ds = "sata"; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," 14598c2ecf20Sopenharmony_ci " phy %d, sas_addr 0x%llx\n", ioc->name, ds, 14608c2ecf20Sopenharmony_ci phy_info->attached.channel, phy_info->attached.id, 14618c2ecf20Sopenharmony_ci phy_info->attached.phy_id, (unsigned long long) 14628c2ecf20Sopenharmony_ci phy_info->attached.sas_address); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci mptsas_parse_device_info(&identify, &phy_info->attached); 14658c2ecf20Sopenharmony_ci rphy = sas_end_device_alloc(port); 14668c2ecf20Sopenharmony_ci if (!rphy) { 14678c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 14688c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 14698c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 14708c2ecf20Sopenharmony_ci return 5; /* non-fatal: an rphy can be added later */ 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci rphy->identify = identify; 14748c2ecf20Sopenharmony_ci if (sas_rphy_add(rphy)) { 14758c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 14768c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 14778c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 14788c2ecf20Sopenharmony_ci sas_rphy_free(rphy); 14798c2ecf20Sopenharmony_ci return 6; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci mptsas_set_rphy(ioc, phy_info, rphy); 14828c2ecf20Sopenharmony_ci return 0; 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci/** 14868c2ecf20Sopenharmony_ci * mptsas_del_end_device - report a deleted end device to sas transport layer 14878c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 14888c2ecf20Sopenharmony_ci * @phy_info: describes attached device 14898c2ecf20Sopenharmony_ci * 14908c2ecf20Sopenharmony_ci **/ 14918c2ecf20Sopenharmony_cistatic void 14928c2ecf20Sopenharmony_cimptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 14958c2ecf20Sopenharmony_ci struct sas_port *port; 14968c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 14978c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info_parent; 14988c2ecf20Sopenharmony_ci int i; 14998c2ecf20Sopenharmony_ci char *ds = NULL; 15008c2ecf20Sopenharmony_ci u8 fw_id; 15018c2ecf20Sopenharmony_ci u64 sas_address; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if (!phy_info) 15048c2ecf20Sopenharmony_ci return; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci fw_id = phy_info->attached.id; 15078c2ecf20Sopenharmony_ci sas_address = phy_info->attached.sas_address; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (!phy_info->port_details) { 15108c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 15118c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 15128c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 15138c2ecf20Sopenharmony_ci return; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci rphy = mptsas_get_rphy(phy_info); 15168c2ecf20Sopenharmony_ci if (!rphy) { 15178c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 15188c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 15198c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 15208c2ecf20Sopenharmony_ci return; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR 15248c2ecf20Sopenharmony_ci || phy_info->attached.device_info 15258c2ecf20Sopenharmony_ci & MPI_SAS_DEVICE_INFO_SMP_INITIATOR 15268c2ecf20Sopenharmony_ci || phy_info->attached.device_info 15278c2ecf20Sopenharmony_ci & MPI_SAS_DEVICE_INFO_STP_INITIATOR) 15288c2ecf20Sopenharmony_ci ds = "initiator"; 15298c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & 15308c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SSP_TARGET) 15318c2ecf20Sopenharmony_ci ds = "ssp"; 15328c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & 15338c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET) 15348c2ecf20Sopenharmony_ci ds = "stp"; 15358c2ecf20Sopenharmony_ci if (phy_info->attached.device_info & 15368c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE) 15378c2ecf20Sopenharmony_ci ds = "sata"; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT 15408c2ecf20Sopenharmony_ci "removing %s device: fw_channel %d, fw_id %d, phy %d," 15418c2ecf20Sopenharmony_ci "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, 15428c2ecf20Sopenharmony_ci phy_info->attached.id, phy_info->attached.phy_id, 15438c2ecf20Sopenharmony_ci (unsigned long long) sas_address); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci port = mptsas_get_port(phy_info); 15468c2ecf20Sopenharmony_ci if (!port) { 15478c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 15488c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 15498c2ecf20Sopenharmony_ci __func__, fw_id, __LINE__)); 15508c2ecf20Sopenharmony_ci return; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci port_info = phy_info->portinfo; 15538c2ecf20Sopenharmony_ci phy_info_parent = port_info->phy_info; 15548c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { 15558c2ecf20Sopenharmony_ci if (!phy_info_parent->phy) 15568c2ecf20Sopenharmony_ci continue; 15578c2ecf20Sopenharmony_ci if (phy_info_parent->attached.sas_address != 15588c2ecf20Sopenharmony_ci sas_address) 15598c2ecf20Sopenharmony_ci continue; 15608c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, 15618c2ecf20Sopenharmony_ci MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", 15628c2ecf20Sopenharmony_ci ioc->name, phy_info_parent->phy_id, 15638c2ecf20Sopenharmony_ci phy_info_parent->phy); 15648c2ecf20Sopenharmony_ci sas_port_delete_phy(port, phy_info_parent->phy); 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT 15688c2ecf20Sopenharmony_ci "delete port %d, sas_addr (0x%llx)\n", ioc->name, 15698c2ecf20Sopenharmony_ci port->port_identifier, (unsigned long long)sas_address); 15708c2ecf20Sopenharmony_ci sas_port_delete(port); 15718c2ecf20Sopenharmony_ci mptsas_set_port(ioc, phy_info, NULL); 15728c2ecf20Sopenharmony_ci mptsas_port_delete(ioc, phy_info->port_details); 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_cistatic struct mptsas_phyinfo * 15768c2ecf20Sopenharmony_cimptsas_refreshing_device_handles(MPT_ADAPTER *ioc, 15778c2ecf20Sopenharmony_ci struct mptsas_devinfo *sas_device) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 15808c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 15818c2ecf20Sopenharmony_ci int i; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 15848c2ecf20Sopenharmony_ci sas_device->sas_address); 15858c2ecf20Sopenharmony_ci if (!phy_info) 15868c2ecf20Sopenharmony_ci goto out; 15878c2ecf20Sopenharmony_ci port_info = phy_info->portinfo; 15888c2ecf20Sopenharmony_ci if (!port_info) 15898c2ecf20Sopenharmony_ci goto out; 15908c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 15918c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 15928c2ecf20Sopenharmony_ci if (port_info->phy_info[i].attached.sas_address != 15938c2ecf20Sopenharmony_ci sas_device->sas_address) 15948c2ecf20Sopenharmony_ci continue; 15958c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.channel = sas_device->channel; 15968c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.id = sas_device->id; 15978c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.sas_address = 15988c2ecf20Sopenharmony_ci sas_device->sas_address; 15998c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.handle = sas_device->handle; 16008c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.handle_parent = 16018c2ecf20Sopenharmony_ci sas_device->handle_parent; 16028c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.handle_enclosure = 16038c2ecf20Sopenharmony_ci sas_device->handle_enclosure; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 16068c2ecf20Sopenharmony_ci out: 16078c2ecf20Sopenharmony_ci return phy_info; 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci/** 16118c2ecf20Sopenharmony_ci * mptsas_firmware_event_work - work thread for processing fw events 16128c2ecf20Sopenharmony_ci * @work: work queue payload containing info describing the event 16138c2ecf20Sopenharmony_ci * Context: user 16148c2ecf20Sopenharmony_ci * 16158c2ecf20Sopenharmony_ci */ 16168c2ecf20Sopenharmony_cistatic void 16178c2ecf20Sopenharmony_cimptsas_firmware_event_work(struct work_struct *work) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct fw_event_work *fw_event = 16208c2ecf20Sopenharmony_ci container_of(work, struct fw_event_work, work.work); 16218c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = fw_event->ioc; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* special rescan topology handling */ 16248c2ecf20Sopenharmony_ci if (fw_event->event == -1) { 16258c2ecf20Sopenharmony_ci if (ioc->in_rescan) { 16268c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 16278c2ecf20Sopenharmony_ci "%s: rescan ignored as it is in progress\n", 16288c2ecf20Sopenharmony_ci ioc->name, __func__)); 16298c2ecf20Sopenharmony_ci return; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " 16328c2ecf20Sopenharmony_ci "reset\n", ioc->name, __func__)); 16338c2ecf20Sopenharmony_ci ioc->in_rescan = 1; 16348c2ecf20Sopenharmony_ci mptsas_not_responding_devices(ioc); 16358c2ecf20Sopenharmony_ci mptsas_scan_sas_topology(ioc); 16368c2ecf20Sopenharmony_ci ioc->in_rescan = 0; 16378c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 16388c2ecf20Sopenharmony_ci mptsas_fw_event_on(ioc); 16398c2ecf20Sopenharmony_ci return; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci /* events handling turned off during host reset */ 16438c2ecf20Sopenharmony_ci if (ioc->fw_events_off) { 16448c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 16458c2ecf20Sopenharmony_ci return; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " 16498c2ecf20Sopenharmony_ci "event = (0x%02x)\n", ioc->name, __func__, fw_event, 16508c2ecf20Sopenharmony_ci (fw_event->event & 0xFF))); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci switch (fw_event->event) { 16538c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 16548c2ecf20Sopenharmony_ci mptsas_send_sas_event(fw_event); 16558c2ecf20Sopenharmony_ci break; 16568c2ecf20Sopenharmony_ci case MPI_EVENT_INTEGRATED_RAID: 16578c2ecf20Sopenharmony_ci mptsas_send_raid_event(fw_event); 16588c2ecf20Sopenharmony_ci break; 16598c2ecf20Sopenharmony_ci case MPI_EVENT_IR2: 16608c2ecf20Sopenharmony_ci mptsas_send_ir2_event(fw_event); 16618c2ecf20Sopenharmony_ci break; 16628c2ecf20Sopenharmony_ci case MPI_EVENT_PERSISTENT_TABLE_FULL: 16638c2ecf20Sopenharmony_ci mptbase_sas_persist_operation(ioc, 16648c2ecf20Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 16658c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 16668c2ecf20Sopenharmony_ci break; 16678c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: 16688c2ecf20Sopenharmony_ci mptsas_broadcast_primitive_work(fw_event); 16698c2ecf20Sopenharmony_ci break; 16708c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: 16718c2ecf20Sopenharmony_ci mptsas_send_expander_event(fw_event); 16728c2ecf20Sopenharmony_ci break; 16738c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_PHY_LINK_STATUS: 16748c2ecf20Sopenharmony_ci mptsas_send_link_status_event(fw_event); 16758c2ecf20Sopenharmony_ci break; 16768c2ecf20Sopenharmony_ci case MPI_EVENT_QUEUE_FULL: 16778c2ecf20Sopenharmony_ci mptsas_handle_queue_full_event(fw_event); 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic int 16858c2ecf20Sopenharmony_cimptsas_slave_configure(struct scsi_device *sdev) 16868c2ecf20Sopenharmony_ci{ 16878c2ecf20Sopenharmony_ci struct Scsi_Host *host = sdev->host; 16888c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 16898c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 16908c2ecf20Sopenharmony_ci VirtDevice *vdevice = sdev->hostdata; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (vdevice->vtarget->deleted) { 16938c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); 16948c2ecf20Sopenharmony_ci vdevice->vtarget->deleted = 0; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* 16988c2ecf20Sopenharmony_ci * RAID volumes placed beyond the last expected port. 16998c2ecf20Sopenharmony_ci * Ignore sending sas mode pages in that case.. 17008c2ecf20Sopenharmony_ci */ 17018c2ecf20Sopenharmony_ci if (sdev->channel == MPTSAS_RAID_CHANNEL) { 17028c2ecf20Sopenharmony_ci mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); 17038c2ecf20Sopenharmony_ci goto out; 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci sas_read_port_mode_page(sdev); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci mptsas_add_device_component_starget(ioc, scsi_target(sdev)); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci out: 17118c2ecf20Sopenharmony_ci return mptscsih_slave_configure(sdev); 17128c2ecf20Sopenharmony_ci} 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cistatic int 17158c2ecf20Sopenharmony_cimptsas_target_alloc(struct scsi_target *starget) 17168c2ecf20Sopenharmony_ci{ 17178c2ecf20Sopenharmony_ci struct Scsi_Host *host = dev_to_shost(&starget->dev); 17188c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 17198c2ecf20Sopenharmony_ci VirtTarget *vtarget; 17208c2ecf20Sopenharmony_ci u8 id, channel; 17218c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 17228c2ecf20Sopenharmony_ci struct mptsas_portinfo *p; 17238c2ecf20Sopenharmony_ci int i; 17248c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); 17278c2ecf20Sopenharmony_ci if (!vtarget) 17288c2ecf20Sopenharmony_ci return -ENOMEM; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci vtarget->starget = starget; 17318c2ecf20Sopenharmony_ci vtarget->ioc_id = ioc->id; 17328c2ecf20Sopenharmony_ci vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; 17338c2ecf20Sopenharmony_ci id = starget->id; 17348c2ecf20Sopenharmony_ci channel = 0; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci /* 17378c2ecf20Sopenharmony_ci * RAID volumes placed beyond the last expected port. 17388c2ecf20Sopenharmony_ci */ 17398c2ecf20Sopenharmony_ci if (starget->channel == MPTSAS_RAID_CHANNEL) { 17408c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg2) { 17418c2ecf20Sopenharmony_ci kfree(vtarget); 17428c2ecf20Sopenharmony_ci return -ENXIO; 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 17458c2ecf20Sopenharmony_ci if (id == ioc->raid_data.pIocPg2-> 17468c2ecf20Sopenharmony_ci RaidVolume[i].VolumeID) { 17478c2ecf20Sopenharmony_ci channel = ioc->raid_data.pIocPg2-> 17488c2ecf20Sopenharmony_ci RaidVolume[i].VolumeBus; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci vtarget->raidVolume = 1; 17528c2ecf20Sopenharmony_ci goto out; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 17568c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 17578c2ecf20Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 17588c2ecf20Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 17598c2ecf20Sopenharmony_ci if (p->phy_info[i].attached.sas_address != 17608c2ecf20Sopenharmony_ci rphy->identify.sas_address) 17618c2ecf20Sopenharmony_ci continue; 17628c2ecf20Sopenharmony_ci id = p->phy_info[i].attached.id; 17638c2ecf20Sopenharmony_ci channel = p->phy_info[i].attached.channel; 17648c2ecf20Sopenharmony_ci mptsas_set_starget(&p->phy_info[i], starget); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci /* 17678c2ecf20Sopenharmony_ci * Exposing hidden raid components 17688c2ecf20Sopenharmony_ci */ 17698c2ecf20Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, channel, id)) { 17708c2ecf20Sopenharmony_ci id = mptscsih_raid_id_to_num(ioc, 17718c2ecf20Sopenharmony_ci channel, id); 17728c2ecf20Sopenharmony_ci vtarget->tflags |= 17738c2ecf20Sopenharmony_ci MPT_TARGET_FLAGS_RAID_COMPONENT; 17748c2ecf20Sopenharmony_ci p->phy_info[i].attached.phys_disk_num = id; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 17778c2ecf20Sopenharmony_ci goto out; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci kfree(vtarget); 17838c2ecf20Sopenharmony_ci return -ENXIO; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci out: 17868c2ecf20Sopenharmony_ci vtarget->id = id; 17878c2ecf20Sopenharmony_ci vtarget->channel = channel; 17888c2ecf20Sopenharmony_ci starget->hostdata = vtarget; 17898c2ecf20Sopenharmony_ci return 0; 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic void 17938c2ecf20Sopenharmony_cimptsas_target_destroy(struct scsi_target *starget) 17948c2ecf20Sopenharmony_ci{ 17958c2ecf20Sopenharmony_ci struct Scsi_Host *host = dev_to_shost(&starget->dev); 17968c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 17978c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 17988c2ecf20Sopenharmony_ci struct mptsas_portinfo *p; 17998c2ecf20Sopenharmony_ci int i; 18008c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 18018c2ecf20Sopenharmony_ci VirtTarget *vtarget; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (!starget->hostdata) 18048c2ecf20Sopenharmony_ci return; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci vtarget = starget->hostdata; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci mptsas_del_device_component_by_os(ioc, starget->channel, 18098c2ecf20Sopenharmony_ci starget->id); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci if (starget->channel == MPTSAS_RAID_CHANNEL) 18138c2ecf20Sopenharmony_ci goto out; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 18168c2ecf20Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 18178c2ecf20Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 18188c2ecf20Sopenharmony_ci if (p->phy_info[i].attached.sas_address != 18198c2ecf20Sopenharmony_ci rphy->identify.sas_address) 18208c2ecf20Sopenharmony_ci continue; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci starget_printk(KERN_INFO, starget, MYIOC_s_FMT 18238c2ecf20Sopenharmony_ci "delete device: fw_channel %d, fw_id %d, phy %d, " 18248c2ecf20Sopenharmony_ci "sas_addr 0x%llx\n", ioc->name, 18258c2ecf20Sopenharmony_ci p->phy_info[i].attached.channel, 18268c2ecf20Sopenharmony_ci p->phy_info[i].attached.id, 18278c2ecf20Sopenharmony_ci p->phy_info[i].attached.phy_id, (unsigned long long) 18288c2ecf20Sopenharmony_ci p->phy_info[i].attached.sas_address); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci mptsas_set_starget(&p->phy_info[i], NULL); 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci out: 18358c2ecf20Sopenharmony_ci vtarget->starget = NULL; 18368c2ecf20Sopenharmony_ci kfree(starget->hostdata); 18378c2ecf20Sopenharmony_ci starget->hostdata = NULL; 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic int 18428c2ecf20Sopenharmony_cimptsas_slave_alloc(struct scsi_device *sdev) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci struct Scsi_Host *host = sdev->host; 18458c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(host); 18468c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 18478c2ecf20Sopenharmony_ci struct mptsas_portinfo *p; 18488c2ecf20Sopenharmony_ci VirtDevice *vdevice; 18498c2ecf20Sopenharmony_ci struct scsi_target *starget; 18508c2ecf20Sopenharmony_ci int i; 18518c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); 18548c2ecf20Sopenharmony_ci if (!vdevice) { 18558c2ecf20Sopenharmony_ci printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", 18568c2ecf20Sopenharmony_ci ioc->name, sizeof(VirtDevice)); 18578c2ecf20Sopenharmony_ci return -ENOMEM; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci starget = scsi_target(sdev); 18608c2ecf20Sopenharmony_ci vdevice->vtarget = starget->hostdata; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (sdev->channel == MPTSAS_RAID_CHANNEL) 18638c2ecf20Sopenharmony_ci goto out; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci rphy = dev_to_rphy(sdev->sdev_target->dev.parent); 18668c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 18678c2ecf20Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 18688c2ecf20Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 18698c2ecf20Sopenharmony_ci if (p->phy_info[i].attached.sas_address != 18708c2ecf20Sopenharmony_ci rphy->identify.sas_address) 18718c2ecf20Sopenharmony_ci continue; 18728c2ecf20Sopenharmony_ci vdevice->lun = sdev->lun; 18738c2ecf20Sopenharmony_ci /* 18748c2ecf20Sopenharmony_ci * Exposing hidden raid components 18758c2ecf20Sopenharmony_ci */ 18768c2ecf20Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, 18778c2ecf20Sopenharmony_ci p->phy_info[i].attached.channel, 18788c2ecf20Sopenharmony_ci p->phy_info[i].attached.id)) 18798c2ecf20Sopenharmony_ci sdev->no_uld_attach = 1; 18808c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 18818c2ecf20Sopenharmony_ci goto out; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci kfree(vdevice); 18878c2ecf20Sopenharmony_ci return -ENXIO; 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci out: 18908c2ecf20Sopenharmony_ci vdevice->vtarget->num_luns++; 18918c2ecf20Sopenharmony_ci sdev->hostdata = vdevice; 18928c2ecf20Sopenharmony_ci return 0; 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_cistatic int 18968c2ecf20Sopenharmony_cimptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd; 18998c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 19008c2ecf20Sopenharmony_ci VirtDevice *vdevice = SCpnt->device->hostdata; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { 19038c2ecf20Sopenharmony_ci SCpnt->result = DID_NO_CONNECT << 16; 19048c2ecf20Sopenharmony_ci SCpnt->scsi_done(SCpnt); 19058c2ecf20Sopenharmony_ci return 0; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci hd = shost_priv(shost); 19098c2ecf20Sopenharmony_ci ioc = hd->ioc; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci if (ioc->sas_discovery_quiesce_io) 19128c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (ioc->debug_level & MPT_DEBUG_SCSI) 19158c2ecf20Sopenharmony_ci scsi_print_command(SCpnt); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci return mptscsih_qcmd(SCpnt); 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci/** 19218c2ecf20Sopenharmony_ci * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout 19228c2ecf20Sopenharmony_ci * if the device under question is currently in the 19238c2ecf20Sopenharmony_ci * device removal delay. 19248c2ecf20Sopenharmony_ci * @sc: scsi command that the midlayer is about to time out 19258c2ecf20Sopenharmony_ci * 19268c2ecf20Sopenharmony_ci **/ 19278c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) 19288c2ecf20Sopenharmony_ci{ 19298c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd; 19308c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 19318c2ecf20Sopenharmony_ci VirtDevice *vdevice; 19328c2ecf20Sopenharmony_ci enum blk_eh_timer_return rc = BLK_EH_DONE; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci hd = shost_priv(sc->device->host); 19358c2ecf20Sopenharmony_ci if (hd == NULL) { 19368c2ecf20Sopenharmony_ci printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n", 19378c2ecf20Sopenharmony_ci __func__, sc); 19388c2ecf20Sopenharmony_ci goto done; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci ioc = hd->ioc; 19428c2ecf20Sopenharmony_ci if (ioc->bus_type != SAS) { 19438c2ecf20Sopenharmony_ci printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n", 19448c2ecf20Sopenharmony_ci __func__, sc); 19458c2ecf20Sopenharmony_ci goto done; 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* In case if IOC is in reset from internal context. 19498c2ecf20Sopenharmony_ci * Do not execute EEH for the same IOC. SML should to reset timer. 19508c2ecf20Sopenharmony_ci */ 19518c2ecf20Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 19528c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," 19538c2ecf20Sopenharmony_ci "SML need to reset the timer (sc=%p)\n", 19548c2ecf20Sopenharmony_ci ioc->name, __func__, sc)); 19558c2ecf20Sopenharmony_ci rc = BLK_EH_RESET_TIMER; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci vdevice = sc->device->hostdata; 19588c2ecf20Sopenharmony_ci if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD 19598c2ecf20Sopenharmony_ci || vdevice->vtarget->deleted)) { 19608c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " 19618c2ecf20Sopenharmony_ci "or in device removal delay (sc=%p)\n", 19628c2ecf20Sopenharmony_ci ioc->name, __func__, sc)); 19638c2ecf20Sopenharmony_ci rc = BLK_EH_RESET_TIMER; 19648c2ecf20Sopenharmony_ci goto done; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cidone: 19688c2ecf20Sopenharmony_ci return rc; 19698c2ecf20Sopenharmony_ci} 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic struct scsi_host_template mptsas_driver_template = { 19738c2ecf20Sopenharmony_ci .module = THIS_MODULE, 19748c2ecf20Sopenharmony_ci .proc_name = "mptsas", 19758c2ecf20Sopenharmony_ci .show_info = mptscsih_show_info, 19768c2ecf20Sopenharmony_ci .name = "MPT SAS Host", 19778c2ecf20Sopenharmony_ci .info = mptscsih_info, 19788c2ecf20Sopenharmony_ci .queuecommand = mptsas_qcmd, 19798c2ecf20Sopenharmony_ci .target_alloc = mptsas_target_alloc, 19808c2ecf20Sopenharmony_ci .slave_alloc = mptsas_slave_alloc, 19818c2ecf20Sopenharmony_ci .slave_configure = mptsas_slave_configure, 19828c2ecf20Sopenharmony_ci .target_destroy = mptsas_target_destroy, 19838c2ecf20Sopenharmony_ci .slave_destroy = mptscsih_slave_destroy, 19848c2ecf20Sopenharmony_ci .change_queue_depth = mptscsih_change_queue_depth, 19858c2ecf20Sopenharmony_ci .eh_timed_out = mptsas_eh_timed_out, 19868c2ecf20Sopenharmony_ci .eh_abort_handler = mptscsih_abort, 19878c2ecf20Sopenharmony_ci .eh_device_reset_handler = mptscsih_dev_reset, 19888c2ecf20Sopenharmony_ci .eh_host_reset_handler = mptscsih_host_reset, 19898c2ecf20Sopenharmony_ci .bios_param = mptscsih_bios_param, 19908c2ecf20Sopenharmony_ci .can_queue = MPT_SAS_CAN_QUEUE, 19918c2ecf20Sopenharmony_ci .this_id = -1, 19928c2ecf20Sopenharmony_ci .sg_tablesize = MPT_SCSI_SG_DEPTH, 19938c2ecf20Sopenharmony_ci .max_sectors = 8192, 19948c2ecf20Sopenharmony_ci .cmd_per_lun = 7, 19958c2ecf20Sopenharmony_ci .shost_attrs = mptscsih_host_attrs, 19968c2ecf20Sopenharmony_ci .no_write_same = 1, 19978c2ecf20Sopenharmony_ci}; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_cistatic int mptsas_get_linkerrors(struct sas_phy *phy) 20008c2ecf20Sopenharmony_ci{ 20018c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = phy_to_ioc(phy); 20028c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 20038c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 20048c2ecf20Sopenharmony_ci SasPhyPage1_t *buffer; 20058c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 20068c2ecf20Sopenharmony_ci int error; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci /* FIXME: only have link errors on local phys */ 20098c2ecf20Sopenharmony_ci if (!scsi_is_sas_phy_local(phy)) 20108c2ecf20Sopenharmony_ci return -EINVAL; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; 20138c2ecf20Sopenharmony_ci hdr.ExtPageLength = 0; 20148c2ecf20Sopenharmony_ci hdr.PageNumber = 1 /* page number 1*/; 20158c2ecf20Sopenharmony_ci hdr.Reserved1 = 0; 20168c2ecf20Sopenharmony_ci hdr.Reserved2 = 0; 20178c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 20188c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 20218c2ecf20Sopenharmony_ci cfg.physAddr = -1; 20228c2ecf20Sopenharmony_ci cfg.pageAddr = phy->identify.phy_identifier; 20238c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 20248c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 20258c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 20288c2ecf20Sopenharmony_ci if (error) 20298c2ecf20Sopenharmony_ci return error; 20308c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) 20318c2ecf20Sopenharmony_ci return -ENXIO; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 20348c2ecf20Sopenharmony_ci &dma_handle); 20358c2ecf20Sopenharmony_ci if (!buffer) 20368c2ecf20Sopenharmony_ci return -ENOMEM; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 20398c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 20428c2ecf20Sopenharmony_ci if (error) 20438c2ecf20Sopenharmony_ci goto out_free_consistent; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci mptsas_print_phy_pg1(ioc, buffer); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); 20488c2ecf20Sopenharmony_ci phy->running_disparity_error_count = 20498c2ecf20Sopenharmony_ci le32_to_cpu(buffer->RunningDisparityErrorCount); 20508c2ecf20Sopenharmony_ci phy->loss_of_dword_sync_count = 20518c2ecf20Sopenharmony_ci le32_to_cpu(buffer->LossDwordSynchCount); 20528c2ecf20Sopenharmony_ci phy->phy_reset_problem_count = 20538c2ecf20Sopenharmony_ci le32_to_cpu(buffer->PhyResetProblemCount); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci out_free_consistent: 20568c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 20578c2ecf20Sopenharmony_ci buffer, dma_handle); 20588c2ecf20Sopenharmony_ci return error; 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_cistatic int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, 20628c2ecf20Sopenharmony_ci MPT_FRAME_HDR *reply) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; 20658c2ecf20Sopenharmony_ci if (reply != NULL) { 20668c2ecf20Sopenharmony_ci ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; 20678c2ecf20Sopenharmony_ci memcpy(ioc->sas_mgmt.reply, reply, 20688c2ecf20Sopenharmony_ci min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { 20728c2ecf20Sopenharmony_ci ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; 20738c2ecf20Sopenharmony_ci complete(&ioc->sas_mgmt.done); 20748c2ecf20Sopenharmony_ci return 1; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci return 0; 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistatic int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) 20808c2ecf20Sopenharmony_ci{ 20818c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = phy_to_ioc(phy); 20828c2ecf20Sopenharmony_ci SasIoUnitControlRequest_t *req; 20838c2ecf20Sopenharmony_ci SasIoUnitControlReply_t *reply; 20848c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 20858c2ecf20Sopenharmony_ci MPIHeader_t *hdr; 20868c2ecf20Sopenharmony_ci unsigned long timeleft; 20878c2ecf20Sopenharmony_ci int error = -ERESTARTSYS; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci /* FIXME: fusion doesn't allow non-local phy reset */ 20908c2ecf20Sopenharmony_ci if (!scsi_is_sas_phy_local(phy)) 20918c2ecf20Sopenharmony_ci return -EINVAL; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci /* not implemented for expanders */ 20948c2ecf20Sopenharmony_ci if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) 20958c2ecf20Sopenharmony_ci return -ENXIO; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) 20988c2ecf20Sopenharmony_ci goto out; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); 21018c2ecf20Sopenharmony_ci if (!mf) { 21028c2ecf20Sopenharmony_ci error = -ENOMEM; 21038c2ecf20Sopenharmony_ci goto out_unlock; 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci hdr = (MPIHeader_t *) mf; 21078c2ecf20Sopenharmony_ci req = (SasIoUnitControlRequest_t *)mf; 21088c2ecf20Sopenharmony_ci memset(req, 0, sizeof(SasIoUnitControlRequest_t)); 21098c2ecf20Sopenharmony_ci req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; 21108c2ecf20Sopenharmony_ci req->MsgContext = hdr->MsgContext; 21118c2ecf20Sopenharmony_ci req->Operation = hard_reset ? 21128c2ecf20Sopenharmony_ci MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; 21138c2ecf20Sopenharmony_ci req->PhyNum = phy->identify.phy_identifier; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) 21168c2ecf20Sopenharmony_ci mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 21198c2ecf20Sopenharmony_ci 10 * HZ); 21208c2ecf20Sopenharmony_ci if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 21218c2ecf20Sopenharmony_ci error = -ETIME; 21228c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 21238c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) 21248c2ecf20Sopenharmony_ci goto out_unlock; 21258c2ecf20Sopenharmony_ci if (!timeleft) 21268c2ecf20Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 21278c2ecf20Sopenharmony_ci goto out_unlock; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* a reply frame is expected */ 21318c2ecf20Sopenharmony_ci if ((ioc->sas_mgmt.status & 21328c2ecf20Sopenharmony_ci MPT_MGMT_STATUS_RF_VALID) == 0) { 21338c2ecf20Sopenharmony_ci error = -ENXIO; 21348c2ecf20Sopenharmony_ci goto out_unlock; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci /* process the completed Reply Message Frame */ 21388c2ecf20Sopenharmony_ci reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; 21398c2ecf20Sopenharmony_ci if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { 21408c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", 21418c2ecf20Sopenharmony_ci ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); 21428c2ecf20Sopenharmony_ci error = -ENXIO; 21438c2ecf20Sopenharmony_ci goto out_unlock; 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci error = 0; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci out_unlock: 21498c2ecf20Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) 21508c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_mgmt.mutex); 21518c2ecf20Sopenharmony_ci out: 21528c2ecf20Sopenharmony_ci return error; 21538c2ecf20Sopenharmony_ci} 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_cistatic int 21568c2ecf20Sopenharmony_cimptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) 21578c2ecf20Sopenharmony_ci{ 21588c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = rphy_to_ioc(rphy); 21598c2ecf20Sopenharmony_ci int i, error; 21608c2ecf20Sopenharmony_ci struct mptsas_portinfo *p; 21618c2ecf20Sopenharmony_ci struct mptsas_enclosure enclosure_info; 21628c2ecf20Sopenharmony_ci u64 enclosure_handle; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 21658c2ecf20Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 21668c2ecf20Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 21678c2ecf20Sopenharmony_ci if (p->phy_info[i].attached.sas_address == 21688c2ecf20Sopenharmony_ci rphy->identify.sas_address) { 21698c2ecf20Sopenharmony_ci enclosure_handle = p->phy_info[i]. 21708c2ecf20Sopenharmony_ci attached.handle_enclosure; 21718c2ecf20Sopenharmony_ci goto found_info; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 21768c2ecf20Sopenharmony_ci return -ENXIO; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci found_info: 21798c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 21808c2ecf20Sopenharmony_ci memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); 21818c2ecf20Sopenharmony_ci error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, 21828c2ecf20Sopenharmony_ci (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << 21838c2ecf20Sopenharmony_ci MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); 21848c2ecf20Sopenharmony_ci if (!error) 21858c2ecf20Sopenharmony_ci *identifier = enclosure_info.enclosure_logical_id; 21868c2ecf20Sopenharmony_ci return error; 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cistatic int 21908c2ecf20Sopenharmony_cimptsas_get_bay_identifier(struct sas_rphy *rphy) 21918c2ecf20Sopenharmony_ci{ 21928c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = rphy_to_ioc(rphy); 21938c2ecf20Sopenharmony_ci struct mptsas_portinfo *p; 21948c2ecf20Sopenharmony_ci int i, rc; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 21978c2ecf20Sopenharmony_ci list_for_each_entry(p, &ioc->sas_topology, list) { 21988c2ecf20Sopenharmony_ci for (i = 0; i < p->num_phys; i++) { 21998c2ecf20Sopenharmony_ci if (p->phy_info[i].attached.sas_address == 22008c2ecf20Sopenharmony_ci rphy->identify.sas_address) { 22018c2ecf20Sopenharmony_ci rc = p->phy_info[i].attached.slot; 22028c2ecf20Sopenharmony_ci goto out; 22038c2ecf20Sopenharmony_ci } 22048c2ecf20Sopenharmony_ci } 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci rc = -ENXIO; 22078c2ecf20Sopenharmony_ci out: 22088c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 22098c2ecf20Sopenharmony_ci return rc; 22108c2ecf20Sopenharmony_ci} 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cistatic void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, 22138c2ecf20Sopenharmony_ci struct sas_rphy *rphy) 22148c2ecf20Sopenharmony_ci{ 22158c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; 22168c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 22178c2ecf20Sopenharmony_ci SmpPassthroughRequest_t *smpreq; 22188c2ecf20Sopenharmony_ci int flagsLength; 22198c2ecf20Sopenharmony_ci unsigned long timeleft; 22208c2ecf20Sopenharmony_ci char *psge; 22218c2ecf20Sopenharmony_ci u64 sas_address = 0; 22228c2ecf20Sopenharmony_ci unsigned int reslen = 0; 22238c2ecf20Sopenharmony_ci int ret = -EINVAL; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci /* do we need to support multiple segments? */ 22268c2ecf20Sopenharmony_ci if (job->request_payload.sg_cnt > 1 || 22278c2ecf20Sopenharmony_ci job->reply_payload.sg_cnt > 1) { 22288c2ecf20Sopenharmony_ci printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n", 22298c2ecf20Sopenharmony_ci ioc->name, __func__, job->request_payload.payload_len, 22308c2ecf20Sopenharmony_ci job->reply_payload.payload_len); 22318c2ecf20Sopenharmony_ci goto out; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); 22358c2ecf20Sopenharmony_ci if (ret) 22368c2ecf20Sopenharmony_ci goto out; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); 22398c2ecf20Sopenharmony_ci if (!mf) { 22408c2ecf20Sopenharmony_ci ret = -ENOMEM; 22418c2ecf20Sopenharmony_ci goto out_unlock; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci smpreq = (SmpPassthroughRequest_t *)mf; 22458c2ecf20Sopenharmony_ci memset(smpreq, 0, sizeof(*smpreq)); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci smpreq->RequestDataLength = 22488c2ecf20Sopenharmony_ci cpu_to_le16(job->request_payload.payload_len - 4); 22498c2ecf20Sopenharmony_ci smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (rphy) 22528c2ecf20Sopenharmony_ci sas_address = rphy->identify.sas_address; 22538c2ecf20Sopenharmony_ci else { 22548c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 22578c2ecf20Sopenharmony_ci port_info = ioc->hba_port_info; 22588c2ecf20Sopenharmony_ci if (port_info && port_info->phy_info) 22598c2ecf20Sopenharmony_ci sas_address = 22608c2ecf20Sopenharmony_ci port_info->phy_info[0].phy->identify.sas_address; 22618c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci psge = (char *) 22678c2ecf20Sopenharmony_ci (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* request */ 22708c2ecf20Sopenharmony_ci flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 22718c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER | 22728c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_DIRECTION) 22738c2ecf20Sopenharmony_ci << MPI_SGE_FLAGS_SHIFT; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 22768c2ecf20Sopenharmony_ci 1, PCI_DMA_BIDIRECTIONAL)) 22778c2ecf20Sopenharmony_ci goto put_mf; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4); 22808c2ecf20Sopenharmony_ci ioc->add_sge(psge, flagsLength, 22818c2ecf20Sopenharmony_ci sg_dma_address(job->request_payload.sg_list)); 22828c2ecf20Sopenharmony_ci psge += ioc->SGE_size; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci /* response */ 22858c2ecf20Sopenharmony_ci flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 22868c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 22878c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_IOC_TO_HOST | 22888c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 22938c2ecf20Sopenharmony_ci 1, PCI_DMA_BIDIRECTIONAL)) 22948c2ecf20Sopenharmony_ci goto unmap_out; 22958c2ecf20Sopenharmony_ci flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4; 22968c2ecf20Sopenharmony_ci ioc->add_sge(psge, flagsLength, 22978c2ecf20Sopenharmony_ci sg_dma_address(job->reply_payload.sg_list)); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) 23008c2ecf20Sopenharmony_ci mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); 23038c2ecf20Sopenharmony_ci if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 23048c2ecf20Sopenharmony_ci ret = -ETIME; 23058c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 23068c2ecf20Sopenharmony_ci mf = NULL; 23078c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) 23088c2ecf20Sopenharmony_ci goto unmap_in; 23098c2ecf20Sopenharmony_ci if (!timeleft) 23108c2ecf20Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 23118c2ecf20Sopenharmony_ci goto unmap_in; 23128c2ecf20Sopenharmony_ci } 23138c2ecf20Sopenharmony_ci mf = NULL; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { 23168c2ecf20Sopenharmony_ci SmpPassthroughReply_t *smprep; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; 23198c2ecf20Sopenharmony_ci memcpy(job->reply, smprep, sizeof(*smprep)); 23208c2ecf20Sopenharmony_ci job->reply_len = sizeof(*smprep); 23218c2ecf20Sopenharmony_ci reslen = smprep->ResponseDataLength; 23228c2ecf20Sopenharmony_ci } else { 23238c2ecf20Sopenharmony_ci printk(MYIOC_s_ERR_FMT 23248c2ecf20Sopenharmony_ci "%s: smp passthru reply failed to be returned\n", 23258c2ecf20Sopenharmony_ci ioc->name, __func__); 23268c2ecf20Sopenharmony_ci ret = -ENXIO; 23278c2ecf20Sopenharmony_ci } 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ciunmap_in: 23308c2ecf20Sopenharmony_ci dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1, 23318c2ecf20Sopenharmony_ci PCI_DMA_BIDIRECTIONAL); 23328c2ecf20Sopenharmony_ciunmap_out: 23338c2ecf20Sopenharmony_ci dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1, 23348c2ecf20Sopenharmony_ci PCI_DMA_BIDIRECTIONAL); 23358c2ecf20Sopenharmony_ciput_mf: 23368c2ecf20Sopenharmony_ci if (mf) 23378c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 23388c2ecf20Sopenharmony_ciout_unlock: 23398c2ecf20Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) 23408c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_mgmt.mutex); 23418c2ecf20Sopenharmony_ciout: 23428c2ecf20Sopenharmony_ci bsg_job_done(job, ret, reslen); 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_cistatic struct sas_function_template mptsas_transport_functions = { 23468c2ecf20Sopenharmony_ci .get_linkerrors = mptsas_get_linkerrors, 23478c2ecf20Sopenharmony_ci .get_enclosure_identifier = mptsas_get_enclosure_identifier, 23488c2ecf20Sopenharmony_ci .get_bay_identifier = mptsas_get_bay_identifier, 23498c2ecf20Sopenharmony_ci .phy_reset = mptsas_phy_reset, 23508c2ecf20Sopenharmony_ci .smp_handler = mptsas_smp_handler, 23518c2ecf20Sopenharmony_ci}; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_cistatic struct scsi_transport_template *mptsas_transport_template; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_cistatic int 23568c2ecf20Sopenharmony_cimptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) 23578c2ecf20Sopenharmony_ci{ 23588c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 23598c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 23608c2ecf20Sopenharmony_ci SasIOUnitPage0_t *buffer; 23618c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 23628c2ecf20Sopenharmony_ci int error, i; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; 23658c2ecf20Sopenharmony_ci hdr.ExtPageLength = 0; 23668c2ecf20Sopenharmony_ci hdr.PageNumber = 0; 23678c2ecf20Sopenharmony_ci hdr.Reserved1 = 0; 23688c2ecf20Sopenharmony_ci hdr.Reserved2 = 0; 23698c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 23708c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 23738c2ecf20Sopenharmony_ci cfg.physAddr = -1; 23748c2ecf20Sopenharmony_ci cfg.pageAddr = 0; 23758c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 23768c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 23778c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 23808c2ecf20Sopenharmony_ci if (error) 23818c2ecf20Sopenharmony_ci goto out; 23828c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 23838c2ecf20Sopenharmony_ci error = -ENXIO; 23848c2ecf20Sopenharmony_ci goto out; 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 23888c2ecf20Sopenharmony_ci &dma_handle); 23898c2ecf20Sopenharmony_ci if (!buffer) { 23908c2ecf20Sopenharmony_ci error = -ENOMEM; 23918c2ecf20Sopenharmony_ci goto out; 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 23958c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 23988c2ecf20Sopenharmony_ci if (error) 23998c2ecf20Sopenharmony_ci goto out_free_consistent; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci port_info->num_phys = buffer->NumPhys; 24028c2ecf20Sopenharmony_ci port_info->phy_info = kcalloc(port_info->num_phys, 24038c2ecf20Sopenharmony_ci sizeof(struct mptsas_phyinfo), GFP_KERNEL); 24048c2ecf20Sopenharmony_ci if (!port_info->phy_info) { 24058c2ecf20Sopenharmony_ci error = -ENOMEM; 24068c2ecf20Sopenharmony_ci goto out_free_consistent; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci ioc->nvdata_version_persistent = 24108c2ecf20Sopenharmony_ci le16_to_cpu(buffer->NvdataVersionPersistent); 24118c2ecf20Sopenharmony_ci ioc->nvdata_version_default = 24128c2ecf20Sopenharmony_ci le16_to_cpu(buffer->NvdataVersionDefault); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 24158c2ecf20Sopenharmony_ci mptsas_print_phy_data(ioc, &buffer->PhyData[i]); 24168c2ecf20Sopenharmony_ci port_info->phy_info[i].phy_id = i; 24178c2ecf20Sopenharmony_ci port_info->phy_info[i].port_id = 24188c2ecf20Sopenharmony_ci buffer->PhyData[i].Port; 24198c2ecf20Sopenharmony_ci port_info->phy_info[i].negotiated_link_rate = 24208c2ecf20Sopenharmony_ci buffer->PhyData[i].NegotiatedLinkRate; 24218c2ecf20Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 24228c2ecf20Sopenharmony_ci port_info->phy_info[i].handle = 24238c2ecf20Sopenharmony_ci le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci out_free_consistent: 24278c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 24288c2ecf20Sopenharmony_ci buffer, dma_handle); 24298c2ecf20Sopenharmony_ci out: 24308c2ecf20Sopenharmony_ci return error; 24318c2ecf20Sopenharmony_ci} 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_cistatic int 24348c2ecf20Sopenharmony_cimptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) 24358c2ecf20Sopenharmony_ci{ 24368c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 24378c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 24388c2ecf20Sopenharmony_ci SasIOUnitPage1_t *buffer; 24398c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 24408c2ecf20Sopenharmony_ci int error; 24418c2ecf20Sopenharmony_ci u8 device_missing_delay; 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); 24448c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(CONFIGPARMS)); 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 24478c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 24488c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 24498c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 24508c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; 24518c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; 24528c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr->PageNumber = 1; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 24558c2ecf20Sopenharmony_ci if (error) 24568c2ecf20Sopenharmony_ci goto out; 24578c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 24588c2ecf20Sopenharmony_ci error = -ENXIO; 24598c2ecf20Sopenharmony_ci goto out; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 24638c2ecf20Sopenharmony_ci &dma_handle); 24648c2ecf20Sopenharmony_ci if (!buffer) { 24658c2ecf20Sopenharmony_ci error = -ENOMEM; 24668c2ecf20Sopenharmony_ci goto out; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 24708c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 24738c2ecf20Sopenharmony_ci if (error) 24748c2ecf20Sopenharmony_ci goto out_free_consistent; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci ioc->io_missing_delay = 24778c2ecf20Sopenharmony_ci le16_to_cpu(buffer->IODeviceMissingDelay); 24788c2ecf20Sopenharmony_ci device_missing_delay = buffer->ReportDeviceMissingDelay; 24798c2ecf20Sopenharmony_ci ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? 24808c2ecf20Sopenharmony_ci (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : 24818c2ecf20Sopenharmony_ci device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci out_free_consistent: 24848c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 24858c2ecf20Sopenharmony_ci buffer, dma_handle); 24868c2ecf20Sopenharmony_ci out: 24878c2ecf20Sopenharmony_ci return error; 24888c2ecf20Sopenharmony_ci} 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_cistatic int 24918c2ecf20Sopenharmony_cimptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, 24928c2ecf20Sopenharmony_ci u32 form, u32 form_specific) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 24958c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 24968c2ecf20Sopenharmony_ci SasPhyPage0_t *buffer; 24978c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 24988c2ecf20Sopenharmony_ci int error; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; 25018c2ecf20Sopenharmony_ci hdr.ExtPageLength = 0; 25028c2ecf20Sopenharmony_ci hdr.PageNumber = 0; 25038c2ecf20Sopenharmony_ci hdr.Reserved1 = 0; 25048c2ecf20Sopenharmony_ci hdr.Reserved2 = 0; 25058c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 25068c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 25098c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 25108c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci /* Get Phy Pg 0 for each Phy. */ 25138c2ecf20Sopenharmony_ci cfg.physAddr = -1; 25148c2ecf20Sopenharmony_ci cfg.pageAddr = form + form_specific; 25158c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 25188c2ecf20Sopenharmony_ci if (error) 25198c2ecf20Sopenharmony_ci goto out; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 25228c2ecf20Sopenharmony_ci error = -ENXIO; 25238c2ecf20Sopenharmony_ci goto out; 25248c2ecf20Sopenharmony_ci } 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 25278c2ecf20Sopenharmony_ci &dma_handle); 25288c2ecf20Sopenharmony_ci if (!buffer) { 25298c2ecf20Sopenharmony_ci error = -ENOMEM; 25308c2ecf20Sopenharmony_ci goto out; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 25348c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 25378c2ecf20Sopenharmony_ci if (error) 25388c2ecf20Sopenharmony_ci goto out_free_consistent; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci mptsas_print_phy_pg0(ioc, buffer); 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci phy_info->hw_link_rate = buffer->HwLinkRate; 25438c2ecf20Sopenharmony_ci phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; 25448c2ecf20Sopenharmony_ci phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); 25458c2ecf20Sopenharmony_ci phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci out_free_consistent: 25488c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 25498c2ecf20Sopenharmony_ci buffer, dma_handle); 25508c2ecf20Sopenharmony_ci out: 25518c2ecf20Sopenharmony_ci return error; 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cistatic int 25558c2ecf20Sopenharmony_cimptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, 25568c2ecf20Sopenharmony_ci u32 form, u32 form_specific) 25578c2ecf20Sopenharmony_ci{ 25588c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 25598c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 25608c2ecf20Sopenharmony_ci SasDevicePage0_t *buffer; 25618c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 25628c2ecf20Sopenharmony_ci __le64 sas_address; 25638c2ecf20Sopenharmony_ci int error=0; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; 25668c2ecf20Sopenharmony_ci hdr.ExtPageLength = 0; 25678c2ecf20Sopenharmony_ci hdr.PageNumber = 0; 25688c2ecf20Sopenharmony_ci hdr.Reserved1 = 0; 25698c2ecf20Sopenharmony_ci hdr.Reserved2 = 0; 25708c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 25718c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 25748c2ecf20Sopenharmony_ci cfg.pageAddr = form + form_specific; 25758c2ecf20Sopenharmony_ci cfg.physAddr = -1; 25768c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 25778c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 25788c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci memset(device_info, 0, sizeof(struct mptsas_devinfo)); 25818c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 25828c2ecf20Sopenharmony_ci if (error) 25838c2ecf20Sopenharmony_ci goto out; 25848c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 25858c2ecf20Sopenharmony_ci error = -ENXIO; 25868c2ecf20Sopenharmony_ci goto out; 25878c2ecf20Sopenharmony_ci } 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 25908c2ecf20Sopenharmony_ci &dma_handle); 25918c2ecf20Sopenharmony_ci if (!buffer) { 25928c2ecf20Sopenharmony_ci error = -ENOMEM; 25938c2ecf20Sopenharmony_ci goto out; 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 25978c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 26028c2ecf20Sopenharmony_ci error = -ENODEV; 26038c2ecf20Sopenharmony_ci goto out_free_consistent; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci if (error) 26078c2ecf20Sopenharmony_ci goto out_free_consistent; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci mptsas_print_device_pg0(ioc, buffer); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci memset(device_info, 0, sizeof(struct mptsas_devinfo)); 26128c2ecf20Sopenharmony_ci device_info->handle = le16_to_cpu(buffer->DevHandle); 26138c2ecf20Sopenharmony_ci device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); 26148c2ecf20Sopenharmony_ci device_info->handle_enclosure = 26158c2ecf20Sopenharmony_ci le16_to_cpu(buffer->EnclosureHandle); 26168c2ecf20Sopenharmony_ci device_info->slot = le16_to_cpu(buffer->Slot); 26178c2ecf20Sopenharmony_ci device_info->phy_id = buffer->PhyNum; 26188c2ecf20Sopenharmony_ci device_info->port_id = buffer->PhysicalPort; 26198c2ecf20Sopenharmony_ci device_info->id = buffer->TargetID; 26208c2ecf20Sopenharmony_ci device_info->phys_disk_num = ~0; 26218c2ecf20Sopenharmony_ci device_info->channel = buffer->Bus; 26228c2ecf20Sopenharmony_ci memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); 26238c2ecf20Sopenharmony_ci device_info->sas_address = le64_to_cpu(sas_address); 26248c2ecf20Sopenharmony_ci device_info->device_info = 26258c2ecf20Sopenharmony_ci le32_to_cpu(buffer->DeviceInfo); 26268c2ecf20Sopenharmony_ci device_info->flags = le16_to_cpu(buffer->Flags); 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci out_free_consistent: 26298c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 26308c2ecf20Sopenharmony_ci buffer, dma_handle); 26318c2ecf20Sopenharmony_ci out: 26328c2ecf20Sopenharmony_ci return error; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_cistatic int 26368c2ecf20Sopenharmony_cimptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, 26378c2ecf20Sopenharmony_ci u32 form, u32 form_specific) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 26408c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 26418c2ecf20Sopenharmony_ci SasExpanderPage0_t *buffer; 26428c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 26438c2ecf20Sopenharmony_ci int i, error; 26448c2ecf20Sopenharmony_ci __le64 sas_address; 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci memset(port_info, 0, sizeof(struct mptsas_portinfo)); 26478c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; 26488c2ecf20Sopenharmony_ci hdr.ExtPageLength = 0; 26498c2ecf20Sopenharmony_ci hdr.PageNumber = 0; 26508c2ecf20Sopenharmony_ci hdr.Reserved1 = 0; 26518c2ecf20Sopenharmony_ci hdr.Reserved2 = 0; 26528c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 26538c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 26568c2ecf20Sopenharmony_ci cfg.physAddr = -1; 26578c2ecf20Sopenharmony_ci cfg.pageAddr = form + form_specific; 26588c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 26598c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 26608c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci memset(port_info, 0, sizeof(struct mptsas_portinfo)); 26638c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 26648c2ecf20Sopenharmony_ci if (error) 26658c2ecf20Sopenharmony_ci goto out; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 26688c2ecf20Sopenharmony_ci error = -ENXIO; 26698c2ecf20Sopenharmony_ci goto out; 26708c2ecf20Sopenharmony_ci } 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 26738c2ecf20Sopenharmony_ci &dma_handle); 26748c2ecf20Sopenharmony_ci if (!buffer) { 26758c2ecf20Sopenharmony_ci error = -ENOMEM; 26768c2ecf20Sopenharmony_ci goto out; 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 26808c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 26838c2ecf20Sopenharmony_ci if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 26848c2ecf20Sopenharmony_ci error = -ENODEV; 26858c2ecf20Sopenharmony_ci goto out_free_consistent; 26868c2ecf20Sopenharmony_ci } 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci if (error) 26898c2ecf20Sopenharmony_ci goto out_free_consistent; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci /* save config data */ 26928c2ecf20Sopenharmony_ci port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; 26938c2ecf20Sopenharmony_ci port_info->phy_info = kcalloc(port_info->num_phys, 26948c2ecf20Sopenharmony_ci sizeof(struct mptsas_phyinfo), GFP_KERNEL); 26958c2ecf20Sopenharmony_ci if (!port_info->phy_info) { 26968c2ecf20Sopenharmony_ci error = -ENOMEM; 26978c2ecf20Sopenharmony_ci goto out_free_consistent; 26988c2ecf20Sopenharmony_ci } 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); 27018c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 27028c2ecf20Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 27038c2ecf20Sopenharmony_ci port_info->phy_info[i].handle = 27048c2ecf20Sopenharmony_ci le16_to_cpu(buffer->DevHandle); 27058c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.sas_address = 27068c2ecf20Sopenharmony_ci le64_to_cpu(sas_address); 27078c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 27088c2ecf20Sopenharmony_ci le16_to_cpu(buffer->ParentDevHandle); 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci out_free_consistent: 27128c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 27138c2ecf20Sopenharmony_ci buffer, dma_handle); 27148c2ecf20Sopenharmony_ci out: 27158c2ecf20Sopenharmony_ci return error; 27168c2ecf20Sopenharmony_ci} 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_cistatic int 27198c2ecf20Sopenharmony_cimptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, 27208c2ecf20Sopenharmony_ci u32 form, u32 form_specific) 27218c2ecf20Sopenharmony_ci{ 27228c2ecf20Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 27238c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 27248c2ecf20Sopenharmony_ci SasExpanderPage1_t *buffer; 27258c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 27268c2ecf20Sopenharmony_ci int error=0; 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; 27298c2ecf20Sopenharmony_ci hdr.ExtPageLength = 0; 27308c2ecf20Sopenharmony_ci hdr.PageNumber = 1; 27318c2ecf20Sopenharmony_ci hdr.Reserved1 = 0; 27328c2ecf20Sopenharmony_ci hdr.Reserved2 = 0; 27338c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 27348c2ecf20Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 27378c2ecf20Sopenharmony_ci cfg.physAddr = -1; 27388c2ecf20Sopenharmony_ci cfg.pageAddr = form + form_specific; 27398c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 27408c2ecf20Sopenharmony_ci cfg.dir = 0; /* read */ 27418c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 27448c2ecf20Sopenharmony_ci if (error) 27458c2ecf20Sopenharmony_ci goto out; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci if (!hdr.ExtPageLength) { 27488c2ecf20Sopenharmony_ci error = -ENXIO; 27498c2ecf20Sopenharmony_ci goto out; 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 27538c2ecf20Sopenharmony_ci &dma_handle); 27548c2ecf20Sopenharmony_ci if (!buffer) { 27558c2ecf20Sopenharmony_ci error = -ENOMEM; 27568c2ecf20Sopenharmony_ci goto out; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 27608c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci error = mpt_config(ioc, &cfg); 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 27658c2ecf20Sopenharmony_ci error = -ENODEV; 27668c2ecf20Sopenharmony_ci goto out_free_consistent; 27678c2ecf20Sopenharmony_ci } 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci if (error) 27708c2ecf20Sopenharmony_ci goto out_free_consistent; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci mptsas_print_expander_pg1(ioc, buffer); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* save config data */ 27768c2ecf20Sopenharmony_ci phy_info->phy_id = buffer->PhyIdentifier; 27778c2ecf20Sopenharmony_ci phy_info->port_id = buffer->PhysicalPort; 27788c2ecf20Sopenharmony_ci phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; 27798c2ecf20Sopenharmony_ci phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; 27808c2ecf20Sopenharmony_ci phy_info->hw_link_rate = buffer->HwLinkRate; 27818c2ecf20Sopenharmony_ci phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); 27828c2ecf20Sopenharmony_ci phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci out_free_consistent: 27858c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, 27868c2ecf20Sopenharmony_ci buffer, dma_handle); 27878c2ecf20Sopenharmony_ci out: 27888c2ecf20Sopenharmony_ci return error; 27898c2ecf20Sopenharmony_ci} 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_cistruct rep_manu_request{ 27928c2ecf20Sopenharmony_ci u8 smp_frame_type; 27938c2ecf20Sopenharmony_ci u8 function; 27948c2ecf20Sopenharmony_ci u8 reserved; 27958c2ecf20Sopenharmony_ci u8 request_length; 27968c2ecf20Sopenharmony_ci}; 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_cistruct rep_manu_reply{ 27998c2ecf20Sopenharmony_ci u8 smp_frame_type; /* 0x41 */ 28008c2ecf20Sopenharmony_ci u8 function; /* 0x01 */ 28018c2ecf20Sopenharmony_ci u8 function_result; 28028c2ecf20Sopenharmony_ci u8 response_length; 28038c2ecf20Sopenharmony_ci u16 expander_change_count; 28048c2ecf20Sopenharmony_ci u8 reserved0[2]; 28058c2ecf20Sopenharmony_ci u8 sas_format:1; 28068c2ecf20Sopenharmony_ci u8 reserved1:7; 28078c2ecf20Sopenharmony_ci u8 reserved2[3]; 28088c2ecf20Sopenharmony_ci u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; 28098c2ecf20Sopenharmony_ci u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; 28108c2ecf20Sopenharmony_ci u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; 28118c2ecf20Sopenharmony_ci u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; 28128c2ecf20Sopenharmony_ci u16 component_id; 28138c2ecf20Sopenharmony_ci u8 component_revision_id; 28148c2ecf20Sopenharmony_ci u8 reserved3; 28158c2ecf20Sopenharmony_ci u8 vendor_specific[8]; 28168c2ecf20Sopenharmony_ci}; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci/** 28198c2ecf20Sopenharmony_ci * mptsas_exp_repmanufacture_info - 28208c2ecf20Sopenharmony_ci * @ioc: per adapter object 28218c2ecf20Sopenharmony_ci * @sas_address: expander sas address 28228c2ecf20Sopenharmony_ci * @edev: the sas_expander_device object 28238c2ecf20Sopenharmony_ci * 28248c2ecf20Sopenharmony_ci * Fills in the sas_expander_device object when SMP port is created. 28258c2ecf20Sopenharmony_ci * 28268c2ecf20Sopenharmony_ci * Returns 0 for success, non-zero for failure. 28278c2ecf20Sopenharmony_ci */ 28288c2ecf20Sopenharmony_cistatic int 28298c2ecf20Sopenharmony_cimptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, 28308c2ecf20Sopenharmony_ci u64 sas_address, struct sas_expander_device *edev) 28318c2ecf20Sopenharmony_ci{ 28328c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 28338c2ecf20Sopenharmony_ci SmpPassthroughRequest_t *smpreq; 28348c2ecf20Sopenharmony_ci SmpPassthroughReply_t *smprep; 28358c2ecf20Sopenharmony_ci struct rep_manu_reply *manufacture_reply; 28368c2ecf20Sopenharmony_ci struct rep_manu_request *manufacture_request; 28378c2ecf20Sopenharmony_ci int ret; 28388c2ecf20Sopenharmony_ci int flagsLength; 28398c2ecf20Sopenharmony_ci unsigned long timeleft; 28408c2ecf20Sopenharmony_ci char *psge; 28418c2ecf20Sopenharmony_ci unsigned long flags; 28428c2ecf20Sopenharmony_ci void *data_out = NULL; 28438c2ecf20Sopenharmony_ci dma_addr_t data_out_dma = 0; 28448c2ecf20Sopenharmony_ci u32 sz; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 28478c2ecf20Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 28488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 28498c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", 28508c2ecf20Sopenharmony_ci __func__, ioc->name); 28518c2ecf20Sopenharmony_ci return -EFAULT; 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); 28568c2ecf20Sopenharmony_ci if (ret) 28578c2ecf20Sopenharmony_ci goto out; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); 28608c2ecf20Sopenharmony_ci if (!mf) { 28618c2ecf20Sopenharmony_ci ret = -ENOMEM; 28628c2ecf20Sopenharmony_ci goto out_unlock; 28638c2ecf20Sopenharmony_ci } 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci smpreq = (SmpPassthroughRequest_t *)mf; 28668c2ecf20Sopenharmony_ci memset(smpreq, 0, sizeof(*smpreq)); 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); 28718c2ecf20Sopenharmony_ci if (!data_out) { 28728c2ecf20Sopenharmony_ci printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", 28738c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 28748c2ecf20Sopenharmony_ci ret = -ENOMEM; 28758c2ecf20Sopenharmony_ci goto put_mf; 28768c2ecf20Sopenharmony_ci } 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci manufacture_request = data_out; 28798c2ecf20Sopenharmony_ci manufacture_request->smp_frame_type = 0x40; 28808c2ecf20Sopenharmony_ci manufacture_request->function = 1; 28818c2ecf20Sopenharmony_ci manufacture_request->reserved = 0; 28828c2ecf20Sopenharmony_ci manufacture_request->request_length = 0; 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; 28858c2ecf20Sopenharmony_ci smpreq->PhysicalPort = 0xFF; 28868c2ecf20Sopenharmony_ci *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); 28878c2ecf20Sopenharmony_ci smpreq->RequestDataLength = sizeof(struct rep_manu_request); 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci psge = (char *) 28908c2ecf20Sopenharmony_ci (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 28938c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 28948c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_HOST_TO_IOC | 28958c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 28968c2ecf20Sopenharmony_ci flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; 28978c2ecf20Sopenharmony_ci flagsLength |= sizeof(struct rep_manu_request); 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci ioc->add_sge(psge, flagsLength, data_out_dma); 29008c2ecf20Sopenharmony_ci psge += ioc->SGE_size; 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 29038c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 29048c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_IOC_TO_HOST | 29058c2ecf20Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 29068c2ecf20Sopenharmony_ci flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; 29078c2ecf20Sopenharmony_ci flagsLength |= sizeof(struct rep_manu_reply); 29088c2ecf20Sopenharmony_ci ioc->add_sge(psge, flagsLength, data_out_dma + 29098c2ecf20Sopenharmony_ci sizeof(struct rep_manu_request)); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) 29128c2ecf20Sopenharmony_ci mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); 29158c2ecf20Sopenharmony_ci if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 29168c2ecf20Sopenharmony_ci ret = -ETIME; 29178c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 29188c2ecf20Sopenharmony_ci mf = NULL; 29198c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) 29208c2ecf20Sopenharmony_ci goto out_free; 29218c2ecf20Sopenharmony_ci if (!timeleft) 29228c2ecf20Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 29238c2ecf20Sopenharmony_ci goto out_free; 29248c2ecf20Sopenharmony_ci } 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci mf = NULL; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { 29298c2ecf20Sopenharmony_ci u8 *tmp; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; 29328c2ecf20Sopenharmony_ci if (le16_to_cpu(smprep->ResponseDataLength) != 29338c2ecf20Sopenharmony_ci sizeof(struct rep_manu_reply)) 29348c2ecf20Sopenharmony_ci goto out_free; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci manufacture_reply = data_out + sizeof(struct rep_manu_request); 29378c2ecf20Sopenharmony_ci strncpy(edev->vendor_id, manufacture_reply->vendor_id, 29388c2ecf20Sopenharmony_ci SAS_EXPANDER_VENDOR_ID_LEN); 29398c2ecf20Sopenharmony_ci strncpy(edev->product_id, manufacture_reply->product_id, 29408c2ecf20Sopenharmony_ci SAS_EXPANDER_PRODUCT_ID_LEN); 29418c2ecf20Sopenharmony_ci strncpy(edev->product_rev, manufacture_reply->product_rev, 29428c2ecf20Sopenharmony_ci SAS_EXPANDER_PRODUCT_REV_LEN); 29438c2ecf20Sopenharmony_ci edev->level = manufacture_reply->sas_format; 29448c2ecf20Sopenharmony_ci if (manufacture_reply->sas_format) { 29458c2ecf20Sopenharmony_ci strncpy(edev->component_vendor_id, 29468c2ecf20Sopenharmony_ci manufacture_reply->component_vendor_id, 29478c2ecf20Sopenharmony_ci SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); 29488c2ecf20Sopenharmony_ci tmp = (u8 *)&manufacture_reply->component_id; 29498c2ecf20Sopenharmony_ci edev->component_id = tmp[0] << 8 | tmp[1]; 29508c2ecf20Sopenharmony_ci edev->component_revision_id = 29518c2ecf20Sopenharmony_ci manufacture_reply->component_revision_id; 29528c2ecf20Sopenharmony_ci } 29538c2ecf20Sopenharmony_ci } else { 29548c2ecf20Sopenharmony_ci printk(MYIOC_s_ERR_FMT 29558c2ecf20Sopenharmony_ci "%s: smp passthru reply failed to be returned\n", 29568c2ecf20Sopenharmony_ci ioc->name, __func__); 29578c2ecf20Sopenharmony_ci ret = -ENXIO; 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_ciout_free: 29608c2ecf20Sopenharmony_ci if (data_out_dma) 29618c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); 29628c2ecf20Sopenharmony_ciput_mf: 29638c2ecf20Sopenharmony_ci if (mf) 29648c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 29658c2ecf20Sopenharmony_ciout_unlock: 29668c2ecf20Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) 29678c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_mgmt.mutex); 29688c2ecf20Sopenharmony_ciout: 29698c2ecf20Sopenharmony_ci return ret; 29708c2ecf20Sopenharmony_ci} 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_cistatic void 29738c2ecf20Sopenharmony_cimptsas_parse_device_info(struct sas_identify *identify, 29748c2ecf20Sopenharmony_ci struct mptsas_devinfo *device_info) 29758c2ecf20Sopenharmony_ci{ 29768c2ecf20Sopenharmony_ci u16 protocols; 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci identify->sas_address = device_info->sas_address; 29798c2ecf20Sopenharmony_ci identify->phy_identifier = device_info->phy_id; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci /* 29828c2ecf20Sopenharmony_ci * Fill in Phy Initiator Port Protocol. 29838c2ecf20Sopenharmony_ci * Bits 6:3, more than one bit can be set, fall through cases. 29848c2ecf20Sopenharmony_ci */ 29858c2ecf20Sopenharmony_ci protocols = device_info->device_info & 0x78; 29868c2ecf20Sopenharmony_ci identify->initiator_port_protocols = 0; 29878c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) 29888c2ecf20Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; 29898c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) 29908c2ecf20Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_STP; 29918c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) 29928c2ecf20Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; 29938c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) 29948c2ecf20Sopenharmony_ci identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci /* 29978c2ecf20Sopenharmony_ci * Fill in Phy Target Port Protocol. 29988c2ecf20Sopenharmony_ci * Bits 10:7, more than one bit can be set, fall through cases. 29998c2ecf20Sopenharmony_ci */ 30008c2ecf20Sopenharmony_ci protocols = device_info->device_info & 0x780; 30018c2ecf20Sopenharmony_ci identify->target_port_protocols = 0; 30028c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) 30038c2ecf20Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_SSP; 30048c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) 30058c2ecf20Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_STP; 30068c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) 30078c2ecf20Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_SMP; 30088c2ecf20Sopenharmony_ci if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) 30098c2ecf20Sopenharmony_ci identify->target_port_protocols |= SAS_PROTOCOL_SATA; 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci /* 30128c2ecf20Sopenharmony_ci * Fill in Attached device type. 30138c2ecf20Sopenharmony_ci */ 30148c2ecf20Sopenharmony_ci switch (device_info->device_info & 30158c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { 30168c2ecf20Sopenharmony_ci case MPI_SAS_DEVICE_INFO_NO_DEVICE: 30178c2ecf20Sopenharmony_ci identify->device_type = SAS_PHY_UNUSED; 30188c2ecf20Sopenharmony_ci break; 30198c2ecf20Sopenharmony_ci case MPI_SAS_DEVICE_INFO_END_DEVICE: 30208c2ecf20Sopenharmony_ci identify->device_type = SAS_END_DEVICE; 30218c2ecf20Sopenharmony_ci break; 30228c2ecf20Sopenharmony_ci case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: 30238c2ecf20Sopenharmony_ci identify->device_type = SAS_EDGE_EXPANDER_DEVICE; 30248c2ecf20Sopenharmony_ci break; 30258c2ecf20Sopenharmony_ci case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: 30268c2ecf20Sopenharmony_ci identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; 30278c2ecf20Sopenharmony_ci break; 30288c2ecf20Sopenharmony_ci } 30298c2ecf20Sopenharmony_ci} 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_cistatic int mptsas_probe_one_phy(struct device *dev, 30328c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info, int index, int local) 30338c2ecf20Sopenharmony_ci{ 30348c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 30358c2ecf20Sopenharmony_ci struct sas_phy *phy; 30368c2ecf20Sopenharmony_ci struct sas_port *port; 30378c2ecf20Sopenharmony_ci int error = 0; 30388c2ecf20Sopenharmony_ci VirtTarget *vtarget; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci if (!dev) { 30418c2ecf20Sopenharmony_ci error = -ENODEV; 30428c2ecf20Sopenharmony_ci goto out; 30438c2ecf20Sopenharmony_ci } 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci if (!phy_info->phy) { 30468c2ecf20Sopenharmony_ci phy = sas_phy_alloc(dev, index); 30478c2ecf20Sopenharmony_ci if (!phy) { 30488c2ecf20Sopenharmony_ci error = -ENOMEM; 30498c2ecf20Sopenharmony_ci goto out; 30508c2ecf20Sopenharmony_ci } 30518c2ecf20Sopenharmony_ci } else 30528c2ecf20Sopenharmony_ci phy = phy_info->phy; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci mptsas_parse_device_info(&phy->identify, &phy_info->identify); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci /* 30578c2ecf20Sopenharmony_ci * Set Negotiated link rate. 30588c2ecf20Sopenharmony_ci */ 30598c2ecf20Sopenharmony_ci switch (phy_info->negotiated_link_rate) { 30608c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: 30618c2ecf20Sopenharmony_ci phy->negotiated_linkrate = SAS_PHY_DISABLED; 30628c2ecf20Sopenharmony_ci break; 30638c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: 30648c2ecf20Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; 30658c2ecf20Sopenharmony_ci break; 30668c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_1_5: 30678c2ecf20Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; 30688c2ecf20Sopenharmony_ci break; 30698c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_3_0: 30708c2ecf20Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; 30718c2ecf20Sopenharmony_ci break; 30728c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_6_0: 30738c2ecf20Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; 30748c2ecf20Sopenharmony_ci break; 30758c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: 30768c2ecf20Sopenharmony_ci case MPI_SAS_IOUNIT0_RATE_UNKNOWN: 30778c2ecf20Sopenharmony_ci default: 30788c2ecf20Sopenharmony_ci phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 30798c2ecf20Sopenharmony_ci break; 30808c2ecf20Sopenharmony_ci } 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci /* 30838c2ecf20Sopenharmony_ci * Set Max hardware link rate. 30848c2ecf20Sopenharmony_ci */ 30858c2ecf20Sopenharmony_ci switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { 30868c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: 30878c2ecf20Sopenharmony_ci phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 30888c2ecf20Sopenharmony_ci break; 30898c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: 30908c2ecf20Sopenharmony_ci phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; 30918c2ecf20Sopenharmony_ci break; 30928c2ecf20Sopenharmony_ci default: 30938c2ecf20Sopenharmony_ci break; 30948c2ecf20Sopenharmony_ci } 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci /* 30978c2ecf20Sopenharmony_ci * Set Max programmed link rate. 30988c2ecf20Sopenharmony_ci */ 30998c2ecf20Sopenharmony_ci switch (phy_info->programmed_link_rate & 31008c2ecf20Sopenharmony_ci MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { 31018c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: 31028c2ecf20Sopenharmony_ci phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; 31038c2ecf20Sopenharmony_ci break; 31048c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: 31058c2ecf20Sopenharmony_ci phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; 31068c2ecf20Sopenharmony_ci break; 31078c2ecf20Sopenharmony_ci default: 31088c2ecf20Sopenharmony_ci break; 31098c2ecf20Sopenharmony_ci } 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci /* 31128c2ecf20Sopenharmony_ci * Set Min hardware link rate. 31138c2ecf20Sopenharmony_ci */ 31148c2ecf20Sopenharmony_ci switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { 31158c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: 31168c2ecf20Sopenharmony_ci phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 31178c2ecf20Sopenharmony_ci break; 31188c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: 31198c2ecf20Sopenharmony_ci phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; 31208c2ecf20Sopenharmony_ci break; 31218c2ecf20Sopenharmony_ci default: 31228c2ecf20Sopenharmony_ci break; 31238c2ecf20Sopenharmony_ci } 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci /* 31268c2ecf20Sopenharmony_ci * Set Min programmed link rate. 31278c2ecf20Sopenharmony_ci */ 31288c2ecf20Sopenharmony_ci switch (phy_info->programmed_link_rate & 31298c2ecf20Sopenharmony_ci MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { 31308c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: 31318c2ecf20Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; 31328c2ecf20Sopenharmony_ci break; 31338c2ecf20Sopenharmony_ci case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: 31348c2ecf20Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; 31358c2ecf20Sopenharmony_ci break; 31368c2ecf20Sopenharmony_ci default: 31378c2ecf20Sopenharmony_ci break; 31388c2ecf20Sopenharmony_ci } 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci if (!phy_info->phy) { 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci error = sas_phy_add(phy); 31438c2ecf20Sopenharmony_ci if (error) { 31448c2ecf20Sopenharmony_ci sas_phy_free(phy); 31458c2ecf20Sopenharmony_ci goto out; 31468c2ecf20Sopenharmony_ci } 31478c2ecf20Sopenharmony_ci phy_info->phy = phy; 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci if (!phy_info->attached.handle || 31518c2ecf20Sopenharmony_ci !phy_info->port_details) 31528c2ecf20Sopenharmony_ci goto out; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci port = mptsas_get_port(phy_info); 31558c2ecf20Sopenharmony_ci ioc = phy_to_ioc(phy_info->phy); 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci if (phy_info->sas_port_add_phy) { 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci if (!port) { 31608c2ecf20Sopenharmony_ci port = sas_port_alloc_num(dev); 31618c2ecf20Sopenharmony_ci if (!port) { 31628c2ecf20Sopenharmony_ci error = -ENOMEM; 31638c2ecf20Sopenharmony_ci goto out; 31648c2ecf20Sopenharmony_ci } 31658c2ecf20Sopenharmony_ci error = sas_port_add(port); 31668c2ecf20Sopenharmony_ci if (error) { 31678c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 31688c2ecf20Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 31698c2ecf20Sopenharmony_ci __func__, __LINE__)); 31708c2ecf20Sopenharmony_ci goto out; 31718c2ecf20Sopenharmony_ci } 31728c2ecf20Sopenharmony_ci mptsas_set_port(ioc, phy_info, port); 31738c2ecf20Sopenharmony_ci devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, 31748c2ecf20Sopenharmony_ci MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", 31758c2ecf20Sopenharmony_ci ioc->name, port->port_identifier, 31768c2ecf20Sopenharmony_ci (unsigned long long)phy_info-> 31778c2ecf20Sopenharmony_ci attached.sas_address)); 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT 31808c2ecf20Sopenharmony_ci "sas_port_add_phy: phy_id=%d\n", 31818c2ecf20Sopenharmony_ci ioc->name, phy_info->phy_id)); 31828c2ecf20Sopenharmony_ci sas_port_add_phy(port, phy_info->phy); 31838c2ecf20Sopenharmony_ci phy_info->sas_port_add_phy = 0; 31848c2ecf20Sopenharmony_ci devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, 31858c2ecf20Sopenharmony_ci MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, 31868c2ecf20Sopenharmony_ci phy_info->phy_id, phy_info->phy)); 31878c2ecf20Sopenharmony_ci } 31888c2ecf20Sopenharmony_ci if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 31918c2ecf20Sopenharmony_ci struct device *parent; 31928c2ecf20Sopenharmony_ci struct sas_identify identify; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci parent = dev->parent->parent; 31958c2ecf20Sopenharmony_ci /* 31968c2ecf20Sopenharmony_ci * Let the hotplug_work thread handle processing 31978c2ecf20Sopenharmony_ci * the adding/removing of devices that occur 31988c2ecf20Sopenharmony_ci * after start of day. 31998c2ecf20Sopenharmony_ci */ 32008c2ecf20Sopenharmony_ci if (mptsas_is_end_device(&phy_info->attached) && 32018c2ecf20Sopenharmony_ci phy_info->attached.handle_parent) { 32028c2ecf20Sopenharmony_ci goto out; 32038c2ecf20Sopenharmony_ci } 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci mptsas_parse_device_info(&identify, &phy_info->attached); 32068c2ecf20Sopenharmony_ci if (scsi_is_host_device(parent)) { 32078c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 32088c2ecf20Sopenharmony_ci int i; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci port_info = ioc->hba_port_info; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 32138c2ecf20Sopenharmony_ci if (port_info->phy_info[i].identify.sas_address == 32148c2ecf20Sopenharmony_ci identify.sas_address) { 32158c2ecf20Sopenharmony_ci sas_port_mark_backlink(port); 32168c2ecf20Sopenharmony_ci goto out; 32178c2ecf20Sopenharmony_ci } 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci } else if (scsi_is_sas_rphy(parent)) { 32208c2ecf20Sopenharmony_ci struct sas_rphy *parent_rphy = dev_to_rphy(parent); 32218c2ecf20Sopenharmony_ci if (identify.sas_address == 32228c2ecf20Sopenharmony_ci parent_rphy->identify.sas_address) { 32238c2ecf20Sopenharmony_ci sas_port_mark_backlink(port); 32248c2ecf20Sopenharmony_ci goto out; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci } 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci switch (identify.device_type) { 32298c2ecf20Sopenharmony_ci case SAS_END_DEVICE: 32308c2ecf20Sopenharmony_ci rphy = sas_end_device_alloc(port); 32318c2ecf20Sopenharmony_ci break; 32328c2ecf20Sopenharmony_ci case SAS_EDGE_EXPANDER_DEVICE: 32338c2ecf20Sopenharmony_ci case SAS_FANOUT_EXPANDER_DEVICE: 32348c2ecf20Sopenharmony_ci rphy = sas_expander_alloc(port, identify.device_type); 32358c2ecf20Sopenharmony_ci break; 32368c2ecf20Sopenharmony_ci default: 32378c2ecf20Sopenharmony_ci rphy = NULL; 32388c2ecf20Sopenharmony_ci break; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci if (!rphy) { 32418c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 32428c2ecf20Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 32438c2ecf20Sopenharmony_ci __func__, __LINE__)); 32448c2ecf20Sopenharmony_ci goto out; 32458c2ecf20Sopenharmony_ci } 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci rphy->identify = identify; 32488c2ecf20Sopenharmony_ci error = sas_rphy_add(rphy); 32498c2ecf20Sopenharmony_ci if (error) { 32508c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 32518c2ecf20Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 32528c2ecf20Sopenharmony_ci __func__, __LINE__)); 32538c2ecf20Sopenharmony_ci sas_rphy_free(rphy); 32548c2ecf20Sopenharmony_ci goto out; 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci mptsas_set_rphy(ioc, phy_info, rphy); 32578c2ecf20Sopenharmony_ci if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || 32588c2ecf20Sopenharmony_ci identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) 32598c2ecf20Sopenharmony_ci mptsas_exp_repmanufacture_info(ioc, 32608c2ecf20Sopenharmony_ci identify.sas_address, 32618c2ecf20Sopenharmony_ci rphy_to_expander_device(rphy)); 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci /* If the device exists,verify it wasn't previously flagged 32658c2ecf20Sopenharmony_ci as a missing device. If so, clear it */ 32668c2ecf20Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, 32678c2ecf20Sopenharmony_ci phy_info->attached.channel, 32688c2ecf20Sopenharmony_ci phy_info->attached.id); 32698c2ecf20Sopenharmony_ci if (vtarget && vtarget->inDMD) { 32708c2ecf20Sopenharmony_ci printk(KERN_INFO "Device returned, unsetting inDMD\n"); 32718c2ecf20Sopenharmony_ci vtarget->inDMD = 0; 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci out: 32758c2ecf20Sopenharmony_ci return error; 32768c2ecf20Sopenharmony_ci} 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_cistatic int 32798c2ecf20Sopenharmony_cimptsas_probe_hba_phys(MPT_ADAPTER *ioc) 32808c2ecf20Sopenharmony_ci{ 32818c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info, *hba; 32828c2ecf20Sopenharmony_ci int error = -ENOMEM, i; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 32858c2ecf20Sopenharmony_ci if (! hba) 32868c2ecf20Sopenharmony_ci goto out; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci error = mptsas_sas_io_unit_pg0(ioc, hba); 32898c2ecf20Sopenharmony_ci if (error) 32908c2ecf20Sopenharmony_ci goto out_free_port_info; 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci mptsas_sas_io_unit_pg1(ioc); 32938c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 32948c2ecf20Sopenharmony_ci port_info = ioc->hba_port_info; 32958c2ecf20Sopenharmony_ci if (!port_info) { 32968c2ecf20Sopenharmony_ci ioc->hba_port_info = port_info = hba; 32978c2ecf20Sopenharmony_ci ioc->hba_port_num_phy = port_info->num_phys; 32988c2ecf20Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 32998c2ecf20Sopenharmony_ci } else { 33008c2ecf20Sopenharmony_ci for (i = 0; i < hba->num_phys; i++) { 33018c2ecf20Sopenharmony_ci port_info->phy_info[i].negotiated_link_rate = 33028c2ecf20Sopenharmony_ci hba->phy_info[i].negotiated_link_rate; 33038c2ecf20Sopenharmony_ci port_info->phy_info[i].handle = 33048c2ecf20Sopenharmony_ci hba->phy_info[i].handle; 33058c2ecf20Sopenharmony_ci port_info->phy_info[i].port_id = 33068c2ecf20Sopenharmony_ci hba->phy_info[i].port_id; 33078c2ecf20Sopenharmony_ci } 33088c2ecf20Sopenharmony_ci kfree(hba->phy_info); 33098c2ecf20Sopenharmony_ci kfree(hba); 33108c2ecf20Sopenharmony_ci hba = NULL; 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 33138c2ecf20Sopenharmony_ci#if defined(CPQ_CIM) 33148c2ecf20Sopenharmony_ci ioc->num_ports = port_info->num_phys; 33158c2ecf20Sopenharmony_ci#endif 33168c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 33178c2ecf20Sopenharmony_ci mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], 33188c2ecf20Sopenharmony_ci (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << 33198c2ecf20Sopenharmony_ci MPI_SAS_PHY_PGAD_FORM_SHIFT), i); 33208c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle = 33218c2ecf20Sopenharmony_ci port_info->phy_info[i].handle; 33228c2ecf20Sopenharmony_ci mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, 33238c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 33248c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 33258c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle); 33268c2ecf20Sopenharmony_ci if (!ioc->hba_port_sas_addr) 33278c2ecf20Sopenharmony_ci ioc->hba_port_sas_addr = 33288c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.sas_address; 33298c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.phy_id = 33308c2ecf20Sopenharmony_ci port_info->phy_info[i].phy_id = i; 33318c2ecf20Sopenharmony_ci if (port_info->phy_info[i].attached.handle) 33328c2ecf20Sopenharmony_ci mptsas_sas_device_pg0(ioc, 33338c2ecf20Sopenharmony_ci &port_info->phy_info[i].attached, 33348c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 33358c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 33368c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.handle); 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci mptsas_setup_wide_ports(ioc, port_info); 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) 33428c2ecf20Sopenharmony_ci mptsas_probe_one_phy(&ioc->sh->shost_gendev, 33438c2ecf20Sopenharmony_ci &port_info->phy_info[i], ioc->sas_index, 1); 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci return 0; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci out_free_port_info: 33488c2ecf20Sopenharmony_ci kfree(hba); 33498c2ecf20Sopenharmony_ci out: 33508c2ecf20Sopenharmony_ci return error; 33518c2ecf20Sopenharmony_ci} 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_cistatic void 33548c2ecf20Sopenharmony_cimptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) 33558c2ecf20Sopenharmony_ci{ 33568c2ecf20Sopenharmony_ci struct mptsas_portinfo *parent; 33578c2ecf20Sopenharmony_ci struct device *parent_dev; 33588c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 33598c2ecf20Sopenharmony_ci int i; 33608c2ecf20Sopenharmony_ci u64 sas_address; /* expander sas address */ 33618c2ecf20Sopenharmony_ci u32 handle; 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci handle = port_info->phy_info[0].handle; 33648c2ecf20Sopenharmony_ci sas_address = port_info->phy_info[0].identify.sas_address; 33658c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 33668c2ecf20Sopenharmony_ci mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], 33678c2ecf20Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << 33688c2ecf20Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci mptsas_sas_device_pg0(ioc, 33718c2ecf20Sopenharmony_ci &port_info->phy_info[i].identify, 33728c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 33738c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 33748c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle); 33758c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.phy_id = 33768c2ecf20Sopenharmony_ci port_info->phy_info[i].phy_id; 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci if (port_info->phy_info[i].attached.handle) { 33798c2ecf20Sopenharmony_ci mptsas_sas_device_pg0(ioc, 33808c2ecf20Sopenharmony_ci &port_info->phy_info[i].attached, 33818c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << 33828c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 33838c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.handle); 33848c2ecf20Sopenharmony_ci port_info->phy_info[i].attached.phy_id = 33858c2ecf20Sopenharmony_ci port_info->phy_info[i].phy_id; 33868c2ecf20Sopenharmony_ci } 33878c2ecf20Sopenharmony_ci } 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 33908c2ecf20Sopenharmony_ci parent = mptsas_find_portinfo_by_handle(ioc, 33918c2ecf20Sopenharmony_ci port_info->phy_info[0].identify.handle_parent); 33928c2ecf20Sopenharmony_ci if (!parent) { 33938c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 33948c2ecf20Sopenharmony_ci return; 33958c2ecf20Sopenharmony_ci } 33968c2ecf20Sopenharmony_ci for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; 33978c2ecf20Sopenharmony_ci i++) { 33988c2ecf20Sopenharmony_ci if (parent->phy_info[i].attached.sas_address == sas_address) { 33998c2ecf20Sopenharmony_ci rphy = mptsas_get_rphy(&parent->phy_info[i]); 34008c2ecf20Sopenharmony_ci parent_dev = &rphy->dev; 34018c2ecf20Sopenharmony_ci } 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci mptsas_setup_wide_ports(ioc, port_info); 34068c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) 34078c2ecf20Sopenharmony_ci mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], 34088c2ecf20Sopenharmony_ci ioc->sas_index, 0); 34098c2ecf20Sopenharmony_ci} 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_cistatic void 34128c2ecf20Sopenharmony_cimptsas_expander_event_add(MPT_ADAPTER *ioc, 34138c2ecf20Sopenharmony_ci MpiEventDataSasExpanderStatusChange_t *expander_data) 34148c2ecf20Sopenharmony_ci{ 34158c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 34168c2ecf20Sopenharmony_ci int i; 34178c2ecf20Sopenharmony_ci __le64 sas_address; 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 34208c2ecf20Sopenharmony_ci if (!port_info) 34218c2ecf20Sopenharmony_ci BUG(); 34228c2ecf20Sopenharmony_ci port_info->num_phys = (expander_data->NumPhys) ? 34238c2ecf20Sopenharmony_ci expander_data->NumPhys : 1; 34248c2ecf20Sopenharmony_ci port_info->phy_info = kcalloc(port_info->num_phys, 34258c2ecf20Sopenharmony_ci sizeof(struct mptsas_phyinfo), GFP_KERNEL); 34268c2ecf20Sopenharmony_ci if (!port_info->phy_info) 34278c2ecf20Sopenharmony_ci BUG(); 34288c2ecf20Sopenharmony_ci memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); 34298c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 34308c2ecf20Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 34318c2ecf20Sopenharmony_ci port_info->phy_info[i].handle = 34328c2ecf20Sopenharmony_ci le16_to_cpu(expander_data->DevHandle); 34338c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.sas_address = 34348c2ecf20Sopenharmony_ci le64_to_cpu(sas_address); 34358c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 34368c2ecf20Sopenharmony_ci le16_to_cpu(expander_data->ParentDevHandle); 34378c2ecf20Sopenharmony_ci } 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 34408c2ecf20Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 34418c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " 34448c2ecf20Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 34458c2ecf20Sopenharmony_ci (unsigned long long)sas_address); 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 34488c2ecf20Sopenharmony_ci} 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci/** 34518c2ecf20Sopenharmony_ci * mptsas_delete_expander_siblings - remove siblings attached to expander 34528c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 34538c2ecf20Sopenharmony_ci * @parent: the parent port_info object 34548c2ecf20Sopenharmony_ci * @expander: the expander port_info object 34558c2ecf20Sopenharmony_ci **/ 34568c2ecf20Sopenharmony_cistatic void 34578c2ecf20Sopenharmony_cimptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo 34588c2ecf20Sopenharmony_ci *parent, struct mptsas_portinfo *expander) 34598c2ecf20Sopenharmony_ci{ 34608c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 34618c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 34628c2ecf20Sopenharmony_ci struct sas_rphy *rphy; 34638c2ecf20Sopenharmony_ci int i; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci phy_info = expander->phy_info; 34668c2ecf20Sopenharmony_ci for (i = 0; i < expander->num_phys; i++, phy_info++) { 34678c2ecf20Sopenharmony_ci rphy = mptsas_get_rphy(phy_info); 34688c2ecf20Sopenharmony_ci if (!rphy) 34698c2ecf20Sopenharmony_ci continue; 34708c2ecf20Sopenharmony_ci if (rphy->identify.device_type == SAS_END_DEVICE) 34718c2ecf20Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 34728c2ecf20Sopenharmony_ci } 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci phy_info = expander->phy_info; 34758c2ecf20Sopenharmony_ci for (i = 0; i < expander->num_phys; i++, phy_info++) { 34768c2ecf20Sopenharmony_ci rphy = mptsas_get_rphy(phy_info); 34778c2ecf20Sopenharmony_ci if (!rphy) 34788c2ecf20Sopenharmony_ci continue; 34798c2ecf20Sopenharmony_ci if (rphy->identify.device_type == 34808c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || 34818c2ecf20Sopenharmony_ci rphy->identify.device_type == 34828c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { 34838c2ecf20Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, 34848c2ecf20Sopenharmony_ci rphy->identify.sas_address); 34858c2ecf20Sopenharmony_ci if (!port_info) 34868c2ecf20Sopenharmony_ci continue; 34878c2ecf20Sopenharmony_ci if (port_info == parent) /* backlink rphy */ 34888c2ecf20Sopenharmony_ci continue; 34898c2ecf20Sopenharmony_ci /* 34908c2ecf20Sopenharmony_ci Delete this expander even if the expdevpage is exists 34918c2ecf20Sopenharmony_ci because the parent expander is already deleted 34928c2ecf20Sopenharmony_ci */ 34938c2ecf20Sopenharmony_ci mptsas_expander_delete(ioc, port_info, 1); 34948c2ecf20Sopenharmony_ci } 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci} 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci/** 35008c2ecf20Sopenharmony_ci * mptsas_expander_delete - remove this expander 35018c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 35028c2ecf20Sopenharmony_ci * @port_info: expander port_info struct 35038c2ecf20Sopenharmony_ci * @force: Flag to forcefully delete the expander 35048c2ecf20Sopenharmony_ci * 35058c2ecf20Sopenharmony_ci **/ 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_cistatic void mptsas_expander_delete(MPT_ADAPTER *ioc, 35088c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info, u8 force) 35098c2ecf20Sopenharmony_ci{ 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci struct mptsas_portinfo *parent; 35128c2ecf20Sopenharmony_ci int i; 35138c2ecf20Sopenharmony_ci u64 expander_sas_address; 35148c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 35158c2ecf20Sopenharmony_ci struct mptsas_portinfo buffer; 35168c2ecf20Sopenharmony_ci struct mptsas_portinfo_details *port_details; 35178c2ecf20Sopenharmony_ci struct sas_port *port; 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci if (!port_info) 35208c2ecf20Sopenharmony_ci return; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci /* see if expander is still there before deleting */ 35238c2ecf20Sopenharmony_ci mptsas_sas_expander_pg0(ioc, &buffer, 35248c2ecf20Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << 35258c2ecf20Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), 35268c2ecf20Sopenharmony_ci port_info->phy_info[0].identify.handle); 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci if (buffer.num_phys) { 35298c2ecf20Sopenharmony_ci kfree(buffer.phy_info); 35308c2ecf20Sopenharmony_ci if (!force) 35318c2ecf20Sopenharmony_ci return; 35328c2ecf20Sopenharmony_ci } 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci /* 35368c2ecf20Sopenharmony_ci * Obtain the port_info instance to the parent port 35378c2ecf20Sopenharmony_ci */ 35388c2ecf20Sopenharmony_ci port_details = NULL; 35398c2ecf20Sopenharmony_ci expander_sas_address = 35408c2ecf20Sopenharmony_ci port_info->phy_info[0].identify.sas_address; 35418c2ecf20Sopenharmony_ci parent = mptsas_find_portinfo_by_handle(ioc, 35428c2ecf20Sopenharmony_ci port_info->phy_info[0].identify.handle_parent); 35438c2ecf20Sopenharmony_ci mptsas_delete_expander_siblings(ioc, parent, port_info); 35448c2ecf20Sopenharmony_ci if (!parent) 35458c2ecf20Sopenharmony_ci goto out; 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci /* 35488c2ecf20Sopenharmony_ci * Delete rphys in the parent that point 35498c2ecf20Sopenharmony_ci * to this expander. 35508c2ecf20Sopenharmony_ci */ 35518c2ecf20Sopenharmony_ci phy_info = parent->phy_info; 35528c2ecf20Sopenharmony_ci port = NULL; 35538c2ecf20Sopenharmony_ci for (i = 0; i < parent->num_phys; i++, phy_info++) { 35548c2ecf20Sopenharmony_ci if (!phy_info->phy) 35558c2ecf20Sopenharmony_ci continue; 35568c2ecf20Sopenharmony_ci if (phy_info->attached.sas_address != 35578c2ecf20Sopenharmony_ci expander_sas_address) 35588c2ecf20Sopenharmony_ci continue; 35598c2ecf20Sopenharmony_ci if (!port) { 35608c2ecf20Sopenharmony_ci port = mptsas_get_port(phy_info); 35618c2ecf20Sopenharmony_ci port_details = phy_info->port_details; 35628c2ecf20Sopenharmony_ci } 35638c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &phy_info->phy->dev, 35648c2ecf20Sopenharmony_ci MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, 35658c2ecf20Sopenharmony_ci phy_info->phy_id, phy_info->phy); 35668c2ecf20Sopenharmony_ci sas_port_delete_phy(port, phy_info->phy); 35678c2ecf20Sopenharmony_ci } 35688c2ecf20Sopenharmony_ci if (port) { 35698c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &port->dev, 35708c2ecf20Sopenharmony_ci MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", 35718c2ecf20Sopenharmony_ci ioc->name, port->port_identifier, 35728c2ecf20Sopenharmony_ci (unsigned long long)expander_sas_address); 35738c2ecf20Sopenharmony_ci sas_port_delete(port); 35748c2ecf20Sopenharmony_ci mptsas_port_delete(ioc, port_details); 35758c2ecf20Sopenharmony_ci } 35768c2ecf20Sopenharmony_ci out: 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " 35798c2ecf20Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 35808c2ecf20Sopenharmony_ci (unsigned long long)expander_sas_address); 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci /* 35838c2ecf20Sopenharmony_ci * free link 35848c2ecf20Sopenharmony_ci */ 35858c2ecf20Sopenharmony_ci list_del(&port_info->list); 35868c2ecf20Sopenharmony_ci kfree(port_info->phy_info); 35878c2ecf20Sopenharmony_ci kfree(port_info); 35888c2ecf20Sopenharmony_ci} 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci/** 35928c2ecf20Sopenharmony_ci * mptsas_send_expander_event - expanders events 35938c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 35948c2ecf20Sopenharmony_ci * @expander_data: event data 35958c2ecf20Sopenharmony_ci * 35968c2ecf20Sopenharmony_ci * 35978c2ecf20Sopenharmony_ci * This function handles adding, removing, and refreshing 35988c2ecf20Sopenharmony_ci * device handles within the expander objects. 35998c2ecf20Sopenharmony_ci */ 36008c2ecf20Sopenharmony_cistatic void 36018c2ecf20Sopenharmony_cimptsas_send_expander_event(struct fw_event_work *fw_event) 36028c2ecf20Sopenharmony_ci{ 36038c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 36048c2ecf20Sopenharmony_ci MpiEventDataSasExpanderStatusChange_t *expander_data; 36058c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 36068c2ecf20Sopenharmony_ci __le64 sas_address; 36078c2ecf20Sopenharmony_ci int i; 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci ioc = fw_event->ioc; 36108c2ecf20Sopenharmony_ci expander_data = (MpiEventDataSasExpanderStatusChange_t *) 36118c2ecf20Sopenharmony_ci fw_event->event_data; 36128c2ecf20Sopenharmony_ci memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); 36138c2ecf20Sopenharmony_ci sas_address = le64_to_cpu(sas_address); 36148c2ecf20Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { 36178c2ecf20Sopenharmony_ci if (port_info) { 36188c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 36198c2ecf20Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 36208c2ecf20Sopenharmony_ci port_info->phy_info[i].handle = 36218c2ecf20Sopenharmony_ci le16_to_cpu(expander_data->DevHandle); 36228c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.sas_address = 36238c2ecf20Sopenharmony_ci le64_to_cpu(sas_address); 36248c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 36258c2ecf20Sopenharmony_ci le16_to_cpu(expander_data->ParentDevHandle); 36268c2ecf20Sopenharmony_ci } 36278c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 36288c2ecf20Sopenharmony_ci } else if (!port_info && expander_data->NumPhys) 36298c2ecf20Sopenharmony_ci mptsas_expander_event_add(ioc, expander_data); 36308c2ecf20Sopenharmony_ci } else if (expander_data->ReasonCode == 36318c2ecf20Sopenharmony_ci MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) 36328c2ecf20Sopenharmony_ci mptsas_expander_delete(ioc, port_info, 0); 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 36358c2ecf20Sopenharmony_ci} 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci/** 36398c2ecf20Sopenharmony_ci * mptsas_expander_add - 36408c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 36418c2ecf20Sopenharmony_ci * @handle: 36428c2ecf20Sopenharmony_ci * 36438c2ecf20Sopenharmony_ci */ 36448c2ecf20Sopenharmony_cistatic struct mptsas_portinfo * 36458c2ecf20Sopenharmony_cimptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) 36468c2ecf20Sopenharmony_ci{ 36478c2ecf20Sopenharmony_ci struct mptsas_portinfo buffer, *port_info; 36488c2ecf20Sopenharmony_ci int i; 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci if ((mptsas_sas_expander_pg0(ioc, &buffer, 36518c2ecf20Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << 36528c2ecf20Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) 36538c2ecf20Sopenharmony_ci return NULL; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); 36568c2ecf20Sopenharmony_ci if (!port_info) { 36578c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 36588c2ecf20Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 36598c2ecf20Sopenharmony_ci __func__, __LINE__)); 36608c2ecf20Sopenharmony_ci return NULL; 36618c2ecf20Sopenharmony_ci } 36628c2ecf20Sopenharmony_ci port_info->num_phys = buffer.num_phys; 36638c2ecf20Sopenharmony_ci port_info->phy_info = buffer.phy_info; 36648c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 36658c2ecf20Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 36668c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 36678c2ecf20Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 36688c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 36698c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " 36708c2ecf20Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 36718c2ecf20Sopenharmony_ci (unsigned long long)buffer.phy_info[0].identify.sas_address); 36728c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 36738c2ecf20Sopenharmony_ci return port_info; 36748c2ecf20Sopenharmony_ci} 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_cistatic void 36778c2ecf20Sopenharmony_cimptsas_send_link_status_event(struct fw_event_work *fw_event) 36788c2ecf20Sopenharmony_ci{ 36798c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 36808c2ecf20Sopenharmony_ci MpiEventDataSasPhyLinkStatus_t *link_data; 36818c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 36828c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 36838c2ecf20Sopenharmony_ci __le64 sas_address; 36848c2ecf20Sopenharmony_ci u8 phy_num; 36858c2ecf20Sopenharmony_ci u8 link_rate; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci ioc = fw_event->ioc; 36888c2ecf20Sopenharmony_ci link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); 36918c2ecf20Sopenharmony_ci sas_address = le64_to_cpu(sas_address); 36928c2ecf20Sopenharmony_ci link_rate = link_data->LinkRates >> 4; 36938c2ecf20Sopenharmony_ci phy_num = link_data->PhyNum; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); 36968c2ecf20Sopenharmony_ci if (port_info) { 36978c2ecf20Sopenharmony_ci phy_info = &port_info->phy_info[phy_num]; 36988c2ecf20Sopenharmony_ci if (phy_info) 36998c2ecf20Sopenharmony_ci phy_info->negotiated_link_rate = link_rate; 37008c2ecf20Sopenharmony_ci } 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || 37038c2ecf20Sopenharmony_ci link_rate == MPI_SAS_IOUNIT0_RATE_3_0 || 37048c2ecf20Sopenharmony_ci link_rate == MPI_SAS_IOUNIT0_RATE_6_0) { 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci if (!port_info) { 37078c2ecf20Sopenharmony_ci if (ioc->old_sas_discovery_protocal) { 37088c2ecf20Sopenharmony_ci port_info = mptsas_expander_add(ioc, 37098c2ecf20Sopenharmony_ci le16_to_cpu(link_data->DevHandle)); 37108c2ecf20Sopenharmony_ci if (port_info) 37118c2ecf20Sopenharmony_ci goto out; 37128c2ecf20Sopenharmony_ci } 37138c2ecf20Sopenharmony_ci goto out; 37148c2ecf20Sopenharmony_ci } 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci if (port_info == ioc->hba_port_info) 37178c2ecf20Sopenharmony_ci mptsas_probe_hba_phys(ioc); 37188c2ecf20Sopenharmony_ci else 37198c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 37208c2ecf20Sopenharmony_ci } else if (phy_info && phy_info->phy) { 37218c2ecf20Sopenharmony_ci if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) 37228c2ecf20Sopenharmony_ci phy_info->phy->negotiated_linkrate = 37238c2ecf20Sopenharmony_ci SAS_PHY_DISABLED; 37248c2ecf20Sopenharmony_ci else if (link_rate == 37258c2ecf20Sopenharmony_ci MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) 37268c2ecf20Sopenharmony_ci phy_info->phy->negotiated_linkrate = 37278c2ecf20Sopenharmony_ci SAS_LINK_RATE_FAILED; 37288c2ecf20Sopenharmony_ci else { 37298c2ecf20Sopenharmony_ci phy_info->phy->negotiated_linkrate = 37308c2ecf20Sopenharmony_ci SAS_LINK_RATE_UNKNOWN; 37318c2ecf20Sopenharmony_ci if (ioc->device_missing_delay && 37328c2ecf20Sopenharmony_ci mptsas_is_end_device(&phy_info->attached)) { 37338c2ecf20Sopenharmony_ci struct scsi_device *sdev; 37348c2ecf20Sopenharmony_ci VirtDevice *vdevice; 37358c2ecf20Sopenharmony_ci u8 channel, id; 37368c2ecf20Sopenharmony_ci id = phy_info->attached.id; 37378c2ecf20Sopenharmony_ci channel = phy_info->attached.channel; 37388c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 37398c2ecf20Sopenharmony_ci "Link down for fw_id %d:fw_channel %d\n", 37408c2ecf20Sopenharmony_ci ioc->name, phy_info->attached.id, 37418c2ecf20Sopenharmony_ci phy_info->attached.channel)); 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 37448c2ecf20Sopenharmony_ci vdevice = sdev->hostdata; 37458c2ecf20Sopenharmony_ci if ((vdevice == NULL) || 37468c2ecf20Sopenharmony_ci (vdevice->vtarget == NULL)) 37478c2ecf20Sopenharmony_ci continue; 37488c2ecf20Sopenharmony_ci if ((vdevice->vtarget->tflags & 37498c2ecf20Sopenharmony_ci MPT_TARGET_FLAGS_RAID_COMPONENT || 37508c2ecf20Sopenharmony_ci vdevice->vtarget->raidVolume)) 37518c2ecf20Sopenharmony_ci continue; 37528c2ecf20Sopenharmony_ci if (vdevice->vtarget->id == id && 37538c2ecf20Sopenharmony_ci vdevice->vtarget->channel == 37548c2ecf20Sopenharmony_ci channel) 37558c2ecf20Sopenharmony_ci devtprintk(ioc, 37568c2ecf20Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT 37578c2ecf20Sopenharmony_ci "SDEV OUTSTANDING CMDS" 37588c2ecf20Sopenharmony_ci "%d\n", ioc->name, 37598c2ecf20Sopenharmony_ci atomic_read(&sdev->device_busy))); 37608c2ecf20Sopenharmony_ci } 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci } 37648c2ecf20Sopenharmony_ci } 37658c2ecf20Sopenharmony_ci out: 37668c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 37678c2ecf20Sopenharmony_ci} 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_cistatic void 37708c2ecf20Sopenharmony_cimptsas_not_responding_devices(MPT_ADAPTER *ioc) 37718c2ecf20Sopenharmony_ci{ 37728c2ecf20Sopenharmony_ci struct mptsas_portinfo buffer, *port_info; 37738c2ecf20Sopenharmony_ci struct mptsas_device_info *sas_info; 37748c2ecf20Sopenharmony_ci struct mptsas_devinfo sas_device; 37758c2ecf20Sopenharmony_ci u32 handle; 37768c2ecf20Sopenharmony_ci VirtTarget *vtarget = NULL; 37778c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 37788c2ecf20Sopenharmony_ci u8 found_expander; 37798c2ecf20Sopenharmony_ci int retval, retry_count; 37808c2ecf20Sopenharmony_ci unsigned long flags; 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 37858c2ecf20Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 37868c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT 37878c2ecf20Sopenharmony_ci "%s: exiting due to a parallel reset \n", ioc->name, 37888c2ecf20Sopenharmony_ci __func__)); 37898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 37908c2ecf20Sopenharmony_ci return; 37918c2ecf20Sopenharmony_ci } 37928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci /* devices, logical volumes */ 37958c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 37968c2ecf20Sopenharmony_ci redo_device_scan: 37978c2ecf20Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { 37988c2ecf20Sopenharmony_ci if (sas_info->is_cached) 37998c2ecf20Sopenharmony_ci continue; 38008c2ecf20Sopenharmony_ci if (!sas_info->is_logical_volume) { 38018c2ecf20Sopenharmony_ci sas_device.handle = 0; 38028c2ecf20Sopenharmony_ci retry_count = 0; 38038c2ecf20Sopenharmony_ciretry_page: 38048c2ecf20Sopenharmony_ci retval = mptsas_sas_device_pg0(ioc, &sas_device, 38058c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID 38068c2ecf20Sopenharmony_ci << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 38078c2ecf20Sopenharmony_ci (sas_info->fw.channel << 8) + 38088c2ecf20Sopenharmony_ci sas_info->fw.id); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci if (sas_device.handle) 38118c2ecf20Sopenharmony_ci continue; 38128c2ecf20Sopenharmony_ci if (retval == -EBUSY) { 38138c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 38148c2ecf20Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 38158c2ecf20Sopenharmony_ci dfailprintk(ioc, 38168c2ecf20Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT 38178c2ecf20Sopenharmony_ci "%s: exiting due to reset\n", 38188c2ecf20Sopenharmony_ci ioc->name, __func__)); 38198c2ecf20Sopenharmony_ci spin_unlock_irqrestore 38208c2ecf20Sopenharmony_ci (&ioc->taskmgmt_lock, flags); 38218c2ecf20Sopenharmony_ci mutex_unlock(&ioc-> 38228c2ecf20Sopenharmony_ci sas_device_info_mutex); 38238c2ecf20Sopenharmony_ci return; 38248c2ecf20Sopenharmony_ci } 38258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, 38268c2ecf20Sopenharmony_ci flags); 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci if (retval && (retval != -ENODEV)) { 38308c2ecf20Sopenharmony_ci if (retry_count < 10) { 38318c2ecf20Sopenharmony_ci retry_count++; 38328c2ecf20Sopenharmony_ci goto retry_page; 38338c2ecf20Sopenharmony_ci } else { 38348c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 38358c2ecf20Sopenharmony_ci "%s: Config page retry exceeded retry " 38368c2ecf20Sopenharmony_ci "count deleting device 0x%llx\n", 38378c2ecf20Sopenharmony_ci ioc->name, __func__, 38388c2ecf20Sopenharmony_ci sas_info->sas_address)); 38398c2ecf20Sopenharmony_ci } 38408c2ecf20Sopenharmony_ci } 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci /* delete device */ 38438c2ecf20Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, 38448c2ecf20Sopenharmony_ci sas_info->fw.channel, sas_info->fw.id); 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci if (vtarget) 38478c2ecf20Sopenharmony_ci vtarget->deleted = 1; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 38508c2ecf20Sopenharmony_ci sas_info->sas_address); 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 38538c2ecf20Sopenharmony_ci goto redo_device_scan; 38548c2ecf20Sopenharmony_ci } else 38558c2ecf20Sopenharmony_ci mptsas_volume_delete(ioc, sas_info->fw.id); 38568c2ecf20Sopenharmony_ci } 38578c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci /* expanders */ 38608c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 38618c2ecf20Sopenharmony_ci redo_expander_scan: 38628c2ecf20Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) { 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci if (!(port_info->phy_info[0].identify.device_info & 38658c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SMP_TARGET)) 38668c2ecf20Sopenharmony_ci continue; 38678c2ecf20Sopenharmony_ci found_expander = 0; 38688c2ecf20Sopenharmony_ci handle = 0xFFFF; 38698c2ecf20Sopenharmony_ci while (!mptsas_sas_expander_pg0(ioc, &buffer, 38708c2ecf20Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << 38718c2ecf20Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && 38728c2ecf20Sopenharmony_ci !found_expander) { 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci handle = buffer.phy_info[0].handle; 38758c2ecf20Sopenharmony_ci if (buffer.phy_info[0].identify.sas_address == 38768c2ecf20Sopenharmony_ci port_info->phy_info[0].identify.sas_address) { 38778c2ecf20Sopenharmony_ci found_expander = 1; 38788c2ecf20Sopenharmony_ci } 38798c2ecf20Sopenharmony_ci kfree(buffer.phy_info); 38808c2ecf20Sopenharmony_ci } 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci if (!found_expander) { 38838c2ecf20Sopenharmony_ci mptsas_expander_delete(ioc, port_info, 0); 38848c2ecf20Sopenharmony_ci goto redo_expander_scan; 38858c2ecf20Sopenharmony_ci } 38868c2ecf20Sopenharmony_ci } 38878c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 38888c2ecf20Sopenharmony_ci} 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci/** 38918c2ecf20Sopenharmony_ci * mptsas_probe_expanders - adding expanders 38928c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 38938c2ecf20Sopenharmony_ci * 38948c2ecf20Sopenharmony_ci **/ 38958c2ecf20Sopenharmony_cistatic void 38968c2ecf20Sopenharmony_cimptsas_probe_expanders(MPT_ADAPTER *ioc) 38978c2ecf20Sopenharmony_ci{ 38988c2ecf20Sopenharmony_ci struct mptsas_portinfo buffer, *port_info; 38998c2ecf20Sopenharmony_ci u32 handle; 39008c2ecf20Sopenharmony_ci int i; 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_ci handle = 0xFFFF; 39038c2ecf20Sopenharmony_ci while (!mptsas_sas_expander_pg0(ioc, &buffer, 39048c2ecf20Sopenharmony_ci (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << 39058c2ecf20Sopenharmony_ci MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci handle = buffer.phy_info[0].handle; 39088c2ecf20Sopenharmony_ci port_info = mptsas_find_portinfo_by_sas_address(ioc, 39098c2ecf20Sopenharmony_ci buffer.phy_info[0].identify.sas_address); 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci if (port_info) { 39128c2ecf20Sopenharmony_ci /* refreshing handles */ 39138c2ecf20Sopenharmony_ci for (i = 0; i < buffer.num_phys; i++) { 39148c2ecf20Sopenharmony_ci port_info->phy_info[i].handle = handle; 39158c2ecf20Sopenharmony_ci port_info->phy_info[i].identify.handle_parent = 39168c2ecf20Sopenharmony_ci buffer.phy_info[0].identify.handle_parent; 39178c2ecf20Sopenharmony_ci } 39188c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 39198c2ecf20Sopenharmony_ci kfree(buffer.phy_info); 39208c2ecf20Sopenharmony_ci continue; 39218c2ecf20Sopenharmony_ci } 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); 39248c2ecf20Sopenharmony_ci if (!port_info) { 39258c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 39268c2ecf20Sopenharmony_ci "%s: exit at line=%d\n", ioc->name, 39278c2ecf20Sopenharmony_ci __func__, __LINE__)); 39288c2ecf20Sopenharmony_ci return; 39298c2ecf20Sopenharmony_ci } 39308c2ecf20Sopenharmony_ci port_info->num_phys = buffer.num_phys; 39318c2ecf20Sopenharmony_ci port_info->phy_info = buffer.phy_info; 39328c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) 39338c2ecf20Sopenharmony_ci port_info->phy_info[i].portinfo = port_info; 39348c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 39358c2ecf20Sopenharmony_ci list_add_tail(&port_info->list, &ioc->sas_topology); 39368c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 39378c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " 39388c2ecf20Sopenharmony_ci "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, 39398c2ecf20Sopenharmony_ci (unsigned long long)buffer.phy_info[0].identify.sas_address); 39408c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 39418c2ecf20Sopenharmony_ci } 39428c2ecf20Sopenharmony_ci} 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_cistatic void 39458c2ecf20Sopenharmony_cimptsas_probe_devices(MPT_ADAPTER *ioc) 39468c2ecf20Sopenharmony_ci{ 39478c2ecf20Sopenharmony_ci u16 handle; 39488c2ecf20Sopenharmony_ci struct mptsas_devinfo sas_device; 39498c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci handle = 0xFFFF; 39528c2ecf20Sopenharmony_ci while (!(mptsas_sas_device_pg0(ioc, &sas_device, 39538c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci handle = sas_device.handle; 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci if ((sas_device.device_info & 39588c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_INFO_SSP_TARGET | 39598c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET | 39608c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) 39618c2ecf20Sopenharmony_ci continue; 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci /* If there is no FW B_T mapping for this device then continue 39648c2ecf20Sopenharmony_ci * */ 39658c2ecf20Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 39668c2ecf20Sopenharmony_ci || !(sas_device.flags & 39678c2ecf20Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 39688c2ecf20Sopenharmony_ci continue; 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); 39718c2ecf20Sopenharmony_ci if (!phy_info) 39728c2ecf20Sopenharmony_ci continue; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci if (mptsas_get_rphy(phy_info)) 39758c2ecf20Sopenharmony_ci continue; 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci mptsas_add_end_device(ioc, phy_info); 39788c2ecf20Sopenharmony_ci } 39798c2ecf20Sopenharmony_ci} 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci/** 39828c2ecf20Sopenharmony_ci * mptsas_scan_sas_topology - 39838c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 39848c2ecf20Sopenharmony_ci * @sas_address: 39858c2ecf20Sopenharmony_ci * 39868c2ecf20Sopenharmony_ci **/ 39878c2ecf20Sopenharmony_cistatic void 39888c2ecf20Sopenharmony_cimptsas_scan_sas_topology(MPT_ADAPTER *ioc) 39898c2ecf20Sopenharmony_ci{ 39908c2ecf20Sopenharmony_ci struct scsi_device *sdev; 39918c2ecf20Sopenharmony_ci int i; 39928c2ecf20Sopenharmony_ci 39938c2ecf20Sopenharmony_ci mptsas_probe_hba_phys(ioc); 39948c2ecf20Sopenharmony_ci mptsas_probe_expanders(ioc); 39958c2ecf20Sopenharmony_ci mptsas_probe_devices(ioc); 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci /* 39988c2ecf20Sopenharmony_ci Reporting RAID volumes. 39998c2ecf20Sopenharmony_ci */ 40008c2ecf20Sopenharmony_ci if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || 40018c2ecf20Sopenharmony_ci !ioc->raid_data.pIocPg2->NumActiveVolumes) 40028c2ecf20Sopenharmony_ci return; 40038c2ecf20Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 40048c2ecf20Sopenharmony_ci sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, 40058c2ecf20Sopenharmony_ci ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); 40068c2ecf20Sopenharmony_ci if (sdev) { 40078c2ecf20Sopenharmony_ci scsi_device_put(sdev); 40088c2ecf20Sopenharmony_ci continue; 40098c2ecf20Sopenharmony_ci } 40108c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " 40118c2ecf20Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, 40128c2ecf20Sopenharmony_ci ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); 40138c2ecf20Sopenharmony_ci scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, 40148c2ecf20Sopenharmony_ci ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); 40158c2ecf20Sopenharmony_ci } 40168c2ecf20Sopenharmony_ci} 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci 40198c2ecf20Sopenharmony_cistatic void 40208c2ecf20Sopenharmony_cimptsas_handle_queue_full_event(struct fw_event_work *fw_event) 40218c2ecf20Sopenharmony_ci{ 40228c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 40238c2ecf20Sopenharmony_ci EventDataQueueFull_t *qfull_data; 40248c2ecf20Sopenharmony_ci struct mptsas_device_info *sas_info; 40258c2ecf20Sopenharmony_ci struct scsi_device *sdev; 40268c2ecf20Sopenharmony_ci int depth; 40278c2ecf20Sopenharmony_ci int id = -1; 40288c2ecf20Sopenharmony_ci int channel = -1; 40298c2ecf20Sopenharmony_ci int fw_id, fw_channel; 40308c2ecf20Sopenharmony_ci u16 current_depth; 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci ioc = fw_event->ioc; 40348c2ecf20Sopenharmony_ci qfull_data = (EventDataQueueFull_t *)fw_event->event_data; 40358c2ecf20Sopenharmony_ci fw_id = qfull_data->TargetID; 40368c2ecf20Sopenharmony_ci fw_channel = qfull_data->Bus; 40378c2ecf20Sopenharmony_ci current_depth = le16_to_cpu(qfull_data->CurrentDepth); 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci /* if hidden raid component, look for the volume id */ 40408c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_device_info_mutex); 40418c2ecf20Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { 40428c2ecf20Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, 40438c2ecf20Sopenharmony_ci list) { 40448c2ecf20Sopenharmony_ci if (sas_info->is_cached || 40458c2ecf20Sopenharmony_ci sas_info->is_logical_volume) 40468c2ecf20Sopenharmony_ci continue; 40478c2ecf20Sopenharmony_ci if (sas_info->is_hidden_raid_component && 40488c2ecf20Sopenharmony_ci (sas_info->fw.channel == fw_channel && 40498c2ecf20Sopenharmony_ci sas_info->fw.id == fw_id)) { 40508c2ecf20Sopenharmony_ci id = sas_info->volume_id; 40518c2ecf20Sopenharmony_ci channel = MPTSAS_RAID_CHANNEL; 40528c2ecf20Sopenharmony_ci goto out; 40538c2ecf20Sopenharmony_ci } 40548c2ecf20Sopenharmony_ci } 40558c2ecf20Sopenharmony_ci } else { 40568c2ecf20Sopenharmony_ci list_for_each_entry(sas_info, &ioc->sas_device_info_list, 40578c2ecf20Sopenharmony_ci list) { 40588c2ecf20Sopenharmony_ci if (sas_info->is_cached || 40598c2ecf20Sopenharmony_ci sas_info->is_hidden_raid_component || 40608c2ecf20Sopenharmony_ci sas_info->is_logical_volume) 40618c2ecf20Sopenharmony_ci continue; 40628c2ecf20Sopenharmony_ci if (sas_info->fw.channel == fw_channel && 40638c2ecf20Sopenharmony_ci sas_info->fw.id == fw_id) { 40648c2ecf20Sopenharmony_ci id = sas_info->os.id; 40658c2ecf20Sopenharmony_ci channel = sas_info->os.channel; 40668c2ecf20Sopenharmony_ci goto out; 40678c2ecf20Sopenharmony_ci } 40688c2ecf20Sopenharmony_ci } 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci } 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci out: 40738c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_device_info_mutex); 40748c2ecf20Sopenharmony_ci 40758c2ecf20Sopenharmony_ci if (id != -1) { 40768c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 40778c2ecf20Sopenharmony_ci if (sdev->id == id && sdev->channel == channel) { 40788c2ecf20Sopenharmony_ci if (current_depth > sdev->queue_depth) { 40798c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 40808c2ecf20Sopenharmony_ci "strange observation, the queue " 40818c2ecf20Sopenharmony_ci "depth is (%d) meanwhile fw queue " 40828c2ecf20Sopenharmony_ci "depth (%d)\n", sdev->queue_depth, 40838c2ecf20Sopenharmony_ci current_depth); 40848c2ecf20Sopenharmony_ci continue; 40858c2ecf20Sopenharmony_ci } 40868c2ecf20Sopenharmony_ci depth = scsi_track_queue_full(sdev, 40878c2ecf20Sopenharmony_ci sdev->queue_depth - 1); 40888c2ecf20Sopenharmony_ci if (depth > 0) 40898c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 40908c2ecf20Sopenharmony_ci "Queue depth reduced to (%d)\n", 40918c2ecf20Sopenharmony_ci depth); 40928c2ecf20Sopenharmony_ci else if (depth < 0) 40938c2ecf20Sopenharmony_ci sdev_printk(KERN_INFO, sdev, 40948c2ecf20Sopenharmony_ci "Tagged Command Queueing is being " 40958c2ecf20Sopenharmony_ci "disabled\n"); 40968c2ecf20Sopenharmony_ci else if (depth == 0) 40978c2ecf20Sopenharmony_ci sdev_printk(KERN_DEBUG, sdev, 40988c2ecf20Sopenharmony_ci "Queue depth not changed yet\n"); 40998c2ecf20Sopenharmony_ci } 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci } 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 41048c2ecf20Sopenharmony_ci} 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_cistatic struct mptsas_phyinfo * 41088c2ecf20Sopenharmony_cimptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) 41098c2ecf20Sopenharmony_ci{ 41108c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 41118c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 41128c2ecf20Sopenharmony_ci int i; 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 41158c2ecf20Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) { 41168c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys; i++) { 41178c2ecf20Sopenharmony_ci if (!mptsas_is_end_device( 41188c2ecf20Sopenharmony_ci &port_info->phy_info[i].attached)) 41198c2ecf20Sopenharmony_ci continue; 41208c2ecf20Sopenharmony_ci if (port_info->phy_info[i].attached.sas_address 41218c2ecf20Sopenharmony_ci != sas_address) 41228c2ecf20Sopenharmony_ci continue; 41238c2ecf20Sopenharmony_ci phy_info = &port_info->phy_info[i]; 41248c2ecf20Sopenharmony_ci break; 41258c2ecf20Sopenharmony_ci } 41268c2ecf20Sopenharmony_ci } 41278c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 41288c2ecf20Sopenharmony_ci return phy_info; 41298c2ecf20Sopenharmony_ci} 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci/** 41328c2ecf20Sopenharmony_ci * mptsas_find_phyinfo_by_phys_disk_num - 41338c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 41348c2ecf20Sopenharmony_ci * @phys_disk_num: 41358c2ecf20Sopenharmony_ci * @channel: 41368c2ecf20Sopenharmony_ci * @id: 41378c2ecf20Sopenharmony_ci * 41388c2ecf20Sopenharmony_ci **/ 41398c2ecf20Sopenharmony_cistatic struct mptsas_phyinfo * 41408c2ecf20Sopenharmony_cimptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, 41418c2ecf20Sopenharmony_ci u8 channel, u8 id) 41428c2ecf20Sopenharmony_ci{ 41438c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info = NULL; 41448c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 41458c2ecf20Sopenharmony_ci RaidPhysDiskPage1_t *phys_disk = NULL; 41468c2ecf20Sopenharmony_ci int num_paths; 41478c2ecf20Sopenharmony_ci u64 sas_address = 0; 41488c2ecf20Sopenharmony_ci int i; 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci phy_info = NULL; 41518c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg3) 41528c2ecf20Sopenharmony_ci return NULL; 41538c2ecf20Sopenharmony_ci /* dual port support */ 41548c2ecf20Sopenharmony_ci num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); 41558c2ecf20Sopenharmony_ci if (!num_paths) 41568c2ecf20Sopenharmony_ci goto out; 41578c2ecf20Sopenharmony_ci phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + 41588c2ecf20Sopenharmony_ci (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); 41598c2ecf20Sopenharmony_ci if (!phys_disk) 41608c2ecf20Sopenharmony_ci goto out; 41618c2ecf20Sopenharmony_ci mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); 41628c2ecf20Sopenharmony_ci for (i = 0; i < num_paths; i++) { 41638c2ecf20Sopenharmony_ci if ((phys_disk->Path[i].Flags & 1) != 0) 41648c2ecf20Sopenharmony_ci /* entry no longer valid */ 41658c2ecf20Sopenharmony_ci continue; 41668c2ecf20Sopenharmony_ci if ((id == phys_disk->Path[i].PhysDiskID) && 41678c2ecf20Sopenharmony_ci (channel == phys_disk->Path[i].PhysDiskBus)) { 41688c2ecf20Sopenharmony_ci memcpy(&sas_address, &phys_disk->Path[i].WWID, 41698c2ecf20Sopenharmony_ci sizeof(u64)); 41708c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 41718c2ecf20Sopenharmony_ci sas_address); 41728c2ecf20Sopenharmony_ci goto out; 41738c2ecf20Sopenharmony_ci } 41748c2ecf20Sopenharmony_ci } 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci out: 41778c2ecf20Sopenharmony_ci kfree(phys_disk); 41788c2ecf20Sopenharmony_ci if (phy_info) 41798c2ecf20Sopenharmony_ci return phy_info; 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_ci /* 41828c2ecf20Sopenharmony_ci * Extra code to handle RAID0 case, where the sas_address is not updated 41838c2ecf20Sopenharmony_ci * in phys_disk_page_1 when hotswapped 41848c2ecf20Sopenharmony_ci */ 41858c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 41868c2ecf20Sopenharmony_ci list_for_each_entry(port_info, &ioc->sas_topology, list) { 41878c2ecf20Sopenharmony_ci for (i = 0; i < port_info->num_phys && !phy_info; i++) { 41888c2ecf20Sopenharmony_ci if (!mptsas_is_end_device( 41898c2ecf20Sopenharmony_ci &port_info->phy_info[i].attached)) 41908c2ecf20Sopenharmony_ci continue; 41918c2ecf20Sopenharmony_ci if (port_info->phy_info[i].attached.phys_disk_num == ~0) 41928c2ecf20Sopenharmony_ci continue; 41938c2ecf20Sopenharmony_ci if ((port_info->phy_info[i].attached.phys_disk_num == 41948c2ecf20Sopenharmony_ci phys_disk_num) && 41958c2ecf20Sopenharmony_ci (port_info->phy_info[i].attached.id == id) && 41968c2ecf20Sopenharmony_ci (port_info->phy_info[i].attached.channel == 41978c2ecf20Sopenharmony_ci channel)) 41988c2ecf20Sopenharmony_ci phy_info = &port_info->phy_info[i]; 41998c2ecf20Sopenharmony_ci } 42008c2ecf20Sopenharmony_ci } 42018c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 42028c2ecf20Sopenharmony_ci return phy_info; 42038c2ecf20Sopenharmony_ci} 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_cistatic void 42068c2ecf20Sopenharmony_cimptsas_reprobe_lun(struct scsi_device *sdev, void *data) 42078c2ecf20Sopenharmony_ci{ 42088c2ecf20Sopenharmony_ci int rc; 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci sdev->no_uld_attach = data ? 1 : 0; 42118c2ecf20Sopenharmony_ci rc = scsi_device_reprobe(sdev); 42128c2ecf20Sopenharmony_ci} 42138c2ecf20Sopenharmony_ci 42148c2ecf20Sopenharmony_cistatic void 42158c2ecf20Sopenharmony_cimptsas_reprobe_target(struct scsi_target *starget, int uld_attach) 42168c2ecf20Sopenharmony_ci{ 42178c2ecf20Sopenharmony_ci starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, 42188c2ecf20Sopenharmony_ci mptsas_reprobe_lun); 42198c2ecf20Sopenharmony_ci} 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_cistatic void 42228c2ecf20Sopenharmony_cimptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) 42238c2ecf20Sopenharmony_ci{ 42248c2ecf20Sopenharmony_ci CONFIGPARMS cfg; 42258c2ecf20Sopenharmony_ci ConfigPageHeader_t hdr; 42268c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 42278c2ecf20Sopenharmony_ci pRaidVolumePage0_t buffer = NULL; 42288c2ecf20Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 42298c2ecf20Sopenharmony_ci int i; 42308c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 42318c2ecf20Sopenharmony_ci struct mptsas_devinfo sas_device; 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 42348c2ecf20Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 42358c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; 42368c2ecf20Sopenharmony_ci cfg.pageAddr = (channel << 8) + id; 42378c2ecf20Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 42388c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 42398c2ecf20Sopenharmony_ci cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 42428c2ecf20Sopenharmony_ci goto out; 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci if (!hdr.PageLength) 42458c2ecf20Sopenharmony_ci goto out; 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, 42488c2ecf20Sopenharmony_ci &dma_handle); 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci if (!buffer) 42518c2ecf20Sopenharmony_ci goto out; 42528c2ecf20Sopenharmony_ci 42538c2ecf20Sopenharmony_ci cfg.physAddr = dma_handle; 42548c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 42578c2ecf20Sopenharmony_ci goto out; 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci if (!(buffer->VolumeStatus.Flags & 42608c2ecf20Sopenharmony_ci MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) 42618c2ecf20Sopenharmony_ci goto out; 42628c2ecf20Sopenharmony_ci 42638c2ecf20Sopenharmony_ci if (!buffer->NumPhysDisks) 42648c2ecf20Sopenharmony_ci goto out; 42658c2ecf20Sopenharmony_ci 42668c2ecf20Sopenharmony_ci for (i = 0; i < buffer->NumPhysDisks; i++) { 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_ci if (mpt_raid_phys_disk_pg0(ioc, 42698c2ecf20Sopenharmony_ci buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) 42708c2ecf20Sopenharmony_ci continue; 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci if (mptsas_sas_device_pg0(ioc, &sas_device, 42738c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 42748c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 42758c2ecf20Sopenharmony_ci (phys_disk.PhysDiskBus << 8) + 42768c2ecf20Sopenharmony_ci phys_disk.PhysDiskID)) 42778c2ecf20Sopenharmony_ci continue; 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_ci /* If there is no FW B_T mapping for this device then continue 42808c2ecf20Sopenharmony_ci * */ 42818c2ecf20Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 42828c2ecf20Sopenharmony_ci || !(sas_device.flags & 42838c2ecf20Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 42848c2ecf20Sopenharmony_ci continue; 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 42888c2ecf20Sopenharmony_ci sas_device.sas_address); 42898c2ecf20Sopenharmony_ci mptsas_add_end_device(ioc, phy_info); 42908c2ecf20Sopenharmony_ci } 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci out: 42938c2ecf20Sopenharmony_ci if (buffer) 42948c2ecf20Sopenharmony_ci pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, 42958c2ecf20Sopenharmony_ci dma_handle); 42968c2ecf20Sopenharmony_ci} 42978c2ecf20Sopenharmony_ci/* 42988c2ecf20Sopenharmony_ci * Work queue thread to handle SAS hotplug events 42998c2ecf20Sopenharmony_ci */ 43008c2ecf20Sopenharmony_cistatic void 43018c2ecf20Sopenharmony_cimptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, 43028c2ecf20Sopenharmony_ci struct mptsas_hotplug_event *hot_plug_info) 43038c2ecf20Sopenharmony_ci{ 43048c2ecf20Sopenharmony_ci struct mptsas_phyinfo *phy_info; 43058c2ecf20Sopenharmony_ci struct scsi_target * starget; 43068c2ecf20Sopenharmony_ci struct mptsas_devinfo sas_device; 43078c2ecf20Sopenharmony_ci VirtTarget *vtarget; 43088c2ecf20Sopenharmony_ci int i; 43098c2ecf20Sopenharmony_ci struct mptsas_portinfo *port_info; 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_ci switch (hot_plug_info->event_type) { 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci case MPTSAS_ADD_PHYSDISK: 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg2) 43168c2ecf20Sopenharmony_ci break; 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 43198c2ecf20Sopenharmony_ci if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == 43208c2ecf20Sopenharmony_ci hot_plug_info->id) { 43218c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "firmware bug: unable " 43228c2ecf20Sopenharmony_ci "to add hidden disk - target_id matches " 43238c2ecf20Sopenharmony_ci "volume_id\n", ioc->name); 43248c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 43258c2ecf20Sopenharmony_ci return; 43268c2ecf20Sopenharmony_ci } 43278c2ecf20Sopenharmony_ci } 43288c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 43298c2ecf20Sopenharmony_ci fallthrough; 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci case MPTSAS_ADD_DEVICE: 43328c2ecf20Sopenharmony_ci memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); 43338c2ecf20Sopenharmony_ci mptsas_sas_device_pg0(ioc, &sas_device, 43348c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 43358c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 43368c2ecf20Sopenharmony_ci (hot_plug_info->channel << 8) + 43378c2ecf20Sopenharmony_ci hot_plug_info->id); 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci /* If there is no FW B_T mapping for this device then break 43408c2ecf20Sopenharmony_ci * */ 43418c2ecf20Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 43428c2ecf20Sopenharmony_ci || !(sas_device.flags & 43438c2ecf20Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 43448c2ecf20Sopenharmony_ci break; 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci if (!sas_device.handle) 43478c2ecf20Sopenharmony_ci return; 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); 43508c2ecf20Sopenharmony_ci /* Device hot plug */ 43518c2ecf20Sopenharmony_ci if (!phy_info) { 43528c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 43538c2ecf20Sopenharmony_ci "%s %d HOT PLUG: " 43548c2ecf20Sopenharmony_ci "parent handle of device %x\n", ioc->name, 43558c2ecf20Sopenharmony_ci __func__, __LINE__, sas_device.handle_parent)); 43568c2ecf20Sopenharmony_ci port_info = mptsas_find_portinfo_by_handle(ioc, 43578c2ecf20Sopenharmony_ci sas_device.handle_parent); 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci if (port_info == ioc->hba_port_info) 43608c2ecf20Sopenharmony_ci mptsas_probe_hba_phys(ioc); 43618c2ecf20Sopenharmony_ci else if (port_info) 43628c2ecf20Sopenharmony_ci mptsas_expander_refresh(ioc, port_info); 43638c2ecf20Sopenharmony_ci else { 43648c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 43658c2ecf20Sopenharmony_ci "%s %d port info is NULL\n", 43668c2ecf20Sopenharmony_ci ioc->name, __func__, __LINE__)); 43678c2ecf20Sopenharmony_ci break; 43688c2ecf20Sopenharmony_ci } 43698c2ecf20Sopenharmony_ci phy_info = mptsas_refreshing_device_handles 43708c2ecf20Sopenharmony_ci (ioc, &sas_device); 43718c2ecf20Sopenharmony_ci } 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci if (!phy_info) { 43748c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 43758c2ecf20Sopenharmony_ci "%s %d phy info is NULL\n", 43768c2ecf20Sopenharmony_ci ioc->name, __func__, __LINE__)); 43778c2ecf20Sopenharmony_ci break; 43788c2ecf20Sopenharmony_ci } 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci if (mptsas_get_rphy(phy_info)) 43818c2ecf20Sopenharmony_ci break; 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci mptsas_add_end_device(ioc, phy_info); 43848c2ecf20Sopenharmony_ci break; 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci case MPTSAS_DEL_DEVICE: 43878c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 43888c2ecf20Sopenharmony_ci hot_plug_info->sas_address); 43898c2ecf20Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 43908c2ecf20Sopenharmony_ci break; 43918c2ecf20Sopenharmony_ci 43928c2ecf20Sopenharmony_ci case MPTSAS_DEL_PHYSDISK: 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 43958c2ecf20Sopenharmony_ci 43968c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_phys_disk_num( 43978c2ecf20Sopenharmony_ci ioc, hot_plug_info->phys_disk_num, 43988c2ecf20Sopenharmony_ci hot_plug_info->channel, 43998c2ecf20Sopenharmony_ci hot_plug_info->id); 44008c2ecf20Sopenharmony_ci mptsas_del_end_device(ioc, phy_info); 44018c2ecf20Sopenharmony_ci break; 44028c2ecf20Sopenharmony_ci 44038c2ecf20Sopenharmony_ci case MPTSAS_ADD_PHYSDISK_REPROBE: 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ci if (mptsas_sas_device_pg0(ioc, &sas_device, 44068c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 44078c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 44088c2ecf20Sopenharmony_ci (hot_plug_info->channel << 8) + hot_plug_info->id)) { 44098c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44108c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 44118c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 44128c2ecf20Sopenharmony_ci break; 44138c2ecf20Sopenharmony_ci } 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci /* If there is no FW B_T mapping for this device then break 44168c2ecf20Sopenharmony_ci * */ 44178c2ecf20Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 44188c2ecf20Sopenharmony_ci || !(sas_device.flags & 44198c2ecf20Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 44208c2ecf20Sopenharmony_ci break; 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address( 44238c2ecf20Sopenharmony_ci ioc, sas_device.sas_address); 44248c2ecf20Sopenharmony_ci 44258c2ecf20Sopenharmony_ci if (!phy_info) { 44268c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44278c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 44288c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 44298c2ecf20Sopenharmony_ci break; 44308c2ecf20Sopenharmony_ci } 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci starget = mptsas_get_starget(phy_info); 44338c2ecf20Sopenharmony_ci if (!starget) { 44348c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44358c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 44368c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 44378c2ecf20Sopenharmony_ci break; 44388c2ecf20Sopenharmony_ci } 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ci vtarget = starget->hostdata; 44418c2ecf20Sopenharmony_ci if (!vtarget) { 44428c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44438c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 44448c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 44458c2ecf20Sopenharmony_ci break; 44468c2ecf20Sopenharmony_ci } 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 44498c2ecf20Sopenharmony_ci 44508c2ecf20Sopenharmony_ci starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " 44518c2ecf20Sopenharmony_ci "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", 44528c2ecf20Sopenharmony_ci ioc->name, hot_plug_info->channel, hot_plug_info->id, 44538c2ecf20Sopenharmony_ci hot_plug_info->phys_disk_num, (unsigned long long) 44548c2ecf20Sopenharmony_ci sas_device.sas_address); 44558c2ecf20Sopenharmony_ci 44568c2ecf20Sopenharmony_ci vtarget->id = hot_plug_info->phys_disk_num; 44578c2ecf20Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; 44588c2ecf20Sopenharmony_ci phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; 44598c2ecf20Sopenharmony_ci mptsas_reprobe_target(starget, 1); 44608c2ecf20Sopenharmony_ci break; 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci case MPTSAS_DEL_PHYSDISK_REPROBE: 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci if (mptsas_sas_device_pg0(ioc, &sas_device, 44658c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << 44668c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_SHIFT), 44678c2ecf20Sopenharmony_ci (hot_plug_info->channel << 8) + hot_plug_info->id)) { 44688c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44698c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", 44708c2ecf20Sopenharmony_ci ioc->name, __func__, 44718c2ecf20Sopenharmony_ci hot_plug_info->id, __LINE__)); 44728c2ecf20Sopenharmony_ci break; 44738c2ecf20Sopenharmony_ci } 44748c2ecf20Sopenharmony_ci 44758c2ecf20Sopenharmony_ci /* If there is no FW B_T mapping for this device then break 44768c2ecf20Sopenharmony_ci * */ 44778c2ecf20Sopenharmony_ci if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) 44788c2ecf20Sopenharmony_ci || !(sas_device.flags & 44798c2ecf20Sopenharmony_ci MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) 44808c2ecf20Sopenharmony_ci break; 44818c2ecf20Sopenharmony_ci 44828c2ecf20Sopenharmony_ci phy_info = mptsas_find_phyinfo_by_sas_address(ioc, 44838c2ecf20Sopenharmony_ci sas_device.sas_address); 44848c2ecf20Sopenharmony_ci if (!phy_info) { 44858c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44868c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 44878c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 44888c2ecf20Sopenharmony_ci break; 44898c2ecf20Sopenharmony_ci } 44908c2ecf20Sopenharmony_ci 44918c2ecf20Sopenharmony_ci starget = mptsas_get_starget(phy_info); 44928c2ecf20Sopenharmony_ci if (!starget) { 44938c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 44948c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 44958c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 44968c2ecf20Sopenharmony_ci break; 44978c2ecf20Sopenharmony_ci } 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci vtarget = starget->hostdata; 45008c2ecf20Sopenharmony_ci if (!vtarget) { 45018c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 45028c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 45038c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 45048c2ecf20Sopenharmony_ci break; 45058c2ecf20Sopenharmony_ci } 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { 45088c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_ERR_FMT 45098c2ecf20Sopenharmony_ci "%s: fw_id=%d exit at line=%d\n", ioc->name, 45108c2ecf20Sopenharmony_ci __func__, hot_plug_info->id, __LINE__)); 45118c2ecf20Sopenharmony_ci break; 45128c2ecf20Sopenharmony_ci } 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 45158c2ecf20Sopenharmony_ci 45168c2ecf20Sopenharmony_ci starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" 45178c2ecf20Sopenharmony_ci " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", 45188c2ecf20Sopenharmony_ci ioc->name, hot_plug_info->channel, hot_plug_info->id, 45198c2ecf20Sopenharmony_ci hot_plug_info->phys_disk_num, (unsigned long long) 45208c2ecf20Sopenharmony_ci sas_device.sas_address); 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; 45238c2ecf20Sopenharmony_ci vtarget->id = hot_plug_info->id; 45248c2ecf20Sopenharmony_ci phy_info->attached.phys_disk_num = ~0; 45258c2ecf20Sopenharmony_ci mptsas_reprobe_target(starget, 0); 45268c2ecf20Sopenharmony_ci mptsas_add_device_component_by_fw(ioc, 45278c2ecf20Sopenharmony_ci hot_plug_info->channel, hot_plug_info->id); 45288c2ecf20Sopenharmony_ci break; 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci case MPTSAS_ADD_RAID: 45318c2ecf20Sopenharmony_ci 45328c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 45338c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " 45348c2ecf20Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, 45358c2ecf20Sopenharmony_ci hot_plug_info->id); 45368c2ecf20Sopenharmony_ci scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, 45378c2ecf20Sopenharmony_ci hot_plug_info->id, 0); 45388c2ecf20Sopenharmony_ci break; 45398c2ecf20Sopenharmony_ci 45408c2ecf20Sopenharmony_ci case MPTSAS_DEL_RAID: 45418c2ecf20Sopenharmony_ci 45428c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 45438c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " 45448c2ecf20Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, 45458c2ecf20Sopenharmony_ci hot_plug_info->id); 45468c2ecf20Sopenharmony_ci scsi_remove_device(hot_plug_info->sdev); 45478c2ecf20Sopenharmony_ci scsi_device_put(hot_plug_info->sdev); 45488c2ecf20Sopenharmony_ci break; 45498c2ecf20Sopenharmony_ci 45508c2ecf20Sopenharmony_ci case MPTSAS_ADD_INACTIVE_VOLUME: 45518c2ecf20Sopenharmony_ci 45528c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 45538c2ecf20Sopenharmony_ci mptsas_adding_inactive_raid_components(ioc, 45548c2ecf20Sopenharmony_ci hot_plug_info->channel, hot_plug_info->id); 45558c2ecf20Sopenharmony_ci break; 45568c2ecf20Sopenharmony_ci 45578c2ecf20Sopenharmony_ci default: 45588c2ecf20Sopenharmony_ci break; 45598c2ecf20Sopenharmony_ci } 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 45628c2ecf20Sopenharmony_ci} 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_cistatic void 45658c2ecf20Sopenharmony_cimptsas_send_sas_event(struct fw_event_work *fw_event) 45668c2ecf20Sopenharmony_ci{ 45678c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 45688c2ecf20Sopenharmony_ci struct mptsas_hotplug_event hot_plug_info; 45698c2ecf20Sopenharmony_ci EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; 45708c2ecf20Sopenharmony_ci u32 device_info; 45718c2ecf20Sopenharmony_ci u64 sas_address; 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci ioc = fw_event->ioc; 45748c2ecf20Sopenharmony_ci sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) 45758c2ecf20Sopenharmony_ci fw_event->event_data; 45768c2ecf20Sopenharmony_ci device_info = le32_to_cpu(sas_event_data->DeviceInfo); 45778c2ecf20Sopenharmony_ci 45788c2ecf20Sopenharmony_ci if ((device_info & 45798c2ecf20Sopenharmony_ci (MPI_SAS_DEVICE_INFO_SSP_TARGET | 45808c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_STP_TARGET | 45818c2ecf20Sopenharmony_ci MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { 45828c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 45838c2ecf20Sopenharmony_ci return; 45848c2ecf20Sopenharmony_ci } 45858c2ecf20Sopenharmony_ci 45868c2ecf20Sopenharmony_ci if (sas_event_data->ReasonCode == 45878c2ecf20Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { 45888c2ecf20Sopenharmony_ci mptbase_sas_persist_operation(ioc, 45898c2ecf20Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 45908c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 45918c2ecf20Sopenharmony_ci return; 45928c2ecf20Sopenharmony_ci } 45938c2ecf20Sopenharmony_ci 45948c2ecf20Sopenharmony_ci switch (sas_event_data->ReasonCode) { 45958c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: 45968c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: 45978c2ecf20Sopenharmony_ci memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); 45988c2ecf20Sopenharmony_ci hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); 45998c2ecf20Sopenharmony_ci hot_plug_info.channel = sas_event_data->Bus; 46008c2ecf20Sopenharmony_ci hot_plug_info.id = sas_event_data->TargetID; 46018c2ecf20Sopenharmony_ci hot_plug_info.phy_id = sas_event_data->PhyNum; 46028c2ecf20Sopenharmony_ci memcpy(&sas_address, &sas_event_data->SASAddress, 46038c2ecf20Sopenharmony_ci sizeof(u64)); 46048c2ecf20Sopenharmony_ci hot_plug_info.sas_address = le64_to_cpu(sas_address); 46058c2ecf20Sopenharmony_ci hot_plug_info.device_info = device_info; 46068c2ecf20Sopenharmony_ci if (sas_event_data->ReasonCode & 46078c2ecf20Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_ADDED) 46088c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_DEVICE; 46098c2ecf20Sopenharmony_ci else 46108c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_DEVICE; 46118c2ecf20Sopenharmony_ci mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); 46128c2ecf20Sopenharmony_ci break; 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: 46158c2ecf20Sopenharmony_ci mptbase_sas_persist_operation(ioc, 46168c2ecf20Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 46178c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 46188c2ecf20Sopenharmony_ci break; 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: 46218c2ecf20Sopenharmony_ci /* TODO */ 46228c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: 46238c2ecf20Sopenharmony_ci /* TODO */ 46248c2ecf20Sopenharmony_ci default: 46258c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 46268c2ecf20Sopenharmony_ci break; 46278c2ecf20Sopenharmony_ci } 46288c2ecf20Sopenharmony_ci} 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_cistatic void 46318c2ecf20Sopenharmony_cimptsas_send_raid_event(struct fw_event_work *fw_event) 46328c2ecf20Sopenharmony_ci{ 46338c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 46348c2ecf20Sopenharmony_ci EVENT_DATA_RAID *raid_event_data; 46358c2ecf20Sopenharmony_ci struct mptsas_hotplug_event hot_plug_info; 46368c2ecf20Sopenharmony_ci int status; 46378c2ecf20Sopenharmony_ci int state; 46388c2ecf20Sopenharmony_ci struct scsi_device *sdev = NULL; 46398c2ecf20Sopenharmony_ci VirtDevice *vdevice = NULL; 46408c2ecf20Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci ioc = fw_event->ioc; 46438c2ecf20Sopenharmony_ci raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; 46448c2ecf20Sopenharmony_ci status = le32_to_cpu(raid_event_data->SettingsStatus); 46458c2ecf20Sopenharmony_ci state = (status >> 8) & 0xff; 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); 46488c2ecf20Sopenharmony_ci hot_plug_info.id = raid_event_data->VolumeID; 46498c2ecf20Sopenharmony_ci hot_plug_info.channel = raid_event_data->VolumeBus; 46508c2ecf20Sopenharmony_ci hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; 46518c2ecf20Sopenharmony_ci 46528c2ecf20Sopenharmony_ci if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || 46538c2ecf20Sopenharmony_ci raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || 46548c2ecf20Sopenharmony_ci raid_event_data->ReasonCode == 46558c2ecf20Sopenharmony_ci MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { 46568c2ecf20Sopenharmony_ci sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, 46578c2ecf20Sopenharmony_ci hot_plug_info.id, 0); 46588c2ecf20Sopenharmony_ci hot_plug_info.sdev = sdev; 46598c2ecf20Sopenharmony_ci if (sdev) 46608c2ecf20Sopenharmony_ci vdevice = sdev->hostdata; 46618c2ecf20Sopenharmony_ci } 46628c2ecf20Sopenharmony_ci 46638c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " 46648c2ecf20Sopenharmony_ci "ReasonCode=%02x\n", ioc->name, __func__, 46658c2ecf20Sopenharmony_ci raid_event_data->ReasonCode)); 46668c2ecf20Sopenharmony_ci 46678c2ecf20Sopenharmony_ci switch (raid_event_data->ReasonCode) { 46688c2ecf20Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: 46698c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; 46708c2ecf20Sopenharmony_ci break; 46718c2ecf20Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: 46728c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; 46738c2ecf20Sopenharmony_ci break; 46748c2ecf20Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: 46758c2ecf20Sopenharmony_ci switch (state) { 46768c2ecf20Sopenharmony_ci case MPI_PD_STATE_ONLINE: 46778c2ecf20Sopenharmony_ci case MPI_PD_STATE_NOT_COMPATIBLE: 46788c2ecf20Sopenharmony_ci mpt_raid_phys_disk_pg0(ioc, 46798c2ecf20Sopenharmony_ci raid_event_data->PhysDiskNum, &phys_disk); 46808c2ecf20Sopenharmony_ci hot_plug_info.id = phys_disk.PhysDiskID; 46818c2ecf20Sopenharmony_ci hot_plug_info.channel = phys_disk.PhysDiskBus; 46828c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; 46838c2ecf20Sopenharmony_ci break; 46848c2ecf20Sopenharmony_ci case MPI_PD_STATE_FAILED: 46858c2ecf20Sopenharmony_ci case MPI_PD_STATE_MISSING: 46868c2ecf20Sopenharmony_ci case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: 46878c2ecf20Sopenharmony_ci case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: 46888c2ecf20Sopenharmony_ci case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: 46898c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; 46908c2ecf20Sopenharmony_ci break; 46918c2ecf20Sopenharmony_ci default: 46928c2ecf20Sopenharmony_ci break; 46938c2ecf20Sopenharmony_ci } 46948c2ecf20Sopenharmony_ci break; 46958c2ecf20Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_DELETED: 46968c2ecf20Sopenharmony_ci if (!sdev) 46978c2ecf20Sopenharmony_ci break; 46988c2ecf20Sopenharmony_ci vdevice->vtarget->deleted = 1; /* block IO */ 46998c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_RAID; 47008c2ecf20Sopenharmony_ci break; 47018c2ecf20Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_CREATED: 47028c2ecf20Sopenharmony_ci if (sdev) { 47038c2ecf20Sopenharmony_ci scsi_device_put(sdev); 47048c2ecf20Sopenharmony_ci break; 47058c2ecf20Sopenharmony_ci } 47068c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_RAID; 47078c2ecf20Sopenharmony_ci break; 47088c2ecf20Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: 47098c2ecf20Sopenharmony_ci if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { 47108c2ecf20Sopenharmony_ci if (!sdev) 47118c2ecf20Sopenharmony_ci break; 47128c2ecf20Sopenharmony_ci vdevice->vtarget->deleted = 1; /* block IO */ 47138c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_RAID; 47148c2ecf20Sopenharmony_ci break; 47158c2ecf20Sopenharmony_ci } 47168c2ecf20Sopenharmony_ci switch (state) { 47178c2ecf20Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_FAILED: 47188c2ecf20Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_MISSING: 47198c2ecf20Sopenharmony_ci if (!sdev) 47208c2ecf20Sopenharmony_ci break; 47218c2ecf20Sopenharmony_ci vdevice->vtarget->deleted = 1; /* block IO */ 47228c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_RAID; 47238c2ecf20Sopenharmony_ci break; 47248c2ecf20Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: 47258c2ecf20Sopenharmony_ci case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: 47268c2ecf20Sopenharmony_ci if (sdev) { 47278c2ecf20Sopenharmony_ci scsi_device_put(sdev); 47288c2ecf20Sopenharmony_ci break; 47298c2ecf20Sopenharmony_ci } 47308c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_RAID; 47318c2ecf20Sopenharmony_ci break; 47328c2ecf20Sopenharmony_ci default: 47338c2ecf20Sopenharmony_ci break; 47348c2ecf20Sopenharmony_ci } 47358c2ecf20Sopenharmony_ci break; 47368c2ecf20Sopenharmony_ci default: 47378c2ecf20Sopenharmony_ci break; 47388c2ecf20Sopenharmony_ci } 47398c2ecf20Sopenharmony_ci 47408c2ecf20Sopenharmony_ci if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) 47418c2ecf20Sopenharmony_ci mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); 47428c2ecf20Sopenharmony_ci else 47438c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 47448c2ecf20Sopenharmony_ci} 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci/** 47478c2ecf20Sopenharmony_ci * mptsas_issue_tm - send mptsas internal tm request 47488c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 47498c2ecf20Sopenharmony_ci * @type: Task Management type 47508c2ecf20Sopenharmony_ci * @channel: channel number for task management 47518c2ecf20Sopenharmony_ci * @id: Logical Target ID for reset (if appropriate) 47528c2ecf20Sopenharmony_ci * @lun: Logical unit for reset (if appropriate) 47538c2ecf20Sopenharmony_ci * @task_context: Context for the task to be aborted 47548c2ecf20Sopenharmony_ci * @timeout: timeout for task management control 47558c2ecf20Sopenharmony_ci * 47568c2ecf20Sopenharmony_ci * return 0 on success and -1 on failure: 47578c2ecf20Sopenharmony_ci * 47588c2ecf20Sopenharmony_ci */ 47598c2ecf20Sopenharmony_cistatic int 47608c2ecf20Sopenharmony_cimptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, 47618c2ecf20Sopenharmony_ci int task_context, ulong timeout, u8 *issue_reset) 47628c2ecf20Sopenharmony_ci{ 47638c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 47648c2ecf20Sopenharmony_ci SCSITaskMgmt_t *pScsiTm; 47658c2ecf20Sopenharmony_ci int retval; 47668c2ecf20Sopenharmony_ci unsigned long timeleft; 47678c2ecf20Sopenharmony_ci 47688c2ecf20Sopenharmony_ci *issue_reset = 0; 47698c2ecf20Sopenharmony_ci mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); 47708c2ecf20Sopenharmony_ci if (mf == NULL) { 47718c2ecf20Sopenharmony_ci retval = -1; /* return failure */ 47728c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " 47738c2ecf20Sopenharmony_ci "msg frames!!\n", ioc->name)); 47748c2ecf20Sopenharmony_ci goto out; 47758c2ecf20Sopenharmony_ci } 47768c2ecf20Sopenharmony_ci 47778c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " 47788c2ecf20Sopenharmony_ci "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " 47798c2ecf20Sopenharmony_ci "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, 47808c2ecf20Sopenharmony_ci type, timeout, channel, id, (unsigned long long)lun, 47818c2ecf20Sopenharmony_ci task_context)); 47828c2ecf20Sopenharmony_ci 47838c2ecf20Sopenharmony_ci pScsiTm = (SCSITaskMgmt_t *) mf; 47848c2ecf20Sopenharmony_ci memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); 47858c2ecf20Sopenharmony_ci pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 47868c2ecf20Sopenharmony_ci pScsiTm->TaskType = type; 47878c2ecf20Sopenharmony_ci pScsiTm->MsgFlags = 0; 47888c2ecf20Sopenharmony_ci pScsiTm->TargetID = id; 47898c2ecf20Sopenharmony_ci pScsiTm->Bus = channel; 47908c2ecf20Sopenharmony_ci pScsiTm->ChainOffset = 0; 47918c2ecf20Sopenharmony_ci pScsiTm->Reserved = 0; 47928c2ecf20Sopenharmony_ci pScsiTm->Reserved1 = 0; 47938c2ecf20Sopenharmony_ci pScsiTm->TaskMsgContext = task_context; 47948c2ecf20Sopenharmony_ci int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) 47978c2ecf20Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->internal_cmds.status) 47988c2ecf20Sopenharmony_ci retval = 0; 47998c2ecf20Sopenharmony_ci mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci /* Now wait for the command to complete */ 48028c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, 48038c2ecf20Sopenharmony_ci timeout*HZ); 48048c2ecf20Sopenharmony_ci if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 48058c2ecf20Sopenharmony_ci retval = -1; /* return failure */ 48068c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_ERR_FMT 48078c2ecf20Sopenharmony_ci "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); 48088c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 48098c2ecf20Sopenharmony_ci if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) 48108c2ecf20Sopenharmony_ci goto out; 48118c2ecf20Sopenharmony_ci *issue_reset = 1; 48128c2ecf20Sopenharmony_ci goto out; 48138c2ecf20Sopenharmony_ci } 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { 48168c2ecf20Sopenharmony_ci retval = -1; /* return failure */ 48178c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 48188c2ecf20Sopenharmony_ci "TaskMgmt request: failed with no reply\n", ioc->name)); 48198c2ecf20Sopenharmony_ci goto out; 48208c2ecf20Sopenharmony_ci } 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci out: 48238c2ecf20Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) 48248c2ecf20Sopenharmony_ci return retval; 48258c2ecf20Sopenharmony_ci} 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_ci/** 48288c2ecf20Sopenharmony_ci * mptsas_broadcast_primitive_work - Handle broadcast primitives 48298c2ecf20Sopenharmony_ci * @work: work queue payload containing info describing the event 48308c2ecf20Sopenharmony_ci * 48318c2ecf20Sopenharmony_ci * this will be handled in workqueue context. 48328c2ecf20Sopenharmony_ci */ 48338c2ecf20Sopenharmony_cistatic void 48348c2ecf20Sopenharmony_cimptsas_broadcast_primitive_work(struct fw_event_work *fw_event) 48358c2ecf20Sopenharmony_ci{ 48368c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = fw_event->ioc; 48378c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 48388c2ecf20Sopenharmony_ci VirtDevice *vdevice; 48398c2ecf20Sopenharmony_ci int ii; 48408c2ecf20Sopenharmony_ci struct scsi_cmnd *sc; 48418c2ecf20Sopenharmony_ci SCSITaskMgmtReply_t *pScsiTmReply; 48428c2ecf20Sopenharmony_ci u8 issue_reset; 48438c2ecf20Sopenharmony_ci int task_context; 48448c2ecf20Sopenharmony_ci u8 channel, id; 48458c2ecf20Sopenharmony_ci int lun; 48468c2ecf20Sopenharmony_ci u32 termination_count; 48478c2ecf20Sopenharmony_ci u32 query_count; 48488c2ecf20Sopenharmony_ci 48498c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 48508c2ecf20Sopenharmony_ci "%s - enter\n", ioc->name, __func__)); 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci mutex_lock(&ioc->taskmgmt_cmds.mutex); 48538c2ecf20Sopenharmony_ci if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { 48548c2ecf20Sopenharmony_ci mutex_unlock(&ioc->taskmgmt_cmds.mutex); 48558c2ecf20Sopenharmony_ci mptsas_requeue_fw_event(ioc, fw_event, 1000); 48568c2ecf20Sopenharmony_ci return; 48578c2ecf20Sopenharmony_ci } 48588c2ecf20Sopenharmony_ci 48598c2ecf20Sopenharmony_ci issue_reset = 0; 48608c2ecf20Sopenharmony_ci termination_count = 0; 48618c2ecf20Sopenharmony_ci query_count = 0; 48628c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 48638c2ecf20Sopenharmony_ci pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; 48648c2ecf20Sopenharmony_ci 48658c2ecf20Sopenharmony_ci for (ii = 0; ii < ioc->req_depth; ii++) { 48668c2ecf20Sopenharmony_ci if (ioc->fw_events_off) 48678c2ecf20Sopenharmony_ci goto out; 48688c2ecf20Sopenharmony_ci sc = mptscsih_get_scsi_lookup(ioc, ii); 48698c2ecf20Sopenharmony_ci if (!sc) 48708c2ecf20Sopenharmony_ci continue; 48718c2ecf20Sopenharmony_ci mf = MPT_INDEX_2_MFPTR(ioc, ii); 48728c2ecf20Sopenharmony_ci if (!mf) 48738c2ecf20Sopenharmony_ci continue; 48748c2ecf20Sopenharmony_ci task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; 48758c2ecf20Sopenharmony_ci vdevice = sc->device->hostdata; 48768c2ecf20Sopenharmony_ci if (!vdevice || !vdevice->vtarget) 48778c2ecf20Sopenharmony_ci continue; 48788c2ecf20Sopenharmony_ci if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) 48798c2ecf20Sopenharmony_ci continue; /* skip hidden raid components */ 48808c2ecf20Sopenharmony_ci if (vdevice->vtarget->raidVolume) 48818c2ecf20Sopenharmony_ci continue; /* skip hidden raid components */ 48828c2ecf20Sopenharmony_ci channel = vdevice->vtarget->channel; 48838c2ecf20Sopenharmony_ci id = vdevice->vtarget->id; 48848c2ecf20Sopenharmony_ci lun = vdevice->lun; 48858c2ecf20Sopenharmony_ci if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, 48868c2ecf20Sopenharmony_ci channel, id, (u64)lun, task_context, 30, &issue_reset)) 48878c2ecf20Sopenharmony_ci goto out; 48888c2ecf20Sopenharmony_ci query_count++; 48898c2ecf20Sopenharmony_ci termination_count += 48908c2ecf20Sopenharmony_ci le32_to_cpu(pScsiTmReply->TerminationCount); 48918c2ecf20Sopenharmony_ci if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && 48928c2ecf20Sopenharmony_ci (pScsiTmReply->ResponseCode == 48938c2ecf20Sopenharmony_ci MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || 48948c2ecf20Sopenharmony_ci pScsiTmReply->ResponseCode == 48958c2ecf20Sopenharmony_ci MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) 48968c2ecf20Sopenharmony_ci continue; 48978c2ecf20Sopenharmony_ci if (mptsas_issue_tm(ioc, 48988c2ecf20Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 48998c2ecf20Sopenharmony_ci channel, id, (u64)lun, 0, 30, &issue_reset)) 49008c2ecf20Sopenharmony_ci goto out; 49018c2ecf20Sopenharmony_ci termination_count += 49028c2ecf20Sopenharmony_ci le32_to_cpu(pScsiTmReply->TerminationCount); 49038c2ecf20Sopenharmony_ci } 49048c2ecf20Sopenharmony_ci 49058c2ecf20Sopenharmony_ci out: 49068c2ecf20Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 49078c2ecf20Sopenharmony_ci "%s - exit, query_count = %d termination_count = %d\n", 49088c2ecf20Sopenharmony_ci ioc->name, __func__, query_count, termination_count)); 49098c2ecf20Sopenharmony_ci 49108c2ecf20Sopenharmony_ci ioc->broadcast_aen_busy = 0; 49118c2ecf20Sopenharmony_ci mpt_clear_taskmgmt_in_progress_flag(ioc); 49128c2ecf20Sopenharmony_ci mutex_unlock(&ioc->taskmgmt_cmds.mutex); 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci if (issue_reset) { 49158c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 49168c2ecf20Sopenharmony_ci "Issuing Reset from %s!! doorbell=0x%08x\n", 49178c2ecf20Sopenharmony_ci ioc->name, __func__, mpt_GetIocState(ioc, 0)); 49188c2ecf20Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 49198c2ecf20Sopenharmony_ci } 49208c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 49218c2ecf20Sopenharmony_ci} 49228c2ecf20Sopenharmony_ci 49238c2ecf20Sopenharmony_ci/* 49248c2ecf20Sopenharmony_ci * mptsas_send_ir2_event - handle exposing hidden disk when 49258c2ecf20Sopenharmony_ci * an inactive raid volume is added 49268c2ecf20Sopenharmony_ci * 49278c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 49288c2ecf20Sopenharmony_ci * @ir2_data 49298c2ecf20Sopenharmony_ci * 49308c2ecf20Sopenharmony_ci */ 49318c2ecf20Sopenharmony_cistatic void 49328c2ecf20Sopenharmony_cimptsas_send_ir2_event(struct fw_event_work *fw_event) 49338c2ecf20Sopenharmony_ci{ 49348c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 49358c2ecf20Sopenharmony_ci struct mptsas_hotplug_event hot_plug_info; 49368c2ecf20Sopenharmony_ci MPI_EVENT_DATA_IR2 *ir2_data; 49378c2ecf20Sopenharmony_ci u8 reasonCode; 49388c2ecf20Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 49398c2ecf20Sopenharmony_ci 49408c2ecf20Sopenharmony_ci ioc = fw_event->ioc; 49418c2ecf20Sopenharmony_ci ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; 49428c2ecf20Sopenharmony_ci reasonCode = ir2_data->ReasonCode; 49438c2ecf20Sopenharmony_ci 49448c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " 49458c2ecf20Sopenharmony_ci "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); 49488c2ecf20Sopenharmony_ci hot_plug_info.id = ir2_data->TargetID; 49498c2ecf20Sopenharmony_ci hot_plug_info.channel = ir2_data->Bus; 49508c2ecf20Sopenharmony_ci switch (reasonCode) { 49518c2ecf20Sopenharmony_ci case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: 49528c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; 49538c2ecf20Sopenharmony_ci break; 49548c2ecf20Sopenharmony_ci case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: 49558c2ecf20Sopenharmony_ci hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; 49568c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; 49578c2ecf20Sopenharmony_ci break; 49588c2ecf20Sopenharmony_ci case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: 49598c2ecf20Sopenharmony_ci hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; 49608c2ecf20Sopenharmony_ci mpt_raid_phys_disk_pg0(ioc, 49618c2ecf20Sopenharmony_ci ir2_data->PhysDiskNum, &phys_disk); 49628c2ecf20Sopenharmony_ci hot_plug_info.id = phys_disk.PhysDiskID; 49638c2ecf20Sopenharmony_ci hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; 49648c2ecf20Sopenharmony_ci break; 49658c2ecf20Sopenharmony_ci default: 49668c2ecf20Sopenharmony_ci mptsas_free_fw_event(ioc, fw_event); 49678c2ecf20Sopenharmony_ci return; 49688c2ecf20Sopenharmony_ci } 49698c2ecf20Sopenharmony_ci mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); 49708c2ecf20Sopenharmony_ci} 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_cistatic int 49738c2ecf20Sopenharmony_cimptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) 49748c2ecf20Sopenharmony_ci{ 49758c2ecf20Sopenharmony_ci u32 event = le32_to_cpu(reply->Event); 49768c2ecf20Sopenharmony_ci int event_data_sz; 49778c2ecf20Sopenharmony_ci struct fw_event_work *fw_event; 49788c2ecf20Sopenharmony_ci unsigned long delay; 49798c2ecf20Sopenharmony_ci 49808c2ecf20Sopenharmony_ci if (ioc->bus_type != SAS) 49818c2ecf20Sopenharmony_ci return 0; 49828c2ecf20Sopenharmony_ci 49838c2ecf20Sopenharmony_ci /* events turned off due to host reset or driver unloading */ 49848c2ecf20Sopenharmony_ci if (ioc->fw_events_off) 49858c2ecf20Sopenharmony_ci return 0; 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci delay = msecs_to_jiffies(1); 49888c2ecf20Sopenharmony_ci switch (event) { 49898c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: 49908c2ecf20Sopenharmony_ci { 49918c2ecf20Sopenharmony_ci EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = 49928c2ecf20Sopenharmony_ci (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; 49938c2ecf20Sopenharmony_ci if (broadcast_event_data->Primitive != 49948c2ecf20Sopenharmony_ci MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) 49958c2ecf20Sopenharmony_ci return 0; 49968c2ecf20Sopenharmony_ci if (ioc->broadcast_aen_busy) 49978c2ecf20Sopenharmony_ci return 0; 49988c2ecf20Sopenharmony_ci ioc->broadcast_aen_busy = 1; 49998c2ecf20Sopenharmony_ci break; 50008c2ecf20Sopenharmony_ci } 50018c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 50028c2ecf20Sopenharmony_ci { 50038c2ecf20Sopenharmony_ci EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = 50048c2ecf20Sopenharmony_ci (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; 50058c2ecf20Sopenharmony_ci u16 ioc_stat; 50068c2ecf20Sopenharmony_ci ioc_stat = le16_to_cpu(reply->IOCStatus); 50078c2ecf20Sopenharmony_ci 50088c2ecf20Sopenharmony_ci if (sas_event_data->ReasonCode == 50098c2ecf20Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { 50108c2ecf20Sopenharmony_ci mptsas_target_reset_queue(ioc, sas_event_data); 50118c2ecf20Sopenharmony_ci return 0; 50128c2ecf20Sopenharmony_ci } 50138c2ecf20Sopenharmony_ci if (sas_event_data->ReasonCode == 50148c2ecf20Sopenharmony_ci MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && 50158c2ecf20Sopenharmony_ci ioc->device_missing_delay && 50168c2ecf20Sopenharmony_ci (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { 50178c2ecf20Sopenharmony_ci VirtTarget *vtarget = NULL; 50188c2ecf20Sopenharmony_ci u8 id, channel; 50198c2ecf20Sopenharmony_ci 50208c2ecf20Sopenharmony_ci id = sas_event_data->TargetID; 50218c2ecf20Sopenharmony_ci channel = sas_event_data->Bus; 50228c2ecf20Sopenharmony_ci 50238c2ecf20Sopenharmony_ci vtarget = mptsas_find_vtarget(ioc, channel, id); 50248c2ecf20Sopenharmony_ci if (vtarget) { 50258c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 50268c2ecf20Sopenharmony_ci "LogInfo (0x%x) available for " 50278c2ecf20Sopenharmony_ci "INTERNAL_DEVICE_RESET" 50288c2ecf20Sopenharmony_ci "fw_id %d fw_channel %d\n", ioc->name, 50298c2ecf20Sopenharmony_ci le32_to_cpu(reply->IOCLogInfo), 50308c2ecf20Sopenharmony_ci id, channel)); 50318c2ecf20Sopenharmony_ci if (vtarget->raidVolume) { 50328c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 50338c2ecf20Sopenharmony_ci "Skipping Raid Volume for inDMD\n", 50348c2ecf20Sopenharmony_ci ioc->name)); 50358c2ecf20Sopenharmony_ci } else { 50368c2ecf20Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 50378c2ecf20Sopenharmony_ci "Setting device flag inDMD\n", 50388c2ecf20Sopenharmony_ci ioc->name)); 50398c2ecf20Sopenharmony_ci vtarget->inDMD = 1; 50408c2ecf20Sopenharmony_ci } 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_ci } 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci } 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci break; 50478c2ecf20Sopenharmony_ci } 50488c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: 50498c2ecf20Sopenharmony_ci { 50508c2ecf20Sopenharmony_ci MpiEventDataSasExpanderStatusChange_t *expander_data = 50518c2ecf20Sopenharmony_ci (MpiEventDataSasExpanderStatusChange_t *)reply->Data; 50528c2ecf20Sopenharmony_ci 50538c2ecf20Sopenharmony_ci if (ioc->old_sas_discovery_protocal) 50548c2ecf20Sopenharmony_ci return 0; 50558c2ecf20Sopenharmony_ci 50568c2ecf20Sopenharmony_ci if (expander_data->ReasonCode == 50578c2ecf20Sopenharmony_ci MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && 50588c2ecf20Sopenharmony_ci ioc->device_missing_delay) 50598c2ecf20Sopenharmony_ci delay = HZ * ioc->device_missing_delay; 50608c2ecf20Sopenharmony_ci break; 50618c2ecf20Sopenharmony_ci } 50628c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_DISCOVERY: 50638c2ecf20Sopenharmony_ci { 50648c2ecf20Sopenharmony_ci u32 discovery_status; 50658c2ecf20Sopenharmony_ci EventDataSasDiscovery_t *discovery_data = 50668c2ecf20Sopenharmony_ci (EventDataSasDiscovery_t *)reply->Data; 50678c2ecf20Sopenharmony_ci 50688c2ecf20Sopenharmony_ci discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); 50698c2ecf20Sopenharmony_ci ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; 50708c2ecf20Sopenharmony_ci if (ioc->old_sas_discovery_protocal && !discovery_status) 50718c2ecf20Sopenharmony_ci mptsas_queue_rescan(ioc); 50728c2ecf20Sopenharmony_ci return 0; 50738c2ecf20Sopenharmony_ci } 50748c2ecf20Sopenharmony_ci case MPI_EVENT_INTEGRATED_RAID: 50758c2ecf20Sopenharmony_ci case MPI_EVENT_PERSISTENT_TABLE_FULL: 50768c2ecf20Sopenharmony_ci case MPI_EVENT_IR2: 50778c2ecf20Sopenharmony_ci case MPI_EVENT_SAS_PHY_LINK_STATUS: 50788c2ecf20Sopenharmony_ci case MPI_EVENT_QUEUE_FULL: 50798c2ecf20Sopenharmony_ci break; 50808c2ecf20Sopenharmony_ci default: 50818c2ecf20Sopenharmony_ci return 0; 50828c2ecf20Sopenharmony_ci } 50838c2ecf20Sopenharmony_ci 50848c2ecf20Sopenharmony_ci event_data_sz = ((reply->MsgLength * 4) - 50858c2ecf20Sopenharmony_ci offsetof(EventNotificationReply_t, Data)); 50868c2ecf20Sopenharmony_ci fw_event = kzalloc(sizeof(*fw_event) + event_data_sz, GFP_ATOMIC); 50878c2ecf20Sopenharmony_ci if (!fw_event) { 50888c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, 50898c2ecf20Sopenharmony_ci __func__, __LINE__); 50908c2ecf20Sopenharmony_ci return 0; 50918c2ecf20Sopenharmony_ci } 50928c2ecf20Sopenharmony_ci memcpy(fw_event->event_data, reply->Data, event_data_sz); 50938c2ecf20Sopenharmony_ci fw_event->event = event; 50948c2ecf20Sopenharmony_ci fw_event->ioc = ioc; 50958c2ecf20Sopenharmony_ci mptsas_add_fw_event(ioc, fw_event, delay); 50968c2ecf20Sopenharmony_ci return 0; 50978c2ecf20Sopenharmony_ci} 50988c2ecf20Sopenharmony_ci 50998c2ecf20Sopenharmony_ci/* Delete a volume when no longer listed in ioc pg2 51008c2ecf20Sopenharmony_ci */ 51018c2ecf20Sopenharmony_cistatic void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) 51028c2ecf20Sopenharmony_ci{ 51038c2ecf20Sopenharmony_ci struct scsi_device *sdev; 51048c2ecf20Sopenharmony_ci int i; 51058c2ecf20Sopenharmony_ci 51068c2ecf20Sopenharmony_ci sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); 51078c2ecf20Sopenharmony_ci if (!sdev) 51088c2ecf20Sopenharmony_ci return; 51098c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg2) 51108c2ecf20Sopenharmony_ci goto out; 51118c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg2->NumActiveVolumes) 51128c2ecf20Sopenharmony_ci goto out; 51138c2ecf20Sopenharmony_ci for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) 51148c2ecf20Sopenharmony_ci if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) 51158c2ecf20Sopenharmony_ci goto release_sdev; 51168c2ecf20Sopenharmony_ci out: 51178c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " 51188c2ecf20Sopenharmony_ci "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); 51198c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 51208c2ecf20Sopenharmony_ci release_sdev: 51218c2ecf20Sopenharmony_ci scsi_device_put(sdev); 51228c2ecf20Sopenharmony_ci} 51238c2ecf20Sopenharmony_ci 51248c2ecf20Sopenharmony_cistatic int 51258c2ecf20Sopenharmony_cimptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) 51268c2ecf20Sopenharmony_ci{ 51278c2ecf20Sopenharmony_ci struct Scsi_Host *sh; 51288c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd; 51298c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 51308c2ecf20Sopenharmony_ci unsigned long flags; 51318c2ecf20Sopenharmony_ci int ii; 51328c2ecf20Sopenharmony_ci int numSGE = 0; 51338c2ecf20Sopenharmony_ci int scale; 51348c2ecf20Sopenharmony_ci int ioc_cap; 51358c2ecf20Sopenharmony_ci int error=0; 51368c2ecf20Sopenharmony_ci int r; 51378c2ecf20Sopenharmony_ci 51388c2ecf20Sopenharmony_ci r = mpt_attach(pdev,id); 51398c2ecf20Sopenharmony_ci if (r) 51408c2ecf20Sopenharmony_ci return r; 51418c2ecf20Sopenharmony_ci 51428c2ecf20Sopenharmony_ci ioc = pci_get_drvdata(pdev); 51438c2ecf20Sopenharmony_ci mptsas_fw_event_off(ioc); 51448c2ecf20Sopenharmony_ci ioc->DoneCtx = mptsasDoneCtx; 51458c2ecf20Sopenharmony_ci ioc->TaskCtx = mptsasTaskCtx; 51468c2ecf20Sopenharmony_ci ioc->InternalCtx = mptsasInternalCtx; 51478c2ecf20Sopenharmony_ci ioc->schedule_target_reset = &mptsas_schedule_target_reset; 51488c2ecf20Sopenharmony_ci ioc->schedule_dead_ioc_flush_running_cmds = 51498c2ecf20Sopenharmony_ci &mptscsih_flush_running_cmds; 51508c2ecf20Sopenharmony_ci /* Added sanity check on readiness of the MPT adapter. 51518c2ecf20Sopenharmony_ci */ 51528c2ecf20Sopenharmony_ci if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { 51538c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 51548c2ecf20Sopenharmony_ci "Skipping because it's not operational!\n", 51558c2ecf20Sopenharmony_ci ioc->name); 51568c2ecf20Sopenharmony_ci error = -ENODEV; 51578c2ecf20Sopenharmony_ci goto out_mptsas_probe; 51588c2ecf20Sopenharmony_ci } 51598c2ecf20Sopenharmony_ci 51608c2ecf20Sopenharmony_ci if (!ioc->active) { 51618c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", 51628c2ecf20Sopenharmony_ci ioc->name); 51638c2ecf20Sopenharmony_ci error = -ENODEV; 51648c2ecf20Sopenharmony_ci goto out_mptsas_probe; 51658c2ecf20Sopenharmony_ci } 51668c2ecf20Sopenharmony_ci 51678c2ecf20Sopenharmony_ci /* Sanity check - ensure at least 1 port is INITIATOR capable 51688c2ecf20Sopenharmony_ci */ 51698c2ecf20Sopenharmony_ci ioc_cap = 0; 51708c2ecf20Sopenharmony_ci for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) { 51718c2ecf20Sopenharmony_ci if (ioc->pfacts[ii].ProtocolFlags & 51728c2ecf20Sopenharmony_ci MPI_PORTFACTS_PROTOCOL_INITIATOR) 51738c2ecf20Sopenharmony_ci ioc_cap++; 51748c2ecf20Sopenharmony_ci } 51758c2ecf20Sopenharmony_ci 51768c2ecf20Sopenharmony_ci if (!ioc_cap) { 51778c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 51788c2ecf20Sopenharmony_ci "Skipping ioc=%p because SCSI Initiator mode " 51798c2ecf20Sopenharmony_ci "is NOT enabled!\n", ioc->name, ioc); 51808c2ecf20Sopenharmony_ci return 0; 51818c2ecf20Sopenharmony_ci } 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST)); 51848c2ecf20Sopenharmony_ci if (!sh) { 51858c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 51868c2ecf20Sopenharmony_ci "Unable to register controller with SCSI subsystem\n", 51878c2ecf20Sopenharmony_ci ioc->name); 51888c2ecf20Sopenharmony_ci error = -1; 51898c2ecf20Sopenharmony_ci goto out_mptsas_probe; 51908c2ecf20Sopenharmony_ci } 51918c2ecf20Sopenharmony_ci 51928c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci /* Attach the SCSI Host to the IOC structure 51958c2ecf20Sopenharmony_ci */ 51968c2ecf20Sopenharmony_ci ioc->sh = sh; 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci sh->io_port = 0; 51998c2ecf20Sopenharmony_ci sh->n_io_port = 0; 52008c2ecf20Sopenharmony_ci sh->irq = 0; 52018c2ecf20Sopenharmony_ci 52028c2ecf20Sopenharmony_ci /* set 16 byte cdb's */ 52038c2ecf20Sopenharmony_ci sh->max_cmd_len = 16; 52048c2ecf20Sopenharmony_ci sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); 52058c2ecf20Sopenharmony_ci sh->max_id = -1; 52068c2ecf20Sopenharmony_ci sh->max_lun = max_lun; 52078c2ecf20Sopenharmony_ci sh->transportt = mptsas_transport_template; 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci /* Required entry. 52108c2ecf20Sopenharmony_ci */ 52118c2ecf20Sopenharmony_ci sh->unique_id = ioc->id; 52128c2ecf20Sopenharmony_ci 52138c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ioc->sas_topology); 52148c2ecf20Sopenharmony_ci mutex_init(&ioc->sas_topology_mutex); 52158c2ecf20Sopenharmony_ci mutex_init(&ioc->sas_discovery_mutex); 52168c2ecf20Sopenharmony_ci mutex_init(&ioc->sas_mgmt.mutex); 52178c2ecf20Sopenharmony_ci init_completion(&ioc->sas_mgmt.done); 52188c2ecf20Sopenharmony_ci 52198c2ecf20Sopenharmony_ci /* Verify that we won't exceed the maximum 52208c2ecf20Sopenharmony_ci * number of chain buffers 52218c2ecf20Sopenharmony_ci * We can optimize: ZZ = req_sz/sizeof(SGE) 52228c2ecf20Sopenharmony_ci * For 32bit SGE's: 52238c2ecf20Sopenharmony_ci * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ 52248c2ecf20Sopenharmony_ci * + (req_sz - 64)/sizeof(SGE) 52258c2ecf20Sopenharmony_ci * A slightly different algorithm is required for 52268c2ecf20Sopenharmony_ci * 64bit SGEs. 52278c2ecf20Sopenharmony_ci */ 52288c2ecf20Sopenharmony_ci scale = ioc->req_sz/ioc->SGE_size; 52298c2ecf20Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) { 52308c2ecf20Sopenharmony_ci numSGE = (scale - 1) * 52318c2ecf20Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 52328c2ecf20Sopenharmony_ci (ioc->req_sz - 60) / ioc->SGE_size; 52338c2ecf20Sopenharmony_ci } else { 52348c2ecf20Sopenharmony_ci numSGE = 1 + (scale - 1) * 52358c2ecf20Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 52368c2ecf20Sopenharmony_ci (ioc->req_sz - 64) / ioc->SGE_size; 52378c2ecf20Sopenharmony_ci } 52388c2ecf20Sopenharmony_ci 52398c2ecf20Sopenharmony_ci if (numSGE < sh->sg_tablesize) { 52408c2ecf20Sopenharmony_ci /* Reset this value */ 52418c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 52428c2ecf20Sopenharmony_ci "Resetting sg_tablesize to %d from %d\n", 52438c2ecf20Sopenharmony_ci ioc->name, numSGE, sh->sg_tablesize)); 52448c2ecf20Sopenharmony_ci sh->sg_tablesize = numSGE; 52458c2ecf20Sopenharmony_ci } 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci if (mpt_loadtime_max_sectors) { 52488c2ecf20Sopenharmony_ci if (mpt_loadtime_max_sectors < 64 || 52498c2ecf20Sopenharmony_ci mpt_loadtime_max_sectors > 8192) { 52508c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "Invalid value passed for" 52518c2ecf20Sopenharmony_ci "mpt_loadtime_max_sectors %d." 52528c2ecf20Sopenharmony_ci "Range from 64 to 8192\n", ioc->name, 52538c2ecf20Sopenharmony_ci mpt_loadtime_max_sectors); 52548c2ecf20Sopenharmony_ci } 52558c2ecf20Sopenharmony_ci mpt_loadtime_max_sectors &= 0xFFFFFFFE; 52568c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 52578c2ecf20Sopenharmony_ci "Resetting max sector to %d from %d\n", 52588c2ecf20Sopenharmony_ci ioc->name, mpt_loadtime_max_sectors, sh->max_sectors)); 52598c2ecf20Sopenharmony_ci sh->max_sectors = mpt_loadtime_max_sectors; 52608c2ecf20Sopenharmony_ci } 52618c2ecf20Sopenharmony_ci 52628c2ecf20Sopenharmony_ci hd = shost_priv(sh); 52638c2ecf20Sopenharmony_ci hd->ioc = ioc; 52648c2ecf20Sopenharmony_ci 52658c2ecf20Sopenharmony_ci /* SCSI needs scsi_cmnd lookup table! 52668c2ecf20Sopenharmony_ci * (with size equal to req_depth*PtrSz!) 52678c2ecf20Sopenharmony_ci */ 52688c2ecf20Sopenharmony_ci ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); 52698c2ecf20Sopenharmony_ci if (!ioc->ScsiLookup) { 52708c2ecf20Sopenharmony_ci error = -ENOMEM; 52718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 52728c2ecf20Sopenharmony_ci goto out_mptsas_probe; 52738c2ecf20Sopenharmony_ci } 52748c2ecf20Sopenharmony_ci spin_lock_init(&ioc->scsi_lookup_lock); 52758c2ecf20Sopenharmony_ci 52768c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", 52778c2ecf20Sopenharmony_ci ioc->name, ioc->ScsiLookup)); 52788c2ecf20Sopenharmony_ci 52798c2ecf20Sopenharmony_ci ioc->sas_data.ptClear = mpt_pt_clear; 52808c2ecf20Sopenharmony_ci 52818c2ecf20Sopenharmony_ci hd->last_queue_full = 0; 52828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hd->target_reset_list); 52838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ioc->sas_device_info_list); 52848c2ecf20Sopenharmony_ci mutex_init(&ioc->sas_device_info_mutex); 52858c2ecf20Sopenharmony_ci 52868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 52878c2ecf20Sopenharmony_ci 52888c2ecf20Sopenharmony_ci if (ioc->sas_data.ptClear==1) { 52898c2ecf20Sopenharmony_ci mptbase_sas_persist_operation( 52908c2ecf20Sopenharmony_ci ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); 52918c2ecf20Sopenharmony_ci } 52928c2ecf20Sopenharmony_ci 52938c2ecf20Sopenharmony_ci error = scsi_add_host(sh, &ioc->pcidev->dev); 52948c2ecf20Sopenharmony_ci if (error) { 52958c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_ERR_FMT 52968c2ecf20Sopenharmony_ci "scsi_add_host failed\n", ioc->name)); 52978c2ecf20Sopenharmony_ci goto out_mptsas_probe; 52988c2ecf20Sopenharmony_ci } 52998c2ecf20Sopenharmony_ci 53008c2ecf20Sopenharmony_ci /* older firmware doesn't support expander events */ 53018c2ecf20Sopenharmony_ci if ((ioc->facts.HeaderVersion >> 8) < 0xE) 53028c2ecf20Sopenharmony_ci ioc->old_sas_discovery_protocal = 1; 53038c2ecf20Sopenharmony_ci mptsas_scan_sas_topology(ioc); 53048c2ecf20Sopenharmony_ci mptsas_fw_event_on(ioc); 53058c2ecf20Sopenharmony_ci return 0; 53068c2ecf20Sopenharmony_ci 53078c2ecf20Sopenharmony_ci out_mptsas_probe: 53088c2ecf20Sopenharmony_ci 53098c2ecf20Sopenharmony_ci mptscsih_remove(pdev); 53108c2ecf20Sopenharmony_ci return error; 53118c2ecf20Sopenharmony_ci} 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_cistatic void 53148c2ecf20Sopenharmony_cimptsas_shutdown(struct pci_dev *pdev) 53158c2ecf20Sopenharmony_ci{ 53168c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 53178c2ecf20Sopenharmony_ci 53188c2ecf20Sopenharmony_ci mptsas_fw_event_off(ioc); 53198c2ecf20Sopenharmony_ci mptsas_cleanup_fw_event_q(ioc); 53208c2ecf20Sopenharmony_ci} 53218c2ecf20Sopenharmony_ci 53228c2ecf20Sopenharmony_cistatic void mptsas_remove(struct pci_dev *pdev) 53238c2ecf20Sopenharmony_ci{ 53248c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 53258c2ecf20Sopenharmony_ci struct mptsas_portinfo *p, *n; 53268c2ecf20Sopenharmony_ci int i; 53278c2ecf20Sopenharmony_ci 53288c2ecf20Sopenharmony_ci if (!ioc->sh) { 53298c2ecf20Sopenharmony_ci printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name); 53308c2ecf20Sopenharmony_ci mpt_detach(pdev); 53318c2ecf20Sopenharmony_ci return; 53328c2ecf20Sopenharmony_ci } 53338c2ecf20Sopenharmony_ci 53348c2ecf20Sopenharmony_ci mptsas_shutdown(pdev); 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci mptsas_del_device_components(ioc); 53378c2ecf20Sopenharmony_ci 53388c2ecf20Sopenharmony_ci ioc->sas_discovery_ignore_events = 1; 53398c2ecf20Sopenharmony_ci sas_remove_host(ioc->sh); 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_ci mutex_lock(&ioc->sas_topology_mutex); 53428c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { 53438c2ecf20Sopenharmony_ci list_del(&p->list); 53448c2ecf20Sopenharmony_ci for (i = 0 ; i < p->num_phys ; i++) 53458c2ecf20Sopenharmony_ci mptsas_port_delete(ioc, p->phy_info[i].port_details); 53468c2ecf20Sopenharmony_ci 53478c2ecf20Sopenharmony_ci kfree(p->phy_info); 53488c2ecf20Sopenharmony_ci kfree(p); 53498c2ecf20Sopenharmony_ci } 53508c2ecf20Sopenharmony_ci mutex_unlock(&ioc->sas_topology_mutex); 53518c2ecf20Sopenharmony_ci ioc->hba_port_info = NULL; 53528c2ecf20Sopenharmony_ci mptscsih_remove(pdev); 53538c2ecf20Sopenharmony_ci} 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_cistatic struct pci_device_id mptsas_pci_table[] = { 53568c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, 53578c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 53588c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, 53598c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 53608c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E, 53618c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 53628c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E, 53638c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 53648c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, 53658c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 53668c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP, 53678c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 53688c2ecf20Sopenharmony_ci {0} /* Terminating entry */ 53698c2ecf20Sopenharmony_ci}; 53708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mptsas_pci_table); 53718c2ecf20Sopenharmony_ci 53728c2ecf20Sopenharmony_ci 53738c2ecf20Sopenharmony_cistatic struct pci_driver mptsas_driver = { 53748c2ecf20Sopenharmony_ci .name = "mptsas", 53758c2ecf20Sopenharmony_ci .id_table = mptsas_pci_table, 53768c2ecf20Sopenharmony_ci .probe = mptsas_probe, 53778c2ecf20Sopenharmony_ci .remove = mptsas_remove, 53788c2ecf20Sopenharmony_ci .shutdown = mptsas_shutdown, 53798c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 53808c2ecf20Sopenharmony_ci .suspend = mptscsih_suspend, 53818c2ecf20Sopenharmony_ci .resume = mptscsih_resume, 53828c2ecf20Sopenharmony_ci#endif 53838c2ecf20Sopenharmony_ci}; 53848c2ecf20Sopenharmony_ci 53858c2ecf20Sopenharmony_cistatic int __init 53868c2ecf20Sopenharmony_cimptsas_init(void) 53878c2ecf20Sopenharmony_ci{ 53888c2ecf20Sopenharmony_ci int error; 53898c2ecf20Sopenharmony_ci 53908c2ecf20Sopenharmony_ci show_mptmod_ver(my_NAME, my_VERSION); 53918c2ecf20Sopenharmony_ci 53928c2ecf20Sopenharmony_ci mptsas_transport_template = 53938c2ecf20Sopenharmony_ci sas_attach_transport(&mptsas_transport_functions); 53948c2ecf20Sopenharmony_ci if (!mptsas_transport_template) 53958c2ecf20Sopenharmony_ci return -ENODEV; 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER, 53988c2ecf20Sopenharmony_ci "mptscsih_io_done"); 53998c2ecf20Sopenharmony_ci mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER, 54008c2ecf20Sopenharmony_ci "mptscsih_taskmgmt_complete"); 54018c2ecf20Sopenharmony_ci mptsasInternalCtx = 54028c2ecf20Sopenharmony_ci mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER, 54038c2ecf20Sopenharmony_ci "mptscsih_scandv_complete"); 54048c2ecf20Sopenharmony_ci mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER, 54058c2ecf20Sopenharmony_ci "mptsas_mgmt_done"); 54068c2ecf20Sopenharmony_ci mptsasDeviceResetCtx = 54078c2ecf20Sopenharmony_ci mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER, 54088c2ecf20Sopenharmony_ci "mptsas_taskmgmt_complete"); 54098c2ecf20Sopenharmony_ci 54108c2ecf20Sopenharmony_ci mpt_event_register(mptsasDoneCtx, mptsas_event_process); 54118c2ecf20Sopenharmony_ci mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); 54128c2ecf20Sopenharmony_ci 54138c2ecf20Sopenharmony_ci error = pci_register_driver(&mptsas_driver); 54148c2ecf20Sopenharmony_ci if (error) 54158c2ecf20Sopenharmony_ci sas_release_transport(mptsas_transport_template); 54168c2ecf20Sopenharmony_ci 54178c2ecf20Sopenharmony_ci return error; 54188c2ecf20Sopenharmony_ci} 54198c2ecf20Sopenharmony_ci 54208c2ecf20Sopenharmony_cistatic void __exit 54218c2ecf20Sopenharmony_cimptsas_exit(void) 54228c2ecf20Sopenharmony_ci{ 54238c2ecf20Sopenharmony_ci pci_unregister_driver(&mptsas_driver); 54248c2ecf20Sopenharmony_ci sas_release_transport(mptsas_transport_template); 54258c2ecf20Sopenharmony_ci 54268c2ecf20Sopenharmony_ci mpt_reset_deregister(mptsasDoneCtx); 54278c2ecf20Sopenharmony_ci mpt_event_deregister(mptsasDoneCtx); 54288c2ecf20Sopenharmony_ci 54298c2ecf20Sopenharmony_ci mpt_deregister(mptsasMgmtCtx); 54308c2ecf20Sopenharmony_ci mpt_deregister(mptsasInternalCtx); 54318c2ecf20Sopenharmony_ci mpt_deregister(mptsasTaskCtx); 54328c2ecf20Sopenharmony_ci mpt_deregister(mptsasDoneCtx); 54338c2ecf20Sopenharmony_ci mpt_deregister(mptsasDeviceResetCtx); 54348c2ecf20Sopenharmony_ci} 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_cimodule_init(mptsas_init); 54378c2ecf20Sopenharmony_cimodule_exit(mptsas_exit); 5438