summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorJohn Garry <john.garry@huawei.com>2019-04-12 16:57:55 +0800
committerMartin K. Petersen <martin.petersen@oracle.com>2019-04-15 18:55:00 -0400
commit085f104a83d565097644889bf1f6f1aa6d345cb5 (patch)
treec3c531c4172c6591a5914741384929ed742e4c80 /drivers/scsi/libsas
parenta5b38d3159eac6a30c1c57d67707c141b9ac3efb (diff)
downloadlinux-085f104a83d565097644889bf1f6f1aa6d345cb5.tar.bz2
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: John Garry <john.garry@huawei.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_port.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 03fe479359b6..38a10478605c 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -95,6 +95,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
int i;
struct sas_ha_struct *sas_ha = phy->ha;
struct asd_sas_port *port = phy->port;
+ struct domain_device *port_dev;
struct sas_internal *si =
to_sas_internal(sas_ha->core.shost->transportt);
unsigned long flags;
@@ -153,8 +154,9 @@ static void sas_form_port(struct asd_sas_phy *phy)
}
/* add the phy to the port */
+ port_dev = port->port_dev;
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;
port->num_phys++;
port->phy_mask |= (1U << phy->id);
@@ -184,14 +186,21 @@ static void sas_form_port(struct asd_sas_phy *phy)
port->phy_mask,
SAS_ADDR(port->attached_sas_addr));
- if (port->port_dev)
- port->port_dev->pathways = port->num_phys;
+ if (port_dev)
+ port_dev->pathways = port->num_phys;
/* Tell the LLDD about this port formation. */
if (si->dft->lldd_port_formed)
si->dft->lldd_port_formed(phy);
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);
}
@@ -254,6 +263,15 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
spin_unlock(&port->phy_list_lock);
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;
}