From 5381837f125cc62ad703fbcdfcd7566fc81fd404 Mon Sep 17 00:00:00 2001 From: Tom Peng Date: Wed, 1 Jul 2009 20:37:26 +0800 Subject: [SCSI] libsas: reuse the original port when hotplugging phys in wide ports There's a hotplug problem in the way libsas allocates ports: it loops over the available ports first trying to add to an existing for a wide port and otherwise allocating the next free port. This scheme only works if the port array is packed from zero, which fails if a port gets hot unplugged and the array becomes sparse. In that case, a new port is formed even if there's a wide port it should be part of. Fix this by creating two loops over all the ports: the first to see if the phy should be part of a wide port and the second to form a new port in an empty port slot. Signed-off-by: Tom Peng Signed-off-by: Jack Wang Signed-off-by: Lindar Liu Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/libsas/sas_port.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/libsas/sas_port.c') diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index e6ac59c023f..fe8b74c706d 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -56,7 +56,7 @@ static void sas_form_port(struct asd_sas_phy *phy) } } - /* find a port */ + /* see if the phy should be part of a wide port */ spin_lock_irqsave(&sas_ha->phy_port_lock, flags); for (i = 0; i < sas_ha->num_phys; i++) { port = sas_ha->sas_port[i]; @@ -69,12 +69,23 @@ static void sas_form_port(struct asd_sas_phy *phy) SAS_DPRINTK("phy%d matched wide port%d\n", phy->id, port->id); break; - } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) { - memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE); - break; } spin_unlock(&port->phy_list_lock); } + /* The phy does not match any existing port, create a new one */ + if (i == sas_ha->num_phys) { + for (i = 0; i < sas_ha->num_phys; i++) { + port = sas_ha->sas_port[i]; + spin_lock(&port->phy_list_lock); + if (*(u64 *)port->sas_addr == 0 + && port->num_phys == 0) { + memcpy(port->sas_addr, phy->sas_addr, + SAS_ADDR_SIZE); + break; + } + spin_unlock(&port->phy_list_lock); + } + } if (i >= sas_ha->num_phys) { printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", -- cgit v1.2.3-70-g09d2