1 // SPDX-License-Identifier: GPL-2.0
3 * Serial Attached SCSI (SAS) Port class
5 * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
9 #include "sas_internal.h"
11 #include <scsi/scsi_transport.h>
12 #include <scsi/scsi_transport_sas.h>
13 #include "scsi_sas_internal.h"
15 static bool phy_is_wideport_member(struct asd_sas_port
*port
, struct asd_sas_phy
*phy
)
17 struct sas_ha_struct
*sas_ha
= phy
->ha
;
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))
26 static void sas_resume_port(struct asd_sas_phy
*phy
)
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
);
33 if (si
->dft
->lldd_port_formed
)
34 si
->dft
->lldd_port_formed(phy
);
39 /* we only need to handle "link returned" actions once */
43 /* if the port came back:
44 * 1/ presume every device came back
45 * 2/ force the next revalidation to check all expander phys
47 list_for_each_entry_safe(dev
, n
, &port
->dev_list
, dev_list_node
) {
50 rc
= sas_notify_lldd_dev_found(dev
);
52 sas_unregister_dev(port
, dev
);
53 sas_destruct_devices(port
);
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
];
62 phy
->phy_change_count
= -1;
67 sas_discover_event(port
, DISCE_RESUME
);
70 static void sas_form_port_add_phy(struct asd_sas_port
*port
,
71 struct asd_sas_phy
*phy
, bool wideport
)
73 list_add_tail(&phy
->port_phy_el
, &port
->phy_list
);
74 sas_phy_set_target(phy
, port
->port_dev
);
77 port
->phy_mask
|= (1U << phy
->id
);
80 pr_debug("phy%d matched wide port%d\n", phy
->id
,
83 memcpy(port
->sas_addr
, phy
->sas_addr
, SAS_ADDR_SIZE
);
85 if (*(u64
*)port
->attached_sas_addr
== 0) {
86 memcpy(port
->attached_sas_addr
, phy
->attached_sas_addr
,
88 port
->iproto
= phy
->iproto
;
89 port
->tproto
= phy
->tproto
;
90 port
->oob_mode
= phy
->oob_mode
;
91 port
->linkrate
= phy
->linkrate
;
93 port
->linkrate
= max(port
->linkrate
, phy
->linkrate
);
98 * sas_form_port - add this phy to a port
99 * @phy: the phy of interest
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.
104 static void sas_form_port(struct asd_sas_phy
*phy
)
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
);
115 if (!phy_is_wideport_member(port
, phy
))
116 sas_deform_port(phy
, 0);
117 else if (phy
->suspended
) {
119 sas_resume_port(phy
);
121 /* phy came back, try to cancel the timeout */
122 wake_up(&sas_ha
->eh_wait_q
);
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
);
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) {
140 port_dev
= port
->port_dev
;
141 sas_form_port_add_phy(port
, phy
, true);
142 spin_unlock(&port
->phy_list_lock
);
145 spin_unlock(&port
->phy_list_lock
);
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
);
159 spin_unlock(&port
->phy_list_lock
);
162 if (i
>= sas_ha
->num_phys
) {
163 pr_err("%s: couldn't find a free port, bug?\n",
165 spin_unlock_irqrestore(&sas_ha
->phy_port_lock
, flags
);
169 spin_unlock_irqrestore(&sas_ha
->phy_port_lock
, flags
);
172 port
->port
= sas_port_alloc(phy
->phy
->dev
.parent
, port
->id
);
174 sas_port_add(port
->port
);
176 sas_port_add_phy(port
->port
, phy
->phy
);
178 pr_debug("%s added to %s, phy_mask:0x%x (%016llx)\n",
179 dev_name(&phy
->phy
->dev
), dev_name(&port
->port
->dev
),
181 SAS_ADDR(port
->attached_sas_addr
));
184 port_dev
->pathways
= port
->num_phys
;
186 /* Tell the LLDD about this port formation. */
187 if (si
->dft
->lldd_port_formed
)
188 si
->dft
->lldd_port_formed(phy
);
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
;
195 ex_dev
->ex_change_count
= -1;
196 sas_discover_event(port
, DISCE_REVALIDATE_DOMAIN
);
198 flush_workqueue(sas_ha
->disco_q
);
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
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.
209 void sas_deform_port(struct asd_sas_phy
*phy
, int gone
)
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
;
219 return; /* done by a phy event */
221 dev
= port
->port_dev
;
225 if (port
->num_phys
== 1) {
226 sas_unregister_domain_devices(port
, gone
);
227 sas_destruct_devices(port
);
228 sas_port_delete(port
->port
);
231 sas_port_delete_phy(port
->port
, phy
->phy
);
232 sas_device_set_phy(dev
, port
->port
);
235 if (si
->dft
->lldd_port_deformed
)
236 si
->dft
->lldd_port_deformed(phy
);
238 spin_lock_irqsave(&sas_ha
->phy_port_lock
, flags
);
239 spin_lock(&port
->phy_list_lock
);
241 list_del_init(&phy
->port_phy_el
);
242 sas_phy_set_target(phy
, NULL
);
245 port
->phy_mask
&= ~(1U << phy
->id
);
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
);
256 spin_unlock(&port
->phy_list_lock
);
257 spin_unlock_irqrestore(&sas_ha
->phy_port_lock
, flags
);
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
;
263 ex_dev
->ex_change_count
= -1;
264 sas_discover_event(port
, DISCE_REVALIDATE_DOMAIN
);
266 flush_workqueue(sas_ha
->disco_q
);
271 /* ---------- SAS port events ---------- */
273 void sas_porte_bytes_dmaed(struct work_struct
*work
)
275 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
276 struct asd_sas_phy
*phy
= ev
->phy
;
281 void sas_porte_broadcast_rcvd(struct work_struct
*work
)
283 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
284 struct asd_sas_phy
*phy
= ev
->phy
;
288 spin_lock_irqsave(&phy
->sas_prim_lock
, flags
);
289 prim
= phy
->sas_prim
;
290 spin_unlock_irqrestore(&phy
->sas_prim_lock
, flags
);
292 pr_debug("broadcast received: %d\n", prim
);
293 sas_discover_event(phy
->port
, DISCE_REVALIDATE_DOMAIN
);
296 flush_workqueue(phy
->port
->ha
->disco_q
);
299 void sas_porte_link_reset_err(struct work_struct
*work
)
301 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
302 struct asd_sas_phy
*phy
= ev
->phy
;
304 sas_deform_port(phy
, 1);
307 void sas_porte_timer_event(struct work_struct
*work
)
309 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
310 struct asd_sas_phy
*phy
= ev
->phy
;
312 sas_deform_port(phy
, 1);
315 void sas_porte_hard_reset(struct work_struct
*work
)
317 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
318 struct asd_sas_phy
*phy
= ev
->phy
;
320 sas_deform_port(phy
, 1);
323 /* ---------- SAS port registration ---------- */
325 static void sas_init_port(struct asd_sas_port
*port
,
326 struct sas_ha_struct
*sas_ha
, int i
)
328 memset(port
, 0, sizeof(*port
));
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
);
338 spin_lock_init(&port
->dev_list_lock
);
341 int sas_register_ports(struct sas_ha_struct
*sas_ha
)
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
];
349 sas_init_port(port
, sas_ha
, i
);
350 sas_init_disc(&port
->disc
, port
);
355 void sas_unregister_ports(struct sas_ha_struct
*sas_ha
)
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);
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
,