RE: [PATCH v2 27/28] libsas: fix sas_find_local_phy(), take phy references

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> 
> In the direct-attached case this routine returns the phy on which this
> device was first discovered.  Which is broken if we want to support
> wide-targets, as this phy reference can become stale even though the
> port is still active.
> 
> In the expander-attached case this routine tries to lookup the phy by
> scanning the attached sas addresses of the parent expander, and BUG_ONs
> if it can't find it.  However since eh and the libsas workqueue run
> independently we can still be attempting device recovery via eh after
> libsas has recorded the device as detached.  This is even easier to hit
> now that eh is blocked while device domain rediscovery takes place, and
> that libata is fed more timed out commands increasing the chances that
> it will try to recover the ata device.
> 
> Arrange for dev->phy to always point to a last known good phy, it may be
> stale after the port is torn down, but it will catch up for wide port
> reconfigurations, and never be NULL.
> 
> Q: How is pm8001_I_T_nexus_reset getting away with not performing reset
>    on direct attached sata devices?
> 
[Jack Wang] 
We found reset may lead to some SATA disks can not be found sometime, in
fact no only for direct attached sata devices.

I wonder why we always reset the sata device when probe, for pm8001 direct
attached sata firmware will report Initial SATA FIS when phy ready.


> Cc: Jack Wang <jack_wang@xxxxxxxxx>
> Cc: Xiangliang Yu <yuxiangl@xxxxxxxxxxx>
> Cc: Luben Tuikov <ltuikov@xxxxxxxxx>
> Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
> ---
>  drivers/scsi/aic94xx/aic94xx_tmf.c  |    9 ++++++--
>  drivers/scsi/isci/task.c            |    9 +++++---
>  drivers/scsi/libsas/sas_ata.c       |    7 +++++-
>  drivers/scsi/libsas/sas_discover.c  |   24 ++++++++++++++++++++++
>  drivers/scsi/libsas/sas_expander.c  |    5 ++++-
>  drivers/scsi/libsas/sas_internal.h  |    1 +
>  drivers/scsi/libsas/sas_port.c      |    7 +++---
>  drivers/scsi/libsas/sas_scsi_host.c |   38
> +++++++++++++++++------------------
>  drivers/scsi/mvsas/mv_sas.c         |    3 ++-
>  drivers/scsi/pm8001/pm8001_sas.c    |   19 +++++++++++-------
>  drivers/scsi/scsi_transport_sas.c   |   23 +++++++++++++++++++++
>  include/scsi/libsas.h               |    9 ++++++--
>  include/scsi/scsi_transport_sas.h   |    6 ++++++
>  13 files changed, 116 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c
> b/drivers/scsi/aic94xx/aic94xx_tmf.c
> index 0add73b..50b914f 100644
> --- a/drivers/scsi/aic94xx/aic94xx_tmf.c
> +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
> @@ -181,7 +181,7 @@ static int asd_clear_nexus_I_T(struct domain_device
*dev,
>  int asd_I_T_nexus_reset(struct domain_device *dev)
>  {
>  	int res, tmp_res, i;
> -	struct sas_phy *phy = sas_find_local_phy(dev);
> +	struct sas_phy *phy = sas_get_local_phy(dev);
>  	/* Standard mandates link reset for ATA  (type 0) and
>  	 * hard reset for SSP (type 1) */
>  	int reset_type = (dev->dev_type == SATA_DEV ||
> @@ -201,7 +201,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
>  	for (i = 0 ; i < 3; i++) {
>  		tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
>  		if (tmp_res == TC_RESUME)
> -			return res;
> +			goto out;
>  		msleep(500);
>  	}
> 
> @@ -211,7 +211,10 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
>  	dev_printk(KERN_ERR, &phy->dev,
>  		   "Failed to resume nexus after reset 0x%x\n", tmp_res);
> 
> -	return TMF_RESP_FUNC_FAILED;
> +	res = TMF_RESP_FUNC_FAILED;
> + out:
> +	sas_put_local_phy(phy);
> +	return res;
>  }
> 
>  static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
> diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
> index 5901a0e..a6ab49a 100644
> --- a/drivers/scsi/isci/task.c
> +++ b/drivers/scsi/isci/task.c
> @@ -1332,7 +1332,7 @@ isci_task_request_complete(struct isci_host *ihost,
>  static int isci_reset_device(struct isci_host *ihost,
>  			     struct isci_remote_device *idev)
>  {
> -	struct sas_phy *phy = sas_find_local_phy(idev->domain_dev);
> +	struct sas_phy *phy = sas_get_local_phy(idev->domain_dev);
>  	enum sci_status status;
>  	unsigned long flags;
>  	int rc;
> @@ -1347,8 +1347,8 @@ static int isci_reset_device(struct isci_host
*ihost,
>  		dev_dbg(&ihost->pdev->dev,
>  			 "%s: sci_remote_device_reset(%p) returned %d!\n",
>  			 __func__, idev, status);
> -
> -		return TMF_RESP_FUNC_FAILED;
> +		rc = TMF_RESP_FUNC_FAILED;
> +		goto out;
>  	}
>  	spin_unlock_irqrestore(&ihost->scic_lock, flags);
> 
> @@ -1369,7 +1369,8 @@ static int isci_reset_device(struct isci_host
*ihost,
>  	}
> 
>  	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__,
idev);
> -
> + out:
> +	sas_put_local_phy(phy);
>  	return rc;
>  }
> 
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index e174a73..96f316f 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -279,9 +279,10 @@ static int smp_ata_check_ready(struct ata_link *link)
>  	struct ata_port *ap = link->ap;
>  	struct domain_device *dev = ap->private_data;
>  	struct domain_device *ex_dev = dev->parent;
> -	struct sas_phy *phy = sas_find_local_phy(dev);
> +	struct sas_phy *phy = sas_get_local_phy(dev);
> 
>  	res = sas_get_phy_attached_sas_addr(ex_dev, phy->number, addr);
> +	sas_put_local_phy(phy);
>  	/* break the wait early if the expander is unreachable,
>  	 * otherwise keep polling
>  	 */
> @@ -314,10 +315,10 @@ static int sas_ata_hard_reset(struct ata_link *link,
> unsigned int *class,
>  			      unsigned long deadline)
>  {
>  	int ret = 0, res;
> +	struct sas_phy *phy;
>  	struct ata_port *ap = link->ap;
>  	int (*check_ready)(struct ata_link *link);
>  	struct domain_device *dev = ap->private_data;
> -	struct sas_phy *phy = sas_find_local_phy(dev);
>  	struct sas_internal *i = dev_to_sas_internal(dev);
> 
>  	res = i->dft->lldd_I_T_nexus_reset(dev);
> @@ -325,10 +326,12 @@ static int sas_ata_hard_reset(struct ata_link *link,
> unsigned int *class,
>  	if (res != TMF_RESP_FUNC_COMPLETE)
>  		SAS_DPRINTK("%s: Unable to reset ata device?\n", __func__);
> 
> +	phy = sas_get_local_phy(dev);
>  	if (scsi_is_sas_phy_local(phy))
>  		check_ready = local_ata_check_ready;
>  	else
>  		check_ready = smp_ata_check_ready;
> +	sas_put_local_phy(phy);
> 
>  	ret = ata_wait_after_reset(link, deadline, check_ready);
>  	if (ret && ret != -EAGAIN)
> diff --git a/drivers/scsi/libsas/sas_discover.c
> b/drivers/scsi/libsas/sas_discover.c
> index 6e5fdfd..c765218 100644
> --- a/drivers/scsi/libsas/sas_discover.c
> +++ b/drivers/scsi/libsas/sas_discover.c
> @@ -147,6 +147,7 @@ static int sas_get_port_device(struct asd_sas_port
*port)
>  	memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
>  	memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
>  	port->disc.max_level = 0;
> +	sas_device_set_phy(dev, port->port);
> 
>  	dev->rphy = rphy;
> 
> @@ -234,6 +235,9 @@ void sas_free_device(struct kref *kref)
>  	if (dev->parent)
>  		sas_put_device(dev->parent);
> 
> +	sas_port_put_phy(dev->phy);
> +	dev->phy = NULL;
> +
>  	/* remove the phys and ports, everything else should be gone */
>  	if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV)
>  		kfree(dev->ex_dev.ex_phy);
> @@ -307,6 +311,26 @@ void sas_unregister_domain_devices(struct
asd_sas_port
> *port)
> 
>  }
> 
> +void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
> +{
> +	struct sas_ha_struct *ha;
> +	struct sas_phy *new_phy;
> +
> +	if (!dev)
> +		return;
> +
> +	ha = dev->port->ha;
> +	new_phy = sas_port_get_phy(port);
> +
> +	/* pin and record last seen phy */
> +	spin_lock_irq(&ha->phy_port_lock);
> +	if (new_phy) {
> +		sas_port_put_phy(dev->phy);
> +		dev->phy = new_phy;
> +	}
> +	spin_unlock_irq(&ha->phy_port_lock);
> +}
> +
>  /* ---------- Discovery and Revalidation ---------- */
> 
>  /**
> diff --git a/drivers/scsi/libsas/sas_expander.c
> b/drivers/scsi/libsas/sas_expander.c
> index e2efc6c..e47599b 100644
> --- a/drivers/scsi/libsas/sas_expander.c
> +++ b/drivers/scsi/libsas/sas_expander.c
> @@ -721,6 +721,7 @@ static struct domain_device *sas_ex_discover_end_dev(
>  		}
>  	}
>  	sas_ex_get_linkrate(parent, child, phy);
> +	sas_device_set_phy(child, phy->port);
> 
>  #ifdef CONFIG_SCSI_SAS_ATA
>  	if ((phy->attached_tproto & SAS_PROTOCOL_STP) ||
phy->attached_sata_dev)
> {
> @@ -1808,7 +1809,7 @@ static void sas_unregister_devs_sas_addr(struct
> domain_device *parent,
>  {
>  	struct expander_device *ex_dev = &parent->ex_dev;
>  	struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
> -	struct domain_device *child, *n;
> +	struct domain_device *child, *n, *found = NULL;
>  	if (last) {
>  		list_for_each_entry_safe(child, n,
>  			&ex_dev->children, siblings) {
> @@ -1820,6 +1821,7 @@ static void sas_unregister_devs_sas_addr(struct
> domain_device *parent,
>  					sas_unregister_ex_tree(parent->port,
child);
>  				else
>  					sas_unregister_dev(parent->port,
child);
> +				found = child;
>  				break;
>  			}
>  		}
> @@ -1828,6 +1830,7 @@ static void sas_unregister_devs_sas_addr(struct
> domain_device *parent,
>  	memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
>  	if (phy->port) {
>  		sas_port_delete_phy(phy->port, phy->phy);
> +		sas_device_set_phy(found, phy->port);
>  		if (phy->port->num_phys == 0)
>  			sas_port_delete(phy->port);
>  		phy->port = NULL;
> diff --git a/drivers/scsi/libsas/sas_internal.h
> b/drivers/scsi/libsas/sas_internal.h
> index c6317c1..eec945e 100644
> --- a/drivers/scsi/libsas/sas_internal.h
> +++ b/drivers/scsi/libsas/sas_internal.h
> @@ -85,6 +85,7 @@ int sas_smp_phy_control(struct domain_device *dev, int
> phy_id,
>  			enum phy_func phy_func, struct sas_phy_linkrates *);
>  int sas_smp_get_phy_events(struct sas_phy *phy);
> 
> +void sas_device_set_phy(struct domain_device *dev, struct sas_port
*port);
>  struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
>  struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int
> phy_id);
>  int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
> diff --git a/drivers/scsi/libsas/sas_port.c
> b/drivers/scsi/libsas/sas_port.c
> index e8e68d0..36e2905 100644
> --- a/drivers/scsi/libsas/sas_port.c
> +++ b/drivers/scsi/libsas/sas_port.c
> @@ -108,9 +108,6 @@ static void sas_form_port(struct asd_sas_phy *phy)
>  	port->num_phys++;
>  	port->phy_mask |= (1U << phy->id);
> 
> -	if (!port->phy)
> -		port->phy = phy->phy;
> -
>  	if (*(u64 *)port->attached_sas_addr == 0) {
>  		port->class = phy->class;
>  		memcpy(port->attached_sas_addr, phy->attached_sas_addr,
> @@ -175,8 +172,10 @@ void sas_deform_port(struct asd_sas_phy *phy, int
gone)
>  		sas_unregister_domain_devices(port);
>  		sas_port_delete(port->port);
>  		port->port = NULL;
> -	} else
> +	} else {
>  		sas_port_delete_phy(port->port, phy->phy);
> +		sas_device_set_phy(dev, port->port);
> +	}
> 
>  	if (si->dft->lldd_port_deformed)
>  		si->dft->lldd_port_deformed(phy);
> diff --git a/drivers/scsi/libsas/sas_scsi_host.c
> b/drivers/scsi/libsas/sas_scsi_host.c
> index b849dcd..59a227d 100644
> --- a/drivers/scsi/libsas/sas_scsi_host.c
> +++ b/drivers/scsi/libsas/sas_scsi_host.c
> @@ -439,30 +439,26 @@ static int sas_recover_I_T(struct domain_device
*dev)
>  	return res;
>  }
> 
> -/* Find the sas_phy that's attached to this device */
> -struct sas_phy *sas_find_local_phy(struct domain_device *dev)
> +/* take a reference on the last known good phy for this device */
> +struct sas_phy *sas_get_local_phy(struct domain_device *dev)
>  {
> -	struct domain_device *pdev = dev->parent;
> -	struct ex_phy *exphy = NULL;
> -	int i;
> +	struct sas_ha_struct *ha = dev->port->ha;
> +	struct sas_phy *phy;
> +	unsigned long flags;
> 
> -	/* Directly attached device */
> -	if (!pdev)
> -		return dev->port->phy;
> +	/* a published domain device always has a valid phy, it may be
> +	 * stale, but it is never NULL
> +	 */
> +	BUG_ON(!dev->phy);
> 
> -	/* Otherwise look in the expander */
> -	for (i = 0; i < pdev->ex_dev.num_phys; i++)
> -		if (!memcmp(dev->sas_addr,
> -			    pdev->ex_dev.ex_phy[i].attached_sas_addr,
> -			    SAS_ADDR_SIZE)) {
> -			exphy = &pdev->ex_dev.ex_phy[i];
> -			break;
> -		}
> +	spin_lock_irqsave(&ha->phy_port_lock, flags);
> +	phy = dev->phy;
> +	get_device(&phy->dev);
> +	spin_unlock_irqrestore(&ha->phy_port_lock, flags);
> 
> -	BUG_ON(!exphy);
> -	return exphy->phy;
> +	return phy;
>  }
> -EXPORT_SYMBOL_GPL(sas_find_local_phy);
> +EXPORT_SYMBOL_GPL(sas_get_local_phy);
> 
>  /* Attempt to send a LUN reset message to a device */
>  int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
> @@ -489,7 +485,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
>  int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
>  {
>  	struct domain_device *dev = cmd_to_domain_dev(cmd);
> -	struct sas_phy *phy = sas_find_local_phy(dev);
> +	struct sas_phy *phy = sas_get_local_phy(dev);
>  	int res;
> 
>  	res = sas_phy_reset(phy, 1);
> @@ -497,6 +493,8 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
>  		SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
>  			    kobject_name(&phy->dev.kobj),
>  			    res);
> +	sas_put_local_phy(phy);
> +
>  	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
>  		return SUCCESS;
> 
> diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
> index cd88223..b68a653 100644
> --- a/drivers/scsi/mvsas/mv_sas.c
> +++ b/drivers/scsi/mvsas/mv_sas.c
> @@ -1474,10 +1474,11 @@ static int mvs_debug_issue_ssp_tmf(struct
> domain_device *dev,
>  static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
>  {
>  	int rc;
> -	struct sas_phy *phy = sas_find_local_phy(dev);
> +	struct sas_phy *phy = sas_get_local_phy(dev);
>  	int reset_type = (dev->dev_type == SATA_DEV ||
>  			(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
>  	rc = sas_phy_reset(phy, reset_type);
> +	sas_put_local_phy(phy);
>  	msleep(2000);
>  	return rc;
>  }
> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
> b/drivers/scsi/pm8001/pm8001_sas.c
> index 5add18c..b111018 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.c
> +++ b/drivers/scsi/pm8001/pm8001_sas.c
> @@ -873,12 +873,14 @@ int pm8001_I_T_nexus_reset(struct domain_device
*dev)
> 
>  	pm8001_dev = dev->lldd_dev;
>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
> -	phy = sas_find_local_phy(dev);
> +	phy = sas_get_local_phy(dev);
> 
>  	if (dev_is_sata(dev)) {
>  		DECLARE_COMPLETION_ONSTACK(completion_setstate);
> -		if (scsi_is_sas_phy_local(phy))
> -			return 0;
> +		if (scsi_is_sas_phy_local(phy)) {
> +			rc = 0;
> +			goto out;
> +		}
>  		rc = sas_phy_reset(phy, 1);
>  		msleep(2000);
>  		rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
> @@ -887,12 +889,14 @@ int pm8001_I_T_nexus_reset(struct domain_device
*dev)
>  		rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
>  			pm8001_dev, 0x01);
>  		wait_for_completion(&completion_setstate);
> -	} else{
> -	rc = sas_phy_reset(phy, 1);
> -	msleep(2000);
> +	} else {
> +		rc = sas_phy_reset(phy, 1);
> +		msleep(2000);
>  	}
>  	PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n",
>  		pm8001_dev->device_id, rc));
> + out:
> +	sas_put_local_phy(phy);
>  	return rc;
>  }
> 
> @@ -904,10 +908,11 @@ int pm8001_lu_reset(struct domain_device *dev, u8
*lun)
>  	struct pm8001_device *pm8001_dev = dev->lldd_dev;
>  	struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
>  	if (dev_is_sata(dev)) {
> -		struct sas_phy *phy = sas_find_local_phy(dev);
> +		struct sas_phy *phy = sas_get_local_phy(dev);
>  		rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>  			dev, 1, 0);
>  		rc = sas_phy_reset(phy, 1);
> +		sas_put_local_phy(phy);
>  		rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
>  			pm8001_dev, 0x01);
>  		msleep(2000);
> diff --git a/drivers/scsi/scsi_transport_sas.c
> b/drivers/scsi/scsi_transport_sas.c
> index ab3bd0b..7d69a25 100644
> --- a/drivers/scsi/scsi_transport_sas.c
> +++ b/drivers/scsi/scsi_transport_sas.c
> @@ -1060,6 +1060,29 @@ int scsi_is_sas_port(const struct device *dev)
>  EXPORT_SYMBOL(scsi_is_sas_port);
> 
>  /**
> + * sas_port_get_phy - try to take a reference on a port member
> + * @port: port to check
> + */
> +struct sas_phy *sas_port_get_phy(struct sas_port *port)
> +{
> +	struct sas_phy *phy;
> +
> +	mutex_lock(&port->phy_list_mutex);
> +	if (list_empty(&port->phy_list))
> +		phy = NULL;
> +	else {
> +		struct list_head *ent = port->phy_list.next;
> +
> +		phy = list_entry(ent, typeof(*phy), port_siblings);
> +		get_device(&phy->dev);
> +	}
> +	mutex_unlock(&port->phy_list_mutex);
> +
> +	return phy;
> +}
> +EXPORT_SYMBOL(sas_port_get_phy);
> +
> +/**
>   * sas_port_add_phy - add another phy to a port to form a wide port
>   * @port:	port to add the phy to
>   * @phy:	phy to add
> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
> index 3c9849c..571e7fc 100644
> --- a/include/scsi/libsas.h
> +++ b/include/scsi/libsas.h
> @@ -188,6 +188,7 @@ struct domain_device {
>          struct domain_device *parent;
>          struct list_head siblings; /* devices on the same level */
>          struct asd_sas_port *port;        /* shortcut to root of the tree
*/
> +	struct sas_phy *phy;
> 
>          struct list_head dev_list_node;
>  	struct list_head disco_list_node;
> @@ -239,7 +240,6 @@ struct asd_sas_port {
>  	struct list_head destroy_list;
>  	enum   sas_linkrate linkrate;
> 
> -	struct sas_phy *phy;
>  	struct work_struct work;
> 
>  /* public: */
> @@ -424,6 +424,11 @@ static inline unsigned int to_sas_gpio_od(int device,
int
> bit)
>  	return 3 * device + bit;
>  }
> 
> +static inline void sas_put_local_phy(struct sas_phy *phy)
> +{
> +	put_device(&phy->dev);
> +}
> +
>  #ifdef CONFIG_SCSI_SAS_HOST_SMP
>  int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8
count);
>  #else
> @@ -679,7 +684,7 @@ extern int sas_smp_handler(struct Scsi_Host *shost,
struct
> sas_rphy *rphy,
> 
>  extern void sas_ssp_task_response(struct device *dev, struct sas_task
*task,
>  				  struct ssp_response_iu *iu);
> -struct sas_phy *sas_find_local_phy(struct domain_device *dev);
> +struct sas_phy *sas_get_local_phy(struct domain_device *dev);
> 
>  int sas_request_addr(struct Scsi_Host *shost, u8 *addr);
> 
> diff --git a/include/scsi/scsi_transport_sas.h
> b/include/scsi/scsi_transport_sas.h
> index 42817fa..98b3a20 100644
> --- a/include/scsi/scsi_transport_sas.h
> +++ b/include/scsi/scsi_transport_sas.h
> @@ -209,6 +209,12 @@ void sas_port_add_phy(struct sas_port *, struct
sas_phy
> *);
>  void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
>  void sas_port_mark_backlink(struct sas_port *);
>  int scsi_is_sas_port(const struct device *);
> +struct sas_phy *sas_port_get_phy(struct sas_port *port);
> +static inline void sas_port_put_phy(struct sas_phy *phy)
> +{
> +	if (phy)
> +		put_device(&phy->dev);
> +}
> 
>  extern struct scsi_transport_template *
>  sas_attach_transport(struct sas_function_template *);
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux