1c7ebbbceSChristoph Hellwig /* 2a0125641SChristoph Hellwig * Copyright (C) 2005-2006 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 41a0125641SChristoph Hellwig #define SAS_RPORT_ATTRS 7 4242ab0360SJames Bottomley #define SAS_END_DEV_ATTRS 3 43c7ebbbceSChristoph Hellwig 44c7ebbbceSChristoph Hellwig struct sas_internal { 45c7ebbbceSChristoph Hellwig struct scsi_transport_template t; 46c7ebbbceSChristoph Hellwig struct sas_function_template *f; 47c7ebbbceSChristoph Hellwig 48c7ebbbceSChristoph Hellwig struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; 49c7ebbbceSChristoph Hellwig struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; 50c7ebbbceSChristoph Hellwig struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 5142ab0360SJames Bottomley struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; 52c7ebbbceSChristoph Hellwig 53c7ebbbceSChristoph Hellwig struct transport_container phy_attr_cont; 54c7ebbbceSChristoph Hellwig struct transport_container rphy_attr_cont; 5542ab0360SJames Bottomley struct transport_container end_dev_attr_cont; 56c7ebbbceSChristoph Hellwig 57c7ebbbceSChristoph Hellwig /* 58c7ebbbceSChristoph Hellwig * The array of null terminated pointers to attributes 59c7ebbbceSChristoph Hellwig * needed by scsi_sysfs.c 60c7ebbbceSChristoph Hellwig */ 61c7ebbbceSChristoph Hellwig struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; 62c7ebbbceSChristoph Hellwig struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 63c7ebbbceSChristoph Hellwig struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 6442ab0360SJames Bottomley struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; 65c7ebbbceSChristoph Hellwig }; 66c7ebbbceSChristoph Hellwig #define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) 67c7ebbbceSChristoph Hellwig 68c7ebbbceSChristoph Hellwig struct sas_host_attrs { 69c7ebbbceSChristoph Hellwig struct list_head rphy_list; 70e02f3f59SChristoph Hellwig struct mutex lock; 71c7ebbbceSChristoph Hellwig u32 next_target_id; 72c7ebbbceSChristoph Hellwig }; 73c7ebbbceSChristoph Hellwig #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 74c7ebbbceSChristoph Hellwig 75c7ebbbceSChristoph Hellwig 76c7ebbbceSChristoph Hellwig /* 77c7ebbbceSChristoph Hellwig * Hack to allow attributes of the same name in different objects. 78c7ebbbceSChristoph Hellwig */ 79c7ebbbceSChristoph Hellwig #define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ 80c7ebbbceSChristoph Hellwig struct class_device_attribute class_device_attr_##_prefix##_##_name = \ 81c7ebbbceSChristoph Hellwig __ATTR(_name,_mode,_show,_store) 82c7ebbbceSChristoph Hellwig 83c7ebbbceSChristoph Hellwig 84c7ebbbceSChristoph Hellwig /* 85c7ebbbceSChristoph Hellwig * Pretty printing helpers 86c7ebbbceSChristoph Hellwig */ 87c7ebbbceSChristoph Hellwig 88c7ebbbceSChristoph Hellwig #define sas_bitfield_name_match(title, table) \ 89c7ebbbceSChristoph Hellwig static ssize_t \ 90c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 91c7ebbbceSChristoph Hellwig { \ 92c7ebbbceSChristoph Hellwig char *prefix = ""; \ 93c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 94c7ebbbceSChristoph Hellwig int i; \ 95c7ebbbceSChristoph Hellwig \ 96c7ebbbceSChristoph Hellwig for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 97c7ebbbceSChristoph Hellwig if (table[i].value & table_key) { \ 98c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s%s", \ 99c7ebbbceSChristoph Hellwig prefix, table[i].name); \ 100c7ebbbceSChristoph Hellwig prefix = ", "; \ 101c7ebbbceSChristoph Hellwig } \ 102c7ebbbceSChristoph Hellwig } \ 103c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 104c7ebbbceSChristoph Hellwig return len; \ 105c7ebbbceSChristoph Hellwig } 106c7ebbbceSChristoph Hellwig 107c7ebbbceSChristoph Hellwig #define sas_bitfield_name_search(title, table) \ 108c7ebbbceSChristoph Hellwig static ssize_t \ 109c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 110c7ebbbceSChristoph Hellwig { \ 111c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 112c7ebbbceSChristoph Hellwig int i; \ 113c7ebbbceSChristoph Hellwig \ 114c7ebbbceSChristoph Hellwig for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 115c7ebbbceSChristoph Hellwig if (table[i].value == table_key) { \ 116c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s", \ 117c7ebbbceSChristoph Hellwig table[i].name); \ 118c7ebbbceSChristoph Hellwig break; \ 119c7ebbbceSChristoph Hellwig } \ 120c7ebbbceSChristoph Hellwig } \ 121c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 122c7ebbbceSChristoph Hellwig return len; \ 123c7ebbbceSChristoph Hellwig } 124c7ebbbceSChristoph Hellwig 125c7ebbbceSChristoph Hellwig static struct { 126c7ebbbceSChristoph Hellwig u32 value; 127c7ebbbceSChristoph Hellwig char *name; 128c7ebbbceSChristoph Hellwig } sas_device_type_names[] = { 129c7ebbbceSChristoph Hellwig { SAS_PHY_UNUSED, "unused" }, 130c7ebbbceSChristoph Hellwig { SAS_END_DEVICE, "end device" }, 131c7ebbbceSChristoph Hellwig { SAS_EDGE_EXPANDER_DEVICE, "edge expander" }, 132c7ebbbceSChristoph Hellwig { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" }, 133c7ebbbceSChristoph Hellwig }; 134c7ebbbceSChristoph Hellwig sas_bitfield_name_search(device_type, sas_device_type_names) 135c7ebbbceSChristoph Hellwig 136c7ebbbceSChristoph Hellwig 137c7ebbbceSChristoph Hellwig static struct { 138c7ebbbceSChristoph Hellwig u32 value; 139c7ebbbceSChristoph Hellwig char *name; 140c7ebbbceSChristoph Hellwig } sas_protocol_names[] = { 141c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SATA, "sata" }, 142c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SMP, "smp" }, 143c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_STP, "stp" }, 144c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SSP, "ssp" }, 145c7ebbbceSChristoph Hellwig }; 146c7ebbbceSChristoph Hellwig sas_bitfield_name_match(protocol, sas_protocol_names) 147c7ebbbceSChristoph Hellwig 148c7ebbbceSChristoph Hellwig static struct { 149c7ebbbceSChristoph Hellwig u32 value; 150c7ebbbceSChristoph Hellwig char *name; 151c7ebbbceSChristoph Hellwig } sas_linkspeed_names[] = { 152c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_UNKNOWN, "Unknown" }, 153c7ebbbceSChristoph Hellwig { SAS_PHY_DISABLED, "Phy disabled" }, 154c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_FAILED, "Link Rate failed" }, 155c7ebbbceSChristoph Hellwig { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, 156c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 157c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 1587e6dff62SJames Bottomley { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, 159c7ebbbceSChristoph Hellwig }; 160c7ebbbceSChristoph Hellwig sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 161c7ebbbceSChristoph Hellwig 162c7ebbbceSChristoph Hellwig 163c7ebbbceSChristoph Hellwig /* 164c7ebbbceSChristoph Hellwig * SAS host attributes 165c7ebbbceSChristoph Hellwig */ 166c7ebbbceSChristoph Hellwig 16737be6eebSJames Bottomley static int sas_host_setup(struct transport_container *tc, struct device *dev, 16837be6eebSJames Bottomley struct class_device *cdev) 169c7ebbbceSChristoph Hellwig { 170c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(dev); 171c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 172c7ebbbceSChristoph Hellwig 173c7ebbbceSChristoph Hellwig INIT_LIST_HEAD(&sas_host->rphy_list); 174e02f3f59SChristoph Hellwig mutex_init(&sas_host->lock); 175c7ebbbceSChristoph Hellwig sas_host->next_target_id = 0; 176c7ebbbceSChristoph Hellwig return 0; 177c7ebbbceSChristoph Hellwig } 178c7ebbbceSChristoph Hellwig 179c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_host_class, 180c7ebbbceSChristoph Hellwig "sas_host", sas_host_setup, NULL, NULL); 181c7ebbbceSChristoph Hellwig 182c7ebbbceSChristoph Hellwig static int sas_host_match(struct attribute_container *cont, 183c7ebbbceSChristoph Hellwig struct device *dev) 184c7ebbbceSChristoph Hellwig { 185c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 186c7ebbbceSChristoph Hellwig struct sas_internal *i; 187c7ebbbceSChristoph Hellwig 188c7ebbbceSChristoph Hellwig if (!scsi_is_host_device(dev)) 189c7ebbbceSChristoph Hellwig return 0; 190c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev); 191c7ebbbceSChristoph Hellwig 192c7ebbbceSChristoph Hellwig if (!shost->transportt) 193c7ebbbceSChristoph Hellwig return 0; 194c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 195c7ebbbceSChristoph Hellwig &sas_host_class.class) 196c7ebbbceSChristoph Hellwig return 0; 197c7ebbbceSChristoph Hellwig 198c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 199c7ebbbceSChristoph Hellwig return &i->t.host_attrs.ac == cont; 200c7ebbbceSChristoph Hellwig } 201c7ebbbceSChristoph Hellwig 202c7ebbbceSChristoph Hellwig static int do_sas_phy_delete(struct device *dev, void *data) 203c7ebbbceSChristoph Hellwig { 204c7ebbbceSChristoph Hellwig if (scsi_is_sas_phy(dev)) 205c7ebbbceSChristoph Hellwig sas_phy_delete(dev_to_phy(dev)); 206c7ebbbceSChristoph Hellwig return 0; 207c7ebbbceSChristoph Hellwig } 208c7ebbbceSChristoph Hellwig 209c7ebbbceSChristoph Hellwig /** 210c7ebbbceSChristoph Hellwig * sas_remove_host -- tear down a Scsi_Host's SAS data structures 211c7ebbbceSChristoph Hellwig * @shost: Scsi Host that is torn down 212c7ebbbceSChristoph Hellwig * 213c7ebbbceSChristoph Hellwig * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 214c7ebbbceSChristoph Hellwig * Must be called just before scsi_remove_host for SAS HBAs. 215c7ebbbceSChristoph Hellwig */ 216c7ebbbceSChristoph Hellwig void sas_remove_host(struct Scsi_Host *shost) 217c7ebbbceSChristoph Hellwig { 218c7ebbbceSChristoph Hellwig device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); 219c7ebbbceSChristoph Hellwig } 220c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_remove_host); 221c7ebbbceSChristoph Hellwig 222c7ebbbceSChristoph Hellwig 223c7ebbbceSChristoph Hellwig /* 224c7ebbbceSChristoph Hellwig * SAS Port attributes 225c7ebbbceSChristoph Hellwig */ 226c7ebbbceSChristoph Hellwig 227c7ebbbceSChristoph Hellwig #define sas_phy_show_simple(field, name, format_string, cast) \ 228c7ebbbceSChristoph Hellwig static ssize_t \ 229c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 230c7ebbbceSChristoph Hellwig { \ 231c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 232c7ebbbceSChristoph Hellwig \ 233c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast phy->field); \ 234c7ebbbceSChristoph Hellwig } 235c7ebbbceSChristoph Hellwig 236c7ebbbceSChristoph Hellwig #define sas_phy_simple_attr(field, name, format_string, type) \ 237c7ebbbceSChristoph Hellwig sas_phy_show_simple(field, name, format_string, (type)) \ 238c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 239c7ebbbceSChristoph Hellwig 240c7ebbbceSChristoph Hellwig #define sas_phy_show_protocol(field, name) \ 241c7ebbbceSChristoph Hellwig static ssize_t \ 242c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 243c7ebbbceSChristoph Hellwig { \ 244c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 245c7ebbbceSChristoph Hellwig \ 246c7ebbbceSChristoph Hellwig if (!phy->field) \ 247c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 248c7ebbbceSChristoph Hellwig return get_sas_protocol_names(phy->field, buf); \ 249c7ebbbceSChristoph Hellwig } 250c7ebbbceSChristoph Hellwig 251c7ebbbceSChristoph Hellwig #define sas_phy_protocol_attr(field, name) \ 252c7ebbbceSChristoph Hellwig sas_phy_show_protocol(field, name) \ 253c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 254c7ebbbceSChristoph Hellwig 255c7ebbbceSChristoph Hellwig #define sas_phy_show_linkspeed(field) \ 256c7ebbbceSChristoph Hellwig static ssize_t \ 257c7ebbbceSChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 258c7ebbbceSChristoph Hellwig { \ 259c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 260c7ebbbceSChristoph Hellwig \ 261c7ebbbceSChristoph Hellwig return get_sas_linkspeed_names(phy->field, buf); \ 262c7ebbbceSChristoph Hellwig } 263c7ebbbceSChristoph Hellwig 264c7ebbbceSChristoph Hellwig #define sas_phy_linkspeed_attr(field) \ 265c7ebbbceSChristoph Hellwig sas_phy_show_linkspeed(field) \ 266c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 267c7ebbbceSChristoph Hellwig 268c3ee74c4SChristoph Hellwig #define sas_phy_show_linkerror(field) \ 269c3ee74c4SChristoph Hellwig static ssize_t \ 270c3ee74c4SChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 271c3ee74c4SChristoph Hellwig { \ 272c3ee74c4SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 273c3ee74c4SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 274c3ee74c4SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); \ 275c3ee74c4SChristoph Hellwig int error; \ 276c3ee74c4SChristoph Hellwig \ 277ac01bbbdSChristoph Hellwig if (!phy->local_attached) \ 278ac01bbbdSChristoph Hellwig return -EINVAL; \ 279ac01bbbdSChristoph Hellwig \ 280dd9fbb52SJames Bottomley error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ 281c3ee74c4SChristoph Hellwig if (error) \ 282c3ee74c4SChristoph Hellwig return error; \ 283c3ee74c4SChristoph Hellwig return snprintf(buf, 20, "%u\n", phy->field); \ 284c3ee74c4SChristoph Hellwig } 285c3ee74c4SChristoph Hellwig 286c3ee74c4SChristoph Hellwig #define sas_phy_linkerror_attr(field) \ 287c3ee74c4SChristoph Hellwig sas_phy_show_linkerror(field) \ 288c3ee74c4SChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 289c3ee74c4SChristoph Hellwig 290c3ee74c4SChristoph Hellwig 291c7ebbbceSChristoph Hellwig static ssize_t 292c7ebbbceSChristoph Hellwig show_sas_device_type(struct class_device *cdev, char *buf) 293c7ebbbceSChristoph Hellwig { 294c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 295c7ebbbceSChristoph Hellwig 296c7ebbbceSChristoph Hellwig if (!phy->identify.device_type) 297c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 298c7ebbbceSChristoph Hellwig return get_sas_device_type_names(phy->identify.device_type, buf); 299c7ebbbceSChristoph Hellwig } 300c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 301c7ebbbceSChristoph Hellwig 30207ba3a95SChristoph Hellwig static ssize_t do_sas_phy_reset(struct class_device *cdev, 30307ba3a95SChristoph Hellwig size_t count, int hard_reset) 30407ba3a95SChristoph Hellwig { 30507ba3a95SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 30607ba3a95SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 30707ba3a95SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 30807ba3a95SChristoph Hellwig int error; 30907ba3a95SChristoph Hellwig 31007ba3a95SChristoph Hellwig if (!phy->local_attached) 31107ba3a95SChristoph Hellwig return -EINVAL; 31207ba3a95SChristoph Hellwig 31307ba3a95SChristoph Hellwig error = i->f->phy_reset(phy, hard_reset); 31407ba3a95SChristoph Hellwig if (error) 31507ba3a95SChristoph Hellwig return error; 31607ba3a95SChristoph Hellwig return count; 31707ba3a95SChristoph Hellwig }; 31807ba3a95SChristoph Hellwig 31907ba3a95SChristoph Hellwig static ssize_t store_sas_link_reset(struct class_device *cdev, 32007ba3a95SChristoph Hellwig const char *buf, size_t count) 32107ba3a95SChristoph Hellwig { 32207ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 0); 32307ba3a95SChristoph Hellwig } 32407ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 32507ba3a95SChristoph Hellwig 32607ba3a95SChristoph Hellwig static ssize_t store_sas_hard_reset(struct class_device *cdev, 32707ba3a95SChristoph Hellwig const char *buf, size_t count) 32807ba3a95SChristoph Hellwig { 32907ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 1); 33007ba3a95SChristoph Hellwig } 33107ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 33207ba3a95SChristoph Hellwig 333c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.initiator_port_protocols, 334c7ebbbceSChristoph Hellwig initiator_port_protocols); 335c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.target_port_protocols, 336c7ebbbceSChristoph Hellwig target_port_protocols); 337c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 338c7ebbbceSChristoph Hellwig unsigned long long); 339c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 340c7ebbbceSChristoph Hellwig sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); 341c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(negotiated_linkrate); 342c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate_hw); 343c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate); 344c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate_hw); 345c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate); 346c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(invalid_dword_count); 347c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(running_disparity_error_count); 348c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(loss_of_dword_sync_count); 349c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(phy_reset_problem_count); 350c7ebbbceSChristoph Hellwig 351c7ebbbceSChristoph Hellwig 352c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_phy_class, 353c7ebbbceSChristoph Hellwig "sas_phy", NULL, NULL, NULL); 354c7ebbbceSChristoph Hellwig 355c7ebbbceSChristoph Hellwig static int sas_phy_match(struct attribute_container *cont, struct device *dev) 356c7ebbbceSChristoph Hellwig { 357c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 358c7ebbbceSChristoph Hellwig struct sas_internal *i; 359c7ebbbceSChristoph Hellwig 360c7ebbbceSChristoph Hellwig if (!scsi_is_sas_phy(dev)) 361c7ebbbceSChristoph Hellwig return 0; 362c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent); 363c7ebbbceSChristoph Hellwig 364c7ebbbceSChristoph Hellwig if (!shost->transportt) 365c7ebbbceSChristoph Hellwig return 0; 366c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 367c7ebbbceSChristoph Hellwig &sas_host_class.class) 368c7ebbbceSChristoph Hellwig return 0; 369c7ebbbceSChristoph Hellwig 370c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 371c7ebbbceSChristoph Hellwig return &i->phy_attr_cont.ac == cont; 372c7ebbbceSChristoph Hellwig } 373c7ebbbceSChristoph Hellwig 374c7ebbbceSChristoph Hellwig static void sas_phy_release(struct device *dev) 375c7ebbbceSChristoph Hellwig { 376c7ebbbceSChristoph Hellwig struct sas_phy *phy = dev_to_phy(dev); 377c7ebbbceSChristoph Hellwig 378c7ebbbceSChristoph Hellwig put_device(dev->parent); 379c7ebbbceSChristoph Hellwig kfree(phy); 380c7ebbbceSChristoph Hellwig } 381c7ebbbceSChristoph Hellwig 382c7ebbbceSChristoph Hellwig /** 383c7ebbbceSChristoph Hellwig * sas_phy_alloc -- allocates and initialize a SAS PHY structure 384c7ebbbceSChristoph Hellwig * @parent: Parent device 385d99ca418SMoore, Eric * @number: Phy index 386c7ebbbceSChristoph Hellwig * 387c7ebbbceSChristoph Hellwig * Allocates an SAS PHY structure. It will be added in the device tree 388c7ebbbceSChristoph Hellwig * below the device specified by @parent, which has to be either a Scsi_Host 389c7ebbbceSChristoph Hellwig * or sas_rphy. 390c7ebbbceSChristoph Hellwig * 391c7ebbbceSChristoph Hellwig * Returns: 392c7ebbbceSChristoph Hellwig * SAS PHY allocated or %NULL if the allocation failed. 393c7ebbbceSChristoph Hellwig */ 394c7ebbbceSChristoph Hellwig struct sas_phy *sas_phy_alloc(struct device *parent, int number) 395c7ebbbceSChristoph Hellwig { 396c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent); 397c7ebbbceSChristoph Hellwig struct sas_phy *phy; 398c7ebbbceSChristoph Hellwig 39924669f75SJes Sorensen phy = kzalloc(sizeof(*phy), GFP_KERNEL); 400c7ebbbceSChristoph Hellwig if (!phy) 401c7ebbbceSChristoph Hellwig return NULL; 402c7ebbbceSChristoph Hellwig 403c7ebbbceSChristoph Hellwig get_device(parent); 404c7ebbbceSChristoph Hellwig 405c7ebbbceSChristoph Hellwig phy->number = number; 406c7ebbbceSChristoph Hellwig 407c7ebbbceSChristoph Hellwig device_initialize(&phy->dev); 408c7ebbbceSChristoph Hellwig phy->dev.parent = get_device(parent); 409c7ebbbceSChristoph Hellwig phy->dev.release = sas_phy_release; 410c7ebbbceSChristoph Hellwig sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 411c7ebbbceSChristoph Hellwig 412c7ebbbceSChristoph Hellwig transport_setup_device(&phy->dev); 413c7ebbbceSChristoph Hellwig 414c7ebbbceSChristoph Hellwig return phy; 415c7ebbbceSChristoph Hellwig } 416c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_alloc); 417c7ebbbceSChristoph Hellwig 418c7ebbbceSChristoph Hellwig /** 419c7ebbbceSChristoph Hellwig * sas_phy_add -- add a SAS PHY to the device hierachy 420c7ebbbceSChristoph Hellwig * @phy: The PHY to be added 421c7ebbbceSChristoph Hellwig * 422c7ebbbceSChristoph Hellwig * Publishes a SAS PHY to the rest of the system. 423c7ebbbceSChristoph Hellwig */ 424c7ebbbceSChristoph Hellwig int sas_phy_add(struct sas_phy *phy) 425c7ebbbceSChristoph Hellwig { 426c7ebbbceSChristoph Hellwig int error; 427c7ebbbceSChristoph Hellwig 428c7ebbbceSChristoph Hellwig error = device_add(&phy->dev); 429c7ebbbceSChristoph Hellwig if (!error) { 430c7ebbbceSChristoph Hellwig transport_add_device(&phy->dev); 431c7ebbbceSChristoph Hellwig transport_configure_device(&phy->dev); 432c7ebbbceSChristoph Hellwig } 433c7ebbbceSChristoph Hellwig 434c7ebbbceSChristoph Hellwig return error; 435c7ebbbceSChristoph Hellwig } 436c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_add); 437c7ebbbceSChristoph Hellwig 438c7ebbbceSChristoph Hellwig /** 439c7ebbbceSChristoph Hellwig * sas_phy_free -- free a SAS PHY 440c7ebbbceSChristoph Hellwig * @phy: SAS PHY to free 441c7ebbbceSChristoph Hellwig * 442c7ebbbceSChristoph Hellwig * Frees the specified SAS PHY. 443c7ebbbceSChristoph Hellwig * 444c7ebbbceSChristoph Hellwig * Note: 445c7ebbbceSChristoph Hellwig * This function must only be called on a PHY that has not 446c7ebbbceSChristoph Hellwig * sucessfully been added using sas_phy_add(). 447c7ebbbceSChristoph Hellwig */ 448c7ebbbceSChristoph Hellwig void sas_phy_free(struct sas_phy *phy) 449c7ebbbceSChristoph Hellwig { 450c7ebbbceSChristoph Hellwig transport_destroy_device(&phy->dev); 451c7ebbbceSChristoph Hellwig put_device(phy->dev.parent); 452c7ebbbceSChristoph Hellwig put_device(phy->dev.parent); 453c7ebbbceSChristoph Hellwig put_device(phy->dev.parent); 454c7ebbbceSChristoph Hellwig kfree(phy); 455c7ebbbceSChristoph Hellwig } 456c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_free); 457c7ebbbceSChristoph Hellwig 458c7ebbbceSChristoph Hellwig /** 459c7ebbbceSChristoph Hellwig * sas_phy_delete -- remove SAS PHY 460c7ebbbceSChristoph Hellwig * @phy: SAS PHY to remove 461c7ebbbceSChristoph Hellwig * 462c7ebbbceSChristoph Hellwig * Removes the specified SAS PHY. If the SAS PHY has an 463c7ebbbceSChristoph Hellwig * associated remote PHY it is removed before. 464c7ebbbceSChristoph Hellwig */ 465c7ebbbceSChristoph Hellwig void 466c7ebbbceSChristoph Hellwig sas_phy_delete(struct sas_phy *phy) 467c7ebbbceSChristoph Hellwig { 468c7ebbbceSChristoph Hellwig struct device *dev = &phy->dev; 469c7ebbbceSChristoph Hellwig 470c7ebbbceSChristoph Hellwig if (phy->rphy) 471c7ebbbceSChristoph Hellwig sas_rphy_delete(phy->rphy); 472c7ebbbceSChristoph Hellwig 473c7ebbbceSChristoph Hellwig transport_remove_device(dev); 474c7ebbbceSChristoph Hellwig device_del(dev); 475c7ebbbceSChristoph Hellwig transport_destroy_device(dev); 476c7ebbbceSChristoph Hellwig put_device(dev->parent); 477c7ebbbceSChristoph Hellwig } 478c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_delete); 479c7ebbbceSChristoph Hellwig 480c7ebbbceSChristoph Hellwig /** 481c7ebbbceSChristoph Hellwig * scsi_is_sas_phy -- check if a struct device represents a SAS PHY 482c7ebbbceSChristoph Hellwig * @dev: device to check 483c7ebbbceSChristoph Hellwig * 484c7ebbbceSChristoph Hellwig * Returns: 485c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS PHY, %0 else 486c7ebbbceSChristoph Hellwig */ 487c7ebbbceSChristoph Hellwig int scsi_is_sas_phy(const struct device *dev) 488c7ebbbceSChristoph Hellwig { 489c7ebbbceSChristoph Hellwig return dev->release == sas_phy_release; 490c7ebbbceSChristoph Hellwig } 491c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_phy); 492c7ebbbceSChristoph Hellwig 493c7ebbbceSChristoph Hellwig /* 494c7ebbbceSChristoph Hellwig * SAS remote PHY attributes. 495c7ebbbceSChristoph Hellwig */ 496c7ebbbceSChristoph Hellwig 497c7ebbbceSChristoph Hellwig #define sas_rphy_show_simple(field, name, format_string, cast) \ 498c7ebbbceSChristoph Hellwig static ssize_t \ 499c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 500c7ebbbceSChristoph Hellwig { \ 501c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 502c7ebbbceSChristoph Hellwig \ 503c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast rphy->field); \ 504c7ebbbceSChristoph Hellwig } 505c7ebbbceSChristoph Hellwig 506c7ebbbceSChristoph Hellwig #define sas_rphy_simple_attr(field, name, format_string, type) \ 507c7ebbbceSChristoph Hellwig sas_rphy_show_simple(field, name, format_string, (type)) \ 508c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 509c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 510c7ebbbceSChristoph Hellwig 511c7ebbbceSChristoph Hellwig #define sas_rphy_show_protocol(field, name) \ 512c7ebbbceSChristoph Hellwig static ssize_t \ 513c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 514c7ebbbceSChristoph Hellwig { \ 515c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 516c7ebbbceSChristoph Hellwig \ 517c7ebbbceSChristoph Hellwig if (!rphy->field) \ 518c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 519c7ebbbceSChristoph Hellwig return get_sas_protocol_names(rphy->field, buf); \ 520c7ebbbceSChristoph Hellwig } 521c7ebbbceSChristoph Hellwig 522c7ebbbceSChristoph Hellwig #define sas_rphy_protocol_attr(field, name) \ 523c7ebbbceSChristoph Hellwig sas_rphy_show_protocol(field, name) \ 524c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 525c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 526c7ebbbceSChristoph Hellwig 527c7ebbbceSChristoph Hellwig static ssize_t 528c7ebbbceSChristoph Hellwig show_sas_rphy_device_type(struct class_device *cdev, char *buf) 529c7ebbbceSChristoph Hellwig { 530c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 531c7ebbbceSChristoph Hellwig 532c7ebbbceSChristoph Hellwig if (!rphy->identify.device_type) 533c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 534c7ebbbceSChristoph Hellwig return get_sas_device_type_names( 535c7ebbbceSChristoph Hellwig rphy->identify.device_type, buf); 536c7ebbbceSChristoph Hellwig } 537c7ebbbceSChristoph Hellwig 538c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 539c7ebbbceSChristoph Hellwig show_sas_rphy_device_type, NULL); 540c7ebbbceSChristoph Hellwig 541a0125641SChristoph Hellwig static ssize_t 542a0125641SChristoph Hellwig show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf) 543a0125641SChristoph Hellwig { 544a0125641SChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 545a0125641SChristoph Hellwig struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 546a0125641SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 547a0125641SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 548a0125641SChristoph Hellwig u64 identifier; 549a0125641SChristoph Hellwig int error; 550a0125641SChristoph Hellwig 551a0125641SChristoph Hellwig /* 552a0125641SChristoph Hellwig * Only devices behind an expander are supported, because the 553a0125641SChristoph Hellwig * enclosure identifier is a SMP feature. 554a0125641SChristoph Hellwig */ 555a0125641SChristoph Hellwig if (phy->local_attached) 556a0125641SChristoph Hellwig return -EINVAL; 557a0125641SChristoph Hellwig 558a0125641SChristoph Hellwig error = i->f->get_enclosure_identifier(rphy, &identifier); 559a0125641SChristoph Hellwig if (error) 560a0125641SChristoph Hellwig return error; 561a0125641SChristoph Hellwig return sprintf(buf, "0x%llx\n", (unsigned long long)identifier); 562a0125641SChristoph Hellwig } 563a0125641SChristoph Hellwig 564a0125641SChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO, 565a0125641SChristoph Hellwig show_sas_rphy_enclosure_identifier, NULL); 566a0125641SChristoph Hellwig 567a0125641SChristoph Hellwig static ssize_t 568a0125641SChristoph Hellwig show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf) 569a0125641SChristoph Hellwig { 570a0125641SChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 571a0125641SChristoph Hellwig struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 572a0125641SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 573a0125641SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 574a0125641SChristoph Hellwig int val; 575a0125641SChristoph Hellwig 576a0125641SChristoph Hellwig if (phy->local_attached) 577a0125641SChristoph Hellwig return -EINVAL; 578a0125641SChristoph Hellwig 579a0125641SChristoph Hellwig val = i->f->get_bay_identifier(rphy); 580a0125641SChristoph Hellwig if (val < 0) 581a0125641SChristoph Hellwig return val; 582a0125641SChristoph Hellwig return sprintf(buf, "%d\n", val); 583a0125641SChristoph Hellwig } 584a0125641SChristoph Hellwig 585a0125641SChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO, 586a0125641SChristoph Hellwig show_sas_rphy_bay_identifier, NULL); 587a0125641SChristoph Hellwig 588c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.initiator_port_protocols, 589c7ebbbceSChristoph Hellwig initiator_port_protocols); 590c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 591c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 592c7ebbbceSChristoph Hellwig unsigned long long); 593c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 594c7ebbbceSChristoph Hellwig 59542ab0360SJames Bottomley /* only need 8 bytes of data plus header (4 or 8) */ 59642ab0360SJames Bottomley #define BUF_SIZE 64 59742ab0360SJames Bottomley 59842ab0360SJames Bottomley int sas_read_port_mode_page(struct scsi_device *sdev) 59942ab0360SJames Bottomley { 60042ab0360SJames Bottomley char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; 60142ab0360SJames Bottomley struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); 60242ab0360SJames Bottomley struct sas_end_device *rdev; 60342ab0360SJames Bottomley struct scsi_mode_data mode_data; 60442ab0360SJames Bottomley int res, error; 60542ab0360SJames Bottomley 60642ab0360SJames Bottomley BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); 60742ab0360SJames Bottomley 60842ab0360SJames Bottomley rdev = rphy_to_end_device(rphy); 60942ab0360SJames Bottomley 61042ab0360SJames Bottomley if (!buffer) 61142ab0360SJames Bottomley return -ENOMEM; 61242ab0360SJames Bottomley 61342ab0360SJames Bottomley res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3, 61442ab0360SJames Bottomley &mode_data, NULL); 61542ab0360SJames Bottomley 61642ab0360SJames Bottomley error = -EINVAL; 61742ab0360SJames Bottomley if (!scsi_status_is_good(res)) 61842ab0360SJames Bottomley goto out; 61942ab0360SJames Bottomley 62042ab0360SJames Bottomley msdata = buffer + mode_data.header_length + 62142ab0360SJames Bottomley mode_data.block_descriptor_length; 62242ab0360SJames Bottomley 62342ab0360SJames Bottomley if (msdata - buffer > BUF_SIZE - 8) 62442ab0360SJames Bottomley goto out; 62542ab0360SJames Bottomley 62642ab0360SJames Bottomley error = 0; 62742ab0360SJames Bottomley 62842ab0360SJames Bottomley rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0; 62942ab0360SJames Bottomley rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5]; 63042ab0360SJames Bottomley rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7]; 63142ab0360SJames Bottomley 63242ab0360SJames Bottomley out: 63342ab0360SJames Bottomley kfree(buffer); 63442ab0360SJames Bottomley return error; 63542ab0360SJames Bottomley } 63642ab0360SJames Bottomley EXPORT_SYMBOL(sas_read_port_mode_page); 63742ab0360SJames Bottomley 63842ab0360SJames Bottomley #define sas_end_dev_show_simple(field, name, format_string, cast) \ 63942ab0360SJames Bottomley static ssize_t \ 64042ab0360SJames Bottomley show_sas_end_dev_##name(struct class_device *cdev, char *buf) \ 64142ab0360SJames Bottomley { \ 64242ab0360SJames Bottomley struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 64342ab0360SJames Bottomley struct sas_end_device *rdev = rphy_to_end_device(rphy); \ 64442ab0360SJames Bottomley \ 64542ab0360SJames Bottomley return snprintf(buf, 20, format_string, cast rdev->field); \ 64642ab0360SJames Bottomley } 64742ab0360SJames Bottomley 64842ab0360SJames Bottomley #define sas_end_dev_simple_attr(field, name, format_string, type) \ 64942ab0360SJames Bottomley sas_end_dev_show_simple(field, name, format_string, (type)) \ 65042ab0360SJames Bottomley static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, \ 65142ab0360SJames Bottomley show_sas_end_dev_##name, NULL) 65242ab0360SJames Bottomley 65342ab0360SJames Bottomley sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int); 65442ab0360SJames Bottomley sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, 65542ab0360SJames Bottomley "%d\n", int); 65642ab0360SJames Bottomley sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, 65742ab0360SJames Bottomley "%d\n", int); 65842ab0360SJames Bottomley 65942ab0360SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_end_dev_class, 66042ab0360SJames Bottomley "sas_end_device", NULL, NULL, NULL); 66142ab0360SJames Bottomley 662c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 663c7ebbbceSChristoph Hellwig "sas_rphy", NULL, NULL, NULL); 664c7ebbbceSChristoph Hellwig 665c7ebbbceSChristoph Hellwig static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 666c7ebbbceSChristoph Hellwig { 667c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 668c7ebbbceSChristoph Hellwig struct sas_internal *i; 669c7ebbbceSChristoph Hellwig 670c7ebbbceSChristoph Hellwig if (!scsi_is_sas_rphy(dev)) 671c7ebbbceSChristoph Hellwig return 0; 672c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent->parent); 673c7ebbbceSChristoph Hellwig 674c7ebbbceSChristoph Hellwig if (!shost->transportt) 675c7ebbbceSChristoph Hellwig return 0; 676c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 677c7ebbbceSChristoph Hellwig &sas_host_class.class) 678c7ebbbceSChristoph Hellwig return 0; 679c7ebbbceSChristoph Hellwig 680c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 681c7ebbbceSChristoph Hellwig return &i->rphy_attr_cont.ac == cont; 682c7ebbbceSChristoph Hellwig } 683c7ebbbceSChristoph Hellwig 68442ab0360SJames Bottomley static int sas_end_dev_match(struct attribute_container *cont, 68542ab0360SJames Bottomley struct device *dev) 68642ab0360SJames Bottomley { 68742ab0360SJames Bottomley struct Scsi_Host *shost; 68842ab0360SJames Bottomley struct sas_internal *i; 68942ab0360SJames Bottomley struct sas_rphy *rphy; 69042ab0360SJames Bottomley 69142ab0360SJames Bottomley if (!scsi_is_sas_rphy(dev)) 69242ab0360SJames Bottomley return 0; 69342ab0360SJames Bottomley shost = dev_to_shost(dev->parent->parent); 69442ab0360SJames Bottomley rphy = dev_to_rphy(dev); 69542ab0360SJames Bottomley 69642ab0360SJames Bottomley if (!shost->transportt) 69742ab0360SJames Bottomley return 0; 69842ab0360SJames Bottomley if (shost->transportt->host_attrs.ac.class != 69942ab0360SJames Bottomley &sas_host_class.class) 70042ab0360SJames Bottomley return 0; 70142ab0360SJames Bottomley 70242ab0360SJames Bottomley i = to_sas_internal(shost->transportt); 70342ab0360SJames Bottomley return &i->end_dev_attr_cont.ac == cont && 70442ab0360SJames Bottomley rphy->identify.device_type == SAS_END_DEVICE && 70542ab0360SJames Bottomley /* FIXME: remove contained eventually */ 70642ab0360SJames Bottomley rphy->contained; 70742ab0360SJames Bottomley } 70842ab0360SJames Bottomley 709c7ebbbceSChristoph Hellwig static void sas_rphy_release(struct device *dev) 710c7ebbbceSChristoph Hellwig { 711c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = dev_to_rphy(dev); 712c7ebbbceSChristoph Hellwig 713c7ebbbceSChristoph Hellwig put_device(dev->parent); 714c7ebbbceSChristoph Hellwig kfree(rphy); 715c7ebbbceSChristoph Hellwig } 716c7ebbbceSChristoph Hellwig 717c7ebbbceSChristoph Hellwig /** 718c7ebbbceSChristoph Hellwig * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure 719c7ebbbceSChristoph Hellwig * @parent: SAS PHY this remote PHY is conneted to 720c7ebbbceSChristoph Hellwig * 721c7ebbbceSChristoph Hellwig * Allocates an SAS remote PHY structure, connected to @parent. 722c7ebbbceSChristoph Hellwig * 723c7ebbbceSChristoph Hellwig * Returns: 724c7ebbbceSChristoph Hellwig * SAS PHY allocated or %NULL if the allocation failed. 725c7ebbbceSChristoph Hellwig */ 726c7ebbbceSChristoph Hellwig struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent) 727c7ebbbceSChristoph Hellwig { 728c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(&parent->dev); 729c7ebbbceSChristoph Hellwig struct sas_rphy *rphy; 730c7ebbbceSChristoph Hellwig 73124669f75SJes Sorensen rphy = kzalloc(sizeof(*rphy), GFP_KERNEL); 732c7ebbbceSChristoph Hellwig if (!rphy) { 733c7ebbbceSChristoph Hellwig put_device(&parent->dev); 734c7ebbbceSChristoph Hellwig return NULL; 735c7ebbbceSChristoph Hellwig } 736c7ebbbceSChristoph Hellwig 737c7ebbbceSChristoph Hellwig device_initialize(&rphy->dev); 738c7ebbbceSChristoph Hellwig rphy->dev.parent = get_device(&parent->dev); 739c7ebbbceSChristoph Hellwig rphy->dev.release = sas_rphy_release; 740d99ca418SMoore, Eric sprintf(rphy->dev.bus_id, "rphy-%d:%d-%d", 741d99ca418SMoore, Eric shost->host_no, parent->port_identifier, parent->number); 742c7ebbbceSChristoph Hellwig transport_setup_device(&rphy->dev); 743c7ebbbceSChristoph Hellwig 744c7ebbbceSChristoph Hellwig return rphy; 745c7ebbbceSChristoph Hellwig } 746c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_alloc); 747c7ebbbceSChristoph Hellwig 748c7ebbbceSChristoph Hellwig /** 74942ab0360SJames Bottomley * sas_end_device_alloc - allocate an rphy for an end device 75042ab0360SJames Bottomley * 75142ab0360SJames Bottomley * Allocates an SAS remote PHY structure, connected to @parent. 75242ab0360SJames Bottomley * 75342ab0360SJames Bottomley * Returns: 75442ab0360SJames Bottomley * SAS PHY allocated or %NULL if the allocation failed. 75542ab0360SJames Bottomley */ 75642ab0360SJames Bottomley struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) 75742ab0360SJames Bottomley { 75842ab0360SJames Bottomley struct Scsi_Host *shost = dev_to_shost(&parent->dev); 75942ab0360SJames Bottomley struct sas_end_device *rdev; 76042ab0360SJames Bottomley 76142ab0360SJames Bottomley rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 76242ab0360SJames Bottomley if (!rdev) { 76342ab0360SJames Bottomley put_device(&parent->dev); 76442ab0360SJames Bottomley return NULL; 76542ab0360SJames Bottomley } 76642ab0360SJames Bottomley 76742ab0360SJames Bottomley device_initialize(&rdev->rphy.dev); 76842ab0360SJames Bottomley rdev->rphy.dev.parent = get_device(&parent->dev); 76942ab0360SJames Bottomley rdev->rphy.dev.release = sas_rphy_release; 77042ab0360SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "rphy-%d:%d-%d", 77142ab0360SJames Bottomley shost->host_no, parent->port_identifier, parent->number); 77242ab0360SJames Bottomley rdev->rphy.identify.device_type = SAS_END_DEVICE; 77342ab0360SJames Bottomley /* FIXME: mark the rphy as being contained in a larger structure */ 77442ab0360SJames Bottomley rdev->rphy.contained = 1; 77542ab0360SJames Bottomley transport_setup_device(&rdev->rphy.dev); 77642ab0360SJames Bottomley 77742ab0360SJames Bottomley return &rdev->rphy; 77842ab0360SJames Bottomley } 77942ab0360SJames Bottomley EXPORT_SYMBOL(sas_end_device_alloc); 78042ab0360SJames Bottomley 78142ab0360SJames Bottomley 78242ab0360SJames Bottomley /** 783c7ebbbceSChristoph Hellwig * sas_rphy_add -- add a SAS remote PHY to the device hierachy 784c7ebbbceSChristoph Hellwig * @rphy: The remote PHY to be added 785c7ebbbceSChristoph Hellwig * 786c7ebbbceSChristoph Hellwig * Publishes a SAS remote PHY to the rest of the system. 787c7ebbbceSChristoph Hellwig */ 788c7ebbbceSChristoph Hellwig int sas_rphy_add(struct sas_rphy *rphy) 789c7ebbbceSChristoph Hellwig { 790c7ebbbceSChristoph Hellwig struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 791c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 792c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 793c7ebbbceSChristoph Hellwig struct sas_identify *identify = &rphy->identify; 794c7ebbbceSChristoph Hellwig int error; 795c7ebbbceSChristoph Hellwig 796c7ebbbceSChristoph Hellwig if (parent->rphy) 797c7ebbbceSChristoph Hellwig return -ENXIO; 798c7ebbbceSChristoph Hellwig parent->rphy = rphy; 799c7ebbbceSChristoph Hellwig 800c7ebbbceSChristoph Hellwig error = device_add(&rphy->dev); 801c7ebbbceSChristoph Hellwig if (error) 802c7ebbbceSChristoph Hellwig return error; 803c7ebbbceSChristoph Hellwig transport_add_device(&rphy->dev); 804c7ebbbceSChristoph Hellwig transport_configure_device(&rphy->dev); 805c7ebbbceSChristoph Hellwig 806e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 807c7ebbbceSChristoph Hellwig list_add_tail(&rphy->list, &sas_host->rphy_list); 808c7ebbbceSChristoph Hellwig if (identify->device_type == SAS_END_DEVICE && 809c7ebbbceSChristoph Hellwig (identify->target_port_protocols & 810c7ebbbceSChristoph Hellwig (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 811c7ebbbceSChristoph Hellwig rphy->scsi_target_id = sas_host->next_target_id++; 812c7ebbbceSChristoph Hellwig else 813c7ebbbceSChristoph Hellwig rphy->scsi_target_id = -1; 814e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 815c7ebbbceSChristoph Hellwig 816c7ebbbceSChristoph Hellwig if (rphy->scsi_target_id != -1) { 817e6bc863cSMoore, Eric scsi_scan_target(&rphy->dev, parent->port_identifier, 818c7ebbbceSChristoph Hellwig rphy->scsi_target_id, ~0, 0); 819c7ebbbceSChristoph Hellwig } 820c7ebbbceSChristoph Hellwig 821c7ebbbceSChristoph Hellwig return 0; 822c7ebbbceSChristoph Hellwig } 823c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_add); 824c7ebbbceSChristoph Hellwig 825c7ebbbceSChristoph Hellwig /** 826c7ebbbceSChristoph Hellwig * sas_rphy_free -- free a SAS remote PHY 827c7ebbbceSChristoph Hellwig * @rphy SAS remote PHY to free 828c7ebbbceSChristoph Hellwig * 829c7ebbbceSChristoph Hellwig * Frees the specified SAS remote PHY. 830c7ebbbceSChristoph Hellwig * 831c7ebbbceSChristoph Hellwig * Note: 832c7ebbbceSChristoph Hellwig * This function must only be called on a remote 833c7ebbbceSChristoph Hellwig * PHY that has not sucessfully been added using 834c7ebbbceSChristoph Hellwig * sas_rphy_add(). 835c7ebbbceSChristoph Hellwig */ 836c7ebbbceSChristoph Hellwig void sas_rphy_free(struct sas_rphy *rphy) 837c7ebbbceSChristoph Hellwig { 838c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 839c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 840c7ebbbceSChristoph Hellwig 841e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 842c7ebbbceSChristoph Hellwig list_del(&rphy->list); 843e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 844c7ebbbceSChristoph Hellwig 845c7ebbbceSChristoph Hellwig transport_destroy_device(&rphy->dev); 846c7ebbbceSChristoph Hellwig put_device(rphy->dev.parent); 847c7ebbbceSChristoph Hellwig put_device(rphy->dev.parent); 848c7ebbbceSChristoph Hellwig put_device(rphy->dev.parent); 849c7ebbbceSChristoph Hellwig kfree(rphy); 850c7ebbbceSChristoph Hellwig } 851c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_free); 852c7ebbbceSChristoph Hellwig 853c7ebbbceSChristoph Hellwig /** 854c7ebbbceSChristoph Hellwig * sas_rphy_delete -- remove SAS remote PHY 855c7ebbbceSChristoph Hellwig * @rphy: SAS remote PHY to remove 856c7ebbbceSChristoph Hellwig * 857c7ebbbceSChristoph Hellwig * Removes the specified SAS remote PHY. 858c7ebbbceSChristoph Hellwig */ 859c7ebbbceSChristoph Hellwig void 860c7ebbbceSChristoph Hellwig sas_rphy_delete(struct sas_rphy *rphy) 861c7ebbbceSChristoph Hellwig { 862c7ebbbceSChristoph Hellwig struct device *dev = &rphy->dev; 863c7ebbbceSChristoph Hellwig struct sas_phy *parent = dev_to_phy(dev->parent); 864c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 865c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 866c7ebbbceSChristoph Hellwig 867d4054239SChristoph Hellwig switch (rphy->identify.device_type) { 868d4054239SChristoph Hellwig case SAS_END_DEVICE: 869fe8b2304SChristoph Hellwig scsi_remove_target(dev); 870d4054239SChristoph Hellwig break; 871d4054239SChristoph Hellwig case SAS_EDGE_EXPANDER_DEVICE: 872d4054239SChristoph Hellwig case SAS_FANOUT_EXPANDER_DEVICE: 873d4054239SChristoph Hellwig device_for_each_child(dev, NULL, do_sas_phy_delete); 874d4054239SChristoph Hellwig break; 875d4054239SChristoph Hellwig default: 876d4054239SChristoph Hellwig break; 877d4054239SChristoph Hellwig } 878c7ebbbceSChristoph Hellwig 879fe8b2304SChristoph Hellwig transport_remove_device(dev); 880fe8b2304SChristoph Hellwig device_del(dev); 881fe8b2304SChristoph Hellwig transport_destroy_device(dev); 882c7ebbbceSChristoph Hellwig 883e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 884c7ebbbceSChristoph Hellwig list_del(&rphy->list); 885e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 886c7ebbbceSChristoph Hellwig 88733b114e9SChristoph Hellwig parent->rphy = NULL; 88833b114e9SChristoph Hellwig 889c7ebbbceSChristoph Hellwig put_device(&parent->dev); 890c7ebbbceSChristoph Hellwig } 891c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_delete); 892c7ebbbceSChristoph Hellwig 893c7ebbbceSChristoph Hellwig /** 894c7ebbbceSChristoph Hellwig * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 895c7ebbbceSChristoph Hellwig * @dev: device to check 896c7ebbbceSChristoph Hellwig * 897c7ebbbceSChristoph Hellwig * Returns: 898c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS remote PHY, %0 else 899c7ebbbceSChristoph Hellwig */ 900c7ebbbceSChristoph Hellwig int scsi_is_sas_rphy(const struct device *dev) 901c7ebbbceSChristoph Hellwig { 902c7ebbbceSChristoph Hellwig return dev->release == sas_rphy_release; 903c7ebbbceSChristoph Hellwig } 904c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_rphy); 905c7ebbbceSChristoph Hellwig 906c7ebbbceSChristoph Hellwig 907c7ebbbceSChristoph Hellwig /* 908c7ebbbceSChristoph Hellwig * SCSI scan helper 909c7ebbbceSChristoph Hellwig */ 910c7ebbbceSChristoph Hellwig 911e02f3f59SChristoph Hellwig static int sas_user_scan(struct Scsi_Host *shost, uint channel, 912e02f3f59SChristoph Hellwig uint id, uint lun) 913c7ebbbceSChristoph Hellwig { 914c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 915c7ebbbceSChristoph Hellwig struct sas_rphy *rphy; 916c7ebbbceSChristoph Hellwig 917e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 918c7ebbbceSChristoph Hellwig list_for_each_entry(rphy, &sas_host->rphy_list, list) { 919c7ebbbceSChristoph Hellwig struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 920c7ebbbceSChristoph Hellwig 921e02f3f59SChristoph Hellwig if (rphy->scsi_target_id == -1) 922e02f3f59SChristoph Hellwig continue; 923e02f3f59SChristoph Hellwig 924e6bc863cSMoore, Eric if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) && 925e02f3f59SChristoph Hellwig (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 926e6bc863cSMoore, Eric scsi_scan_target(&rphy->dev, parent->port_identifier, 927e02f3f59SChristoph Hellwig rphy->scsi_target_id, lun, 1); 928e02f3f59SChristoph Hellwig } 929e02f3f59SChristoph Hellwig } 930e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 931e02f3f59SChristoph Hellwig 932e02f3f59SChristoph Hellwig return 0; 933c7ebbbceSChristoph Hellwig } 934c7ebbbceSChristoph Hellwig 935c7ebbbceSChristoph Hellwig 936c7ebbbceSChristoph Hellwig /* 937c7ebbbceSChristoph Hellwig * Setup / Teardown code 938c7ebbbceSChristoph Hellwig */ 939c7ebbbceSChristoph Hellwig 94042ab0360SJames Bottomley #define SETUP_TEMPLATE(attrb, field, perm, test) \ 94142ab0360SJames Bottomley i->private_##attrb[count] = class_device_attr_##field; \ 94242ab0360SJames Bottomley i->private_##attrb[count].attr.mode = perm; \ 94342ab0360SJames Bottomley i->private_##attrb[count].store = NULL; \ 94442ab0360SJames Bottomley i->attrb[count] = &i->private_##attrb[count]; \ 94542ab0360SJames Bottomley if (test) \ 946c7ebbbceSChristoph Hellwig count++ 947c7ebbbceSChristoph Hellwig 94842ab0360SJames Bottomley 94942ab0360SJames Bottomley #define SETUP_RPORT_ATTRIBUTE(field) \ 95042ab0360SJames Bottomley SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) 95142ab0360SJames Bottomley 952dd9fbb52SJames Bottomley #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 95342ab0360SJames Bottomley SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) 954dd9fbb52SJames Bottomley 955c7ebbbceSChristoph Hellwig #define SETUP_PORT_ATTRIBUTE(field) \ 95642ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) 957c7ebbbceSChristoph Hellwig 958dd9fbb52SJames Bottomley #define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ 95942ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) 960dd9fbb52SJames Bottomley 96107ba3a95SChristoph Hellwig #define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 96242ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) 96307ba3a95SChristoph Hellwig 964dd9fbb52SJames Bottomley #define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ 96542ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) 966dd9fbb52SJames Bottomley 96742ab0360SJames Bottomley #define SETUP_END_DEV_ATTRIBUTE(field) \ 96842ab0360SJames Bottomley SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) 969c7ebbbceSChristoph Hellwig 970c7ebbbceSChristoph Hellwig /** 971c7ebbbceSChristoph Hellwig * sas_attach_transport -- instantiate SAS transport template 972c7ebbbceSChristoph Hellwig * @ft: SAS transport class function template 973c7ebbbceSChristoph Hellwig */ 974c7ebbbceSChristoph Hellwig struct scsi_transport_template * 975c7ebbbceSChristoph Hellwig sas_attach_transport(struct sas_function_template *ft) 976c7ebbbceSChristoph Hellwig { 977c7ebbbceSChristoph Hellwig struct sas_internal *i; 978c7ebbbceSChristoph Hellwig int count; 979c7ebbbceSChristoph Hellwig 98024669f75SJes Sorensen i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); 981c7ebbbceSChristoph Hellwig if (!i) 982c7ebbbceSChristoph Hellwig return NULL; 983c7ebbbceSChristoph Hellwig 984e02f3f59SChristoph Hellwig i->t.user_scan = sas_user_scan; 985c7ebbbceSChristoph Hellwig 986c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 987c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.class = &sas_host_class.class; 988c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.match = sas_host_match; 989c7ebbbceSChristoph Hellwig transport_container_register(&i->t.host_attrs); 990c7ebbbceSChristoph Hellwig i->t.host_size = sizeof(struct sas_host_attrs); 991c7ebbbceSChristoph Hellwig 992c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.class = &sas_phy_class.class; 993c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 994c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.match = sas_phy_match; 995c7ebbbceSChristoph Hellwig transport_container_register(&i->phy_attr_cont); 996c7ebbbceSChristoph Hellwig 997c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 998c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 999c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.match = sas_rphy_match; 1000c7ebbbceSChristoph Hellwig transport_container_register(&i->rphy_attr_cont); 1001c7ebbbceSChristoph Hellwig 100242ab0360SJames Bottomley i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class; 100342ab0360SJames Bottomley i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0]; 100442ab0360SJames Bottomley i->end_dev_attr_cont.ac.match = sas_end_dev_match; 100542ab0360SJames Bottomley transport_container_register(&i->end_dev_attr_cont); 100642ab0360SJames Bottomley 1007c7ebbbceSChristoph Hellwig i->f = ft; 1008c7ebbbceSChristoph Hellwig 1009c7ebbbceSChristoph Hellwig count = 0; 1010c7ebbbceSChristoph Hellwig i->host_attrs[count] = NULL; 1011c7ebbbceSChristoph Hellwig 1012c7ebbbceSChristoph Hellwig count = 0; 1013c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(initiator_port_protocols); 1014c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(target_port_protocols); 1015c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(device_type); 1016c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(sas_address); 1017c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(phy_identifier); 1018c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(port_identifier); 1019c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(negotiated_linkrate); 1020c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); 1021c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(minimum_linkrate); 1022c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); 1023c7ebbbceSChristoph Hellwig SETUP_PORT_ATTRIBUTE(maximum_linkrate); 1024c3ee74c4SChristoph Hellwig 1025c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(invalid_dword_count); 1026c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 1027c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 1028c3ee74c4SChristoph Hellwig SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 1029dd9fbb52SJames Bottomley SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); 1030dd9fbb52SJames Bottomley SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 1031c7ebbbceSChristoph Hellwig i->phy_attrs[count] = NULL; 1032c7ebbbceSChristoph Hellwig 1033c7ebbbceSChristoph Hellwig count = 0; 1034c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 1035c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 1036c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_device_type); 1037c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 1038c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 1039dd9fbb52SJames Bottomley SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier, 1040dd9fbb52SJames Bottomley get_enclosure_identifier); 1041dd9fbb52SJames Bottomley SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier, 1042dd9fbb52SJames Bottomley get_bay_identifier); 1043c7ebbbceSChristoph Hellwig i->rphy_attrs[count] = NULL; 1044c7ebbbceSChristoph Hellwig 104542ab0360SJames Bottomley count = 0; 104642ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); 104742ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); 104842ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); 104942ab0360SJames Bottomley i->end_dev_attrs[count] = NULL; 105042ab0360SJames Bottomley 1051c7ebbbceSChristoph Hellwig return &i->t; 1052c7ebbbceSChristoph Hellwig } 1053c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_attach_transport); 1054c7ebbbceSChristoph Hellwig 1055c7ebbbceSChristoph Hellwig /** 1056c7ebbbceSChristoph Hellwig * sas_release_transport -- release SAS transport template instance 1057c7ebbbceSChristoph Hellwig * @t: transport template instance 1058c7ebbbceSChristoph Hellwig */ 1059c7ebbbceSChristoph Hellwig void sas_release_transport(struct scsi_transport_template *t) 1060c7ebbbceSChristoph Hellwig { 1061c7ebbbceSChristoph Hellwig struct sas_internal *i = to_sas_internal(t); 1062c7ebbbceSChristoph Hellwig 1063c7ebbbceSChristoph Hellwig transport_container_unregister(&i->t.host_attrs); 1064c7ebbbceSChristoph Hellwig transport_container_unregister(&i->phy_attr_cont); 1065c7ebbbceSChristoph Hellwig transport_container_unregister(&i->rphy_attr_cont); 1066c7ebbbceSChristoph Hellwig 1067c7ebbbceSChristoph Hellwig kfree(i); 1068c7ebbbceSChristoph Hellwig } 1069c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_release_transport); 1070c7ebbbceSChristoph Hellwig 1071c7ebbbceSChristoph Hellwig static __init int sas_transport_init(void) 1072c7ebbbceSChristoph Hellwig { 1073c7ebbbceSChristoph Hellwig int error; 1074c7ebbbceSChristoph Hellwig 1075c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_host_class); 1076c7ebbbceSChristoph Hellwig if (error) 1077c7ebbbceSChristoph Hellwig goto out; 1078c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_phy_class); 1079c7ebbbceSChristoph Hellwig if (error) 1080c7ebbbceSChristoph Hellwig goto out_unregister_transport; 1081c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_rphy_class); 1082c7ebbbceSChristoph Hellwig if (error) 1083c7ebbbceSChristoph Hellwig goto out_unregister_phy; 108442ab0360SJames Bottomley error = transport_class_register(&sas_end_dev_class); 108542ab0360SJames Bottomley if (error) 108642ab0360SJames Bottomley goto out_unregister_rphy; 1087c7ebbbceSChristoph Hellwig 1088c7ebbbceSChristoph Hellwig return 0; 1089c7ebbbceSChristoph Hellwig 109042ab0360SJames Bottomley out_unregister_rphy: 109142ab0360SJames Bottomley transport_class_unregister(&sas_rphy_class); 1092c7ebbbceSChristoph Hellwig out_unregister_phy: 1093c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 1094c7ebbbceSChristoph Hellwig out_unregister_transport: 1095c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 1096c7ebbbceSChristoph Hellwig out: 1097c7ebbbceSChristoph Hellwig return error; 1098c7ebbbceSChristoph Hellwig 1099c7ebbbceSChristoph Hellwig } 1100c7ebbbceSChristoph Hellwig 1101c7ebbbceSChristoph Hellwig static void __exit sas_transport_exit(void) 1102c7ebbbceSChristoph Hellwig { 1103c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 1104c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 1105c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_rphy_class); 110642ab0360SJames Bottomley transport_class_unregister(&sas_end_dev_class); 1107c7ebbbceSChristoph Hellwig } 1108c7ebbbceSChristoph Hellwig 1109c7ebbbceSChristoph Hellwig MODULE_AUTHOR("Christoph Hellwig"); 1110c7ebbbceSChristoph Hellwig MODULE_DESCRIPTION("SAS Transphy Attributes"); 1111c7ebbbceSChristoph Hellwig MODULE_LICENSE("GPL"); 1112c7ebbbceSChristoph Hellwig 1113c7ebbbceSChristoph Hellwig module_init(sas_transport_init); 1114c7ebbbceSChristoph Hellwig module_exit(sas_transport_exit); 1115