Commit 085f104a authored by John Garry's avatar John Garry Committed by Martin K. Petersen

scsi: libsas: Inject revalidate event for root port event

According to the SAS spec, an expander device shall transmit BROADCAST
(CHANGE) from at least one phy in each expander port other than the
expander port that is the cause for transmitting BROADCAST (CHANGE).

As such, for when the link is lost for a root PHY attached to an expander
PHY, we get no broadcast event.

This causes an issue for libsas, in that we will not revalidate the domain
for these events.

As a solution, for when a root PHY is formed or deformed from a root port,
insert a broadcast event to trigger a domain revalidation.
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent a5b38d31
...@@ -95,6 +95,7 @@ static void sas_form_port(struct asd_sas_phy *phy) ...@@ -95,6 +95,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
int i; int i;
struct sas_ha_struct *sas_ha = phy->ha; struct sas_ha_struct *sas_ha = phy->ha;
struct asd_sas_port *port = phy->port; struct asd_sas_port *port = phy->port;
struct domain_device *port_dev;
struct sas_internal *si = struct sas_internal *si =
to_sas_internal(sas_ha->core.shost->transportt); to_sas_internal(sas_ha->core.shost->transportt);
unsigned long flags; unsigned long flags;
...@@ -153,8 +154,9 @@ static void sas_form_port(struct asd_sas_phy *phy) ...@@ -153,8 +154,9 @@ static void sas_form_port(struct asd_sas_phy *phy)
} }
/* add the phy to the port */ /* add the phy to the port */
port_dev = port->port_dev;
list_add_tail(&phy->port_phy_el, &port->phy_list); list_add_tail(&phy->port_phy_el, &port->phy_list);
sas_phy_set_target(phy, port->port_dev); sas_phy_set_target(phy, port_dev);
phy->port = port; phy->port = port;
port->num_phys++; port->num_phys++;
port->phy_mask |= (1U << phy->id); port->phy_mask |= (1U << phy->id);
...@@ -184,14 +186,21 @@ static void sas_form_port(struct asd_sas_phy *phy) ...@@ -184,14 +186,21 @@ static void sas_form_port(struct asd_sas_phy *phy)
port->phy_mask, port->phy_mask,
SAS_ADDR(port->attached_sas_addr)); SAS_ADDR(port->attached_sas_addr));
if (port->port_dev) if (port_dev)
port->port_dev->pathways = port->num_phys; port_dev->pathways = port->num_phys;
/* Tell the LLDD about this port formation. */ /* Tell the LLDD about this port formation. */
if (si->dft->lldd_port_formed) if (si->dft->lldd_port_formed)
si->dft->lldd_port_formed(phy); si->dft->lldd_port_formed(phy);
sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
/* Only insert a revalidate event after initial discovery */
if (port_dev && sas_dev_type_is_expander(port_dev->dev_type)) {
struct expander_device *ex_dev = &port_dev->ex_dev;
ex_dev->ex_change_count = -1;
sas_discover_event(port, DISCE_REVALIDATE_DOMAIN);
}
flush_workqueue(sas_ha->disco_q); flush_workqueue(sas_ha->disco_q);
} }
...@@ -254,6 +263,15 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone) ...@@ -254,6 +263,15 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
spin_unlock(&port->phy_list_lock); spin_unlock(&port->phy_list_lock);
spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
/* Only insert revalidate event if the port still has members */
if (port->port && dev && sas_dev_type_is_expander(dev->dev_type)) {
struct expander_device *ex_dev = &dev->ex_dev;
ex_dev->ex_change_count = -1;
sas_discover_event(port, DISCE_REVALIDATE_DOMAIN);
}
flush_workqueue(sas_ha->disco_q);
return; return;
} }
......
...@@ -224,6 +224,13 @@ struct sas_work { ...@@ -224,6 +224,13 @@ struct sas_work {
struct work_struct work; struct work_struct work;
}; };
/* Lots of code duplicates this in the SCSI tree, which can be factored out */
static inline bool sas_dev_type_is_expander(enum sas_device_type type)
{
return type == SAS_EDGE_EXPANDER_DEVICE ||
type == SAS_FANOUT_EXPANDER_DEVICE;
}
static inline void INIT_SAS_WORK(struct sas_work *sw, void (*fn)(struct work_struct *)) static inline void INIT_SAS_WORK(struct sas_work *sw, void (*fn)(struct work_struct *))
{ {
INIT_WORK(&sw->work, fn); INIT_WORK(&sw->work, fn);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment