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