1954 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2005-2006 Dell Inc.4 *5 * Serial Attached SCSI (SAS) transport class.6 *7 * The SAS transport class contains common code to deal with SAS HBAs,8 * an aproximated representation of SAS topologies in the driver model,9 * and various sysfs attributes to expose these topologies and management10 * interfaces to userspace.11 *12 * In addition to the basic SCSI core objects this transport class13 * introduces two additional intermediate objects: The SAS PHY14 * as represented by struct sas_phy defines an "outgoing" PHY on15 * a SAS HBA or Expander, and the SAS remote PHY represented by16 * struct sas_rphy defines an "incoming" PHY on a SAS Expander or17 * end device. Note that this is purely a software concept, the18 * underlying hardware for a PHY and a remote PHY is the exactly19 * the same.20 *21 * There is no concept of a SAS port in this code, users can see22 * what PHYs form a wide port based on the port_identifier attribute,23 * which is the same for all PHYs in a port.24 */25 26#include <linux/init.h>27#include <linux/module.h>28#include <linux/jiffies.h>29#include <linux/err.h>30#include <linux/slab.h>31#include <linux/string.h>32#include <linux/blkdev.h>33#include <linux/bsg.h>34 35#include <scsi/scsi.h>36#include <scsi/scsi_cmnd.h>37#include <scsi/scsi_device.h>38#include <scsi/scsi_host.h>39#include <scsi/scsi_transport.h>40#include <scsi/scsi_transport_sas.h>41 42#include "scsi_sas_internal.h"43struct sas_host_attrs {44 struct list_head rphy_list;45 struct mutex lock;46 struct request_queue *q;47 u32 next_target_id;48 u32 next_expander_id;49 int next_port_id;50};51#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)52 53 54/*55 * Hack to allow attributes of the same name in different objects.56 */57#define SAS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \58 struct device_attribute dev_attr_##_prefix##_##_name = \59 __ATTR(_name,_mode,_show,_store)60 61 62/*63 * Pretty printing helpers64 */65 66#define sas_bitfield_name_match(title, table) \67static ssize_t \68get_sas_##title##_names(u32 table_key, char *buf) \69{ \70 char *prefix = ""; \71 ssize_t len = 0; \72 int i; \73 \74 for (i = 0; i < ARRAY_SIZE(table); i++) { \75 if (table[i].value & table_key) { \76 len += sprintf(buf + len, "%s%s", \77 prefix, table[i].name); \78 prefix = ", "; \79 } \80 } \81 len += sprintf(buf + len, "\n"); \82 return len; \83}84 85#define sas_bitfield_name_set(title, table) \86static ssize_t \87set_sas_##title##_names(u32 *table_key, const char *buf) \88{ \89 ssize_t len = 0; \90 int i; \91 \92 for (i = 0; i < ARRAY_SIZE(table); i++) { \93 len = strlen(table[i].name); \94 if (strncmp(buf, table[i].name, len) == 0 && \95 (buf[len] == '\n' || buf[len] == '\0')) { \96 *table_key = table[i].value; \97 return 0; \98 } \99 } \100 return -EINVAL; \101}102 103#define sas_bitfield_name_search(title, table) \104static ssize_t \105get_sas_##title##_names(u32 table_key, char *buf) \106{ \107 ssize_t len = 0; \108 int i; \109 \110 for (i = 0; i < ARRAY_SIZE(table); i++) { \111 if (table[i].value == table_key) { \112 len += sprintf(buf + len, "%s", \113 table[i].name); \114 break; \115 } \116 } \117 len += sprintf(buf + len, "\n"); \118 return len; \119}120 121static struct {122 u32 value;123 char *name;124} sas_device_type_names[] = {125 { SAS_PHY_UNUSED, "unused" },126 { SAS_END_DEVICE, "end device" },127 { SAS_EDGE_EXPANDER_DEVICE, "edge expander" },128 { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" },129};130sas_bitfield_name_search(device_type, sas_device_type_names)131 132 133static struct {134 u32 value;135 char *name;136} sas_protocol_names[] = {137 { SAS_PROTOCOL_SATA, "sata" },138 { SAS_PROTOCOL_SMP, "smp" },139 { SAS_PROTOCOL_STP, "stp" },140 { SAS_PROTOCOL_SSP, "ssp" },141};142sas_bitfield_name_match(protocol, sas_protocol_names)143 144static struct {145 u32 value;146 char *name;147} sas_linkspeed_names[] = {148 { SAS_LINK_RATE_UNKNOWN, "Unknown" },149 { SAS_PHY_DISABLED, "Phy disabled" },150 { SAS_LINK_RATE_FAILED, "Link Rate failed" },151 { SAS_SATA_SPINUP_HOLD, "Spin-up hold" },152 { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },153 { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },154 { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },155 { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },156 { SAS_LINK_RATE_22_5_GBPS, "22.5 Gbit" },157};158sas_bitfield_name_search(linkspeed, sas_linkspeed_names)159sas_bitfield_name_set(linkspeed, sas_linkspeed_names)160 161static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev)162{163 struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);164 struct sas_end_device *rdev;165 166 BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);167 168 rdev = rphy_to_end_device(rphy);169 return rdev;170}171 172static int sas_smp_dispatch(struct bsg_job *job)173{174 struct Scsi_Host *shost = dev_to_shost(job->dev);175 struct sas_rphy *rphy = NULL;176 177 if (!scsi_is_host_device(job->dev))178 rphy = dev_to_rphy(job->dev);179 180 if (!job->reply_payload.payload_len) {181 dev_warn(job->dev, "space for a smp response is missing\n");182 bsg_job_done(job, -EINVAL, 0);183 return 0;184 }185 186 to_sas_internal(shost->transportt)->f->smp_handler(job, shost, rphy);187 return 0;188}189 190static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)191{192 struct request_queue *q;193 194 if (!to_sas_internal(shost->transportt)->f->smp_handler) {195 printk("%s can't handle SMP requests\n", shost->hostt->name);196 return 0;197 }198 199 if (rphy) {200 q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev), NULL,201 sas_smp_dispatch, NULL, 0);202 if (IS_ERR(q))203 return PTR_ERR(q);204 rphy->q = q;205 } else {206 char name[20];207 208 snprintf(name, sizeof(name), "sas_host%d", shost->host_no);209 q = bsg_setup_queue(&shost->shost_gendev, name, NULL,210 sas_smp_dispatch, NULL, 0);211 if (IS_ERR(q))212 return PTR_ERR(q);213 to_sas_host_attrs(shost)->q = q;214 }215 216 return 0;217}218 219/*220 * SAS host attributes221 */222 223static int sas_host_setup(struct transport_container *tc, struct device *dev,224 struct device *cdev)225{226 struct Scsi_Host *shost = dev_to_shost(dev);227 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);228 struct device *dma_dev = shost->dma_dev;229 230 INIT_LIST_HEAD(&sas_host->rphy_list);231 mutex_init(&sas_host->lock);232 sas_host->next_target_id = 0;233 sas_host->next_expander_id = 0;234 sas_host->next_port_id = 0;235 236 if (sas_bsg_initialize(shost, NULL))237 dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",238 shost->host_no);239 240 if (dma_dev->dma_mask) {241 shost->opt_sectors = min_t(unsigned int, shost->max_sectors,242 dma_opt_mapping_size(dma_dev) >> SECTOR_SHIFT);243 }244 245 return 0;246}247 248static int sas_host_remove(struct transport_container *tc, struct device *dev,249 struct device *cdev)250{251 struct Scsi_Host *shost = dev_to_shost(dev);252 struct request_queue *q = to_sas_host_attrs(shost)->q;253 254 bsg_remove_queue(q);255 return 0;256}257 258static DECLARE_TRANSPORT_CLASS(sas_host_class,259 "sas_host", sas_host_setup, sas_host_remove, NULL);260 261static int sas_host_match(struct attribute_container *cont,262 struct device *dev)263{264 struct Scsi_Host *shost;265 struct sas_internal *i;266 267 if (!scsi_is_host_device(dev))268 return 0;269 shost = dev_to_shost(dev);270 271 if (!shost->transportt)272 return 0;273 if (shost->transportt->host_attrs.ac.class !=274 &sas_host_class.class)275 return 0;276 277 i = to_sas_internal(shost->transportt);278 return &i->t.host_attrs.ac == cont;279}280 281static int do_sas_phy_delete(struct device *dev, void *data)282{283 int pass = (int)(unsigned long)data;284 285 if (pass == 0 && scsi_is_sas_port(dev))286 sas_port_delete(dev_to_sas_port(dev));287 else if (pass == 1 && scsi_is_sas_phy(dev))288 sas_phy_delete(dev_to_phy(dev));289 return 0;290}291 292/**293 * sas_remove_children - tear down a devices SAS data structures294 * @dev: device belonging to the sas object295 *296 * Removes all SAS PHYs and remote PHYs for a given object297 */298void sas_remove_children(struct device *dev)299{300 device_for_each_child(dev, (void *)0, do_sas_phy_delete);301 device_for_each_child(dev, (void *)1, do_sas_phy_delete);302}303EXPORT_SYMBOL(sas_remove_children);304 305/**306 * sas_remove_host - tear down a Scsi_Host's SAS data structures307 * @shost: Scsi Host that is torn down308 *309 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host and remove the310 * Scsi_Host as well.311 *312 * Note: Do not call scsi_remove_host() on the Scsi_Host any more, as it is313 * already removed.314 */315void sas_remove_host(struct Scsi_Host *shost)316{317 sas_remove_children(&shost->shost_gendev);318 scsi_remove_host(shost);319}320EXPORT_SYMBOL(sas_remove_host);321 322/**323 * sas_get_address - return the SAS address of the device324 * @sdev: scsi device325 *326 * Returns the SAS address of the scsi device327 */328u64 sas_get_address(struct scsi_device *sdev)329{330 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);331 332 return rdev->rphy.identify.sas_address;333}334EXPORT_SYMBOL(sas_get_address);335 336/**337 * sas_tlr_supported - checking TLR bit in vpd 0x90338 * @sdev: scsi device struct339 *340 * Check Transport Layer Retries are supported or not.341 * If vpd page 0x90 is present, TRL is supported.342 *343 */344unsigned int345sas_tlr_supported(struct scsi_device *sdev)346{347 const int vpd_len = 32;348 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);349 char *buffer = kzalloc(vpd_len, GFP_KERNEL);350 int ret = 0;351 352 if (!buffer)353 goto out;354 355 if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))356 goto out;357 358 /*359 * Magic numbers: the VPD Protocol page (0x90)360 * has a 4 byte header and then one entry per device port361 * the TLR bit is at offset 8 on each port entry362 * if we take the first port, that's at total offset 12363 */364 ret = buffer[12] & 0x01;365 366 out:367 kfree(buffer);368 rdev->tlr_supported = ret;369 return ret;370 371}372EXPORT_SYMBOL_GPL(sas_tlr_supported);373 374/**375 * sas_disable_tlr - setting TLR flags376 * @sdev: scsi device struct377 *378 * Seting tlr_enabled flag to 0.379 *380 */381void382sas_disable_tlr(struct scsi_device *sdev)383{384 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);385 386 rdev->tlr_enabled = 0;387}388EXPORT_SYMBOL_GPL(sas_disable_tlr);389 390/**391 * sas_enable_tlr - setting TLR flags392 * @sdev: scsi device struct393 *394 * Seting tlr_enabled flag 1.395 *396 */397void sas_enable_tlr(struct scsi_device *sdev)398{399 unsigned int tlr_supported = 0;400 tlr_supported = sas_tlr_supported(sdev);401 402 if (tlr_supported) {403 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);404 405 rdev->tlr_enabled = 1;406 }407 408 return;409}410EXPORT_SYMBOL_GPL(sas_enable_tlr);411 412unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)413{414 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);415 return rdev->tlr_enabled;416}417EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);418 419/**420 * sas_ata_ncq_prio_supported - Check for ATA NCQ command priority support421 * @sdev: SCSI device422 *423 * Check if an ATA device supports NCQ priority using VPD page 89h (ATA424 * Information). Since this VPD page is implemented only for ATA devices,425 * this function always returns false for SCSI devices.426 */427bool sas_ata_ncq_prio_supported(struct scsi_device *sdev)428{429 struct scsi_vpd *vpd;430 bool ncq_prio_supported = false;431 432 rcu_read_lock();433 vpd = rcu_dereference(sdev->vpd_pg89);434 if (vpd && vpd->len >= 214)435 ncq_prio_supported = (vpd->data[213] >> 4) & 1;436 rcu_read_unlock();437 438 return ncq_prio_supported;439}440EXPORT_SYMBOL_GPL(sas_ata_ncq_prio_supported);441 442/*443 * SAS Phy attributes444 */445 446#define sas_phy_show_simple(field, name, format_string, cast) \447static ssize_t \448show_sas_phy_##name(struct device *dev, \449 struct device_attribute *attr, char *buf) \450{ \451 struct sas_phy *phy = transport_class_to_phy(dev); \452 \453 return snprintf(buf, 20, format_string, cast phy->field); \454}455 456#define sas_phy_simple_attr(field, name, format_string, type) \457 sas_phy_show_simple(field, name, format_string, (type)) \458static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)459 460#define sas_phy_show_protocol(field, name) \461static ssize_t \462show_sas_phy_##name(struct device *dev, \463 struct device_attribute *attr, char *buf) \464{ \465 struct sas_phy *phy = transport_class_to_phy(dev); \466 \467 if (!phy->field) \468 return snprintf(buf, 20, "none\n"); \469 return get_sas_protocol_names(phy->field, buf); \470}471 472#define sas_phy_protocol_attr(field, name) \473 sas_phy_show_protocol(field, name) \474static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)475 476#define sas_phy_show_linkspeed(field) \477static ssize_t \478show_sas_phy_##field(struct device *dev, \479 struct device_attribute *attr, char *buf) \480{ \481 struct sas_phy *phy = transport_class_to_phy(dev); \482 \483 return get_sas_linkspeed_names(phy->field, buf); \484}485 486/* Fudge to tell if we're minimum or maximum */487#define sas_phy_store_linkspeed(field) \488static ssize_t \489store_sas_phy_##field(struct device *dev, \490 struct device_attribute *attr, \491 const char *buf, size_t count) \492{ \493 struct sas_phy *phy = transport_class_to_phy(dev); \494 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \495 struct sas_internal *i = to_sas_internal(shost->transportt); \496 u32 value; \497 struct sas_phy_linkrates rates = {0}; \498 int error; \499 \500 error = set_sas_linkspeed_names(&value, buf); \501 if (error) \502 return error; \503 rates.field = value; \504 error = i->f->set_phy_speed(phy, &rates); \505 \506 return error ? error : count; \507}508 509#define sas_phy_linkspeed_rw_attr(field) \510 sas_phy_show_linkspeed(field) \511 sas_phy_store_linkspeed(field) \512static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \513 store_sas_phy_##field)514 515#define sas_phy_linkspeed_attr(field) \516 sas_phy_show_linkspeed(field) \517static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)518 519 520#define sas_phy_show_linkerror(field) \521static ssize_t \522show_sas_phy_##field(struct device *dev, \523 struct device_attribute *attr, char *buf) \524{ \525 struct sas_phy *phy = transport_class_to_phy(dev); \526 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \527 struct sas_internal *i = to_sas_internal(shost->transportt); \528 int error; \529 \530 error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \531 if (error) \532 return error; \533 return snprintf(buf, 20, "%u\n", phy->field); \534}535 536#define sas_phy_linkerror_attr(field) \537 sas_phy_show_linkerror(field) \538static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)539 540 541static ssize_t542show_sas_device_type(struct device *dev,543 struct device_attribute *attr, char *buf)544{545 struct sas_phy *phy = transport_class_to_phy(dev);546 547 if (!phy->identify.device_type)548 return snprintf(buf, 20, "none\n");549 return get_sas_device_type_names(phy->identify.device_type, buf);550}551static DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);552 553static ssize_t do_sas_phy_enable(struct device *dev,554 size_t count, int enable)555{556 struct sas_phy *phy = transport_class_to_phy(dev);557 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);558 struct sas_internal *i = to_sas_internal(shost->transportt);559 int error;560 561 error = i->f->phy_enable(phy, enable);562 if (error)563 return error;564 phy->enabled = enable;565 return count;566};567 568static ssize_t569store_sas_phy_enable(struct device *dev, struct device_attribute *attr,570 const char *buf, size_t count)571{572 if (count < 1)573 return -EINVAL;574 575 switch (buf[0]) {576 case '0':577 do_sas_phy_enable(dev, count, 0);578 break;579 case '1':580 do_sas_phy_enable(dev, count, 1);581 break;582 default:583 return -EINVAL;584 }585 586 return count;587}588 589static ssize_t590show_sas_phy_enable(struct device *dev, struct device_attribute *attr,591 char *buf)592{593 struct sas_phy *phy = transport_class_to_phy(dev);594 595 return snprintf(buf, 20, "%d\n", phy->enabled);596}597 598static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,599 store_sas_phy_enable);600 601static ssize_t602do_sas_phy_reset(struct device *dev, size_t count, int hard_reset)603{604 struct sas_phy *phy = transport_class_to_phy(dev);605 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);606 struct sas_internal *i = to_sas_internal(shost->transportt);607 int error;608 609 error = i->f->phy_reset(phy, hard_reset);610 if (error)611 return error;612 phy->enabled = 1;613 return count;614};615 616static ssize_t617store_sas_link_reset(struct device *dev, struct device_attribute *attr,618 const char *buf, size_t count)619{620 return do_sas_phy_reset(dev, count, 0);621}622static DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);623 624static ssize_t625store_sas_hard_reset(struct device *dev, struct device_attribute *attr,626 const char *buf, size_t count)627{628 return do_sas_phy_reset(dev, count, 1);629}630static DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);631 632sas_phy_protocol_attr(identify.initiator_port_protocols,633 initiator_port_protocols);634sas_phy_protocol_attr(identify.target_port_protocols,635 target_port_protocols);636sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",637 unsigned long long);638sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);639sas_phy_linkspeed_attr(negotiated_linkrate);640sas_phy_linkspeed_attr(minimum_linkrate_hw);641sas_phy_linkspeed_rw_attr(minimum_linkrate);642sas_phy_linkspeed_attr(maximum_linkrate_hw);643sas_phy_linkspeed_rw_attr(maximum_linkrate);644sas_phy_linkerror_attr(invalid_dword_count);645sas_phy_linkerror_attr(running_disparity_error_count);646sas_phy_linkerror_attr(loss_of_dword_sync_count);647sas_phy_linkerror_attr(phy_reset_problem_count);648 649static int sas_phy_setup(struct transport_container *tc, struct device *dev,650 struct device *cdev)651{652 struct sas_phy *phy = dev_to_phy(dev);653 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);654 struct sas_internal *i = to_sas_internal(shost->transportt);655 656 if (i->f->phy_setup)657 i->f->phy_setup(phy);658 659 return 0;660}661 662static DECLARE_TRANSPORT_CLASS(sas_phy_class,663 "sas_phy", sas_phy_setup, NULL, NULL);664 665static int sas_phy_match(struct attribute_container *cont, struct device *dev)666{667 struct Scsi_Host *shost;668 struct sas_internal *i;669 670 if (!scsi_is_sas_phy(dev))671 return 0;672 shost = dev_to_shost(dev->parent);673 674 if (!shost->transportt)675 return 0;676 if (shost->transportt->host_attrs.ac.class !=677 &sas_host_class.class)678 return 0;679 680 i = to_sas_internal(shost->transportt);681 return &i->phy_attr_cont.ac == cont;682}683 684static void sas_phy_release(struct device *dev)685{686 struct sas_phy *phy = dev_to_phy(dev);687 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);688 struct sas_internal *i = to_sas_internal(shost->transportt);689 690 if (i->f->phy_release)691 i->f->phy_release(phy);692 put_device(dev->parent);693 kfree(phy);694}695 696/**697 * sas_phy_alloc - allocates and initialize a SAS PHY structure698 * @parent: Parent device699 * @number: Phy index700 *701 * Allocates an SAS PHY structure. It will be added in the device tree702 * below the device specified by @parent, which has to be either a Scsi_Host703 * or sas_rphy.704 *705 * Returns:706 * SAS PHY allocated or %NULL if the allocation failed.707 */708struct sas_phy *sas_phy_alloc(struct device *parent, int number)709{710 struct Scsi_Host *shost = dev_to_shost(parent);711 struct sas_phy *phy;712 713 phy = kzalloc(sizeof(*phy), GFP_KERNEL);714 if (!phy)715 return NULL;716 717 phy->number = number;718 phy->enabled = 1;719 720 device_initialize(&phy->dev);721 phy->dev.parent = get_device(parent);722 phy->dev.release = sas_phy_release;723 INIT_LIST_HEAD(&phy->port_siblings);724 if (scsi_is_sas_expander_device(parent)) {725 struct sas_rphy *rphy = dev_to_rphy(parent);726 dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no,727 rphy->scsi_target_id, number);728 } else729 dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number);730 731 transport_setup_device(&phy->dev);732 733 return phy;734}735EXPORT_SYMBOL(sas_phy_alloc);736 737/**738 * sas_phy_add - add a SAS PHY to the device hierarchy739 * @phy: The PHY to be added740 *741 * Publishes a SAS PHY to the rest of the system.742 */743int sas_phy_add(struct sas_phy *phy)744{745 int error;746 747 error = device_add(&phy->dev);748 if (error)749 return error;750 751 error = transport_add_device(&phy->dev);752 if (error) {753 device_del(&phy->dev);754 return error;755 }756 transport_configure_device(&phy->dev);757 758 return 0;759}760EXPORT_SYMBOL(sas_phy_add);761 762/**763 * sas_phy_free - free a SAS PHY764 * @phy: SAS PHY to free765 *766 * Frees the specified SAS PHY.767 *768 * Note:769 * This function must only be called on a PHY that has not770 * successfully been added using sas_phy_add().771 */772void sas_phy_free(struct sas_phy *phy)773{774 transport_destroy_device(&phy->dev);775 put_device(&phy->dev);776}777EXPORT_SYMBOL(sas_phy_free);778 779/**780 * sas_phy_delete - remove SAS PHY781 * @phy: SAS PHY to remove782 *783 * Removes the specified SAS PHY. If the SAS PHY has an784 * associated remote PHY it is removed before.785 */786void787sas_phy_delete(struct sas_phy *phy)788{789 struct device *dev = &phy->dev;790 791 /* this happens if the phy is still part of a port when deleted */792 BUG_ON(!list_empty(&phy->port_siblings));793 794 transport_remove_device(dev);795 device_del(dev);796 transport_destroy_device(dev);797 put_device(dev);798}799EXPORT_SYMBOL(sas_phy_delete);800 801/**802 * scsi_is_sas_phy - check if a struct device represents a SAS PHY803 * @dev: device to check804 *805 * Returns:806 * %1 if the device represents a SAS PHY, %0 else807 */808int scsi_is_sas_phy(const struct device *dev)809{810 return dev->release == sas_phy_release;811}812EXPORT_SYMBOL(scsi_is_sas_phy);813 814/*815 * SAS Port attributes816 */817#define sas_port_show_simple(field, name, format_string, cast) \818static ssize_t \819show_sas_port_##name(struct device *dev, \820 struct device_attribute *attr, char *buf) \821{ \822 struct sas_port *port = transport_class_to_sas_port(dev); \823 \824 return snprintf(buf, 20, format_string, cast port->field); \825}826 827#define sas_port_simple_attr(field, name, format_string, type) \828 sas_port_show_simple(field, name, format_string, (type)) \829static DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)830 831sas_port_simple_attr(num_phys, num_phys, "%d\n", int);832 833static DECLARE_TRANSPORT_CLASS(sas_port_class,834 "sas_port", NULL, NULL, NULL);835 836static int sas_port_match(struct attribute_container *cont, struct device *dev)837{838 struct Scsi_Host *shost;839 struct sas_internal *i;840 841 if (!scsi_is_sas_port(dev))842 return 0;843 shost = dev_to_shost(dev->parent);844 845 if (!shost->transportt)846 return 0;847 if (shost->transportt->host_attrs.ac.class !=848 &sas_host_class.class)849 return 0;850 851 i = to_sas_internal(shost->transportt);852 return &i->port_attr_cont.ac == cont;853}854 855 856static void sas_port_release(struct device *dev)857{858 struct sas_port *port = dev_to_sas_port(dev);859 860 BUG_ON(!list_empty(&port->phy_list));861 862 put_device(dev->parent);863 kfree(port);864}865 866static void sas_port_create_link(struct sas_port *port,867 struct sas_phy *phy)868{869 int res;870 871 res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,872 dev_name(&phy->dev));873 if (res)874 goto err;875 res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");876 if (res)877 goto err;878 return;879err:880 printk(KERN_ERR "%s: Cannot create port links, err=%d\n",881 __func__, res);882}883 884static void sas_port_delete_link(struct sas_port *port,885 struct sas_phy *phy)886{887 sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev));888 sysfs_remove_link(&phy->dev.kobj, "port");889}890 891/** sas_port_alloc - allocate and initialize a SAS port structure892 *893 * @parent: parent device894 * @port_id: port number895 *896 * Allocates a SAS port structure. It will be added to the device tree897 * below the device specified by @parent which must be either a Scsi_Host898 * or a sas_expander_device.899 *900 * Returns %NULL on error901 */902struct sas_port *sas_port_alloc(struct device *parent, int port_id)903{904 struct Scsi_Host *shost = dev_to_shost(parent);905 struct sas_port *port;906 907 port = kzalloc(sizeof(*port), GFP_KERNEL);908 if (!port)909 return NULL;910 911 port->port_identifier = port_id;912 913 device_initialize(&port->dev);914 915 port->dev.parent = get_device(parent);916 port->dev.release = sas_port_release;917 918 mutex_init(&port->phy_list_mutex);919 INIT_LIST_HEAD(&port->phy_list);920 921 if (scsi_is_sas_expander_device(parent)) {922 struct sas_rphy *rphy = dev_to_rphy(parent);923 dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no,924 rphy->scsi_target_id, port->port_identifier);925 } else926 dev_set_name(&port->dev, "port-%d:%d", shost->host_no,927 port->port_identifier);928 929 transport_setup_device(&port->dev);930 931 return port;932}933EXPORT_SYMBOL(sas_port_alloc);934 935/** sas_port_alloc_num - allocate and initialize a SAS port structure936 *937 * @parent: parent device938 *939 * Allocates a SAS port structure and a number to go with it. This940 * interface is really for adapters where the port number has no941 * meansing, so the sas class should manage them. It will be added to942 * the device tree below the device specified by @parent which must be943 * either a Scsi_Host or a sas_expander_device.944 *945 * Returns %NULL on error946 */947struct sas_port *sas_port_alloc_num(struct device *parent)948{949 int index;950 struct Scsi_Host *shost = dev_to_shost(parent);951 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);952 953 /* FIXME: use idr for this eventually */954 mutex_lock(&sas_host->lock);955 if (scsi_is_sas_expander_device(parent)) {956 struct sas_rphy *rphy = dev_to_rphy(parent);957 struct sas_expander_device *exp = rphy_to_expander_device(rphy);958 959 index = exp->next_port_id++;960 } else961 index = sas_host->next_port_id++;962 mutex_unlock(&sas_host->lock);963 return sas_port_alloc(parent, index);964}965EXPORT_SYMBOL(sas_port_alloc_num);966 967/**968 * sas_port_add - add a SAS port to the device hierarchy969 * @port: port to be added970 *971 * publishes a port to the rest of the system972 */973int sas_port_add(struct sas_port *port)974{975 int error;976 977 /* No phys should be added until this is made visible */978 BUG_ON(!list_empty(&port->phy_list));979 980 error = device_add(&port->dev);981 982 if (error)983 return error;984 985 transport_add_device(&port->dev);986 transport_configure_device(&port->dev);987 988 return 0;989}990EXPORT_SYMBOL(sas_port_add);991 992/**993 * sas_port_free - free a SAS PORT994 * @port: SAS PORT to free995 *996 * Frees the specified SAS PORT.997 *998 * Note:999 * This function must only be called on a PORT that has not1000 * successfully been added using sas_port_add().1001 */1002void sas_port_free(struct sas_port *port)1003{1004 transport_destroy_device(&port->dev);1005 put_device(&port->dev);1006}1007EXPORT_SYMBOL(sas_port_free);1008 1009/**1010 * sas_port_delete - remove SAS PORT1011 * @port: SAS PORT to remove1012 *1013 * Removes the specified SAS PORT. If the SAS PORT has an1014 * associated phys, unlink them from the port as well.1015 */1016void sas_port_delete(struct sas_port *port)1017{1018 struct device *dev = &port->dev;1019 struct sas_phy *phy, *tmp_phy;1020 1021 if (port->rphy) {1022 sas_rphy_delete(port->rphy);1023 port->rphy = NULL;1024 }1025 1026 mutex_lock(&port->phy_list_mutex);1027 list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,1028 port_siblings) {1029 sas_port_delete_link(port, phy);1030 list_del_init(&phy->port_siblings);1031 }1032 mutex_unlock(&port->phy_list_mutex);1033 1034 if (port->is_backlink) {1035 struct device *parent = port->dev.parent;1036 1037 sysfs_remove_link(&port->dev.kobj, dev_name(parent));1038 port->is_backlink = 0;1039 }1040 1041 transport_remove_device(dev);1042 device_del(dev);1043 transport_destroy_device(dev);1044 put_device(dev);1045}1046EXPORT_SYMBOL(sas_port_delete);1047 1048/**1049 * scsi_is_sas_port - check if a struct device represents a SAS port1050 * @dev: device to check1051 *1052 * Returns:1053 * %1 if the device represents a SAS Port, %0 else1054 */1055int scsi_is_sas_port(const struct device *dev)1056{1057 return dev->release == sas_port_release;1058}1059EXPORT_SYMBOL(scsi_is_sas_port);1060 1061/**1062 * sas_port_get_phy - try to take a reference on a port member1063 * @port: port to check1064 */1065struct sas_phy *sas_port_get_phy(struct sas_port *port)1066{1067 struct sas_phy *phy;1068 1069 mutex_lock(&port->phy_list_mutex);1070 if (list_empty(&port->phy_list))1071 phy = NULL;1072 else {1073 struct list_head *ent = port->phy_list.next;1074 1075 phy = list_entry(ent, typeof(*phy), port_siblings);1076 get_device(&phy->dev);1077 }1078 mutex_unlock(&port->phy_list_mutex);1079 1080 return phy;1081}1082EXPORT_SYMBOL(sas_port_get_phy);1083 1084/**1085 * sas_port_add_phy - add another phy to a port to form a wide port1086 * @port: port to add the phy to1087 * @phy: phy to add1088 *1089 * When a port is initially created, it is empty (has no phys). All1090 * ports must have at least one phy to operated, and all wide ports1091 * must have at least two. The current code makes no difference1092 * between ports and wide ports, but the only object that can be1093 * connected to a remote device is a port, so ports must be formed on1094 * all devices with phys if they're connected to anything.1095 */1096void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)1097{1098 mutex_lock(&port->phy_list_mutex);1099 if (unlikely(!list_empty(&phy->port_siblings))) {1100 /* make sure we're already on this port */1101 struct sas_phy *tmp;1102 1103 list_for_each_entry(tmp, &port->phy_list, port_siblings)1104 if (tmp == phy)1105 break;1106 /* If this trips, you added a phy that was already1107 * part of a different port */1108 if (unlikely(tmp != phy)) {1109 dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n",1110 dev_name(&phy->dev));1111 BUG();1112 }1113 } else {1114 sas_port_create_link(port, phy);1115 list_add_tail(&phy->port_siblings, &port->phy_list);1116 port->num_phys++;1117 }1118 mutex_unlock(&port->phy_list_mutex);1119}1120EXPORT_SYMBOL(sas_port_add_phy);1121 1122/**1123 * sas_port_delete_phy - remove a phy from a port or wide port1124 * @port: port to remove the phy from1125 * @phy: phy to remove1126 *1127 * This operation is used for tearing down ports again. It must be1128 * done to every port or wide port before calling sas_port_delete.1129 */1130void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)1131{1132 mutex_lock(&port->phy_list_mutex);1133 sas_port_delete_link(port, phy);1134 list_del_init(&phy->port_siblings);1135 port->num_phys--;1136 mutex_unlock(&port->phy_list_mutex);1137}1138EXPORT_SYMBOL(sas_port_delete_phy);1139 1140void sas_port_mark_backlink(struct sas_port *port)1141{1142 int res;1143 struct device *parent = port->dev.parent->parent->parent;1144 1145 if (port->is_backlink)1146 return;1147 port->is_backlink = 1;1148 res = sysfs_create_link(&port->dev.kobj, &parent->kobj,1149 dev_name(parent));1150 if (res)1151 goto err;1152 return;1153err:1154 printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",1155 __func__, res);1156 1157}1158EXPORT_SYMBOL(sas_port_mark_backlink);1159 1160/*1161 * SAS remote PHY attributes.1162 */1163 1164#define sas_rphy_show_simple(field, name, format_string, cast) \1165static ssize_t \1166show_sas_rphy_##name(struct device *dev, \1167 struct device_attribute *attr, char *buf) \1168{ \1169 struct sas_rphy *rphy = transport_class_to_rphy(dev); \1170 \1171 return snprintf(buf, 20, format_string, cast rphy->field); \1172}1173 1174#define sas_rphy_simple_attr(field, name, format_string, type) \1175 sas_rphy_show_simple(field, name, format_string, (type)) \1176static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \1177 show_sas_rphy_##name, NULL)1178 1179#define sas_rphy_show_protocol(field, name) \1180static ssize_t \1181show_sas_rphy_##name(struct device *dev, \1182 struct device_attribute *attr, char *buf) \1183{ \1184 struct sas_rphy *rphy = transport_class_to_rphy(dev); \1185 \1186 if (!rphy->field) \1187 return snprintf(buf, 20, "none\n"); \1188 return get_sas_protocol_names(rphy->field, buf); \1189}1190 1191#define sas_rphy_protocol_attr(field, name) \1192 sas_rphy_show_protocol(field, name) \1193static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \1194 show_sas_rphy_##name, NULL)1195 1196static ssize_t1197show_sas_rphy_device_type(struct device *dev,1198 struct device_attribute *attr, char *buf)1199{1200 struct sas_rphy *rphy = transport_class_to_rphy(dev);1201 1202 if (!rphy->identify.device_type)1203 return snprintf(buf, 20, "none\n");1204 return get_sas_device_type_names(1205 rphy->identify.device_type, buf);1206}1207 1208static SAS_DEVICE_ATTR(rphy, device_type, S_IRUGO,1209 show_sas_rphy_device_type, NULL);1210 1211static ssize_t1212show_sas_rphy_enclosure_identifier(struct device *dev,1213 struct device_attribute *attr, char *buf)1214{1215 struct sas_rphy *rphy = transport_class_to_rphy(dev);1216 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);1217 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);1218 struct sas_internal *i = to_sas_internal(shost->transportt);1219 u64 identifier;1220 int error;1221 1222 error = i->f->get_enclosure_identifier(rphy, &identifier);1223 if (error)1224 return error;1225 return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);1226}1227 1228static SAS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,1229 show_sas_rphy_enclosure_identifier, NULL);1230 1231static ssize_t1232show_sas_rphy_bay_identifier(struct device *dev,1233 struct device_attribute *attr, char *buf)1234{1235 struct sas_rphy *rphy = transport_class_to_rphy(dev);1236 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);1237 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);1238 struct sas_internal *i = to_sas_internal(shost->transportt);1239 int val;1240 1241 val = i->f->get_bay_identifier(rphy);1242 if (val < 0)1243 return val;1244 return sprintf(buf, "%d\n", val);1245}1246 1247static SAS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,1248 show_sas_rphy_bay_identifier, NULL);1249 1250sas_rphy_protocol_attr(identify.initiator_port_protocols,1251 initiator_port_protocols);1252sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);1253sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",1254 unsigned long long);1255sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);1256sas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d\n", u32);1257 1258/* only need 8 bytes of data plus header (4 or 8) */1259#define BUF_SIZE 641260 1261int sas_read_port_mode_page(struct scsi_device *sdev)1262{1263 char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;1264 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);1265 struct scsi_mode_data mode_data;1266 int error;1267 1268 if (!buffer)1269 return -ENOMEM;1270 1271 error = scsi_mode_sense(sdev, 1, 0x19, 0, buffer, BUF_SIZE, 30*HZ, 3,1272 &mode_data, NULL);1273 1274 if (error)1275 goto out;1276 1277 msdata = buffer + mode_data.header_length +1278 mode_data.block_descriptor_length;1279 1280 if (msdata - buffer > BUF_SIZE - 8)1281 goto out;1282 1283 error = 0;1284 1285 rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;1286 rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];1287 rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];1288 1289 out:1290 kfree(buffer);1291 return error;1292}1293EXPORT_SYMBOL(sas_read_port_mode_page);1294 1295static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,1296 "sas_end_device", NULL, NULL, NULL);1297 1298#define sas_end_dev_show_simple(field, name, format_string, cast) \1299static ssize_t \1300show_sas_end_dev_##name(struct device *dev, \1301 struct device_attribute *attr, char *buf) \1302{ \1303 struct sas_rphy *rphy = transport_class_to_rphy(dev); \1304 struct sas_end_device *rdev = rphy_to_end_device(rphy); \1305 \1306 return snprintf(buf, 20, format_string, cast rdev->field); \1307}1308 1309#define sas_end_dev_simple_attr(field, name, format_string, type) \1310 sas_end_dev_show_simple(field, name, format_string, (type)) \1311static SAS_DEVICE_ATTR(end_dev, name, S_IRUGO, \1312 show_sas_end_dev_##name, NULL)1313 1314sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);1315sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,1316 "%d\n", int);1317sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,1318 "%d\n", int);1319sas_end_dev_simple_attr(tlr_supported, tlr_supported,1320 "%d\n", int);1321sas_end_dev_simple_attr(tlr_enabled, tlr_enabled,1322 "%d\n", int);1323 1324static DECLARE_TRANSPORT_CLASS(sas_expander_class,1325 "sas_expander", NULL, NULL, NULL);1326 1327#define sas_expander_show_simple(field, name, format_string, cast) \1328static ssize_t \1329show_sas_expander_##name(struct device *dev, \1330 struct device_attribute *attr, char *buf) \1331{ \1332 struct sas_rphy *rphy = transport_class_to_rphy(dev); \1333 struct sas_expander_device *edev = rphy_to_expander_device(rphy); \1334 \1335 return snprintf(buf, 20, format_string, cast edev->field); \1336}1337 1338#define sas_expander_simple_attr(field, name, format_string, type) \1339 sas_expander_show_simple(field, name, format_string, (type)) \1340static SAS_DEVICE_ATTR(expander, name, S_IRUGO, \1341 show_sas_expander_##name, NULL)1342 1343sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);1344sas_expander_simple_attr(product_id, product_id, "%s\n", char *);1345sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);1346sas_expander_simple_attr(component_vendor_id, component_vendor_id,1347 "%s\n", char *);1348sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);1349sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",1350 unsigned int);1351sas_expander_simple_attr(level, level, "%d\n", int);1352 1353static DECLARE_TRANSPORT_CLASS(sas_rphy_class,1354 "sas_device", NULL, NULL, NULL);1355 1356static int sas_rphy_match(struct attribute_container *cont, struct device *dev)1357{1358 struct Scsi_Host *shost;1359 struct sas_internal *i;1360 1361 if (!scsi_is_sas_rphy(dev))1362 return 0;1363 shost = dev_to_shost(dev->parent->parent);1364 1365 if (!shost->transportt)1366 return 0;1367 if (shost->transportt->host_attrs.ac.class !=1368 &sas_host_class.class)1369 return 0;1370 1371 i = to_sas_internal(shost->transportt);1372 return &i->rphy_attr_cont.ac == cont;1373}1374 1375static int sas_end_dev_match(struct attribute_container *cont,1376 struct device *dev)1377{1378 struct Scsi_Host *shost;1379 struct sas_internal *i;1380 struct sas_rphy *rphy;1381 1382 if (!scsi_is_sas_rphy(dev))1383 return 0;1384 shost = dev_to_shost(dev->parent->parent);1385 rphy = dev_to_rphy(dev);1386 1387 if (!shost->transportt)1388 return 0;1389 if (shost->transportt->host_attrs.ac.class !=1390 &sas_host_class.class)1391 return 0;1392 1393 i = to_sas_internal(shost->transportt);1394 return &i->end_dev_attr_cont.ac == cont &&1395 rphy->identify.device_type == SAS_END_DEVICE;1396}1397 1398static int sas_expander_match(struct attribute_container *cont,1399 struct device *dev)1400{1401 struct Scsi_Host *shost;1402 struct sas_internal *i;1403 struct sas_rphy *rphy;1404 1405 if (!scsi_is_sas_rphy(dev))1406 return 0;1407 shost = dev_to_shost(dev->parent->parent);1408 rphy = dev_to_rphy(dev);1409 1410 if (!shost->transportt)1411 return 0;1412 if (shost->transportt->host_attrs.ac.class !=1413 &sas_host_class.class)1414 return 0;1415 1416 i = to_sas_internal(shost->transportt);1417 return &i->expander_attr_cont.ac == cont &&1418 (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||1419 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);1420}1421 1422static void sas_expander_release(struct device *dev)1423{1424 struct sas_rphy *rphy = dev_to_rphy(dev);1425 struct sas_expander_device *edev = rphy_to_expander_device(rphy);1426 1427 put_device(dev->parent);1428 kfree(edev);1429}1430 1431static void sas_end_device_release(struct device *dev)1432{1433 struct sas_rphy *rphy = dev_to_rphy(dev);1434 struct sas_end_device *edev = rphy_to_end_device(rphy);1435 1436 put_device(dev->parent);1437 kfree(edev);1438}1439 1440/**1441 * sas_rphy_initialize - common rphy initialization1442 * @rphy: rphy to initialise1443 *1444 * Used by both sas_end_device_alloc() and sas_expander_alloc() to1445 * initialise the common rphy component of each.1446 */1447static void sas_rphy_initialize(struct sas_rphy *rphy)1448{1449 INIT_LIST_HEAD(&rphy->list);1450}1451 1452/**1453 * sas_end_device_alloc - allocate an rphy for an end device1454 * @parent: which port1455 *1456 * Allocates an SAS remote PHY structure, connected to @parent.1457 *1458 * Returns:1459 * SAS PHY allocated or %NULL if the allocation failed.1460 */1461struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)1462{1463 struct Scsi_Host *shost = dev_to_shost(&parent->dev);1464 struct sas_end_device *rdev;1465 1466 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);1467 if (!rdev) {1468 return NULL;1469 }1470 1471 device_initialize(&rdev->rphy.dev);1472 rdev->rphy.dev.parent = get_device(&parent->dev);1473 rdev->rphy.dev.release = sas_end_device_release;1474 if (scsi_is_sas_expander_device(parent->dev.parent)) {1475 struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);1476 dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d",1477 shost->host_no, rphy->scsi_target_id,1478 parent->port_identifier);1479 } else1480 dev_set_name(&rdev->rphy.dev, "end_device-%d:%d",1481 shost->host_no, parent->port_identifier);1482 rdev->rphy.identify.device_type = SAS_END_DEVICE;1483 sas_rphy_initialize(&rdev->rphy);1484 transport_setup_device(&rdev->rphy.dev);1485 1486 return &rdev->rphy;1487}1488EXPORT_SYMBOL(sas_end_device_alloc);1489 1490/**1491 * sas_expander_alloc - allocate an rphy for an end device1492 * @parent: which port1493 * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE1494 *1495 * Allocates an SAS remote PHY structure, connected to @parent.1496 *1497 * Returns:1498 * SAS PHY allocated or %NULL if the allocation failed.1499 */1500struct sas_rphy *sas_expander_alloc(struct sas_port *parent,1501 enum sas_device_type type)1502{1503 struct Scsi_Host *shost = dev_to_shost(&parent->dev);1504 struct sas_expander_device *rdev;1505 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);1506 1507 BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&1508 type != SAS_FANOUT_EXPANDER_DEVICE);1509 1510 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);1511 if (!rdev) {1512 return NULL;1513 }1514 1515 device_initialize(&rdev->rphy.dev);1516 rdev->rphy.dev.parent = get_device(&parent->dev);1517 rdev->rphy.dev.release = sas_expander_release;1518 mutex_lock(&sas_host->lock);1519 rdev->rphy.scsi_target_id = sas_host->next_expander_id++;1520 mutex_unlock(&sas_host->lock);1521 dev_set_name(&rdev->rphy.dev, "expander-%d:%d",1522 shost->host_no, rdev->rphy.scsi_target_id);1523 rdev->rphy.identify.device_type = type;1524 sas_rphy_initialize(&rdev->rphy);1525 transport_setup_device(&rdev->rphy.dev);1526 1527 return &rdev->rphy;1528}1529EXPORT_SYMBOL(sas_expander_alloc);1530 1531/**1532 * sas_rphy_add - add a SAS remote PHY to the device hierarchy1533 * @rphy: The remote PHY to be added1534 *1535 * Publishes a SAS remote PHY to the rest of the system.1536 */1537int sas_rphy_add(struct sas_rphy *rphy)1538{1539 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);1540 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);1541 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);1542 struct sas_identify *identify = &rphy->identify;1543 int error;1544 1545 if (parent->rphy)1546 return -ENXIO;1547 parent->rphy = rphy;1548 1549 error = device_add(&rphy->dev);1550 if (error)1551 return error;1552 transport_add_device(&rphy->dev);1553 transport_configure_device(&rphy->dev);1554 if (sas_bsg_initialize(shost, rphy))1555 printk("fail to a bsg device %s\n", dev_name(&rphy->dev));1556 1557 1558 mutex_lock(&sas_host->lock);1559 list_add_tail(&rphy->list, &sas_host->rphy_list);1560 if (identify->device_type == SAS_END_DEVICE &&1561 (identify->target_port_protocols &1562 (SAS_PROTOCOL_SSP | SAS_PROTOCOL_STP | SAS_PROTOCOL_SATA)))1563 rphy->scsi_target_id = sas_host->next_target_id++;1564 else if (identify->device_type == SAS_END_DEVICE)1565 rphy->scsi_target_id = -1;1566 mutex_unlock(&sas_host->lock);1567 1568 if (identify->device_type == SAS_END_DEVICE &&1569 rphy->scsi_target_id != -1) {1570 int lun;1571 1572 if (identify->target_port_protocols & SAS_PROTOCOL_SSP)1573 lun = SCAN_WILD_CARD;1574 else1575 lun = 0;1576 1577 scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun,1578 SCSI_SCAN_INITIAL);1579 }1580 1581 return 0;1582}1583EXPORT_SYMBOL(sas_rphy_add);1584 1585/**1586 * sas_rphy_free - free a SAS remote PHY1587 * @rphy: SAS remote PHY to free1588 *1589 * Frees the specified SAS remote PHY.1590 *1591 * Note:1592 * This function must only be called on a remote1593 * PHY that has not successfully been added using1594 * sas_rphy_add() (or has been sas_rphy_remove()'d)1595 */1596void sas_rphy_free(struct sas_rphy *rphy)1597{1598 struct device *dev = &rphy->dev;1599 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);1600 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);1601 1602 mutex_lock(&sas_host->lock);1603 list_del(&rphy->list);1604 mutex_unlock(&sas_host->lock);1605 1606 transport_destroy_device(dev);1607 1608 put_device(dev);1609}1610EXPORT_SYMBOL(sas_rphy_free);1611 1612/**1613 * sas_rphy_delete - remove and free SAS remote PHY1614 * @rphy: SAS remote PHY to remove and free1615 *1616 * Removes the specified SAS remote PHY and frees it.1617 */1618void1619sas_rphy_delete(struct sas_rphy *rphy)1620{1621 sas_rphy_remove(rphy);1622 sas_rphy_free(rphy);1623}1624EXPORT_SYMBOL(sas_rphy_delete);1625 1626/**1627 * sas_rphy_unlink - unlink SAS remote PHY1628 * @rphy: SAS remote phy to unlink from its parent port1629 *1630 * Removes port reference to an rphy1631 */1632void sas_rphy_unlink(struct sas_rphy *rphy)1633{1634 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);1635 1636 parent->rphy = NULL;1637}1638EXPORT_SYMBOL(sas_rphy_unlink);1639 1640/**1641 * sas_rphy_remove - remove SAS remote PHY1642 * @rphy: SAS remote phy to remove1643 *1644 * Removes the specified SAS remote PHY.1645 */1646void1647sas_rphy_remove(struct sas_rphy *rphy)1648{1649 struct device *dev = &rphy->dev;1650 1651 switch (rphy->identify.device_type) {1652 case SAS_END_DEVICE:1653 scsi_remove_target(dev);1654 break;1655 case SAS_EDGE_EXPANDER_DEVICE:1656 case SAS_FANOUT_EXPANDER_DEVICE:1657 sas_remove_children(dev);1658 break;1659 default:1660 break;1661 }1662 1663 sas_rphy_unlink(rphy);1664 bsg_remove_queue(rphy->q);1665 transport_remove_device(dev);1666 device_del(dev);1667}1668EXPORT_SYMBOL(sas_rphy_remove);1669 1670/**1671 * scsi_is_sas_rphy - check if a struct device represents a SAS remote PHY1672 * @dev: device to check1673 *1674 * Returns:1675 * %1 if the device represents a SAS remote PHY, %0 else1676 */1677int scsi_is_sas_rphy(const struct device *dev)1678{1679 return dev->release == sas_end_device_release ||1680 dev->release == sas_expander_release;1681}1682EXPORT_SYMBOL(scsi_is_sas_rphy);1683 1684 1685/*1686 * SCSI scan helper1687 */1688 1689static int sas_user_scan(struct Scsi_Host *shost, uint channel,1690 uint id, u64 lun)1691{1692 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);1693 struct sas_rphy *rphy;1694 1695 mutex_lock(&sas_host->lock);1696 list_for_each_entry(rphy, &sas_host->rphy_list, list) {1697 if (rphy->identify.device_type != SAS_END_DEVICE ||1698 rphy->scsi_target_id == -1)1699 continue;1700 1701 if ((channel == SCAN_WILD_CARD || channel == 0) &&1702 (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {1703 scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,1704 lun, SCSI_SCAN_MANUAL);1705 }1706 }1707 mutex_unlock(&sas_host->lock);1708 1709 return 0;1710}1711 1712 1713/*1714 * Setup / Teardown code1715 */1716 1717#define SETUP_TEMPLATE(attrb, field, perm, test) \1718 i->private_##attrb[count] = dev_attr_##field; \1719 i->private_##attrb[count].attr.mode = perm; \1720 i->attrb[count] = &i->private_##attrb[count]; \1721 if (test) \1722 count++1723 1724#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \1725 i->private_##attrb[count] = dev_attr_##field; \1726 i->private_##attrb[count].attr.mode = perm; \1727 if (ro_test) { \1728 i->private_##attrb[count].attr.mode = ro_perm; \1729 i->private_##attrb[count].store = NULL; \1730 } \1731 i->attrb[count] = &i->private_##attrb[count]; \1732 if (test) \1733 count++1734 1735#define SETUP_RPORT_ATTRIBUTE(field) \1736 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)1737 1738#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \1739 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)1740 1741#define SETUP_PHY_ATTRIBUTE(field) \1742 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)1743 1744#define SETUP_PHY_ATTRIBUTE_RW(field) \1745 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \1746 !i->f->set_phy_speed, S_IRUGO)1747 1748#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \1749 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \1750 !i->f->func, S_IRUGO)1751 1752#define SETUP_PORT_ATTRIBUTE(field) \1753 SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)1754 1755#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \1756 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)1757 1758#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \1759 SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1)1760 1761#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \1762 SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func)1763 1764#define SETUP_END_DEV_ATTRIBUTE(field) \1765 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)1766 1767#define SETUP_EXPANDER_ATTRIBUTE(field) \1768 SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)1769 1770/**1771 * sas_attach_transport - instantiate SAS transport template1772 * @ft: SAS transport class function template1773 */1774struct scsi_transport_template *1775sas_attach_transport(struct sas_function_template *ft)1776{1777 struct sas_internal *i;1778 int count;1779 1780 i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);1781 if (!i)1782 return NULL;1783 1784 i->t.user_scan = sas_user_scan;1785 1786 i->t.host_attrs.ac.attrs = &i->host_attrs[0];1787 i->t.host_attrs.ac.class = &sas_host_class.class;1788 i->t.host_attrs.ac.match = sas_host_match;1789 transport_container_register(&i->t.host_attrs);1790 i->t.host_size = sizeof(struct sas_host_attrs);1791 1792 i->phy_attr_cont.ac.class = &sas_phy_class.class;1793 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];1794 i->phy_attr_cont.ac.match = sas_phy_match;1795 transport_container_register(&i->phy_attr_cont);1796 1797 i->port_attr_cont.ac.class = &sas_port_class.class;1798 i->port_attr_cont.ac.attrs = &i->port_attrs[0];1799 i->port_attr_cont.ac.match = sas_port_match;1800 transport_container_register(&i->port_attr_cont);1801 1802 i->rphy_attr_cont.ac.class = &sas_rphy_class.class;1803 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];1804 i->rphy_attr_cont.ac.match = sas_rphy_match;1805 transport_container_register(&i->rphy_attr_cont);1806 1807 i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;1808 i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];1809 i->end_dev_attr_cont.ac.match = sas_end_dev_match;1810 transport_container_register(&i->end_dev_attr_cont);1811 1812 i->expander_attr_cont.ac.class = &sas_expander_class.class;1813 i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];1814 i->expander_attr_cont.ac.match = sas_expander_match;1815 transport_container_register(&i->expander_attr_cont);1816 1817 i->f = ft;1818 1819 count = 0;1820 SETUP_PHY_ATTRIBUTE(initiator_port_protocols);1821 SETUP_PHY_ATTRIBUTE(target_port_protocols);1822 SETUP_PHY_ATTRIBUTE(device_type);1823 SETUP_PHY_ATTRIBUTE(sas_address);1824 SETUP_PHY_ATTRIBUTE(phy_identifier);1825 SETUP_PHY_ATTRIBUTE(negotiated_linkrate);1826 SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);1827 SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);1828 SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);1829 SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);1830 1831 SETUP_PHY_ATTRIBUTE(invalid_dword_count);1832 SETUP_PHY_ATTRIBUTE(running_disparity_error_count);1833 SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);1834 SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);1835 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);1836 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);1837 SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);1838 i->phy_attrs[count] = NULL;1839 1840 count = 0;1841 SETUP_PORT_ATTRIBUTE(num_phys);1842 i->port_attrs[count] = NULL;1843 1844 count = 0;1845 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);1846 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);1847 SETUP_RPORT_ATTRIBUTE(rphy_device_type);1848 SETUP_RPORT_ATTRIBUTE(rphy_sas_address);1849 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);1850 SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);1851 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,1852 get_enclosure_identifier);1853 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,1854 get_bay_identifier);1855 i->rphy_attrs[count] = NULL;1856 1857 count = 0;1858 SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);1859 SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);1860 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);1861 SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);1862 SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);1863 i->end_dev_attrs[count] = NULL;1864 1865 count = 0;1866 SETUP_EXPANDER_ATTRIBUTE(vendor_id);1867 SETUP_EXPANDER_ATTRIBUTE(product_id);1868 SETUP_EXPANDER_ATTRIBUTE(product_rev);1869 SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);1870 SETUP_EXPANDER_ATTRIBUTE(component_id);1871 SETUP_EXPANDER_ATTRIBUTE(component_revision_id);1872 SETUP_EXPANDER_ATTRIBUTE(level);1873 i->expander_attrs[count] = NULL;1874 1875 return &i->t;1876}1877EXPORT_SYMBOL(sas_attach_transport);1878 1879/**1880 * sas_release_transport - release SAS transport template instance1881 * @t: transport template instance1882 */1883void sas_release_transport(struct scsi_transport_template *t)1884{1885 struct sas_internal *i = to_sas_internal(t);1886 1887 transport_container_unregister(&i->t.host_attrs);1888 transport_container_unregister(&i->phy_attr_cont);1889 transport_container_unregister(&i->port_attr_cont);1890 transport_container_unregister(&i->rphy_attr_cont);1891 transport_container_unregister(&i->end_dev_attr_cont);1892 transport_container_unregister(&i->expander_attr_cont);1893 1894 kfree(i);1895}1896EXPORT_SYMBOL(sas_release_transport);1897 1898static __init int sas_transport_init(void)1899{1900 int error;1901 1902 error = transport_class_register(&sas_host_class);1903 if (error)1904 goto out;1905 error = transport_class_register(&sas_phy_class);1906 if (error)1907 goto out_unregister_transport;1908 error = transport_class_register(&sas_port_class);1909 if (error)1910 goto out_unregister_phy;1911 error = transport_class_register(&sas_rphy_class);1912 if (error)1913 goto out_unregister_port;1914 error = transport_class_register(&sas_end_dev_class);1915 if (error)1916 goto out_unregister_rphy;1917 error = transport_class_register(&sas_expander_class);1918 if (error)1919 goto out_unregister_end_dev;1920 1921 return 0;1922 1923 out_unregister_end_dev:1924 transport_class_unregister(&sas_end_dev_class);1925 out_unregister_rphy:1926 transport_class_unregister(&sas_rphy_class);1927 out_unregister_port:1928 transport_class_unregister(&sas_port_class);1929 out_unregister_phy:1930 transport_class_unregister(&sas_phy_class);1931 out_unregister_transport:1932 transport_class_unregister(&sas_host_class);1933 out:1934 return error;1935 1936}1937 1938static void __exit sas_transport_exit(void)1939{1940 transport_class_unregister(&sas_host_class);1941 transport_class_unregister(&sas_phy_class);1942 transport_class_unregister(&sas_port_class);1943 transport_class_unregister(&sas_rphy_class);1944 transport_class_unregister(&sas_end_dev_class);1945 transport_class_unregister(&sas_expander_class);1946}1947 1948MODULE_AUTHOR("Christoph Hellwig");1949MODULE_DESCRIPTION("SAS Transport Attributes");1950MODULE_LICENSE("GPL");1951 1952module_init(sas_transport_init);1953module_exit(sas_transport_exit);1954