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