1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Serial Attached SCSI (SAS) Port class 4 * 5 * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 7 */ 8 9 #include "sas_internal.h" 10 11 #include <scsi/scsi_transport.h> 12 #include <scsi/scsi_transport_sas.h> 13 #include "../scsi_sas_internal.h" 14 15 static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy) 16 { 17 struct sas_ha_struct *sas_ha = phy->ha; 18 19 if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, 20 SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports && 21 memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0)) 22 return false; 23 return true; 24 } 25 26 static void sas_resume_port(struct asd_sas_phy *phy) 27 { 28 struct domain_device *dev; 29 struct asd_sas_port *port = phy->port; 30 struct sas_ha_struct *sas_ha = phy->ha; 31 struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); 32 33 if (si->dft->lldd_port_formed) 34 si->dft->lldd_port_formed(phy); 35 36 if (port->suspended) 37 port->suspended = 0; 38 else { 39 /* we only need to handle "link returned" actions once */ 40 return; 41 } 42 43 /* if the port came back: 44 * 1/ presume every device came back 45 * 2/ force the next revalidation to check all expander phys 46 */ 47 list_for_each_entry(dev, &port->dev_list, dev_list_node) { 48 int i, rc; 49 50 rc = sas_notify_lldd_dev_found(dev); 51 if (rc) { 52 sas_unregister_dev(port, dev); 53 sas_destruct_devices(port); 54 continue; 55 } 56 57 if (dev_is_expander(dev->dev_type)) { 58 dev->ex_dev.ex_change_count = -1; 59 for (i = 0; i < dev->ex_dev.num_phys; i++) { 60 struct ex_phy *phy = &dev->ex_dev.ex_phy[i]; 61 62 phy->phy_change_count = -1; 63 } 64 } 65 } 66 67 sas_discover_event(port, DISCE_RESUME); 68 } 69 70 /** 71 * sas_form_port - add this phy to a port 72 * @phy: the phy of interest 73 * 74 * This function adds this phy to an existing port, thus creating a wide 75 * port, or it creates a port and adds the phy to the port. 76 */ 77 static void sas_form_port(struct asd_sas_phy *phy) 78 { 79 int i; 80 struct sas_ha_struct *sas_ha = phy->ha; 81 struct asd_sas_port *port = phy->port; 82 struct domain_device *port_dev; 83 struct sas_internal *si = 84 to_sas_internal(sas_ha->core.shost->transportt); 85 unsigned long flags; 86 87 if (port) { 88 if (!phy_is_wideport_member(port, phy)) 89 sas_deform_port(phy, 0); 90 else if (phy->suspended) { 91 phy->suspended = 0; 92 sas_resume_port(phy); 93 94 /* phy came back, try to cancel the timeout */ 95 wake_up(&sas_ha->eh_wait_q); 96 return; 97 } else { 98 pr_info("%s: phy%d belongs to port%d already(%d)!\n", 99 __func__, phy->id, phy->port->id, 100 phy->port->num_phys); 101 return; 102 } 103 } 104 105 /* see if the phy should be part of a wide port */ 106 spin_lock_irqsave(&sas_ha->phy_port_lock, flags); 107 for (i = 0; i < sas_ha->num_phys; i++) { 108 port = sas_ha->sas_port[i]; 109 spin_lock(&port->phy_list_lock); 110 if (*(u64 *) port->sas_addr && 111 phy_is_wideport_member(port, phy) && port->num_phys > 0) { 112 /* wide port */ 113 pr_debug("phy%d matched wide port%d\n", phy->id, 114 port->id); 115 break; 116 } 117 spin_unlock(&port->phy_list_lock); 118 } 119 /* The phy does not match any existing port, create a new one */ 120 if (i == sas_ha->num_phys) { 121 for (i = 0; i < sas_ha->num_phys; i++) { 122 port = sas_ha->sas_port[i]; 123 spin_lock(&port->phy_list_lock); 124 if (*(u64 *)port->sas_addr == 0 125 && port->num_phys == 0) { 126 memcpy(port->sas_addr, phy->sas_addr, 127 SAS_ADDR_SIZE); 128 break; 129 } 130 spin_unlock(&port->phy_list_lock); 131 } 132 } 133 134 if (i >= sas_ha->num_phys) { 135 pr_err("%s: couldn't find a free port, bug?\n", __func__); 136 spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); 137 return; 138 } 139 140 /* add the phy to the port */ 141 port_dev = port->port_dev; 142 list_add_tail(&phy->port_phy_el, &port->phy_list); 143 sas_phy_set_target(phy, port_dev); 144 phy->port = port; 145 port->num_phys++; 146 port->phy_mask |= (1U << phy->id); 147 148 if (*(u64 *)port->attached_sas_addr == 0) { 149 port->class = phy->class; 150 memcpy(port->attached_sas_addr, phy->attached_sas_addr, 151 SAS_ADDR_SIZE); 152 port->iproto = phy->iproto; 153 port->tproto = phy->tproto; 154 port->oob_mode = phy->oob_mode; 155 port->linkrate = phy->linkrate; 156 } else 157 port->linkrate = max(port->linkrate, phy->linkrate); 158 spin_unlock(&port->phy_list_lock); 159 spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); 160 161 if (!port->port) { 162 port->port = sas_port_alloc(phy->phy->dev.parent, port->id); 163 BUG_ON(!port->port); 164 sas_port_add(port->port); 165 } 166 sas_port_add_phy(port->port, phy->phy); 167 168 pr_debug("%s added to %s, phy_mask:0x%x (%016llx)\n", 169 dev_name(&phy->phy->dev), dev_name(&port->port->dev), 170 port->phy_mask, 171 SAS_ADDR(port->attached_sas_addr)); 172 173 if (port_dev) 174 port_dev->pathways = port->num_phys; 175 176 /* Tell the LLDD about this port formation. */ 177 if (si->dft->lldd_port_formed) 178 si->dft->lldd_port_formed(phy); 179 180 sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); 181 /* Only insert a revalidate event after initial discovery */ 182 if (port_dev && dev_is_expander(port_dev->dev_type)) { 183 struct expander_device *ex_dev = &port_dev->ex_dev; 184 185 ex_dev->ex_change_count = -1; 186 sas_discover_event(port, DISCE_REVALIDATE_DOMAIN); 187 } 188 flush_workqueue(sas_ha->disco_q); 189 } 190 191 /** 192 * sas_deform_port - remove this phy from the port it belongs to 193 * @phy: the phy of interest 194 * @gone: whether or not the PHY is gone 195 * 196 * This is called when the physical link to the other phy has been 197 * lost (on this phy), in Event thread context. We cannot delay here. 198 */ 199 void sas_deform_port(struct asd_sas_phy *phy, int gone) 200 { 201 struct sas_ha_struct *sas_ha = phy->ha; 202 struct asd_sas_port *port = phy->port; 203 struct sas_internal *si = 204 to_sas_internal(sas_ha->core.shost->transportt); 205 struct domain_device *dev; 206 unsigned long flags; 207 208 if (!port) 209 return; /* done by a phy event */ 210 211 dev = port->port_dev; 212 if (dev) 213 dev->pathways--; 214 215 if (port->num_phys == 1) { 216 sas_unregister_domain_devices(port, gone); 217 sas_destruct_devices(port); 218 sas_port_delete(port->port); 219 port->port = NULL; 220 } else { 221 sas_port_delete_phy(port->port, phy->phy); 222 sas_device_set_phy(dev, port->port); 223 } 224 225 if (si->dft->lldd_port_deformed) 226 si->dft->lldd_port_deformed(phy); 227 228 spin_lock_irqsave(&sas_ha->phy_port_lock, flags); 229 spin_lock(&port->phy_list_lock); 230 231 list_del_init(&phy->port_phy_el); 232 sas_phy_set_target(phy, NULL); 233 phy->port = NULL; 234 port->num_phys--; 235 port->phy_mask &= ~(1U << phy->id); 236 237 if (port->num_phys == 0) { 238 INIT_LIST_HEAD(&port->phy_list); 239 memset(port->sas_addr, 0, SAS_ADDR_SIZE); 240 memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE); 241 port->class = 0; 242 port->iproto = 0; 243 port->tproto = 0; 244 port->oob_mode = 0; 245 port->phy_mask = 0; 246 } 247 spin_unlock(&port->phy_list_lock); 248 spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); 249 250 /* Only insert revalidate event if the port still has members */ 251 if (port->port && dev && dev_is_expander(dev->dev_type)) { 252 struct expander_device *ex_dev = &dev->ex_dev; 253 254 ex_dev->ex_change_count = -1; 255 sas_discover_event(port, DISCE_REVALIDATE_DOMAIN); 256 } 257 flush_workqueue(sas_ha->disco_q); 258 259 return; 260 } 261 262 /* ---------- SAS port events ---------- */ 263 264 void sas_porte_bytes_dmaed(struct work_struct *work) 265 { 266 struct asd_sas_event *ev = to_asd_sas_event(work); 267 struct asd_sas_phy *phy = ev->phy; 268 269 sas_form_port(phy); 270 } 271 272 void sas_porte_broadcast_rcvd(struct work_struct *work) 273 { 274 struct asd_sas_event *ev = to_asd_sas_event(work); 275 struct asd_sas_phy *phy = ev->phy; 276 unsigned long flags; 277 u32 prim; 278 279 spin_lock_irqsave(&phy->sas_prim_lock, flags); 280 prim = phy->sas_prim; 281 spin_unlock_irqrestore(&phy->sas_prim_lock, flags); 282 283 pr_debug("broadcast received: %d\n", prim); 284 sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); 285 286 if (phy->port) 287 flush_workqueue(phy->port->ha->disco_q); 288 } 289 290 void sas_porte_link_reset_err(struct work_struct *work) 291 { 292 struct asd_sas_event *ev = to_asd_sas_event(work); 293 struct asd_sas_phy *phy = ev->phy; 294 295 sas_deform_port(phy, 1); 296 } 297 298 void sas_porte_timer_event(struct work_struct *work) 299 { 300 struct asd_sas_event *ev = to_asd_sas_event(work); 301 struct asd_sas_phy *phy = ev->phy; 302 303 sas_deform_port(phy, 1); 304 } 305 306 void sas_porte_hard_reset(struct work_struct *work) 307 { 308 struct asd_sas_event *ev = to_asd_sas_event(work); 309 struct asd_sas_phy *phy = ev->phy; 310 311 sas_deform_port(phy, 1); 312 } 313 314 /* ---------- SAS port registration ---------- */ 315 316 static void sas_init_port(struct asd_sas_port *port, 317 struct sas_ha_struct *sas_ha, int i) 318 { 319 memset(port, 0, sizeof(*port)); 320 port->id = i; 321 INIT_LIST_HEAD(&port->dev_list); 322 INIT_LIST_HEAD(&port->disco_list); 323 INIT_LIST_HEAD(&port->destroy_list); 324 INIT_LIST_HEAD(&port->sas_port_del_list); 325 spin_lock_init(&port->phy_list_lock); 326 INIT_LIST_HEAD(&port->phy_list); 327 port->ha = sas_ha; 328 329 spin_lock_init(&port->dev_list_lock); 330 } 331 332 int sas_register_ports(struct sas_ha_struct *sas_ha) 333 { 334 int i; 335 336 /* initialize the ports and discovery */ 337 for (i = 0; i < sas_ha->num_phys; i++) { 338 struct asd_sas_port *port = sas_ha->sas_port[i]; 339 340 sas_init_port(port, sas_ha, i); 341 sas_init_disc(&port->disc, port); 342 } 343 return 0; 344 } 345 346 void sas_unregister_ports(struct sas_ha_struct *sas_ha) 347 { 348 int i; 349 350 for (i = 0; i < sas_ha->num_phys; i++) 351 if (sas_ha->sas_phy[i]->port) 352 sas_deform_port(sas_ha->sas_phy[i], 0); 353 354 } 355 356 const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { 357 [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, 358 [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, 359 [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, 360 [PORTE_TIMER_EVENT] = sas_porte_timer_event, 361 [PORTE_HARD_RESET] = sas_porte_hard_reset, 362 }; 363