1c7ebbbceSChristoph Hellwig /* 2c7ebbbceSChristoph Hellwig * Copyright (C) 2005 Dell Inc. 3c7ebbbceSChristoph Hellwig * Released under GPL v2. 4c7ebbbceSChristoph Hellwig * 5c7ebbbceSChristoph Hellwig * Serial Attached SCSI (SAS) transport class. 6c7ebbbceSChristoph Hellwig * 7c7ebbbceSChristoph Hellwig * The SAS transport class contains common code to deal with SAS HBAs, 8c7ebbbceSChristoph Hellwig * an aproximated representation of SAS topologies in the driver model, 9c7ebbbceSChristoph Hellwig * and various sysfs attributes to expose these topologies and managment 10c7ebbbceSChristoph Hellwig * interfaces to userspace. 11c7ebbbceSChristoph Hellwig * 12c7ebbbceSChristoph Hellwig * In addition to the basic SCSI core objects this transport class 13c7ebbbceSChristoph Hellwig * introduces two additional intermediate objects: The SAS PHY 14c7ebbbceSChristoph Hellwig * as represented by struct sas_phy defines an "outgoing" PHY on 15c7ebbbceSChristoph Hellwig * a SAS HBA or Expander, and the SAS remote PHY represented by 16c7ebbbceSChristoph Hellwig * struct sas_rphy defines an "incoming" PHY on a SAS Expander or 17c7ebbbceSChristoph Hellwig * end device. Note that this is purely a software concept, the 18c7ebbbceSChristoph Hellwig * underlying hardware for a PHY and a remote PHY is the exactly 19c7ebbbceSChristoph Hellwig * the same. 20c7ebbbceSChristoph Hellwig * 21c7ebbbceSChristoph Hellwig * There is no concept of a SAS port in this code, users can see 22c7ebbbceSChristoph Hellwig * what PHYs form a wide port based on the port_identifier attribute, 23c7ebbbceSChristoph Hellwig * which is the same for all PHYs in a port. 24c7ebbbceSChristoph Hellwig */ 25c7ebbbceSChristoph Hellwig 26c7ebbbceSChristoph Hellwig #include <linux/init.h> 27c7ebbbceSChristoph Hellwig #include <linux/module.h> 28c7ebbbceSChristoph Hellwig #include <linux/err.h> 29c7ebbbceSChristoph Hellwig 30c7ebbbceSChristoph Hellwig #include <scsi/scsi_device.h> 31c7ebbbceSChristoph Hellwig #include <scsi/scsi_host.h> 32c7ebbbceSChristoph Hellwig #include <scsi/scsi_transport.h> 33c7ebbbceSChristoph Hellwig #include <scsi/scsi_transport_sas.h> 34c7ebbbceSChristoph Hellwig 35c7ebbbceSChristoph Hellwig 36c7ebbbceSChristoph Hellwig #define SAS_HOST_ATTRS 0 3707ba3a95SChristoph Hellwig #define SAS_PORT_ATTRS 17 38c7ebbbceSChristoph Hellwig #define SAS_RPORT_ATTRS 5 39c7ebbbceSChristoph Hellwig 40c7ebbbceSChristoph Hellwig struct sas_internal { 41c7ebbbceSChristoph Hellwig struct scsi_transport_template t; 42c7ebbbceSChristoph Hellwig struct sas_function_template *f; 43c7ebbbceSChristoph Hellwig 44c7ebbbceSChristoph Hellwig struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; 45c7ebbbceSChristoph Hellwig struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; 46c7ebbbceSChristoph Hellwig struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 47c7ebbbceSChristoph Hellwig 48c7ebbbceSChristoph Hellwig struct transport_container phy_attr_cont; 49c7ebbbceSChristoph Hellwig struct transport_container rphy_attr_cont; 50c7ebbbceSChristoph Hellwig 51c7ebbbceSChristoph Hellwig /* 52c7ebbbceSChristoph Hellwig * The array of null terminated pointers to attributes 53c7ebbbceSChristoph Hellwig * needed by scsi_sysfs.c 54c7ebbbceSChristoph Hellwig */ 55c7ebbbceSChristoph Hellwig struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; 56c7ebbbceSChristoph Hellwig struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 57c7ebbbceSChristoph Hellwig struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 58c7ebbbceSChristoph Hellwig }; 59c7ebbbceSChristoph Hellwig #define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) 60c7ebbbceSChristoph Hellwig 61c7ebbbceSChristoph Hellwig struct sas_host_attrs { 62c7ebbbceSChristoph Hellwig struct list_head rphy_list; 63c7ebbbceSChristoph Hellwig spinlock_t lock; 64c7ebbbceSChristoph Hellwig u32 next_target_id; 65c7ebbbceSChristoph Hellwig }; 66c7ebbbceSChristoph Hellwig #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 67c7ebbbceSChristoph Hellwig 68c7ebbbceSChristoph Hellwig 69c7ebbbceSChristoph Hellwig /* 70c7ebbbceSChristoph Hellwig * Hack to allow attributes of the same name in different objects. 71c7ebbbceSChristoph Hellwig */ 72c7ebbbceSChristoph Hellwig #define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ 73c7ebbbceSChristoph Hellwig struct class_device_attribute class_device_attr_##_prefix##_##_name = \ 74c7ebbbceSChristoph Hellwig __ATTR(_name,_mode,_show,_store) 75c7ebbbceSChristoph Hellwig 76c7ebbbceSChristoph Hellwig 77c7ebbbceSChristoph Hellwig /* 78c7ebbbceSChristoph Hellwig * Pretty printing helpers 79c7ebbbceSChristoph Hellwig */ 80c7ebbbceSChristoph Hellwig 81c7ebbbceSChristoph Hellwig #define sas_bitfield_name_match(title, table) \ 82c7ebbbceSChristoph Hellwig static ssize_t \ 83c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 84c7ebbbceSChristoph Hellwig { \ 85c7ebbbceSChristoph Hellwig char *prefix = ""; \ 86c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 87c7ebbbceSChristoph Hellwig int i; \ 88c7ebbbceSChristoph Hellwig \ 89c7ebbbceSChristoph Hellwig for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 90c7ebbbceSChristoph Hellwig if (table[i].value & table_key) { \ 91c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s%s", \ 92c7ebbbceSChristoph Hellwig prefix, table[i].name); \ 93c7ebbbceSChristoph Hellwig prefix = ", "; \ 94c7ebbbceSChristoph Hellwig } \ 95c7ebbbceSChristoph Hellwig } \ 96c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 97c7ebbbceSChristoph Hellwig return len; \ 98c7ebbbceSChristoph Hellwig } 99c7ebbbceSChristoph Hellwig 100c7ebbbceSChristoph Hellwig #define sas_bitfield_name_search(title, table) \ 101c7ebbbceSChristoph Hellwig static ssize_t \ 102c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 103c7ebbbceSChristoph Hellwig { \ 104c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 105c7ebbbceSChristoph Hellwig int i; \ 106c7ebbbceSChristoph Hellwig \ 107c7ebbbceSChristoph Hellwig for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 108c7ebbbceSChristoph Hellwig if (table[i].value == table_key) { \ 109c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s", \ 110c7ebbbceSChristoph Hellwig table[i].name); \ 111c7ebbbceSChristoph Hellwig break; \ 112c7ebbbceSChristoph Hellwig } \ 113c7ebbbceSChristoph Hellwig } \ 114c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 115c7ebbbceSChristoph Hellwig return len; \ 116c7ebbbceSChristoph Hellwig } 117c7ebbbceSChristoph Hellwig 118c7ebbbceSChristoph Hellwig static struct { 119c7ebbbceSChristoph Hellwig u32 value; 120c7ebbbceSChristoph Hellwig char *name; 121c7ebbbceSChristoph Hellwig } sas_device_type_names[] = { 122c7ebbbceSChristoph Hellwig { SAS_PHY_UNUSED, "unused" }, 123c7ebbbceSChristoph Hellwig { SAS_END_DEVICE, "end device" }, 124c7ebbbceSChristoph Hellwig { SAS_EDGE_EXPANDER_DEVICE, "edge expander" }, 125c7ebbbceSChristoph Hellwig { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" }, 126c7ebbbceSChristoph Hellwig }; 127c7ebbbceSChristoph Hellwig sas_bitfield_name_search(device_type, sas_device_type_names) 128c7ebbbceSChristoph Hellwig 129c7ebbbceSChristoph Hellwig 130c7ebbbceSChristoph Hellwig static struct { 131c7ebbbceSChristoph Hellwig u32 value; 132c7ebbbceSChristoph Hellwig char *name; 133c7ebbbceSChristoph Hellwig } sas_protocol_names[] = { 134c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SATA, "sata" }, 135c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SMP, "smp" }, 136c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_STP, "stp" }, 137c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SSP, "ssp" }, 138c7ebbbceSChristoph Hellwig }; 139c7ebbbceSChristoph Hellwig sas_bitfield_name_match(protocol, sas_protocol_names) 140c7ebbbceSChristoph Hellwig 141c7ebbbceSChristoph Hellwig static struct { 142c7ebbbceSChristoph Hellwig u32 value; 143c7ebbbceSChristoph Hellwig char *name; 144c7ebbbceSChristoph Hellwig } sas_linkspeed_names[] = { 145c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_UNKNOWN, "Unknown" }, 146c7ebbbceSChristoph Hellwig { SAS_PHY_DISABLED, "Phy disabled" }, 147c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_FAILED, "Link Rate failed" }, 148c7ebbbceSChristoph Hellwig { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, 149c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 150c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 151c7ebbbceSChristoph Hellwig }; 152c7ebbbceSChristoph Hellwig sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 153c7ebbbceSChristoph Hellwig 154c7ebbbceSChristoph Hellwig 155c7ebbbceSChristoph Hellwig /* 156c7ebbbceSChristoph Hellwig * SAS host attributes 157c7ebbbceSChristoph Hellwig */ 158c7ebbbceSChristoph Hellwig 15937be6eebSJames Bottomley static int sas_host_setup(struct transport_container *tc, struct device *dev, 16037be6eebSJames Bottomley struct class_device *cdev) 161c7ebbbceSChristoph Hellwig { 162c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(dev); 163c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 164c7ebbbceSChristoph Hellwig 165c7ebbbceSChristoph Hellwig INIT_LIST_HEAD(&sas_host->rphy_list); 166c7ebbbceSChristoph Hellwig spin_lock_init(&sas_host->lock); 167c7ebbbceSChristoph Hellwig sas_host->next_target_id = 0; 168c7ebbbceSChristoph Hellwig return 0; 169c7ebbbceSChristoph Hellwig } 170c7ebbbceSChristoph Hellwig 171c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_host_class, 172c7ebbbceSChristoph Hellwig "sas_host", sas_host_setup, NULL, NULL); 173c7ebbbceSChristoph Hellwig 174c7ebbbceSChristoph Hellwig static int sas_host_match(struct attribute_container *cont, 175c7ebbbceSChristoph Hellwig struct device *dev) 176c7ebbbceSChristoph Hellwig { 177c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 178c7ebbbceSChristoph Hellwig struct sas_internal *i; 179c7ebbbceSChristoph Hellwig 180c7ebbbceSChristoph Hellwig if (!scsi_is_host_device(dev)) 181c7ebbbceSChristoph Hellwig return 0; 182c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev); 183c7ebbbceSChristoph Hellwig 184c7ebbbceSChristoph Hellwig if (!shost->transportt) 185c7ebbbceSChristoph Hellwig return 0; 186c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 187c7ebbbceSChristoph Hellwig &sas_host_class.class) 188c7ebbbceSChristoph Hellwig return 0; 189c7ebbbceSChristoph Hellwig 190c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 191c7ebbbceSChristoph Hellwig return &i->t.host_attrs.ac == cont; 192c7ebbbceSChristoph Hellwig } 193c7ebbbceSChristoph Hellwig 194c7ebbbceSChristoph Hellwig static int do_sas_phy_delete(struct device *dev, void *data) 195c7ebbbceSChristoph Hellwig { 196c7ebbbceSChristoph Hellwig if (scsi_is_sas_phy(dev)) 197c7ebbbceSChristoph Hellwig sas_phy_delete(dev_to_phy(dev)); 198c7ebbbceSChristoph Hellwig return 0; 199c7ebbbceSChristoph Hellwig } 200c7ebbbceSChristoph Hellwig 201c7ebbbceSChristoph Hellwig /** 202c7ebbbceSChristoph Hellwig * sas_remove_host -- tear down a Scsi_Host's SAS data structures 203c7ebbbceSChristoph Hellwig * @shost: Scsi Host that is torn down 204c7ebbbceSChristoph Hellwig * 205c7ebbbceSChristoph Hellwig * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 206c7ebbbceSChristoph Hellwig * Must be called just before scsi_remove_host for SAS HBAs. 207c7ebbbceSChristoph Hellwig */ 208c7ebbbceSChristoph Hellwig void sas_remove_host(struct Scsi_Host *shost) 209c7ebbbceSChristoph Hellwig { 210c7ebbbceSChristoph Hellwig device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); 211c7ebbbceSChristoph Hellwig } 212c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_remove_host); 213c7ebbbceSChristoph Hellwig 214c7ebbbceSChristoph Hellwig 215c7ebbbceSChristoph Hellwig /* 216c7ebbbceSChristoph Hellwig * SAS Port attributes 217c7ebbbceSChristoph Hellwig */ 218c7ebbbceSChristoph Hellwig 219c7ebbbceSChristoph Hellwig #define sas_phy_show_simple(field, name, format_string, cast) \ 220c7ebbbceSChristoph Hellwig static ssize_t \ 221c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 222c7ebbbceSChristoph Hellwig { \ 223c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 224c7ebbbceSChristoph Hellwig \ 225c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast phy->field); \ 226c7ebbbceSChristoph Hellwig } 227c7ebbbceSChristoph Hellwig 228c7ebbbceSChristoph Hellwig #define sas_phy_simple_attr(field, name, format_string, type) \ 229c7ebbbceSChristoph Hellwig sas_phy_show_simple(field, name, format_string, (type)) \ 230c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 231c7ebbbceSChristoph Hellwig 232c7ebbbceSChristoph Hellwig #define sas_phy_show_protocol(field, name) \ 233c7ebbbceSChristoph Hellwig static ssize_t \ 234c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 235c7ebbbceSChristoph Hellwig { \ 236c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 237c7ebbbceSChristoph Hellwig \ 238c7ebbbceSChristoph Hellwig if (!phy->field) \ 239c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 240c7ebbbceSChristoph Hellwig return get_sas_protocol_names(phy->field, buf); \ 241c7ebbbceSChristoph Hellwig } 242c7ebbbceSChristoph Hellwig 243c7ebbbceSChristoph Hellwig #define sas_phy_protocol_attr(field, name) \ 244c7ebbbceSChristoph Hellwig sas_phy_show_protocol(field, name) \ 245c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 246c7ebbbceSChristoph Hellwig 247c7ebbbceSChristoph Hellwig #define sas_phy_show_linkspeed(field) \ 248c7ebbbceSChristoph Hellwig static ssize_t \ 249c7ebbbceSChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 250c7ebbbceSChristoph Hellwig { \ 251c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 252c7ebbbceSChristoph Hellwig \ 253c7ebbbceSChristoph Hellwig return get_sas_linkspeed_names(phy->field, buf); \ 254c7ebbbceSChristoph Hellwig } 255c7ebbbceSChristoph Hellwig 256c7ebbbceSChristoph Hellwig #define sas_phy_linkspeed_attr(field) \ 257c7ebbbceSChristoph Hellwig sas_phy_show_linkspeed(field) \ 258c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 259c7ebbbceSChristoph Hellwig 260c3ee74c4SChristoph Hellwig #define sas_phy_show_linkerror(field) \ 261c3ee74c4SChristoph Hellwig static ssize_t \ 262c3ee74c4SChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 263c3ee74c4SChristoph Hellwig { \ 264c3ee74c4SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 265c3ee74c4SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 266c3ee74c4SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); \ 267c3ee74c4SChristoph Hellwig int error; \ 268c3ee74c4SChristoph Hellwig \ 269ac01bbbdSChristoph Hellwig if (!phy->local_attached) \ 270ac01bbbdSChristoph Hellwig return -EINVAL; \ 271ac01bbbdSChristoph Hellwig \ 272c3ee74c4SChristoph Hellwig error = i->f->get_linkerrors(phy); \ 273c3ee74c4SChristoph Hellwig if (error) \ 274c3ee74c4SChristoph Hellwig return error; \ 275c3ee74c4SChristoph Hellwig return snprintf(buf, 20, "%u\n", phy->field); \ 276c3ee74c4SChristoph Hellwig } 277c3ee74c4SChristoph Hellwig 278c3ee74c4SChristoph Hellwig #define sas_phy_linkerror_attr(field) \ 279c3ee74c4SChristoph Hellwig sas_phy_show_linkerror(field) \ 280c3ee74c4SChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 281c3ee74c4SChristoph Hellwig 282c3ee74c4SChristoph Hellwig 283c7ebbbceSChristoph Hellwig static ssize_t 284c7ebbbceSChristoph Hellwig show_sas_device_type(struct class_device *cdev, char *buf) 285c7ebbbceSChristoph Hellwig { 286c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 287c7ebbbceSChristoph Hellwig 288c7ebbbceSChristoph Hellwig if (!phy->identify.device_type) 289c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 290c7ebbbceSChristoph Hellwig return get_sas_device_type_names(phy->identify.device_type, buf); 291c7ebbbceSChristoph Hellwig } 292c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 293c7ebbbceSChristoph Hellwig 29407ba3a95SChristoph Hellwig static ssize_t do_sas_phy_reset(struct class_device *cdev, 29507ba3a95SChristoph Hellwig size_t count, int hard_reset) 29607ba3a95SChristoph Hellwig { 29707ba3a95SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 29807ba3a95SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 29907ba3a95SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 30007ba3a95SChristoph Hellwig int error; 30107ba3a95SChristoph Hellwig 30207ba3a95SChristoph Hellwig if (!phy->local_attached) 30307ba3a95SChristoph Hellwig return -EINVAL; 30407ba3a95SChristoph Hellwig 30507ba3a95SChristoph Hellwig error = i->f->phy_reset(phy, hard_reset); 30607ba3a95SChristoph Hellwig if (error) 30707ba3a95SChristoph Hellwig return error; 30807ba3a95SChristoph Hellwig return count; 30907ba3a95SChristoph Hellwig }; 31007ba3a95SChristoph Hellwig 31107ba3a95SChristoph Hellwig static ssize_t store_sas_link_reset(struct class_device *cdev, 31207ba3a95SChristoph Hellwig const char *buf, size_t count) 31307ba3a95SChristoph Hellwig { 31407ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 0); 31507ba3a95SChristoph Hellwig } 31607ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 31707ba3a95SChristoph Hellwig 31807ba3a95SChristoph Hellwig static ssize_t store_sas_hard_reset(struct class_device *cdev, 31907ba3a95SChristoph Hellwig const char *buf, size_t count) 32007ba3a95SChristoph Hellwig { 32107ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 1); 32207ba3a95SChristoph Hellwig } 32307ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 32407ba3a95SChristoph Hellwig 325c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.initiator_port_protocols, 326c7ebbbceSChristoph Hellwig initiator_port_protocols); 327c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.target_port_protocols, 328c7ebbbceSChristoph Hellwig target_port_protocols); 329c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 330c7ebbbceSChristoph Hellwig unsigned long long); 331c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 332c7ebbbceSChristoph Hellwig sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); 333c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(negotiated_linkrate); 334c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate_hw); 335c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate); 336c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate_hw); 337c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate); 338c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(invalid_dword_count); 339c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(running_disparity_error_count); 340c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(loss_of_dword_sync_count); 341c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(phy_reset_problem_count); 342c7ebbbceSChristoph Hellwig 343c7ebbbceSChristoph Hellwig 344c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_phy_class, 345c7ebbbceSChristoph Hellwig "sas_phy", NULL, NULL, NULL); 346c7ebbbceSChristoph Hellwig 347c7ebbbceSChristoph Hellwig static int sas_phy_match(struct attribute_container *cont, struct device *dev) 348c7ebbbceSChristoph Hellwig { 349c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 350c7ebbbceSChristoph Hellwig struct sas_internal *i; 351c7ebbbceSChristoph Hellwig 352c7ebbbceSChristoph Hellwig if (!scsi_is_sas_phy(dev)) 353c7ebbbceSChristoph Hellwig return 0; 354c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent); 355c7ebbbceSChristoph Hellwig 356c7ebbbceSChristoph Hellwig if (!shost->transportt) 357c7ebbbceSChristoph Hellwig return 0; 358c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 359c7ebbbceSChristoph Hellwig &sas_host_class.class) 360c7ebbbceSChristoph Hellwig return 0; 361c7ebbbceSChristoph Hellwig 362c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 363c7ebbbceSChristoph Hellwig return &i->phy_attr_cont.ac == cont; 364c7ebbbceSChristoph Hellwig } 365c7ebbbceSChristoph Hellwig 366c7ebbbceSChristoph Hellwig static void sas_phy_release(struct device *dev) 367c7ebbbceSChristoph Hellwig { 368c7ebbbceSChristoph Hellwig struct sas_phy *phy = dev_to_phy(dev); 369c7ebbbceSChristoph Hellwig 370c7ebbbceSChristoph Hellwig put_device(dev->parent); 371c7ebbbceSChristoph Hellwig kfree(phy); 372c7ebbbceSChristoph Hellwig } 373c7ebbbceSChristoph Hellwig 374c7ebbbceSChristoph Hellwig /** 375c7ebbbceSChristoph Hellwig * sas_phy_alloc -- allocates and initialize a SAS PHY structure 376c7ebbbceSChristoph Hellwig * @parent: Parent device 377c7ebbbceSChristoph Hellwig * @number: Port number 378c7ebbbceSChristoph Hellwig * 379c7ebbbceSChristoph Hellwig * Allocates an SAS PHY structure. It will be added in the device tree 380c7ebbbceSChristoph Hellwig * below the device specified by @parent, which has to be either a Scsi_Host 381c7ebbbceSChristoph Hellwig * or sas_rphy. 382c7ebbbceSChristoph Hellwig * 383c7ebbbceSChristoph Hellwig * Returns: 384c7ebbbceSChristoph Hellwig * SAS PHY allocated or %NULL if the allocation failed. 385c7ebbbceSChristoph Hellwig */ 386c7ebbbceSChristoph Hellwig struct sas_phy *sas_phy_alloc(struct device *parent, int number) 387c7ebbbceSChristoph Hellwig { 388c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent); 389c7ebbbceSChristoph Hellwig struct sas_phy *phy; 390c7ebbbceSChristoph Hellwig 391c7ebbbceSChristoph Hellwig phy = kmalloc(sizeof(*phy), GFP_KERNEL); 392c7ebbbceSChristoph Hellwig if (!phy) 393c7ebbbceSChristoph Hellwig return NULL; 394c7ebbbceSChristoph Hellwig memset(phy, 0, sizeof(*phy)); 395c7ebbbceSChristoph Hellwig 396c7ebbbceSChristoph Hellwig get_device(parent); 397c7ebbbceSChristoph Hellwig 398c7ebbbceSChristoph Hellwig phy->number = number; 399c7ebbbceSChristoph Hellwig 400c7ebbbceSChristoph Hellwig device_initialize(&phy->dev); 401c7ebbbceSChristoph Hellwig phy->dev.parent = get_device(parent); 402c7ebbbceSChristoph Hellwig phy->dev.release = sas_phy_release; 403c7ebbbceSChristoph Hellwig sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 404c7ebbbceSChristoph Hellwig 405c7ebbbceSChristoph Hellwig transport_setup_device(&phy->dev); 406c7ebbbceSChristoph Hellwig 407c7ebbbceSChristoph Hellwig return phy; 408c7ebbbceSChristoph Hellwig } 409c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_alloc); 410c7ebbbceSChristoph Hellwig 411c7ebbbceSChristoph Hellwig /** 412c7ebbbceSChristoph Hellwig * sas_phy_add -- add a SAS PHY to the device hierachy 413c7ebbbceSChristoph Hellwig * @phy: The PHY to be added 414c7ebbbceSChristoph Hellwig * 415c7ebbbceSChristoph Hellwig * Publishes a SAS PHY to the rest of the system. 416c7ebbbceSChristoph Hellwig */ 417c7ebbbceSChristoph Hellwig int sas_phy_add(struct sas_phy *phy) 418c7ebbbceSChristoph Hellwig { 419c7ebbbceSChristoph Hellwig int error; 420c7ebbbceSChristoph Hellwig 421c7ebbbceSChristoph Hellwig error = device_add(&phy->dev); 422c7ebbbceSChristoph Hellwig if (!error) { 423c7ebbbceSChristoph Hellwig transport_add_device(&phy->dev); 424c7ebbbceSChristoph Hellwig transport_configure_device(&phy->dev); 425c7ebbbceSChristoph Hellwig } 426c7ebbbceSChristoph Hellwig 427c7ebbbceSChristoph Hellwig return error; 428c7ebbbceSChristoph Hellwig } 429c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_add); 430c7ebbbceSChristoph Hellwig 431c7ebbbceSChristoph Hellwig /** 432c7ebbbceSChristoph Hellwig * sas_phy_free -- free a SAS PHY 433c7ebbbceSChristoph Hellwig * @phy: SAS PHY to free 434c7ebbbceSChristoph Hellwig * 435c7ebbbceSChristoph Hellwig * Frees the specified SAS PHY. 436c7ebbbceSChristoph Hellwig * 437c7ebbbceSChristoph Hellwig * Note: 438c7ebbbceSChristoph Hellwig * This function must only be called on a PHY that has not 439c7ebbbceSChristoph Hellwig * sucessfully been added using sas_phy_add(). 440c7ebbbceSChristoph Hellwig */ 441c7ebbbceSChristoph Hellwig void sas_phy_free(struct sas_phy *phy) 442c7ebbbceSChristoph Hellwig { 443c7ebbbceSChristoph Hellwig transport_destroy_device(&phy->dev); 444c7ebbbceSChristoph Hellwig put_device(phy->dev.parent); 445c7ebbbceSChristoph Hellwig put_device(phy->dev.parent); 446c7ebbbceSChristoph Hellwig put_device(phy->dev.parent); 447c7ebbbceSChristoph Hellwig kfree(phy); 448c7ebbbceSChristoph Hellwig } 449c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_free); 450c7ebbbceSChristoph Hellwig 451c7ebbbceSChristoph Hellwig /** 452c7ebbbceSChristoph Hellwig * sas_phy_delete -- remove SAS PHY 453c7ebbbceSChristoph Hellwig * @phy: SAS PHY to remove 454c7ebbbceSChristoph Hellwig * 455c7ebbbceSChristoph Hellwig * Removes the specified SAS PHY. If the SAS PHY has an 456c7ebbbceSChristoph Hellwig * associated remote PHY it is removed before. 457c7ebbbceSChristoph Hellwig */ 458c7ebbbceSChristoph Hellwig void 459c7ebbbceSChristoph Hellwig sas_phy_delete(struct sas_phy *phy) 460c7ebbbceSChristoph Hellwig { 461c7ebbbceSChristoph Hellwig struct device *dev = &phy->dev; 462c7ebbbceSChristoph Hellwig 463c7ebbbceSChristoph Hellwig if (phy->rphy) 464c7ebbbceSChristoph Hellwig sas_rphy_delete(phy->rphy); 465c7ebbbceSChristoph Hellwig 466c7ebbbceSChristoph Hellwig transport_remove_device(dev); 467c7ebbbceSChristoph Hellwig device_del(dev); 468c7ebbbceSChristoph Hellwig transport_destroy_device(dev); 469c7ebbbceSChristoph Hellwig put_device(dev->parent); 470c7ebbbceSChristoph Hellwig } 471c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_delete); 472c7ebbbceSChristoph Hellwig 473c7ebbbceSChristoph Hellwig /** 474c7ebbbceSChristoph Hellwig * scsi_is_sas_phy -- check if a struct device represents a SAS PHY 475c7ebbbceSChristoph Hellwig * @dev: device to check 476c7ebbbceSChristoph Hellwig * 477c7ebbbceSChristoph Hellwig * Returns: 478c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS PHY, %0 else 479c7ebbbceSChristoph Hellwig */ 480c7ebbbceSChristoph Hellwig int scsi_is_sas_phy(const struct device *dev) 481c7ebbbceSChristoph Hellwig { 482c7ebbbceSChristoph Hellwig return dev->release == sas_phy_release; 483c7ebbbceSChristoph Hellwig } 484c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_phy); 485c7ebbbceSChristoph Hellwig 486c7ebbbceSChristoph Hellwig /* 487c7ebbbceSChristoph Hellwig * SAS remote PHY attributes. 488c7ebbbceSChristoph Hellwig */ 489c7ebbbceSChristoph Hellwig 490c7ebbbceSChristoph Hellwig #define sas_rphy_show_simple(field, name, format_string, cast) \ 491c7ebbbceSChristoph Hellwig static ssize_t \ 492c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 493c7ebbbceSChristoph Hellwig { \ 494c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 495c7ebbbceSChristoph Hellwig \ 496c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast rphy->field); \ 497c7ebbbceSChristoph Hellwig } 498c7ebbbceSChristoph Hellwig 499c7ebbbceSChristoph Hellwig #define sas_rphy_simple_attr(field, name, format_string, type) \ 500c7ebbbceSChristoph Hellwig sas_rphy_show_simple(field, name, format_string, (type)) \ 501c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 502c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 503c7ebbbceSChristoph Hellwig 504c7ebbbceSChristoph Hellwig #define sas_rphy_show_protocol(field, name) \ 505c7ebbbceSChristoph Hellwig static ssize_t \ 506c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 507c7ebbbceSChristoph Hellwig { \ 508c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 509c7ebbbceSChristoph Hellwig \ 510c7ebbbceSChristoph Hellwig if (!rphy->field) \ 511c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 512c7ebbbceSChristoph Hellwig return get_sas_protocol_names(rphy->field, buf); \ 513c7ebbbceSChristoph Hellwig } 514c7ebbbceSChristoph Hellwig 515c7ebbbceSChristoph Hellwig #define sas_rphy_protocol_attr(field, name) \ 516c7ebbbceSChristoph Hellwig sas_rphy_show_protocol(field, name) \ 517c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 518c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 519c7ebbbceSChristoph Hellwig 520c7ebbbceSChristoph Hellwig static ssize_t 521c7ebbbceSChristoph Hellwig show_sas_rphy_device_type(struct class_device *cdev, char *buf) 522c7ebbbceSChristoph Hellwig { 523c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 524c7ebbbceSChristoph Hellwig 525c7ebbbceSChristoph Hellwig if (!rphy->identify.device_type) 526c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 527c7ebbbceSChristoph Hellwig return get_sas_device_type_names( 528c7ebbbceSChristoph Hellwig rphy->identify.device_type, buf); 529c7ebbbceSChristoph Hellwig } 530c7ebbbceSChristoph Hellwig 531c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 532c7ebbbceSChristoph Hellwig show_sas_rphy_device_type, NULL); 533c7ebbbceSChristoph Hellwig 534c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.initiator_port_protocols, 535c7ebbbceSChristoph Hellwig initiator_port_protocols); 536c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 537c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 538c7ebbbceSChristoph Hellwig unsigned long long); 539c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 540c7ebbbceSChristoph Hellwig 541c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 542c7ebbbceSChristoph Hellwig "sas_rphy", NULL, NULL, NULL); 543c7ebbbceSChristoph Hellwig 544c7ebbbceSChristoph Hellwig static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 545c7ebbbceSChristoph Hellwig { 546c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 547c7ebbbceSChristoph Hellwig struct sas_internal *i; 548c7ebbbceSChristoph Hellwig 549c7ebbbceSChristoph Hellwig if (!scsi_is_sas_rphy(dev)) 550c7ebbbceSChristoph Hellwig return 0; 551c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent->parent); 552c7ebbbceSChristoph Hellwig 553c7ebbbceSChristoph Hellwig if (!shost->transportt) 554c7ebbbceSChristoph Hellwig return 0; 555c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 556c7ebbbceSChristoph Hellwig &sas_host_class.class) 557c7ebbbceSChristoph Hellwig return 0; 558c7ebbbceSChristoph Hellwig 559c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 560c7ebbbceSChristoph Hellwig return &i->rphy_attr_cont.ac == cont; 561c7ebbbceSChristoph Hellwig } 562c7ebbbceSChristoph Hellwig 563c7ebbbceSChristoph Hellwig static void sas_rphy_release(struct device *dev) 564c7ebbbceSChristoph Hellwig { 565c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = dev_to_rphy(dev); 566c7ebbbceSChristoph Hellwig 567c7ebbbceSChristoph Hellwig put_device(dev->parent); 568c7ebbbceSChristoph Hellwig kfree(rphy); 569c7ebbbceSChristoph Hellwig } 570c7ebbbceSChristoph Hellwig 571c7ebbbceSChristoph Hellwig /** 572c7ebbbceSChristoph Hellwig * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure 573c7ebbbceSChristoph Hellwig * @parent: SAS PHY this remote PHY is conneted to 574c7ebbbceSChristoph Hellwig * 575c7ebbbceSChristoph Hellwig * Allocates an SAS remote PHY structure, connected to @parent. 576c7ebbbceSChristoph Hellwig * 577c7ebbbceSChristoph Hellwig * Returns: 578c7ebbbceSChristoph Hellwig * SAS PHY allocated or %NULL if the allocation failed. 579c7ebbbceSChristoph Hellwig */ 580c7ebbbceSChristoph Hellwig struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent) 581c7ebbbceSChristoph Hellwig { 582c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(&parent->dev); 583c7ebbbceSChristoph Hellwig struct sas_rphy *rphy; 584c7ebbbceSChristoph Hellwig 585c7ebbbceSChristoph Hellwig rphy = kmalloc(sizeof(*rphy), GFP_KERNEL); 586c7ebbbceSChristoph Hellwig if (!rphy) { 587c7ebbbceSChristoph Hellwig put_device(&parent->dev); 588c7ebbbceSChristoph Hellwig return NULL; 589c7ebbbceSChristoph Hellwig } 590c7ebbbceSChristoph Hellwig memset(rphy, 0, sizeof(*rphy)); 591c7ebbbceSChristoph Hellwig 592c7ebbbceSChristoph Hellwig device_initialize(&rphy->dev); 593c7ebbbceSChristoph Hellwig rphy->dev.parent = get_device(&parent->dev); 594c7ebbbceSChristoph Hellwig rphy->dev.release = sas_rphy_release; 595c7ebbbceSChristoph Hellwig sprintf(rphy->dev.bus_id, "rphy-%d:%d", 596c7ebbbceSChristoph Hellwig shost->host_no, parent->number); 597c7ebbbceSChristoph Hellwig transport_setup_device(&rphy->dev); 598c7ebbbceSChristoph Hellwig 599c7ebbbceSChristoph Hellwig return rphy; 600c7ebbbceSChristoph Hellwig } 601c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_alloc); 602c7ebbbceSChristoph Hellwig 603c7ebbbceSChristoph Hellwig /** 604c7ebbbceSChristoph Hellwig * sas_rphy_add -- add a SAS remote PHY to the device hierachy 605c7ebbbceSChristoph Hellwig * @rphy: The remote PHY to be added 606c7ebbbceSChristoph Hellwig * 607c7ebbbceSChristoph Hellwig * Publishes a SAS remote PHY to the rest of the system. 608c7ebbbceSChristoph Hellwig */ 609c7ebbbceSChristoph Hellwig int sas_rphy_add(struct sas_rphy *rphy) 610c7ebbbceSChristoph Hellwig { 611c7ebbbceSChristoph Hellwig struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 612c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 613c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 614c7ebbbceSChristoph Hellwig struct sas_identify *identify = &rphy->identify; 615c7ebbbceSChristoph Hellwig int error; 616c7ebbbceSChristoph Hellwig 617c7ebbbceSChristoph Hellwig if (parent->rphy) 618c7ebbbceSChristoph Hellwig return -ENXIO; 619c7ebbbceSChristoph Hellwig parent->rphy = rphy; 620c7ebbbceSChristoph Hellwig 621c7ebbbceSChristoph Hellwig error = device_add(&rphy->dev); 622c7ebbbceSChristoph Hellwig if (error) 623c7ebbbceSChristoph Hellwig return error; 624c7ebbbceSChristoph Hellwig transport_add_device(&rphy->dev); 625c7ebbbceSChristoph Hellwig transport_configure_device(&rphy->dev); 626c7ebbbceSChristoph Hellwig 627c7ebbbceSChristoph Hellwig spin_lock(&sas_host->lock); 628c7ebbbceSChristoph Hellwig list_add_tail(&rphy->list, &sas_host->rphy_list); 629c7ebbbceSChristoph Hellwig if (identify->device_type == SAS_END_DEVICE && 630c7ebbbceSChristoph Hellwig (identify->target_port_protocols & 631c7ebbbceSChristoph Hellwig (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 632c7ebbbceSChristoph Hellwig rphy->scsi_target_id = sas_host->next_target_id++; 633c7ebbbceSChristoph Hellwig else 634c7ebbbceSChristoph Hellwig rphy->scsi_target_id = -1; 635c7ebbbceSChristoph Hellwig spin_unlock(&sas_host->lock); 636c7ebbbceSChristoph Hellwig 637c7ebbbceSChristoph Hellwig if (rphy->scsi_target_id != -1) { 638c7ebbbceSChristoph Hellwig scsi_scan_target(&rphy->dev, parent->number, 639c7ebbbceSChristoph Hellwig rphy->scsi_target_id, ~0, 0); 640c7ebbbceSChristoph Hellwig } 641c7ebbbceSChristoph Hellwig 642c7ebbbceSChristoph Hellwig return 0; 643c7ebbbceSChristoph Hellwig } 644c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_add); 645c7ebbbceSChristoph Hellwig 646c7ebbbceSChristoph Hellwig /** 647c7ebbbceSChristoph Hellwig * sas_rphy_free -- free a SAS remote PHY 648c7ebbbceSChristoph Hellwig * @rphy SAS remote PHY to free 649c7ebbbceSChristoph Hellwig * 650c7ebbbceSChristoph Hellwig * Frees the specified SAS remote PHY. 651c7ebbbceSChristoph Hellwig * 652c7ebbbceSChristoph Hellwig * Note: 653c7ebbbceSChristoph Hellwig * This function must only be called on a remote 654c7ebbbceSChristoph Hellwig * PHY that has not sucessfully been added using 655c7ebbbceSChristoph Hellwig * sas_rphy_add(). 656c7ebbbceSChristoph Hellwig */ 657c7ebbbceSChristoph Hellwig void sas_rphy_free(struct sas_rphy *rphy) 658c7ebbbceSChristoph Hellwig { 659c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 660c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 661c7ebbbceSChristoph Hellwig 662c7ebbbceSChristoph Hellwig spin_lock(&sas_host->lock); 663c7ebbbceSChristoph Hellwig list_del(&rphy->list); 664c7ebbbceSChristoph Hellwig spin_unlock(&sas_host->lock); 665c7ebbbceSChristoph Hellwig 666c7ebbbceSChristoph Hellwig transport_destroy_device(&rphy->dev); 667c7ebbbceSChristoph Hellwig put_device(rphy->dev.parent); 668c7ebbbceSChristoph Hellwig put_device(rphy->dev.parent); 669c7ebbbceSChristoph Hellwig put_device(rphy->dev.parent); 670c7ebbbceSChristoph Hellwig kfree(rphy); 671c7ebbbceSChristoph Hellwig } 672c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_free); 673c7ebbbceSChristoph Hellwig 674c7ebbbceSChristoph Hellwig /** 675c7ebbbceSChristoph Hellwig * sas_rphy_delete -- remove SAS remote PHY 676c7ebbbceSChristoph Hellwig * @rphy: SAS remote PHY to remove 677c7ebbbceSChristoph Hellwig * 678c7ebbbceSChristoph Hellwig * Removes the specified SAS remote PHY. 679c7ebbbceSChristoph Hellwig */ 680c7ebbbceSChristoph Hellwig void 681c7ebbbceSChristoph Hellwig sas_rphy_delete(struct sas_rphy *rphy) 682c7ebbbceSChristoph Hellwig { 683c7ebbbceSChristoph Hellwig struct device *dev = &rphy->dev; 684c7ebbbceSChristoph Hellwig struct sas_phy *parent = dev_to_phy(dev->parent); 685c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 686c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 687c7ebbbceSChristoph Hellwig 688fe8b2304SChristoph Hellwig scsi_remove_target(dev); 689c7ebbbceSChristoph Hellwig 690fe8b2304SChristoph Hellwig transport_remove_device(dev); 691fe8b2304SChristoph Hellwig device_del(dev); 692fe8b2304SChristoph Hellwig transport_destroy_device(dev); 693c7ebbbceSChristoph Hellwig 694c7ebbbceSChristoph Hellwig spin_lock(&sas_host->lock); 695c7ebbbceSChristoph Hellwig list_del(&rphy->list); 696c7ebbbceSChristoph Hellwig spin_unlock(&sas_host->lock); 697c7ebbbceSChristoph Hellwig 698c7ebbbceSChristoph Hellwig put_device(&parent->dev); 699c7ebbbceSChristoph Hellwig } 700c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_delete); 701c7ebbbceSChristoph Hellwig 702c7ebbbceSChristoph Hellwig /** 703c7ebbbceSChristoph Hellwig * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 704c7ebbbceSChristoph Hellwig * @dev: device to check 705c7ebbbceSChristoph Hellwig * 706c7ebbbceSChristoph Hellwig * Returns: 707c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS remote PHY, %0 else 708c7ebbbceSChristoph Hellwig */ 709c7ebbbceSChristoph Hellwig int scsi_is_sas_rphy(const struct device *dev) 710c7ebbbceSChristoph Hellwig { 711c7ebbbceSChristoph Hellwig return dev->release == sas_rphy_release; 712c7ebbbceSChristoph Hellwig } 713c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_rphy); 714c7ebbbceSChristoph Hellwig 715c7ebbbceSChristoph Hellwig 716c7ebbbceSChristoph Hellwig /* 717c7ebbbceSChristoph Hellwig * SCSI scan helper 718c7ebbbceSChristoph Hellwig */ 719c7ebbbceSChristoph Hellwig 720c7ebbbceSChristoph Hellwig static struct device *sas_target_parent(struct Scsi_Host *shost, 721c7ebbbceSChristoph Hellwig int channel, uint id) 722c7ebbbceSChristoph Hellwig { 723c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 724c7ebbbceSChristoph Hellwig struct sas_rphy *rphy; 725c7ebbbceSChristoph Hellwig struct device *dev = NULL; 726c7ebbbceSChristoph Hellwig 727c7ebbbceSChristoph Hellwig spin_lock(&sas_host->lock); 728c7ebbbceSChristoph Hellwig list_for_each_entry(rphy, &sas_host->rphy_list, list) { 729c7ebbbceSChristoph Hellwig struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 730c7ebbbceSChristoph Hellwig if (parent->number == channel && 731c7ebbbceSChristoph Hellwig rphy->scsi_target_id == id) 732c7ebbbceSChristoph Hellwig dev = &rphy->dev; 733c7ebbbceSChristoph Hellwig } 734c7ebbbceSChristoph Hellwig spin_unlock(&sas_host->lock); 735c7ebbbceSChristoph Hellwig 736c7ebbbceSChristoph Hellwig return dev; 737c7ebbbceSChristoph Hellwig } 738c7ebbbceSChristoph Hellwig 739c7ebbbceSChristoph Hellwig 740c7ebbbceSChristoph Hellwig /* 741c7ebbbceSChristoph Hellwig * Setup / Teardown code 742c7ebbbceSChristoph Hellwig */ 743c7ebbbceSChristoph Hellwig 744c7ebbbceSChristoph Hellwig #define SETUP_RPORT_ATTRIBUTE(field) \ 745c7ebbbceSChristoph Hellwig i->private_rphy_attrs[count] = class_device_attr_##field; \ 746c7ebbbceSChristoph Hellwig i->private_rphy_attrs[count].attr.mode = S_IRUGO; \ 747c7ebbbceSChristoph Hellwig i->private_rphy_attrs[count].store = NULL; \ 748c7ebbbceSChristoph Hellwig i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \ 749c7ebbbceSChristoph Hellwig count++ 750c7ebbbceSChristoph Hellwig 751c7ebbbceSChristoph Hellwig #define SETUP_PORT_ATTRIBUTE(field) \ 752c7ebbbceSChristoph Hellwig i->private_phy_attrs[count] = class_device_attr_##field; \ 753c7ebbbceSChristoph Hellwig i->private_phy_attrs[count].attr.mode = S_IRUGO; \ 754c7ebbbceSChristoph Hellwig i->private_phy_attrs[count].store = NULL; \ 755c7ebbbceSChristoph Hellwig i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 756c7ebbbceSChristoph Hellwig count++ 757c7ebbbceSChristoph Hellwig 75807ba3a95SChristoph Hellwig #define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 75907ba3a95SChristoph Hellwig i->private_phy_attrs[count] = class_device_attr_##field; \ 76007ba3a95SChristoph Hellwig i->private_phy_attrs[count].attr.mode = S_IWUGO; \ 76107ba3a95SChristoph Hellwig i->private_phy_attrs[count].show = NULL; \ 76207ba3a95SChristoph Hellwig i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 76307ba3a95SChristoph Hellwig count++ 76407ba3a95SChristoph Hellwig 765c7ebbbceSChristoph Hellwig 766c7ebbbceSChristoph Hellwig /** 767c7ebbbceSChristoph Hellwig * sas_attach_transport -- instantiate SAS transport template 768c7ebbbceSChristoph Hellwig * @ft: SAS transport class function template 769c7ebbbceSChristoph Hellwig */ 770c7ebbbceSChristoph Hellwig struct scsi_transport_template * 771c7ebbbceSChristoph Hellwig sas_attach_transport(struct sas_function_template *ft) 772c7ebbbceSChristoph Hellwig { 773c7ebbbceSChristoph Hellwig struct sas_internal *i; 774c7ebbbceSChristoph Hellwig int count; 775c7ebbbceSChristoph Hellwig 776c7ebbbceSChristoph Hellwig i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL); 777c7ebbbceSChristoph Hellwig if (!i) 778c7ebbbceSChristoph Hellwig return NULL; 779c7ebbbceSChristoph Hellwig memset(i, 0, sizeof(struct sas_internal)); 780c7ebbbceSChristoph Hellwig 781c7ebbbceSChristoph Hellwig i->t.target_parent = sas_target_parent; 782c7ebbbceSChristoph Hellwig 783c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 784c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.class = &sas_host_class.class; 785c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.match = sas_host_match; 786c7ebbbceSChristoph Hellwig transport_container_register(&i->t.host_attrs); 787c7ebbbceSChristoph Hellwig i->t.host_size = sizeof(struct sas_host_attrs); 788c7ebbbceSChristoph Hellwig 789c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.class = &sas_phy_class.class; 790c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 791c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.match = sas_phy_match; 792c7ebbbceSChristoph Hellwig transport_container_register(&i->phy_attr_cont); 793c7ebbbceSChristoph Hellwig 794c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 795c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 796c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.match = sas_rphy_match; 797c7ebbbceSChristoph Hellwig transport_container_register(&i->rphy_attr_cont); 798c7ebbbceSChristoph Hellwig 799c7ebbbceSChristoph Hellwig i->f = ft; 800c7ebbbceSChristoph Hellwig 801c7ebbbceSChristoph Hellwig count = 0; 802c7ebbbceSChristoph Hellwig i->host_attrs[count] = NULL; 803c7ebbbceSChristoph Hellwig 804c7ebbbceSChristoph Hellwig count = 0; 805c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(initiator_port_protocols); 806c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(target_port_protocols); 807c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(device_type); 808c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(sas_address); 809c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(phy_identifier); 810c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(port_identifier); 811c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(negotiated_linkrate); 812c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); 813c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(minimum_linkrate); 814c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); 815c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(maximum_linkrate); 816c3ee74c4SChristoph Hellwig 817c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(invalid_dword_count); 818c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 819c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 820c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 82107ba3a95SChristoph Hellwig SETUP_PORT_ATTRIBUTE_WRONLY(link_reset); 82207ba3a95SChristoph Hellwig SETUP_PORT_ATTRIBUTE_WRONLY(hard_reset); 823c7ebbbceSChristoph Hellwig i->phy_attrs[count] = NULL; 824c7ebbbceSChristoph Hellwig 825c7ebbbceSChristoph Hellwig count = 0; 826c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 827c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 828c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_device_type); 829c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 830c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 831c7ebbbceSChristoph Hellwig i->rphy_attrs[count] = NULL; 832c7ebbbceSChristoph Hellwig 833c7ebbbceSChristoph Hellwig return &i->t; 834c7ebbbceSChristoph Hellwig } 835c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_attach_transport); 836c7ebbbceSChristoph Hellwig 837c7ebbbceSChristoph Hellwig /** 838c7ebbbceSChristoph Hellwig * sas_release_transport -- release SAS transport template instance 839c7ebbbceSChristoph Hellwig * @t: transport template instance 840c7ebbbceSChristoph Hellwig */ 841c7ebbbceSChristoph Hellwig void sas_release_transport(struct scsi_transport_template *t) 842c7ebbbceSChristoph Hellwig { 843c7ebbbceSChristoph Hellwig struct sas_internal *i = to_sas_internal(t); 844c7ebbbceSChristoph Hellwig 845c7ebbbceSChristoph Hellwig transport_container_unregister(&i->t.host_attrs); 846c7ebbbceSChristoph Hellwig transport_container_unregister(&i->phy_attr_cont); 847c7ebbbceSChristoph Hellwig transport_container_unregister(&i->rphy_attr_cont); 848c7ebbbceSChristoph Hellwig 849c7ebbbceSChristoph Hellwig kfree(i); 850c7ebbbceSChristoph Hellwig } 851c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_release_transport); 852c7ebbbceSChristoph Hellwig 853c7ebbbceSChristoph Hellwig static __init int sas_transport_init(void) 854c7ebbbceSChristoph Hellwig { 855c7ebbbceSChristoph Hellwig int error; 856c7ebbbceSChristoph Hellwig 857c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_host_class); 858c7ebbbceSChristoph Hellwig if (error) 859c7ebbbceSChristoph Hellwig goto out; 860c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_phy_class); 861c7ebbbceSChristoph Hellwig if (error) 862c7ebbbceSChristoph Hellwig goto out_unregister_transport; 863c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_rphy_class); 864c7ebbbceSChristoph Hellwig if (error) 865c7ebbbceSChristoph Hellwig goto out_unregister_phy; 866c7ebbbceSChristoph Hellwig 867c7ebbbceSChristoph Hellwig return 0; 868c7ebbbceSChristoph Hellwig 869c7ebbbceSChristoph Hellwig out_unregister_phy: 870c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 871c7ebbbceSChristoph Hellwig out_unregister_transport: 872c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 873c7ebbbceSChristoph Hellwig out: 874c7ebbbceSChristoph Hellwig return error; 875c7ebbbceSChristoph Hellwig 876c7ebbbceSChristoph Hellwig } 877c7ebbbceSChristoph Hellwig 878c7ebbbceSChristoph Hellwig static void __exit sas_transport_exit(void) 879c7ebbbceSChristoph Hellwig { 880c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 881c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 882c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_rphy_class); 883c7ebbbceSChristoph Hellwig } 884c7ebbbceSChristoph Hellwig 885c7ebbbceSChristoph Hellwig MODULE_AUTHOR("Christoph Hellwig"); 886c7ebbbceSChristoph Hellwig MODULE_DESCRIPTION("SAS Transphy Attributes"); 887c7ebbbceSChristoph Hellwig MODULE_LICENSE("GPL"); 888c7ebbbceSChristoph Hellwig 889c7ebbbceSChristoph Hellwig module_init(sas_transport_init); 890c7ebbbceSChristoph Hellwig module_exit(sas_transport_exit); 891