18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Dell Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Serial Attached SCSI (SAS) transport class.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * The SAS transport class contains common code to deal with SAS HBAs,
88c2ecf20Sopenharmony_ci * an aproximated representation of SAS topologies in the driver model,
98c2ecf20Sopenharmony_ci * and various sysfs attributes to expose these topologies and management
108c2ecf20Sopenharmony_ci * interfaces to userspace.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * In addition to the basic SCSI core objects this transport class
138c2ecf20Sopenharmony_ci * introduces two additional intermediate objects:  The SAS PHY
148c2ecf20Sopenharmony_ci * as represented by struct sas_phy defines an "outgoing" PHY on
158c2ecf20Sopenharmony_ci * a SAS HBA or Expander, and the SAS remote PHY represented by
168c2ecf20Sopenharmony_ci * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
178c2ecf20Sopenharmony_ci * end device.  Note that this is purely a software concept, the
188c2ecf20Sopenharmony_ci * underlying hardware for a PHY and a remote PHY is the exactly
198c2ecf20Sopenharmony_ci * the same.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * There is no concept of a SAS port in this code, users can see
228c2ecf20Sopenharmony_ci * what PHYs form a wide port based on the port_identifier attribute,
238c2ecf20Sopenharmony_ci * which is the same for all PHYs in a port.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/init.h>
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
298c2ecf20Sopenharmony_ci#include <linux/err.h>
308c2ecf20Sopenharmony_ci#include <linux/slab.h>
318c2ecf20Sopenharmony_ci#include <linux/string.h>
328c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
338c2ecf20Sopenharmony_ci#include <linux/bsg.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
368c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
378c2ecf20Sopenharmony_ci#include <scsi/scsi_request.h>
388c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
398c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
408c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h>
418c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_sas.h>
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include "scsi_sas_internal.h"
448c2ecf20Sopenharmony_cistruct sas_host_attrs {
458c2ecf20Sopenharmony_ci	struct list_head rphy_list;
468c2ecf20Sopenharmony_ci	struct mutex lock;
478c2ecf20Sopenharmony_ci	struct request_queue *q;
488c2ecf20Sopenharmony_ci	u32 next_target_id;
498c2ecf20Sopenharmony_ci	u32 next_expander_id;
508c2ecf20Sopenharmony_ci	int next_port_id;
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci#define to_sas_host_attrs(host)	((struct sas_host_attrs *)(host)->shost_data)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * Hack to allow attributes of the same name in different objects.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_ci#define SAS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
598c2ecf20Sopenharmony_ci	struct device_attribute dev_attr_##_prefix##_##_name = \
608c2ecf20Sopenharmony_ci	__ATTR(_name,_mode,_show,_store)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci * Pretty printing helpers
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define sas_bitfield_name_match(title, table)			\
688c2ecf20Sopenharmony_cistatic ssize_t							\
698c2ecf20Sopenharmony_ciget_sas_##title##_names(u32 table_key, char *buf)		\
708c2ecf20Sopenharmony_ci{								\
718c2ecf20Sopenharmony_ci	char *prefix = "";					\
728c2ecf20Sopenharmony_ci	ssize_t len = 0;					\
738c2ecf20Sopenharmony_ci	int i;							\
748c2ecf20Sopenharmony_ci								\
758c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
768c2ecf20Sopenharmony_ci		if (table[i].value & table_key) {		\
778c2ecf20Sopenharmony_ci			len += sprintf(buf + len, "%s%s",	\
788c2ecf20Sopenharmony_ci				prefix, table[i].name);		\
798c2ecf20Sopenharmony_ci			prefix = ", ";				\
808c2ecf20Sopenharmony_ci		}						\
818c2ecf20Sopenharmony_ci	}							\
828c2ecf20Sopenharmony_ci	len += sprintf(buf + len, "\n");			\
838c2ecf20Sopenharmony_ci	return len;						\
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define sas_bitfield_name_set(title, table)			\
878c2ecf20Sopenharmony_cistatic ssize_t							\
888c2ecf20Sopenharmony_ciset_sas_##title##_names(u32 *table_key, const char *buf)	\
898c2ecf20Sopenharmony_ci{								\
908c2ecf20Sopenharmony_ci	ssize_t len = 0;					\
918c2ecf20Sopenharmony_ci	int i;							\
928c2ecf20Sopenharmony_ci								\
938c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
948c2ecf20Sopenharmony_ci		len = strlen(table[i].name);			\
958c2ecf20Sopenharmony_ci		if (strncmp(buf, table[i].name, len) == 0 &&	\
968c2ecf20Sopenharmony_ci		    (buf[len] == '\n' || buf[len] == '\0')) {	\
978c2ecf20Sopenharmony_ci			*table_key = table[i].value;		\
988c2ecf20Sopenharmony_ci			return 0;				\
998c2ecf20Sopenharmony_ci		}						\
1008c2ecf20Sopenharmony_ci	}							\
1018c2ecf20Sopenharmony_ci	return -EINVAL;						\
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define sas_bitfield_name_search(title, table)			\
1058c2ecf20Sopenharmony_cistatic ssize_t							\
1068c2ecf20Sopenharmony_ciget_sas_##title##_names(u32 table_key, char *buf)		\
1078c2ecf20Sopenharmony_ci{								\
1088c2ecf20Sopenharmony_ci	ssize_t len = 0;					\
1098c2ecf20Sopenharmony_ci	int i;							\
1108c2ecf20Sopenharmony_ci								\
1118c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
1128c2ecf20Sopenharmony_ci		if (table[i].value == table_key) {		\
1138c2ecf20Sopenharmony_ci			len += sprintf(buf + len, "%s",		\
1148c2ecf20Sopenharmony_ci				table[i].name);			\
1158c2ecf20Sopenharmony_ci			break;					\
1168c2ecf20Sopenharmony_ci		}						\
1178c2ecf20Sopenharmony_ci	}							\
1188c2ecf20Sopenharmony_ci	len += sprintf(buf + len, "\n");			\
1198c2ecf20Sopenharmony_ci	return len;						\
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic struct {
1238c2ecf20Sopenharmony_ci	u32		value;
1248c2ecf20Sopenharmony_ci	char		*name;
1258c2ecf20Sopenharmony_ci} sas_device_type_names[] = {
1268c2ecf20Sopenharmony_ci	{ SAS_PHY_UNUSED,		"unused" },
1278c2ecf20Sopenharmony_ci	{ SAS_END_DEVICE,		"end device" },
1288c2ecf20Sopenharmony_ci	{ SAS_EDGE_EXPANDER_DEVICE,	"edge expander" },
1298c2ecf20Sopenharmony_ci	{ SAS_FANOUT_EXPANDER_DEVICE,	"fanout expander" },
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_cisas_bitfield_name_search(device_type, sas_device_type_names)
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct {
1358c2ecf20Sopenharmony_ci	u32		value;
1368c2ecf20Sopenharmony_ci	char		*name;
1378c2ecf20Sopenharmony_ci} sas_protocol_names[] = {
1388c2ecf20Sopenharmony_ci	{ SAS_PROTOCOL_SATA,		"sata" },
1398c2ecf20Sopenharmony_ci	{ SAS_PROTOCOL_SMP,		"smp" },
1408c2ecf20Sopenharmony_ci	{ SAS_PROTOCOL_STP,		"stp" },
1418c2ecf20Sopenharmony_ci	{ SAS_PROTOCOL_SSP,		"ssp" },
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_cisas_bitfield_name_match(protocol, sas_protocol_names)
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic struct {
1468c2ecf20Sopenharmony_ci	u32		value;
1478c2ecf20Sopenharmony_ci	char		*name;
1488c2ecf20Sopenharmony_ci} sas_linkspeed_names[] = {
1498c2ecf20Sopenharmony_ci	{ SAS_LINK_RATE_UNKNOWN,	"Unknown" },
1508c2ecf20Sopenharmony_ci	{ SAS_PHY_DISABLED,		"Phy disabled" },
1518c2ecf20Sopenharmony_ci	{ SAS_LINK_RATE_FAILED,		"Link Rate failed" },
1528c2ecf20Sopenharmony_ci	{ SAS_SATA_SPINUP_HOLD,		"Spin-up hold" },
1538c2ecf20Sopenharmony_ci	{ SAS_LINK_RATE_1_5_GBPS,	"1.5 Gbit" },
1548c2ecf20Sopenharmony_ci	{ SAS_LINK_RATE_3_0_GBPS,	"3.0 Gbit" },
1558c2ecf20Sopenharmony_ci	{ SAS_LINK_RATE_6_0_GBPS,	"6.0 Gbit" },
1568c2ecf20Sopenharmony_ci	{ SAS_LINK_RATE_12_0_GBPS,	"12.0 Gbit" },
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_cisas_bitfield_name_search(linkspeed, sas_linkspeed_names)
1598c2ecf20Sopenharmony_cisas_bitfield_name_set(linkspeed, sas_linkspeed_names)
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
1648c2ecf20Sopenharmony_ci	struct sas_end_device *rdev;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	rdev = rphy_to_end_device(rphy);
1698c2ecf20Sopenharmony_ci	return rdev;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic int sas_smp_dispatch(struct bsg_job *job)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(job->dev);
1758c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = NULL;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (!scsi_is_host_device(job->dev))
1788c2ecf20Sopenharmony_ci		rphy = dev_to_rphy(job->dev);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (!job->reply_payload.payload_len) {
1818c2ecf20Sopenharmony_ci		dev_warn(job->dev, "space for a smp response is missing\n");
1828c2ecf20Sopenharmony_ci		bsg_job_done(job, -EINVAL, 0);
1838c2ecf20Sopenharmony_ci		return 0;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	to_sas_internal(shost->transportt)->f->smp_handler(job, shost, rphy);
1878c2ecf20Sopenharmony_ci	return 0;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct request_queue *q;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (!to_sas_internal(shost->transportt)->f->smp_handler) {
1958c2ecf20Sopenharmony_ci		printk("%s can't handle SMP requests\n", shost->hostt->name);
1968c2ecf20Sopenharmony_ci		return 0;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (rphy) {
2008c2ecf20Sopenharmony_ci		q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev),
2018c2ecf20Sopenharmony_ci				sas_smp_dispatch, NULL, 0);
2028c2ecf20Sopenharmony_ci		if (IS_ERR(q))
2038c2ecf20Sopenharmony_ci			return PTR_ERR(q);
2048c2ecf20Sopenharmony_ci		rphy->q = q;
2058c2ecf20Sopenharmony_ci	} else {
2068c2ecf20Sopenharmony_ci		char name[20];
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		snprintf(name, sizeof(name), "sas_host%d", shost->host_no);
2098c2ecf20Sopenharmony_ci		q = bsg_setup_queue(&shost->shost_gendev, name,
2108c2ecf20Sopenharmony_ci				sas_smp_dispatch, NULL, 0);
2118c2ecf20Sopenharmony_ci		if (IS_ERR(q))
2128c2ecf20Sopenharmony_ci			return PTR_ERR(q);
2138c2ecf20Sopenharmony_ci		to_sas_host_attrs(shost)->q = q;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	return 0;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/*
2208c2ecf20Sopenharmony_ci * SAS host attributes
2218c2ecf20Sopenharmony_ci */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int sas_host_setup(struct transport_container *tc, struct device *dev,
2248c2ecf20Sopenharmony_ci			  struct device *cdev)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(dev);
2278c2ecf20Sopenharmony_ci	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sas_host->rphy_list);
2308c2ecf20Sopenharmony_ci	mutex_init(&sas_host->lock);
2318c2ecf20Sopenharmony_ci	sas_host->next_target_id = 0;
2328c2ecf20Sopenharmony_ci	sas_host->next_expander_id = 0;
2338c2ecf20Sopenharmony_ci	sas_host->next_port_id = 0;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (sas_bsg_initialize(shost, NULL))
2368c2ecf20Sopenharmony_ci		dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
2378c2ecf20Sopenharmony_ci			   shost->host_no);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int sas_host_remove(struct transport_container *tc, struct device *dev,
2438c2ecf20Sopenharmony_ci			   struct device *cdev)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(dev);
2468c2ecf20Sopenharmony_ci	struct request_queue *q = to_sas_host_attrs(shost)->q;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	bsg_remove_queue(q);
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic DECLARE_TRANSPORT_CLASS(sas_host_class,
2538c2ecf20Sopenharmony_ci		"sas_host", sas_host_setup, sas_host_remove, NULL);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int sas_host_match(struct attribute_container *cont,
2568c2ecf20Sopenharmony_ci			    struct device *dev)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
2598c2ecf20Sopenharmony_ci	struct sas_internal *i;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (!scsi_is_host_device(dev))
2628c2ecf20Sopenharmony_ci		return 0;
2638c2ecf20Sopenharmony_ci	shost = dev_to_shost(dev);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (!shost->transportt)
2668c2ecf20Sopenharmony_ci		return 0;
2678c2ecf20Sopenharmony_ci	if (shost->transportt->host_attrs.ac.class !=
2688c2ecf20Sopenharmony_ci			&sas_host_class.class)
2698c2ecf20Sopenharmony_ci		return 0;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	i = to_sas_internal(shost->transportt);
2728c2ecf20Sopenharmony_ci	return &i->t.host_attrs.ac == cont;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int do_sas_phy_delete(struct device *dev, void *data)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int pass = (int)(unsigned long)data;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (pass == 0 && scsi_is_sas_port(dev))
2808c2ecf20Sopenharmony_ci		sas_port_delete(dev_to_sas_port(dev));
2818c2ecf20Sopenharmony_ci	else if (pass == 1 && scsi_is_sas_phy(dev))
2828c2ecf20Sopenharmony_ci		sas_phy_delete(dev_to_phy(dev));
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/**
2878c2ecf20Sopenharmony_ci * sas_remove_children  -  tear down a devices SAS data structures
2888c2ecf20Sopenharmony_ci * @dev:	device belonging to the sas object
2898c2ecf20Sopenharmony_ci *
2908c2ecf20Sopenharmony_ci * Removes all SAS PHYs and remote PHYs for a given object
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_civoid sas_remove_children(struct device *dev)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	device_for_each_child(dev, (void *)0, do_sas_phy_delete);
2958c2ecf20Sopenharmony_ci	device_for_each_child(dev, (void *)1, do_sas_phy_delete);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_remove_children);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/**
3008c2ecf20Sopenharmony_ci * sas_remove_host  -  tear down a Scsi_Host's SAS data structures
3018c2ecf20Sopenharmony_ci * @shost:	Scsi Host that is torn down
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * Removes all SAS PHYs and remote PHYs for a given Scsi_Host and remove the
3048c2ecf20Sopenharmony_ci * Scsi_Host as well.
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * Note: Do not call scsi_remove_host() on the Scsi_Host any more, as it is
3078c2ecf20Sopenharmony_ci * already removed.
3088c2ecf20Sopenharmony_ci */
3098c2ecf20Sopenharmony_civoid sas_remove_host(struct Scsi_Host *shost)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	sas_remove_children(&shost->shost_gendev);
3128c2ecf20Sopenharmony_ci	scsi_remove_host(shost);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_remove_host);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/**
3178c2ecf20Sopenharmony_ci * sas_get_address - return the SAS address of the device
3188c2ecf20Sopenharmony_ci * @sdev: scsi device
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * Returns the SAS address of the scsi device
3218c2ecf20Sopenharmony_ci */
3228c2ecf20Sopenharmony_ciu64 sas_get_address(struct scsi_device *sdev)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return rdev->rphy.identify.sas_address;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_get_address);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci/**
3318c2ecf20Sopenharmony_ci * sas_tlr_supported - checking TLR bit in vpd 0x90
3328c2ecf20Sopenharmony_ci * @sdev: scsi device struct
3338c2ecf20Sopenharmony_ci *
3348c2ecf20Sopenharmony_ci * Check Transport Layer Retries are supported or not.
3358c2ecf20Sopenharmony_ci * If vpd page 0x90 is present, TRL is supported.
3368c2ecf20Sopenharmony_ci *
3378c2ecf20Sopenharmony_ci */
3388c2ecf20Sopenharmony_ciunsigned int
3398c2ecf20Sopenharmony_cisas_tlr_supported(struct scsi_device *sdev)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	const int vpd_len = 32;
3428c2ecf20Sopenharmony_ci	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
3438c2ecf20Sopenharmony_ci	char *buffer = kzalloc(vpd_len, GFP_KERNEL);
3448c2ecf20Sopenharmony_ci	int ret = 0;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (!buffer)
3478c2ecf20Sopenharmony_ci		goto out;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))
3508c2ecf20Sopenharmony_ci		goto out;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * Magic numbers: the VPD Protocol page (0x90)
3548c2ecf20Sopenharmony_ci	 * has a 4 byte header and then one entry per device port
3558c2ecf20Sopenharmony_ci	 * the TLR bit is at offset 8 on each port entry
3568c2ecf20Sopenharmony_ci	 * if we take the first port, that's at total offset 12
3578c2ecf20Sopenharmony_ci	 */
3588c2ecf20Sopenharmony_ci	ret = buffer[12] & 0x01;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci out:
3618c2ecf20Sopenharmony_ci	kfree(buffer);
3628c2ecf20Sopenharmony_ci	rdev->tlr_supported = ret;
3638c2ecf20Sopenharmony_ci	return ret;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sas_tlr_supported);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci/**
3698c2ecf20Sopenharmony_ci * sas_disable_tlr - setting TLR flags
3708c2ecf20Sopenharmony_ci * @sdev: scsi device struct
3718c2ecf20Sopenharmony_ci *
3728c2ecf20Sopenharmony_ci * Seting tlr_enabled flag to 0.
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci */
3758c2ecf20Sopenharmony_civoid
3768c2ecf20Sopenharmony_cisas_disable_tlr(struct scsi_device *sdev)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	rdev->tlr_enabled = 0;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sas_disable_tlr);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/**
3858c2ecf20Sopenharmony_ci * sas_enable_tlr - setting TLR flags
3868c2ecf20Sopenharmony_ci * @sdev: scsi device struct
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci * Seting tlr_enabled flag 1.
3898c2ecf20Sopenharmony_ci *
3908c2ecf20Sopenharmony_ci */
3918c2ecf20Sopenharmony_civoid sas_enable_tlr(struct scsi_device *sdev)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	unsigned int tlr_supported = 0;
3948c2ecf20Sopenharmony_ci	tlr_supported  = sas_tlr_supported(sdev);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (tlr_supported) {
3978c2ecf20Sopenharmony_ci		struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		rdev->tlr_enabled = 1;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sas_enable_tlr);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ciunsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
4098c2ecf20Sopenharmony_ci	return rdev->tlr_enabled;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci/*
4148c2ecf20Sopenharmony_ci * SAS Phy attributes
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci#define sas_phy_show_simple(field, name, format_string, cast)		\
4188c2ecf20Sopenharmony_cistatic ssize_t								\
4198c2ecf20Sopenharmony_cishow_sas_phy_##name(struct device *dev, 				\
4208c2ecf20Sopenharmony_ci		    struct device_attribute *attr, char *buf)		\
4218c2ecf20Sopenharmony_ci{									\
4228c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);		\
4238c2ecf20Sopenharmony_ci									\
4248c2ecf20Sopenharmony_ci	return snprintf(buf, 20, format_string, cast phy->field);	\
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci#define sas_phy_simple_attr(field, name, format_string, type)		\
4288c2ecf20Sopenharmony_ci	sas_phy_show_simple(field, name, format_string, (type))	\
4298c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci#define sas_phy_show_protocol(field, name)				\
4328c2ecf20Sopenharmony_cistatic ssize_t								\
4338c2ecf20Sopenharmony_cishow_sas_phy_##name(struct device *dev, 				\
4348c2ecf20Sopenharmony_ci		    struct device_attribute *attr, char *buf)		\
4358c2ecf20Sopenharmony_ci{									\
4368c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);		\
4378c2ecf20Sopenharmony_ci									\
4388c2ecf20Sopenharmony_ci	if (!phy->field)						\
4398c2ecf20Sopenharmony_ci		return snprintf(buf, 20, "none\n");			\
4408c2ecf20Sopenharmony_ci	return get_sas_protocol_names(phy->field, buf);		\
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci#define sas_phy_protocol_attr(field, name)				\
4448c2ecf20Sopenharmony_ci	sas_phy_show_protocol(field, name)				\
4458c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci#define sas_phy_show_linkspeed(field)					\
4488c2ecf20Sopenharmony_cistatic ssize_t								\
4498c2ecf20Sopenharmony_cishow_sas_phy_##field(struct device *dev, 				\
4508c2ecf20Sopenharmony_ci		     struct device_attribute *attr, char *buf)		\
4518c2ecf20Sopenharmony_ci{									\
4528c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);		\
4538c2ecf20Sopenharmony_ci									\
4548c2ecf20Sopenharmony_ci	return get_sas_linkspeed_names(phy->field, buf);		\
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci/* Fudge to tell if we're minimum or maximum */
4588c2ecf20Sopenharmony_ci#define sas_phy_store_linkspeed(field)					\
4598c2ecf20Sopenharmony_cistatic ssize_t								\
4608c2ecf20Sopenharmony_cistore_sas_phy_##field(struct device *dev, 				\
4618c2ecf20Sopenharmony_ci		      struct device_attribute *attr, 			\
4628c2ecf20Sopenharmony_ci		      const char *buf,	size_t count)			\
4638c2ecf20Sopenharmony_ci{									\
4648c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);		\
4658c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);	\
4668c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);	\
4678c2ecf20Sopenharmony_ci	u32 value;							\
4688c2ecf20Sopenharmony_ci	struct sas_phy_linkrates rates = {0};				\
4698c2ecf20Sopenharmony_ci	int error;							\
4708c2ecf20Sopenharmony_ci									\
4718c2ecf20Sopenharmony_ci	error = set_sas_linkspeed_names(&value, buf);			\
4728c2ecf20Sopenharmony_ci	if (error)							\
4738c2ecf20Sopenharmony_ci		return error;						\
4748c2ecf20Sopenharmony_ci	rates.field = value;						\
4758c2ecf20Sopenharmony_ci	error = i->f->set_phy_speed(phy, &rates);			\
4768c2ecf20Sopenharmony_ci									\
4778c2ecf20Sopenharmony_ci	return error ? error : count;					\
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci#define sas_phy_linkspeed_rw_attr(field)				\
4818c2ecf20Sopenharmony_ci	sas_phy_show_linkspeed(field)					\
4828c2ecf20Sopenharmony_ci	sas_phy_store_linkspeed(field)					\
4838c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field,		\
4848c2ecf20Sopenharmony_ci	store_sas_phy_##field)
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci#define sas_phy_linkspeed_attr(field)					\
4878c2ecf20Sopenharmony_ci	sas_phy_show_linkspeed(field)					\
4888c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci#define sas_phy_show_linkerror(field)					\
4928c2ecf20Sopenharmony_cistatic ssize_t								\
4938c2ecf20Sopenharmony_cishow_sas_phy_##field(struct device *dev, 				\
4948c2ecf20Sopenharmony_ci		     struct device_attribute *attr, char *buf)		\
4958c2ecf20Sopenharmony_ci{									\
4968c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);		\
4978c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);	\
4988c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);	\
4998c2ecf20Sopenharmony_ci	int error;							\
5008c2ecf20Sopenharmony_ci									\
5018c2ecf20Sopenharmony_ci	error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0;	\
5028c2ecf20Sopenharmony_ci	if (error)							\
5038c2ecf20Sopenharmony_ci		return error;						\
5048c2ecf20Sopenharmony_ci	return snprintf(buf, 20, "%u\n", phy->field);			\
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci#define sas_phy_linkerror_attr(field)					\
5088c2ecf20Sopenharmony_ci	sas_phy_show_linkerror(field)					\
5098c2ecf20Sopenharmony_cistatic DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic ssize_t
5138c2ecf20Sopenharmony_cishow_sas_device_type(struct device *dev,
5148c2ecf20Sopenharmony_ci		     struct device_attribute *attr, char *buf)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (!phy->identify.device_type)
5198c2ecf20Sopenharmony_ci		return snprintf(buf, 20, "none\n");
5208c2ecf20Sopenharmony_ci	return get_sas_device_type_names(phy->identify.device_type, buf);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_cistatic DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic ssize_t do_sas_phy_enable(struct device *dev,
5258c2ecf20Sopenharmony_ci		size_t count, int enable)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);
5288c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
5298c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);
5308c2ecf20Sopenharmony_ci	int error;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	error = i->f->phy_enable(phy, enable);
5338c2ecf20Sopenharmony_ci	if (error)
5348c2ecf20Sopenharmony_ci		return error;
5358c2ecf20Sopenharmony_ci	phy->enabled = enable;
5368c2ecf20Sopenharmony_ci	return count;
5378c2ecf20Sopenharmony_ci};
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic ssize_t
5408c2ecf20Sopenharmony_cistore_sas_phy_enable(struct device *dev, struct device_attribute *attr,
5418c2ecf20Sopenharmony_ci		     const char *buf, size_t count)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	if (count < 1)
5448c2ecf20Sopenharmony_ci		return -EINVAL;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	switch (buf[0]) {
5478c2ecf20Sopenharmony_ci	case '0':
5488c2ecf20Sopenharmony_ci		do_sas_phy_enable(dev, count, 0);
5498c2ecf20Sopenharmony_ci		break;
5508c2ecf20Sopenharmony_ci	case '1':
5518c2ecf20Sopenharmony_ci		do_sas_phy_enable(dev, count, 1);
5528c2ecf20Sopenharmony_ci		break;
5538c2ecf20Sopenharmony_ci	default:
5548c2ecf20Sopenharmony_ci		return -EINVAL;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return count;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic ssize_t
5618c2ecf20Sopenharmony_cishow_sas_phy_enable(struct device *dev, struct device_attribute *attr,
5628c2ecf20Sopenharmony_ci		    char *buf)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	return snprintf(buf, 20, "%d\n", phy->enabled);
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,
5708c2ecf20Sopenharmony_ci			 store_sas_phy_enable);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic ssize_t
5738c2ecf20Sopenharmony_cido_sas_phy_reset(struct device *dev, size_t count, int hard_reset)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct sas_phy *phy = transport_class_to_phy(dev);
5768c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
5778c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);
5788c2ecf20Sopenharmony_ci	int error;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	error = i->f->phy_reset(phy, hard_reset);
5818c2ecf20Sopenharmony_ci	if (error)
5828c2ecf20Sopenharmony_ci		return error;
5838c2ecf20Sopenharmony_ci	phy->enabled = 1;
5848c2ecf20Sopenharmony_ci	return count;
5858c2ecf20Sopenharmony_ci};
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic ssize_t
5888c2ecf20Sopenharmony_cistore_sas_link_reset(struct device *dev, struct device_attribute *attr,
5898c2ecf20Sopenharmony_ci		     const char *buf, size_t count)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	return do_sas_phy_reset(dev, count, 0);
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_cistatic DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic ssize_t
5968c2ecf20Sopenharmony_cistore_sas_hard_reset(struct device *dev, struct device_attribute *attr,
5978c2ecf20Sopenharmony_ci		     const char *buf, size_t count)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	return do_sas_phy_reset(dev, count, 1);
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_cistatic DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cisas_phy_protocol_attr(identify.initiator_port_protocols,
6048c2ecf20Sopenharmony_ci		initiator_port_protocols);
6058c2ecf20Sopenharmony_cisas_phy_protocol_attr(identify.target_port_protocols,
6068c2ecf20Sopenharmony_ci		target_port_protocols);
6078c2ecf20Sopenharmony_cisas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
6088c2ecf20Sopenharmony_ci		unsigned long long);
6098c2ecf20Sopenharmony_cisas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
6108c2ecf20Sopenharmony_cisas_phy_linkspeed_attr(negotiated_linkrate);
6118c2ecf20Sopenharmony_cisas_phy_linkspeed_attr(minimum_linkrate_hw);
6128c2ecf20Sopenharmony_cisas_phy_linkspeed_rw_attr(minimum_linkrate);
6138c2ecf20Sopenharmony_cisas_phy_linkspeed_attr(maximum_linkrate_hw);
6148c2ecf20Sopenharmony_cisas_phy_linkspeed_rw_attr(maximum_linkrate);
6158c2ecf20Sopenharmony_cisas_phy_linkerror_attr(invalid_dword_count);
6168c2ecf20Sopenharmony_cisas_phy_linkerror_attr(running_disparity_error_count);
6178c2ecf20Sopenharmony_cisas_phy_linkerror_attr(loss_of_dword_sync_count);
6188c2ecf20Sopenharmony_cisas_phy_linkerror_attr(phy_reset_problem_count);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic int sas_phy_setup(struct transport_container *tc, struct device *dev,
6218c2ecf20Sopenharmony_ci			 struct device *cdev)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct sas_phy *phy = dev_to_phy(dev);
6248c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
6258c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (i->f->phy_setup)
6288c2ecf20Sopenharmony_ci		i->f->phy_setup(phy);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	return 0;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic DECLARE_TRANSPORT_CLASS(sas_phy_class,
6348c2ecf20Sopenharmony_ci		"sas_phy", sas_phy_setup, NULL, NULL);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic int sas_phy_match(struct attribute_container *cont, struct device *dev)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
6398c2ecf20Sopenharmony_ci	struct sas_internal *i;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (!scsi_is_sas_phy(dev))
6428c2ecf20Sopenharmony_ci		return 0;
6438c2ecf20Sopenharmony_ci	shost = dev_to_shost(dev->parent);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (!shost->transportt)
6468c2ecf20Sopenharmony_ci		return 0;
6478c2ecf20Sopenharmony_ci	if (shost->transportt->host_attrs.ac.class !=
6488c2ecf20Sopenharmony_ci			&sas_host_class.class)
6498c2ecf20Sopenharmony_ci		return 0;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	i = to_sas_internal(shost->transportt);
6528c2ecf20Sopenharmony_ci	return &i->phy_attr_cont.ac == cont;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic void sas_phy_release(struct device *dev)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct sas_phy *phy = dev_to_phy(dev);
6588c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
6598c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (i->f->phy_release)
6628c2ecf20Sopenharmony_ci		i->f->phy_release(phy);
6638c2ecf20Sopenharmony_ci	put_device(dev->parent);
6648c2ecf20Sopenharmony_ci	kfree(phy);
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci/**
6688c2ecf20Sopenharmony_ci * sas_phy_alloc  -  allocates and initialize a SAS PHY structure
6698c2ecf20Sopenharmony_ci * @parent:	Parent device
6708c2ecf20Sopenharmony_ci * @number:	Phy index
6718c2ecf20Sopenharmony_ci *
6728c2ecf20Sopenharmony_ci * Allocates an SAS PHY structure.  It will be added in the device tree
6738c2ecf20Sopenharmony_ci * below the device specified by @parent, which has to be either a Scsi_Host
6748c2ecf20Sopenharmony_ci * or sas_rphy.
6758c2ecf20Sopenharmony_ci *
6768c2ecf20Sopenharmony_ci * Returns:
6778c2ecf20Sopenharmony_ci *	SAS PHY allocated or %NULL if the allocation failed.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistruct sas_phy *sas_phy_alloc(struct device *parent, int number)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(parent);
6828c2ecf20Sopenharmony_ci	struct sas_phy *phy;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
6858c2ecf20Sopenharmony_ci	if (!phy)
6868c2ecf20Sopenharmony_ci		return NULL;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	phy->number = number;
6898c2ecf20Sopenharmony_ci	phy->enabled = 1;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	device_initialize(&phy->dev);
6928c2ecf20Sopenharmony_ci	phy->dev.parent = get_device(parent);
6938c2ecf20Sopenharmony_ci	phy->dev.release = sas_phy_release;
6948c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&phy->port_siblings);
6958c2ecf20Sopenharmony_ci	if (scsi_is_sas_expander_device(parent)) {
6968c2ecf20Sopenharmony_ci		struct sas_rphy *rphy = dev_to_rphy(parent);
6978c2ecf20Sopenharmony_ci		dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no,
6988c2ecf20Sopenharmony_ci			rphy->scsi_target_id, number);
6998c2ecf20Sopenharmony_ci	} else
7008c2ecf20Sopenharmony_ci		dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	transport_setup_device(&phy->dev);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	return phy;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_phy_alloc);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci/**
7098c2ecf20Sopenharmony_ci * sas_phy_add  -  add a SAS PHY to the device hierarchy
7108c2ecf20Sopenharmony_ci * @phy:	The PHY to be added
7118c2ecf20Sopenharmony_ci *
7128c2ecf20Sopenharmony_ci * Publishes a SAS PHY to the rest of the system.
7138c2ecf20Sopenharmony_ci */
7148c2ecf20Sopenharmony_ciint sas_phy_add(struct sas_phy *phy)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	int error;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	error = device_add(&phy->dev);
7198c2ecf20Sopenharmony_ci	if (error)
7208c2ecf20Sopenharmony_ci		return error;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	error = transport_add_device(&phy->dev);
7238c2ecf20Sopenharmony_ci	if (error) {
7248c2ecf20Sopenharmony_ci		device_del(&phy->dev);
7258c2ecf20Sopenharmony_ci		return error;
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci	transport_configure_device(&phy->dev);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	return 0;
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_phy_add);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci/**
7348c2ecf20Sopenharmony_ci * sas_phy_free  -  free a SAS PHY
7358c2ecf20Sopenharmony_ci * @phy:	SAS PHY to free
7368c2ecf20Sopenharmony_ci *
7378c2ecf20Sopenharmony_ci * Frees the specified SAS PHY.
7388c2ecf20Sopenharmony_ci *
7398c2ecf20Sopenharmony_ci * Note:
7408c2ecf20Sopenharmony_ci *   This function must only be called on a PHY that has not
7418c2ecf20Sopenharmony_ci *   successfully been added using sas_phy_add().
7428c2ecf20Sopenharmony_ci */
7438c2ecf20Sopenharmony_civoid sas_phy_free(struct sas_phy *phy)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	transport_destroy_device(&phy->dev);
7468c2ecf20Sopenharmony_ci	put_device(&phy->dev);
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_phy_free);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci/**
7518c2ecf20Sopenharmony_ci * sas_phy_delete  -  remove SAS PHY
7528c2ecf20Sopenharmony_ci * @phy:	SAS PHY to remove
7538c2ecf20Sopenharmony_ci *
7548c2ecf20Sopenharmony_ci * Removes the specified SAS PHY.  If the SAS PHY has an
7558c2ecf20Sopenharmony_ci * associated remote PHY it is removed before.
7568c2ecf20Sopenharmony_ci */
7578c2ecf20Sopenharmony_civoid
7588c2ecf20Sopenharmony_cisas_phy_delete(struct sas_phy *phy)
7598c2ecf20Sopenharmony_ci{
7608c2ecf20Sopenharmony_ci	struct device *dev = &phy->dev;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* this happens if the phy is still part of a port when deleted */
7638c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&phy->port_siblings));
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	transport_remove_device(dev);
7668c2ecf20Sopenharmony_ci	device_del(dev);
7678c2ecf20Sopenharmony_ci	transport_destroy_device(dev);
7688c2ecf20Sopenharmony_ci	put_device(dev);
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_phy_delete);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci/**
7738c2ecf20Sopenharmony_ci * scsi_is_sas_phy  -  check if a struct device represents a SAS PHY
7748c2ecf20Sopenharmony_ci * @dev:	device to check
7758c2ecf20Sopenharmony_ci *
7768c2ecf20Sopenharmony_ci * Returns:
7778c2ecf20Sopenharmony_ci *	%1 if the device represents a SAS PHY, %0 else
7788c2ecf20Sopenharmony_ci */
7798c2ecf20Sopenharmony_ciint scsi_is_sas_phy(const struct device *dev)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	return dev->release == sas_phy_release;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_is_sas_phy);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci/*
7868c2ecf20Sopenharmony_ci * SAS Port attributes
7878c2ecf20Sopenharmony_ci */
7888c2ecf20Sopenharmony_ci#define sas_port_show_simple(field, name, format_string, cast)		\
7898c2ecf20Sopenharmony_cistatic ssize_t								\
7908c2ecf20Sopenharmony_cishow_sas_port_##name(struct device *dev, 				\
7918c2ecf20Sopenharmony_ci		     struct device_attribute *attr, char *buf)		\
7928c2ecf20Sopenharmony_ci{									\
7938c2ecf20Sopenharmony_ci	struct sas_port *port = transport_class_to_sas_port(dev);	\
7948c2ecf20Sopenharmony_ci									\
7958c2ecf20Sopenharmony_ci	return snprintf(buf, 20, format_string, cast port->field);	\
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci#define sas_port_simple_attr(field, name, format_string, type)		\
7998c2ecf20Sopenharmony_ci	sas_port_show_simple(field, name, format_string, (type))	\
8008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cisas_port_simple_attr(num_phys, num_phys, "%d\n", int);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic DECLARE_TRANSPORT_CLASS(sas_port_class,
8058c2ecf20Sopenharmony_ci			       "sas_port", NULL, NULL, NULL);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic int sas_port_match(struct attribute_container *cont, struct device *dev)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
8108c2ecf20Sopenharmony_ci	struct sas_internal *i;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (!scsi_is_sas_port(dev))
8138c2ecf20Sopenharmony_ci		return 0;
8148c2ecf20Sopenharmony_ci	shost = dev_to_shost(dev->parent);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (!shost->transportt)
8178c2ecf20Sopenharmony_ci		return 0;
8188c2ecf20Sopenharmony_ci	if (shost->transportt->host_attrs.ac.class !=
8198c2ecf20Sopenharmony_ci			&sas_host_class.class)
8208c2ecf20Sopenharmony_ci		return 0;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	i = to_sas_internal(shost->transportt);
8238c2ecf20Sopenharmony_ci	return &i->port_attr_cont.ac == cont;
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic void sas_port_release(struct device *dev)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	struct sas_port *port = dev_to_sas_port(dev);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&port->phy_list));
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	put_device(dev->parent);
8348c2ecf20Sopenharmony_ci	kfree(port);
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic void sas_port_create_link(struct sas_port *port,
8388c2ecf20Sopenharmony_ci				 struct sas_phy *phy)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	int res;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,
8438c2ecf20Sopenharmony_ci				dev_name(&phy->dev));
8448c2ecf20Sopenharmony_ci	if (res)
8458c2ecf20Sopenharmony_ci		goto err;
8468c2ecf20Sopenharmony_ci	res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
8478c2ecf20Sopenharmony_ci	if (res)
8488c2ecf20Sopenharmony_ci		goto err;
8498c2ecf20Sopenharmony_ci	return;
8508c2ecf20Sopenharmony_cierr:
8518c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s: Cannot create port links, err=%d\n",
8528c2ecf20Sopenharmony_ci	       __func__, res);
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic void sas_port_delete_link(struct sas_port *port,
8568c2ecf20Sopenharmony_ci				 struct sas_phy *phy)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev));
8598c2ecf20Sopenharmony_ci	sysfs_remove_link(&phy->dev.kobj, "port");
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci/** sas_port_alloc - allocate and initialize a SAS port structure
8638c2ecf20Sopenharmony_ci *
8648c2ecf20Sopenharmony_ci * @parent:	parent device
8658c2ecf20Sopenharmony_ci * @port_id:	port number
8668c2ecf20Sopenharmony_ci *
8678c2ecf20Sopenharmony_ci * Allocates a SAS port structure.  It will be added to the device tree
8688c2ecf20Sopenharmony_ci * below the device specified by @parent which must be either a Scsi_Host
8698c2ecf20Sopenharmony_ci * or a sas_expander_device.
8708c2ecf20Sopenharmony_ci *
8718c2ecf20Sopenharmony_ci * Returns %NULL on error
8728c2ecf20Sopenharmony_ci */
8738c2ecf20Sopenharmony_cistruct sas_port *sas_port_alloc(struct device *parent, int port_id)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(parent);
8768c2ecf20Sopenharmony_ci	struct sas_port *port;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	port = kzalloc(sizeof(*port), GFP_KERNEL);
8798c2ecf20Sopenharmony_ci	if (!port)
8808c2ecf20Sopenharmony_ci		return NULL;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	port->port_identifier = port_id;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	device_initialize(&port->dev);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	port->dev.parent = get_device(parent);
8878c2ecf20Sopenharmony_ci	port->dev.release = sas_port_release;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	mutex_init(&port->phy_list_mutex);
8908c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&port->phy_list);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (scsi_is_sas_expander_device(parent)) {
8938c2ecf20Sopenharmony_ci		struct sas_rphy *rphy = dev_to_rphy(parent);
8948c2ecf20Sopenharmony_ci		dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no,
8958c2ecf20Sopenharmony_ci			     rphy->scsi_target_id, port->port_identifier);
8968c2ecf20Sopenharmony_ci	} else
8978c2ecf20Sopenharmony_ci		dev_set_name(&port->dev, "port-%d:%d", shost->host_no,
8988c2ecf20Sopenharmony_ci			     port->port_identifier);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	transport_setup_device(&port->dev);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return port;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_alloc);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci/** sas_port_alloc_num - allocate and initialize a SAS port structure
9078c2ecf20Sopenharmony_ci *
9088c2ecf20Sopenharmony_ci * @parent:	parent device
9098c2ecf20Sopenharmony_ci *
9108c2ecf20Sopenharmony_ci * Allocates a SAS port structure and a number to go with it.  This
9118c2ecf20Sopenharmony_ci * interface is really for adapters where the port number has no
9128c2ecf20Sopenharmony_ci * meansing, so the sas class should manage them.  It will be added to
9138c2ecf20Sopenharmony_ci * the device tree below the device specified by @parent which must be
9148c2ecf20Sopenharmony_ci * either a Scsi_Host or a sas_expander_device.
9158c2ecf20Sopenharmony_ci *
9168c2ecf20Sopenharmony_ci * Returns %NULL on error
9178c2ecf20Sopenharmony_ci */
9188c2ecf20Sopenharmony_cistruct sas_port *sas_port_alloc_num(struct device *parent)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	int index;
9218c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(parent);
9228c2ecf20Sopenharmony_ci	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	/* FIXME: use idr for this eventually */
9258c2ecf20Sopenharmony_ci	mutex_lock(&sas_host->lock);
9268c2ecf20Sopenharmony_ci	if (scsi_is_sas_expander_device(parent)) {
9278c2ecf20Sopenharmony_ci		struct sas_rphy *rphy = dev_to_rphy(parent);
9288c2ecf20Sopenharmony_ci		struct sas_expander_device *exp = rphy_to_expander_device(rphy);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		index = exp->next_port_id++;
9318c2ecf20Sopenharmony_ci	} else
9328c2ecf20Sopenharmony_ci		index = sas_host->next_port_id++;
9338c2ecf20Sopenharmony_ci	mutex_unlock(&sas_host->lock);
9348c2ecf20Sopenharmony_ci	return sas_port_alloc(parent, index);
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_alloc_num);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci/**
9398c2ecf20Sopenharmony_ci * sas_port_add - add a SAS port to the device hierarchy
9408c2ecf20Sopenharmony_ci * @port:	port to be added
9418c2ecf20Sopenharmony_ci *
9428c2ecf20Sopenharmony_ci * publishes a port to the rest of the system
9438c2ecf20Sopenharmony_ci */
9448c2ecf20Sopenharmony_ciint sas_port_add(struct sas_port *port)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	int error;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/* No phys should be added until this is made visible */
9498c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&port->phy_list));
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	error = device_add(&port->dev);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	if (error)
9548c2ecf20Sopenharmony_ci		return error;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	transport_add_device(&port->dev);
9578c2ecf20Sopenharmony_ci	transport_configure_device(&port->dev);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	return 0;
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_add);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci/**
9648c2ecf20Sopenharmony_ci * sas_port_free  -  free a SAS PORT
9658c2ecf20Sopenharmony_ci * @port:	SAS PORT to free
9668c2ecf20Sopenharmony_ci *
9678c2ecf20Sopenharmony_ci * Frees the specified SAS PORT.
9688c2ecf20Sopenharmony_ci *
9698c2ecf20Sopenharmony_ci * Note:
9708c2ecf20Sopenharmony_ci *   This function must only be called on a PORT that has not
9718c2ecf20Sopenharmony_ci *   successfully been added using sas_port_add().
9728c2ecf20Sopenharmony_ci */
9738c2ecf20Sopenharmony_civoid sas_port_free(struct sas_port *port)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	transport_destroy_device(&port->dev);
9768c2ecf20Sopenharmony_ci	put_device(&port->dev);
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_free);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci/**
9818c2ecf20Sopenharmony_ci * sas_port_delete  -  remove SAS PORT
9828c2ecf20Sopenharmony_ci * @port:	SAS PORT to remove
9838c2ecf20Sopenharmony_ci *
9848c2ecf20Sopenharmony_ci * Removes the specified SAS PORT.  If the SAS PORT has an
9858c2ecf20Sopenharmony_ci * associated phys, unlink them from the port as well.
9868c2ecf20Sopenharmony_ci */
9878c2ecf20Sopenharmony_civoid sas_port_delete(struct sas_port *port)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct device *dev = &port->dev;
9908c2ecf20Sopenharmony_ci	struct sas_phy *phy, *tmp_phy;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (port->rphy) {
9938c2ecf20Sopenharmony_ci		sas_rphy_delete(port->rphy);
9948c2ecf20Sopenharmony_ci		port->rphy = NULL;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	mutex_lock(&port->phy_list_mutex);
9988c2ecf20Sopenharmony_ci	list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
9998c2ecf20Sopenharmony_ci				 port_siblings) {
10008c2ecf20Sopenharmony_ci		sas_port_delete_link(port, phy);
10018c2ecf20Sopenharmony_ci		list_del_init(&phy->port_siblings);
10028c2ecf20Sopenharmony_ci	}
10038c2ecf20Sopenharmony_ci	mutex_unlock(&port->phy_list_mutex);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (port->is_backlink) {
10068c2ecf20Sopenharmony_ci		struct device *parent = port->dev.parent;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci		sysfs_remove_link(&port->dev.kobj, dev_name(parent));
10098c2ecf20Sopenharmony_ci		port->is_backlink = 0;
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	transport_remove_device(dev);
10138c2ecf20Sopenharmony_ci	device_del(dev);
10148c2ecf20Sopenharmony_ci	transport_destroy_device(dev);
10158c2ecf20Sopenharmony_ci	put_device(dev);
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_delete);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci/**
10208c2ecf20Sopenharmony_ci * scsi_is_sas_port -  check if a struct device represents a SAS port
10218c2ecf20Sopenharmony_ci * @dev:	device to check
10228c2ecf20Sopenharmony_ci *
10238c2ecf20Sopenharmony_ci * Returns:
10248c2ecf20Sopenharmony_ci *	%1 if the device represents a SAS Port, %0 else
10258c2ecf20Sopenharmony_ci */
10268c2ecf20Sopenharmony_ciint scsi_is_sas_port(const struct device *dev)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	return dev->release == sas_port_release;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_is_sas_port);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci/**
10338c2ecf20Sopenharmony_ci * sas_port_get_phy - try to take a reference on a port member
10348c2ecf20Sopenharmony_ci * @port: port to check
10358c2ecf20Sopenharmony_ci */
10368c2ecf20Sopenharmony_cistruct sas_phy *sas_port_get_phy(struct sas_port *port)
10378c2ecf20Sopenharmony_ci{
10388c2ecf20Sopenharmony_ci	struct sas_phy *phy;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	mutex_lock(&port->phy_list_mutex);
10418c2ecf20Sopenharmony_ci	if (list_empty(&port->phy_list))
10428c2ecf20Sopenharmony_ci		phy = NULL;
10438c2ecf20Sopenharmony_ci	else {
10448c2ecf20Sopenharmony_ci		struct list_head *ent = port->phy_list.next;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci		phy = list_entry(ent, typeof(*phy), port_siblings);
10478c2ecf20Sopenharmony_ci		get_device(&phy->dev);
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci	mutex_unlock(&port->phy_list_mutex);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	return phy;
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_get_phy);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci/**
10568c2ecf20Sopenharmony_ci * sas_port_add_phy - add another phy to a port to form a wide port
10578c2ecf20Sopenharmony_ci * @port:	port to add the phy to
10588c2ecf20Sopenharmony_ci * @phy:	phy to add
10598c2ecf20Sopenharmony_ci *
10608c2ecf20Sopenharmony_ci * When a port is initially created, it is empty (has no phys).  All
10618c2ecf20Sopenharmony_ci * ports must have at least one phy to operated, and all wide ports
10628c2ecf20Sopenharmony_ci * must have at least two.  The current code makes no difference
10638c2ecf20Sopenharmony_ci * between ports and wide ports, but the only object that can be
10648c2ecf20Sopenharmony_ci * connected to a remote device is a port, so ports must be formed on
10658c2ecf20Sopenharmony_ci * all devices with phys if they're connected to anything.
10668c2ecf20Sopenharmony_ci */
10678c2ecf20Sopenharmony_civoid sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
10688c2ecf20Sopenharmony_ci{
10698c2ecf20Sopenharmony_ci	mutex_lock(&port->phy_list_mutex);
10708c2ecf20Sopenharmony_ci	if (unlikely(!list_empty(&phy->port_siblings))) {
10718c2ecf20Sopenharmony_ci		/* make sure we're already on this port */
10728c2ecf20Sopenharmony_ci		struct sas_phy *tmp;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci		list_for_each_entry(tmp, &port->phy_list, port_siblings)
10758c2ecf20Sopenharmony_ci			if (tmp == phy)
10768c2ecf20Sopenharmony_ci				break;
10778c2ecf20Sopenharmony_ci		/* If this trips, you added a phy that was already
10788c2ecf20Sopenharmony_ci		 * part of a different port */
10798c2ecf20Sopenharmony_ci		if (unlikely(tmp != phy)) {
10808c2ecf20Sopenharmony_ci			dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n",
10818c2ecf20Sopenharmony_ci				   dev_name(&phy->dev));
10828c2ecf20Sopenharmony_ci			BUG();
10838c2ecf20Sopenharmony_ci		}
10848c2ecf20Sopenharmony_ci	} else {
10858c2ecf20Sopenharmony_ci		sas_port_create_link(port, phy);
10868c2ecf20Sopenharmony_ci		list_add_tail(&phy->port_siblings, &port->phy_list);
10878c2ecf20Sopenharmony_ci		port->num_phys++;
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci	mutex_unlock(&port->phy_list_mutex);
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_add_phy);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci/**
10948c2ecf20Sopenharmony_ci * sas_port_delete_phy - remove a phy from a port or wide port
10958c2ecf20Sopenharmony_ci * @port:	port to remove the phy from
10968c2ecf20Sopenharmony_ci * @phy:	phy to remove
10978c2ecf20Sopenharmony_ci *
10988c2ecf20Sopenharmony_ci * This operation is used for tearing down ports again.  It must be
10998c2ecf20Sopenharmony_ci * done to every port or wide port before calling sas_port_delete.
11008c2ecf20Sopenharmony_ci */
11018c2ecf20Sopenharmony_civoid sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	mutex_lock(&port->phy_list_mutex);
11048c2ecf20Sopenharmony_ci	sas_port_delete_link(port, phy);
11058c2ecf20Sopenharmony_ci	list_del_init(&phy->port_siblings);
11068c2ecf20Sopenharmony_ci	port->num_phys--;
11078c2ecf20Sopenharmony_ci	mutex_unlock(&port->phy_list_mutex);
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_delete_phy);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_civoid sas_port_mark_backlink(struct sas_port *port)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	int res;
11148c2ecf20Sopenharmony_ci	struct device *parent = port->dev.parent->parent->parent;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	if (port->is_backlink)
11178c2ecf20Sopenharmony_ci		return;
11188c2ecf20Sopenharmony_ci	port->is_backlink = 1;
11198c2ecf20Sopenharmony_ci	res = sysfs_create_link(&port->dev.kobj, &parent->kobj,
11208c2ecf20Sopenharmony_ci				dev_name(parent));
11218c2ecf20Sopenharmony_ci	if (res)
11228c2ecf20Sopenharmony_ci		goto err;
11238c2ecf20Sopenharmony_ci	return;
11248c2ecf20Sopenharmony_cierr:
11258c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",
11268c2ecf20Sopenharmony_ci	       __func__, res);
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_port_mark_backlink);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci/*
11328c2ecf20Sopenharmony_ci * SAS remote PHY attributes.
11338c2ecf20Sopenharmony_ci */
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci#define sas_rphy_show_simple(field, name, format_string, cast)		\
11368c2ecf20Sopenharmony_cistatic ssize_t								\
11378c2ecf20Sopenharmony_cishow_sas_rphy_##name(struct device *dev, 				\
11388c2ecf20Sopenharmony_ci		     struct device_attribute *attr, char *buf)		\
11398c2ecf20Sopenharmony_ci{									\
11408c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
11418c2ecf20Sopenharmony_ci									\
11428c2ecf20Sopenharmony_ci	return snprintf(buf, 20, format_string, cast rphy->field);	\
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci#define sas_rphy_simple_attr(field, name, format_string, type)		\
11468c2ecf20Sopenharmony_ci	sas_rphy_show_simple(field, name, format_string, (type))	\
11478c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(rphy, name, S_IRUGO, 			\
11488c2ecf20Sopenharmony_ci		show_sas_rphy_##name, NULL)
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci#define sas_rphy_show_protocol(field, name)				\
11518c2ecf20Sopenharmony_cistatic ssize_t								\
11528c2ecf20Sopenharmony_cishow_sas_rphy_##name(struct device *dev, 				\
11538c2ecf20Sopenharmony_ci		     struct device_attribute *attr, char *buf)		\
11548c2ecf20Sopenharmony_ci{									\
11558c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
11568c2ecf20Sopenharmony_ci									\
11578c2ecf20Sopenharmony_ci	if (!rphy->field)					\
11588c2ecf20Sopenharmony_ci		return snprintf(buf, 20, "none\n");			\
11598c2ecf20Sopenharmony_ci	return get_sas_protocol_names(rphy->field, buf);	\
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci#define sas_rphy_protocol_attr(field, name)				\
11638c2ecf20Sopenharmony_ci	sas_rphy_show_protocol(field, name)				\
11648c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(rphy, name, S_IRUGO,			\
11658c2ecf20Sopenharmony_ci		show_sas_rphy_##name, NULL)
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_cistatic ssize_t
11688c2ecf20Sopenharmony_cishow_sas_rphy_device_type(struct device *dev,
11698c2ecf20Sopenharmony_ci			  struct device_attribute *attr, char *buf)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	if (!rphy->identify.device_type)
11748c2ecf20Sopenharmony_ci		return snprintf(buf, 20, "none\n");
11758c2ecf20Sopenharmony_ci	return get_sas_device_type_names(
11768c2ecf20Sopenharmony_ci			rphy->identify.device_type, buf);
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
11808c2ecf20Sopenharmony_ci		show_sas_rphy_device_type, NULL);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_cistatic ssize_t
11838c2ecf20Sopenharmony_cishow_sas_rphy_enclosure_identifier(struct device *dev,
11848c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);
11878c2ecf20Sopenharmony_ci	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
11888c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
11898c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);
11908c2ecf20Sopenharmony_ci	u64 identifier;
11918c2ecf20Sopenharmony_ci	int error;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	error = i->f->get_enclosure_identifier(rphy, &identifier);
11948c2ecf20Sopenharmony_ci	if (error)
11958c2ecf20Sopenharmony_ci		return error;
11968c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
12008c2ecf20Sopenharmony_ci		show_sas_rphy_enclosure_identifier, NULL);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic ssize_t
12038c2ecf20Sopenharmony_cishow_sas_rphy_bay_identifier(struct device *dev,
12048c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);
12078c2ecf20Sopenharmony_ci	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
12088c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
12098c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(shost->transportt);
12108c2ecf20Sopenharmony_ci	int val;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	val = i->f->get_bay_identifier(rphy);
12138c2ecf20Sopenharmony_ci	if (val < 0)
12148c2ecf20Sopenharmony_ci		return val;
12158c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", val);
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
12198c2ecf20Sopenharmony_ci		show_sas_rphy_bay_identifier, NULL);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_cisas_rphy_protocol_attr(identify.initiator_port_protocols,
12228c2ecf20Sopenharmony_ci		initiator_port_protocols);
12238c2ecf20Sopenharmony_cisas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
12248c2ecf20Sopenharmony_cisas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
12258c2ecf20Sopenharmony_ci		unsigned long long);
12268c2ecf20Sopenharmony_cisas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
12278c2ecf20Sopenharmony_cisas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d\n", u32);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci/* only need 8 bytes of data plus header (4 or 8) */
12308c2ecf20Sopenharmony_ci#define BUF_SIZE 64
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ciint sas_read_port_mode_page(struct scsi_device *sdev)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
12358c2ecf20Sopenharmony_ci	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
12368c2ecf20Sopenharmony_ci	struct scsi_mode_data mode_data;
12378c2ecf20Sopenharmony_ci	int error;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	if (!buffer)
12408c2ecf20Sopenharmony_ci		return -ENOMEM;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	error = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
12438c2ecf20Sopenharmony_ci				&mode_data, NULL);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	if (error)
12468c2ecf20Sopenharmony_ci		goto out;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	msdata = buffer +  mode_data.header_length +
12498c2ecf20Sopenharmony_ci		mode_data.block_descriptor_length;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	if (msdata - buffer > BUF_SIZE - 8)
12528c2ecf20Sopenharmony_ci		goto out;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	error = 0;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
12578c2ecf20Sopenharmony_ci	rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
12588c2ecf20Sopenharmony_ci	rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci out:
12618c2ecf20Sopenharmony_ci	kfree(buffer);
12628c2ecf20Sopenharmony_ci	return error;
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_read_port_mode_page);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
12678c2ecf20Sopenharmony_ci			       "sas_end_device", NULL, NULL, NULL);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci#define sas_end_dev_show_simple(field, name, format_string, cast)	\
12708c2ecf20Sopenharmony_cistatic ssize_t								\
12718c2ecf20Sopenharmony_cishow_sas_end_dev_##name(struct device *dev, 				\
12728c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)	\
12738c2ecf20Sopenharmony_ci{									\
12748c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
12758c2ecf20Sopenharmony_ci	struct sas_end_device *rdev = rphy_to_end_device(rphy);		\
12768c2ecf20Sopenharmony_ci									\
12778c2ecf20Sopenharmony_ci	return snprintf(buf, 20, format_string, cast rdev->field);	\
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci#define sas_end_dev_simple_attr(field, name, format_string, type)	\
12818c2ecf20Sopenharmony_ci	sas_end_dev_show_simple(field, name, format_string, (type))	\
12828c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(end_dev, name, S_IRUGO, 			\
12838c2ecf20Sopenharmony_ci		show_sas_end_dev_##name, NULL)
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cisas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);
12868c2ecf20Sopenharmony_cisas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
12878c2ecf20Sopenharmony_ci			"%d\n", int);
12888c2ecf20Sopenharmony_cisas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
12898c2ecf20Sopenharmony_ci			"%d\n", int);
12908c2ecf20Sopenharmony_cisas_end_dev_simple_attr(tlr_supported, tlr_supported,
12918c2ecf20Sopenharmony_ci			"%d\n", int);
12928c2ecf20Sopenharmony_cisas_end_dev_simple_attr(tlr_enabled, tlr_enabled,
12938c2ecf20Sopenharmony_ci			"%d\n", int);
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_cistatic DECLARE_TRANSPORT_CLASS(sas_expander_class,
12968c2ecf20Sopenharmony_ci			       "sas_expander", NULL, NULL, NULL);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci#define sas_expander_show_simple(field, name, format_string, cast)	\
12998c2ecf20Sopenharmony_cistatic ssize_t								\
13008c2ecf20Sopenharmony_cishow_sas_expander_##name(struct device *dev, 				\
13018c2ecf20Sopenharmony_ci			 struct device_attribute *attr, char *buf)	\
13028c2ecf20Sopenharmony_ci{									\
13038c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
13048c2ecf20Sopenharmony_ci	struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
13058c2ecf20Sopenharmony_ci									\
13068c2ecf20Sopenharmony_ci	return snprintf(buf, 20, format_string, cast edev->field);	\
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci#define sas_expander_simple_attr(field, name, format_string, type)	\
13108c2ecf20Sopenharmony_ci	sas_expander_show_simple(field, name, format_string, (type))	\
13118c2ecf20Sopenharmony_cistatic SAS_DEVICE_ATTR(expander, name, S_IRUGO, 			\
13128c2ecf20Sopenharmony_ci		show_sas_expander_##name, NULL)
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_cisas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);
13158c2ecf20Sopenharmony_cisas_expander_simple_attr(product_id, product_id, "%s\n", char *);
13168c2ecf20Sopenharmony_cisas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);
13178c2ecf20Sopenharmony_cisas_expander_simple_attr(component_vendor_id, component_vendor_id,
13188c2ecf20Sopenharmony_ci			 "%s\n", char *);
13198c2ecf20Sopenharmony_cisas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);
13208c2ecf20Sopenharmony_cisas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",
13218c2ecf20Sopenharmony_ci			 unsigned int);
13228c2ecf20Sopenharmony_cisas_expander_simple_attr(level, level, "%d\n", int);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_cistatic DECLARE_TRANSPORT_CLASS(sas_rphy_class,
13258c2ecf20Sopenharmony_ci		"sas_device", NULL, NULL, NULL);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_cistatic int sas_rphy_match(struct attribute_container *cont, struct device *dev)
13288c2ecf20Sopenharmony_ci{
13298c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
13308c2ecf20Sopenharmony_ci	struct sas_internal *i;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	if (!scsi_is_sas_rphy(dev))
13338c2ecf20Sopenharmony_ci		return 0;
13348c2ecf20Sopenharmony_ci	shost = dev_to_shost(dev->parent->parent);
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	if (!shost->transportt)
13378c2ecf20Sopenharmony_ci		return 0;
13388c2ecf20Sopenharmony_ci	if (shost->transportt->host_attrs.ac.class !=
13398c2ecf20Sopenharmony_ci			&sas_host_class.class)
13408c2ecf20Sopenharmony_ci		return 0;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	i = to_sas_internal(shost->transportt);
13438c2ecf20Sopenharmony_ci	return &i->rphy_attr_cont.ac == cont;
13448c2ecf20Sopenharmony_ci}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic int sas_end_dev_match(struct attribute_container *cont,
13478c2ecf20Sopenharmony_ci			     struct device *dev)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
13508c2ecf20Sopenharmony_ci	struct sas_internal *i;
13518c2ecf20Sopenharmony_ci	struct sas_rphy *rphy;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	if (!scsi_is_sas_rphy(dev))
13548c2ecf20Sopenharmony_ci		return 0;
13558c2ecf20Sopenharmony_ci	shost = dev_to_shost(dev->parent->parent);
13568c2ecf20Sopenharmony_ci	rphy = dev_to_rphy(dev);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	if (!shost->transportt)
13598c2ecf20Sopenharmony_ci		return 0;
13608c2ecf20Sopenharmony_ci	if (shost->transportt->host_attrs.ac.class !=
13618c2ecf20Sopenharmony_ci			&sas_host_class.class)
13628c2ecf20Sopenharmony_ci		return 0;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	i = to_sas_internal(shost->transportt);
13658c2ecf20Sopenharmony_ci	return &i->end_dev_attr_cont.ac == cont &&
13668c2ecf20Sopenharmony_ci		rphy->identify.device_type == SAS_END_DEVICE;
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cistatic int sas_expander_match(struct attribute_container *cont,
13708c2ecf20Sopenharmony_ci			      struct device *dev)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
13738c2ecf20Sopenharmony_ci	struct sas_internal *i;
13748c2ecf20Sopenharmony_ci	struct sas_rphy *rphy;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	if (!scsi_is_sas_rphy(dev))
13778c2ecf20Sopenharmony_ci		return 0;
13788c2ecf20Sopenharmony_ci	shost = dev_to_shost(dev->parent->parent);
13798c2ecf20Sopenharmony_ci	rphy = dev_to_rphy(dev);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	if (!shost->transportt)
13828c2ecf20Sopenharmony_ci		return 0;
13838c2ecf20Sopenharmony_ci	if (shost->transportt->host_attrs.ac.class !=
13848c2ecf20Sopenharmony_ci			&sas_host_class.class)
13858c2ecf20Sopenharmony_ci		return 0;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	i = to_sas_internal(shost->transportt);
13888c2ecf20Sopenharmony_ci	return &i->expander_attr_cont.ac == cont &&
13898c2ecf20Sopenharmony_ci		(rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
13908c2ecf20Sopenharmony_ci		 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cistatic void sas_expander_release(struct device *dev)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = dev_to_rphy(dev);
13968c2ecf20Sopenharmony_ci	struct sas_expander_device *edev = rphy_to_expander_device(rphy);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	put_device(dev->parent);
13998c2ecf20Sopenharmony_ci	kfree(edev);
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_cistatic void sas_end_device_release(struct device *dev)
14038c2ecf20Sopenharmony_ci{
14048c2ecf20Sopenharmony_ci	struct sas_rphy *rphy = dev_to_rphy(dev);
14058c2ecf20Sopenharmony_ci	struct sas_end_device *edev = rphy_to_end_device(rphy);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	put_device(dev->parent);
14088c2ecf20Sopenharmony_ci	kfree(edev);
14098c2ecf20Sopenharmony_ci}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci/**
14128c2ecf20Sopenharmony_ci * sas_rphy_initialize - common rphy initialization
14138c2ecf20Sopenharmony_ci * @rphy:	rphy to initialise
14148c2ecf20Sopenharmony_ci *
14158c2ecf20Sopenharmony_ci * Used by both sas_end_device_alloc() and sas_expander_alloc() to
14168c2ecf20Sopenharmony_ci * initialise the common rphy component of each.
14178c2ecf20Sopenharmony_ci */
14188c2ecf20Sopenharmony_cistatic void sas_rphy_initialize(struct sas_rphy *rphy)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rphy->list);
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci/**
14248c2ecf20Sopenharmony_ci * sas_end_device_alloc - allocate an rphy for an end device
14258c2ecf20Sopenharmony_ci * @parent: which port
14268c2ecf20Sopenharmony_ci *
14278c2ecf20Sopenharmony_ci * Allocates an SAS remote PHY structure, connected to @parent.
14288c2ecf20Sopenharmony_ci *
14298c2ecf20Sopenharmony_ci * Returns:
14308c2ecf20Sopenharmony_ci *	SAS PHY allocated or %NULL if the allocation failed.
14318c2ecf20Sopenharmony_ci */
14328c2ecf20Sopenharmony_cistruct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
14358c2ecf20Sopenharmony_ci	struct sas_end_device *rdev;
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
14388c2ecf20Sopenharmony_ci	if (!rdev) {
14398c2ecf20Sopenharmony_ci		return NULL;
14408c2ecf20Sopenharmony_ci	}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	device_initialize(&rdev->rphy.dev);
14438c2ecf20Sopenharmony_ci	rdev->rphy.dev.parent = get_device(&parent->dev);
14448c2ecf20Sopenharmony_ci	rdev->rphy.dev.release = sas_end_device_release;
14458c2ecf20Sopenharmony_ci	if (scsi_is_sas_expander_device(parent->dev.parent)) {
14468c2ecf20Sopenharmony_ci		struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
14478c2ecf20Sopenharmony_ci		dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d",
14488c2ecf20Sopenharmony_ci			     shost->host_no, rphy->scsi_target_id,
14498c2ecf20Sopenharmony_ci			     parent->port_identifier);
14508c2ecf20Sopenharmony_ci	} else
14518c2ecf20Sopenharmony_ci		dev_set_name(&rdev->rphy.dev, "end_device-%d:%d",
14528c2ecf20Sopenharmony_ci			     shost->host_no, parent->port_identifier);
14538c2ecf20Sopenharmony_ci	rdev->rphy.identify.device_type = SAS_END_DEVICE;
14548c2ecf20Sopenharmony_ci	sas_rphy_initialize(&rdev->rphy);
14558c2ecf20Sopenharmony_ci	transport_setup_device(&rdev->rphy.dev);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	return &rdev->rphy;
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_end_device_alloc);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci/**
14628c2ecf20Sopenharmony_ci * sas_expander_alloc - allocate an rphy for an end device
14638c2ecf20Sopenharmony_ci * @parent: which port
14648c2ecf20Sopenharmony_ci * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
14658c2ecf20Sopenharmony_ci *
14668c2ecf20Sopenharmony_ci * Allocates an SAS remote PHY structure, connected to @parent.
14678c2ecf20Sopenharmony_ci *
14688c2ecf20Sopenharmony_ci * Returns:
14698c2ecf20Sopenharmony_ci *	SAS PHY allocated or %NULL if the allocation failed.
14708c2ecf20Sopenharmony_ci */
14718c2ecf20Sopenharmony_cistruct sas_rphy *sas_expander_alloc(struct sas_port *parent,
14728c2ecf20Sopenharmony_ci				    enum sas_device_type type)
14738c2ecf20Sopenharmony_ci{
14748c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
14758c2ecf20Sopenharmony_ci	struct sas_expander_device *rdev;
14768c2ecf20Sopenharmony_ci	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
14798c2ecf20Sopenharmony_ci	       type != SAS_FANOUT_EXPANDER_DEVICE);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
14828c2ecf20Sopenharmony_ci	if (!rdev) {
14838c2ecf20Sopenharmony_ci		return NULL;
14848c2ecf20Sopenharmony_ci	}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	device_initialize(&rdev->rphy.dev);
14878c2ecf20Sopenharmony_ci	rdev->rphy.dev.parent = get_device(&parent->dev);
14888c2ecf20Sopenharmony_ci	rdev->rphy.dev.release = sas_expander_release;
14898c2ecf20Sopenharmony_ci	mutex_lock(&sas_host->lock);
14908c2ecf20Sopenharmony_ci	rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
14918c2ecf20Sopenharmony_ci	mutex_unlock(&sas_host->lock);
14928c2ecf20Sopenharmony_ci	dev_set_name(&rdev->rphy.dev, "expander-%d:%d",
14938c2ecf20Sopenharmony_ci		     shost->host_no, rdev->rphy.scsi_target_id);
14948c2ecf20Sopenharmony_ci	rdev->rphy.identify.device_type = type;
14958c2ecf20Sopenharmony_ci	sas_rphy_initialize(&rdev->rphy);
14968c2ecf20Sopenharmony_ci	transport_setup_device(&rdev->rphy.dev);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	return &rdev->rphy;
14998c2ecf20Sopenharmony_ci}
15008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_expander_alloc);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci/**
15038c2ecf20Sopenharmony_ci * sas_rphy_add  -  add a SAS remote PHY to the device hierarchy
15048c2ecf20Sopenharmony_ci * @rphy:	The remote PHY to be added
15058c2ecf20Sopenharmony_ci *
15068c2ecf20Sopenharmony_ci * Publishes a SAS remote PHY to the rest of the system.
15078c2ecf20Sopenharmony_ci */
15088c2ecf20Sopenharmony_ciint sas_rphy_add(struct sas_rphy *rphy)
15098c2ecf20Sopenharmony_ci{
15108c2ecf20Sopenharmony_ci	struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
15118c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
15128c2ecf20Sopenharmony_ci	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
15138c2ecf20Sopenharmony_ci	struct sas_identify *identify = &rphy->identify;
15148c2ecf20Sopenharmony_ci	int error;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (parent->rphy)
15178c2ecf20Sopenharmony_ci		return -ENXIO;
15188c2ecf20Sopenharmony_ci	parent->rphy = rphy;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	error = device_add(&rphy->dev);
15218c2ecf20Sopenharmony_ci	if (error)
15228c2ecf20Sopenharmony_ci		return error;
15238c2ecf20Sopenharmony_ci	transport_add_device(&rphy->dev);
15248c2ecf20Sopenharmony_ci	transport_configure_device(&rphy->dev);
15258c2ecf20Sopenharmony_ci	if (sas_bsg_initialize(shost, rphy))
15268c2ecf20Sopenharmony_ci		printk("fail to a bsg device %s\n", dev_name(&rphy->dev));
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	mutex_lock(&sas_host->lock);
15308c2ecf20Sopenharmony_ci	list_add_tail(&rphy->list, &sas_host->rphy_list);
15318c2ecf20Sopenharmony_ci	if (identify->device_type == SAS_END_DEVICE &&
15328c2ecf20Sopenharmony_ci	    (identify->target_port_protocols &
15338c2ecf20Sopenharmony_ci	     (SAS_PROTOCOL_SSP | SAS_PROTOCOL_STP | SAS_PROTOCOL_SATA)))
15348c2ecf20Sopenharmony_ci		rphy->scsi_target_id = sas_host->next_target_id++;
15358c2ecf20Sopenharmony_ci	else if (identify->device_type == SAS_END_DEVICE)
15368c2ecf20Sopenharmony_ci		rphy->scsi_target_id = -1;
15378c2ecf20Sopenharmony_ci	mutex_unlock(&sas_host->lock);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (identify->device_type == SAS_END_DEVICE &&
15408c2ecf20Sopenharmony_ci	    rphy->scsi_target_id != -1) {
15418c2ecf20Sopenharmony_ci		int lun;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		if (identify->target_port_protocols & SAS_PROTOCOL_SSP)
15448c2ecf20Sopenharmony_ci			lun = SCAN_WILD_CARD;
15458c2ecf20Sopenharmony_ci		else
15468c2ecf20Sopenharmony_ci			lun = 0;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun,
15498c2ecf20Sopenharmony_ci				 SCSI_SCAN_INITIAL);
15508c2ecf20Sopenharmony_ci	}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	return 0;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_rphy_add);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci/**
15578c2ecf20Sopenharmony_ci * sas_rphy_free  -  free a SAS remote PHY
15588c2ecf20Sopenharmony_ci * @rphy: SAS remote PHY to free
15598c2ecf20Sopenharmony_ci *
15608c2ecf20Sopenharmony_ci * Frees the specified SAS remote PHY.
15618c2ecf20Sopenharmony_ci *
15628c2ecf20Sopenharmony_ci * Note:
15638c2ecf20Sopenharmony_ci *   This function must only be called on a remote
15648c2ecf20Sopenharmony_ci *   PHY that has not successfully been added using
15658c2ecf20Sopenharmony_ci *   sas_rphy_add() (or has been sas_rphy_remove()'d)
15668c2ecf20Sopenharmony_ci */
15678c2ecf20Sopenharmony_civoid sas_rphy_free(struct sas_rphy *rphy)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct device *dev = &rphy->dev;
15708c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
15718c2ecf20Sopenharmony_ci	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	mutex_lock(&sas_host->lock);
15748c2ecf20Sopenharmony_ci	list_del(&rphy->list);
15758c2ecf20Sopenharmony_ci	mutex_unlock(&sas_host->lock);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	transport_destroy_device(dev);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	put_device(dev);
15808c2ecf20Sopenharmony_ci}
15818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_rphy_free);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci/**
15848c2ecf20Sopenharmony_ci * sas_rphy_delete  -  remove and free SAS remote PHY
15858c2ecf20Sopenharmony_ci * @rphy:	SAS remote PHY to remove and free
15868c2ecf20Sopenharmony_ci *
15878c2ecf20Sopenharmony_ci * Removes the specified SAS remote PHY and frees it.
15888c2ecf20Sopenharmony_ci */
15898c2ecf20Sopenharmony_civoid
15908c2ecf20Sopenharmony_cisas_rphy_delete(struct sas_rphy *rphy)
15918c2ecf20Sopenharmony_ci{
15928c2ecf20Sopenharmony_ci	sas_rphy_remove(rphy);
15938c2ecf20Sopenharmony_ci	sas_rphy_free(rphy);
15948c2ecf20Sopenharmony_ci}
15958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_rphy_delete);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci/**
15988c2ecf20Sopenharmony_ci * sas_rphy_unlink  -  unlink SAS remote PHY
15998c2ecf20Sopenharmony_ci * @rphy:	SAS remote phy to unlink from its parent port
16008c2ecf20Sopenharmony_ci *
16018c2ecf20Sopenharmony_ci * Removes port reference to an rphy
16028c2ecf20Sopenharmony_ci */
16038c2ecf20Sopenharmony_civoid sas_rphy_unlink(struct sas_rphy *rphy)
16048c2ecf20Sopenharmony_ci{
16058c2ecf20Sopenharmony_ci	struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	parent->rphy = NULL;
16088c2ecf20Sopenharmony_ci}
16098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_rphy_unlink);
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci/**
16128c2ecf20Sopenharmony_ci * sas_rphy_remove  -  remove SAS remote PHY
16138c2ecf20Sopenharmony_ci * @rphy:	SAS remote phy to remove
16148c2ecf20Sopenharmony_ci *
16158c2ecf20Sopenharmony_ci * Removes the specified SAS remote PHY.
16168c2ecf20Sopenharmony_ci */
16178c2ecf20Sopenharmony_civoid
16188c2ecf20Sopenharmony_cisas_rphy_remove(struct sas_rphy *rphy)
16198c2ecf20Sopenharmony_ci{
16208c2ecf20Sopenharmony_ci	struct device *dev = &rphy->dev;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	switch (rphy->identify.device_type) {
16238c2ecf20Sopenharmony_ci	case SAS_END_DEVICE:
16248c2ecf20Sopenharmony_ci		scsi_remove_target(dev);
16258c2ecf20Sopenharmony_ci		break;
16268c2ecf20Sopenharmony_ci	case SAS_EDGE_EXPANDER_DEVICE:
16278c2ecf20Sopenharmony_ci	case SAS_FANOUT_EXPANDER_DEVICE:
16288c2ecf20Sopenharmony_ci		sas_remove_children(dev);
16298c2ecf20Sopenharmony_ci		break;
16308c2ecf20Sopenharmony_ci	default:
16318c2ecf20Sopenharmony_ci		break;
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	sas_rphy_unlink(rphy);
16358c2ecf20Sopenharmony_ci	bsg_remove_queue(rphy->q);
16368c2ecf20Sopenharmony_ci	transport_remove_device(dev);
16378c2ecf20Sopenharmony_ci	device_del(dev);
16388c2ecf20Sopenharmony_ci}
16398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_rphy_remove);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci/**
16428c2ecf20Sopenharmony_ci * scsi_is_sas_rphy  -  check if a struct device represents a SAS remote PHY
16438c2ecf20Sopenharmony_ci * @dev:	device to check
16448c2ecf20Sopenharmony_ci *
16458c2ecf20Sopenharmony_ci * Returns:
16468c2ecf20Sopenharmony_ci *	%1 if the device represents a SAS remote PHY, %0 else
16478c2ecf20Sopenharmony_ci */
16488c2ecf20Sopenharmony_ciint scsi_is_sas_rphy(const struct device *dev)
16498c2ecf20Sopenharmony_ci{
16508c2ecf20Sopenharmony_ci	return dev->release == sas_end_device_release ||
16518c2ecf20Sopenharmony_ci		dev->release == sas_expander_release;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_is_sas_rphy);
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci/*
16578c2ecf20Sopenharmony_ci * SCSI scan helper
16588c2ecf20Sopenharmony_ci */
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_cistatic int sas_user_scan(struct Scsi_Host *shost, uint channel,
16618c2ecf20Sopenharmony_ci		uint id, u64 lun)
16628c2ecf20Sopenharmony_ci{
16638c2ecf20Sopenharmony_ci	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
16648c2ecf20Sopenharmony_ci	struct sas_rphy *rphy;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	mutex_lock(&sas_host->lock);
16678c2ecf20Sopenharmony_ci	list_for_each_entry(rphy, &sas_host->rphy_list, list) {
16688c2ecf20Sopenharmony_ci		if (rphy->identify.device_type != SAS_END_DEVICE ||
16698c2ecf20Sopenharmony_ci		    rphy->scsi_target_id == -1)
16708c2ecf20Sopenharmony_ci			continue;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci		if ((channel == SCAN_WILD_CARD || channel == 0) &&
16738c2ecf20Sopenharmony_ci		    (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
16748c2ecf20Sopenharmony_ci			scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,
16758c2ecf20Sopenharmony_ci					 lun, SCSI_SCAN_MANUAL);
16768c2ecf20Sopenharmony_ci		}
16778c2ecf20Sopenharmony_ci	}
16788c2ecf20Sopenharmony_ci	mutex_unlock(&sas_host->lock);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	return 0;
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci/*
16858c2ecf20Sopenharmony_ci * Setup / Teardown code
16868c2ecf20Sopenharmony_ci */
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci#define SETUP_TEMPLATE(attrb, field, perm, test)			\
16898c2ecf20Sopenharmony_ci	i->private_##attrb[count] = dev_attr_##field;		\
16908c2ecf20Sopenharmony_ci	i->private_##attrb[count].attr.mode = perm;			\
16918c2ecf20Sopenharmony_ci	i->attrb[count] = &i->private_##attrb[count];			\
16928c2ecf20Sopenharmony_ci	if (test)							\
16938c2ecf20Sopenharmony_ci		count++
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm)	\
16968c2ecf20Sopenharmony_ci	i->private_##attrb[count] = dev_attr_##field;		\
16978c2ecf20Sopenharmony_ci	i->private_##attrb[count].attr.mode = perm;			\
16988c2ecf20Sopenharmony_ci	if (ro_test) {							\
16998c2ecf20Sopenharmony_ci		i->private_##attrb[count].attr.mode = ro_perm;		\
17008c2ecf20Sopenharmony_ci		i->private_##attrb[count].store = NULL;			\
17018c2ecf20Sopenharmony_ci	}								\
17028c2ecf20Sopenharmony_ci	i->attrb[count] = &i->private_##attrb[count];			\
17038c2ecf20Sopenharmony_ci	if (test)							\
17048c2ecf20Sopenharmony_ci		count++
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci#define SETUP_RPORT_ATTRIBUTE(field) 					\
17078c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func)			\
17108c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci#define SETUP_PHY_ATTRIBUTE(field)					\
17138c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci#define SETUP_PHY_ATTRIBUTE_RW(field)					\
17168c2ecf20Sopenharmony_ci	SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1,	\
17178c2ecf20Sopenharmony_ci			!i->f->set_phy_speed, S_IRUGO)
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func)			\
17208c2ecf20Sopenharmony_ci	SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1,	\
17218c2ecf20Sopenharmony_ci			  !i->f->func, S_IRUGO)
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci#define SETUP_PORT_ATTRIBUTE(field)					\
17248c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func)			\
17278c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci#define SETUP_PHY_ATTRIBUTE_WRONLY(field)				\
17308c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1)
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func)		\
17338c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func)
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci#define SETUP_END_DEV_ATTRIBUTE(field)					\
17368c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci#define SETUP_EXPANDER_ATTRIBUTE(field)					\
17398c2ecf20Sopenharmony_ci	SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci/**
17428c2ecf20Sopenharmony_ci * sas_attach_transport  -  instantiate SAS transport template
17438c2ecf20Sopenharmony_ci * @ft:		SAS transport class function template
17448c2ecf20Sopenharmony_ci */
17458c2ecf20Sopenharmony_cistruct scsi_transport_template *
17468c2ecf20Sopenharmony_cisas_attach_transport(struct sas_function_template *ft)
17478c2ecf20Sopenharmony_ci{
17488c2ecf20Sopenharmony_ci	struct sas_internal *i;
17498c2ecf20Sopenharmony_ci	int count;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
17528c2ecf20Sopenharmony_ci	if (!i)
17538c2ecf20Sopenharmony_ci		return NULL;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	i->t.user_scan = sas_user_scan;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
17588c2ecf20Sopenharmony_ci	i->t.host_attrs.ac.class = &sas_host_class.class;
17598c2ecf20Sopenharmony_ci	i->t.host_attrs.ac.match = sas_host_match;
17608c2ecf20Sopenharmony_ci	transport_container_register(&i->t.host_attrs);
17618c2ecf20Sopenharmony_ci	i->t.host_size = sizeof(struct sas_host_attrs);
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	i->phy_attr_cont.ac.class = &sas_phy_class.class;
17648c2ecf20Sopenharmony_ci	i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
17658c2ecf20Sopenharmony_ci	i->phy_attr_cont.ac.match = sas_phy_match;
17668c2ecf20Sopenharmony_ci	transport_container_register(&i->phy_attr_cont);
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	i->port_attr_cont.ac.class = &sas_port_class.class;
17698c2ecf20Sopenharmony_ci	i->port_attr_cont.ac.attrs = &i->port_attrs[0];
17708c2ecf20Sopenharmony_ci	i->port_attr_cont.ac.match = sas_port_match;
17718c2ecf20Sopenharmony_ci	transport_container_register(&i->port_attr_cont);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
17748c2ecf20Sopenharmony_ci	i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
17758c2ecf20Sopenharmony_ci	i->rphy_attr_cont.ac.match = sas_rphy_match;
17768c2ecf20Sopenharmony_ci	transport_container_register(&i->rphy_attr_cont);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
17798c2ecf20Sopenharmony_ci	i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
17808c2ecf20Sopenharmony_ci	i->end_dev_attr_cont.ac.match = sas_end_dev_match;
17818c2ecf20Sopenharmony_ci	transport_container_register(&i->end_dev_attr_cont);
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	i->expander_attr_cont.ac.class = &sas_expander_class.class;
17848c2ecf20Sopenharmony_ci	i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
17858c2ecf20Sopenharmony_ci	i->expander_attr_cont.ac.match = sas_expander_match;
17868c2ecf20Sopenharmony_ci	transport_container_register(&i->expander_attr_cont);
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	i->f = ft;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	count = 0;
17918c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
17928c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(target_port_protocols);
17938c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(device_type);
17948c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(sas_address);
17958c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(phy_identifier);
17968c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
17978c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
17988c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
17998c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
18008c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(invalid_dword_count);
18038c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
18048c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
18058c2ecf20Sopenharmony_ci	SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
18068c2ecf20Sopenharmony_ci	SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
18078c2ecf20Sopenharmony_ci	SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
18088c2ecf20Sopenharmony_ci	SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);
18098c2ecf20Sopenharmony_ci	i->phy_attrs[count] = NULL;
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	count = 0;
18128c2ecf20Sopenharmony_ci	SETUP_PORT_ATTRIBUTE(num_phys);
18138c2ecf20Sopenharmony_ci	i->port_attrs[count] = NULL;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	count = 0;
18168c2ecf20Sopenharmony_ci	SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
18178c2ecf20Sopenharmony_ci	SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
18188c2ecf20Sopenharmony_ci	SETUP_RPORT_ATTRIBUTE(rphy_device_type);
18198c2ecf20Sopenharmony_ci	SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
18208c2ecf20Sopenharmony_ci	SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
18218c2ecf20Sopenharmony_ci	SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);
18228c2ecf20Sopenharmony_ci	SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
18238c2ecf20Sopenharmony_ci				       get_enclosure_identifier);
18248c2ecf20Sopenharmony_ci	SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
18258c2ecf20Sopenharmony_ci				       get_bay_identifier);
18268c2ecf20Sopenharmony_ci	i->rphy_attrs[count] = NULL;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	count = 0;
18298c2ecf20Sopenharmony_ci	SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
18308c2ecf20Sopenharmony_ci	SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
18318c2ecf20Sopenharmony_ci	SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
18328c2ecf20Sopenharmony_ci	SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);
18338c2ecf20Sopenharmony_ci	SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);
18348c2ecf20Sopenharmony_ci	i->end_dev_attrs[count] = NULL;
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	count = 0;
18378c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(vendor_id);
18388c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(product_id);
18398c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(product_rev);
18408c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
18418c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(component_id);
18428c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
18438c2ecf20Sopenharmony_ci	SETUP_EXPANDER_ATTRIBUTE(level);
18448c2ecf20Sopenharmony_ci	i->expander_attrs[count] = NULL;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	return &i->t;
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_attach_transport);
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci/**
18518c2ecf20Sopenharmony_ci * sas_release_transport  -  release SAS transport template instance
18528c2ecf20Sopenharmony_ci * @t:		transport template instance
18538c2ecf20Sopenharmony_ci */
18548c2ecf20Sopenharmony_civoid sas_release_transport(struct scsi_transport_template *t)
18558c2ecf20Sopenharmony_ci{
18568c2ecf20Sopenharmony_ci	struct sas_internal *i = to_sas_internal(t);
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	transport_container_unregister(&i->t.host_attrs);
18598c2ecf20Sopenharmony_ci	transport_container_unregister(&i->phy_attr_cont);
18608c2ecf20Sopenharmony_ci	transport_container_unregister(&i->port_attr_cont);
18618c2ecf20Sopenharmony_ci	transport_container_unregister(&i->rphy_attr_cont);
18628c2ecf20Sopenharmony_ci	transport_container_unregister(&i->end_dev_attr_cont);
18638c2ecf20Sopenharmony_ci	transport_container_unregister(&i->expander_attr_cont);
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	kfree(i);
18668c2ecf20Sopenharmony_ci}
18678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sas_release_transport);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_cistatic __init int sas_transport_init(void)
18708c2ecf20Sopenharmony_ci{
18718c2ecf20Sopenharmony_ci	int error;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	error = transport_class_register(&sas_host_class);
18748c2ecf20Sopenharmony_ci	if (error)
18758c2ecf20Sopenharmony_ci		goto out;
18768c2ecf20Sopenharmony_ci	error = transport_class_register(&sas_phy_class);
18778c2ecf20Sopenharmony_ci	if (error)
18788c2ecf20Sopenharmony_ci		goto out_unregister_transport;
18798c2ecf20Sopenharmony_ci	error = transport_class_register(&sas_port_class);
18808c2ecf20Sopenharmony_ci	if (error)
18818c2ecf20Sopenharmony_ci		goto out_unregister_phy;
18828c2ecf20Sopenharmony_ci	error = transport_class_register(&sas_rphy_class);
18838c2ecf20Sopenharmony_ci	if (error)
18848c2ecf20Sopenharmony_ci		goto out_unregister_port;
18858c2ecf20Sopenharmony_ci	error = transport_class_register(&sas_end_dev_class);
18868c2ecf20Sopenharmony_ci	if (error)
18878c2ecf20Sopenharmony_ci		goto out_unregister_rphy;
18888c2ecf20Sopenharmony_ci	error = transport_class_register(&sas_expander_class);
18898c2ecf20Sopenharmony_ci	if (error)
18908c2ecf20Sopenharmony_ci		goto out_unregister_end_dev;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	return 0;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci out_unregister_end_dev:
18958c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_end_dev_class);
18968c2ecf20Sopenharmony_ci out_unregister_rphy:
18978c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_rphy_class);
18988c2ecf20Sopenharmony_ci out_unregister_port:
18998c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_port_class);
19008c2ecf20Sopenharmony_ci out_unregister_phy:
19018c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_phy_class);
19028c2ecf20Sopenharmony_ci out_unregister_transport:
19038c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_host_class);
19048c2ecf20Sopenharmony_ci out:
19058c2ecf20Sopenharmony_ci	return error;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci}
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_cistatic void __exit sas_transport_exit(void)
19108c2ecf20Sopenharmony_ci{
19118c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_host_class);
19128c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_phy_class);
19138c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_port_class);
19148c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_rphy_class);
19158c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_end_dev_class);
19168c2ecf20Sopenharmony_ci	transport_class_unregister(&sas_expander_class);
19178c2ecf20Sopenharmony_ci}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christoph Hellwig");
19208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SAS Transport Attributes");
19218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_cimodule_init(sas_transport_init);
19248c2ecf20Sopenharmony_cimodule_exit(sas_transport_exit);
1925