Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] libsas: Clean up discovery failure handler code

sas_rphy_delete does two things: it removes the sas_rphy from the transport
layer and frees the sas_rphy. This can be broken down into two functions,
sas_rphy_remove and sas_rphy_free; sas_rphy_remove is of interest to
sas_discover_root_expander because it calls functions that require
sas_rphy_add as a prerequisite and can fail (namely sas_discover_expander).
In that case, sas_discover_root_expander needs to be able to undo the effects
of sas_rphy_add yet leave the job of freeing the sas_rphy to the caller of
sas_discover_root_expander.

This patch also removes some unnecessary code from sas_discover_end_dev
to eliminate an unnecessary cycle of sas_notify_lldd_gone/found for SAS
devices, thus eliminating a sas_rphy_remove call (and fixing a race condition
where a SCSI target scan can come in between the gone and found call).
It also moves the sas_rphy_free calls into sas_discover_domain and
sas_ex_discover_end_dev to complement the sas_rphy_allocation via
sas_get_port_device.

This patch does not change the semantics of sas_rphy_delete.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

authored by

Darrick J. Wong and committed by
James Bottomley
6f63caae 3b6e9faf

+40 -47
+17 -28
drivers/scsi/libsas/sas_discover.c
··· 577 577 out_err: 578 578 sas_notify_lldd_dev_gone(dev); 579 579 out_err2: 580 - sas_rphy_free(dev->rphy); 581 - dev->rphy = NULL; 582 580 return res; 583 581 } 584 582 ··· 598 600 if (res) 599 601 goto out_err; 600 602 601 - /* do this to get the end device port attributes which will have 602 - * been scanned in sas_rphy_add */ 603 - sas_notify_lldd_dev_gone(dev); 604 - res = sas_notify_lldd_dev_found(dev); 605 - if (res) 606 - goto out_err3; 607 - 608 603 return 0; 609 604 610 605 out_err: 611 606 sas_notify_lldd_dev_gone(dev); 612 607 out_err2: 613 - sas_rphy_free(dev->rphy); 614 - dev->rphy = NULL; 615 - return res; 616 - out_err3: 617 - sas_rphy_delete(dev->rphy); 618 - dev->rphy = NULL; 619 608 return res; 620 609 } 621 610 ··· 657 672 */ 658 673 static void sas_discover_domain(struct work_struct *work) 659 674 { 675 + struct domain_device *dev; 660 676 int error = 0; 661 677 struct sas_discovery_event *ev = 662 678 container_of(work, struct sas_discovery_event, work); ··· 667 681 &port->disc.pending); 668 682 669 683 if (port->port_dev) 670 - return ; 671 - else { 672 - error = sas_get_port_device(port); 673 - if (error) 674 - return; 675 - } 684 + return; 685 + 686 + error = sas_get_port_device(port); 687 + if (error) 688 + return; 689 + dev = port->port_dev; 676 690 677 691 SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, 678 692 current->pid); 679 693 680 - switch (port->port_dev->dev_type) { 694 + switch (dev->dev_type) { 681 695 case SAS_END_DEV: 682 - error = sas_discover_end_dev(port->port_dev); 696 + error = sas_discover_end_dev(dev); 683 697 break; 684 698 case EDGE_DEV: 685 699 case FANOUT_DEV: 686 - error = sas_discover_root_expander(port->port_dev); 700 + error = sas_discover_root_expander(dev); 687 701 break; 688 702 case SATA_DEV: 689 703 case SATA_PM: 690 - error = sas_discover_sata(port->port_dev); 704 + error = sas_discover_sata(dev); 691 705 break; 692 706 default: 693 - SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type); 707 + SAS_DPRINTK("unhandled device %d\n", dev->dev_type); 694 708 break; 695 709 } 696 710 697 711 if (error) { 712 + sas_rphy_free(dev->rphy); 713 + dev->rphy = NULL; 714 + 698 715 spin_lock(&port->dev_list_lock); 699 - list_del_init(&port->port_dev->dev_list_node); 716 + list_del_init(&dev->dev_list_node); 700 717 spin_unlock(&port->dev_list_lock); 701 718 702 - kfree(port->port_dev); /* not kobject_register-ed yet */ 719 + kfree(dev); /* not kobject_register-ed yet */ 703 720 port->port_dev = NULL; 704 721 } 705 722
+3 -5
drivers/scsi/libsas/sas_expander.c
··· 667 667 return child; 668 668 669 669 out_list_del: 670 + sas_rphy_free(child->rphy); 671 + child->rphy = NULL; 670 672 list_del(&child->dev_list_node); 671 673 out_free: 672 674 sas_port_delete(phy->port); ··· 1446 1444 return res; 1447 1445 1448 1446 out_err2: 1449 - sas_rphy_delete(dev->rphy); 1450 - dev->rphy = NULL; 1451 - return res; 1447 + sas_rphy_remove(dev->rphy); 1452 1448 out_err: 1453 - sas_rphy_free(dev->rphy); 1454 - dev->rphy = NULL; 1455 1449 return res; 1456 1450 } 1457 1451
+19 -14
drivers/scsi/scsi_transport_sas.c
··· 1299 1299 * Note: 1300 1300 * This function must only be called on a remote 1301 1301 * PHY that has not sucessfully been added using 1302 - * sas_rphy_add(). 1302 + * sas_rphy_add() (or has been sas_rphy_remove()'d) 1303 1303 */ 1304 1304 void sas_rphy_free(struct sas_rphy *rphy) 1305 1305 { ··· 1318 1318 EXPORT_SYMBOL(sas_rphy_free); 1319 1319 1320 1320 /** 1321 - * sas_rphy_delete -- remove SAS remote PHY 1322 - * @rphy: SAS remote PHY to remove 1321 + * sas_rphy_delete -- remove and free SAS remote PHY 1322 + * @rphy: SAS remote PHY to remove and free 1323 1323 * 1324 - * Removes the specified SAS remote PHY. 1324 + * Removes the specified SAS remote PHY and frees it. 1325 1325 */ 1326 1326 void 1327 1327 sas_rphy_delete(struct sas_rphy *rphy) 1328 1328 { 1329 + sas_rphy_remove(rphy); 1330 + sas_rphy_free(rphy); 1331 + } 1332 + EXPORT_SYMBOL(sas_rphy_delete); 1333 + 1334 + /** 1335 + * sas_rphy_remove -- remove SAS remote PHY 1336 + * @rphy: SAS remote phy to remove 1337 + * 1338 + * Removes the specified SAS remote PHY. 1339 + */ 1340 + void 1341 + sas_rphy_remove(struct sas_rphy *rphy) 1342 + { 1329 1343 struct device *dev = &rphy->dev; 1330 1344 struct sas_port *parent = dev_to_sas_port(dev->parent); 1331 - struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 1332 - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1333 1345 1334 1346 switch (rphy->identify.device_type) { 1335 1347 case SAS_END_DEVICE: ··· 1357 1345 1358 1346 transport_remove_device(dev); 1359 1347 device_del(dev); 1360 - transport_destroy_device(dev); 1361 - 1362 - mutex_lock(&sas_host->lock); 1363 - list_del(&rphy->list); 1364 - mutex_unlock(&sas_host->lock); 1365 1348 1366 1349 parent->rphy = NULL; 1367 - 1368 - put_device(dev); 1369 1350 } 1370 - EXPORT_SYMBOL(sas_rphy_delete); 1351 + EXPORT_SYMBOL(sas_rphy_remove); 1371 1352 1372 1353 /** 1373 1354 * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY
+1
include/scsi/scsi_transport_sas.h
··· 182 182 extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); 183 183 void sas_rphy_free(struct sas_rphy *); 184 184 extern int sas_rphy_add(struct sas_rphy *); 185 + extern void sas_rphy_remove(struct sas_rphy *); 185 186 extern void sas_rphy_delete(struct sas_rphy *); 186 187 extern int scsi_is_sas_rphy(const struct device *); 187 188