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