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