162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef SCSI_TRANSPORT_SAS_H
362306a36Sopenharmony_ci#define SCSI_TRANSPORT_SAS_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/transport_class.h>
662306a36Sopenharmony_ci#include <linux/types.h>
762306a36Sopenharmony_ci#include <linux/mutex.h>
862306a36Sopenharmony_ci#include <scsi/sas.h>
962306a36Sopenharmony_ci#include <linux/bsg-lib.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistruct scsi_transport_template;
1262306a36Sopenharmony_cistruct sas_rphy;
1362306a36Sopenharmony_cistruct request;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_SCSI_SAS_ATTRS)
1662306a36Sopenharmony_cistatic inline int scsi_is_sas_rphy(const struct device *sdev)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	return 0;
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci#else
2162306a36Sopenharmony_ciextern int scsi_is_sas_rphy(const struct device *);
2262306a36Sopenharmony_ci#endif
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic inline int sas_protocol_ata(enum sas_protocol proto)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	return ((proto & SAS_PROTOCOL_SATA) ||
2762306a36Sopenharmony_ci		(proto & SAS_PROTOCOL_STP))? 1 : 0;
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cienum sas_linkrate {
3162306a36Sopenharmony_ci	/* These Values are defined in the SAS standard */
3262306a36Sopenharmony_ci	SAS_LINK_RATE_UNKNOWN = 0,
3362306a36Sopenharmony_ci	SAS_PHY_DISABLED = 1,
3462306a36Sopenharmony_ci	SAS_PHY_RESET_PROBLEM = 2,
3562306a36Sopenharmony_ci	SAS_SATA_SPINUP_HOLD = 3,
3662306a36Sopenharmony_ci	SAS_SATA_PORT_SELECTOR = 4,
3762306a36Sopenharmony_ci	SAS_PHY_RESET_IN_PROGRESS = 5,
3862306a36Sopenharmony_ci	SAS_LINK_RATE_1_5_GBPS = 8,
3962306a36Sopenharmony_ci	SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
4062306a36Sopenharmony_ci	SAS_LINK_RATE_3_0_GBPS = 9,
4162306a36Sopenharmony_ci	SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
4262306a36Sopenharmony_ci	SAS_LINK_RATE_6_0_GBPS = 10,
4362306a36Sopenharmony_ci	SAS_LINK_RATE_12_0_GBPS = 11,
4462306a36Sopenharmony_ci	SAS_LINK_RATE_22_5_GBPS = 12,
4562306a36Sopenharmony_ci	/* These are virtual to the transport class and may never
4662306a36Sopenharmony_ci	 * be signalled normally since the standard defined field
4762306a36Sopenharmony_ci	 * is only 4 bits */
4862306a36Sopenharmony_ci	SAS_LINK_RATE_FAILED = 0x10,
4962306a36Sopenharmony_ci	SAS_PHY_VIRTUAL = 0x11,
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct sas_identify {
5362306a36Sopenharmony_ci	enum sas_device_type	device_type;
5462306a36Sopenharmony_ci	enum sas_protocol	initiator_port_protocols;
5562306a36Sopenharmony_ci	enum sas_protocol	target_port_protocols;
5662306a36Sopenharmony_ci	u64			sas_address;
5762306a36Sopenharmony_ci	u8			phy_identifier;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct sas_phy {
6162306a36Sopenharmony_ci	struct device		dev;
6262306a36Sopenharmony_ci	int			number;
6362306a36Sopenharmony_ci	int			enabled;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* phy identification */
6662306a36Sopenharmony_ci	struct sas_identify	identify;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* phy attributes */
6962306a36Sopenharmony_ci	enum sas_linkrate	negotiated_linkrate;
7062306a36Sopenharmony_ci	enum sas_linkrate	minimum_linkrate_hw;
7162306a36Sopenharmony_ci	enum sas_linkrate	minimum_linkrate;
7262306a36Sopenharmony_ci	enum sas_linkrate	maximum_linkrate_hw;
7362306a36Sopenharmony_ci	enum sas_linkrate	maximum_linkrate;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* link error statistics */
7662306a36Sopenharmony_ci	u32			invalid_dword_count;
7762306a36Sopenharmony_ci	u32			running_disparity_error_count;
7862306a36Sopenharmony_ci	u32			loss_of_dword_sync_count;
7962306a36Sopenharmony_ci	u32			phy_reset_problem_count;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* for the list of phys belonging to a port */
8262306a36Sopenharmony_ci	struct list_head	port_siblings;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* available to the lldd */
8562306a36Sopenharmony_ci	void			*hostdata;
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define dev_to_phy(d) \
8962306a36Sopenharmony_ci	container_of((d), struct sas_phy, dev)
9062306a36Sopenharmony_ci#define transport_class_to_phy(dev) \
9162306a36Sopenharmony_ci	dev_to_phy((dev)->parent)
9262306a36Sopenharmony_ci#define phy_to_shost(phy) \
9362306a36Sopenharmony_ci	dev_to_shost((phy)->dev.parent)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct request_queue;
9662306a36Sopenharmony_cistruct sas_rphy {
9762306a36Sopenharmony_ci	struct device		dev;
9862306a36Sopenharmony_ci	struct sas_identify	identify;
9962306a36Sopenharmony_ci	struct list_head	list;
10062306a36Sopenharmony_ci	struct request_queue	*q;
10162306a36Sopenharmony_ci	u32			scsi_target_id;
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define dev_to_rphy(d) \
10562306a36Sopenharmony_ci	container_of((d), struct sas_rphy, dev)
10662306a36Sopenharmony_ci#define transport_class_to_rphy(dev) \
10762306a36Sopenharmony_ci	dev_to_rphy((dev)->parent)
10862306a36Sopenharmony_ci#define rphy_to_shost(rphy) \
10962306a36Sopenharmony_ci	dev_to_shost((rphy)->dev.parent)
11062306a36Sopenharmony_ci#define target_to_rphy(targ) \
11162306a36Sopenharmony_ci	dev_to_rphy((targ)->dev.parent)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistruct sas_end_device {
11462306a36Sopenharmony_ci	struct sas_rphy		rphy;
11562306a36Sopenharmony_ci	/* flags */
11662306a36Sopenharmony_ci	unsigned		ready_led_meaning:1;
11762306a36Sopenharmony_ci	unsigned		tlr_supported:1;
11862306a36Sopenharmony_ci	unsigned		tlr_enabled:1;
11962306a36Sopenharmony_ci	/* parameters */
12062306a36Sopenharmony_ci	u16			I_T_nexus_loss_timeout;
12162306a36Sopenharmony_ci	u16			initiator_response_timeout;
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci#define rphy_to_end_device(r) \
12462306a36Sopenharmony_ci	container_of((r), struct sas_end_device, rphy)
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistruct sas_expander_device {
12762306a36Sopenharmony_ci	int    level;
12862306a36Sopenharmony_ci	int    next_port_id;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	#define SAS_EXPANDER_VENDOR_ID_LEN	8
13162306a36Sopenharmony_ci	char   vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
13262306a36Sopenharmony_ci	#define SAS_EXPANDER_PRODUCT_ID_LEN	16
13362306a36Sopenharmony_ci	char   product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
13462306a36Sopenharmony_ci	#define SAS_EXPANDER_PRODUCT_REV_LEN	4
13562306a36Sopenharmony_ci	char   product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
13662306a36Sopenharmony_ci	#define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN	8
13762306a36Sopenharmony_ci	char   component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
13862306a36Sopenharmony_ci	u16    component_id;
13962306a36Sopenharmony_ci	u8     component_revision_id;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	struct sas_rphy		rphy;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci#define rphy_to_expander_device(r) \
14562306a36Sopenharmony_ci	container_of((r), struct sas_expander_device, rphy)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct sas_port {
14862306a36Sopenharmony_ci	struct device		dev;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	int			port_identifier;
15162306a36Sopenharmony_ci	int			num_phys;
15262306a36Sopenharmony_ci	/* port flags */
15362306a36Sopenharmony_ci	unsigned int		is_backlink:1;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* the other end of the link */
15662306a36Sopenharmony_ci	struct sas_rphy		*rphy;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	struct mutex		phy_list_mutex;
15962306a36Sopenharmony_ci	struct list_head	phy_list;
16062306a36Sopenharmony_ci	struct list_head	del_list; /* libsas only */
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define dev_to_sas_port(d) \
16462306a36Sopenharmony_ci	container_of((d), struct sas_port, dev)
16562306a36Sopenharmony_ci#define transport_class_to_sas_port(dev) \
16662306a36Sopenharmony_ci	dev_to_sas_port((dev)->parent)
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistruct sas_phy_linkrates {
16962306a36Sopenharmony_ci	enum sas_linkrate maximum_linkrate;
17062306a36Sopenharmony_ci	enum sas_linkrate minimum_linkrate;
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* The functions by which the transport class and the driver communicate */
17462306a36Sopenharmony_cistruct sas_function_template {
17562306a36Sopenharmony_ci	int (*get_linkerrors)(struct sas_phy *);
17662306a36Sopenharmony_ci	int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
17762306a36Sopenharmony_ci	int (*get_bay_identifier)(struct sas_rphy *);
17862306a36Sopenharmony_ci	int (*phy_reset)(struct sas_phy *, int);
17962306a36Sopenharmony_ci	int (*phy_enable)(struct sas_phy *, int);
18062306a36Sopenharmony_ci	int (*phy_setup)(struct sas_phy *);
18162306a36Sopenharmony_ci	void (*phy_release)(struct sas_phy *);
18262306a36Sopenharmony_ci	int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
18362306a36Sopenharmony_ci	void (*smp_handler)(struct bsg_job *, struct Scsi_Host *,
18462306a36Sopenharmony_ci			struct sas_rphy *);
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid sas_remove_children(struct device *);
18962306a36Sopenharmony_ciextern void sas_remove_host(struct Scsi_Host *);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciextern struct sas_phy *sas_phy_alloc(struct device *, int);
19262306a36Sopenharmony_ciextern void sas_phy_free(struct sas_phy *);
19362306a36Sopenharmony_ciextern int sas_phy_add(struct sas_phy *);
19462306a36Sopenharmony_ciextern void sas_phy_delete(struct sas_phy *);
19562306a36Sopenharmony_ciextern int scsi_is_sas_phy(const struct device *);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciu64 sas_get_address(struct scsi_device *);
19862306a36Sopenharmony_ciunsigned int sas_tlr_supported(struct scsi_device *);
19962306a36Sopenharmony_ciunsigned int sas_is_tlr_enabled(struct scsi_device *);
20062306a36Sopenharmony_civoid sas_disable_tlr(struct scsi_device *);
20162306a36Sopenharmony_civoid sas_enable_tlr(struct scsi_device *);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciextern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
20462306a36Sopenharmony_ciextern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
20562306a36Sopenharmony_civoid sas_rphy_free(struct sas_rphy *);
20662306a36Sopenharmony_ciextern int sas_rphy_add(struct sas_rphy *);
20762306a36Sopenharmony_ciextern void sas_rphy_remove(struct sas_rphy *);
20862306a36Sopenharmony_ciextern void sas_rphy_delete(struct sas_rphy *);
20962306a36Sopenharmony_ciextern void sas_rphy_unlink(struct sas_rphy *);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct sas_port *sas_port_alloc(struct device *, int);
21262306a36Sopenharmony_cistruct sas_port *sas_port_alloc_num(struct device *);
21362306a36Sopenharmony_ciint sas_port_add(struct sas_port *);
21462306a36Sopenharmony_civoid sas_port_free(struct sas_port *);
21562306a36Sopenharmony_civoid sas_port_delete(struct sas_port *);
21662306a36Sopenharmony_civoid sas_port_add_phy(struct sas_port *, struct sas_phy *);
21762306a36Sopenharmony_civoid sas_port_delete_phy(struct sas_port *, struct sas_phy *);
21862306a36Sopenharmony_civoid sas_port_mark_backlink(struct sas_port *);
21962306a36Sopenharmony_ciint scsi_is_sas_port(const struct device *);
22062306a36Sopenharmony_cistruct sas_phy *sas_port_get_phy(struct sas_port *port);
22162306a36Sopenharmony_cistatic inline void sas_port_put_phy(struct sas_phy *phy)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	if (phy)
22462306a36Sopenharmony_ci		put_device(&phy->dev);
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ciextern struct scsi_transport_template *
22862306a36Sopenharmony_cisas_attach_transport(struct sas_function_template *);
22962306a36Sopenharmony_ciextern void sas_release_transport(struct scsi_transport_template *);
23062306a36Sopenharmony_ciint sas_read_port_mode_page(struct scsi_device *);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic inline int
23362306a36Sopenharmony_ciscsi_is_sas_expander_device(struct device *dev)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct sas_rphy *rphy;
23662306a36Sopenharmony_ci	if (!scsi_is_sas_rphy(dev))
23762306a36Sopenharmony_ci		return 0;
23862306a36Sopenharmony_ci	rphy = dev_to_rphy(dev);
23962306a36Sopenharmony_ci	return rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE ||
24062306a36Sopenharmony_ci		rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#define scsi_is_sas_phy_local(phy)	scsi_is_host_device((phy)->dev.parent)
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#endif /* SCSI_TRANSPORT_SAS_H */
246