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 38d6159c17SJames Bottomley #include "scsi_sas_internal.h" 39c7ebbbceSChristoph Hellwig struct sas_host_attrs { 40c7ebbbceSChristoph Hellwig struct list_head rphy_list; 41e02f3f59SChristoph Hellwig struct mutex lock; 42c7ebbbceSChristoph Hellwig u32 next_target_id; 4379cb1819SJames Bottomley u32 next_expander_id; 44c9fefeb2SJames Bottomley int next_port_id; 45c7ebbbceSChristoph Hellwig }; 46c7ebbbceSChristoph Hellwig #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 47c7ebbbceSChristoph Hellwig 48c7ebbbceSChristoph Hellwig 49c7ebbbceSChristoph Hellwig /* 50c7ebbbceSChristoph Hellwig * Hack to allow attributes of the same name in different objects. 51c7ebbbceSChristoph Hellwig */ 52c7ebbbceSChristoph Hellwig #define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ 53c7ebbbceSChristoph Hellwig struct class_device_attribute class_device_attr_##_prefix##_##_name = \ 54c7ebbbceSChristoph Hellwig __ATTR(_name,_mode,_show,_store) 55c7ebbbceSChristoph Hellwig 56c7ebbbceSChristoph Hellwig 57c7ebbbceSChristoph Hellwig /* 58c7ebbbceSChristoph Hellwig * Pretty printing helpers 59c7ebbbceSChristoph Hellwig */ 60c7ebbbceSChristoph Hellwig 61c7ebbbceSChristoph Hellwig #define sas_bitfield_name_match(title, table) \ 62c7ebbbceSChristoph Hellwig static ssize_t \ 63c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 64c7ebbbceSChristoph Hellwig { \ 65c7ebbbceSChristoph Hellwig char *prefix = ""; \ 66c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 67c7ebbbceSChristoph Hellwig int i; \ 68c7ebbbceSChristoph Hellwig \ 696391a113STobias Klauser for (i = 0; i < ARRAY_SIZE(table); i++) { \ 70c7ebbbceSChristoph Hellwig if (table[i].value & table_key) { \ 71c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s%s", \ 72c7ebbbceSChristoph Hellwig prefix, table[i].name); \ 73c7ebbbceSChristoph Hellwig prefix = ", "; \ 74c7ebbbceSChristoph Hellwig } \ 75c7ebbbceSChristoph Hellwig } \ 76c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 77c7ebbbceSChristoph Hellwig return len; \ 78c7ebbbceSChristoph Hellwig } 79c7ebbbceSChristoph Hellwig 80c7ebbbceSChristoph Hellwig #define sas_bitfield_name_search(title, table) \ 81c7ebbbceSChristoph Hellwig static ssize_t \ 82c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 83c7ebbbceSChristoph Hellwig { \ 84c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 85c7ebbbceSChristoph Hellwig int i; \ 86c7ebbbceSChristoph Hellwig \ 876391a113STobias Klauser for (i = 0; i < ARRAY_SIZE(table); i++) { \ 88c7ebbbceSChristoph Hellwig if (table[i].value == table_key) { \ 89c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s", \ 90c7ebbbceSChristoph Hellwig table[i].name); \ 91c7ebbbceSChristoph Hellwig break; \ 92c7ebbbceSChristoph Hellwig } \ 93c7ebbbceSChristoph Hellwig } \ 94c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 95c7ebbbceSChristoph Hellwig return len; \ 96c7ebbbceSChristoph Hellwig } 97c7ebbbceSChristoph Hellwig 98c7ebbbceSChristoph Hellwig static struct { 99c7ebbbceSChristoph Hellwig u32 value; 100c7ebbbceSChristoph Hellwig char *name; 101c7ebbbceSChristoph Hellwig } sas_device_type_names[] = { 102c7ebbbceSChristoph Hellwig { SAS_PHY_UNUSED, "unused" }, 103c7ebbbceSChristoph Hellwig { SAS_END_DEVICE, "end device" }, 104c7ebbbceSChristoph Hellwig { SAS_EDGE_EXPANDER_DEVICE, "edge expander" }, 105c7ebbbceSChristoph Hellwig { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" }, 106c7ebbbceSChristoph Hellwig }; 107c7ebbbceSChristoph Hellwig sas_bitfield_name_search(device_type, sas_device_type_names) 108c7ebbbceSChristoph Hellwig 109c7ebbbceSChristoph Hellwig 110c7ebbbceSChristoph Hellwig static struct { 111c7ebbbceSChristoph Hellwig u32 value; 112c7ebbbceSChristoph Hellwig char *name; 113c7ebbbceSChristoph Hellwig } sas_protocol_names[] = { 114c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SATA, "sata" }, 115c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SMP, "smp" }, 116c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_STP, "stp" }, 117c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SSP, "ssp" }, 118c7ebbbceSChristoph Hellwig }; 119c7ebbbceSChristoph Hellwig sas_bitfield_name_match(protocol, sas_protocol_names) 120c7ebbbceSChristoph Hellwig 121c7ebbbceSChristoph Hellwig static struct { 122c7ebbbceSChristoph Hellwig u32 value; 123c7ebbbceSChristoph Hellwig char *name; 124c7ebbbceSChristoph Hellwig } sas_linkspeed_names[] = { 125c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_UNKNOWN, "Unknown" }, 126c7ebbbceSChristoph Hellwig { SAS_PHY_DISABLED, "Phy disabled" }, 127c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_FAILED, "Link Rate failed" }, 128c7ebbbceSChristoph Hellwig { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, 129c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 130c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 1317e6dff62SJames Bottomley { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, 132c7ebbbceSChristoph Hellwig }; 133c7ebbbceSChristoph Hellwig sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 134c7ebbbceSChristoph Hellwig 135c7ebbbceSChristoph Hellwig 136c7ebbbceSChristoph Hellwig /* 137c7ebbbceSChristoph Hellwig * SAS host attributes 138c7ebbbceSChristoph Hellwig */ 139c7ebbbceSChristoph Hellwig 14037be6eebSJames Bottomley static int sas_host_setup(struct transport_container *tc, struct device *dev, 14137be6eebSJames Bottomley struct class_device *cdev) 142c7ebbbceSChristoph Hellwig { 143c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(dev); 144c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 145c7ebbbceSChristoph Hellwig 146c7ebbbceSChristoph Hellwig INIT_LIST_HEAD(&sas_host->rphy_list); 147e02f3f59SChristoph Hellwig mutex_init(&sas_host->lock); 148c7ebbbceSChristoph Hellwig sas_host->next_target_id = 0; 14979cb1819SJames Bottomley sas_host->next_expander_id = 0; 150c9fefeb2SJames Bottomley sas_host->next_port_id = 0; 151c7ebbbceSChristoph Hellwig return 0; 152c7ebbbceSChristoph Hellwig } 153c7ebbbceSChristoph Hellwig 154c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_host_class, 155c7ebbbceSChristoph Hellwig "sas_host", sas_host_setup, NULL, NULL); 156c7ebbbceSChristoph Hellwig 157c7ebbbceSChristoph Hellwig static int sas_host_match(struct attribute_container *cont, 158c7ebbbceSChristoph Hellwig struct device *dev) 159c7ebbbceSChristoph Hellwig { 160c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 161c7ebbbceSChristoph Hellwig struct sas_internal *i; 162c7ebbbceSChristoph Hellwig 163c7ebbbceSChristoph Hellwig if (!scsi_is_host_device(dev)) 164c7ebbbceSChristoph Hellwig return 0; 165c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev); 166c7ebbbceSChristoph Hellwig 167c7ebbbceSChristoph Hellwig if (!shost->transportt) 168c7ebbbceSChristoph Hellwig return 0; 169c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 170c7ebbbceSChristoph Hellwig &sas_host_class.class) 171c7ebbbceSChristoph Hellwig return 0; 172c7ebbbceSChristoph Hellwig 173c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 174c7ebbbceSChristoph Hellwig return &i->t.host_attrs.ac == cont; 175c7ebbbceSChristoph Hellwig } 176c7ebbbceSChristoph Hellwig 177c7ebbbceSChristoph Hellwig static int do_sas_phy_delete(struct device *dev, void *data) 178c7ebbbceSChristoph Hellwig { 17965c92b09SJames Bottomley int pass = (int)(unsigned long)data; 18065c92b09SJames Bottomley 18165c92b09SJames Bottomley if (pass == 0 && scsi_is_sas_port(dev)) 18265c92b09SJames Bottomley sas_port_delete(dev_to_sas_port(dev)); 18365c92b09SJames Bottomley else if (pass == 1 && scsi_is_sas_phy(dev)) 184c7ebbbceSChristoph Hellwig sas_phy_delete(dev_to_phy(dev)); 185c7ebbbceSChristoph Hellwig return 0; 186c7ebbbceSChristoph Hellwig } 187c7ebbbceSChristoph Hellwig 188c7ebbbceSChristoph Hellwig /** 18965c92b09SJames Bottomley * sas_remove_children -- tear down a devices SAS data structures 19065c92b09SJames Bottomley * @dev: device belonging to the sas object 19165c92b09SJames Bottomley * 19265c92b09SJames Bottomley * Removes all SAS PHYs and remote PHYs for a given object 19365c92b09SJames Bottomley */ 19465c92b09SJames Bottomley void sas_remove_children(struct device *dev) 19565c92b09SJames Bottomley { 19665c92b09SJames Bottomley device_for_each_child(dev, (void *)0, do_sas_phy_delete); 19765c92b09SJames Bottomley device_for_each_child(dev, (void *)1, do_sas_phy_delete); 19865c92b09SJames Bottomley } 19965c92b09SJames Bottomley EXPORT_SYMBOL(sas_remove_children); 20065c92b09SJames Bottomley 20165c92b09SJames Bottomley /** 202c7ebbbceSChristoph Hellwig * sas_remove_host -- tear down a Scsi_Host's SAS data structures 203c7ebbbceSChristoph Hellwig * @shost: Scsi Host that is torn down 204c7ebbbceSChristoph Hellwig * 205c7ebbbceSChristoph Hellwig * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 206c7ebbbceSChristoph Hellwig * Must be called just before scsi_remove_host for SAS HBAs. 207c7ebbbceSChristoph Hellwig */ 208c7ebbbceSChristoph Hellwig void sas_remove_host(struct Scsi_Host *shost) 209c7ebbbceSChristoph Hellwig { 21065c92b09SJames Bottomley sas_remove_children(&shost->shost_gendev); 211c7ebbbceSChristoph Hellwig } 212c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_remove_host); 213c7ebbbceSChristoph Hellwig 214c7ebbbceSChristoph Hellwig 215c7ebbbceSChristoph Hellwig /* 21665c92b09SJames Bottomley * SAS Phy attributes 217c7ebbbceSChristoph Hellwig */ 218c7ebbbceSChristoph Hellwig 219c7ebbbceSChristoph Hellwig #define sas_phy_show_simple(field, name, format_string, cast) \ 220c7ebbbceSChristoph Hellwig static ssize_t \ 221c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 222c7ebbbceSChristoph Hellwig { \ 223c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 224c7ebbbceSChristoph Hellwig \ 225c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast phy->field); \ 226c7ebbbceSChristoph Hellwig } 227c7ebbbceSChristoph Hellwig 228c7ebbbceSChristoph Hellwig #define sas_phy_simple_attr(field, name, format_string, type) \ 229c7ebbbceSChristoph Hellwig sas_phy_show_simple(field, name, format_string, (type)) \ 230c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 231c7ebbbceSChristoph Hellwig 232c7ebbbceSChristoph Hellwig #define sas_phy_show_protocol(field, name) \ 233c7ebbbceSChristoph Hellwig static ssize_t \ 234c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 235c7ebbbceSChristoph Hellwig { \ 236c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 237c7ebbbceSChristoph Hellwig \ 238c7ebbbceSChristoph Hellwig if (!phy->field) \ 239c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 240c7ebbbceSChristoph Hellwig return get_sas_protocol_names(phy->field, buf); \ 241c7ebbbceSChristoph Hellwig } 242c7ebbbceSChristoph Hellwig 243c7ebbbceSChristoph Hellwig #define sas_phy_protocol_attr(field, name) \ 244c7ebbbceSChristoph Hellwig sas_phy_show_protocol(field, name) \ 245c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 246c7ebbbceSChristoph Hellwig 247c7ebbbceSChristoph Hellwig #define sas_phy_show_linkspeed(field) \ 248c7ebbbceSChristoph Hellwig static ssize_t \ 249c7ebbbceSChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 250c7ebbbceSChristoph Hellwig { \ 251c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 252c7ebbbceSChristoph Hellwig \ 253c7ebbbceSChristoph Hellwig return get_sas_linkspeed_names(phy->field, buf); \ 254c7ebbbceSChristoph Hellwig } 255c7ebbbceSChristoph Hellwig 256c7ebbbceSChristoph Hellwig #define sas_phy_linkspeed_attr(field) \ 257c7ebbbceSChristoph Hellwig sas_phy_show_linkspeed(field) \ 258c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 259c7ebbbceSChristoph Hellwig 260c3ee74c4SChristoph Hellwig #define sas_phy_show_linkerror(field) \ 261c3ee74c4SChristoph Hellwig static ssize_t \ 262c3ee74c4SChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 263c3ee74c4SChristoph Hellwig { \ 264c3ee74c4SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 265c3ee74c4SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 266c3ee74c4SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); \ 267c3ee74c4SChristoph Hellwig int error; \ 268c3ee74c4SChristoph Hellwig \ 269dd9fbb52SJames Bottomley error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ 270c3ee74c4SChristoph Hellwig if (error) \ 271c3ee74c4SChristoph Hellwig return error; \ 272c3ee74c4SChristoph Hellwig return snprintf(buf, 20, "%u\n", phy->field); \ 273c3ee74c4SChristoph Hellwig } 274c3ee74c4SChristoph Hellwig 275c3ee74c4SChristoph Hellwig #define sas_phy_linkerror_attr(field) \ 276c3ee74c4SChristoph Hellwig sas_phy_show_linkerror(field) \ 277c3ee74c4SChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 278c3ee74c4SChristoph Hellwig 279c3ee74c4SChristoph Hellwig 280c7ebbbceSChristoph Hellwig static ssize_t 281c7ebbbceSChristoph Hellwig show_sas_device_type(struct class_device *cdev, char *buf) 282c7ebbbceSChristoph Hellwig { 283c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 284c7ebbbceSChristoph Hellwig 285c7ebbbceSChristoph Hellwig if (!phy->identify.device_type) 286c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 287c7ebbbceSChristoph Hellwig return get_sas_device_type_names(phy->identify.device_type, buf); 288c7ebbbceSChristoph Hellwig } 289c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 290c7ebbbceSChristoph Hellwig 29107ba3a95SChristoph Hellwig static ssize_t do_sas_phy_reset(struct class_device *cdev, 29207ba3a95SChristoph Hellwig size_t count, int hard_reset) 29307ba3a95SChristoph Hellwig { 29407ba3a95SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 29507ba3a95SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 29607ba3a95SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 29707ba3a95SChristoph Hellwig int error; 29807ba3a95SChristoph Hellwig 29907ba3a95SChristoph Hellwig error = i->f->phy_reset(phy, hard_reset); 30007ba3a95SChristoph Hellwig if (error) 30107ba3a95SChristoph Hellwig return error; 30207ba3a95SChristoph Hellwig return count; 30307ba3a95SChristoph Hellwig }; 30407ba3a95SChristoph Hellwig 30507ba3a95SChristoph Hellwig static ssize_t store_sas_link_reset(struct class_device *cdev, 30607ba3a95SChristoph Hellwig const char *buf, size_t count) 30707ba3a95SChristoph Hellwig { 30807ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 0); 30907ba3a95SChristoph Hellwig } 31007ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 31107ba3a95SChristoph Hellwig 31207ba3a95SChristoph Hellwig static ssize_t store_sas_hard_reset(struct class_device *cdev, 31307ba3a95SChristoph Hellwig const char *buf, size_t count) 31407ba3a95SChristoph Hellwig { 31507ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 1); 31607ba3a95SChristoph Hellwig } 31707ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 31807ba3a95SChristoph Hellwig 319c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.initiator_port_protocols, 320c7ebbbceSChristoph Hellwig initiator_port_protocols); 321c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.target_port_protocols, 322c7ebbbceSChristoph Hellwig target_port_protocols); 323c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 324c7ebbbceSChristoph Hellwig unsigned long long); 325c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 326c9fefeb2SJames Bottomley //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); 327c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(negotiated_linkrate); 328c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate_hw); 329c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate); 330c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate_hw); 331c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate); 332c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(invalid_dword_count); 333c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(running_disparity_error_count); 334c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(loss_of_dword_sync_count); 335c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(phy_reset_problem_count); 336c7ebbbceSChristoph Hellwig 337c7ebbbceSChristoph Hellwig 338c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_phy_class, 339c7ebbbceSChristoph Hellwig "sas_phy", NULL, NULL, NULL); 340c7ebbbceSChristoph Hellwig 341c7ebbbceSChristoph Hellwig static int sas_phy_match(struct attribute_container *cont, struct device *dev) 342c7ebbbceSChristoph Hellwig { 343c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 344c7ebbbceSChristoph Hellwig struct sas_internal *i; 345c7ebbbceSChristoph Hellwig 346c7ebbbceSChristoph Hellwig if (!scsi_is_sas_phy(dev)) 347c7ebbbceSChristoph Hellwig return 0; 348c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent); 349c7ebbbceSChristoph Hellwig 350c7ebbbceSChristoph Hellwig if (!shost->transportt) 351c7ebbbceSChristoph Hellwig return 0; 352c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 353c7ebbbceSChristoph Hellwig &sas_host_class.class) 354c7ebbbceSChristoph Hellwig return 0; 355c7ebbbceSChristoph Hellwig 356c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 357c7ebbbceSChristoph Hellwig return &i->phy_attr_cont.ac == cont; 358c7ebbbceSChristoph Hellwig } 359c7ebbbceSChristoph Hellwig 360c7ebbbceSChristoph Hellwig static void sas_phy_release(struct device *dev) 361c7ebbbceSChristoph Hellwig { 362c7ebbbceSChristoph Hellwig struct sas_phy *phy = dev_to_phy(dev); 363c7ebbbceSChristoph Hellwig 364c7ebbbceSChristoph Hellwig put_device(dev->parent); 365c7ebbbceSChristoph Hellwig kfree(phy); 366c7ebbbceSChristoph Hellwig } 367c7ebbbceSChristoph Hellwig 368c7ebbbceSChristoph Hellwig /** 369c7ebbbceSChristoph Hellwig * sas_phy_alloc -- allocates and initialize a SAS PHY structure 370c7ebbbceSChristoph Hellwig * @parent: Parent device 371d99ca418SMoore, Eric * @number: Phy index 372c7ebbbceSChristoph Hellwig * 373c7ebbbceSChristoph Hellwig * Allocates an SAS PHY structure. It will be added in the device tree 374c7ebbbceSChristoph Hellwig * below the device specified by @parent, which has to be either a Scsi_Host 375c7ebbbceSChristoph Hellwig * or sas_rphy. 376c7ebbbceSChristoph Hellwig * 377c7ebbbceSChristoph Hellwig * Returns: 378c7ebbbceSChristoph Hellwig * SAS PHY allocated or %NULL if the allocation failed. 379c7ebbbceSChristoph Hellwig */ 380c7ebbbceSChristoph Hellwig struct sas_phy *sas_phy_alloc(struct device *parent, int number) 381c7ebbbceSChristoph Hellwig { 382c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent); 383c7ebbbceSChristoph Hellwig struct sas_phy *phy; 384c7ebbbceSChristoph Hellwig 38524669f75SJes Sorensen phy = kzalloc(sizeof(*phy), GFP_KERNEL); 386c7ebbbceSChristoph Hellwig if (!phy) 387c7ebbbceSChristoph Hellwig return NULL; 388c7ebbbceSChristoph Hellwig 389c7ebbbceSChristoph Hellwig phy->number = number; 390c7ebbbceSChristoph Hellwig 391c7ebbbceSChristoph Hellwig device_initialize(&phy->dev); 392c7ebbbceSChristoph Hellwig phy->dev.parent = get_device(parent); 393c7ebbbceSChristoph Hellwig phy->dev.release = sas_phy_release; 39465c92b09SJames Bottomley INIT_LIST_HEAD(&phy->port_siblings); 39579cb1819SJames Bottomley if (scsi_is_sas_expander_device(parent)) { 39679cb1819SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent); 39765c92b09SJames Bottomley sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no, 39879cb1819SJames Bottomley rphy->scsi_target_id, number); 39979cb1819SJames Bottomley } else 400c7ebbbceSChristoph Hellwig sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 401c7ebbbceSChristoph Hellwig 402c7ebbbceSChristoph Hellwig transport_setup_device(&phy->dev); 403c7ebbbceSChristoph Hellwig 404c7ebbbceSChristoph Hellwig return phy; 405c7ebbbceSChristoph Hellwig } 406c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_alloc); 407c7ebbbceSChristoph Hellwig 408c7ebbbceSChristoph Hellwig /** 409c7ebbbceSChristoph Hellwig * sas_phy_add -- add a SAS PHY to the device hierachy 410c7ebbbceSChristoph Hellwig * @phy: The PHY to be added 411c7ebbbceSChristoph Hellwig * 412c7ebbbceSChristoph Hellwig * Publishes a SAS PHY to the rest of the system. 413c7ebbbceSChristoph Hellwig */ 414c7ebbbceSChristoph Hellwig int sas_phy_add(struct sas_phy *phy) 415c7ebbbceSChristoph Hellwig { 416c7ebbbceSChristoph Hellwig int error; 417c7ebbbceSChristoph Hellwig 418c7ebbbceSChristoph Hellwig error = device_add(&phy->dev); 419c7ebbbceSChristoph Hellwig if (!error) { 420c7ebbbceSChristoph Hellwig transport_add_device(&phy->dev); 421c7ebbbceSChristoph Hellwig transport_configure_device(&phy->dev); 422c7ebbbceSChristoph Hellwig } 423c7ebbbceSChristoph Hellwig 424c7ebbbceSChristoph Hellwig return error; 425c7ebbbceSChristoph Hellwig } 426c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_add); 427c7ebbbceSChristoph Hellwig 428c7ebbbceSChristoph Hellwig /** 429c7ebbbceSChristoph Hellwig * sas_phy_free -- free a SAS PHY 430c7ebbbceSChristoph Hellwig * @phy: SAS PHY to free 431c7ebbbceSChristoph Hellwig * 432c7ebbbceSChristoph Hellwig * Frees the specified SAS PHY. 433c7ebbbceSChristoph Hellwig * 434c7ebbbceSChristoph Hellwig * Note: 435c7ebbbceSChristoph Hellwig * This function must only be called on a PHY that has not 436c7ebbbceSChristoph Hellwig * sucessfully been added using sas_phy_add(). 437c7ebbbceSChristoph Hellwig */ 438c7ebbbceSChristoph Hellwig void sas_phy_free(struct sas_phy *phy) 439c7ebbbceSChristoph Hellwig { 440c7ebbbceSChristoph Hellwig transport_destroy_device(&phy->dev); 44192aab646SMike Anderson put_device(&phy->dev); 442c7ebbbceSChristoph Hellwig } 443c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_free); 444c7ebbbceSChristoph Hellwig 445c7ebbbceSChristoph Hellwig /** 446c7ebbbceSChristoph Hellwig * sas_phy_delete -- remove SAS PHY 447c7ebbbceSChristoph Hellwig * @phy: SAS PHY to remove 448c7ebbbceSChristoph Hellwig * 449c7ebbbceSChristoph Hellwig * Removes the specified SAS PHY. If the SAS PHY has an 450c7ebbbceSChristoph Hellwig * associated remote PHY it is removed before. 451c7ebbbceSChristoph Hellwig */ 452c7ebbbceSChristoph Hellwig void 453c7ebbbceSChristoph Hellwig sas_phy_delete(struct sas_phy *phy) 454c7ebbbceSChristoph Hellwig { 455c7ebbbceSChristoph Hellwig struct device *dev = &phy->dev; 456c7ebbbceSChristoph Hellwig 45765c92b09SJames Bottomley /* this happens if the phy is still part of a port when deleted */ 45865c92b09SJames Bottomley BUG_ON(!list_empty(&phy->port_siblings)); 459c7ebbbceSChristoph Hellwig 460c7ebbbceSChristoph Hellwig transport_remove_device(dev); 461c7ebbbceSChristoph Hellwig device_del(dev); 462c7ebbbceSChristoph Hellwig transport_destroy_device(dev); 46392aab646SMike Anderson put_device(dev); 464c7ebbbceSChristoph Hellwig } 465c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_delete); 466c7ebbbceSChristoph Hellwig 467c7ebbbceSChristoph Hellwig /** 468c7ebbbceSChristoph Hellwig * scsi_is_sas_phy -- check if a struct device represents a SAS PHY 469c7ebbbceSChristoph Hellwig * @dev: device to check 470c7ebbbceSChristoph Hellwig * 471c7ebbbceSChristoph Hellwig * Returns: 472c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS PHY, %0 else 473c7ebbbceSChristoph Hellwig */ 474c7ebbbceSChristoph Hellwig int scsi_is_sas_phy(const struct device *dev) 475c7ebbbceSChristoph Hellwig { 476c7ebbbceSChristoph Hellwig return dev->release == sas_phy_release; 477c7ebbbceSChristoph Hellwig } 478c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_phy); 479c7ebbbceSChristoph Hellwig 480c7ebbbceSChristoph Hellwig /* 48165c92b09SJames Bottomley * SAS Port attributes 48265c92b09SJames Bottomley */ 48365c92b09SJames Bottomley #define sas_port_show_simple(field, name, format_string, cast) \ 48465c92b09SJames Bottomley static ssize_t \ 48565c92b09SJames Bottomley show_sas_port_##name(struct class_device *cdev, char *buf) \ 48665c92b09SJames Bottomley { \ 48765c92b09SJames Bottomley struct sas_port *port = transport_class_to_sas_port(cdev); \ 48865c92b09SJames Bottomley \ 48965c92b09SJames Bottomley return snprintf(buf, 20, format_string, cast port->field); \ 49065c92b09SJames Bottomley } 49165c92b09SJames Bottomley 49265c92b09SJames Bottomley #define sas_port_simple_attr(field, name, format_string, type) \ 49365c92b09SJames Bottomley sas_port_show_simple(field, name, format_string, (type)) \ 49465c92b09SJames Bottomley static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) 49565c92b09SJames Bottomley 49665c92b09SJames Bottomley sas_port_simple_attr(num_phys, num_phys, "%d\n", int); 49765c92b09SJames Bottomley 49865c92b09SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_port_class, 49965c92b09SJames Bottomley "sas_port", NULL, NULL, NULL); 50065c92b09SJames Bottomley 50165c92b09SJames Bottomley static int sas_port_match(struct attribute_container *cont, struct device *dev) 50265c92b09SJames Bottomley { 50365c92b09SJames Bottomley struct Scsi_Host *shost; 50465c92b09SJames Bottomley struct sas_internal *i; 50565c92b09SJames Bottomley 50665c92b09SJames Bottomley if (!scsi_is_sas_port(dev)) 50765c92b09SJames Bottomley return 0; 50865c92b09SJames Bottomley shost = dev_to_shost(dev->parent); 50965c92b09SJames Bottomley 51065c92b09SJames Bottomley if (!shost->transportt) 51165c92b09SJames Bottomley return 0; 51265c92b09SJames Bottomley if (shost->transportt->host_attrs.ac.class != 51365c92b09SJames Bottomley &sas_host_class.class) 51465c92b09SJames Bottomley return 0; 51565c92b09SJames Bottomley 51665c92b09SJames Bottomley i = to_sas_internal(shost->transportt); 51765c92b09SJames Bottomley return &i->port_attr_cont.ac == cont; 51865c92b09SJames Bottomley } 51965c92b09SJames Bottomley 52065c92b09SJames Bottomley 52165c92b09SJames Bottomley static void sas_port_release(struct device *dev) 52265c92b09SJames Bottomley { 52365c92b09SJames Bottomley struct sas_port *port = dev_to_sas_port(dev); 52465c92b09SJames Bottomley 52565c92b09SJames Bottomley BUG_ON(!list_empty(&port->phy_list)); 52665c92b09SJames Bottomley 52765c92b09SJames Bottomley put_device(dev->parent); 52865c92b09SJames Bottomley kfree(port); 52965c92b09SJames Bottomley } 53065c92b09SJames Bottomley 53165c92b09SJames Bottomley static void sas_port_create_link(struct sas_port *port, 53265c92b09SJames Bottomley struct sas_phy *phy) 53365c92b09SJames Bottomley { 53465c92b09SJames Bottomley sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id); 53565c92b09SJames Bottomley sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); 53665c92b09SJames Bottomley } 53765c92b09SJames Bottomley 53865c92b09SJames Bottomley static void sas_port_delete_link(struct sas_port *port, 53965c92b09SJames Bottomley struct sas_phy *phy) 54065c92b09SJames Bottomley { 54165c92b09SJames Bottomley sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id); 54265c92b09SJames Bottomley sysfs_remove_link(&phy->dev.kobj, "port"); 54365c92b09SJames Bottomley } 54465c92b09SJames Bottomley 54565c92b09SJames Bottomley /** sas_port_alloc - allocate and initialize a SAS port structure 54665c92b09SJames Bottomley * 54765c92b09SJames Bottomley * @parent: parent device 54865c92b09SJames Bottomley * @port_id: port number 54965c92b09SJames Bottomley * 55065c92b09SJames Bottomley * Allocates a SAS port structure. It will be added to the device tree 55165c92b09SJames Bottomley * below the device specified by @parent which must be either a Scsi_Host 55265c92b09SJames Bottomley * or a sas_expander_device. 55365c92b09SJames Bottomley * 55465c92b09SJames Bottomley * Returns %NULL on error 55565c92b09SJames Bottomley */ 55665c92b09SJames Bottomley struct sas_port *sas_port_alloc(struct device *parent, int port_id) 55765c92b09SJames Bottomley { 55865c92b09SJames Bottomley struct Scsi_Host *shost = dev_to_shost(parent); 55965c92b09SJames Bottomley struct sas_port *port; 56065c92b09SJames Bottomley 56165c92b09SJames Bottomley port = kzalloc(sizeof(*port), GFP_KERNEL); 56265c92b09SJames Bottomley if (!port) 56365c92b09SJames Bottomley return NULL; 56465c92b09SJames Bottomley 56565c92b09SJames Bottomley port->port_identifier = port_id; 56665c92b09SJames Bottomley 56765c92b09SJames Bottomley device_initialize(&port->dev); 56865c92b09SJames Bottomley 56965c92b09SJames Bottomley port->dev.parent = get_device(parent); 57065c92b09SJames Bottomley port->dev.release = sas_port_release; 57165c92b09SJames Bottomley 57265c92b09SJames Bottomley mutex_init(&port->phy_list_mutex); 57365c92b09SJames Bottomley INIT_LIST_HEAD(&port->phy_list); 57465c92b09SJames Bottomley 57565c92b09SJames Bottomley if (scsi_is_sas_expander_device(parent)) { 57665c92b09SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent); 57765c92b09SJames Bottomley sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no, 57865c92b09SJames Bottomley rphy->scsi_target_id, port->port_identifier); 57965c92b09SJames Bottomley } else 58065c92b09SJames Bottomley sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no, 58165c92b09SJames Bottomley port->port_identifier); 58265c92b09SJames Bottomley 58365c92b09SJames Bottomley transport_setup_device(&port->dev); 58465c92b09SJames Bottomley 58565c92b09SJames Bottomley return port; 58665c92b09SJames Bottomley } 58765c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_alloc); 58865c92b09SJames Bottomley 589c9fefeb2SJames Bottomley /** sas_port_alloc_num - allocate and initialize a SAS port structure 590c9fefeb2SJames Bottomley * 591c9fefeb2SJames Bottomley * @parent: parent device 592c9fefeb2SJames Bottomley * 593c9fefeb2SJames Bottomley * Allocates a SAS port structure and a number to go with it. This 594c9fefeb2SJames Bottomley * interface is really for adapters where the port number has no 595c9fefeb2SJames Bottomley * meansing, so the sas class should manage them. It will be added to 596c9fefeb2SJames Bottomley * the device tree below the device specified by @parent which must be 597c9fefeb2SJames Bottomley * either a Scsi_Host or a sas_expander_device. 598c9fefeb2SJames Bottomley * 599c9fefeb2SJames Bottomley * Returns %NULL on error 600c9fefeb2SJames Bottomley */ 601c9fefeb2SJames Bottomley struct sas_port *sas_port_alloc_num(struct device *parent) 602c9fefeb2SJames Bottomley { 603c9fefeb2SJames Bottomley int index; 604c9fefeb2SJames Bottomley struct Scsi_Host *shost = dev_to_shost(parent); 605c9fefeb2SJames Bottomley struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 606c9fefeb2SJames Bottomley 607c9fefeb2SJames Bottomley /* FIXME: use idr for this eventually */ 608c9fefeb2SJames Bottomley mutex_lock(&sas_host->lock); 609c9fefeb2SJames Bottomley if (scsi_is_sas_expander_device(parent)) { 610c9fefeb2SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent); 611c9fefeb2SJames Bottomley struct sas_expander_device *exp = rphy_to_expander_device(rphy); 612c9fefeb2SJames Bottomley 613c9fefeb2SJames Bottomley index = exp->next_port_id++; 614c9fefeb2SJames Bottomley } else 615c9fefeb2SJames Bottomley index = sas_host->next_port_id++; 616c9fefeb2SJames Bottomley mutex_unlock(&sas_host->lock); 617c9fefeb2SJames Bottomley return sas_port_alloc(parent, index); 618c9fefeb2SJames Bottomley } 619c9fefeb2SJames Bottomley EXPORT_SYMBOL(sas_port_alloc_num); 620c9fefeb2SJames Bottomley 62165c92b09SJames Bottomley /** 62265c92b09SJames Bottomley * sas_port_add - add a SAS port to the device hierarchy 62365c92b09SJames Bottomley * 62465c92b09SJames Bottomley * @port: port to be added 62565c92b09SJames Bottomley * 62665c92b09SJames Bottomley * publishes a port to the rest of the system 62765c92b09SJames Bottomley */ 62865c92b09SJames Bottomley int sas_port_add(struct sas_port *port) 62965c92b09SJames Bottomley { 63065c92b09SJames Bottomley int error; 63165c92b09SJames Bottomley 63265c92b09SJames Bottomley /* No phys should be added until this is made visible */ 63365c92b09SJames Bottomley BUG_ON(!list_empty(&port->phy_list)); 63465c92b09SJames Bottomley 63565c92b09SJames Bottomley error = device_add(&port->dev); 63665c92b09SJames Bottomley 63765c92b09SJames Bottomley if (error) 63865c92b09SJames Bottomley return error; 63965c92b09SJames Bottomley 64065c92b09SJames Bottomley transport_add_device(&port->dev); 64165c92b09SJames Bottomley transport_configure_device(&port->dev); 64265c92b09SJames Bottomley 64365c92b09SJames Bottomley return 0; 64465c92b09SJames Bottomley } 64565c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_add); 64665c92b09SJames Bottomley 64765c92b09SJames Bottomley /** 64865c92b09SJames Bottomley * sas_port_free -- free a SAS PORT 64965c92b09SJames Bottomley * @port: SAS PORT to free 65065c92b09SJames Bottomley * 65165c92b09SJames Bottomley * Frees the specified SAS PORT. 65265c92b09SJames Bottomley * 65365c92b09SJames Bottomley * Note: 65465c92b09SJames Bottomley * This function must only be called on a PORT that has not 65565c92b09SJames Bottomley * sucessfully been added using sas_port_add(). 65665c92b09SJames Bottomley */ 65765c92b09SJames Bottomley void sas_port_free(struct sas_port *port) 65865c92b09SJames Bottomley { 65965c92b09SJames Bottomley transport_destroy_device(&port->dev); 66065c92b09SJames Bottomley put_device(&port->dev); 66165c92b09SJames Bottomley } 66265c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_free); 66365c92b09SJames Bottomley 66465c92b09SJames Bottomley /** 66565c92b09SJames Bottomley * sas_port_delete -- remove SAS PORT 66665c92b09SJames Bottomley * @port: SAS PORT to remove 66765c92b09SJames Bottomley * 66865c92b09SJames Bottomley * Removes the specified SAS PORT. If the SAS PORT has an 66965c92b09SJames Bottomley * associated phys, unlink them from the port as well. 67065c92b09SJames Bottomley */ 67165c92b09SJames Bottomley void sas_port_delete(struct sas_port *port) 67265c92b09SJames Bottomley { 67365c92b09SJames Bottomley struct device *dev = &port->dev; 67465c92b09SJames Bottomley struct sas_phy *phy, *tmp_phy; 67565c92b09SJames Bottomley 67665c92b09SJames Bottomley if (port->rphy) { 67765c92b09SJames Bottomley sas_rphy_delete(port->rphy); 67865c92b09SJames Bottomley port->rphy = NULL; 67965c92b09SJames Bottomley } 68065c92b09SJames Bottomley 68165c92b09SJames Bottomley mutex_lock(&port->phy_list_mutex); 68265c92b09SJames Bottomley list_for_each_entry_safe(phy, tmp_phy, &port->phy_list, 68365c92b09SJames Bottomley port_siblings) { 68465c92b09SJames Bottomley sas_port_delete_link(port, phy); 68565c92b09SJames Bottomley list_del_init(&phy->port_siblings); 68665c92b09SJames Bottomley } 68765c92b09SJames Bottomley mutex_unlock(&port->phy_list_mutex); 68865c92b09SJames Bottomley 689a0e1b6efSJames Bottomley if (port->is_backlink) { 690a0e1b6efSJames Bottomley struct device *parent = port->dev.parent; 691a0e1b6efSJames Bottomley 692a0e1b6efSJames Bottomley sysfs_remove_link(&port->dev.kobj, parent->bus_id); 693a0e1b6efSJames Bottomley port->is_backlink = 0; 694a0e1b6efSJames Bottomley } 695a0e1b6efSJames Bottomley 69665c92b09SJames Bottomley transport_remove_device(dev); 69765c92b09SJames Bottomley device_del(dev); 69865c92b09SJames Bottomley transport_destroy_device(dev); 69965c92b09SJames Bottomley put_device(dev); 70065c92b09SJames Bottomley } 70165c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_delete); 70265c92b09SJames Bottomley 70365c92b09SJames Bottomley /** 70465c92b09SJames Bottomley * scsi_is_sas_port -- check if a struct device represents a SAS port 70565c92b09SJames Bottomley * @dev: device to check 70665c92b09SJames Bottomley * 70765c92b09SJames Bottomley * Returns: 70865c92b09SJames Bottomley * %1 if the device represents a SAS Port, %0 else 70965c92b09SJames Bottomley */ 71065c92b09SJames Bottomley int scsi_is_sas_port(const struct device *dev) 71165c92b09SJames Bottomley { 71265c92b09SJames Bottomley return dev->release == sas_port_release; 71365c92b09SJames Bottomley } 71465c92b09SJames Bottomley EXPORT_SYMBOL(scsi_is_sas_port); 71565c92b09SJames Bottomley 71665c92b09SJames Bottomley /** 71765c92b09SJames Bottomley * sas_port_add_phy - add another phy to a port to form a wide port 71865c92b09SJames Bottomley * @port: port to add the phy to 71965c92b09SJames Bottomley * @phy: phy to add 72065c92b09SJames Bottomley * 72165c92b09SJames Bottomley * When a port is initially created, it is empty (has no phys). All 72265c92b09SJames Bottomley * ports must have at least one phy to operated, and all wide ports 72365c92b09SJames Bottomley * must have at least two. The current code makes no difference 72465c92b09SJames Bottomley * between ports and wide ports, but the only object that can be 72565c92b09SJames Bottomley * connected to a remote device is a port, so ports must be formed on 72665c92b09SJames Bottomley * all devices with phys if they're connected to anything. 72765c92b09SJames Bottomley */ 72865c92b09SJames Bottomley void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) 72965c92b09SJames Bottomley { 73065c92b09SJames Bottomley mutex_lock(&port->phy_list_mutex); 73165c92b09SJames Bottomley if (unlikely(!list_empty(&phy->port_siblings))) { 73265c92b09SJames Bottomley /* make sure we're already on this port */ 73365c92b09SJames Bottomley struct sas_phy *tmp; 73465c92b09SJames Bottomley 73565c92b09SJames Bottomley list_for_each_entry(tmp, &port->phy_list, port_siblings) 73665c92b09SJames Bottomley if (tmp == phy) 73765c92b09SJames Bottomley break; 73865c92b09SJames Bottomley /* If this trips, you added a phy that was already 73965c92b09SJames Bottomley * part of a different port */ 74065c92b09SJames Bottomley if (unlikely(tmp != phy)) { 74165c92b09SJames Bottomley dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id); 74265c92b09SJames Bottomley BUG(); 74365c92b09SJames Bottomley } 74465c92b09SJames Bottomley } else { 74565c92b09SJames Bottomley sas_port_create_link(port, phy); 74665c92b09SJames Bottomley list_add_tail(&phy->port_siblings, &port->phy_list); 74765c92b09SJames Bottomley port->num_phys++; 74865c92b09SJames Bottomley } 74965c92b09SJames Bottomley mutex_unlock(&port->phy_list_mutex); 75065c92b09SJames Bottomley } 75165c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_add_phy); 75265c92b09SJames Bottomley 75365c92b09SJames Bottomley /** 75465c92b09SJames Bottomley * sas_port_delete_phy - remove a phy from a port or wide port 75565c92b09SJames Bottomley * @port: port to remove the phy from 75665c92b09SJames Bottomley * @phy: phy to remove 75765c92b09SJames Bottomley * 75865c92b09SJames Bottomley * This operation is used for tearing down ports again. It must be 75965c92b09SJames Bottomley * done to every port or wide port before calling sas_port_delete. 76065c92b09SJames Bottomley */ 76165c92b09SJames Bottomley void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy) 76265c92b09SJames Bottomley { 76365c92b09SJames Bottomley mutex_lock(&port->phy_list_mutex); 76465c92b09SJames Bottomley sas_port_delete_link(port, phy); 76565c92b09SJames Bottomley list_del_init(&phy->port_siblings); 76665c92b09SJames Bottomley port->num_phys--; 76765c92b09SJames Bottomley mutex_unlock(&port->phy_list_mutex); 76865c92b09SJames Bottomley } 76965c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_delete_phy); 77065c92b09SJames Bottomley 771a0e1b6efSJames Bottomley void sas_port_mark_backlink(struct sas_port *port) 772a0e1b6efSJames Bottomley { 773a0e1b6efSJames Bottomley struct device *parent = port->dev.parent->parent->parent; 774a0e1b6efSJames Bottomley 775a0e1b6efSJames Bottomley if (port->is_backlink) 776a0e1b6efSJames Bottomley return; 777a0e1b6efSJames Bottomley port->is_backlink = 1; 778a0e1b6efSJames Bottomley sysfs_create_link(&port->dev.kobj, &parent->kobj, 779a0e1b6efSJames Bottomley parent->bus_id); 780a0e1b6efSJames Bottomley 781a0e1b6efSJames Bottomley } 782a0e1b6efSJames Bottomley EXPORT_SYMBOL(sas_port_mark_backlink); 783a0e1b6efSJames Bottomley 78465c92b09SJames Bottomley /* 785c7ebbbceSChristoph Hellwig * SAS remote PHY attributes. 786c7ebbbceSChristoph Hellwig */ 787c7ebbbceSChristoph Hellwig 788c7ebbbceSChristoph Hellwig #define sas_rphy_show_simple(field, name, format_string, cast) \ 789c7ebbbceSChristoph Hellwig static ssize_t \ 790c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 791c7ebbbceSChristoph Hellwig { \ 792c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 793c7ebbbceSChristoph Hellwig \ 794c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast rphy->field); \ 795c7ebbbceSChristoph Hellwig } 796c7ebbbceSChristoph Hellwig 797c7ebbbceSChristoph Hellwig #define sas_rphy_simple_attr(field, name, format_string, type) \ 798c7ebbbceSChristoph Hellwig sas_rphy_show_simple(field, name, format_string, (type)) \ 799c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 800c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 801c7ebbbceSChristoph Hellwig 802c7ebbbceSChristoph Hellwig #define sas_rphy_show_protocol(field, name) \ 803c7ebbbceSChristoph Hellwig static ssize_t \ 804c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 805c7ebbbceSChristoph Hellwig { \ 806c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 807c7ebbbceSChristoph Hellwig \ 808c7ebbbceSChristoph Hellwig if (!rphy->field) \ 809c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 810c7ebbbceSChristoph Hellwig return get_sas_protocol_names(rphy->field, buf); \ 811c7ebbbceSChristoph Hellwig } 812c7ebbbceSChristoph Hellwig 813c7ebbbceSChristoph Hellwig #define sas_rphy_protocol_attr(field, name) \ 814c7ebbbceSChristoph Hellwig sas_rphy_show_protocol(field, name) \ 815c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 816c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 817c7ebbbceSChristoph Hellwig 818c7ebbbceSChristoph Hellwig static ssize_t 819c7ebbbceSChristoph Hellwig show_sas_rphy_device_type(struct class_device *cdev, char *buf) 820c7ebbbceSChristoph Hellwig { 821c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 822c7ebbbceSChristoph Hellwig 823c7ebbbceSChristoph Hellwig if (!rphy->identify.device_type) 824c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 825c7ebbbceSChristoph Hellwig return get_sas_device_type_names( 826c7ebbbceSChristoph Hellwig rphy->identify.device_type, buf); 827c7ebbbceSChristoph Hellwig } 828c7ebbbceSChristoph Hellwig 829c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 830c7ebbbceSChristoph Hellwig show_sas_rphy_device_type, NULL); 831c7ebbbceSChristoph Hellwig 832a0125641SChristoph Hellwig static ssize_t 833a0125641SChristoph Hellwig show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf) 834a0125641SChristoph Hellwig { 835a0125641SChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 836a0125641SChristoph Hellwig struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 837a0125641SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 838a0125641SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 839a0125641SChristoph Hellwig u64 identifier; 840a0125641SChristoph Hellwig int error; 841a0125641SChristoph Hellwig 842a0125641SChristoph Hellwig /* 843a0125641SChristoph Hellwig * Only devices behind an expander are supported, because the 844a0125641SChristoph Hellwig * enclosure identifier is a SMP feature. 845a0125641SChristoph Hellwig */ 846f4ad7b58SJames Bottomley if (scsi_is_sas_phy_local(phy)) 847a0125641SChristoph Hellwig return -EINVAL; 848a0125641SChristoph Hellwig 849a0125641SChristoph Hellwig error = i->f->get_enclosure_identifier(rphy, &identifier); 850a0125641SChristoph Hellwig if (error) 851a0125641SChristoph Hellwig return error; 852a0125641SChristoph Hellwig return sprintf(buf, "0x%llx\n", (unsigned long long)identifier); 853a0125641SChristoph Hellwig } 854a0125641SChristoph Hellwig 855a0125641SChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO, 856a0125641SChristoph Hellwig show_sas_rphy_enclosure_identifier, NULL); 857a0125641SChristoph Hellwig 858a0125641SChristoph Hellwig static ssize_t 859a0125641SChristoph Hellwig show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf) 860a0125641SChristoph Hellwig { 861a0125641SChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 862a0125641SChristoph Hellwig struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 863a0125641SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 864a0125641SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 865a0125641SChristoph Hellwig int val; 866a0125641SChristoph Hellwig 867f4ad7b58SJames Bottomley if (scsi_is_sas_phy_local(phy)) 868a0125641SChristoph Hellwig return -EINVAL; 869a0125641SChristoph Hellwig 870a0125641SChristoph Hellwig val = i->f->get_bay_identifier(rphy); 871a0125641SChristoph Hellwig if (val < 0) 872a0125641SChristoph Hellwig return val; 873a0125641SChristoph Hellwig return sprintf(buf, "%d\n", val); 874a0125641SChristoph Hellwig } 875a0125641SChristoph Hellwig 876a0125641SChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO, 877a0125641SChristoph Hellwig show_sas_rphy_bay_identifier, NULL); 878a0125641SChristoph Hellwig 879c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.initiator_port_protocols, 880c7ebbbceSChristoph Hellwig initiator_port_protocols); 881c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 882c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 883c7ebbbceSChristoph Hellwig unsigned long long); 884c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 885c7ebbbceSChristoph Hellwig 88642ab0360SJames Bottomley /* only need 8 bytes of data plus header (4 or 8) */ 88742ab0360SJames Bottomley #define BUF_SIZE 64 88842ab0360SJames Bottomley 88942ab0360SJames Bottomley int sas_read_port_mode_page(struct scsi_device *sdev) 89042ab0360SJames Bottomley { 89142ab0360SJames Bottomley char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; 89242ab0360SJames Bottomley struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); 89342ab0360SJames Bottomley struct sas_end_device *rdev; 89442ab0360SJames Bottomley struct scsi_mode_data mode_data; 89542ab0360SJames Bottomley int res, error; 89642ab0360SJames Bottomley 89742ab0360SJames Bottomley BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); 89842ab0360SJames Bottomley 89942ab0360SJames Bottomley rdev = rphy_to_end_device(rphy); 90042ab0360SJames Bottomley 90142ab0360SJames Bottomley if (!buffer) 90242ab0360SJames Bottomley return -ENOMEM; 90342ab0360SJames Bottomley 90442ab0360SJames Bottomley res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3, 90542ab0360SJames Bottomley &mode_data, NULL); 90642ab0360SJames Bottomley 90742ab0360SJames Bottomley error = -EINVAL; 90842ab0360SJames Bottomley if (!scsi_status_is_good(res)) 90942ab0360SJames Bottomley goto out; 91042ab0360SJames Bottomley 91142ab0360SJames Bottomley msdata = buffer + mode_data.header_length + 91242ab0360SJames Bottomley mode_data.block_descriptor_length; 91342ab0360SJames Bottomley 91442ab0360SJames Bottomley if (msdata - buffer > BUF_SIZE - 8) 91542ab0360SJames Bottomley goto out; 91642ab0360SJames Bottomley 91742ab0360SJames Bottomley error = 0; 91842ab0360SJames Bottomley 91942ab0360SJames Bottomley rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0; 92042ab0360SJames Bottomley rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5]; 92142ab0360SJames Bottomley rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7]; 92242ab0360SJames Bottomley 92342ab0360SJames Bottomley out: 92442ab0360SJames Bottomley kfree(buffer); 92542ab0360SJames Bottomley return error; 92642ab0360SJames Bottomley } 92742ab0360SJames Bottomley EXPORT_SYMBOL(sas_read_port_mode_page); 92842ab0360SJames Bottomley 92979cb1819SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_end_dev_class, 93079cb1819SJames Bottomley "sas_end_device", NULL, NULL, NULL); 93179cb1819SJames Bottomley 93242ab0360SJames Bottomley #define sas_end_dev_show_simple(field, name, format_string, cast) \ 93342ab0360SJames Bottomley static ssize_t \ 93442ab0360SJames Bottomley show_sas_end_dev_##name(struct class_device *cdev, char *buf) \ 93542ab0360SJames Bottomley { \ 93642ab0360SJames Bottomley struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 93742ab0360SJames Bottomley struct sas_end_device *rdev = rphy_to_end_device(rphy); \ 93842ab0360SJames Bottomley \ 93942ab0360SJames Bottomley return snprintf(buf, 20, format_string, cast rdev->field); \ 94042ab0360SJames Bottomley } 94142ab0360SJames Bottomley 94242ab0360SJames Bottomley #define sas_end_dev_simple_attr(field, name, format_string, type) \ 94342ab0360SJames Bottomley sas_end_dev_show_simple(field, name, format_string, (type)) \ 94442ab0360SJames Bottomley static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, \ 94542ab0360SJames Bottomley show_sas_end_dev_##name, NULL) 94642ab0360SJames Bottomley 94742ab0360SJames Bottomley sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int); 94842ab0360SJames Bottomley sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, 94942ab0360SJames Bottomley "%d\n", int); 95042ab0360SJames Bottomley sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, 95142ab0360SJames Bottomley "%d\n", int); 95242ab0360SJames Bottomley 95379cb1819SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_expander_class, 95479cb1819SJames Bottomley "sas_expander", NULL, NULL, NULL); 95579cb1819SJames Bottomley 95679cb1819SJames Bottomley #define sas_expander_show_simple(field, name, format_string, cast) \ 95779cb1819SJames Bottomley static ssize_t \ 95879cb1819SJames Bottomley show_sas_expander_##name(struct class_device *cdev, char *buf) \ 95979cb1819SJames Bottomley { \ 96079cb1819SJames Bottomley struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 96179cb1819SJames Bottomley struct sas_expander_device *edev = rphy_to_expander_device(rphy); \ 96279cb1819SJames Bottomley \ 96379cb1819SJames Bottomley return snprintf(buf, 20, format_string, cast edev->field); \ 96479cb1819SJames Bottomley } 96579cb1819SJames Bottomley 96679cb1819SJames Bottomley #define sas_expander_simple_attr(field, name, format_string, type) \ 96779cb1819SJames Bottomley sas_expander_show_simple(field, name, format_string, (type)) \ 96879cb1819SJames Bottomley static SAS_CLASS_DEVICE_ATTR(expander, name, S_IRUGO, \ 96979cb1819SJames Bottomley show_sas_expander_##name, NULL) 97079cb1819SJames Bottomley 97179cb1819SJames Bottomley sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *); 97279cb1819SJames Bottomley sas_expander_simple_attr(product_id, product_id, "%s\n", char *); 97379cb1819SJames Bottomley sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *); 97479cb1819SJames Bottomley sas_expander_simple_attr(component_vendor_id, component_vendor_id, 97579cb1819SJames Bottomley "%s\n", char *); 97679cb1819SJames Bottomley sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int); 97779cb1819SJames Bottomley sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n", 97879cb1819SJames Bottomley unsigned int); 97979cb1819SJames Bottomley sas_expander_simple_attr(level, level, "%d\n", int); 98042ab0360SJames Bottomley 981c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 9822f8600dfSJames Bottomley "sas_device", NULL, NULL, NULL); 983c7ebbbceSChristoph Hellwig 984c7ebbbceSChristoph Hellwig static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 985c7ebbbceSChristoph Hellwig { 986c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 987c7ebbbceSChristoph Hellwig struct sas_internal *i; 988c7ebbbceSChristoph Hellwig 989c7ebbbceSChristoph Hellwig if (!scsi_is_sas_rphy(dev)) 990c7ebbbceSChristoph Hellwig return 0; 991c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent->parent); 992c7ebbbceSChristoph Hellwig 993c7ebbbceSChristoph Hellwig if (!shost->transportt) 994c7ebbbceSChristoph Hellwig return 0; 995c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 996c7ebbbceSChristoph Hellwig &sas_host_class.class) 997c7ebbbceSChristoph Hellwig return 0; 998c7ebbbceSChristoph Hellwig 999c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 1000c7ebbbceSChristoph Hellwig return &i->rphy_attr_cont.ac == cont; 1001c7ebbbceSChristoph Hellwig } 1002c7ebbbceSChristoph Hellwig 100342ab0360SJames Bottomley static int sas_end_dev_match(struct attribute_container *cont, 100442ab0360SJames Bottomley struct device *dev) 100542ab0360SJames Bottomley { 100642ab0360SJames Bottomley struct Scsi_Host *shost; 100742ab0360SJames Bottomley struct sas_internal *i; 100842ab0360SJames Bottomley struct sas_rphy *rphy; 100942ab0360SJames Bottomley 101042ab0360SJames Bottomley if (!scsi_is_sas_rphy(dev)) 101142ab0360SJames Bottomley return 0; 101242ab0360SJames Bottomley shost = dev_to_shost(dev->parent->parent); 101342ab0360SJames Bottomley rphy = dev_to_rphy(dev); 101442ab0360SJames Bottomley 101542ab0360SJames Bottomley if (!shost->transportt) 101642ab0360SJames Bottomley return 0; 101742ab0360SJames Bottomley if (shost->transportt->host_attrs.ac.class != 101842ab0360SJames Bottomley &sas_host_class.class) 101942ab0360SJames Bottomley return 0; 102042ab0360SJames Bottomley 102142ab0360SJames Bottomley i = to_sas_internal(shost->transportt); 102242ab0360SJames Bottomley return &i->end_dev_attr_cont.ac == cont && 10232f8600dfSJames Bottomley rphy->identify.device_type == SAS_END_DEVICE; 102442ab0360SJames Bottomley } 102542ab0360SJames Bottomley 102679cb1819SJames Bottomley static int sas_expander_match(struct attribute_container *cont, 102779cb1819SJames Bottomley struct device *dev) 102879cb1819SJames Bottomley { 102979cb1819SJames Bottomley struct Scsi_Host *shost; 103079cb1819SJames Bottomley struct sas_internal *i; 103179cb1819SJames Bottomley struct sas_rphy *rphy; 103279cb1819SJames Bottomley 103379cb1819SJames Bottomley if (!scsi_is_sas_rphy(dev)) 103479cb1819SJames Bottomley return 0; 103579cb1819SJames Bottomley shost = dev_to_shost(dev->parent->parent); 103679cb1819SJames Bottomley rphy = dev_to_rphy(dev); 103779cb1819SJames Bottomley 103879cb1819SJames Bottomley if (!shost->transportt) 103979cb1819SJames Bottomley return 0; 104079cb1819SJames Bottomley if (shost->transportt->host_attrs.ac.class != 104179cb1819SJames Bottomley &sas_host_class.class) 104279cb1819SJames Bottomley return 0; 104379cb1819SJames Bottomley 104479cb1819SJames Bottomley i = to_sas_internal(shost->transportt); 104579cb1819SJames Bottomley return &i->expander_attr_cont.ac == cont && 104679cb1819SJames Bottomley (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE || 10472f8600dfSJames Bottomley rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE); 104879cb1819SJames Bottomley } 104979cb1819SJames Bottomley 10502f8600dfSJames Bottomley static void sas_expander_release(struct device *dev) 1051c7ebbbceSChristoph Hellwig { 1052c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = dev_to_rphy(dev); 10532f8600dfSJames Bottomley struct sas_expander_device *edev = rphy_to_expander_device(rphy); 1054c7ebbbceSChristoph Hellwig 1055c7ebbbceSChristoph Hellwig put_device(dev->parent); 10562f8600dfSJames Bottomley kfree(edev); 1057c7ebbbceSChristoph Hellwig } 1058c7ebbbceSChristoph Hellwig 10592f8600dfSJames Bottomley static void sas_end_device_release(struct device *dev) 1060c7ebbbceSChristoph Hellwig { 10612f8600dfSJames Bottomley struct sas_rphy *rphy = dev_to_rphy(dev); 10622f8600dfSJames Bottomley struct sas_end_device *edev = rphy_to_end_device(rphy); 1063c7ebbbceSChristoph Hellwig 10642f8600dfSJames Bottomley put_device(dev->parent); 10652f8600dfSJames Bottomley kfree(edev); 1066c7ebbbceSChristoph Hellwig } 1067c7ebbbceSChristoph Hellwig 1068c7ebbbceSChristoph Hellwig /** 1069c5943d36SJames Bottomley * sas_rphy_initialize - common rphy intialization 1070c5943d36SJames Bottomley * @rphy: rphy to initialise 1071c5943d36SJames Bottomley * 1072c5943d36SJames Bottomley * Used by both sas_end_device_alloc() and sas_expander_alloc() to 1073c5943d36SJames Bottomley * initialise the common rphy component of each. 1074c5943d36SJames Bottomley */ 1075c5943d36SJames Bottomley static void sas_rphy_initialize(struct sas_rphy *rphy) 1076c5943d36SJames Bottomley { 1077c5943d36SJames Bottomley INIT_LIST_HEAD(&rphy->list); 1078c5943d36SJames Bottomley } 1079c5943d36SJames Bottomley 1080c5943d36SJames Bottomley /** 108142ab0360SJames Bottomley * sas_end_device_alloc - allocate an rphy for an end device 108242ab0360SJames Bottomley * 108342ab0360SJames Bottomley * Allocates an SAS remote PHY structure, connected to @parent. 108442ab0360SJames Bottomley * 108542ab0360SJames Bottomley * Returns: 108642ab0360SJames Bottomley * SAS PHY allocated or %NULL if the allocation failed. 108742ab0360SJames Bottomley */ 108865c92b09SJames Bottomley struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) 108942ab0360SJames Bottomley { 109042ab0360SJames Bottomley struct Scsi_Host *shost = dev_to_shost(&parent->dev); 109142ab0360SJames Bottomley struct sas_end_device *rdev; 109242ab0360SJames Bottomley 109342ab0360SJames Bottomley rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 109442ab0360SJames Bottomley if (!rdev) { 109542ab0360SJames Bottomley return NULL; 109642ab0360SJames Bottomley } 109742ab0360SJames Bottomley 109842ab0360SJames Bottomley device_initialize(&rdev->rphy.dev); 109942ab0360SJames Bottomley rdev->rphy.dev.parent = get_device(&parent->dev); 11002f8600dfSJames Bottomley rdev->rphy.dev.release = sas_end_device_release; 110165c92b09SJames Bottomley if (scsi_is_sas_expander_device(parent->dev.parent)) { 110265c92b09SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); 110365c92b09SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d", 110465c92b09SJames Bottomley shost->host_no, rphy->scsi_target_id, parent->port_identifier); 110565c92b09SJames Bottomley } else 110665c92b09SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d", 110765c92b09SJames Bottomley shost->host_no, parent->port_identifier); 110842ab0360SJames Bottomley rdev->rphy.identify.device_type = SAS_END_DEVICE; 1109c5943d36SJames Bottomley sas_rphy_initialize(&rdev->rphy); 111042ab0360SJames Bottomley transport_setup_device(&rdev->rphy.dev); 111142ab0360SJames Bottomley 111242ab0360SJames Bottomley return &rdev->rphy; 111342ab0360SJames Bottomley } 111442ab0360SJames Bottomley EXPORT_SYMBOL(sas_end_device_alloc); 111542ab0360SJames Bottomley 111679cb1819SJames Bottomley /** 111779cb1819SJames Bottomley * sas_expander_alloc - allocate an rphy for an end device 111879cb1819SJames Bottomley * 111979cb1819SJames Bottomley * Allocates an SAS remote PHY structure, connected to @parent. 112079cb1819SJames Bottomley * 112179cb1819SJames Bottomley * Returns: 112279cb1819SJames Bottomley * SAS PHY allocated or %NULL if the allocation failed. 112379cb1819SJames Bottomley */ 112465c92b09SJames Bottomley struct sas_rphy *sas_expander_alloc(struct sas_port *parent, 112579cb1819SJames Bottomley enum sas_device_type type) 112679cb1819SJames Bottomley { 112779cb1819SJames Bottomley struct Scsi_Host *shost = dev_to_shost(&parent->dev); 112879cb1819SJames Bottomley struct sas_expander_device *rdev; 112979cb1819SJames Bottomley struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 113079cb1819SJames Bottomley 113179cb1819SJames Bottomley BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE && 113279cb1819SJames Bottomley type != SAS_FANOUT_EXPANDER_DEVICE); 113379cb1819SJames Bottomley 113479cb1819SJames Bottomley rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 113579cb1819SJames Bottomley if (!rdev) { 113679cb1819SJames Bottomley return NULL; 113779cb1819SJames Bottomley } 113879cb1819SJames Bottomley 113979cb1819SJames Bottomley device_initialize(&rdev->rphy.dev); 114079cb1819SJames Bottomley rdev->rphy.dev.parent = get_device(&parent->dev); 11412f8600dfSJames Bottomley rdev->rphy.dev.release = sas_expander_release; 114279cb1819SJames Bottomley mutex_lock(&sas_host->lock); 114379cb1819SJames Bottomley rdev->rphy.scsi_target_id = sas_host->next_expander_id++; 114479cb1819SJames Bottomley mutex_unlock(&sas_host->lock); 114579cb1819SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d", 114679cb1819SJames Bottomley shost->host_no, rdev->rphy.scsi_target_id); 114779cb1819SJames Bottomley rdev->rphy.identify.device_type = type; 1148c5943d36SJames Bottomley sas_rphy_initialize(&rdev->rphy); 114979cb1819SJames Bottomley transport_setup_device(&rdev->rphy.dev); 115079cb1819SJames Bottomley 115179cb1819SJames Bottomley return &rdev->rphy; 115279cb1819SJames Bottomley } 115379cb1819SJames Bottomley EXPORT_SYMBOL(sas_expander_alloc); 115442ab0360SJames Bottomley 115542ab0360SJames Bottomley /** 1156c7ebbbceSChristoph Hellwig * sas_rphy_add -- add a SAS remote PHY to the device hierachy 1157c7ebbbceSChristoph Hellwig * @rphy: The remote PHY to be added 1158c7ebbbceSChristoph Hellwig * 1159c7ebbbceSChristoph Hellwig * Publishes a SAS remote PHY to the rest of the system. 1160c7ebbbceSChristoph Hellwig */ 1161c7ebbbceSChristoph Hellwig int sas_rphy_add(struct sas_rphy *rphy) 1162c7ebbbceSChristoph Hellwig { 116365c92b09SJames Bottomley struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); 1164c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 1165c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1166c7ebbbceSChristoph Hellwig struct sas_identify *identify = &rphy->identify; 1167c7ebbbceSChristoph Hellwig int error; 1168c7ebbbceSChristoph Hellwig 1169c7ebbbceSChristoph Hellwig if (parent->rphy) 1170c7ebbbceSChristoph Hellwig return -ENXIO; 1171c7ebbbceSChristoph Hellwig parent->rphy = rphy; 1172c7ebbbceSChristoph Hellwig 1173c7ebbbceSChristoph Hellwig error = device_add(&rphy->dev); 1174c7ebbbceSChristoph Hellwig if (error) 1175c7ebbbceSChristoph Hellwig return error; 1176c7ebbbceSChristoph Hellwig transport_add_device(&rphy->dev); 1177c7ebbbceSChristoph Hellwig transport_configure_device(&rphy->dev); 1178c7ebbbceSChristoph Hellwig 1179e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1180c7ebbbceSChristoph Hellwig list_add_tail(&rphy->list, &sas_host->rphy_list); 1181c7ebbbceSChristoph Hellwig if (identify->device_type == SAS_END_DEVICE && 1182c7ebbbceSChristoph Hellwig (identify->target_port_protocols & 1183c7ebbbceSChristoph Hellwig (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 1184c7ebbbceSChristoph Hellwig rphy->scsi_target_id = sas_host->next_target_id++; 11857676f83aSJames Bottomley else if (identify->device_type == SAS_END_DEVICE) 11867676f83aSJames Bottomley rphy->scsi_target_id = -1; 1187e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1188c7ebbbceSChristoph Hellwig 118979cb1819SJames Bottomley if (identify->device_type == SAS_END_DEVICE && 119079cb1819SJames Bottomley rphy->scsi_target_id != -1) { 1191e8bf3941SJames Bottomley scsi_scan_target(&rphy->dev, 0, 1192c7ebbbceSChristoph Hellwig rphy->scsi_target_id, ~0, 0); 1193c7ebbbceSChristoph Hellwig } 1194c7ebbbceSChristoph Hellwig 1195c7ebbbceSChristoph Hellwig return 0; 1196c7ebbbceSChristoph Hellwig } 1197c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_add); 1198c7ebbbceSChristoph Hellwig 1199c7ebbbceSChristoph Hellwig /** 1200c7ebbbceSChristoph Hellwig * sas_rphy_free -- free a SAS remote PHY 1201c7ebbbceSChristoph Hellwig * @rphy SAS remote PHY to free 1202c7ebbbceSChristoph Hellwig * 1203c7ebbbceSChristoph Hellwig * Frees the specified SAS remote PHY. 1204c7ebbbceSChristoph Hellwig * 1205c7ebbbceSChristoph Hellwig * Note: 1206c7ebbbceSChristoph Hellwig * This function must only be called on a remote 1207c7ebbbceSChristoph Hellwig * PHY that has not sucessfully been added using 1208c7ebbbceSChristoph Hellwig * sas_rphy_add(). 1209c7ebbbceSChristoph Hellwig */ 1210c7ebbbceSChristoph Hellwig void sas_rphy_free(struct sas_rphy *rphy) 1211c7ebbbceSChristoph Hellwig { 121292aab646SMike Anderson struct device *dev = &rphy->dev; 1213c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 1214c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1215c7ebbbceSChristoph Hellwig 1216e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1217c7ebbbceSChristoph Hellwig list_del(&rphy->list); 1218e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1219c7ebbbceSChristoph Hellwig 122092aab646SMike Anderson transport_destroy_device(dev); 12212f8600dfSJames Bottomley 122292aab646SMike Anderson put_device(dev); 1223c7ebbbceSChristoph Hellwig } 1224c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_free); 1225c7ebbbceSChristoph Hellwig 1226c7ebbbceSChristoph Hellwig /** 1227c7ebbbceSChristoph Hellwig * sas_rphy_delete -- remove SAS remote PHY 1228c7ebbbceSChristoph Hellwig * @rphy: SAS remote PHY to remove 1229c7ebbbceSChristoph Hellwig * 1230c7ebbbceSChristoph Hellwig * Removes the specified SAS remote PHY. 1231c7ebbbceSChristoph Hellwig */ 1232c7ebbbceSChristoph Hellwig void 1233c7ebbbceSChristoph Hellwig sas_rphy_delete(struct sas_rphy *rphy) 1234c7ebbbceSChristoph Hellwig { 1235c7ebbbceSChristoph Hellwig struct device *dev = &rphy->dev; 123665c92b09SJames Bottomley struct sas_port *parent = dev_to_sas_port(dev->parent); 1237c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 1238c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1239c7ebbbceSChristoph Hellwig 1240d4054239SChristoph Hellwig switch (rphy->identify.device_type) { 1241d4054239SChristoph Hellwig case SAS_END_DEVICE: 1242fe8b2304SChristoph Hellwig scsi_remove_target(dev); 1243d4054239SChristoph Hellwig break; 1244d4054239SChristoph Hellwig case SAS_EDGE_EXPANDER_DEVICE: 1245d4054239SChristoph Hellwig case SAS_FANOUT_EXPANDER_DEVICE: 124665c92b09SJames Bottomley sas_remove_children(dev); 1247d4054239SChristoph Hellwig break; 1248d4054239SChristoph Hellwig default: 1249d4054239SChristoph Hellwig break; 1250d4054239SChristoph Hellwig } 1251c7ebbbceSChristoph Hellwig 1252fe8b2304SChristoph Hellwig transport_remove_device(dev); 1253fe8b2304SChristoph Hellwig device_del(dev); 1254fe8b2304SChristoph Hellwig transport_destroy_device(dev); 1255c7ebbbceSChristoph Hellwig 1256e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1257c7ebbbceSChristoph Hellwig list_del(&rphy->list); 1258e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1259c7ebbbceSChristoph Hellwig 126033b114e9SChristoph Hellwig parent->rphy = NULL; 126133b114e9SChristoph Hellwig 126292aab646SMike Anderson put_device(dev); 1263c7ebbbceSChristoph Hellwig } 1264c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_delete); 1265c7ebbbceSChristoph Hellwig 1266c7ebbbceSChristoph Hellwig /** 1267c7ebbbceSChristoph Hellwig * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 1268c7ebbbceSChristoph Hellwig * @dev: device to check 1269c7ebbbceSChristoph Hellwig * 1270c7ebbbceSChristoph Hellwig * Returns: 1271c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS remote PHY, %0 else 1272c7ebbbceSChristoph Hellwig */ 1273c7ebbbceSChristoph Hellwig int scsi_is_sas_rphy(const struct device *dev) 1274c7ebbbceSChristoph Hellwig { 12752f8600dfSJames Bottomley return dev->release == sas_end_device_release || 12762f8600dfSJames Bottomley dev->release == sas_expander_release; 1277c7ebbbceSChristoph Hellwig } 1278c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_rphy); 1279c7ebbbceSChristoph Hellwig 1280c7ebbbceSChristoph Hellwig 1281c7ebbbceSChristoph Hellwig /* 1282c7ebbbceSChristoph Hellwig * SCSI scan helper 1283c7ebbbceSChristoph Hellwig */ 1284c7ebbbceSChristoph Hellwig 1285e02f3f59SChristoph Hellwig static int sas_user_scan(struct Scsi_Host *shost, uint channel, 1286e02f3f59SChristoph Hellwig uint id, uint lun) 1287c7ebbbceSChristoph Hellwig { 1288c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1289c7ebbbceSChristoph Hellwig struct sas_rphy *rphy; 1290c7ebbbceSChristoph Hellwig 1291e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1292c7ebbbceSChristoph Hellwig list_for_each_entry(rphy, &sas_host->rphy_list, list) { 12936d99a3f3SJames Bottomley if (rphy->identify.device_type != SAS_END_DEVICE || 12946d99a3f3SJames Bottomley rphy->scsi_target_id == -1) 1295e02f3f59SChristoph Hellwig continue; 1296e02f3f59SChristoph Hellwig 1297e8bf3941SJames Bottomley if ((channel == SCAN_WILD_CARD || channel == 0) && 1298e02f3f59SChristoph Hellwig (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 1299e8bf3941SJames Bottomley scsi_scan_target(&rphy->dev, 0, 1300e02f3f59SChristoph Hellwig rphy->scsi_target_id, lun, 1); 1301e02f3f59SChristoph Hellwig } 1302e02f3f59SChristoph Hellwig } 1303e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1304e02f3f59SChristoph Hellwig 1305e02f3f59SChristoph Hellwig return 0; 1306c7ebbbceSChristoph Hellwig } 1307c7ebbbceSChristoph Hellwig 1308c7ebbbceSChristoph Hellwig 1309c7ebbbceSChristoph Hellwig /* 1310c7ebbbceSChristoph Hellwig * Setup / Teardown code 1311c7ebbbceSChristoph Hellwig */ 1312c7ebbbceSChristoph Hellwig 131342ab0360SJames Bottomley #define SETUP_TEMPLATE(attrb, field, perm, test) \ 131442ab0360SJames Bottomley i->private_##attrb[count] = class_device_attr_##field; \ 131542ab0360SJames Bottomley i->private_##attrb[count].attr.mode = perm; \ 131642ab0360SJames Bottomley i->attrb[count] = &i->private_##attrb[count]; \ 131742ab0360SJames Bottomley if (test) \ 1318c7ebbbceSChristoph Hellwig count++ 1319c7ebbbceSChristoph Hellwig 132042ab0360SJames Bottomley 132142ab0360SJames Bottomley #define SETUP_RPORT_ATTRIBUTE(field) \ 132242ab0360SJames Bottomley SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) 132342ab0360SJames Bottomley 1324dd9fbb52SJames Bottomley #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 132542ab0360SJames Bottomley SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) 1326dd9fbb52SJames Bottomley 132765c92b09SJames Bottomley #define SETUP_PHY_ATTRIBUTE(field) \ 132842ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) 1329c7ebbbceSChristoph Hellwig 133065c92b09SJames Bottomley #define SETUP_PORT_ATTRIBUTE(field) \ 133165c92b09SJames Bottomley SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) 133265c92b09SJames Bottomley 133365c92b09SJames Bottomley #define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \ 133442ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) 1335dd9fbb52SJames Bottomley 133665c92b09SJames Bottomley #define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ 133742ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) 133807ba3a95SChristoph Hellwig 133965c92b09SJames Bottomley #define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ 134042ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) 1341dd9fbb52SJames Bottomley 134242ab0360SJames Bottomley #define SETUP_END_DEV_ATTRIBUTE(field) \ 134342ab0360SJames Bottomley SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) 1344c7ebbbceSChristoph Hellwig 134579cb1819SJames Bottomley #define SETUP_EXPANDER_ATTRIBUTE(field) \ 134679cb1819SJames Bottomley SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1) 134779cb1819SJames Bottomley 1348c7ebbbceSChristoph Hellwig /** 1349c7ebbbceSChristoph Hellwig * sas_attach_transport -- instantiate SAS transport template 1350c7ebbbceSChristoph Hellwig * @ft: SAS transport class function template 1351c7ebbbceSChristoph Hellwig */ 1352c7ebbbceSChristoph Hellwig struct scsi_transport_template * 1353c7ebbbceSChristoph Hellwig sas_attach_transport(struct sas_function_template *ft) 1354c7ebbbceSChristoph Hellwig { 1355c7ebbbceSChristoph Hellwig struct sas_internal *i; 1356c7ebbbceSChristoph Hellwig int count; 1357c7ebbbceSChristoph Hellwig 135824669f75SJes Sorensen i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); 1359c7ebbbceSChristoph Hellwig if (!i) 1360c7ebbbceSChristoph Hellwig return NULL; 1361c7ebbbceSChristoph Hellwig 1362e02f3f59SChristoph Hellwig i->t.user_scan = sas_user_scan; 1363c7ebbbceSChristoph Hellwig 1364c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 1365c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.class = &sas_host_class.class; 1366c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.match = sas_host_match; 1367c7ebbbceSChristoph Hellwig transport_container_register(&i->t.host_attrs); 1368c7ebbbceSChristoph Hellwig i->t.host_size = sizeof(struct sas_host_attrs); 1369c7ebbbceSChristoph Hellwig 1370c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.class = &sas_phy_class.class; 1371c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 1372c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.match = sas_phy_match; 1373c7ebbbceSChristoph Hellwig transport_container_register(&i->phy_attr_cont); 1374c7ebbbceSChristoph Hellwig 137565c92b09SJames Bottomley i->port_attr_cont.ac.class = &sas_port_class.class; 137665c92b09SJames Bottomley i->port_attr_cont.ac.attrs = &i->port_attrs[0]; 137765c92b09SJames Bottomley i->port_attr_cont.ac.match = sas_port_match; 137865c92b09SJames Bottomley transport_container_register(&i->port_attr_cont); 137965c92b09SJames Bottomley 1380c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 1381c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 1382c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.match = sas_rphy_match; 1383c7ebbbceSChristoph Hellwig transport_container_register(&i->rphy_attr_cont); 1384c7ebbbceSChristoph Hellwig 138542ab0360SJames Bottomley i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class; 138642ab0360SJames Bottomley i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0]; 138742ab0360SJames Bottomley i->end_dev_attr_cont.ac.match = sas_end_dev_match; 138842ab0360SJames Bottomley transport_container_register(&i->end_dev_attr_cont); 138942ab0360SJames Bottomley 139079cb1819SJames Bottomley i->expander_attr_cont.ac.class = &sas_expander_class.class; 139179cb1819SJames Bottomley i->expander_attr_cont.ac.attrs = &i->expander_attrs[0]; 139279cb1819SJames Bottomley i->expander_attr_cont.ac.match = sas_expander_match; 139379cb1819SJames Bottomley transport_container_register(&i->expander_attr_cont); 139479cb1819SJames Bottomley 1395c7ebbbceSChristoph Hellwig i->f = ft; 1396c7ebbbceSChristoph Hellwig 1397c7ebbbceSChristoph Hellwig count = 0; 139865c92b09SJames Bottomley SETUP_PORT_ATTRIBUTE(num_phys); 1399c7ebbbceSChristoph Hellwig i->host_attrs[count] = NULL; 1400c7ebbbceSChristoph Hellwig 1401c7ebbbceSChristoph Hellwig count = 0; 140265c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(initiator_port_protocols); 140365c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(target_port_protocols); 140465c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(device_type); 140565c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(sas_address); 140665c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(phy_identifier); 140765c92b09SJames Bottomley //SETUP_PHY_ATTRIBUTE(port_identifier); 140865c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(negotiated_linkrate); 140965c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); 141065c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(minimum_linkrate); 141165c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); 141265c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(maximum_linkrate); 1413c3ee74c4SChristoph Hellwig 141465c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(invalid_dword_count); 141565c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(running_disparity_error_count); 141665c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count); 141765c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); 141865c92b09SJames Bottomley SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); 141965c92b09SJames Bottomley SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 1420c7ebbbceSChristoph Hellwig i->phy_attrs[count] = NULL; 1421c7ebbbceSChristoph Hellwig 1422c7ebbbceSChristoph Hellwig count = 0; 142365c92b09SJames Bottomley SETUP_PORT_ATTRIBUTE(num_phys); 142465c92b09SJames Bottomley i->port_attrs[count] = NULL; 142565c92b09SJames Bottomley 142665c92b09SJames Bottomley count = 0; 1427c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 1428c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 1429c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_device_type); 1430c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 1431c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 1432dd9fbb52SJames Bottomley SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier, 1433dd9fbb52SJames Bottomley get_enclosure_identifier); 1434dd9fbb52SJames Bottomley SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier, 1435dd9fbb52SJames Bottomley get_bay_identifier); 1436c7ebbbceSChristoph Hellwig i->rphy_attrs[count] = NULL; 1437c7ebbbceSChristoph Hellwig 143842ab0360SJames Bottomley count = 0; 143942ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); 144042ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); 144142ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); 144242ab0360SJames Bottomley i->end_dev_attrs[count] = NULL; 144342ab0360SJames Bottomley 144479cb1819SJames Bottomley count = 0; 144579cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(vendor_id); 144679cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(product_id); 144779cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(product_rev); 144879cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(component_vendor_id); 144979cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(component_id); 145079cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(component_revision_id); 145179cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(level); 145279cb1819SJames Bottomley i->expander_attrs[count] = NULL; 145379cb1819SJames Bottomley 1454c7ebbbceSChristoph Hellwig return &i->t; 1455c7ebbbceSChristoph Hellwig } 1456c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_attach_transport); 1457c7ebbbceSChristoph Hellwig 1458c7ebbbceSChristoph Hellwig /** 1459c7ebbbceSChristoph Hellwig * sas_release_transport -- release SAS transport template instance 1460c7ebbbceSChristoph Hellwig * @t: transport template instance 1461c7ebbbceSChristoph Hellwig */ 1462c7ebbbceSChristoph Hellwig void sas_release_transport(struct scsi_transport_template *t) 1463c7ebbbceSChristoph Hellwig { 1464c7ebbbceSChristoph Hellwig struct sas_internal *i = to_sas_internal(t); 1465c7ebbbceSChristoph Hellwig 1466c7ebbbceSChristoph Hellwig transport_container_unregister(&i->t.host_attrs); 1467c7ebbbceSChristoph Hellwig transport_container_unregister(&i->phy_attr_cont); 146865c92b09SJames Bottomley transport_container_unregister(&i->port_attr_cont); 1469c7ebbbceSChristoph Hellwig transport_container_unregister(&i->rphy_attr_cont); 1470db82f841SJames Bottomley transport_container_unregister(&i->end_dev_attr_cont); 147179cb1819SJames Bottomley transport_container_unregister(&i->expander_attr_cont); 1472c7ebbbceSChristoph Hellwig 1473c7ebbbceSChristoph Hellwig kfree(i); 1474c7ebbbceSChristoph Hellwig } 1475c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_release_transport); 1476c7ebbbceSChristoph Hellwig 1477c7ebbbceSChristoph Hellwig static __init int sas_transport_init(void) 1478c7ebbbceSChristoph Hellwig { 1479c7ebbbceSChristoph Hellwig int error; 1480c7ebbbceSChristoph Hellwig 1481c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_host_class); 1482c7ebbbceSChristoph Hellwig if (error) 1483c7ebbbceSChristoph Hellwig goto out; 1484c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_phy_class); 1485c7ebbbceSChristoph Hellwig if (error) 1486c7ebbbceSChristoph Hellwig goto out_unregister_transport; 148765c92b09SJames Bottomley error = transport_class_register(&sas_port_class); 1488c7ebbbceSChristoph Hellwig if (error) 1489c7ebbbceSChristoph Hellwig goto out_unregister_phy; 149065c92b09SJames Bottomley error = transport_class_register(&sas_rphy_class); 149165c92b09SJames Bottomley if (error) 149265c92b09SJames Bottomley goto out_unregister_port; 149342ab0360SJames Bottomley error = transport_class_register(&sas_end_dev_class); 149442ab0360SJames Bottomley if (error) 149542ab0360SJames Bottomley goto out_unregister_rphy; 149679cb1819SJames Bottomley error = transport_class_register(&sas_expander_class); 149779cb1819SJames Bottomley if (error) 149879cb1819SJames Bottomley goto out_unregister_end_dev; 1499c7ebbbceSChristoph Hellwig 1500c7ebbbceSChristoph Hellwig return 0; 1501c7ebbbceSChristoph Hellwig 150279cb1819SJames Bottomley out_unregister_end_dev: 150379cb1819SJames Bottomley transport_class_unregister(&sas_end_dev_class); 150442ab0360SJames Bottomley out_unregister_rphy: 150542ab0360SJames Bottomley transport_class_unregister(&sas_rphy_class); 150665c92b09SJames Bottomley out_unregister_port: 150765c92b09SJames Bottomley transport_class_unregister(&sas_port_class); 1508c7ebbbceSChristoph Hellwig out_unregister_phy: 1509c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 1510c7ebbbceSChristoph Hellwig out_unregister_transport: 1511c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 1512c7ebbbceSChristoph Hellwig out: 1513c7ebbbceSChristoph Hellwig return error; 1514c7ebbbceSChristoph Hellwig 1515c7ebbbceSChristoph Hellwig } 1516c7ebbbceSChristoph Hellwig 1517c7ebbbceSChristoph Hellwig static void __exit sas_transport_exit(void) 1518c7ebbbceSChristoph Hellwig { 1519c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 1520c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 152165c92b09SJames Bottomley transport_class_unregister(&sas_port_class); 1522c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_rphy_class); 152342ab0360SJames Bottomley transport_class_unregister(&sas_end_dev_class); 152479cb1819SJames Bottomley transport_class_unregister(&sas_expander_class); 1525c7ebbbceSChristoph Hellwig } 1526c7ebbbceSChristoph Hellwig 1527c7ebbbceSChristoph Hellwig MODULE_AUTHOR("Christoph Hellwig"); 1528c7ebbbceSChristoph Hellwig MODULE_DESCRIPTION("SAS Transphy Attributes"); 1529c7ebbbceSChristoph Hellwig MODULE_LICENSE("GPL"); 1530c7ebbbceSChristoph Hellwig 1531c7ebbbceSChristoph Hellwig module_init(sas_transport_init); 1532c7ebbbceSChristoph Hellwig module_exit(sas_transport_exit); 1533