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