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