diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_discover.c')
| -rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 61 | 
1 files changed, 35 insertions, 26 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 36467967560..629a0865b13 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -72,6 +72,7 @@ static int sas_get_port_device(struct asd_sas_port *port)  	struct asd_sas_phy *phy;  	struct sas_rphy *rphy;  	struct domain_device *dev; +	int rc = -ENODEV;  	dev = sas_alloc_device();  	if (!dev) @@ -110,9 +111,16 @@ static int sas_get_port_device(struct asd_sas_port *port)  	sas_init_dev(dev); +	dev->port = port;  	switch (dev->dev_type) { -	case SAS_END_DEV:  	case SATA_DEV: +		rc = sas_ata_init(dev); +		if (rc) { +			rphy = NULL; +			break; +		} +		/* fall through */ +	case SAS_END_DEV:  		rphy = sas_end_device_alloc(port->port);  		break;  	case EDGE_DEV: @@ -131,19 +139,14 @@ static int sas_get_port_device(struct asd_sas_port *port)  	if (!rphy) {  		sas_put_device(dev); -		return -ENODEV; +		return rc;  	} -	spin_lock_irq(&port->phy_list_lock); -	list_for_each_entry(phy, &port->phy_list, port_phy_el) -		sas_phy_set_target(phy, dev); -	spin_unlock_irq(&port->phy_list_lock);  	rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;  	memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);  	sas_fill_in_rphy(dev, rphy);  	sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);  	port->port_dev = dev; -	dev->port = port;  	dev->linkrate = port->linkrate;  	dev->min_linkrate = port->linkrate;  	dev->max_linkrate = port->linkrate; @@ -155,6 +158,7 @@ static int sas_get_port_device(struct asd_sas_port *port)  	sas_device_set_phy(dev, port->port);  	dev->rphy = rphy; +	get_device(&dev->rphy->dev);  	if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV)  		list_add_tail(&dev->disco_list_node, &port->disco_list); @@ -164,6 +168,11 @@ static int sas_get_port_device(struct asd_sas_port *port)  		spin_unlock_irq(&port->dev_list_lock);  	} +	spin_lock_irq(&port->phy_list_lock); +	list_for_each_entry(phy, &port->phy_list, port_phy_el) +		sas_phy_set_target(phy, dev); +	spin_unlock_irq(&port->phy_list_lock); +  	return 0;  } @@ -205,8 +214,7 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)  static void sas_probe_devices(struct work_struct *work)  {  	struct domain_device *dev, *n; -	struct sas_discovery_event *ev = -		container_of(work, struct sas_discovery_event, work); +	struct sas_discovery_event *ev = to_sas_discovery_event(work);  	struct asd_sas_port *port = ev->port;  	clear_bit(DISCE_PROBE, &port->disc.pending); @@ -255,6 +263,9 @@ void sas_free_device(struct kref *kref)  {  	struct domain_device *dev = container_of(kref, typeof(*dev), kref); +	put_device(&dev->rphy->dev); +	dev->rphy = NULL; +  	if (dev->parent)  		sas_put_device(dev->parent); @@ -291,8 +302,7 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d  static void sas_destruct_devices(struct work_struct *work)  {  	struct domain_device *dev, *n; -	struct sas_discovery_event *ev = -		container_of(work, struct sas_discovery_event, work); +	struct sas_discovery_event *ev = to_sas_discovery_event(work);  	struct asd_sas_port *port = ev->port;  	clear_bit(DISCE_DESTRUCT, &port->disc.pending); @@ -302,7 +312,6 @@ static void sas_destruct_devices(struct work_struct *work)  		sas_remove_children(&dev->rphy->dev);  		sas_rphy_delete(dev->rphy); -		dev->rphy = NULL;  		sas_unregister_common_dev(port, dev);  	}  } @@ -314,11 +323,11 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)  		/* this rphy never saw sas_rphy_add */  		list_del_init(&dev->disco_list_node);  		sas_rphy_free(dev->rphy); -		dev->rphy = NULL;  		sas_unregister_common_dev(port, dev); +		return;  	} -	if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { +	if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {  		sas_rphy_unlink(dev->rphy);  		list_move_tail(&dev->disco_list_node, &port->destroy_list);  		sas_discover_event(dev->port, DISCE_DESTRUCT); @@ -377,8 +386,7 @@ static void sas_discover_domain(struct work_struct *work)  {  	struct domain_device *dev;  	int error = 0; -	struct sas_discovery_event *ev = -		container_of(work, struct sas_discovery_event, work); +	struct sas_discovery_event *ev = to_sas_discovery_event(work);  	struct asd_sas_port *port = ev->port;  	clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); @@ -419,8 +427,6 @@ static void sas_discover_domain(struct work_struct *work)  	if (error) {  		sas_rphy_free(dev->rphy); -		dev->rphy = NULL; -  		list_del_init(&dev->disco_list_node);  		spin_lock_irq(&port->dev_list_lock);  		list_del_init(&dev->dev_list_node); @@ -437,8 +443,7 @@ static void sas_discover_domain(struct work_struct *work)  static void sas_revalidate_domain(struct work_struct *work)  {  	int res = 0; -	struct sas_discovery_event *ev = -		container_of(work, struct sas_discovery_event, work); +	struct sas_discovery_event *ev = to_sas_discovery_event(work);  	struct asd_sas_port *port = ev->port;  	struct sas_ha_struct *ha = port->ha; @@ -466,21 +471,25 @@ static void sas_revalidate_domain(struct work_struct *work)  /* ---------- Events ---------- */ -static void sas_chain_work(struct sas_ha_struct *ha, struct work_struct *work) +static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)  { -	/* chained work is not subject to SA_HA_DRAINING or SAS_HA_REGISTERED */ -	scsi_queue_work(ha->core.shost, work); +	/* chained work is not subject to SA_HA_DRAINING or +	 * SAS_HA_REGISTERED, because it is either submitted in the +	 * workqueue, or known to be submitted from a context that is +	 * not racing against draining +	 */ +	scsi_queue_work(ha->core.shost, &sw->work);  }  static void sas_chain_event(int event, unsigned long *pending, -			    struct work_struct *work, +			    struct sas_work *sw,  			    struct sas_ha_struct *ha)  {  	if (!test_and_set_bit(event, pending)) {  		unsigned long flags;  		spin_lock_irqsave(&ha->state_lock, flags); -		sas_chain_work(ha, work); +		sas_chain_work(ha, sw);  		spin_unlock_irqrestore(&ha->state_lock, flags);  	}  } @@ -519,7 +528,7 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)  	disc->pending = 0;  	for (i = 0; i < DISC_NUM_EVENTS; i++) { -		INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); +		INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]);  		disc->disc_work[i].port = port;  	}  }  |