1*5597088cSDongdong Hao // SPDX-License-Identifier: GPL-2.0 2*5597088cSDongdong Hao /* 3*5597088cSDongdong Hao * Copyright (C) 2026 LeapIO Tech Inc. 4*5597088cSDongdong Hao * 5*5597088cSDongdong Hao * LeapRAID storage and RAID controller driver. 6*5597088cSDongdong Hao */ 7*5597088cSDongdong Hao #include <scsi/scsi_host.h> 8*5597088cSDongdong Hao 9*5597088cSDongdong Hao #include "leapraid_func.h" 10*5597088cSDongdong Hao 11*5597088cSDongdong Hao static struct leapraid_topo_node *leapraid_transport_topo_node_by_sas_addr( 12*5597088cSDongdong Hao struct leapraid_adapter *adapter, 13*5597088cSDongdong Hao u64 sas_addr, 14*5597088cSDongdong Hao struct leapraid_card_port *card_port) 15*5597088cSDongdong Hao { 16*5597088cSDongdong Hao if (adapter->dev_topo.card.sas_address == sas_addr) 17*5597088cSDongdong Hao return &adapter->dev_topo.card; 18*5597088cSDongdong Hao 19*5597088cSDongdong Hao return leapraid_exp_find_by_sas_address(adapter, sas_addr, card_port); 20*5597088cSDongdong Hao } 21*5597088cSDongdong Hao 22*5597088cSDongdong Hao static u8 leapraid_get_port_id_by_expander(struct leapraid_adapter *adapter, 23*5597088cSDongdong Hao struct sas_rphy *rphy) 24*5597088cSDongdong Hao { 25*5597088cSDongdong Hao struct leapraid_topo_node *topo_node_exp; 26*5597088cSDongdong Hao unsigned long flags; 27*5597088cSDongdong Hao u8 port_id = 0xFF; 28*5597088cSDongdong Hao 29*5597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags); 30*5597088cSDongdong Hao list_for_each_entry(topo_node_exp, &adapter->dev_topo.exp_list, list) { 31*5597088cSDongdong Hao if (topo_node_exp->rphy == rphy) { 32*5597088cSDongdong Hao port_id = topo_node_exp->card_port->port_id; 33*5597088cSDongdong Hao break; 34*5597088cSDongdong Hao } 35*5597088cSDongdong Hao } 36*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags); 37*5597088cSDongdong Hao 38*5597088cSDongdong Hao return port_id; 39*5597088cSDongdong Hao } 40*5597088cSDongdong Hao 41*5597088cSDongdong Hao static u8 leapraid_get_port_id_by_end_dev(struct leapraid_adapter *adapter, 42*5597088cSDongdong Hao struct sas_rphy *rphy) 43*5597088cSDongdong Hao { 44*5597088cSDongdong Hao struct leapraid_sas_dev *sas_dev; 45*5597088cSDongdong Hao unsigned long flags; 46*5597088cSDongdong Hao u8 port_id = 0xFF; 47*5597088cSDongdong Hao 48*5597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags); 49*5597088cSDongdong Hao sas_dev = leapraid_hold_lock_get_sas_dev_by_addr_and_rphy( 50*5597088cSDongdong Hao adapter, 51*5597088cSDongdong Hao rphy->identify.sas_address, 52*5597088cSDongdong Hao rphy); 53*5597088cSDongdong Hao if (sas_dev) { 54*5597088cSDongdong Hao port_id = sas_dev->card_port->port_id; 55*5597088cSDongdong Hao leapraid_sdev_put(sas_dev); 56*5597088cSDongdong Hao } 57*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags); 58*5597088cSDongdong Hao 59*5597088cSDongdong Hao return port_id; 60*5597088cSDongdong Hao } 61*5597088cSDongdong Hao 62*5597088cSDongdong Hao static u8 leapraid_transport_get_port_id_by_rphy( 63*5597088cSDongdong Hao struct leapraid_adapter *adapter, 64*5597088cSDongdong Hao struct sas_rphy *rphy) 65*5597088cSDongdong Hao { 66*5597088cSDongdong Hao if (!rphy) 67*5597088cSDongdong Hao return 0xFF; 68*5597088cSDongdong Hao 69*5597088cSDongdong Hao switch (rphy->identify.device_type) { 70*5597088cSDongdong Hao case SAS_EDGE_EXPANDER_DEVICE: 71*5597088cSDongdong Hao case SAS_FANOUT_EXPANDER_DEVICE: 72*5597088cSDongdong Hao return leapraid_get_port_id_by_expander(adapter, rphy); 73*5597088cSDongdong Hao case SAS_END_DEVICE: 74*5597088cSDongdong Hao return leapraid_get_port_id_by_end_dev(adapter, rphy); 75*5597088cSDongdong Hao default: 76*5597088cSDongdong Hao return 0xFF; 77*5597088cSDongdong Hao } 78*5597088cSDongdong Hao } 79*5597088cSDongdong Hao 80*5597088cSDongdong Hao static enum sas_linkrate leapraid_transport_convert_phy_link_rate(u8 link_rate) 81*5597088cSDongdong Hao { 82*5597088cSDongdong Hao unsigned int i; 83*5597088cSDongdong Hao 84*5597088cSDongdong Hao #define SAS_RATE_12G SAS_LINK_RATE_12_0_GBPS 85*5597088cSDongdong Hao 86*5597088cSDongdong Hao const struct linkrate_map { 87*5597088cSDongdong Hao u8 in; 88*5597088cSDongdong Hao enum sas_linkrate out; 89*5597088cSDongdong Hao } linkrate_table[] = { 90*5597088cSDongdong Hao { 91*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_1_5, 92*5597088cSDongdong Hao SAS_LINK_RATE_1_5_GBPS 93*5597088cSDongdong Hao }, 94*5597088cSDongdong Hao { 95*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_3_0, 96*5597088cSDongdong Hao SAS_LINK_RATE_3_0_GBPS 97*5597088cSDongdong Hao }, 98*5597088cSDongdong Hao { 99*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_6_0, 100*5597088cSDongdong Hao SAS_LINK_RATE_6_0_GBPS 101*5597088cSDongdong Hao }, 102*5597088cSDongdong Hao { 103*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_12_0, 104*5597088cSDongdong Hao SAS_RATE_12G 105*5597088cSDongdong Hao }, 106*5597088cSDongdong Hao { 107*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_PHY_DISABLED, 108*5597088cSDongdong Hao SAS_PHY_DISABLED 109*5597088cSDongdong Hao }, 110*5597088cSDongdong Hao { 111*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED, 112*5597088cSDongdong Hao SAS_LINK_RATE_FAILED 113*5597088cSDongdong Hao }, 114*5597088cSDongdong Hao { 115*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_PORT_SELECTOR, 116*5597088cSDongdong Hao SAS_SATA_PORT_SELECTOR 117*5597088cSDongdong Hao }, 118*5597088cSDongdong Hao { 119*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SMP_RESETTING, 120*5597088cSDongdong Hao SAS_LINK_RATE_UNKNOWN 121*5597088cSDongdong Hao }, 122*5597088cSDongdong Hao { 123*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE, 124*5597088cSDongdong Hao SAS_LINK_RATE_UNKNOWN 125*5597088cSDongdong Hao }, 126*5597088cSDongdong Hao { 127*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE, 128*5597088cSDongdong Hao SAS_LINK_RATE_UNKNOWN 129*5597088cSDongdong Hao }, 130*5597088cSDongdong Hao }; 131*5597088cSDongdong Hao 132*5597088cSDongdong Hao for (i = 0; i < ARRAY_SIZE(linkrate_table); i++) 133*5597088cSDongdong Hao if (linkrate_table[i].in == link_rate) 134*5597088cSDongdong Hao return linkrate_table[i].out; 135*5597088cSDongdong Hao 136*5597088cSDongdong Hao return SAS_LINK_RATE_UNKNOWN; 137*5597088cSDongdong Hao } 138*5597088cSDongdong Hao 139*5597088cSDongdong Hao static void leapraid_set_identify_protocol_flags(u32 dev_info, 140*5597088cSDongdong Hao struct sas_identify *identify) 141*5597088cSDongdong Hao { 142*5597088cSDongdong Hao unsigned int i; 143*5597088cSDongdong Hao 144*5597088cSDongdong Hao const struct protocol_mapping { 145*5597088cSDongdong Hao u32 mask; 146*5597088cSDongdong Hao u32 *target; 147*5597088cSDongdong Hao u32 protocol; 148*5597088cSDongdong Hao } mappings[] = { 149*5597088cSDongdong Hao { 150*5597088cSDongdong Hao LEAPRAID_DEVTYP_SSP_INIT, 151*5597088cSDongdong Hao &identify->initiator_port_protocols, 152*5597088cSDongdong Hao SAS_PROTOCOL_SSP 153*5597088cSDongdong Hao }, 154*5597088cSDongdong Hao { 155*5597088cSDongdong Hao LEAPRAID_DEVTYP_STP_INIT, 156*5597088cSDongdong Hao &identify->initiator_port_protocols, 157*5597088cSDongdong Hao SAS_PROTOCOL_STP 158*5597088cSDongdong Hao }, 159*5597088cSDongdong Hao { 160*5597088cSDongdong Hao LEAPRAID_DEVTYP_SMP_INIT, 161*5597088cSDongdong Hao &identify->initiator_port_protocols, 162*5597088cSDongdong Hao SAS_PROTOCOL_SMP 163*5597088cSDongdong Hao }, 164*5597088cSDongdong Hao { 165*5597088cSDongdong Hao LEAPRAID_DEVTYP_SATA_HOST, 166*5597088cSDongdong Hao &identify->initiator_port_protocols, 167*5597088cSDongdong Hao SAS_PROTOCOL_SATA 168*5597088cSDongdong Hao }, 169*5597088cSDongdong Hao { 170*5597088cSDongdong Hao LEAPRAID_DEVTYP_SSP_TGT, 171*5597088cSDongdong Hao &identify->target_port_protocols, 172*5597088cSDongdong Hao SAS_PROTOCOL_SSP 173*5597088cSDongdong Hao }, 174*5597088cSDongdong Hao { 175*5597088cSDongdong Hao LEAPRAID_DEVTYP_STP_TGT, 176*5597088cSDongdong Hao &identify->target_port_protocols, 177*5597088cSDongdong Hao SAS_PROTOCOL_STP 178*5597088cSDongdong Hao }, 179*5597088cSDongdong Hao { 180*5597088cSDongdong Hao LEAPRAID_DEVTYP_SMP_TGT, 181*5597088cSDongdong Hao &identify->target_port_protocols, 182*5597088cSDongdong Hao SAS_PROTOCOL_SMP 183*5597088cSDongdong Hao }, 184*5597088cSDongdong Hao { 185*5597088cSDongdong Hao LEAPRAID_DEVTYP_SATA_DEV, 186*5597088cSDongdong Hao &identify->target_port_protocols, 187*5597088cSDongdong Hao SAS_PROTOCOL_SATA 188*5597088cSDongdong Hao }, 189*5597088cSDongdong Hao }; 190*5597088cSDongdong Hao 191*5597088cSDongdong Hao for (i = 0; i < ARRAY_SIZE(mappings); i++) 192*5597088cSDongdong Hao if (dev_info & mappings[i].mask && mappings[i].target) 193*5597088cSDongdong Hao *mappings[i].target |= mappings[i].protocol; 194*5597088cSDongdong Hao } 195*5597088cSDongdong Hao 196*5597088cSDongdong Hao static int leapraid_transport_set_identify(struct leapraid_adapter *adapter, 197*5597088cSDongdong Hao u16 hdl, 198*5597088cSDongdong Hao struct sas_identify *identify) 199*5597088cSDongdong Hao { 200*5597088cSDongdong Hao union cfg_param_1 cfgp1 = {0}; 201*5597088cSDongdong Hao union cfg_param_2 cfgp2 = {0}; 202*5597088cSDongdong Hao struct leapraid_sas_dev_p0 sas_dev_pg0; 203*5597088cSDongdong Hao u32 dev_info; 204*5597088cSDongdong Hao 205*5597088cSDongdong Hao if ((adapter->access_ctrl.shost_recovering && 206*5597088cSDongdong Hao !adapter->scan_dev_desc.driver_loading) || 207*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) { 208*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 209*5597088cSDongdong Hao "%s: Failed, shost_recovering=%d pcie_recovering=%d\n", 210*5597088cSDongdong Hao __func__, 211*5597088cSDongdong Hao adapter->access_ctrl.shost_recovering, 212*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering); 213*5597088cSDongdong Hao return -EFAULT; 214*5597088cSDongdong Hao } 215*5597088cSDongdong Hao 216*5597088cSDongdong Hao cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL; 217*5597088cSDongdong Hao cfgp2.handle = hdl; 218*5597088cSDongdong Hao if (leapraid_op_config_page(adapter, &sas_dev_pg0, cfgp1, 219*5597088cSDongdong Hao cfgp2, GET_SAS_DEVICE_PG0)) 220*5597088cSDongdong Hao return -ENXIO; 221*5597088cSDongdong Hao 222*5597088cSDongdong Hao memset(identify, 0, sizeof(struct sas_identify)); 223*5597088cSDongdong Hao dev_info = le32_to_cpu(sas_dev_pg0.dev_info); 224*5597088cSDongdong Hao identify->sas_address = le64_to_cpu(sas_dev_pg0.sas_address); 225*5597088cSDongdong Hao identify->phy_identifier = sas_dev_pg0.phy_num; 226*5597088cSDongdong Hao 227*5597088cSDongdong Hao switch (dev_info & LEAPRAID_DEVTYP_MASK_DEV_TYPE) { 228*5597088cSDongdong Hao case LEAPRAID_DEVTYP_NO_DEV: 229*5597088cSDongdong Hao identify->device_type = SAS_PHY_UNUSED; 230*5597088cSDongdong Hao break; 231*5597088cSDongdong Hao case LEAPRAID_DEVTYP_END_DEV: 232*5597088cSDongdong Hao identify->device_type = SAS_END_DEVICE; 233*5597088cSDongdong Hao break; 234*5597088cSDongdong Hao case LEAPRAID_DEVTYP_EDGE_EXPANDER: 235*5597088cSDongdong Hao identify->device_type = SAS_EDGE_EXPANDER_DEVICE; 236*5597088cSDongdong Hao break; 237*5597088cSDongdong Hao case LEAPRAID_DEVTYP_FANOUT_EXPANDER: 238*5597088cSDongdong Hao identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; 239*5597088cSDongdong Hao break; 240*5597088cSDongdong Hao } 241*5597088cSDongdong Hao 242*5597088cSDongdong Hao leapraid_set_identify_protocol_flags(dev_info, identify); 243*5597088cSDongdong Hao 244*5597088cSDongdong Hao return 0; 245*5597088cSDongdong Hao } 246*5597088cSDongdong Hao 247*5597088cSDongdong Hao static void leapraid_transport_exp_set_edev(struct leapraid_adapter *adapter, 248*5597088cSDongdong Hao void *data_out, 249*5597088cSDongdong Hao struct sas_expander_device *edev) 250*5597088cSDongdong Hao { 251*5597088cSDongdong Hao struct leapraid_smp_passthrough_rep *smp_passthrough_rep; 252*5597088cSDongdong Hao struct leapraid_rep_manu_reply *rep_manu_reply; 253*5597088cSDongdong Hao u8 *component_id; 254*5597088cSDongdong Hao 255*5597088cSDongdong Hao smp_passthrough_rep = 256*5597088cSDongdong Hao (void *)&adapter->driver_cmds.transport_cmd.reply; 257*5597088cSDongdong Hao if (le16_to_cpu(smp_passthrough_rep->resp_data_len) != 258*5597088cSDongdong Hao sizeof(struct leapraid_rep_manu_reply)) 259*5597088cSDongdong Hao return; 260*5597088cSDongdong Hao 261*5597088cSDongdong Hao rep_manu_reply = data_out + sizeof(struct leapraid_rep_manu_request); 262*5597088cSDongdong Hao 263*5597088cSDongdong Hao memcpy(edev->vendor_id, rep_manu_reply->vendor_identification, 264*5597088cSDongdong Hao SAS_EXPANDER_VENDOR_ID_LEN); 265*5597088cSDongdong Hao edev->vendor_id[SAS_EXPANDER_VENDOR_ID_LEN] = '\0'; 266*5597088cSDongdong Hao 267*5597088cSDongdong Hao memcpy(edev->product_id, rep_manu_reply->product_identification, 268*5597088cSDongdong Hao SAS_EXPANDER_PRODUCT_ID_LEN); 269*5597088cSDongdong Hao edev->product_id[SAS_EXPANDER_PRODUCT_ID_LEN] = '\0'; 270*5597088cSDongdong Hao 271*5597088cSDongdong Hao memcpy(edev->product_rev, rep_manu_reply->product_revision_level, 272*5597088cSDongdong Hao SAS_EXPANDER_PRODUCT_REV_LEN); 273*5597088cSDongdong Hao edev->product_rev[SAS_EXPANDER_PRODUCT_REV_LEN] = '\0'; 274*5597088cSDongdong Hao 275*5597088cSDongdong Hao edev->level = rep_manu_reply->sas_format & 1; 276*5597088cSDongdong Hao if (edev->level) { 277*5597088cSDongdong Hao memcpy(edev->component_vendor_id, 278*5597088cSDongdong Hao rep_manu_reply->comp_vendor_identification, 279*5597088cSDongdong Hao SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); 280*5597088cSDongdong Hao edev->component_vendor_id[ 281*5597088cSDongdong Hao SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN] = '\0'; 282*5597088cSDongdong Hao 283*5597088cSDongdong Hao component_id = (u8 *)&rep_manu_reply->component_id; 284*5597088cSDongdong Hao edev->component_id = component_id[0] << 8 | component_id[1]; 285*5597088cSDongdong Hao edev->component_revision_id = 286*5597088cSDongdong Hao rep_manu_reply->component_revision_level; 287*5597088cSDongdong Hao } 288*5597088cSDongdong Hao } 289*5597088cSDongdong Hao 290*5597088cSDongdong Hao static int leapraid_transport_exp_report_manu(struct leapraid_adapter *adapter, 291*5597088cSDongdong Hao u64 sas_address, 292*5597088cSDongdong Hao struct sas_expander_device *edev, 293*5597088cSDongdong Hao u8 port_id) 294*5597088cSDongdong Hao { 295*5597088cSDongdong Hao struct leapraid_smp_passthrough_req *smp_passthrough_req; 296*5597088cSDongdong Hao struct leapraid_rep_manu_request *rep_manu_request; 297*5597088cSDongdong Hao dma_addr_t h2c_dma_addr; 298*5597088cSDongdong Hao dma_addr_t c2h_dma_addr; 299*5597088cSDongdong Hao bool issue_reset = false; 300*5597088cSDongdong Hao void *data_out = NULL; 301*5597088cSDongdong Hao u16 inter_taskid; 302*5597088cSDongdong Hao size_t c2h_size; 303*5597088cSDongdong Hao size_t h2c_size; 304*5597088cSDongdong Hao void *psge; 305*5597088cSDongdong Hao int rc; 306*5597088cSDongdong Hao 307*5597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering || 308*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) { 309*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 310*5597088cSDongdong Hao "%s: Failed, shost_recovering=%d pcie_recovering=%d\n", 311*5597088cSDongdong Hao __func__, 312*5597088cSDongdong Hao adapter->access_ctrl.shost_recovering, 313*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering); 314*5597088cSDongdong Hao return -EFAULT; 315*5597088cSDongdong Hao } 316*5597088cSDongdong Hao 317*5597088cSDongdong Hao mutex_lock(&adapter->driver_cmds.transport_cmd.mutex); 318*5597088cSDongdong Hao adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_PENDING; 319*5597088cSDongdong Hao rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT, 320*5597088cSDongdong Hao __func__); 321*5597088cSDongdong Hao if (rc) 322*5597088cSDongdong Hao goto out_cleanup; 323*5597088cSDongdong Hao 324*5597088cSDongdong Hao h2c_size = sizeof(struct leapraid_rep_manu_request); 325*5597088cSDongdong Hao c2h_size = sizeof(struct leapraid_rep_manu_reply); 326*5597088cSDongdong Hao data_out = dma_alloc_coherent(&adapter->pdev->dev, 327*5597088cSDongdong Hao h2c_size + c2h_size, 328*5597088cSDongdong Hao &h2c_dma_addr, 329*5597088cSDongdong Hao GFP_ATOMIC); 330*5597088cSDongdong Hao if (!data_out) { 331*5597088cSDongdong Hao rc = -ENOMEM; 332*5597088cSDongdong Hao goto out_cleanup; 333*5597088cSDongdong Hao } 334*5597088cSDongdong Hao 335*5597088cSDongdong Hao rep_manu_request = data_out; 336*5597088cSDongdong Hao rep_manu_request->smp_frame_type = 337*5597088cSDongdong Hao SMP_REPORT_MANUFACTURER_INFORMATION_FRAME_TYPE; 338*5597088cSDongdong Hao rep_manu_request->function = SMP_REPORT_MANUFACTURER_INFORMATION_FUNC; 339*5597088cSDongdong Hao rep_manu_request->allocated_response_length = 0; 340*5597088cSDongdong Hao rep_manu_request->request_length = 0; 341*5597088cSDongdong Hao 342*5597088cSDongdong Hao inter_taskid = adapter->driver_cmds.transport_cmd.inter_taskid; 343*5597088cSDongdong Hao smp_passthrough_req = leapraid_get_task_desc(adapter, inter_taskid); 344*5597088cSDongdong Hao memset(smp_passthrough_req, 0, 345*5597088cSDongdong Hao sizeof(struct leapraid_smp_passthrough_req)); 346*5597088cSDongdong Hao smp_passthrough_req->func = LEAPRAID_FUNC_SMP_PASSTHROUGH; 347*5597088cSDongdong Hao smp_passthrough_req->physical_port = port_id; 348*5597088cSDongdong Hao smp_passthrough_req->sas_address = cpu_to_le64(sas_address); 349*5597088cSDongdong Hao smp_passthrough_req->req_data_len = cpu_to_le16(h2c_size); 350*5597088cSDongdong Hao psge = &smp_passthrough_req->sgl; 351*5597088cSDongdong Hao c2h_dma_addr = h2c_dma_addr + sizeof(struct leapraid_rep_manu_request); 352*5597088cSDongdong Hao leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size, 353*5597088cSDongdong Hao c2h_dma_addr, c2h_size); 354*5597088cSDongdong Hao 355*5597088cSDongdong Hao init_completion(&adapter->driver_cmds.transport_cmd.done); 356*5597088cSDongdong Hao leapraid_fire_task(adapter, inter_taskid); 357*5597088cSDongdong Hao wait_for_completion_timeout(&adapter->driver_cmds.transport_cmd.done, 358*5597088cSDongdong Hao LEAPRAID_TRANSPORT_CMD_TIMEOUT * HZ); 359*5597088cSDongdong Hao if (!(adapter->driver_cmds.transport_cmd.status & LEAPRAID_CMD_DONE)) { 360*5597088cSDongdong Hao rc = -ETIMEDOUT; 361*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 362*5597088cSDongdong Hao "%s: SMP passthrough timeout, st=0x%x\n", 363*5597088cSDongdong Hao __func__, adapter->driver_cmds.transport_cmd.status); 364*5597088cSDongdong Hao leapraid_log_req_context(adapter, inter_taskid, 365*5597088cSDongdong Hao smp_passthrough_req); 366*5597088cSDongdong Hao if (!(adapter->driver_cmds.transport_cmd.status & 367*5597088cSDongdong Hao LEAPRAID_CMD_RESET)) 368*5597088cSDongdong Hao issue_reset = true; 369*5597088cSDongdong Hao 370*5597088cSDongdong Hao goto hard_reset; 371*5597088cSDongdong Hao } 372*5597088cSDongdong Hao 373*5597088cSDongdong Hao if (adapter->driver_cmds.transport_cmd.status & 374*5597088cSDongdong Hao LEAPRAID_CMD_REPLY_VALID) 375*5597088cSDongdong Hao leapraid_transport_exp_set_edev(adapter, data_out, edev); 376*5597088cSDongdong Hao 377*5597088cSDongdong Hao hard_reset: 378*5597088cSDongdong Hao if (issue_reset) { 379*5597088cSDongdong Hao dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n", 380*5597088cSDongdong Hao __func__, __LINE__); 381*5597088cSDongdong Hao rc = leapraid_hard_reset_handler(adapter, FULL_RESET); 382*5597088cSDongdong Hao } 383*5597088cSDongdong Hao out_cleanup: 384*5597088cSDongdong Hao adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_NOT_USED; 385*5597088cSDongdong Hao if (data_out) 386*5597088cSDongdong Hao dma_free_coherent(&adapter->pdev->dev, h2c_size + c2h_size, 387*5597088cSDongdong Hao data_out, h2c_dma_addr); 388*5597088cSDongdong Hao 389*5597088cSDongdong Hao mutex_unlock(&adapter->driver_cmds.transport_cmd.mutex); 390*5597088cSDongdong Hao return rc; 391*5597088cSDongdong Hao } 392*5597088cSDongdong Hao 393*5597088cSDongdong Hao static void leapraid_transport_del_port(struct leapraid_adapter *adapter, 394*5597088cSDongdong Hao struct leapraid_sas_port *sas_port) 395*5597088cSDongdong Hao { 396*5597088cSDongdong Hao dev_info(&sas_port->port->dev, 397*5597088cSDongdong Hao "Remove port: SAS addr=0x%016llx\n", 398*5597088cSDongdong Hao (unsigned long long)sas_port->remote_identify.sas_address); 399*5597088cSDongdong Hao switch (sas_port->remote_identify.device_type) { 400*5597088cSDongdong Hao case SAS_END_DEVICE: 401*5597088cSDongdong Hao leapraid_sas_dev_remove_by_sas_address( 402*5597088cSDongdong Hao adapter, 403*5597088cSDongdong Hao sas_port->remote_identify.sas_address, 404*5597088cSDongdong Hao sas_port->card_port); 405*5597088cSDongdong Hao break; 406*5597088cSDongdong Hao case SAS_EDGE_EXPANDER_DEVICE: 407*5597088cSDongdong Hao case SAS_FANOUT_EXPANDER_DEVICE: 408*5597088cSDongdong Hao leapraid_exp_rm(adapter, sas_port->remote_identify.sas_address, 409*5597088cSDongdong Hao sas_port->card_port); 410*5597088cSDongdong Hao break; 411*5597088cSDongdong Hao default: 412*5597088cSDongdong Hao break; 413*5597088cSDongdong Hao } 414*5597088cSDongdong Hao } 415*5597088cSDongdong Hao 416*5597088cSDongdong Hao static void leapraid_transport_del_phy(struct leapraid_adapter *adapter, 417*5597088cSDongdong Hao struct leapraid_sas_port *sas_port, 418*5597088cSDongdong Hao struct leapraid_card_phy *card_phy) 419*5597088cSDongdong Hao { 420*5597088cSDongdong Hao dev_info(&card_phy->phy->dev, 421*5597088cSDongdong Hao "Remove PHY: SAS addr=0x%016llx, phy=%d\n", 422*5597088cSDongdong Hao (unsigned long long)sas_port->remote_identify.sas_address, 423*5597088cSDongdong Hao card_phy->phy_id); 424*5597088cSDongdong Hao list_del(&card_phy->port_siblings); 425*5597088cSDongdong Hao sas_port->phys_num--; 426*5597088cSDongdong Hao sas_port_delete_phy(sas_port->port, card_phy->phy); 427*5597088cSDongdong Hao card_phy->phy_is_assigned = 0; 428*5597088cSDongdong Hao } 429*5597088cSDongdong Hao 430*5597088cSDongdong Hao static void leapraid_transport_add_phy(struct leapraid_adapter *adapter, 431*5597088cSDongdong Hao struct leapraid_sas_port *sas_port, 432*5597088cSDongdong Hao struct leapraid_card_phy *card_phy) 433*5597088cSDongdong Hao { 434*5597088cSDongdong Hao dev_info(&card_phy->phy->dev, 435*5597088cSDongdong Hao "Add PHY: SAS addr=0x%016llx, phy=%d\n", 436*5597088cSDongdong Hao (unsigned long long)sas_port->remote_identify.sas_address, 437*5597088cSDongdong Hao card_phy->phy_id); 438*5597088cSDongdong Hao list_add_tail(&card_phy->port_siblings, &sas_port->phy_list); 439*5597088cSDongdong Hao sas_port->phys_num++; 440*5597088cSDongdong Hao sas_port_add_phy(sas_port->port, card_phy->phy); 441*5597088cSDongdong Hao card_phy->phy_is_assigned = 1; 442*5597088cSDongdong Hao } 443*5597088cSDongdong Hao 444*5597088cSDongdong Hao void leapraid_transport_attach_phy_to_port( 445*5597088cSDongdong Hao struct leapraid_adapter *adapter, 446*5597088cSDongdong Hao struct leapraid_topo_node *topo_node, 447*5597088cSDongdong Hao struct leapraid_card_phy *card_phy, 448*5597088cSDongdong Hao u64 sas_address, 449*5597088cSDongdong Hao struct leapraid_card_port *card_port) 450*5597088cSDongdong Hao { 451*5597088cSDongdong Hao struct leapraid_sas_port *sas_port; 452*5597088cSDongdong Hao struct leapraid_card_phy *card_phy_srch; 453*5597088cSDongdong Hao 454*5597088cSDongdong Hao if (card_phy->phy_is_assigned) 455*5597088cSDongdong Hao return; 456*5597088cSDongdong Hao 457*5597088cSDongdong Hao if (!card_port) 458*5597088cSDongdong Hao return; 459*5597088cSDongdong Hao 460*5597088cSDongdong Hao list_for_each_entry(sas_port, &topo_node->sas_port_list, port_list) { 461*5597088cSDongdong Hao if (sas_port->remote_identify.sas_address != sas_address) 462*5597088cSDongdong Hao continue; 463*5597088cSDongdong Hao 464*5597088cSDongdong Hao if (sas_port->card_port != card_port) 465*5597088cSDongdong Hao continue; 466*5597088cSDongdong Hao 467*5597088cSDongdong Hao list_for_each_entry(card_phy_srch, &sas_port->phy_list, 468*5597088cSDongdong Hao port_siblings) { 469*5597088cSDongdong Hao if (card_phy_srch == card_phy) 470*5597088cSDongdong Hao return; 471*5597088cSDongdong Hao } 472*5597088cSDongdong Hao leapraid_transport_add_phy(adapter, sas_port, card_phy); 473*5597088cSDongdong Hao return; 474*5597088cSDongdong Hao } 475*5597088cSDongdong Hao } 476*5597088cSDongdong Hao 477*5597088cSDongdong Hao void leapraid_transport_detach_phy_to_port( 478*5597088cSDongdong Hao struct leapraid_adapter *adapter, 479*5597088cSDongdong Hao struct leapraid_topo_node *topo_node, 480*5597088cSDongdong Hao struct leapraid_card_phy *target_card_phy) 481*5597088cSDongdong Hao { 482*5597088cSDongdong Hao struct leapraid_sas_port *sas_port, *sas_port_next; 483*5597088cSDongdong Hao struct leapraid_card_phy *cur_card_phy; 484*5597088cSDongdong Hao 485*5597088cSDongdong Hao if (!target_card_phy->phy_is_assigned) 486*5597088cSDongdong Hao return; 487*5597088cSDongdong Hao 488*5597088cSDongdong Hao list_for_each_entry_safe(sas_port, sas_port_next, 489*5597088cSDongdong Hao &topo_node->sas_port_list, port_list) { 490*5597088cSDongdong Hao list_for_each_entry(cur_card_phy, &sas_port->phy_list, 491*5597088cSDongdong Hao port_siblings) { 492*5597088cSDongdong Hao if (cur_card_phy != target_card_phy) 493*5597088cSDongdong Hao continue; 494*5597088cSDongdong Hao 495*5597088cSDongdong Hao if (sas_port->phys_num == 1 && 496*5597088cSDongdong Hao !adapter->access_ctrl.shost_recovering) 497*5597088cSDongdong Hao leapraid_transport_del_port(adapter, sas_port); 498*5597088cSDongdong Hao else 499*5597088cSDongdong Hao leapraid_transport_del_phy(adapter, sas_port, 500*5597088cSDongdong Hao target_card_phy); 501*5597088cSDongdong Hao return; 502*5597088cSDongdong Hao } 503*5597088cSDongdong Hao } 504*5597088cSDongdong Hao } 505*5597088cSDongdong Hao 506*5597088cSDongdong Hao static void leapraid_detach_phy_from_old_port( 507*5597088cSDongdong Hao struct leapraid_adapter *adapter, 508*5597088cSDongdong Hao struct leapraid_topo_node *topo_node, 509*5597088cSDongdong Hao u64 sas_address, 510*5597088cSDongdong Hao struct leapraid_card_port *card_port) 511*5597088cSDongdong Hao { 512*5597088cSDongdong Hao int i; 513*5597088cSDongdong Hao 514*5597088cSDongdong Hao for (i = 0; i < topo_node->phys_num; i++) { 515*5597088cSDongdong Hao if (topo_node->card_phy[i].remote_identify.sas_address != 516*5597088cSDongdong Hao sas_address || 517*5597088cSDongdong Hao topo_node->card_phy[i].card_port != card_port) 518*5597088cSDongdong Hao continue; 519*5597088cSDongdong Hao if (topo_node->card_phy[i].phy_is_assigned) 520*5597088cSDongdong Hao leapraid_transport_detach_phy_to_port( 521*5597088cSDongdong Hao adapter, 522*5597088cSDongdong Hao topo_node, 523*5597088cSDongdong Hao &topo_node->card_phy[i]); 524*5597088cSDongdong Hao } 525*5597088cSDongdong Hao } 526*5597088cSDongdong Hao 527*5597088cSDongdong Hao static struct leapraid_sas_port *leapraid_prepare_sas_port( 528*5597088cSDongdong Hao struct leapraid_adapter *adapter, 529*5597088cSDongdong Hao u16 handle, u64 sas_address, 530*5597088cSDongdong Hao struct leapraid_card_port *card_port, 531*5597088cSDongdong Hao struct leapraid_topo_node **out_topo_node) 532*5597088cSDongdong Hao { 533*5597088cSDongdong Hao struct leapraid_topo_node *topo_node; 534*5597088cSDongdong Hao struct leapraid_sas_port *sas_port; 535*5597088cSDongdong Hao unsigned long flags; 536*5597088cSDongdong Hao 537*5597088cSDongdong Hao sas_port = kzalloc_obj(*sas_port); 538*5597088cSDongdong Hao if (!sas_port) { 539*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 540*5597088cSDongdong Hao "%s: Failed alloc sas_port\n", __func__); 541*5597088cSDongdong Hao return NULL; 542*5597088cSDongdong Hao } 543*5597088cSDongdong Hao 544*5597088cSDongdong Hao INIT_LIST_HEAD(&sas_port->port_list); 545*5597088cSDongdong Hao INIT_LIST_HEAD(&sas_port->phy_list); 546*5597088cSDongdong Hao 547*5597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags); 548*5597088cSDongdong Hao topo_node = leapraid_transport_topo_node_by_sas_addr(adapter, 549*5597088cSDongdong Hao sas_address, 550*5597088cSDongdong Hao card_port); 551*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags); 552*5597088cSDongdong Hao 553*5597088cSDongdong Hao if (!topo_node) { 554*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 555*5597088cSDongdong Hao "%s: Failed to locate parent for SAS 0x%016llx!\n", 556*5597088cSDongdong Hao __func__, sas_address); 557*5597088cSDongdong Hao goto out_cleanup; 558*5597088cSDongdong Hao } 559*5597088cSDongdong Hao 560*5597088cSDongdong Hao if (leapraid_transport_set_identify(adapter, handle, 561*5597088cSDongdong Hao &sas_port->remote_identify)) 562*5597088cSDongdong Hao goto out_cleanup; 563*5597088cSDongdong Hao 564*5597088cSDongdong Hao if (sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { 565*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 566*5597088cSDongdong Hao "%s: Failed, device type is SAS_PHY_UNUSED\n", 567*5597088cSDongdong Hao __func__); 568*5597088cSDongdong Hao goto out_cleanup; 569*5597088cSDongdong Hao } 570*5597088cSDongdong Hao 571*5597088cSDongdong Hao sas_port->card_port = card_port; 572*5597088cSDongdong Hao *out_topo_node = topo_node; 573*5597088cSDongdong Hao 574*5597088cSDongdong Hao return sas_port; 575*5597088cSDongdong Hao 576*5597088cSDongdong Hao out_cleanup: 577*5597088cSDongdong Hao kfree(sas_port); 578*5597088cSDongdong Hao return NULL; 579*5597088cSDongdong Hao } 580*5597088cSDongdong Hao 581*5597088cSDongdong Hao static int leapraid_bind_phys_and_vphy(struct leapraid_adapter *adapter, 582*5597088cSDongdong Hao struct leapraid_sas_port *sas_port, 583*5597088cSDongdong Hao struct leapraid_topo_node *topo_node, 584*5597088cSDongdong Hao struct leapraid_card_port *card_port, 585*5597088cSDongdong Hao struct leapraid_vphy **out_vphy) 586*5597088cSDongdong Hao { 587*5597088cSDongdong Hao struct leapraid_vphy *vphy = NULL; 588*5597088cSDongdong Hao int i; 589*5597088cSDongdong Hao 590*5597088cSDongdong Hao for (i = 0; i < topo_node->phys_num; i++) { 591*5597088cSDongdong Hao if (topo_node->card_phy[i].remote_identify.sas_address != 592*5597088cSDongdong Hao sas_port->remote_identify.sas_address || 593*5597088cSDongdong Hao topo_node->card_phy[i].card_port != card_port) 594*5597088cSDongdong Hao continue; 595*5597088cSDongdong Hao 596*5597088cSDongdong Hao list_add_tail(&topo_node->card_phy[i].port_siblings, 597*5597088cSDongdong Hao &sas_port->phy_list); 598*5597088cSDongdong Hao sas_port->phys_num++; 599*5597088cSDongdong Hao 600*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num) { 601*5597088cSDongdong Hao if (!topo_node->card_phy[i].vphy) { 602*5597088cSDongdong Hao card_port->phy_mask |= BIT(i); 603*5597088cSDongdong Hao continue; 604*5597088cSDongdong Hao } 605*5597088cSDongdong Hao 606*5597088cSDongdong Hao vphy = leapraid_get_vphy_by_phy(card_port, i); 607*5597088cSDongdong Hao if (!vphy) 608*5597088cSDongdong Hao return LEAPRAID_OPERATION_FAILED; 609*5597088cSDongdong Hao } 610*5597088cSDongdong Hao } 611*5597088cSDongdong Hao 612*5597088cSDongdong Hao *out_vphy = vphy; 613*5597088cSDongdong Hao return sas_port->phys_num ? 0 : LEAPRAID_OPERATION_FAILED; 614*5597088cSDongdong Hao } 615*5597088cSDongdong Hao 616*5597088cSDongdong Hao static struct sas_rphy *leapraid_create_and_register_rphy( 617*5597088cSDongdong Hao struct leapraid_adapter *adapter, 618*5597088cSDongdong Hao struct leapraid_sas_port *sas_port, 619*5597088cSDongdong Hao struct leapraid_topo_node *topo_node, 620*5597088cSDongdong Hao struct leapraid_card_port *card_port, 621*5597088cSDongdong Hao struct leapraid_vphy *vphy) 622*5597088cSDongdong Hao { 623*5597088cSDongdong Hao struct leapraid_sas_dev *sas_dev = NULL; 624*5597088cSDongdong Hao struct leapraid_card_phy *card_phy; 625*5597088cSDongdong Hao struct sas_port *port; 626*5597088cSDongdong Hao struct sas_rphy *rphy; 627*5597088cSDongdong Hao 628*5597088cSDongdong Hao if (sas_port->remote_identify.device_type == SAS_END_DEVICE) { 629*5597088cSDongdong Hao sas_dev = leapraid_get_sas_dev_by_addr( 630*5597088cSDongdong Hao adapter, 631*5597088cSDongdong Hao sas_port->remote_identify.sas_address, 632*5597088cSDongdong Hao card_port); 633*5597088cSDongdong Hao if (!sas_dev) 634*5597088cSDongdong Hao return NULL; 635*5597088cSDongdong Hao sas_dev->pend_sas_rphy_add = 1; 636*5597088cSDongdong Hao } 637*5597088cSDongdong Hao 638*5597088cSDongdong Hao if (!topo_node->parent_dev) { 639*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 640*5597088cSDongdong Hao "%s: topo_node parent device is NULL\n", __func__); 641*5597088cSDongdong Hao goto cleanup_sas_dev; 642*5597088cSDongdong Hao } 643*5597088cSDongdong Hao 644*5597088cSDongdong Hao port = sas_port_alloc_num(topo_node->parent_dev); 645*5597088cSDongdong Hao if (!port) { 646*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 647*5597088cSDongdong Hao "%s: Failed to allocate SAS port\n", __func__); 648*5597088cSDongdong Hao goto cleanup_sas_dev; 649*5597088cSDongdong Hao } 650*5597088cSDongdong Hao 651*5597088cSDongdong Hao if (sas_port_add(port)) { 652*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 653*5597088cSDongdong Hao "%s: Failed to add SAS port\n", __func__); 654*5597088cSDongdong Hao goto out_delete_port; 655*5597088cSDongdong Hao } 656*5597088cSDongdong Hao 657*5597088cSDongdong Hao list_for_each_entry(card_phy, &sas_port->phy_list, port_siblings) { 658*5597088cSDongdong Hao sas_port_add_phy(port, card_phy->phy); 659*5597088cSDongdong Hao card_phy->phy_is_assigned = 1; 660*5597088cSDongdong Hao card_phy->card_port = card_port; 661*5597088cSDongdong Hao } 662*5597088cSDongdong Hao 663*5597088cSDongdong Hao if (sas_dev) { 664*5597088cSDongdong Hao rphy = sas_end_device_alloc(port); 665*5597088cSDongdong Hao sas_dev->rphy = rphy; 666*5597088cSDongdong Hao 667*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num) { 668*5597088cSDongdong Hao if (!vphy) 669*5597088cSDongdong Hao card_port->sas_address = sas_dev->sas_addr; 670*5597088cSDongdong Hao else 671*5597088cSDongdong Hao vphy->sas_address = sas_dev->sas_addr; 672*5597088cSDongdong Hao } 673*5597088cSDongdong Hao } else { 674*5597088cSDongdong Hao rphy = sas_expander_alloc( 675*5597088cSDongdong Hao port, 676*5597088cSDongdong Hao sas_port->remote_identify.device_type); 677*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num) 678*5597088cSDongdong Hao card_port->sas_address = 679*5597088cSDongdong Hao sas_port->remote_identify.sas_address; 680*5597088cSDongdong Hao } 681*5597088cSDongdong Hao 682*5597088cSDongdong Hao if (!rphy) { 683*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 684*5597088cSDongdong Hao "%s: Failed to allocate RPHY\n", __func__); 685*5597088cSDongdong Hao goto cleanup_card_phy; 686*5597088cSDongdong Hao } 687*5597088cSDongdong Hao 688*5597088cSDongdong Hao rphy->identify = sas_port->remote_identify; 689*5597088cSDongdong Hao 690*5597088cSDongdong Hao if (sas_rphy_add(rphy)) { 691*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 692*5597088cSDongdong Hao "%s: Failed to add RPHY\n", __func__); 693*5597088cSDongdong Hao if (sas_dev) 694*5597088cSDongdong Hao sas_dev->rphy = NULL; 695*5597088cSDongdong Hao 696*5597088cSDongdong Hao sas_rphy_free(rphy); 697*5597088cSDongdong Hao goto cleanup_card_phy; 698*5597088cSDongdong Hao } 699*5597088cSDongdong Hao sas_port->port = port; 700*5597088cSDongdong Hao 701*5597088cSDongdong Hao if (sas_dev) { 702*5597088cSDongdong Hao sas_dev->pend_sas_rphy_add = 0; 703*5597088cSDongdong Hao leapraid_sdev_put(sas_dev); 704*5597088cSDongdong Hao } 705*5597088cSDongdong Hao 706*5597088cSDongdong Hao return rphy; 707*5597088cSDongdong Hao 708*5597088cSDongdong Hao cleanup_card_phy: 709*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num) { 710*5597088cSDongdong Hao if (!vphy) 711*5597088cSDongdong Hao card_port->sas_address = 0; 712*5597088cSDongdong Hao else 713*5597088cSDongdong Hao vphy->sas_address = 0; 714*5597088cSDongdong Hao } 715*5597088cSDongdong Hao 716*5597088cSDongdong Hao list_for_each_entry(card_phy, &sas_port->phy_list, port_siblings) { 717*5597088cSDongdong Hao card_phy->phy_is_assigned = 0; 718*5597088cSDongdong Hao card_phy->card_port = NULL; 719*5597088cSDongdong Hao } 720*5597088cSDongdong Hao 721*5597088cSDongdong Hao out_delete_port: 722*5597088cSDongdong Hao sas_port_delete(port); 723*5597088cSDongdong Hao 724*5597088cSDongdong Hao cleanup_sas_dev: 725*5597088cSDongdong Hao if (sas_dev) { 726*5597088cSDongdong Hao sas_dev->pend_sas_rphy_add = 0; 727*5597088cSDongdong Hao leapraid_sdev_put(sas_dev); 728*5597088cSDongdong Hao } 729*5597088cSDongdong Hao return NULL; 730*5597088cSDongdong Hao } 731*5597088cSDongdong Hao 732*5597088cSDongdong Hao struct leapraid_sas_port *leapraid_transport_port_add( 733*5597088cSDongdong Hao struct leapraid_adapter *adapter, 734*5597088cSDongdong Hao u16 hdl, u64 sas_address, 735*5597088cSDongdong Hao struct leapraid_card_port *card_port) 736*5597088cSDongdong Hao { 737*5597088cSDongdong Hao struct leapraid_card_phy *card_phy, *card_phy_next; 738*5597088cSDongdong Hao struct leapraid_topo_node *topo_node = NULL; 739*5597088cSDongdong Hao struct leapraid_sas_port *sas_port; 740*5597088cSDongdong Hao struct leapraid_vphy *vphy = NULL; 741*5597088cSDongdong Hao struct sas_rphy *rphy; 742*5597088cSDongdong Hao unsigned long flags; 743*5597088cSDongdong Hao 744*5597088cSDongdong Hao if (!card_port) { 745*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 746*5597088cSDongdong Hao "%s: Invalid card_port\n", __func__); 747*5597088cSDongdong Hao return NULL; 748*5597088cSDongdong Hao } 749*5597088cSDongdong Hao 750*5597088cSDongdong Hao sas_port = leapraid_prepare_sas_port(adapter, hdl, sas_address, 751*5597088cSDongdong Hao card_port, &topo_node); 752*5597088cSDongdong Hao if (!sas_port) 753*5597088cSDongdong Hao return NULL; 754*5597088cSDongdong Hao 755*5597088cSDongdong Hao leapraid_detach_phy_from_old_port( 756*5597088cSDongdong Hao adapter, 757*5597088cSDongdong Hao topo_node, 758*5597088cSDongdong Hao sas_port->remote_identify.sas_address, 759*5597088cSDongdong Hao card_port); 760*5597088cSDongdong Hao 761*5597088cSDongdong Hao if (leapraid_bind_phys_and_vphy(adapter, sas_port, topo_node, 762*5597088cSDongdong Hao card_port, &vphy)) { 763*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 764*5597088cSDongdong Hao "%s: Failed to bind phy to vphy\n", __func__); 765*5597088cSDongdong Hao goto out_fail; 766*5597088cSDongdong Hao } 767*5597088cSDongdong Hao 768*5597088cSDongdong Hao rphy = leapraid_create_and_register_rphy(adapter, sas_port, topo_node, 769*5597088cSDongdong Hao card_port, vphy); 770*5597088cSDongdong Hao if (!rphy) { 771*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 772*5597088cSDongdong Hao "%s: Failed to create rphy\n", __func__); 773*5597088cSDongdong Hao goto out_fail; 774*5597088cSDongdong Hao } 775*5597088cSDongdong Hao 776*5597088cSDongdong Hao dev_info(&rphy->dev, 777*5597088cSDongdong Hao "%s: Added dev: hdl=0x%04x, SAS addr=0x%016llx\n", 778*5597088cSDongdong Hao __func__, hdl, 779*5597088cSDongdong Hao (unsigned long long)sas_port->remote_identify.sas_address); 780*5597088cSDongdong Hao 781*5597088cSDongdong Hao sas_port->rphy = rphy; 782*5597088cSDongdong Hao 783*5597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags); 784*5597088cSDongdong Hao list_add_tail(&sas_port->port_list, &topo_node->sas_port_list); 785*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags); 786*5597088cSDongdong Hao 787*5597088cSDongdong Hao if (sas_port->remote_identify.device_type == 788*5597088cSDongdong Hao SAS_EDGE_EXPANDER_DEVICE || 789*5597088cSDongdong Hao sas_port->remote_identify.device_type == 790*5597088cSDongdong Hao SAS_FANOUT_EXPANDER_DEVICE) 791*5597088cSDongdong Hao leapraid_transport_exp_report_manu( 792*5597088cSDongdong Hao adapter, 793*5597088cSDongdong Hao sas_port->remote_identify.sas_address, 794*5597088cSDongdong Hao rphy_to_expander_device(rphy), 795*5597088cSDongdong Hao card_port->port_id); 796*5597088cSDongdong Hao 797*5597088cSDongdong Hao return sas_port; 798*5597088cSDongdong Hao 799*5597088cSDongdong Hao out_fail: 800*5597088cSDongdong Hao list_for_each_entry_safe(card_phy, card_phy_next, 801*5597088cSDongdong Hao &sas_port->phy_list, port_siblings) { 802*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num && 803*5597088cSDongdong Hao !card_phy->vphy) 804*5597088cSDongdong Hao card_port->phy_mask &= ~BIT(card_phy->phy_id); 805*5597088cSDongdong Hao 806*5597088cSDongdong Hao list_del_init(&card_phy->port_siblings); 807*5597088cSDongdong Hao } 808*5597088cSDongdong Hao 809*5597088cSDongdong Hao kfree(sas_port); 810*5597088cSDongdong Hao return NULL; 811*5597088cSDongdong Hao } 812*5597088cSDongdong Hao 813*5597088cSDongdong Hao static struct leapraid_sas_port *leapraid_find_and_remove_sas_port( 814*5597088cSDongdong Hao struct leapraid_topo_node *topo_node, 815*5597088cSDongdong Hao u64 sas_address, 816*5597088cSDongdong Hao struct leapraid_card_port *remove_card_port, 817*5597088cSDongdong Hao bool *found) 818*5597088cSDongdong Hao { 819*5597088cSDongdong Hao struct leapraid_sas_port *sas_port, *sas_port_next; 820*5597088cSDongdong Hao 821*5597088cSDongdong Hao list_for_each_entry_safe(sas_port, sas_port_next, 822*5597088cSDongdong Hao &topo_node->sas_port_list, port_list) { 823*5597088cSDongdong Hao if (sas_port->remote_identify.sas_address != sas_address) 824*5597088cSDongdong Hao continue; 825*5597088cSDongdong Hao 826*5597088cSDongdong Hao if (sas_port->card_port != remove_card_port) 827*5597088cSDongdong Hao continue; 828*5597088cSDongdong Hao 829*5597088cSDongdong Hao *found = true; 830*5597088cSDongdong Hao list_del(&sas_port->port_list); 831*5597088cSDongdong Hao return sas_port; 832*5597088cSDongdong Hao } 833*5597088cSDongdong Hao return NULL; 834*5597088cSDongdong Hao } 835*5597088cSDongdong Hao 836*5597088cSDongdong Hao static void leapraid_cleanup_card_port_and_vphys( 837*5597088cSDongdong Hao struct leapraid_adapter *adapter, 838*5597088cSDongdong Hao u64 sas_address, 839*5597088cSDongdong Hao struct leapraid_card_port *remove_card_port) 840*5597088cSDongdong Hao { 841*5597088cSDongdong Hao struct leapraid_card_port *card_port, *card_port_next; 842*5597088cSDongdong Hao struct leapraid_vphy *vphy, *vphy_next; 843*5597088cSDongdong Hao 844*5597088cSDongdong Hao if (remove_card_port->vphys_mask) { 845*5597088cSDongdong Hao list_for_each_entry_safe(vphy, vphy_next, 846*5597088cSDongdong Hao &remove_card_port->vphys_list, list) { 847*5597088cSDongdong Hao if (vphy->sas_address != sas_address) 848*5597088cSDongdong Hao continue; 849*5597088cSDongdong Hao 850*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 851*5597088cSDongdong Hao "%s: Remove vphy=%p from port=%p port_id=%d\n", 852*5597088cSDongdong Hao __func__, vphy, remove_card_port, 853*5597088cSDongdong Hao remove_card_port->port_id); 854*5597088cSDongdong Hao 855*5597088cSDongdong Hao remove_card_port->vphys_mask &= ~vphy->phy_mask; 856*5597088cSDongdong Hao list_del(&vphy->list); 857*5597088cSDongdong Hao kfree(vphy); 858*5597088cSDongdong Hao } 859*5597088cSDongdong Hao 860*5597088cSDongdong Hao if (!remove_card_port->vphys_mask && 861*5597088cSDongdong Hao !remove_card_port->sas_address) { 862*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 863*5597088cSDongdong Hao "%s: Remove empty hba_port: %p, port_id=%d\n", 864*5597088cSDongdong Hao __func__, 865*5597088cSDongdong Hao remove_card_port, 866*5597088cSDongdong Hao remove_card_port->port_id); 867*5597088cSDongdong Hao list_del(&remove_card_port->list); 868*5597088cSDongdong Hao kfree(remove_card_port); 869*5597088cSDongdong Hao remove_card_port = NULL; 870*5597088cSDongdong Hao } 871*5597088cSDongdong Hao } 872*5597088cSDongdong Hao 873*5597088cSDongdong Hao list_for_each_entry_safe(card_port, card_port_next, 874*5597088cSDongdong Hao &adapter->dev_topo.card_port_list, list) { 875*5597088cSDongdong Hao if (card_port != remove_card_port) 876*5597088cSDongdong Hao continue; 877*5597088cSDongdong Hao 878*5597088cSDongdong Hao if (card_port->sas_address != sas_address) 879*5597088cSDongdong Hao continue; 880*5597088cSDongdong Hao 881*5597088cSDongdong Hao if (!remove_card_port->vphys_mask) { 882*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 883*5597088cSDongdong Hao "%s: Remove hba_port: %p, port_id=%d\n", 884*5597088cSDongdong Hao __func__, card_port, card_port->port_id); 885*5597088cSDongdong Hao list_del(&card_port->list); 886*5597088cSDongdong Hao kfree(card_port); 887*5597088cSDongdong Hao } else { 888*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 889*5597088cSDongdong Hao "Clear sas_address of port=%p, port_id=%d\n", 890*5597088cSDongdong Hao card_port, card_port->port_id); 891*5597088cSDongdong Hao remove_card_port->sas_address = 0; 892*5597088cSDongdong Hao } 893*5597088cSDongdong Hao break; 894*5597088cSDongdong Hao } 895*5597088cSDongdong Hao } 896*5597088cSDongdong Hao 897*5597088cSDongdong Hao static void leapraid_clear_topo_node_phys(struct leapraid_topo_node *topo_node, 898*5597088cSDongdong Hao u64 sas_address) 899*5597088cSDongdong Hao { 900*5597088cSDongdong Hao int i; 901*5597088cSDongdong Hao 902*5597088cSDongdong Hao for (i = 0; i < topo_node->phys_num; i++) 903*5597088cSDongdong Hao if (topo_node->card_phy[i].remote_identify.sas_address == 904*5597088cSDongdong Hao sas_address) { 905*5597088cSDongdong Hao memset(&topo_node->card_phy[i].remote_identify, 0, 906*5597088cSDongdong Hao sizeof(struct sas_identify)); 907*5597088cSDongdong Hao topo_node->card_phy[i].vphy = 0; 908*5597088cSDongdong Hao } 909*5597088cSDongdong Hao } 910*5597088cSDongdong Hao 911*5597088cSDongdong Hao void leapraid_transport_port_remove( 912*5597088cSDongdong Hao struct leapraid_adapter *adapter, 913*5597088cSDongdong Hao u64 sas_address, 914*5597088cSDongdong Hao u64 sas_address_parent, 915*5597088cSDongdong Hao struct leapraid_card_port *remove_card_port) 916*5597088cSDongdong Hao { 917*5597088cSDongdong Hao struct leapraid_card_phy *card_phy, *card_phy_next; 918*5597088cSDongdong Hao struct leapraid_sas_port *sas_port; 919*5597088cSDongdong Hao struct leapraid_topo_node *topo_node; 920*5597088cSDongdong Hao unsigned long flags; 921*5597088cSDongdong Hao bool found = false; 922*5597088cSDongdong Hao 923*5597088cSDongdong Hao if (!remove_card_port) 924*5597088cSDongdong Hao return; 925*5597088cSDongdong Hao 926*5597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags); 927*5597088cSDongdong Hao 928*5597088cSDongdong Hao topo_node = leapraid_transport_topo_node_by_sas_addr(adapter, 929*5597088cSDongdong Hao sas_address_parent, 930*5597088cSDongdong Hao remove_card_port); 931*5597088cSDongdong Hao if (!topo_node) { 932*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, 933*5597088cSDongdong Hao flags); 934*5597088cSDongdong Hao return; 935*5597088cSDongdong Hao } 936*5597088cSDongdong Hao 937*5597088cSDongdong Hao sas_port = leapraid_find_and_remove_sas_port(topo_node, sas_address, 938*5597088cSDongdong Hao remove_card_port, &found); 939*5597088cSDongdong Hao 940*5597088cSDongdong Hao if (!found) { 941*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, 942*5597088cSDongdong Hao flags); 943*5597088cSDongdong Hao return; 944*5597088cSDongdong Hao } 945*5597088cSDongdong Hao 946*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num && 947*5597088cSDongdong Hao adapter->adapter_attr.enable_mp) 948*5597088cSDongdong Hao leapraid_cleanup_card_port_and_vphys(adapter, sas_address, 949*5597088cSDongdong Hao remove_card_port); 950*5597088cSDongdong Hao 951*5597088cSDongdong Hao leapraid_clear_topo_node_phys(topo_node, sas_address); 952*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags); 953*5597088cSDongdong Hao 954*5597088cSDongdong Hao list_for_each_entry_safe(card_phy, card_phy_next, 955*5597088cSDongdong Hao &sas_port->phy_list, port_siblings) { 956*5597088cSDongdong Hao card_phy->phy_is_assigned = 0; 957*5597088cSDongdong Hao if (!adapter->access_ctrl.host_removing) 958*5597088cSDongdong Hao sas_port_delete_phy(sas_port->port, card_phy->phy); 959*5597088cSDongdong Hao 960*5597088cSDongdong Hao list_del(&card_phy->port_siblings); 961*5597088cSDongdong Hao } 962*5597088cSDongdong Hao 963*5597088cSDongdong Hao if (!adapter->access_ctrl.host_removing) 964*5597088cSDongdong Hao sas_port_delete(sas_port->port); 965*5597088cSDongdong Hao 966*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 967*5597088cSDongdong Hao "%s: Removed sas_port for SAS addr=0x%016llx\n", 968*5597088cSDongdong Hao __func__, (unsigned long long)sas_address); 969*5597088cSDongdong Hao 970*5597088cSDongdong Hao kfree(sas_port); 971*5597088cSDongdong Hao } 972*5597088cSDongdong Hao 973*5597088cSDongdong Hao static void leapraid_init_sas_or_exp_phy(struct leapraid_adapter *adapter, 974*5597088cSDongdong Hao struct leapraid_card_phy *card_phy, 975*5597088cSDongdong Hao struct sas_phy *phy, 976*5597088cSDongdong Hao struct leapraid_sas_phy_p0 *phy_pg0, 977*5597088cSDongdong Hao struct leapraid_exp_p1 *exp_pg1) 978*5597088cSDongdong Hao { 979*5597088cSDongdong Hao if (exp_pg1 && phy_pg0) 980*5597088cSDongdong Hao return; 981*5597088cSDongdong Hao 982*5597088cSDongdong Hao if (!exp_pg1 && !phy_pg0) 983*5597088cSDongdong Hao return; 984*5597088cSDongdong Hao 985*5597088cSDongdong Hao phy->identify = card_phy->identify; 986*5597088cSDongdong Hao phy->identify.phy_identifier = card_phy->phy_id; 987*5597088cSDongdong Hao phy->negotiated_linkrate = phy_pg0 ? 988*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 989*5597088cSDongdong Hao phy_pg0->neg_link_rate & 990*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_MASK_PHYSICAL) : 991*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 992*5597088cSDongdong Hao exp_pg1->neg_link_rate & 993*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_MASK_PHYSICAL); 994*5597088cSDongdong Hao phy->minimum_linkrate_hw = phy_pg0 ? 995*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 996*5597088cSDongdong Hao phy_pg0->hw_link_rate & 997*5597088cSDongdong Hao LEAPRAID_SAS_HWRATE_MIN_RATE_MASK) : 998*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 999*5597088cSDongdong Hao exp_pg1->hw_link_rate & 1000*5597088cSDongdong Hao LEAPRAID_SAS_HWRATE_MIN_RATE_MASK); 1001*5597088cSDongdong Hao phy->maximum_linkrate_hw = phy_pg0 ? 1002*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 1003*5597088cSDongdong Hao phy_pg0->hw_link_rate >> 1004*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT) : 1005*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 1006*5597088cSDongdong Hao exp_pg1->hw_link_rate >> 1007*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT); 1008*5597088cSDongdong Hao phy->minimum_linkrate = phy_pg0 ? 1009*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 1010*5597088cSDongdong Hao phy_pg0->p_link_rate & 1011*5597088cSDongdong Hao LEAPRAID_SAS_PRATE_MIN_RATE_MASK) : 1012*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 1013*5597088cSDongdong Hao exp_pg1->p_link_rate & 1014*5597088cSDongdong Hao LEAPRAID_SAS_PRATE_MIN_RATE_MASK); 1015*5597088cSDongdong Hao phy->maximum_linkrate = phy_pg0 ? 1016*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 1017*5597088cSDongdong Hao phy_pg0->p_link_rate >> 1018*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT) : 1019*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate( 1020*5597088cSDongdong Hao exp_pg1->p_link_rate >> 1021*5597088cSDongdong Hao LEAPRAID_SAS_NEG_LINK_RATE_SHIFT); 1022*5597088cSDongdong Hao phy->hostdata = card_phy->card_port; 1023*5597088cSDongdong Hao } 1024*5597088cSDongdong Hao 1025*5597088cSDongdong Hao void leapraid_transport_add_card_phy(struct leapraid_adapter *adapter, 1026*5597088cSDongdong Hao struct leapraid_card_phy *card_phy, 1027*5597088cSDongdong Hao struct leapraid_sas_phy_p0 *phy_pg0, 1028*5597088cSDongdong Hao struct device *parent_dev) 1029*5597088cSDongdong Hao { 1030*5597088cSDongdong Hao struct sas_phy *phy; 1031*5597088cSDongdong Hao int ret; 1032*5597088cSDongdong Hao 1033*5597088cSDongdong Hao INIT_LIST_HEAD(&card_phy->port_siblings); 1034*5597088cSDongdong Hao phy = sas_phy_alloc(parent_dev, card_phy->phy_id); 1035*5597088cSDongdong Hao if (!phy) { 1036*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1037*5597088cSDongdong Hao "%s: sas_phy_alloc failed!\n", __func__); 1038*5597088cSDongdong Hao return; 1039*5597088cSDongdong Hao } 1040*5597088cSDongdong Hao 1041*5597088cSDongdong Hao if (leapraid_transport_set_identify(adapter, card_phy->hdl, 1042*5597088cSDongdong Hao &card_phy->identify)) { 1043*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1044*5597088cSDongdong Hao "%s: Set PHY handle identify failed!\n", __func__); 1045*5597088cSDongdong Hao sas_phy_free(phy); 1046*5597088cSDongdong Hao return; 1047*5597088cSDongdong Hao } 1048*5597088cSDongdong Hao 1049*5597088cSDongdong Hao card_phy->attached_hdl = le16_to_cpu(phy_pg0->attached_dev_hdl); 1050*5597088cSDongdong Hao if (card_phy->attached_hdl) { 1051*5597088cSDongdong Hao ret = leapraid_transport_set_identify( 1052*5597088cSDongdong Hao adapter, 1053*5597088cSDongdong Hao card_phy->attached_hdl, 1054*5597088cSDongdong Hao &card_phy->remote_identify); 1055*5597088cSDongdong Hao if (ret) { 1056*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1057*5597088cSDongdong Hao "%s: Set PHY attached hdl identify failed!\n", 1058*5597088cSDongdong Hao __func__); 1059*5597088cSDongdong Hao sas_phy_free(phy); 1060*5597088cSDongdong Hao return; 1061*5597088cSDongdong Hao } 1062*5597088cSDongdong Hao } 1063*5597088cSDongdong Hao 1064*5597088cSDongdong Hao leapraid_init_sas_or_exp_phy(adapter, card_phy, phy, phy_pg0, NULL); 1065*5597088cSDongdong Hao 1066*5597088cSDongdong Hao if (sas_phy_add(phy)) { 1067*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1068*5597088cSDongdong Hao "%s: SAS PHY add failed!\n", __func__); 1069*5597088cSDongdong Hao sas_phy_free(phy); 1070*5597088cSDongdong Hao return; 1071*5597088cSDongdong Hao } 1072*5597088cSDongdong Hao 1073*5597088cSDongdong Hao card_phy->phy = phy; 1074*5597088cSDongdong Hao } 1075*5597088cSDongdong Hao 1076*5597088cSDongdong Hao int leapraid_transport_add_exp_phy(struct leapraid_adapter *adapter, 1077*5597088cSDongdong Hao struct leapraid_card_phy *card_phy, 1078*5597088cSDongdong Hao struct leapraid_exp_p1 *exp_pg1, 1079*5597088cSDongdong Hao struct device *parent_dev) 1080*5597088cSDongdong Hao { 1081*5597088cSDongdong Hao struct sas_phy *phy; 1082*5597088cSDongdong Hao int ret; 1083*5597088cSDongdong Hao 1084*5597088cSDongdong Hao INIT_LIST_HEAD(&card_phy->port_siblings); 1085*5597088cSDongdong Hao phy = sas_phy_alloc(parent_dev, card_phy->phy_id); 1086*5597088cSDongdong Hao if (!phy) { 1087*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1088*5597088cSDongdong Hao "%s: sas_phy_alloc failed!\n", __func__); 1089*5597088cSDongdong Hao return -EFAULT; 1090*5597088cSDongdong Hao } 1091*5597088cSDongdong Hao 1092*5597088cSDongdong Hao if (leapraid_transport_set_identify(adapter, card_phy->hdl, 1093*5597088cSDongdong Hao &card_phy->identify)) { 1094*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1095*5597088cSDongdong Hao "%s: Set PHY hdl identify failed!\n", __func__); 1096*5597088cSDongdong Hao sas_phy_free(phy); 1097*5597088cSDongdong Hao return -EFAULT; 1098*5597088cSDongdong Hao } 1099*5597088cSDongdong Hao 1100*5597088cSDongdong Hao card_phy->attached_hdl = le16_to_cpu(exp_pg1->attached_dev_hdl); 1101*5597088cSDongdong Hao if (card_phy->attached_hdl) { 1102*5597088cSDongdong Hao ret = leapraid_transport_set_identify( 1103*5597088cSDongdong Hao adapter, 1104*5597088cSDongdong Hao card_phy->attached_hdl, 1105*5597088cSDongdong Hao &card_phy->remote_identify); 1106*5597088cSDongdong Hao if (ret) 1107*5597088cSDongdong Hao dev_warn(&adapter->pdev->dev, 1108*5597088cSDongdong Hao "%s: Set PHY attached hdl identify failed!\n", 1109*5597088cSDongdong Hao __func__); 1110*5597088cSDongdong Hao } 1111*5597088cSDongdong Hao 1112*5597088cSDongdong Hao leapraid_init_sas_or_exp_phy(adapter, card_phy, phy, NULL, exp_pg1); 1113*5597088cSDongdong Hao 1114*5597088cSDongdong Hao if (sas_phy_add(phy)) { 1115*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1116*5597088cSDongdong Hao "%s: SAS PHY add failed!\n", __func__); 1117*5597088cSDongdong Hao sas_phy_free(phy); 1118*5597088cSDongdong Hao return -EFAULT; 1119*5597088cSDongdong Hao } 1120*5597088cSDongdong Hao 1121*5597088cSDongdong Hao card_phy->phy = phy; 1122*5597088cSDongdong Hao return 0; 1123*5597088cSDongdong Hao } 1124*5597088cSDongdong Hao 1125*5597088cSDongdong Hao void leapraid_transport_update_links( 1126*5597088cSDongdong Hao struct leapraid_adapter *adapter, 1127*5597088cSDongdong Hao u64 sas_address, u16 hdl, u8 phy_index, 1128*5597088cSDongdong Hao u8 link_rate, struct leapraid_card_port *target_card_port) 1129*5597088cSDongdong Hao { 1130*5597088cSDongdong Hao struct leapraid_topo_node *topo_node; 1131*5597088cSDongdong Hao struct leapraid_card_phy *card_phy; 1132*5597088cSDongdong Hao struct leapraid_card_port *card_port; 1133*5597088cSDongdong Hao unsigned long flags; 1134*5597088cSDongdong Hao 1135*5597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering || 1136*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) 1137*5597088cSDongdong Hao return; 1138*5597088cSDongdong Hao 1139*5597088cSDongdong Hao spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags); 1140*5597088cSDongdong Hao topo_node = leapraid_transport_topo_node_by_sas_addr(adapter, 1141*5597088cSDongdong Hao sas_address, 1142*5597088cSDongdong Hao target_card_port); 1143*5597088cSDongdong Hao if (!topo_node) { 1144*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, 1145*5597088cSDongdong Hao flags); 1146*5597088cSDongdong Hao return; 1147*5597088cSDongdong Hao } 1148*5597088cSDongdong Hao 1149*5597088cSDongdong Hao card_phy = &topo_node->card_phy[phy_index]; 1150*5597088cSDongdong Hao card_phy->attached_hdl = hdl; 1151*5597088cSDongdong Hao spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags); 1152*5597088cSDongdong Hao 1153*5597088cSDongdong Hao if (hdl && link_rate >= LEAPRAID_SAS_NEG_LINK_RATE_1_5) { 1154*5597088cSDongdong Hao leapraid_transport_set_identify(adapter, hdl, 1155*5597088cSDongdong Hao &card_phy->remote_identify); 1156*5597088cSDongdong Hao if (topo_node->hdl <= adapter->dev_topo.card.phys_num && 1157*5597088cSDongdong Hao adapter->adapter_attr.enable_mp) { 1158*5597088cSDongdong Hao list_for_each_entry(card_port, 1159*5597088cSDongdong Hao &adapter->dev_topo.card_port_list, 1160*5597088cSDongdong Hao list) { 1161*5597088cSDongdong Hao if (card_port->sas_address == sas_address && 1162*5597088cSDongdong Hao card_port == target_card_port) 1163*5597088cSDongdong Hao card_port->phy_mask |= 1164*5597088cSDongdong Hao BIT(card_phy->phy_id); 1165*5597088cSDongdong Hao } 1166*5597088cSDongdong Hao } 1167*5597088cSDongdong Hao leapraid_transport_attach_phy_to_port( 1168*5597088cSDongdong Hao adapter, 1169*5597088cSDongdong Hao topo_node, 1170*5597088cSDongdong Hao card_phy, 1171*5597088cSDongdong Hao card_phy->remote_identify.sas_address, 1172*5597088cSDongdong Hao target_card_port); 1173*5597088cSDongdong Hao } else { 1174*5597088cSDongdong Hao memset(&card_phy->remote_identify, 0, 1175*5597088cSDongdong Hao sizeof(struct sas_identify)); 1176*5597088cSDongdong Hao } 1177*5597088cSDongdong Hao 1178*5597088cSDongdong Hao if (card_phy->phy) 1179*5597088cSDongdong Hao card_phy->phy->negotiated_linkrate = 1180*5597088cSDongdong Hao leapraid_transport_convert_phy_link_rate(link_rate); 1181*5597088cSDongdong Hao } 1182*5597088cSDongdong Hao 1183*5597088cSDongdong Hao static int leapraid_dma_map_buffer(struct device *dev, struct bsg_buffer *buf, 1184*5597088cSDongdong Hao dma_addr_t *dma_addr, 1185*5597088cSDongdong Hao size_t *dma_len, void **p) 1186*5597088cSDongdong Hao { 1187*5597088cSDongdong Hao if (buf->sg_cnt > 1) { 1188*5597088cSDongdong Hao *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr, 1189*5597088cSDongdong Hao GFP_KERNEL); 1190*5597088cSDongdong Hao if (!*p) 1191*5597088cSDongdong Hao return -ENOMEM; 1192*5597088cSDongdong Hao 1193*5597088cSDongdong Hao *dma_len = buf->payload_len; 1194*5597088cSDongdong Hao } else { 1195*5597088cSDongdong Hao if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL)) { 1196*5597088cSDongdong Hao dev_err(dev, 1197*5597088cSDongdong Hao "%s: Failed to map sg buffer for dma\n", 1198*5597088cSDongdong Hao __func__); 1199*5597088cSDongdong Hao return -ENOMEM; 1200*5597088cSDongdong Hao } 1201*5597088cSDongdong Hao 1202*5597088cSDongdong Hao *dma_addr = sg_dma_address(buf->sg_list); 1203*5597088cSDongdong Hao *dma_len = sg_dma_len(buf->sg_list); 1204*5597088cSDongdong Hao *p = NULL; 1205*5597088cSDongdong Hao } 1206*5597088cSDongdong Hao return 0; 1207*5597088cSDongdong Hao } 1208*5597088cSDongdong Hao 1209*5597088cSDongdong Hao static void leapraid_dma_unmap_buffer(struct device *dev, 1210*5597088cSDongdong Hao struct bsg_buffer *buf, 1211*5597088cSDongdong Hao dma_addr_t dma_addr, 1212*5597088cSDongdong Hao void *p) 1213*5597088cSDongdong Hao { 1214*5597088cSDongdong Hao if (p) 1215*5597088cSDongdong Hao dma_free_coherent(dev, buf->payload_len, p, dma_addr); 1216*5597088cSDongdong Hao else 1217*5597088cSDongdong Hao dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL); 1218*5597088cSDongdong Hao } 1219*5597088cSDongdong Hao 1220*5597088cSDongdong Hao static void leapraid_build_smp_task(struct leapraid_adapter *adapter, 1221*5597088cSDongdong Hao struct sas_rphy *rphy, 1222*5597088cSDongdong Hao dma_addr_t h2c_dma_addr, size_t h2c_size, 1223*5597088cSDongdong Hao dma_addr_t c2h_dma_addr, size_t c2h_size) 1224*5597088cSDongdong Hao { 1225*5597088cSDongdong Hao struct leapraid_smp_passthrough_req *smp_passthrough_req; 1226*5597088cSDongdong Hao u16 inter_taskid; 1227*5597088cSDongdong Hao void *psge; 1228*5597088cSDongdong Hao 1229*5597088cSDongdong Hao inter_taskid = adapter->driver_cmds.transport_cmd.inter_taskid; 1230*5597088cSDongdong Hao smp_passthrough_req = leapraid_get_task_desc(adapter, inter_taskid); 1231*5597088cSDongdong Hao memset(smp_passthrough_req, 0, sizeof(*smp_passthrough_req)); 1232*5597088cSDongdong Hao 1233*5597088cSDongdong Hao smp_passthrough_req->func = LEAPRAID_FUNC_SMP_PASSTHROUGH; 1234*5597088cSDongdong Hao smp_passthrough_req->physical_port = 1235*5597088cSDongdong Hao leapraid_transport_get_port_id_by_rphy(adapter, rphy); 1236*5597088cSDongdong Hao smp_passthrough_req->sas_address = (rphy) ? 1237*5597088cSDongdong Hao cpu_to_le64(rphy->identify.sas_address) : 1238*5597088cSDongdong Hao cpu_to_le64(adapter->dev_topo.card.sas_address); 1239*5597088cSDongdong Hao smp_passthrough_req->req_data_len = 1240*5597088cSDongdong Hao cpu_to_le16(h2c_size - LEAPRAID_SMP_FRAME_HEADER_SIZE); 1241*5597088cSDongdong Hao psge = &smp_passthrough_req->sgl; 1242*5597088cSDongdong Hao leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, 1243*5597088cSDongdong Hao h2c_size - LEAPRAID_SMP_FRAME_HEADER_SIZE, 1244*5597088cSDongdong Hao c2h_dma_addr, 1245*5597088cSDongdong Hao c2h_size - LEAPRAID_SMP_FRAME_HEADER_SIZE); 1246*5597088cSDongdong Hao } 1247*5597088cSDongdong Hao 1248*5597088cSDongdong Hao static int leapraid_send_smp_req(struct leapraid_adapter *adapter) 1249*5597088cSDongdong Hao { 1250*5597088cSDongdong Hao const struct leapraid_smp_passthrough_req *smp_passthrough_req; 1251*5597088cSDongdong Hao u16 inter_taskid; 1252*5597088cSDongdong Hao 1253*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 1254*5597088cSDongdong Hao "%s: Sending smp request\n", __func__); 1255*5597088cSDongdong Hao inter_taskid = adapter->driver_cmds.transport_cmd.inter_taskid; 1256*5597088cSDongdong Hao smp_passthrough_req = leapraid_get_task_desc(adapter, inter_taskid); 1257*5597088cSDongdong Hao init_completion(&adapter->driver_cmds.transport_cmd.done); 1258*5597088cSDongdong Hao leapraid_fire_task(adapter, inter_taskid); 1259*5597088cSDongdong Hao wait_for_completion_timeout(&adapter->driver_cmds.transport_cmd.done, 1260*5597088cSDongdong Hao LEAPRAID_TRANSPORT_CMD_TIMEOUT * HZ); 1261*5597088cSDongdong Hao if (!(adapter->driver_cmds.transport_cmd.status & LEAPRAID_CMD_DONE)) { 1262*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, "%s: timeout, st=0x%x\n", 1263*5597088cSDongdong Hao __func__, adapter->driver_cmds.transport_cmd.status); 1264*5597088cSDongdong Hao leapraid_log_req_context(adapter, inter_taskid, 1265*5597088cSDongdong Hao smp_passthrough_req); 1266*5597088cSDongdong Hao if (!(adapter->driver_cmds.transport_cmd.status & 1267*5597088cSDongdong Hao LEAPRAID_CMD_RESET)) { 1268*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, 1269*5597088cSDongdong Hao "%s:%d: call hard_reset\n", 1270*5597088cSDongdong Hao __func__, __LINE__); 1271*5597088cSDongdong Hao leapraid_hard_reset_handler(adapter, FULL_RESET); 1272*5597088cSDongdong Hao return -ETIMEDOUT; 1273*5597088cSDongdong Hao } 1274*5597088cSDongdong Hao } 1275*5597088cSDongdong Hao 1276*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, "%s: SMP request complete\n", __func__); 1277*5597088cSDongdong Hao if (!(adapter->driver_cmds.transport_cmd.status & 1278*5597088cSDongdong Hao LEAPRAID_CMD_REPLY_VALID)) { 1279*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1280*5597088cSDongdong Hao "%s: SMP request no reply\n", __func__); 1281*5597088cSDongdong Hao return -ENXIO; 1282*5597088cSDongdong Hao } 1283*5597088cSDongdong Hao 1284*5597088cSDongdong Hao return 0; 1285*5597088cSDongdong Hao } 1286*5597088cSDongdong Hao 1287*5597088cSDongdong Hao static void leapraid_handle_smp_rep(struct leapraid_adapter *adapter, 1288*5597088cSDongdong Hao struct bsg_job *job, void *addr_in, 1289*5597088cSDongdong Hao unsigned int *reslen) 1290*5597088cSDongdong Hao { 1291*5597088cSDongdong Hao struct leapraid_smp_passthrough_rep *smp_passthrough_rep; 1292*5597088cSDongdong Hao 1293*5597088cSDongdong Hao smp_passthrough_rep = 1294*5597088cSDongdong Hao (void *)&adapter->driver_cmds.transport_cmd.reply; 1295*5597088cSDongdong Hao 1296*5597088cSDongdong Hao dev_dbg(&adapter->pdev->dev, "%s: Response data len=%d\n", 1297*5597088cSDongdong Hao __func__, le16_to_cpu(smp_passthrough_rep->resp_data_len)); 1298*5597088cSDongdong Hao 1299*5597088cSDongdong Hao memcpy(job->reply, smp_passthrough_rep, sizeof(*smp_passthrough_rep)); 1300*5597088cSDongdong Hao job->reply_len = sizeof(*smp_passthrough_rep); 1301*5597088cSDongdong Hao *reslen = le16_to_cpu(smp_passthrough_rep->resp_data_len); 1302*5597088cSDongdong Hao 1303*5597088cSDongdong Hao if (addr_in) 1304*5597088cSDongdong Hao sg_copy_from_buffer(job->reply_payload.sg_list, 1305*5597088cSDongdong Hao job->reply_payload.sg_cnt, addr_in, 1306*5597088cSDongdong Hao job->reply_payload.payload_len); 1307*5597088cSDongdong Hao } 1308*5597088cSDongdong Hao 1309*5597088cSDongdong Hao static void leapraid_transport_smp_handler(struct bsg_job *job, 1310*5597088cSDongdong Hao struct Scsi_Host *shost, 1311*5597088cSDongdong Hao struct sas_rphy *rphy) 1312*5597088cSDongdong Hao { 1313*5597088cSDongdong Hao struct leapraid_adapter *adapter = shost_priv(shost); 1314*5597088cSDongdong Hao dma_addr_t c2h_dma_addr; 1315*5597088cSDongdong Hao dma_addr_t h2c_dma_addr; 1316*5597088cSDongdong Hao void *addr_in = NULL; 1317*5597088cSDongdong Hao void *addr_out = NULL; 1318*5597088cSDongdong Hao size_t c2h_size; 1319*5597088cSDongdong Hao size_t h2c_size; 1320*5597088cSDongdong Hao int rc; 1321*5597088cSDongdong Hao unsigned int reslen = 0; 1322*5597088cSDongdong Hao 1323*5597088cSDongdong Hao if (adapter->access_ctrl.shost_recovering || 1324*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering) { 1325*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1326*5597088cSDongdong Hao "%s: Failed, shost_recovering=%d pcie_recovering=%d\n", 1327*5597088cSDongdong Hao __func__, 1328*5597088cSDongdong Hao adapter->access_ctrl.shost_recovering, 1329*5597088cSDongdong Hao adapter->access_ctrl.pcie_recovering); 1330*5597088cSDongdong Hao rc = -EFAULT; 1331*5597088cSDongdong Hao goto exit_bsg_job; 1332*5597088cSDongdong Hao } 1333*5597088cSDongdong Hao 1334*5597088cSDongdong Hao rc = mutex_lock_interruptible(&adapter->driver_cmds 1335*5597088cSDongdong Hao .transport_cmd.mutex); 1336*5597088cSDongdong Hao if (rc) 1337*5597088cSDongdong Hao goto exit_bsg_job; 1338*5597088cSDongdong Hao 1339*5597088cSDongdong Hao adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_PENDING; 1340*5597088cSDongdong Hao rc = leapraid_dma_map_buffer(&adapter->pdev->dev, 1341*5597088cSDongdong Hao &job->request_payload, 1342*5597088cSDongdong Hao &h2c_dma_addr, &h2c_size, &addr_out); 1343*5597088cSDongdong Hao if (rc) 1344*5597088cSDongdong Hao goto release_lock; 1345*5597088cSDongdong Hao 1346*5597088cSDongdong Hao if (h2c_size < LEAPRAID_SMP_FRAME_HEADER_SIZE) { 1347*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1348*5597088cSDongdong Hao "%s: Invalid SMP request payload size=%zu\n", 1349*5597088cSDongdong Hao __func__, h2c_size); 1350*5597088cSDongdong Hao rc = -EINVAL; 1351*5597088cSDongdong Hao goto free_req_buf; 1352*5597088cSDongdong Hao } 1353*5597088cSDongdong Hao 1354*5597088cSDongdong Hao if (addr_out) 1355*5597088cSDongdong Hao sg_copy_to_buffer(job->request_payload.sg_list, 1356*5597088cSDongdong Hao job->request_payload.sg_cnt, addr_out, 1357*5597088cSDongdong Hao job->request_payload.payload_len); 1358*5597088cSDongdong Hao 1359*5597088cSDongdong Hao rc = leapraid_dma_map_buffer(&adapter->pdev->dev, &job->reply_payload, 1360*5597088cSDongdong Hao &c2h_dma_addr, &c2h_size, &addr_in); 1361*5597088cSDongdong Hao if (rc) 1362*5597088cSDongdong Hao goto free_req_buf; 1363*5597088cSDongdong Hao 1364*5597088cSDongdong Hao if (c2h_size < LEAPRAID_SMP_FRAME_HEADER_SIZE) { 1365*5597088cSDongdong Hao dev_err(&adapter->pdev->dev, 1366*5597088cSDongdong Hao "%s: Invalid SMP reply payload size=%zu\n", 1367*5597088cSDongdong Hao __func__, c2h_size); 1368*5597088cSDongdong Hao rc = -EINVAL; 1369*5597088cSDongdong Hao goto free_rep_buf; 1370*5597088cSDongdong Hao } 1371*5597088cSDongdong Hao 1372*5597088cSDongdong Hao rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT, 1373*5597088cSDongdong Hao __func__); 1374*5597088cSDongdong Hao if (rc) 1375*5597088cSDongdong Hao goto free_rep_buf; 1376*5597088cSDongdong Hao 1377*5597088cSDongdong Hao leapraid_build_smp_task(adapter, rphy, h2c_dma_addr, 1378*5597088cSDongdong Hao h2c_size, c2h_dma_addr, c2h_size); 1379*5597088cSDongdong Hao 1380*5597088cSDongdong Hao rc = leapraid_send_smp_req(adapter); 1381*5597088cSDongdong Hao if (rc) 1382*5597088cSDongdong Hao goto free_rep_buf; 1383*5597088cSDongdong Hao 1384*5597088cSDongdong Hao leapraid_handle_smp_rep(adapter, job, addr_in, &reslen); 1385*5597088cSDongdong Hao 1386*5597088cSDongdong Hao free_rep_buf: 1387*5597088cSDongdong Hao leapraid_dma_unmap_buffer(&adapter->pdev->dev, &job->reply_payload, 1388*5597088cSDongdong Hao c2h_dma_addr, addr_in); 1389*5597088cSDongdong Hao free_req_buf: 1390*5597088cSDongdong Hao leapraid_dma_unmap_buffer(&adapter->pdev->dev, &job->request_payload, 1391*5597088cSDongdong Hao h2c_dma_addr, addr_out); 1392*5597088cSDongdong Hao release_lock: 1393*5597088cSDongdong Hao adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_NOT_USED; 1394*5597088cSDongdong Hao mutex_unlock(&adapter->driver_cmds.transport_cmd.mutex); 1395*5597088cSDongdong Hao exit_bsg_job: 1396*5597088cSDongdong Hao bsg_job_done(job, rc, reslen); 1397*5597088cSDongdong Hao } 1398*5597088cSDongdong Hao 1399*5597088cSDongdong Hao struct sas_function_template leapraid_transport_functions = { 1400*5597088cSDongdong Hao .smp_handler = leapraid_transport_smp_handler, 1401*5597088cSDongdong Hao }; 1402*5597088cSDongdong Hao 1403*5597088cSDongdong Hao struct scsi_transport_template *leapraid_transport_template; 1404