0
     +ˆÈÏƒtÇÂÑ �    +/* SPDX-License-Identifier: GPL-2.0 */
#ifndef SCSI_TRANSPORT_SAS_H
#define SCSI_TRANSPORT_SAS_H

#include <linux/transport_class.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <scsi/sas.h>
#include <linux/bsg-lib.h>

struct scsi_transport_template;
struct sas_rphy;
struct request;

#if !IS_ENABLED(CONFIG_SCSI_SAS_ATTRS)
static inline int scsi_is_sas_rphy(const struct device *sdev)
{
	return 0;
}
#else
extern int scsi_is_sas_rphy(const struct device *);
#endif

static inline int sas_protocol_ata(enum sas_protocol proto)
{
	return ((proto & SAS_PROTOCOL_SATA) ||
		(proto & SAS_PROTOCOL_STP))? 1 : 0;
}

enum sas_linkrate {
	/* These Values are defined in the SAS standard */
	SAS_LINK_RATE_UNKNOWN = 0,
	SAS_PHY_DISABLED = 1,
	SAS_PHY_RESET_PROBLEM = 2,
	SAS_SATA_SPINUP_HOLD = 3,
	SAS_SATA_PORT_SELECTOR = 4,
	SAS_PHY_RESET_IN_PROGRESS = 5,
	SAS_LINK_RATE_1_5_GBPS = 8,
	SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
	SAS_LINK_RATE_3_0_GBPS = 9,
	SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
	SAS_LINK_RATE_6_0_GBPS = 10,
	SAS_LINK_RATE_12_0_GBPS = 11,
	SAS_LINK_RATE_22_5_GBPS = 12,
	/* These are virtual to the transport class and may never
	 * be signalled normally since the standard defined field
	 * is only 4 bits */
	SAS_LINK_RATE_FAILED = 0x10,
	SAS_PHY_VIRTUAL = 0x11,
};

struct sas_identify {
	enum sas_device_type	device_type;
	enum sas_protocol	initiator_port_protocols;
	enum sas_protocol	target_port_protocols;
	u64			sas_address;
	u8			phy_identifier;
};

struct sas_phy {
	struct device		dev;
	int			number;
	int			enabled;

	/* phy identification */
	struct sas_identify	identify;

	/* phy attributes */
	enum sas_linkrate	negotiated_linkrate;
	enum sas_linkrate	minimum_linkrate_hw;
	enum sas_linkrate	minimum_linkrate;
	enum sas_linkrate	maximum_linkrate_hw;
	enum sas_linkrate	maximum_linkrate;

	/* link error statistics */
	u32			invalid_dword_count;
	u32			running_disparity_error_count;
	u32			loss_of_dword_sync_count;
	u32			phy_reset_problem_count;

	/* for the list of phys belonging to a port */
	struct list_head	port_siblings;

	/* available to the lldd */
	void			*hostdata;
};

#define dev_to_phy(d) \
	container_of((d), struct sas_phy, dev)
#define transport_class_to_phy(dev) \
	dev_to_phy((dev)->parent)
#define phy_to_shost(phy) \
	dev_to_shost((phy)->dev.parent)

struct request_queue;
struct sas_rphy {
	struct device		dev;
	struct sas_identify	identify;
	struct list_head	list;
	struct request_queue	*q;
	u32			scsi_target_id;
};

#define dev_to_rphy(d) \
	container_of((d), struct sas_rphy, dev)
#define transport_class_to_rphy(dev) \
	dev_to_rphy((dev)->parent)
#define rphy_to_shost(rphy) \
	dev_to_shost((rphy)->dev.parent)
#define target_to_rphy(targ) \
	dev_to_rphy((targ)->dev.parent)

struct sas_end_device {
	struct sas_rphy		rphy;
	/* flags */
	unsigned		ready_led_meaning:1;
	unsigned		tlr_supported:1;
	unsigned		tlr_enabled:1;
	/* parameters */
	u16			I_T_nexus_loss_timeout;
	u16			initiator_response_timeout;
};
#define rphy_to_end_device(r) \
	container_of((r), struct sas_end_device, rphy)

struct sas_expander_device {
	int    level;
	int    next_port_id;

	#define SAS_EXPANDER_VENDOR_ID_LEN	8
	char   vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
	#define SAS_EXPANDER_PRODUCT_ID_LEN	16
	char   product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
	#define SAS_EXPANDER_PRODUCT_REV_LEN	4
	char   product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
	#define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN	8
	char   component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
	u16    component_id;
	u8     component_revision_id;

	struct sas_rphy		rphy;

};
#define rphy_to_expander_device(r) \
	container_of((r), struct sas_expander_device, rphy)

struct sas_port {
	struct device		dev;

	int			port_identifier;
	int			num_phys;
	/* port flags */
	unsigned int		is_backlink:1;

	/* the other end of the link */
	struct sas_rphy		*rphy;

	struct mutex		phy_list_mutex;
	struct list_head	phy_list;
	struct list_head	del_list; /* libsas only */
};

#define dev_to_sas_port(d) \
	container_of((d), struct sas_port, dev)
#