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> 28f6a57033SAl Viro #include <linux/jiffies.h> 29c7ebbbceSChristoph Hellwig #include <linux/err.h> 308c65b4a6STim Schmielau #include <linux/slab.h> 318c65b4a6STim Schmielau #include <linux/string.h> 32c7ebbbceSChristoph Hellwig 33e02f3f59SChristoph Hellwig #include <scsi/scsi.h> 34c7ebbbceSChristoph Hellwig #include <scsi/scsi_device.h> 35c7ebbbceSChristoph Hellwig #include <scsi/scsi_host.h> 36c7ebbbceSChristoph Hellwig #include <scsi/scsi_transport.h> 37c7ebbbceSChristoph Hellwig #include <scsi/scsi_transport_sas.h> 38c7ebbbceSChristoph Hellwig 39d6159c17SJames Bottomley #include "scsi_sas_internal.h" 40c7ebbbceSChristoph Hellwig struct sas_host_attrs { 41c7ebbbceSChristoph Hellwig struct list_head rphy_list; 42e02f3f59SChristoph Hellwig struct mutex lock; 43c7ebbbceSChristoph Hellwig u32 next_target_id; 4479cb1819SJames Bottomley u32 next_expander_id; 45c9fefeb2SJames Bottomley int next_port_id; 46c7ebbbceSChristoph Hellwig }; 47c7ebbbceSChristoph Hellwig #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 48c7ebbbceSChristoph Hellwig 49c7ebbbceSChristoph Hellwig 50c7ebbbceSChristoph Hellwig /* 51c7ebbbceSChristoph Hellwig * Hack to allow attributes of the same name in different objects. 52c7ebbbceSChristoph Hellwig */ 53c7ebbbceSChristoph Hellwig #define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ 54c7ebbbceSChristoph Hellwig struct class_device_attribute class_device_attr_##_prefix##_##_name = \ 55c7ebbbceSChristoph Hellwig __ATTR(_name,_mode,_show,_store) 56c7ebbbceSChristoph Hellwig 57c7ebbbceSChristoph Hellwig 58c7ebbbceSChristoph Hellwig /* 59c7ebbbceSChristoph Hellwig * Pretty printing helpers 60c7ebbbceSChristoph Hellwig */ 61c7ebbbceSChristoph Hellwig 62c7ebbbceSChristoph Hellwig #define sas_bitfield_name_match(title, table) \ 63c7ebbbceSChristoph Hellwig static ssize_t \ 64c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 65c7ebbbceSChristoph Hellwig { \ 66c7ebbbceSChristoph Hellwig char *prefix = ""; \ 67c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 68c7ebbbceSChristoph Hellwig int i; \ 69c7ebbbceSChristoph Hellwig \ 706391a113STobias Klauser for (i = 0; i < ARRAY_SIZE(table); i++) { \ 71c7ebbbceSChristoph Hellwig if (table[i].value & table_key) { \ 72c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s%s", \ 73c7ebbbceSChristoph Hellwig prefix, table[i].name); \ 74c7ebbbceSChristoph Hellwig prefix = ", "; \ 75c7ebbbceSChristoph Hellwig } \ 76c7ebbbceSChristoph Hellwig } \ 77c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 78c7ebbbceSChristoph Hellwig return len; \ 79c7ebbbceSChristoph Hellwig } 80c7ebbbceSChristoph Hellwig 81d24e1eebSJames Bottomley #define sas_bitfield_name_set(title, table) \ 82d24e1eebSJames Bottomley static ssize_t \ 83d24e1eebSJames Bottomley set_sas_##title##_names(u32 *table_key, const char *buf) \ 84d24e1eebSJames Bottomley { \ 85d24e1eebSJames Bottomley ssize_t len = 0; \ 86d24e1eebSJames Bottomley int i; \ 87d24e1eebSJames Bottomley \ 88d24e1eebSJames Bottomley for (i = 0; i < ARRAY_SIZE(table); i++) { \ 89d24e1eebSJames Bottomley len = strlen(table[i].name); \ 90d24e1eebSJames Bottomley if (strncmp(buf, table[i].name, len) == 0 && \ 91d24e1eebSJames Bottomley (buf[len] == '\n' || buf[len] == '\0')) { \ 92d24e1eebSJames Bottomley *table_key = table[i].value; \ 93d24e1eebSJames Bottomley return 0; \ 94d24e1eebSJames Bottomley } \ 95d24e1eebSJames Bottomley } \ 96d24e1eebSJames Bottomley return -EINVAL; \ 97d24e1eebSJames Bottomley } 98d24e1eebSJames Bottomley 99c7ebbbceSChristoph Hellwig #define sas_bitfield_name_search(title, table) \ 100c7ebbbceSChristoph Hellwig static ssize_t \ 101c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf) \ 102c7ebbbceSChristoph Hellwig { \ 103c7ebbbceSChristoph Hellwig ssize_t len = 0; \ 104c7ebbbceSChristoph Hellwig int i; \ 105c7ebbbceSChristoph Hellwig \ 1066391a113STobias Klauser for (i = 0; i < ARRAY_SIZE(table); i++) { \ 107c7ebbbceSChristoph Hellwig if (table[i].value == table_key) { \ 108c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "%s", \ 109c7ebbbceSChristoph Hellwig table[i].name); \ 110c7ebbbceSChristoph Hellwig break; \ 111c7ebbbceSChristoph Hellwig } \ 112c7ebbbceSChristoph Hellwig } \ 113c7ebbbceSChristoph Hellwig len += sprintf(buf + len, "\n"); \ 114c7ebbbceSChristoph Hellwig return len; \ 115c7ebbbceSChristoph Hellwig } 116c7ebbbceSChristoph Hellwig 117c7ebbbceSChristoph Hellwig static struct { 118c7ebbbceSChristoph Hellwig u32 value; 119c7ebbbceSChristoph Hellwig char *name; 120c7ebbbceSChristoph Hellwig } sas_device_type_names[] = { 121c7ebbbceSChristoph Hellwig { SAS_PHY_UNUSED, "unused" }, 122c7ebbbceSChristoph Hellwig { SAS_END_DEVICE, "end device" }, 123c7ebbbceSChristoph Hellwig { SAS_EDGE_EXPANDER_DEVICE, "edge expander" }, 124c7ebbbceSChristoph Hellwig { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" }, 125c7ebbbceSChristoph Hellwig }; 126c7ebbbceSChristoph Hellwig sas_bitfield_name_search(device_type, sas_device_type_names) 127c7ebbbceSChristoph Hellwig 128c7ebbbceSChristoph Hellwig 129c7ebbbceSChristoph Hellwig static struct { 130c7ebbbceSChristoph Hellwig u32 value; 131c7ebbbceSChristoph Hellwig char *name; 132c7ebbbceSChristoph Hellwig } sas_protocol_names[] = { 133c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SATA, "sata" }, 134c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SMP, "smp" }, 135c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_STP, "stp" }, 136c7ebbbceSChristoph Hellwig { SAS_PROTOCOL_SSP, "ssp" }, 137c7ebbbceSChristoph Hellwig }; 138c7ebbbceSChristoph Hellwig sas_bitfield_name_match(protocol, sas_protocol_names) 139c7ebbbceSChristoph Hellwig 140c7ebbbceSChristoph Hellwig static struct { 141c7ebbbceSChristoph Hellwig u32 value; 142c7ebbbceSChristoph Hellwig char *name; 143c7ebbbceSChristoph Hellwig } sas_linkspeed_names[] = { 144c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_UNKNOWN, "Unknown" }, 145c7ebbbceSChristoph Hellwig { SAS_PHY_DISABLED, "Phy disabled" }, 146c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_FAILED, "Link Rate failed" }, 147c7ebbbceSChristoph Hellwig { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, 148c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 149c7ebbbceSChristoph Hellwig { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 1507e6dff62SJames Bottomley { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, 151c7ebbbceSChristoph Hellwig }; 152c7ebbbceSChristoph Hellwig sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 153d24e1eebSJames Bottomley sas_bitfield_name_set(linkspeed, sas_linkspeed_names) 154c7ebbbceSChristoph Hellwig 155c7ebbbceSChristoph Hellwig /* 156c7ebbbceSChristoph Hellwig * SAS host attributes 157c7ebbbceSChristoph Hellwig */ 158c7ebbbceSChristoph Hellwig 15937be6eebSJames Bottomley static int sas_host_setup(struct transport_container *tc, struct device *dev, 16037be6eebSJames Bottomley struct class_device *cdev) 161c7ebbbceSChristoph Hellwig { 162c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(dev); 163c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 164c7ebbbceSChristoph Hellwig 165c7ebbbceSChristoph Hellwig INIT_LIST_HEAD(&sas_host->rphy_list); 166e02f3f59SChristoph Hellwig mutex_init(&sas_host->lock); 167c7ebbbceSChristoph Hellwig sas_host->next_target_id = 0; 16879cb1819SJames Bottomley sas_host->next_expander_id = 0; 169c9fefeb2SJames Bottomley sas_host->next_port_id = 0; 170c7ebbbceSChristoph Hellwig return 0; 171c7ebbbceSChristoph Hellwig } 172c7ebbbceSChristoph Hellwig 173c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_host_class, 174c7ebbbceSChristoph Hellwig "sas_host", sas_host_setup, NULL, NULL); 175c7ebbbceSChristoph Hellwig 176c7ebbbceSChristoph Hellwig static int sas_host_match(struct attribute_container *cont, 177c7ebbbceSChristoph Hellwig struct device *dev) 178c7ebbbceSChristoph Hellwig { 179c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 180c7ebbbceSChristoph Hellwig struct sas_internal *i; 181c7ebbbceSChristoph Hellwig 182c7ebbbceSChristoph Hellwig if (!scsi_is_host_device(dev)) 183c7ebbbceSChristoph Hellwig return 0; 184c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev); 185c7ebbbceSChristoph Hellwig 186c7ebbbceSChristoph Hellwig if (!shost->transportt) 187c7ebbbceSChristoph Hellwig return 0; 188c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 189c7ebbbceSChristoph Hellwig &sas_host_class.class) 190c7ebbbceSChristoph Hellwig return 0; 191c7ebbbceSChristoph Hellwig 192c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 193c7ebbbceSChristoph Hellwig return &i->t.host_attrs.ac == cont; 194c7ebbbceSChristoph Hellwig } 195c7ebbbceSChristoph Hellwig 196c7ebbbceSChristoph Hellwig static int do_sas_phy_delete(struct device *dev, void *data) 197c7ebbbceSChristoph Hellwig { 19865c92b09SJames Bottomley int pass = (int)(unsigned long)data; 19965c92b09SJames Bottomley 20065c92b09SJames Bottomley if (pass == 0 && scsi_is_sas_port(dev)) 20165c92b09SJames Bottomley sas_port_delete(dev_to_sas_port(dev)); 20265c92b09SJames Bottomley else if (pass == 1 && scsi_is_sas_phy(dev)) 203c7ebbbceSChristoph Hellwig sas_phy_delete(dev_to_phy(dev)); 204c7ebbbceSChristoph Hellwig return 0; 205c7ebbbceSChristoph Hellwig } 206c7ebbbceSChristoph Hellwig 207c7ebbbceSChristoph Hellwig /** 20865c92b09SJames Bottomley * sas_remove_children -- tear down a devices SAS data structures 20965c92b09SJames Bottomley * @dev: device belonging to the sas object 21065c92b09SJames Bottomley * 21165c92b09SJames Bottomley * Removes all SAS PHYs and remote PHYs for a given object 21265c92b09SJames Bottomley */ 21365c92b09SJames Bottomley void sas_remove_children(struct device *dev) 21465c92b09SJames Bottomley { 21565c92b09SJames Bottomley device_for_each_child(dev, (void *)0, do_sas_phy_delete); 21665c92b09SJames Bottomley device_for_each_child(dev, (void *)1, do_sas_phy_delete); 21765c92b09SJames Bottomley } 21865c92b09SJames Bottomley EXPORT_SYMBOL(sas_remove_children); 21965c92b09SJames Bottomley 22065c92b09SJames Bottomley /** 221c7ebbbceSChristoph Hellwig * sas_remove_host -- tear down a Scsi_Host's SAS data structures 222c7ebbbceSChristoph Hellwig * @shost: Scsi Host that is torn down 223c7ebbbceSChristoph Hellwig * 224c7ebbbceSChristoph Hellwig * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 225c7ebbbceSChristoph Hellwig * Must be called just before scsi_remove_host for SAS HBAs. 226c7ebbbceSChristoph Hellwig */ 227c7ebbbceSChristoph Hellwig void sas_remove_host(struct Scsi_Host *shost) 228c7ebbbceSChristoph Hellwig { 22965c92b09SJames Bottomley sas_remove_children(&shost->shost_gendev); 230c7ebbbceSChristoph Hellwig } 231c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_remove_host); 232c7ebbbceSChristoph Hellwig 233c7ebbbceSChristoph Hellwig 234c7ebbbceSChristoph Hellwig /* 23565c92b09SJames Bottomley * SAS Phy attributes 236c7ebbbceSChristoph Hellwig */ 237c7ebbbceSChristoph Hellwig 238c7ebbbceSChristoph Hellwig #define sas_phy_show_simple(field, name, format_string, cast) \ 239c7ebbbceSChristoph Hellwig static ssize_t \ 240c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 241c7ebbbceSChristoph Hellwig { \ 242c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 243c7ebbbceSChristoph Hellwig \ 244c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast phy->field); \ 245c7ebbbceSChristoph Hellwig } 246c7ebbbceSChristoph Hellwig 247c7ebbbceSChristoph Hellwig #define sas_phy_simple_attr(field, name, format_string, type) \ 248c7ebbbceSChristoph Hellwig sas_phy_show_simple(field, name, format_string, (type)) \ 249c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 250c7ebbbceSChristoph Hellwig 251c7ebbbceSChristoph Hellwig #define sas_phy_show_protocol(field, name) \ 252c7ebbbceSChristoph Hellwig static ssize_t \ 253c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf) \ 254c7ebbbceSChristoph Hellwig { \ 255c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 256c7ebbbceSChristoph Hellwig \ 257c7ebbbceSChristoph Hellwig if (!phy->field) \ 258c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 259c7ebbbceSChristoph Hellwig return get_sas_protocol_names(phy->field, buf); \ 260c7ebbbceSChristoph Hellwig } 261c7ebbbceSChristoph Hellwig 262c7ebbbceSChristoph Hellwig #define sas_phy_protocol_attr(field, name) \ 263c7ebbbceSChristoph Hellwig sas_phy_show_protocol(field, name) \ 264c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 265c7ebbbceSChristoph Hellwig 266c7ebbbceSChristoph Hellwig #define sas_phy_show_linkspeed(field) \ 267c7ebbbceSChristoph Hellwig static ssize_t \ 268c7ebbbceSChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 269c7ebbbceSChristoph Hellwig { \ 270c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 271c7ebbbceSChristoph Hellwig \ 272c7ebbbceSChristoph Hellwig return get_sas_linkspeed_names(phy->field, buf); \ 273c7ebbbceSChristoph Hellwig } 274c7ebbbceSChristoph Hellwig 275d24e1eebSJames Bottomley /* Fudge to tell if we're minimum or maximum */ 276d24e1eebSJames Bottomley #define sas_phy_store_linkspeed(field) \ 277d24e1eebSJames Bottomley static ssize_t \ 278d24e1eebSJames Bottomley store_sas_phy_##field(struct class_device *cdev, const char *buf, \ 279d24e1eebSJames Bottomley size_t count) \ 280d24e1eebSJames Bottomley { \ 281d24e1eebSJames Bottomley struct sas_phy *phy = transport_class_to_phy(cdev); \ 282d24e1eebSJames Bottomley struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 283d24e1eebSJames Bottomley struct sas_internal *i = to_sas_internal(shost->transportt); \ 284d24e1eebSJames Bottomley u32 value; \ 285d24e1eebSJames Bottomley struct sas_phy_linkrates rates = {0}; \ 286d24e1eebSJames Bottomley int error; \ 287d24e1eebSJames Bottomley \ 288d24e1eebSJames Bottomley error = set_sas_linkspeed_names(&value, buf); \ 289d24e1eebSJames Bottomley if (error) \ 290d24e1eebSJames Bottomley return error; \ 291d24e1eebSJames Bottomley rates.field = value; \ 292d24e1eebSJames Bottomley error = i->f->set_phy_speed(phy, &rates); \ 293d24e1eebSJames Bottomley \ 294d24e1eebSJames Bottomley return error ? error : count; \ 295d24e1eebSJames Bottomley } 296d24e1eebSJames Bottomley 297d24e1eebSJames Bottomley #define sas_phy_linkspeed_rw_attr(field) \ 298d24e1eebSJames Bottomley sas_phy_show_linkspeed(field) \ 299d24e1eebSJames Bottomley sas_phy_store_linkspeed(field) \ 300d24e1eebSJames Bottomley static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \ 301d24e1eebSJames Bottomley store_sas_phy_##field) 302d24e1eebSJames Bottomley 303c7ebbbceSChristoph Hellwig #define sas_phy_linkspeed_attr(field) \ 304c7ebbbceSChristoph Hellwig sas_phy_show_linkspeed(field) \ 305c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 306c7ebbbceSChristoph Hellwig 307d24e1eebSJames Bottomley 308c3ee74c4SChristoph Hellwig #define sas_phy_show_linkerror(field) \ 309c3ee74c4SChristoph Hellwig static ssize_t \ 310c3ee74c4SChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf) \ 311c3ee74c4SChristoph Hellwig { \ 312c3ee74c4SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); \ 313c3ee74c4SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 314c3ee74c4SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); \ 315c3ee74c4SChristoph Hellwig int error; \ 316c3ee74c4SChristoph Hellwig \ 317dd9fbb52SJames Bottomley error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ 318c3ee74c4SChristoph Hellwig if (error) \ 319c3ee74c4SChristoph Hellwig return error; \ 320c3ee74c4SChristoph Hellwig return snprintf(buf, 20, "%u\n", phy->field); \ 321c3ee74c4SChristoph Hellwig } 322c3ee74c4SChristoph Hellwig 323c3ee74c4SChristoph Hellwig #define sas_phy_linkerror_attr(field) \ 324c3ee74c4SChristoph Hellwig sas_phy_show_linkerror(field) \ 325c3ee74c4SChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 326c3ee74c4SChristoph Hellwig 327c3ee74c4SChristoph Hellwig 328c7ebbbceSChristoph Hellwig static ssize_t 329c7ebbbceSChristoph Hellwig show_sas_device_type(struct class_device *cdev, char *buf) 330c7ebbbceSChristoph Hellwig { 331c7ebbbceSChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 332c7ebbbceSChristoph Hellwig 333c7ebbbceSChristoph Hellwig if (!phy->identify.device_type) 334c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 335c7ebbbceSChristoph Hellwig return get_sas_device_type_names(phy->identify.device_type, buf); 336c7ebbbceSChristoph Hellwig } 337c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 338c7ebbbceSChristoph Hellwig 339acbf167dSDarrick J. Wong static ssize_t do_sas_phy_enable(struct class_device *cdev, 340acbf167dSDarrick J. Wong size_t count, int enable) 341acbf167dSDarrick J. Wong { 342acbf167dSDarrick J. Wong struct sas_phy *phy = transport_class_to_phy(cdev); 343acbf167dSDarrick J. Wong struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 344acbf167dSDarrick J. Wong struct sas_internal *i = to_sas_internal(shost->transportt); 345acbf167dSDarrick J. Wong int error; 346acbf167dSDarrick J. Wong 347acbf167dSDarrick J. Wong error = i->f->phy_enable(phy, enable); 348acbf167dSDarrick J. Wong if (error) 349acbf167dSDarrick J. Wong return error; 350acbf167dSDarrick J. Wong phy->enabled = enable; 351acbf167dSDarrick J. Wong return count; 352acbf167dSDarrick J. Wong }; 353acbf167dSDarrick J. Wong 354acbf167dSDarrick J. Wong static ssize_t store_sas_phy_enable(struct class_device *cdev, 355acbf167dSDarrick J. Wong const char *buf, size_t count) 356acbf167dSDarrick J. Wong { 357acbf167dSDarrick J. Wong if (count < 1) 358acbf167dSDarrick J. Wong return -EINVAL; 359acbf167dSDarrick J. Wong 360acbf167dSDarrick J. Wong switch (buf[0]) { 361acbf167dSDarrick J. Wong case '0': 362acbf167dSDarrick J. Wong do_sas_phy_enable(cdev, count, 0); 363acbf167dSDarrick J. Wong break; 364acbf167dSDarrick J. Wong case '1': 365acbf167dSDarrick J. Wong do_sas_phy_enable(cdev, count, 1); 366acbf167dSDarrick J. Wong break; 367acbf167dSDarrick J. Wong default: 368acbf167dSDarrick J. Wong return -EINVAL; 369acbf167dSDarrick J. Wong } 370acbf167dSDarrick J. Wong 371acbf167dSDarrick J. Wong return count; 372acbf167dSDarrick J. Wong } 373acbf167dSDarrick J. Wong 374acbf167dSDarrick J. Wong static ssize_t show_sas_phy_enable(struct class_device *cdev, char *buf) 375acbf167dSDarrick J. Wong { 376acbf167dSDarrick J. Wong struct sas_phy *phy = transport_class_to_phy(cdev); 377acbf167dSDarrick J. Wong 378acbf167dSDarrick J. Wong return snprintf(buf, 20, "%d", phy->enabled); 379acbf167dSDarrick J. Wong } 380acbf167dSDarrick J. Wong 381acbf167dSDarrick J. Wong static CLASS_DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable, 382acbf167dSDarrick J. Wong store_sas_phy_enable); 383acbf167dSDarrick J. Wong 38407ba3a95SChristoph Hellwig static ssize_t do_sas_phy_reset(struct class_device *cdev, 38507ba3a95SChristoph Hellwig size_t count, int hard_reset) 38607ba3a95SChristoph Hellwig { 38707ba3a95SChristoph Hellwig struct sas_phy *phy = transport_class_to_phy(cdev); 38807ba3a95SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 38907ba3a95SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 39007ba3a95SChristoph Hellwig int error; 39107ba3a95SChristoph Hellwig 39207ba3a95SChristoph Hellwig error = i->f->phy_reset(phy, hard_reset); 39307ba3a95SChristoph Hellwig if (error) 39407ba3a95SChristoph Hellwig return error; 39507ba3a95SChristoph Hellwig return count; 39607ba3a95SChristoph Hellwig }; 39707ba3a95SChristoph Hellwig 39807ba3a95SChristoph Hellwig static ssize_t store_sas_link_reset(struct class_device *cdev, 39907ba3a95SChristoph Hellwig const char *buf, size_t count) 40007ba3a95SChristoph Hellwig { 40107ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 0); 40207ba3a95SChristoph Hellwig } 40307ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 40407ba3a95SChristoph Hellwig 40507ba3a95SChristoph Hellwig static ssize_t store_sas_hard_reset(struct class_device *cdev, 40607ba3a95SChristoph Hellwig const char *buf, size_t count) 40707ba3a95SChristoph Hellwig { 40807ba3a95SChristoph Hellwig return do_sas_phy_reset(cdev, count, 1); 40907ba3a95SChristoph Hellwig } 41007ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 41107ba3a95SChristoph Hellwig 412c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.initiator_port_protocols, 413c7ebbbceSChristoph Hellwig initiator_port_protocols); 414c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.target_port_protocols, 415c7ebbbceSChristoph Hellwig target_port_protocols); 416c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 417c7ebbbceSChristoph Hellwig unsigned long long); 418c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 419c9fefeb2SJames Bottomley //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); 420c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(negotiated_linkrate); 421c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate_hw); 422d24e1eebSJames Bottomley sas_phy_linkspeed_rw_attr(minimum_linkrate); 423c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate_hw); 424d24e1eebSJames Bottomley sas_phy_linkspeed_rw_attr(maximum_linkrate); 425c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(invalid_dword_count); 426c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(running_disparity_error_count); 427c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(loss_of_dword_sync_count); 428c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(phy_reset_problem_count); 429c7ebbbceSChristoph Hellwig 430c7ebbbceSChristoph Hellwig 431c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_phy_class, 432c7ebbbceSChristoph Hellwig "sas_phy", NULL, NULL, NULL); 433c7ebbbceSChristoph Hellwig 434c7ebbbceSChristoph Hellwig static int sas_phy_match(struct attribute_container *cont, struct device *dev) 435c7ebbbceSChristoph Hellwig { 436c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 437c7ebbbceSChristoph Hellwig struct sas_internal *i; 438c7ebbbceSChristoph Hellwig 439c7ebbbceSChristoph Hellwig if (!scsi_is_sas_phy(dev)) 440c7ebbbceSChristoph Hellwig return 0; 441c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent); 442c7ebbbceSChristoph Hellwig 443c7ebbbceSChristoph Hellwig if (!shost->transportt) 444c7ebbbceSChristoph Hellwig return 0; 445c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 446c7ebbbceSChristoph Hellwig &sas_host_class.class) 447c7ebbbceSChristoph Hellwig return 0; 448c7ebbbceSChristoph Hellwig 449c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 450c7ebbbceSChristoph Hellwig return &i->phy_attr_cont.ac == cont; 451c7ebbbceSChristoph Hellwig } 452c7ebbbceSChristoph Hellwig 453c7ebbbceSChristoph Hellwig static void sas_phy_release(struct device *dev) 454c7ebbbceSChristoph Hellwig { 455c7ebbbceSChristoph Hellwig struct sas_phy *phy = dev_to_phy(dev); 456c7ebbbceSChristoph Hellwig 457c7ebbbceSChristoph Hellwig put_device(dev->parent); 458c7ebbbceSChristoph Hellwig kfree(phy); 459c7ebbbceSChristoph Hellwig } 460c7ebbbceSChristoph Hellwig 461c7ebbbceSChristoph Hellwig /** 462c7ebbbceSChristoph Hellwig * sas_phy_alloc -- allocates and initialize a SAS PHY structure 463c7ebbbceSChristoph Hellwig * @parent: Parent device 464d99ca418SMoore, Eric * @number: Phy index 465c7ebbbceSChristoph Hellwig * 466c7ebbbceSChristoph Hellwig * Allocates an SAS PHY structure. It will be added in the device tree 467c7ebbbceSChristoph Hellwig * below the device specified by @parent, which has to be either a Scsi_Host 468c7ebbbceSChristoph Hellwig * or sas_rphy. 469c7ebbbceSChristoph Hellwig * 470c7ebbbceSChristoph Hellwig * Returns: 471c7ebbbceSChristoph Hellwig * SAS PHY allocated or %NULL if the allocation failed. 472c7ebbbceSChristoph Hellwig */ 473c7ebbbceSChristoph Hellwig struct sas_phy *sas_phy_alloc(struct device *parent, int number) 474c7ebbbceSChristoph Hellwig { 475c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent); 476c7ebbbceSChristoph Hellwig struct sas_phy *phy; 477c7ebbbceSChristoph Hellwig 47824669f75SJes Sorensen phy = kzalloc(sizeof(*phy), GFP_KERNEL); 479c7ebbbceSChristoph Hellwig if (!phy) 480c7ebbbceSChristoph Hellwig return NULL; 481c7ebbbceSChristoph Hellwig 482c7ebbbceSChristoph Hellwig phy->number = number; 483acbf167dSDarrick J. Wong phy->enabled = 1; 484c7ebbbceSChristoph Hellwig 485c7ebbbceSChristoph Hellwig device_initialize(&phy->dev); 486c7ebbbceSChristoph Hellwig phy->dev.parent = get_device(parent); 487c7ebbbceSChristoph Hellwig phy->dev.release = sas_phy_release; 48865c92b09SJames Bottomley INIT_LIST_HEAD(&phy->port_siblings); 48979cb1819SJames Bottomley if (scsi_is_sas_expander_device(parent)) { 49079cb1819SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent); 49165c92b09SJames Bottomley sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no, 49279cb1819SJames Bottomley rphy->scsi_target_id, number); 49379cb1819SJames Bottomley } else 494c7ebbbceSChristoph Hellwig sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 495c7ebbbceSChristoph Hellwig 496c7ebbbceSChristoph Hellwig transport_setup_device(&phy->dev); 497c7ebbbceSChristoph Hellwig 498c7ebbbceSChristoph Hellwig return phy; 499c7ebbbceSChristoph Hellwig } 500c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_alloc); 501c7ebbbceSChristoph Hellwig 502c7ebbbceSChristoph Hellwig /** 503c7ebbbceSChristoph Hellwig * sas_phy_add -- add a SAS PHY to the device hierachy 504c7ebbbceSChristoph Hellwig * @phy: The PHY to be added 505c7ebbbceSChristoph Hellwig * 506c7ebbbceSChristoph Hellwig * Publishes a SAS PHY to the rest of the system. 507c7ebbbceSChristoph Hellwig */ 508c7ebbbceSChristoph Hellwig int sas_phy_add(struct sas_phy *phy) 509c7ebbbceSChristoph Hellwig { 510c7ebbbceSChristoph Hellwig int error; 511c7ebbbceSChristoph Hellwig 512c7ebbbceSChristoph Hellwig error = device_add(&phy->dev); 513c7ebbbceSChristoph Hellwig if (!error) { 514c7ebbbceSChristoph Hellwig transport_add_device(&phy->dev); 515c7ebbbceSChristoph Hellwig transport_configure_device(&phy->dev); 516c7ebbbceSChristoph Hellwig } 517c7ebbbceSChristoph Hellwig 518c7ebbbceSChristoph Hellwig return error; 519c7ebbbceSChristoph Hellwig } 520c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_add); 521c7ebbbceSChristoph Hellwig 522c7ebbbceSChristoph Hellwig /** 523c7ebbbceSChristoph Hellwig * sas_phy_free -- free a SAS PHY 524c7ebbbceSChristoph Hellwig * @phy: SAS PHY to free 525c7ebbbceSChristoph Hellwig * 526c7ebbbceSChristoph Hellwig * Frees the specified SAS PHY. 527c7ebbbceSChristoph Hellwig * 528c7ebbbceSChristoph Hellwig * Note: 529c7ebbbceSChristoph Hellwig * This function must only be called on a PHY that has not 530c7ebbbceSChristoph Hellwig * sucessfully been added using sas_phy_add(). 531c7ebbbceSChristoph Hellwig */ 532c7ebbbceSChristoph Hellwig void sas_phy_free(struct sas_phy *phy) 533c7ebbbceSChristoph Hellwig { 534c7ebbbceSChristoph Hellwig transport_destroy_device(&phy->dev); 53592aab646SMike Anderson put_device(&phy->dev); 536c7ebbbceSChristoph Hellwig } 537c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_free); 538c7ebbbceSChristoph Hellwig 539c7ebbbceSChristoph Hellwig /** 540c7ebbbceSChristoph Hellwig * sas_phy_delete -- remove SAS PHY 541c7ebbbceSChristoph Hellwig * @phy: SAS PHY to remove 542c7ebbbceSChristoph Hellwig * 543c7ebbbceSChristoph Hellwig * Removes the specified SAS PHY. If the SAS PHY has an 544c7ebbbceSChristoph Hellwig * associated remote PHY it is removed before. 545c7ebbbceSChristoph Hellwig */ 546c7ebbbceSChristoph Hellwig void 547c7ebbbceSChristoph Hellwig sas_phy_delete(struct sas_phy *phy) 548c7ebbbceSChristoph Hellwig { 549c7ebbbceSChristoph Hellwig struct device *dev = &phy->dev; 550c7ebbbceSChristoph Hellwig 55165c92b09SJames Bottomley /* this happens if the phy is still part of a port when deleted */ 55265c92b09SJames Bottomley BUG_ON(!list_empty(&phy->port_siblings)); 553c7ebbbceSChristoph Hellwig 554c7ebbbceSChristoph Hellwig transport_remove_device(dev); 555c7ebbbceSChristoph Hellwig device_del(dev); 556c7ebbbceSChristoph Hellwig transport_destroy_device(dev); 55792aab646SMike Anderson put_device(dev); 558c7ebbbceSChristoph Hellwig } 559c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_delete); 560c7ebbbceSChristoph Hellwig 561c7ebbbceSChristoph Hellwig /** 562c7ebbbceSChristoph Hellwig * scsi_is_sas_phy -- check if a struct device represents a SAS PHY 563c7ebbbceSChristoph Hellwig * @dev: device to check 564c7ebbbceSChristoph Hellwig * 565c7ebbbceSChristoph Hellwig * Returns: 566c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS PHY, %0 else 567c7ebbbceSChristoph Hellwig */ 568c7ebbbceSChristoph Hellwig int scsi_is_sas_phy(const struct device *dev) 569c7ebbbceSChristoph Hellwig { 570c7ebbbceSChristoph Hellwig return dev->release == sas_phy_release; 571c7ebbbceSChristoph Hellwig } 572c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_phy); 573c7ebbbceSChristoph Hellwig 574c7ebbbceSChristoph Hellwig /* 57565c92b09SJames Bottomley * SAS Port attributes 57665c92b09SJames Bottomley */ 57765c92b09SJames Bottomley #define sas_port_show_simple(field, name, format_string, cast) \ 57865c92b09SJames Bottomley static ssize_t \ 57965c92b09SJames Bottomley show_sas_port_##name(struct class_device *cdev, char *buf) \ 58065c92b09SJames Bottomley { \ 58165c92b09SJames Bottomley struct sas_port *port = transport_class_to_sas_port(cdev); \ 58265c92b09SJames Bottomley \ 58365c92b09SJames Bottomley return snprintf(buf, 20, format_string, cast port->field); \ 58465c92b09SJames Bottomley } 58565c92b09SJames Bottomley 58665c92b09SJames Bottomley #define sas_port_simple_attr(field, name, format_string, type) \ 58765c92b09SJames Bottomley sas_port_show_simple(field, name, format_string, (type)) \ 58865c92b09SJames Bottomley static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) 58965c92b09SJames Bottomley 59065c92b09SJames Bottomley sas_port_simple_attr(num_phys, num_phys, "%d\n", int); 59165c92b09SJames Bottomley 59265c92b09SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_port_class, 59365c92b09SJames Bottomley "sas_port", NULL, NULL, NULL); 59465c92b09SJames Bottomley 59565c92b09SJames Bottomley static int sas_port_match(struct attribute_container *cont, struct device *dev) 59665c92b09SJames Bottomley { 59765c92b09SJames Bottomley struct Scsi_Host *shost; 59865c92b09SJames Bottomley struct sas_internal *i; 59965c92b09SJames Bottomley 60065c92b09SJames Bottomley if (!scsi_is_sas_port(dev)) 60165c92b09SJames Bottomley return 0; 60265c92b09SJames Bottomley shost = dev_to_shost(dev->parent); 60365c92b09SJames Bottomley 60465c92b09SJames Bottomley if (!shost->transportt) 60565c92b09SJames Bottomley return 0; 60665c92b09SJames Bottomley if (shost->transportt->host_attrs.ac.class != 60765c92b09SJames Bottomley &sas_host_class.class) 60865c92b09SJames Bottomley return 0; 60965c92b09SJames Bottomley 61065c92b09SJames Bottomley i = to_sas_internal(shost->transportt); 61165c92b09SJames Bottomley return &i->port_attr_cont.ac == cont; 61265c92b09SJames Bottomley } 61365c92b09SJames Bottomley 61465c92b09SJames Bottomley 61565c92b09SJames Bottomley static void sas_port_release(struct device *dev) 61665c92b09SJames Bottomley { 61765c92b09SJames Bottomley struct sas_port *port = dev_to_sas_port(dev); 61865c92b09SJames Bottomley 61965c92b09SJames Bottomley BUG_ON(!list_empty(&port->phy_list)); 62065c92b09SJames Bottomley 62165c92b09SJames Bottomley put_device(dev->parent); 62265c92b09SJames Bottomley kfree(port); 62365c92b09SJames Bottomley } 62465c92b09SJames Bottomley 62565c92b09SJames Bottomley static void sas_port_create_link(struct sas_port *port, 62665c92b09SJames Bottomley struct sas_phy *phy) 62765c92b09SJames Bottomley { 62821434966SDarrick J. Wong int res; 62921434966SDarrick J. Wong 63021434966SDarrick J. Wong res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, 63121434966SDarrick J. Wong phy->dev.bus_id); 63221434966SDarrick J. Wong if (res) 63321434966SDarrick J. Wong goto err; 63421434966SDarrick J. Wong res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); 63521434966SDarrick J. Wong if (res) 63621434966SDarrick J. Wong goto err; 63721434966SDarrick J. Wong return; 63821434966SDarrick J. Wong err: 63921434966SDarrick J. Wong printk(KERN_ERR "%s: Cannot create port links, err=%d\n", 64021434966SDarrick J. Wong __FUNCTION__, res); 64165c92b09SJames Bottomley } 64265c92b09SJames Bottomley 64365c92b09SJames Bottomley static void sas_port_delete_link(struct sas_port *port, 64465c92b09SJames Bottomley struct sas_phy *phy) 64565c92b09SJames Bottomley { 64665c92b09SJames Bottomley sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id); 64765c92b09SJames Bottomley sysfs_remove_link(&phy->dev.kobj, "port"); 64865c92b09SJames Bottomley } 64965c92b09SJames Bottomley 65065c92b09SJames Bottomley /** sas_port_alloc - allocate and initialize a SAS port structure 65165c92b09SJames Bottomley * 65265c92b09SJames Bottomley * @parent: parent device 65365c92b09SJames Bottomley * @port_id: port number 65465c92b09SJames Bottomley * 65565c92b09SJames Bottomley * Allocates a SAS port structure. It will be added to the device tree 65665c92b09SJames Bottomley * below the device specified by @parent which must be either a Scsi_Host 65765c92b09SJames Bottomley * or a sas_expander_device. 65865c92b09SJames Bottomley * 65965c92b09SJames Bottomley * Returns %NULL on error 66065c92b09SJames Bottomley */ 66165c92b09SJames Bottomley struct sas_port *sas_port_alloc(struct device *parent, int port_id) 66265c92b09SJames Bottomley { 66365c92b09SJames Bottomley struct Scsi_Host *shost = dev_to_shost(parent); 66465c92b09SJames Bottomley struct sas_port *port; 66565c92b09SJames Bottomley 66665c92b09SJames Bottomley port = kzalloc(sizeof(*port), GFP_KERNEL); 66765c92b09SJames Bottomley if (!port) 66865c92b09SJames Bottomley return NULL; 66965c92b09SJames Bottomley 67065c92b09SJames Bottomley port->port_identifier = port_id; 67165c92b09SJames Bottomley 67265c92b09SJames Bottomley device_initialize(&port->dev); 67365c92b09SJames Bottomley 67465c92b09SJames Bottomley port->dev.parent = get_device(parent); 67565c92b09SJames Bottomley port->dev.release = sas_port_release; 67665c92b09SJames Bottomley 67765c92b09SJames Bottomley mutex_init(&port->phy_list_mutex); 67865c92b09SJames Bottomley INIT_LIST_HEAD(&port->phy_list); 67965c92b09SJames Bottomley 68065c92b09SJames Bottomley if (scsi_is_sas_expander_device(parent)) { 68165c92b09SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent); 68265c92b09SJames Bottomley sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no, 68365c92b09SJames Bottomley rphy->scsi_target_id, port->port_identifier); 68465c92b09SJames Bottomley } else 68565c92b09SJames Bottomley sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no, 68665c92b09SJames Bottomley port->port_identifier); 68765c92b09SJames Bottomley 68865c92b09SJames Bottomley transport_setup_device(&port->dev); 68965c92b09SJames Bottomley 69065c92b09SJames Bottomley return port; 69165c92b09SJames Bottomley } 69265c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_alloc); 69365c92b09SJames Bottomley 694c9fefeb2SJames Bottomley /** sas_port_alloc_num - allocate and initialize a SAS port structure 695c9fefeb2SJames Bottomley * 696c9fefeb2SJames Bottomley * @parent: parent device 697c9fefeb2SJames Bottomley * 698c9fefeb2SJames Bottomley * Allocates a SAS port structure and a number to go with it. This 699c9fefeb2SJames Bottomley * interface is really for adapters where the port number has no 700c9fefeb2SJames Bottomley * meansing, so the sas class should manage them. It will be added to 701c9fefeb2SJames Bottomley * the device tree below the device specified by @parent which must be 702c9fefeb2SJames Bottomley * either a Scsi_Host or a sas_expander_device. 703c9fefeb2SJames Bottomley * 704c9fefeb2SJames Bottomley * Returns %NULL on error 705c9fefeb2SJames Bottomley */ 706c9fefeb2SJames Bottomley struct sas_port *sas_port_alloc_num(struct device *parent) 707c9fefeb2SJames Bottomley { 708c9fefeb2SJames Bottomley int index; 709c9fefeb2SJames Bottomley struct Scsi_Host *shost = dev_to_shost(parent); 710c9fefeb2SJames Bottomley struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 711c9fefeb2SJames Bottomley 712c9fefeb2SJames Bottomley /* FIXME: use idr for this eventually */ 713c9fefeb2SJames Bottomley mutex_lock(&sas_host->lock); 714c9fefeb2SJames Bottomley if (scsi_is_sas_expander_device(parent)) { 715c9fefeb2SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent); 716c9fefeb2SJames Bottomley struct sas_expander_device *exp = rphy_to_expander_device(rphy); 717c9fefeb2SJames Bottomley 718c9fefeb2SJames Bottomley index = exp->next_port_id++; 719c9fefeb2SJames Bottomley } else 720c9fefeb2SJames Bottomley index = sas_host->next_port_id++; 721c9fefeb2SJames Bottomley mutex_unlock(&sas_host->lock); 722c9fefeb2SJames Bottomley return sas_port_alloc(parent, index); 723c9fefeb2SJames Bottomley } 724c9fefeb2SJames Bottomley EXPORT_SYMBOL(sas_port_alloc_num); 725c9fefeb2SJames Bottomley 72665c92b09SJames Bottomley /** 72765c92b09SJames Bottomley * sas_port_add - add a SAS port to the device hierarchy 72865c92b09SJames Bottomley * 72965c92b09SJames Bottomley * @port: port to be added 73065c92b09SJames Bottomley * 73165c92b09SJames Bottomley * publishes a port to the rest of the system 73265c92b09SJames Bottomley */ 73365c92b09SJames Bottomley int sas_port_add(struct sas_port *port) 73465c92b09SJames Bottomley { 73565c92b09SJames Bottomley int error; 73665c92b09SJames Bottomley 73765c92b09SJames Bottomley /* No phys should be added until this is made visible */ 73865c92b09SJames Bottomley BUG_ON(!list_empty(&port->phy_list)); 73965c92b09SJames Bottomley 74065c92b09SJames Bottomley error = device_add(&port->dev); 74165c92b09SJames Bottomley 74265c92b09SJames Bottomley if (error) 74365c92b09SJames Bottomley return error; 74465c92b09SJames Bottomley 74565c92b09SJames Bottomley transport_add_device(&port->dev); 74665c92b09SJames Bottomley transport_configure_device(&port->dev); 74765c92b09SJames Bottomley 74865c92b09SJames Bottomley return 0; 74965c92b09SJames Bottomley } 75065c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_add); 75165c92b09SJames Bottomley 75265c92b09SJames Bottomley /** 75365c92b09SJames Bottomley * sas_port_free -- free a SAS PORT 75465c92b09SJames Bottomley * @port: SAS PORT to free 75565c92b09SJames Bottomley * 75665c92b09SJames Bottomley * Frees the specified SAS PORT. 75765c92b09SJames Bottomley * 75865c92b09SJames Bottomley * Note: 75965c92b09SJames Bottomley * This function must only be called on a PORT that has not 76065c92b09SJames Bottomley * sucessfully been added using sas_port_add(). 76165c92b09SJames Bottomley */ 76265c92b09SJames Bottomley void sas_port_free(struct sas_port *port) 76365c92b09SJames Bottomley { 76465c92b09SJames Bottomley transport_destroy_device(&port->dev); 76565c92b09SJames Bottomley put_device(&port->dev); 76665c92b09SJames Bottomley } 76765c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_free); 76865c92b09SJames Bottomley 76965c92b09SJames Bottomley /** 77065c92b09SJames Bottomley * sas_port_delete -- remove SAS PORT 77165c92b09SJames Bottomley * @port: SAS PORT to remove 77265c92b09SJames Bottomley * 77365c92b09SJames Bottomley * Removes the specified SAS PORT. If the SAS PORT has an 77465c92b09SJames Bottomley * associated phys, unlink them from the port as well. 77565c92b09SJames Bottomley */ 77665c92b09SJames Bottomley void sas_port_delete(struct sas_port *port) 77765c92b09SJames Bottomley { 77865c92b09SJames Bottomley struct device *dev = &port->dev; 77965c92b09SJames Bottomley struct sas_phy *phy, *tmp_phy; 78065c92b09SJames Bottomley 78165c92b09SJames Bottomley if (port->rphy) { 78265c92b09SJames Bottomley sas_rphy_delete(port->rphy); 78365c92b09SJames Bottomley port->rphy = NULL; 78465c92b09SJames Bottomley } 78565c92b09SJames Bottomley 78665c92b09SJames Bottomley mutex_lock(&port->phy_list_mutex); 78765c92b09SJames Bottomley list_for_each_entry_safe(phy, tmp_phy, &port->phy_list, 78865c92b09SJames Bottomley port_siblings) { 78965c92b09SJames Bottomley sas_port_delete_link(port, phy); 79065c92b09SJames Bottomley list_del_init(&phy->port_siblings); 79165c92b09SJames Bottomley } 79265c92b09SJames Bottomley mutex_unlock(&port->phy_list_mutex); 79365c92b09SJames Bottomley 794a0e1b6efSJames Bottomley if (port->is_backlink) { 795a0e1b6efSJames Bottomley struct device *parent = port->dev.parent; 796a0e1b6efSJames Bottomley 797a0e1b6efSJames Bottomley sysfs_remove_link(&port->dev.kobj, parent->bus_id); 798a0e1b6efSJames Bottomley port->is_backlink = 0; 799a0e1b6efSJames Bottomley } 800a0e1b6efSJames Bottomley 80165c92b09SJames Bottomley transport_remove_device(dev); 80265c92b09SJames Bottomley device_del(dev); 80365c92b09SJames Bottomley transport_destroy_device(dev); 80465c92b09SJames Bottomley put_device(dev); 80565c92b09SJames Bottomley } 80665c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_delete); 80765c92b09SJames Bottomley 80865c92b09SJames Bottomley /** 80965c92b09SJames Bottomley * scsi_is_sas_port -- check if a struct device represents a SAS port 81065c92b09SJames Bottomley * @dev: device to check 81165c92b09SJames Bottomley * 81265c92b09SJames Bottomley * Returns: 81365c92b09SJames Bottomley * %1 if the device represents a SAS Port, %0 else 81465c92b09SJames Bottomley */ 81565c92b09SJames Bottomley int scsi_is_sas_port(const struct device *dev) 81665c92b09SJames Bottomley { 81765c92b09SJames Bottomley return dev->release == sas_port_release; 81865c92b09SJames Bottomley } 81965c92b09SJames Bottomley EXPORT_SYMBOL(scsi_is_sas_port); 82065c92b09SJames Bottomley 82165c92b09SJames Bottomley /** 82265c92b09SJames Bottomley * sas_port_add_phy - add another phy to a port to form a wide port 82365c92b09SJames Bottomley * @port: port to add the phy to 82465c92b09SJames Bottomley * @phy: phy to add 82565c92b09SJames Bottomley * 82665c92b09SJames Bottomley * When a port is initially created, it is empty (has no phys). All 82765c92b09SJames Bottomley * ports must have at least one phy to operated, and all wide ports 82865c92b09SJames Bottomley * must have at least two. The current code makes no difference 82965c92b09SJames Bottomley * between ports and wide ports, but the only object that can be 83065c92b09SJames Bottomley * connected to a remote device is a port, so ports must be formed on 83165c92b09SJames Bottomley * all devices with phys if they're connected to anything. 83265c92b09SJames Bottomley */ 83365c92b09SJames Bottomley void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) 83465c92b09SJames Bottomley { 83565c92b09SJames Bottomley mutex_lock(&port->phy_list_mutex); 83665c92b09SJames Bottomley if (unlikely(!list_empty(&phy->port_siblings))) { 83765c92b09SJames Bottomley /* make sure we're already on this port */ 83865c92b09SJames Bottomley struct sas_phy *tmp; 83965c92b09SJames Bottomley 84065c92b09SJames Bottomley list_for_each_entry(tmp, &port->phy_list, port_siblings) 84165c92b09SJames Bottomley if (tmp == phy) 84265c92b09SJames Bottomley break; 84365c92b09SJames Bottomley /* If this trips, you added a phy that was already 84465c92b09SJames Bottomley * part of a different port */ 84565c92b09SJames Bottomley if (unlikely(tmp != phy)) { 84665c92b09SJames 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); 84765c92b09SJames Bottomley BUG(); 84865c92b09SJames Bottomley } 84965c92b09SJames Bottomley } else { 85065c92b09SJames Bottomley sas_port_create_link(port, phy); 85165c92b09SJames Bottomley list_add_tail(&phy->port_siblings, &port->phy_list); 85265c92b09SJames Bottomley port->num_phys++; 85365c92b09SJames Bottomley } 85465c92b09SJames Bottomley mutex_unlock(&port->phy_list_mutex); 85565c92b09SJames Bottomley } 85665c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_add_phy); 85765c92b09SJames Bottomley 85865c92b09SJames Bottomley /** 85965c92b09SJames Bottomley * sas_port_delete_phy - remove a phy from a port or wide port 86065c92b09SJames Bottomley * @port: port to remove the phy from 86165c92b09SJames Bottomley * @phy: phy to remove 86265c92b09SJames Bottomley * 86365c92b09SJames Bottomley * This operation is used for tearing down ports again. It must be 86465c92b09SJames Bottomley * done to every port or wide port before calling sas_port_delete. 86565c92b09SJames Bottomley */ 86665c92b09SJames Bottomley void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy) 86765c92b09SJames Bottomley { 86865c92b09SJames Bottomley mutex_lock(&port->phy_list_mutex); 86965c92b09SJames Bottomley sas_port_delete_link(port, phy); 87065c92b09SJames Bottomley list_del_init(&phy->port_siblings); 87165c92b09SJames Bottomley port->num_phys--; 87265c92b09SJames Bottomley mutex_unlock(&port->phy_list_mutex); 87365c92b09SJames Bottomley } 87465c92b09SJames Bottomley EXPORT_SYMBOL(sas_port_delete_phy); 87565c92b09SJames Bottomley 876a0e1b6efSJames Bottomley void sas_port_mark_backlink(struct sas_port *port) 877a0e1b6efSJames Bottomley { 87821434966SDarrick J. Wong int res; 879a0e1b6efSJames Bottomley struct device *parent = port->dev.parent->parent->parent; 880a0e1b6efSJames Bottomley 881a0e1b6efSJames Bottomley if (port->is_backlink) 882a0e1b6efSJames Bottomley return; 883a0e1b6efSJames Bottomley port->is_backlink = 1; 88421434966SDarrick J. Wong res = sysfs_create_link(&port->dev.kobj, &parent->kobj, 885a0e1b6efSJames Bottomley parent->bus_id); 88621434966SDarrick J. Wong if (res) 88721434966SDarrick J. Wong goto err; 88821434966SDarrick J. Wong return; 88921434966SDarrick J. Wong err: 89021434966SDarrick J. Wong printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n", 89121434966SDarrick J. Wong __FUNCTION__, res); 892a0e1b6efSJames Bottomley 893a0e1b6efSJames Bottomley } 894a0e1b6efSJames Bottomley EXPORT_SYMBOL(sas_port_mark_backlink); 895a0e1b6efSJames Bottomley 89665c92b09SJames Bottomley /* 897c7ebbbceSChristoph Hellwig * SAS remote PHY attributes. 898c7ebbbceSChristoph Hellwig */ 899c7ebbbceSChristoph Hellwig 900c7ebbbceSChristoph Hellwig #define sas_rphy_show_simple(field, name, format_string, cast) \ 901c7ebbbceSChristoph Hellwig static ssize_t \ 902c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 903c7ebbbceSChristoph Hellwig { \ 904c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 905c7ebbbceSChristoph Hellwig \ 906c7ebbbceSChristoph Hellwig return snprintf(buf, 20, format_string, cast rphy->field); \ 907c7ebbbceSChristoph Hellwig } 908c7ebbbceSChristoph Hellwig 909c7ebbbceSChristoph Hellwig #define sas_rphy_simple_attr(field, name, format_string, type) \ 910c7ebbbceSChristoph Hellwig sas_rphy_show_simple(field, name, format_string, (type)) \ 911c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 912c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 913c7ebbbceSChristoph Hellwig 914c7ebbbceSChristoph Hellwig #define sas_rphy_show_protocol(field, name) \ 915c7ebbbceSChristoph Hellwig static ssize_t \ 916c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 917c7ebbbceSChristoph Hellwig { \ 918c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 919c7ebbbceSChristoph Hellwig \ 920c7ebbbceSChristoph Hellwig if (!rphy->field) \ 921c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); \ 922c7ebbbceSChristoph Hellwig return get_sas_protocol_names(rphy->field, buf); \ 923c7ebbbceSChristoph Hellwig } 924c7ebbbceSChristoph Hellwig 925c7ebbbceSChristoph Hellwig #define sas_rphy_protocol_attr(field, name) \ 926c7ebbbceSChristoph Hellwig sas_rphy_show_protocol(field, name) \ 927c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 928c7ebbbceSChristoph Hellwig show_sas_rphy_##name, NULL) 929c7ebbbceSChristoph Hellwig 930c7ebbbceSChristoph Hellwig static ssize_t 931c7ebbbceSChristoph Hellwig show_sas_rphy_device_type(struct class_device *cdev, char *buf) 932c7ebbbceSChristoph Hellwig { 933c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 934c7ebbbceSChristoph Hellwig 935c7ebbbceSChristoph Hellwig if (!rphy->identify.device_type) 936c7ebbbceSChristoph Hellwig return snprintf(buf, 20, "none\n"); 937c7ebbbceSChristoph Hellwig return get_sas_device_type_names( 938c7ebbbceSChristoph Hellwig rphy->identify.device_type, buf); 939c7ebbbceSChristoph Hellwig } 940c7ebbbceSChristoph Hellwig 941c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 942c7ebbbceSChristoph Hellwig show_sas_rphy_device_type, NULL); 943c7ebbbceSChristoph Hellwig 944a0125641SChristoph Hellwig static ssize_t 945a0125641SChristoph Hellwig show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf) 946a0125641SChristoph Hellwig { 947a0125641SChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 948a0125641SChristoph Hellwig struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 949a0125641SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 950a0125641SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 951a0125641SChristoph Hellwig u64 identifier; 952a0125641SChristoph Hellwig int error; 953a0125641SChristoph Hellwig 954a0125641SChristoph Hellwig /* 955a0125641SChristoph Hellwig * Only devices behind an expander are supported, because the 956a0125641SChristoph Hellwig * enclosure identifier is a SMP feature. 957a0125641SChristoph Hellwig */ 958f4ad7b58SJames Bottomley if (scsi_is_sas_phy_local(phy)) 959a0125641SChristoph Hellwig return -EINVAL; 960a0125641SChristoph Hellwig 961a0125641SChristoph Hellwig error = i->f->get_enclosure_identifier(rphy, &identifier); 962a0125641SChristoph Hellwig if (error) 963a0125641SChristoph Hellwig return error; 964a0125641SChristoph Hellwig return sprintf(buf, "0x%llx\n", (unsigned long long)identifier); 965a0125641SChristoph Hellwig } 966a0125641SChristoph Hellwig 967a0125641SChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO, 968a0125641SChristoph Hellwig show_sas_rphy_enclosure_identifier, NULL); 969a0125641SChristoph Hellwig 970a0125641SChristoph Hellwig static ssize_t 971a0125641SChristoph Hellwig show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf) 972a0125641SChristoph Hellwig { 973a0125641SChristoph Hellwig struct sas_rphy *rphy = transport_class_to_rphy(cdev); 974a0125641SChristoph Hellwig struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 975a0125641SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 976a0125641SChristoph Hellwig struct sas_internal *i = to_sas_internal(shost->transportt); 977a0125641SChristoph Hellwig int val; 978a0125641SChristoph Hellwig 979f4ad7b58SJames Bottomley if (scsi_is_sas_phy_local(phy)) 980a0125641SChristoph Hellwig return -EINVAL; 981a0125641SChristoph Hellwig 982a0125641SChristoph Hellwig val = i->f->get_bay_identifier(rphy); 983a0125641SChristoph Hellwig if (val < 0) 984a0125641SChristoph Hellwig return val; 985a0125641SChristoph Hellwig return sprintf(buf, "%d\n", val); 986a0125641SChristoph Hellwig } 987a0125641SChristoph Hellwig 988a0125641SChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO, 989a0125641SChristoph Hellwig show_sas_rphy_bay_identifier, NULL); 990a0125641SChristoph Hellwig 991c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.initiator_port_protocols, 992c7ebbbceSChristoph Hellwig initiator_port_protocols); 993c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 994c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 995c7ebbbceSChristoph Hellwig unsigned long long); 996c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 997c7ebbbceSChristoph Hellwig 99842ab0360SJames Bottomley /* only need 8 bytes of data plus header (4 or 8) */ 99942ab0360SJames Bottomley #define BUF_SIZE 64 100042ab0360SJames Bottomley 100142ab0360SJames Bottomley int sas_read_port_mode_page(struct scsi_device *sdev) 100242ab0360SJames Bottomley { 100342ab0360SJames Bottomley char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; 100442ab0360SJames Bottomley struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); 100542ab0360SJames Bottomley struct sas_end_device *rdev; 100642ab0360SJames Bottomley struct scsi_mode_data mode_data; 100742ab0360SJames Bottomley int res, error; 100842ab0360SJames Bottomley 100942ab0360SJames Bottomley BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); 101042ab0360SJames Bottomley 101142ab0360SJames Bottomley rdev = rphy_to_end_device(rphy); 101242ab0360SJames Bottomley 101342ab0360SJames Bottomley if (!buffer) 101442ab0360SJames Bottomley return -ENOMEM; 101542ab0360SJames Bottomley 101642ab0360SJames Bottomley res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3, 101742ab0360SJames Bottomley &mode_data, NULL); 101842ab0360SJames Bottomley 101942ab0360SJames Bottomley error = -EINVAL; 102042ab0360SJames Bottomley if (!scsi_status_is_good(res)) 102142ab0360SJames Bottomley goto out; 102242ab0360SJames Bottomley 102342ab0360SJames Bottomley msdata = buffer + mode_data.header_length + 102442ab0360SJames Bottomley mode_data.block_descriptor_length; 102542ab0360SJames Bottomley 102642ab0360SJames Bottomley if (msdata - buffer > BUF_SIZE - 8) 102742ab0360SJames Bottomley goto out; 102842ab0360SJames Bottomley 102942ab0360SJames Bottomley error = 0; 103042ab0360SJames Bottomley 103142ab0360SJames Bottomley rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0; 103242ab0360SJames Bottomley rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5]; 103342ab0360SJames Bottomley rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7]; 103442ab0360SJames Bottomley 103542ab0360SJames Bottomley out: 103642ab0360SJames Bottomley kfree(buffer); 103742ab0360SJames Bottomley return error; 103842ab0360SJames Bottomley } 103942ab0360SJames Bottomley EXPORT_SYMBOL(sas_read_port_mode_page); 104042ab0360SJames Bottomley 104179cb1819SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_end_dev_class, 104279cb1819SJames Bottomley "sas_end_device", NULL, NULL, NULL); 104379cb1819SJames Bottomley 104442ab0360SJames Bottomley #define sas_end_dev_show_simple(field, name, format_string, cast) \ 104542ab0360SJames Bottomley static ssize_t \ 104642ab0360SJames Bottomley show_sas_end_dev_##name(struct class_device *cdev, char *buf) \ 104742ab0360SJames Bottomley { \ 104842ab0360SJames Bottomley struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 104942ab0360SJames Bottomley struct sas_end_device *rdev = rphy_to_end_device(rphy); \ 105042ab0360SJames Bottomley \ 105142ab0360SJames Bottomley return snprintf(buf, 20, format_string, cast rdev->field); \ 105242ab0360SJames Bottomley } 105342ab0360SJames Bottomley 105442ab0360SJames Bottomley #define sas_end_dev_simple_attr(field, name, format_string, type) \ 105542ab0360SJames Bottomley sas_end_dev_show_simple(field, name, format_string, (type)) \ 105642ab0360SJames Bottomley static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, \ 105742ab0360SJames Bottomley show_sas_end_dev_##name, NULL) 105842ab0360SJames Bottomley 105942ab0360SJames Bottomley sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int); 106042ab0360SJames Bottomley sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, 106142ab0360SJames Bottomley "%d\n", int); 106242ab0360SJames Bottomley sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, 106342ab0360SJames Bottomley "%d\n", int); 106442ab0360SJames Bottomley 106579cb1819SJames Bottomley static DECLARE_TRANSPORT_CLASS(sas_expander_class, 106679cb1819SJames Bottomley "sas_expander", NULL, NULL, NULL); 106779cb1819SJames Bottomley 106879cb1819SJames Bottomley #define sas_expander_show_simple(field, name, format_string, cast) \ 106979cb1819SJames Bottomley static ssize_t \ 107079cb1819SJames Bottomley show_sas_expander_##name(struct class_device *cdev, char *buf) \ 107179cb1819SJames Bottomley { \ 107279cb1819SJames Bottomley struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 107379cb1819SJames Bottomley struct sas_expander_device *edev = rphy_to_expander_device(rphy); \ 107479cb1819SJames Bottomley \ 107579cb1819SJames Bottomley return snprintf(buf, 20, format_string, cast edev->field); \ 107679cb1819SJames Bottomley } 107779cb1819SJames Bottomley 107879cb1819SJames Bottomley #define sas_expander_simple_attr(field, name, format_string, type) \ 107979cb1819SJames Bottomley sas_expander_show_simple(field, name, format_string, (type)) \ 108079cb1819SJames Bottomley static SAS_CLASS_DEVICE_ATTR(expander, name, S_IRUGO, \ 108179cb1819SJames Bottomley show_sas_expander_##name, NULL) 108279cb1819SJames Bottomley 108379cb1819SJames Bottomley sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *); 108479cb1819SJames Bottomley sas_expander_simple_attr(product_id, product_id, "%s\n", char *); 108579cb1819SJames Bottomley sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *); 108679cb1819SJames Bottomley sas_expander_simple_attr(component_vendor_id, component_vendor_id, 108779cb1819SJames Bottomley "%s\n", char *); 108879cb1819SJames Bottomley sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int); 108979cb1819SJames Bottomley sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n", 109079cb1819SJames Bottomley unsigned int); 109179cb1819SJames Bottomley sas_expander_simple_attr(level, level, "%d\n", int); 109242ab0360SJames Bottomley 1093c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 10942f8600dfSJames Bottomley "sas_device", NULL, NULL, NULL); 1095c7ebbbceSChristoph Hellwig 1096c7ebbbceSChristoph Hellwig static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 1097c7ebbbceSChristoph Hellwig { 1098c7ebbbceSChristoph Hellwig struct Scsi_Host *shost; 1099c7ebbbceSChristoph Hellwig struct sas_internal *i; 1100c7ebbbceSChristoph Hellwig 1101c7ebbbceSChristoph Hellwig if (!scsi_is_sas_rphy(dev)) 1102c7ebbbceSChristoph Hellwig return 0; 1103c7ebbbceSChristoph Hellwig shost = dev_to_shost(dev->parent->parent); 1104c7ebbbceSChristoph Hellwig 1105c7ebbbceSChristoph Hellwig if (!shost->transportt) 1106c7ebbbceSChristoph Hellwig return 0; 1107c7ebbbceSChristoph Hellwig if (shost->transportt->host_attrs.ac.class != 1108c7ebbbceSChristoph Hellwig &sas_host_class.class) 1109c7ebbbceSChristoph Hellwig return 0; 1110c7ebbbceSChristoph Hellwig 1111c7ebbbceSChristoph Hellwig i = to_sas_internal(shost->transportt); 1112c7ebbbceSChristoph Hellwig return &i->rphy_attr_cont.ac == cont; 1113c7ebbbceSChristoph Hellwig } 1114c7ebbbceSChristoph Hellwig 111542ab0360SJames Bottomley static int sas_end_dev_match(struct attribute_container *cont, 111642ab0360SJames Bottomley struct device *dev) 111742ab0360SJames Bottomley { 111842ab0360SJames Bottomley struct Scsi_Host *shost; 111942ab0360SJames Bottomley struct sas_internal *i; 112042ab0360SJames Bottomley struct sas_rphy *rphy; 112142ab0360SJames Bottomley 112242ab0360SJames Bottomley if (!scsi_is_sas_rphy(dev)) 112342ab0360SJames Bottomley return 0; 112442ab0360SJames Bottomley shost = dev_to_shost(dev->parent->parent); 112542ab0360SJames Bottomley rphy = dev_to_rphy(dev); 112642ab0360SJames Bottomley 112742ab0360SJames Bottomley if (!shost->transportt) 112842ab0360SJames Bottomley return 0; 112942ab0360SJames Bottomley if (shost->transportt->host_attrs.ac.class != 113042ab0360SJames Bottomley &sas_host_class.class) 113142ab0360SJames Bottomley return 0; 113242ab0360SJames Bottomley 113342ab0360SJames Bottomley i = to_sas_internal(shost->transportt); 113442ab0360SJames Bottomley return &i->end_dev_attr_cont.ac == cont && 11352f8600dfSJames Bottomley rphy->identify.device_type == SAS_END_DEVICE; 113642ab0360SJames Bottomley } 113742ab0360SJames Bottomley 113879cb1819SJames Bottomley static int sas_expander_match(struct attribute_container *cont, 113979cb1819SJames Bottomley struct device *dev) 114079cb1819SJames Bottomley { 114179cb1819SJames Bottomley struct Scsi_Host *shost; 114279cb1819SJames Bottomley struct sas_internal *i; 114379cb1819SJames Bottomley struct sas_rphy *rphy; 114479cb1819SJames Bottomley 114579cb1819SJames Bottomley if (!scsi_is_sas_rphy(dev)) 114679cb1819SJames Bottomley return 0; 114779cb1819SJames Bottomley shost = dev_to_shost(dev->parent->parent); 114879cb1819SJames Bottomley rphy = dev_to_rphy(dev); 114979cb1819SJames Bottomley 115079cb1819SJames Bottomley if (!shost->transportt) 115179cb1819SJames Bottomley return 0; 115279cb1819SJames Bottomley if (shost->transportt->host_attrs.ac.class != 115379cb1819SJames Bottomley &sas_host_class.class) 115479cb1819SJames Bottomley return 0; 115579cb1819SJames Bottomley 115679cb1819SJames Bottomley i = to_sas_internal(shost->transportt); 115779cb1819SJames Bottomley return &i->expander_attr_cont.ac == cont && 115879cb1819SJames Bottomley (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE || 11592f8600dfSJames Bottomley rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE); 116079cb1819SJames Bottomley } 116179cb1819SJames Bottomley 11622f8600dfSJames Bottomley static void sas_expander_release(struct device *dev) 1163c7ebbbceSChristoph Hellwig { 1164c7ebbbceSChristoph Hellwig struct sas_rphy *rphy = dev_to_rphy(dev); 11652f8600dfSJames Bottomley struct sas_expander_device *edev = rphy_to_expander_device(rphy); 1166c7ebbbceSChristoph Hellwig 1167c7ebbbceSChristoph Hellwig put_device(dev->parent); 11682f8600dfSJames Bottomley kfree(edev); 1169c7ebbbceSChristoph Hellwig } 1170c7ebbbceSChristoph Hellwig 11712f8600dfSJames Bottomley static void sas_end_device_release(struct device *dev) 1172c7ebbbceSChristoph Hellwig { 11732f8600dfSJames Bottomley struct sas_rphy *rphy = dev_to_rphy(dev); 11742f8600dfSJames Bottomley struct sas_end_device *edev = rphy_to_end_device(rphy); 1175c7ebbbceSChristoph Hellwig 11762f8600dfSJames Bottomley put_device(dev->parent); 11772f8600dfSJames Bottomley kfree(edev); 1178c7ebbbceSChristoph Hellwig } 1179c7ebbbceSChristoph Hellwig 1180c7ebbbceSChristoph Hellwig /** 1181c5943d36SJames Bottomley * sas_rphy_initialize - common rphy intialization 1182c5943d36SJames Bottomley * @rphy: rphy to initialise 1183c5943d36SJames Bottomley * 1184c5943d36SJames Bottomley * Used by both sas_end_device_alloc() and sas_expander_alloc() to 1185c5943d36SJames Bottomley * initialise the common rphy component of each. 1186c5943d36SJames Bottomley */ 1187c5943d36SJames Bottomley static void sas_rphy_initialize(struct sas_rphy *rphy) 1188c5943d36SJames Bottomley { 1189c5943d36SJames Bottomley INIT_LIST_HEAD(&rphy->list); 1190c5943d36SJames Bottomley } 1191c5943d36SJames Bottomley 1192c5943d36SJames Bottomley /** 119342ab0360SJames Bottomley * sas_end_device_alloc - allocate an rphy for an end device 119442ab0360SJames Bottomley * 119542ab0360SJames Bottomley * Allocates an SAS remote PHY structure, connected to @parent. 119642ab0360SJames Bottomley * 119742ab0360SJames Bottomley * Returns: 119842ab0360SJames Bottomley * SAS PHY allocated or %NULL if the allocation failed. 119942ab0360SJames Bottomley */ 120065c92b09SJames Bottomley struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) 120142ab0360SJames Bottomley { 120242ab0360SJames Bottomley struct Scsi_Host *shost = dev_to_shost(&parent->dev); 120342ab0360SJames Bottomley struct sas_end_device *rdev; 120442ab0360SJames Bottomley 120542ab0360SJames Bottomley rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 120642ab0360SJames Bottomley if (!rdev) { 120742ab0360SJames Bottomley return NULL; 120842ab0360SJames Bottomley } 120942ab0360SJames Bottomley 121042ab0360SJames Bottomley device_initialize(&rdev->rphy.dev); 121142ab0360SJames Bottomley rdev->rphy.dev.parent = get_device(&parent->dev); 12122f8600dfSJames Bottomley rdev->rphy.dev.release = sas_end_device_release; 121365c92b09SJames Bottomley if (scsi_is_sas_expander_device(parent->dev.parent)) { 121465c92b09SJames Bottomley struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); 121565c92b09SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d", 121665c92b09SJames Bottomley shost->host_no, rphy->scsi_target_id, parent->port_identifier); 121765c92b09SJames Bottomley } else 121865c92b09SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d", 121965c92b09SJames Bottomley shost->host_no, parent->port_identifier); 122042ab0360SJames Bottomley rdev->rphy.identify.device_type = SAS_END_DEVICE; 1221c5943d36SJames Bottomley sas_rphy_initialize(&rdev->rphy); 122242ab0360SJames Bottomley transport_setup_device(&rdev->rphy.dev); 122342ab0360SJames Bottomley 122442ab0360SJames Bottomley return &rdev->rphy; 122542ab0360SJames Bottomley } 122642ab0360SJames Bottomley EXPORT_SYMBOL(sas_end_device_alloc); 122742ab0360SJames Bottomley 122879cb1819SJames Bottomley /** 122979cb1819SJames Bottomley * sas_expander_alloc - allocate an rphy for an end device 123079cb1819SJames Bottomley * 123179cb1819SJames Bottomley * Allocates an SAS remote PHY structure, connected to @parent. 123279cb1819SJames Bottomley * 123379cb1819SJames Bottomley * Returns: 123479cb1819SJames Bottomley * SAS PHY allocated or %NULL if the allocation failed. 123579cb1819SJames Bottomley */ 123665c92b09SJames Bottomley struct sas_rphy *sas_expander_alloc(struct sas_port *parent, 123779cb1819SJames Bottomley enum sas_device_type type) 123879cb1819SJames Bottomley { 123979cb1819SJames Bottomley struct Scsi_Host *shost = dev_to_shost(&parent->dev); 124079cb1819SJames Bottomley struct sas_expander_device *rdev; 124179cb1819SJames Bottomley struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 124279cb1819SJames Bottomley 124379cb1819SJames Bottomley BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE && 124479cb1819SJames Bottomley type != SAS_FANOUT_EXPANDER_DEVICE); 124579cb1819SJames Bottomley 124679cb1819SJames Bottomley rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 124779cb1819SJames Bottomley if (!rdev) { 124879cb1819SJames Bottomley return NULL; 124979cb1819SJames Bottomley } 125079cb1819SJames Bottomley 125179cb1819SJames Bottomley device_initialize(&rdev->rphy.dev); 125279cb1819SJames Bottomley rdev->rphy.dev.parent = get_device(&parent->dev); 12532f8600dfSJames Bottomley rdev->rphy.dev.release = sas_expander_release; 125479cb1819SJames Bottomley mutex_lock(&sas_host->lock); 125579cb1819SJames Bottomley rdev->rphy.scsi_target_id = sas_host->next_expander_id++; 125679cb1819SJames Bottomley mutex_unlock(&sas_host->lock); 125779cb1819SJames Bottomley sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d", 125879cb1819SJames Bottomley shost->host_no, rdev->rphy.scsi_target_id); 125979cb1819SJames Bottomley rdev->rphy.identify.device_type = type; 1260c5943d36SJames Bottomley sas_rphy_initialize(&rdev->rphy); 126179cb1819SJames Bottomley transport_setup_device(&rdev->rphy.dev); 126279cb1819SJames Bottomley 126379cb1819SJames Bottomley return &rdev->rphy; 126479cb1819SJames Bottomley } 126579cb1819SJames Bottomley EXPORT_SYMBOL(sas_expander_alloc); 126642ab0360SJames Bottomley 126742ab0360SJames Bottomley /** 1268c7ebbbceSChristoph Hellwig * sas_rphy_add -- add a SAS remote PHY to the device hierachy 1269c7ebbbceSChristoph Hellwig * @rphy: The remote PHY to be added 1270c7ebbbceSChristoph Hellwig * 1271c7ebbbceSChristoph Hellwig * Publishes a SAS remote PHY to the rest of the system. 1272c7ebbbceSChristoph Hellwig */ 1273c7ebbbceSChristoph Hellwig int sas_rphy_add(struct sas_rphy *rphy) 1274c7ebbbceSChristoph Hellwig { 127565c92b09SJames Bottomley struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); 1276c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 1277c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1278c7ebbbceSChristoph Hellwig struct sas_identify *identify = &rphy->identify; 1279c7ebbbceSChristoph Hellwig int error; 1280c7ebbbceSChristoph Hellwig 1281c7ebbbceSChristoph Hellwig if (parent->rphy) 1282c7ebbbceSChristoph Hellwig return -ENXIO; 1283c7ebbbceSChristoph Hellwig parent->rphy = rphy; 1284c7ebbbceSChristoph Hellwig 1285c7ebbbceSChristoph Hellwig error = device_add(&rphy->dev); 1286c7ebbbceSChristoph Hellwig if (error) 1287c7ebbbceSChristoph Hellwig return error; 1288c7ebbbceSChristoph Hellwig transport_add_device(&rphy->dev); 1289c7ebbbceSChristoph Hellwig transport_configure_device(&rphy->dev); 1290c7ebbbceSChristoph Hellwig 1291e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1292c7ebbbceSChristoph Hellwig list_add_tail(&rphy->list, &sas_host->rphy_list); 1293c7ebbbceSChristoph Hellwig if (identify->device_type == SAS_END_DEVICE && 1294c7ebbbceSChristoph Hellwig (identify->target_port_protocols & 1295c7ebbbceSChristoph Hellwig (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 1296c7ebbbceSChristoph Hellwig rphy->scsi_target_id = sas_host->next_target_id++; 12977676f83aSJames Bottomley else if (identify->device_type == SAS_END_DEVICE) 12987676f83aSJames Bottomley rphy->scsi_target_id = -1; 1299e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1300c7ebbbceSChristoph Hellwig 130179cb1819SJames Bottomley if (identify->device_type == SAS_END_DEVICE && 130279cb1819SJames Bottomley rphy->scsi_target_id != -1) { 1303e8bf3941SJames Bottomley scsi_scan_target(&rphy->dev, 0, 1304c8490f3aSDarrick J. Wong rphy->scsi_target_id, SCAN_WILD_CARD, 0); 1305c7ebbbceSChristoph Hellwig } 1306c7ebbbceSChristoph Hellwig 1307c7ebbbceSChristoph Hellwig return 0; 1308c7ebbbceSChristoph Hellwig } 1309c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_add); 1310c7ebbbceSChristoph Hellwig 1311c7ebbbceSChristoph Hellwig /** 1312c7ebbbceSChristoph Hellwig * sas_rphy_free -- free a SAS remote PHY 1313c7ebbbceSChristoph Hellwig * @rphy SAS remote PHY to free 1314c7ebbbceSChristoph Hellwig * 1315c7ebbbceSChristoph Hellwig * Frees the specified SAS remote PHY. 1316c7ebbbceSChristoph Hellwig * 1317c7ebbbceSChristoph Hellwig * Note: 1318c7ebbbceSChristoph Hellwig * This function must only be called on a remote 1319c7ebbbceSChristoph Hellwig * PHY that has not sucessfully been added using 13206f63caaeSDarrick J. Wong * sas_rphy_add() (or has been sas_rphy_remove()'d) 1321c7ebbbceSChristoph Hellwig */ 1322c7ebbbceSChristoph Hellwig void sas_rphy_free(struct sas_rphy *rphy) 1323c7ebbbceSChristoph Hellwig { 132492aab646SMike Anderson struct device *dev = &rphy->dev; 1325c7ebbbceSChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 1326c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1327c7ebbbceSChristoph Hellwig 1328e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1329c7ebbbceSChristoph Hellwig list_del(&rphy->list); 1330e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1331c7ebbbceSChristoph Hellwig 133292aab646SMike Anderson transport_destroy_device(dev); 13332f8600dfSJames Bottomley 133492aab646SMike Anderson put_device(dev); 1335c7ebbbceSChristoph Hellwig } 1336c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_free); 1337c7ebbbceSChristoph Hellwig 1338c7ebbbceSChristoph Hellwig /** 13396f63caaeSDarrick J. Wong * sas_rphy_delete -- remove and free SAS remote PHY 13406f63caaeSDarrick J. Wong * @rphy: SAS remote PHY to remove and free 1341c7ebbbceSChristoph Hellwig * 13426f63caaeSDarrick J. Wong * Removes the specified SAS remote PHY and frees it. 1343c7ebbbceSChristoph Hellwig */ 1344c7ebbbceSChristoph Hellwig void 1345c7ebbbceSChristoph Hellwig sas_rphy_delete(struct sas_rphy *rphy) 1346c7ebbbceSChristoph Hellwig { 13476f63caaeSDarrick J. Wong sas_rphy_remove(rphy); 13486f63caaeSDarrick J. Wong sas_rphy_free(rphy); 13496f63caaeSDarrick J. Wong } 13506f63caaeSDarrick J. Wong EXPORT_SYMBOL(sas_rphy_delete); 13516f63caaeSDarrick J. Wong 13526f63caaeSDarrick J. Wong /** 13536f63caaeSDarrick J. Wong * sas_rphy_remove -- remove SAS remote PHY 13546f63caaeSDarrick J. Wong * @rphy: SAS remote phy to remove 13556f63caaeSDarrick J. Wong * 13566f63caaeSDarrick J. Wong * Removes the specified SAS remote PHY. 13576f63caaeSDarrick J. Wong */ 13586f63caaeSDarrick J. Wong void 13596f63caaeSDarrick J. Wong sas_rphy_remove(struct sas_rphy *rphy) 13606f63caaeSDarrick J. Wong { 1361c7ebbbceSChristoph Hellwig struct device *dev = &rphy->dev; 136265c92b09SJames Bottomley struct sas_port *parent = dev_to_sas_port(dev->parent); 1363c7ebbbceSChristoph Hellwig 1364d4054239SChristoph Hellwig switch (rphy->identify.device_type) { 1365d4054239SChristoph Hellwig case SAS_END_DEVICE: 1366fe8b2304SChristoph Hellwig scsi_remove_target(dev); 1367d4054239SChristoph Hellwig break; 1368d4054239SChristoph Hellwig case SAS_EDGE_EXPANDER_DEVICE: 1369d4054239SChristoph Hellwig case SAS_FANOUT_EXPANDER_DEVICE: 137065c92b09SJames Bottomley sas_remove_children(dev); 1371d4054239SChristoph Hellwig break; 1372d4054239SChristoph Hellwig default: 1373d4054239SChristoph Hellwig break; 1374d4054239SChristoph Hellwig } 1375c7ebbbceSChristoph Hellwig 1376fe8b2304SChristoph Hellwig transport_remove_device(dev); 1377fe8b2304SChristoph Hellwig device_del(dev); 1378c7ebbbceSChristoph Hellwig 137933b114e9SChristoph Hellwig parent->rphy = NULL; 1380c7ebbbceSChristoph Hellwig } 13816f63caaeSDarrick J. Wong EXPORT_SYMBOL(sas_rphy_remove); 1382c7ebbbceSChristoph Hellwig 1383c7ebbbceSChristoph Hellwig /** 1384c7ebbbceSChristoph Hellwig * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 1385c7ebbbceSChristoph Hellwig * @dev: device to check 1386c7ebbbceSChristoph Hellwig * 1387c7ebbbceSChristoph Hellwig * Returns: 1388c7ebbbceSChristoph Hellwig * %1 if the device represents a SAS remote PHY, %0 else 1389c7ebbbceSChristoph Hellwig */ 1390c7ebbbceSChristoph Hellwig int scsi_is_sas_rphy(const struct device *dev) 1391c7ebbbceSChristoph Hellwig { 13922f8600dfSJames Bottomley return dev->release == sas_end_device_release || 13932f8600dfSJames Bottomley dev->release == sas_expander_release; 1394c7ebbbceSChristoph Hellwig } 1395c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_rphy); 1396c7ebbbceSChristoph Hellwig 1397c7ebbbceSChristoph Hellwig 1398c7ebbbceSChristoph Hellwig /* 1399c7ebbbceSChristoph Hellwig * SCSI scan helper 1400c7ebbbceSChristoph Hellwig */ 1401c7ebbbceSChristoph Hellwig 1402e02f3f59SChristoph Hellwig static int sas_user_scan(struct Scsi_Host *shost, uint channel, 1403e02f3f59SChristoph Hellwig uint id, uint lun) 1404c7ebbbceSChristoph Hellwig { 1405c7ebbbceSChristoph Hellwig struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1406c7ebbbceSChristoph Hellwig struct sas_rphy *rphy; 1407c7ebbbceSChristoph Hellwig 1408e02f3f59SChristoph Hellwig mutex_lock(&sas_host->lock); 1409c7ebbbceSChristoph Hellwig list_for_each_entry(rphy, &sas_host->rphy_list, list) { 14106d99a3f3SJames Bottomley if (rphy->identify.device_type != SAS_END_DEVICE || 14116d99a3f3SJames Bottomley rphy->scsi_target_id == -1) 1412e02f3f59SChristoph Hellwig continue; 1413e02f3f59SChristoph Hellwig 1414e8bf3941SJames Bottomley if ((channel == SCAN_WILD_CARD || channel == 0) && 1415e02f3f59SChristoph Hellwig (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 1416e8bf3941SJames Bottomley scsi_scan_target(&rphy->dev, 0, 1417e02f3f59SChristoph Hellwig rphy->scsi_target_id, lun, 1); 1418e02f3f59SChristoph Hellwig } 1419e02f3f59SChristoph Hellwig } 1420e02f3f59SChristoph Hellwig mutex_unlock(&sas_host->lock); 1421e02f3f59SChristoph Hellwig 1422e02f3f59SChristoph Hellwig return 0; 1423c7ebbbceSChristoph Hellwig } 1424c7ebbbceSChristoph Hellwig 1425c7ebbbceSChristoph Hellwig 1426c7ebbbceSChristoph Hellwig /* 1427c7ebbbceSChristoph Hellwig * Setup / Teardown code 1428c7ebbbceSChristoph Hellwig */ 1429c7ebbbceSChristoph Hellwig 143042ab0360SJames Bottomley #define SETUP_TEMPLATE(attrb, field, perm, test) \ 143142ab0360SJames Bottomley i->private_##attrb[count] = class_device_attr_##field; \ 143242ab0360SJames Bottomley i->private_##attrb[count].attr.mode = perm; \ 143342ab0360SJames Bottomley i->attrb[count] = &i->private_##attrb[count]; \ 143442ab0360SJames Bottomley if (test) \ 1435c7ebbbceSChristoph Hellwig count++ 1436c7ebbbceSChristoph Hellwig 1437d24e1eebSJames Bottomley #define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \ 1438d24e1eebSJames Bottomley i->private_##attrb[count] = class_device_attr_##field; \ 1439d24e1eebSJames Bottomley i->private_##attrb[count].attr.mode = perm; \ 1440d24e1eebSJames Bottomley if (ro_test) { \ 1441d24e1eebSJames Bottomley i->private_##attrb[count].attr.mode = ro_perm; \ 1442d24e1eebSJames Bottomley i->private_##attrb[count].store = NULL; \ 1443d24e1eebSJames Bottomley } \ 1444d24e1eebSJames Bottomley i->attrb[count] = &i->private_##attrb[count]; \ 1445d24e1eebSJames Bottomley if (test) \ 1446d24e1eebSJames Bottomley count++ 144742ab0360SJames Bottomley 144842ab0360SJames Bottomley #define SETUP_RPORT_ATTRIBUTE(field) \ 144942ab0360SJames Bottomley SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) 145042ab0360SJames Bottomley 1451dd9fbb52SJames Bottomley #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 145242ab0360SJames Bottomley SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) 1453dd9fbb52SJames Bottomley 145465c92b09SJames Bottomley #define SETUP_PHY_ATTRIBUTE(field) \ 145542ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) 1456c7ebbbceSChristoph Hellwig 1457d24e1eebSJames Bottomley #define SETUP_PHY_ATTRIBUTE_RW(field) \ 1458d24e1eebSJames Bottomley SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ 1459d24e1eebSJames Bottomley !i->f->set_phy_speed, S_IRUGO) 1460d24e1eebSJames Bottomley 1461acbf167dSDarrick J. Wong #define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \ 1462acbf167dSDarrick J. Wong SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ 1463acbf167dSDarrick J. Wong !i->f->func, S_IRUGO) 1464acbf167dSDarrick J. Wong 146565c92b09SJames Bottomley #define SETUP_PORT_ATTRIBUTE(field) \ 146665c92b09SJames Bottomley SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) 146765c92b09SJames Bottomley 146865c92b09SJames Bottomley #define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \ 146942ab0360SJames Bottomley SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) 1470dd9fbb52SJames Bottomley 147165c92b09SJames Bottomley #define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ 1472fe3b5bfeSDarrick J. Wong SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1) 147307ba3a95SChristoph Hellwig 147465c92b09SJames Bottomley #define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ 1475fe3b5bfeSDarrick J. Wong SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func) 1476dd9fbb52SJames Bottomley 147742ab0360SJames Bottomley #define SETUP_END_DEV_ATTRIBUTE(field) \ 147842ab0360SJames Bottomley SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) 1479c7ebbbceSChristoph Hellwig 148079cb1819SJames Bottomley #define SETUP_EXPANDER_ATTRIBUTE(field) \ 148179cb1819SJames Bottomley SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1) 148279cb1819SJames Bottomley 1483c7ebbbceSChristoph Hellwig /** 1484c7ebbbceSChristoph Hellwig * sas_attach_transport -- instantiate SAS transport template 1485c7ebbbceSChristoph Hellwig * @ft: SAS transport class function template 1486c7ebbbceSChristoph Hellwig */ 1487c7ebbbceSChristoph Hellwig struct scsi_transport_template * 1488c7ebbbceSChristoph Hellwig sas_attach_transport(struct sas_function_template *ft) 1489c7ebbbceSChristoph Hellwig { 1490c7ebbbceSChristoph Hellwig struct sas_internal *i; 1491c7ebbbceSChristoph Hellwig int count; 1492c7ebbbceSChristoph Hellwig 149324669f75SJes Sorensen i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); 1494c7ebbbceSChristoph Hellwig if (!i) 1495c7ebbbceSChristoph Hellwig return NULL; 1496c7ebbbceSChristoph Hellwig 1497e02f3f59SChristoph Hellwig i->t.user_scan = sas_user_scan; 1498c7ebbbceSChristoph Hellwig 1499c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 1500c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.class = &sas_host_class.class; 1501c7ebbbceSChristoph Hellwig i->t.host_attrs.ac.match = sas_host_match; 1502c7ebbbceSChristoph Hellwig transport_container_register(&i->t.host_attrs); 1503c7ebbbceSChristoph Hellwig i->t.host_size = sizeof(struct sas_host_attrs); 1504c7ebbbceSChristoph Hellwig 1505c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.class = &sas_phy_class.class; 1506c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 1507c7ebbbceSChristoph Hellwig i->phy_attr_cont.ac.match = sas_phy_match; 1508c7ebbbceSChristoph Hellwig transport_container_register(&i->phy_attr_cont); 1509c7ebbbceSChristoph Hellwig 151065c92b09SJames Bottomley i->port_attr_cont.ac.class = &sas_port_class.class; 151165c92b09SJames Bottomley i->port_attr_cont.ac.attrs = &i->port_attrs[0]; 151265c92b09SJames Bottomley i->port_attr_cont.ac.match = sas_port_match; 151365c92b09SJames Bottomley transport_container_register(&i->port_attr_cont); 151465c92b09SJames Bottomley 1515c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 1516c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 1517c7ebbbceSChristoph Hellwig i->rphy_attr_cont.ac.match = sas_rphy_match; 1518c7ebbbceSChristoph Hellwig transport_container_register(&i->rphy_attr_cont); 1519c7ebbbceSChristoph Hellwig 152042ab0360SJames Bottomley i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class; 152142ab0360SJames Bottomley i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0]; 152242ab0360SJames Bottomley i->end_dev_attr_cont.ac.match = sas_end_dev_match; 152342ab0360SJames Bottomley transport_container_register(&i->end_dev_attr_cont); 152442ab0360SJames Bottomley 152579cb1819SJames Bottomley i->expander_attr_cont.ac.class = &sas_expander_class.class; 152679cb1819SJames Bottomley i->expander_attr_cont.ac.attrs = &i->expander_attrs[0]; 152779cb1819SJames Bottomley i->expander_attr_cont.ac.match = sas_expander_match; 152879cb1819SJames Bottomley transport_container_register(&i->expander_attr_cont); 152979cb1819SJames Bottomley 1530c7ebbbceSChristoph Hellwig i->f = ft; 1531c7ebbbceSChristoph Hellwig 1532c7ebbbceSChristoph Hellwig count = 0; 153365c92b09SJames Bottomley SETUP_PORT_ATTRIBUTE(num_phys); 1534c7ebbbceSChristoph Hellwig i->host_attrs[count] = NULL; 1535c7ebbbceSChristoph Hellwig 1536c7ebbbceSChristoph Hellwig count = 0; 153765c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(initiator_port_protocols); 153865c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(target_port_protocols); 153965c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(device_type); 154065c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(sas_address); 154165c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(phy_identifier); 154265c92b09SJames Bottomley //SETUP_PHY_ATTRIBUTE(port_identifier); 154365c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(negotiated_linkrate); 154465c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); 1545d24e1eebSJames Bottomley SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate); 154665c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); 1547d24e1eebSJames Bottomley SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate); 1548c3ee74c4SChristoph Hellwig 154965c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(invalid_dword_count); 155065c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(running_disparity_error_count); 155165c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count); 155265c92b09SJames Bottomley SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); 155365c92b09SJames Bottomley SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); 155465c92b09SJames Bottomley SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 1555acbf167dSDarrick J. Wong SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable); 1556c7ebbbceSChristoph Hellwig i->phy_attrs[count] = NULL; 1557c7ebbbceSChristoph Hellwig 1558c7ebbbceSChristoph Hellwig count = 0; 155965c92b09SJames Bottomley SETUP_PORT_ATTRIBUTE(num_phys); 156065c92b09SJames Bottomley i->port_attrs[count] = NULL; 156165c92b09SJames Bottomley 156265c92b09SJames Bottomley count = 0; 1563c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 1564c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 1565c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_device_type); 1566c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 1567c7ebbbceSChristoph Hellwig SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 1568dd9fbb52SJames Bottomley SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier, 1569dd9fbb52SJames Bottomley get_enclosure_identifier); 1570dd9fbb52SJames Bottomley SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier, 1571dd9fbb52SJames Bottomley get_bay_identifier); 1572c7ebbbceSChristoph Hellwig i->rphy_attrs[count] = NULL; 1573c7ebbbceSChristoph Hellwig 157442ab0360SJames Bottomley count = 0; 157542ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); 157642ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); 157742ab0360SJames Bottomley SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); 157842ab0360SJames Bottomley i->end_dev_attrs[count] = NULL; 157942ab0360SJames Bottomley 158079cb1819SJames Bottomley count = 0; 158179cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(vendor_id); 158279cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(product_id); 158379cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(product_rev); 158479cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(component_vendor_id); 158579cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(component_id); 158679cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(component_revision_id); 158779cb1819SJames Bottomley SETUP_EXPANDER_ATTRIBUTE(level); 158879cb1819SJames Bottomley i->expander_attrs[count] = NULL; 158979cb1819SJames Bottomley 1590c7ebbbceSChristoph Hellwig return &i->t; 1591c7ebbbceSChristoph Hellwig } 1592c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_attach_transport); 1593c7ebbbceSChristoph Hellwig 1594c7ebbbceSChristoph Hellwig /** 1595c7ebbbceSChristoph Hellwig * sas_release_transport -- release SAS transport template instance 1596c7ebbbceSChristoph Hellwig * @t: transport template instance 1597c7ebbbceSChristoph Hellwig */ 1598c7ebbbceSChristoph Hellwig void sas_release_transport(struct scsi_transport_template *t) 1599c7ebbbceSChristoph Hellwig { 1600c7ebbbceSChristoph Hellwig struct sas_internal *i = to_sas_internal(t); 1601c7ebbbceSChristoph Hellwig 1602c7ebbbceSChristoph Hellwig transport_container_unregister(&i->t.host_attrs); 1603c7ebbbceSChristoph Hellwig transport_container_unregister(&i->phy_attr_cont); 160465c92b09SJames Bottomley transport_container_unregister(&i->port_attr_cont); 1605c7ebbbceSChristoph Hellwig transport_container_unregister(&i->rphy_attr_cont); 1606db82f841SJames Bottomley transport_container_unregister(&i->end_dev_attr_cont); 160779cb1819SJames Bottomley transport_container_unregister(&i->expander_attr_cont); 1608c7ebbbceSChristoph Hellwig 1609c7ebbbceSChristoph Hellwig kfree(i); 1610c7ebbbceSChristoph Hellwig } 1611c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_release_transport); 1612c7ebbbceSChristoph Hellwig 1613c7ebbbceSChristoph Hellwig static __init int sas_transport_init(void) 1614c7ebbbceSChristoph Hellwig { 1615c7ebbbceSChristoph Hellwig int error; 1616c7ebbbceSChristoph Hellwig 1617c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_host_class); 1618c7ebbbceSChristoph Hellwig if (error) 1619c7ebbbceSChristoph Hellwig goto out; 1620c7ebbbceSChristoph Hellwig error = transport_class_register(&sas_phy_class); 1621c7ebbbceSChristoph Hellwig if (error) 1622c7ebbbceSChristoph Hellwig goto out_unregister_transport; 162365c92b09SJames Bottomley error = transport_class_register(&sas_port_class); 1624c7ebbbceSChristoph Hellwig if (error) 1625c7ebbbceSChristoph Hellwig goto out_unregister_phy; 162665c92b09SJames Bottomley error = transport_class_register(&sas_rphy_class); 162765c92b09SJames Bottomley if (error) 162865c92b09SJames Bottomley goto out_unregister_port; 162942ab0360SJames Bottomley error = transport_class_register(&sas_end_dev_class); 163042ab0360SJames Bottomley if (error) 163142ab0360SJames Bottomley goto out_unregister_rphy; 163279cb1819SJames Bottomley error = transport_class_register(&sas_expander_class); 163379cb1819SJames Bottomley if (error) 163479cb1819SJames Bottomley goto out_unregister_end_dev; 1635c7ebbbceSChristoph Hellwig 1636c7ebbbceSChristoph Hellwig return 0; 1637c7ebbbceSChristoph Hellwig 163879cb1819SJames Bottomley out_unregister_end_dev: 163979cb1819SJames Bottomley transport_class_unregister(&sas_end_dev_class); 164042ab0360SJames Bottomley out_unregister_rphy: 164142ab0360SJames Bottomley transport_class_unregister(&sas_rphy_class); 164265c92b09SJames Bottomley out_unregister_port: 164365c92b09SJames Bottomley transport_class_unregister(&sas_port_class); 1644c7ebbbceSChristoph Hellwig out_unregister_phy: 1645c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 1646c7ebbbceSChristoph Hellwig out_unregister_transport: 1647c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 1648c7ebbbceSChristoph Hellwig out: 1649c7ebbbceSChristoph Hellwig return error; 1650c7ebbbceSChristoph Hellwig 1651c7ebbbceSChristoph Hellwig } 1652c7ebbbceSChristoph Hellwig 1653c7ebbbceSChristoph Hellwig static void __exit sas_transport_exit(void) 1654c7ebbbceSChristoph Hellwig { 1655c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_host_class); 1656c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_phy_class); 165765c92b09SJames Bottomley transport_class_unregister(&sas_port_class); 1658c7ebbbceSChristoph Hellwig transport_class_unregister(&sas_rphy_class); 165942ab0360SJames Bottomley transport_class_unregister(&sas_end_dev_class); 166079cb1819SJames Bottomley transport_class_unregister(&sas_expander_class); 1661c7ebbbceSChristoph Hellwig } 1662c7ebbbceSChristoph Hellwig 1663c7ebbbceSChristoph Hellwig MODULE_AUTHOR("Christoph Hellwig"); 166486b9c4c1SAlexis Bruemmer MODULE_DESCRIPTION("SAS Transport Attributes"); 1665c7ebbbceSChristoph Hellwig MODULE_LICENSE("GPL"); 1666c7ebbbceSChristoph Hellwig 1667c7ebbbceSChristoph Hellwig module_init(sas_transport_init); 1668c7ebbbceSChristoph Hellwig module_exit(sas_transport_exit); 1669