scsi_transport_sas.c revision 9f434d4f84a235f6b61aec6e691d6b07bc46fc24
1/* 2 * Copyright (C) 2005-2006 Dell Inc. 3 * Released under GPL v2. 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 managment 10 * interfaces to userspace. 11 * 12 * In addition to the basic SCSI core objects this transport class 13 * introduces two additional intermediate objects: The SAS PHY 14 * as represented by struct sas_phy defines an "outgoing" PHY on 15 * a SAS HBA or Expander, and the SAS remote PHY represented by 16 * struct sas_rphy defines an "incoming" PHY on a SAS Expander or 17 * end device. Note that this is purely a software concept, the 18 * underlying hardware for a PHY and a remote PHY is the exactly 19 * the same. 20 * 21 * There is no concept of a SAS port in this code, users can see 22 * 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/err.h> 29#include <linux/slab.h> 30#include <linux/string.h> 31 32#include <scsi/scsi.h> 33#include <scsi/scsi_device.h> 34#include <scsi/scsi_host.h> 35#include <scsi/scsi_transport.h> 36#include <scsi/scsi_transport_sas.h> 37 38#include "scsi_sas_internal.h" 39struct sas_host_attrs { 40 struct list_head rphy_list; 41 struct mutex lock; 42 u32 next_target_id; 43 u32 next_expander_id; 44}; 45#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 46 47 48/* 49 * Hack to allow attributes of the same name in different objects. 50 */ 51#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ 52 struct class_device_attribute class_device_attr_##_prefix##_##_name = \ 53 __ATTR(_name,_mode,_show,_store) 54 55 56/* 57 * Pretty printing helpers 58 */ 59 60#define sas_bitfield_name_match(title, table) \ 61static ssize_t \ 62get_sas_##title##_names(u32 table_key, char *buf) \ 63{ \ 64 char *prefix = ""; \ 65 ssize_t len = 0; \ 66 int i; \ 67 \ 68 for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 69 if (table[i].value & table_key) { \ 70 len += sprintf(buf + len, "%s%s", \ 71 prefix, table[i].name); \ 72 prefix = ", "; \ 73 } \ 74 } \ 75 len += sprintf(buf + len, "\n"); \ 76 return len; \ 77} 78 79#define sas_bitfield_name_search(title, table) \ 80static ssize_t \ 81get_sas_##title##_names(u32 table_key, char *buf) \ 82{ \ 83 ssize_t len = 0; \ 84 int i; \ 85 \ 86 for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 87 if (table[i].value == table_key) { \ 88 len += sprintf(buf + len, "%s", \ 89 table[i].name); \ 90 break; \ 91 } \ 92 } \ 93 len += sprintf(buf + len, "\n"); \ 94 return len; \ 95} 96 97static struct { 98 u32 value; 99 char *name; 100} sas_device_type_names[] = { 101 { SAS_PHY_UNUSED, "unused" }, 102 { SAS_END_DEVICE, "end device" }, 103 { SAS_EDGE_EXPANDER_DEVICE, "edge expander" }, 104 { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" }, 105}; 106sas_bitfield_name_search(device_type, sas_device_type_names) 107 108 109static struct { 110 u32 value; 111 char *name; 112} sas_protocol_names[] = { 113 { SAS_PROTOCOL_SATA, "sata" }, 114 { SAS_PROTOCOL_SMP, "smp" }, 115 { SAS_PROTOCOL_STP, "stp" }, 116 { SAS_PROTOCOL_SSP, "ssp" }, 117}; 118sas_bitfield_name_match(protocol, sas_protocol_names) 119 120static struct { 121 u32 value; 122 char *name; 123} sas_linkspeed_names[] = { 124 { SAS_LINK_RATE_UNKNOWN, "Unknown" }, 125 { SAS_PHY_DISABLED, "Phy disabled" }, 126 { SAS_LINK_RATE_FAILED, "Link Rate failed" }, 127 { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, 128 { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 129 { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 130 { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, 131}; 132sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 133 134 135/* 136 * SAS host attributes 137 */ 138 139static int sas_host_setup(struct transport_container *tc, struct device *dev, 140 struct class_device *cdev) 141{ 142 struct Scsi_Host *shost = dev_to_shost(dev); 143 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 144 145 INIT_LIST_HEAD(&sas_host->rphy_list); 146 mutex_init(&sas_host->lock); 147 sas_host->next_target_id = 0; 148 sas_host->next_expander_id = 0; 149 return 0; 150} 151 152static DECLARE_TRANSPORT_CLASS(sas_host_class, 153 "sas_host", sas_host_setup, NULL, NULL); 154 155static int sas_host_match(struct attribute_container *cont, 156 struct device *dev) 157{ 158 struct Scsi_Host *shost; 159 struct sas_internal *i; 160 161 if (!scsi_is_host_device(dev)) 162 return 0; 163 shost = dev_to_shost(dev); 164 165 if (!shost->transportt) 166 return 0; 167 if (shost->transportt->host_attrs.ac.class != 168 &sas_host_class.class) 169 return 0; 170 171 i = to_sas_internal(shost->transportt); 172 return &i->t.host_attrs.ac == cont; 173} 174 175static int do_sas_phy_delete(struct device *dev, void *data) 176{ 177 if (scsi_is_sas_phy(dev)) 178 sas_phy_delete(dev_to_phy(dev)); 179 return 0; 180} 181 182/** 183 * sas_remove_host -- tear down a Scsi_Host's SAS data structures 184 * @shost: Scsi Host that is torn down 185 * 186 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 187 * Must be called just before scsi_remove_host for SAS HBAs. 188 */ 189void sas_remove_host(struct Scsi_Host *shost) 190{ 191 device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); 192} 193EXPORT_SYMBOL(sas_remove_host); 194 195 196/* 197 * SAS Port attributes 198 */ 199 200#define sas_phy_show_simple(field, name, format_string, cast) \ 201static ssize_t \ 202show_sas_phy_##name(struct class_device *cdev, char *buf) \ 203{ \ 204 struct sas_phy *phy = transport_class_to_phy(cdev); \ 205 \ 206 return snprintf(buf, 20, format_string, cast phy->field); \ 207} 208 209#define sas_phy_simple_attr(field, name, format_string, type) \ 210 sas_phy_show_simple(field, name, format_string, (type)) \ 211static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 212 213#define sas_phy_show_protocol(field, name) \ 214static ssize_t \ 215show_sas_phy_##name(struct class_device *cdev, char *buf) \ 216{ \ 217 struct sas_phy *phy = transport_class_to_phy(cdev); \ 218 \ 219 if (!phy->field) \ 220 return snprintf(buf, 20, "none\n"); \ 221 return get_sas_protocol_names(phy->field, buf); \ 222} 223 224#define sas_phy_protocol_attr(field, name) \ 225 sas_phy_show_protocol(field, name) \ 226static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 227 228#define sas_phy_show_linkspeed(field) \ 229static ssize_t \ 230show_sas_phy_##field(struct class_device *cdev, char *buf) \ 231{ \ 232 struct sas_phy *phy = transport_class_to_phy(cdev); \ 233 \ 234 return get_sas_linkspeed_names(phy->field, buf); \ 235} 236 237#define sas_phy_linkspeed_attr(field) \ 238 sas_phy_show_linkspeed(field) \ 239static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 240 241#define sas_phy_show_linkerror(field) \ 242static ssize_t \ 243show_sas_phy_##field(struct class_device *cdev, char *buf) \ 244{ \ 245 struct sas_phy *phy = transport_class_to_phy(cdev); \ 246 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 247 struct sas_internal *i = to_sas_internal(shost->transportt); \ 248 int error; \ 249 \ 250 if (!phy->local_attached) \ 251 return -EINVAL; \ 252 \ 253 error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ 254 if (error) \ 255 return error; \ 256 return snprintf(buf, 20, "%u\n", phy->field); \ 257} 258 259#define sas_phy_linkerror_attr(field) \ 260 sas_phy_show_linkerror(field) \ 261static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 262 263 264static ssize_t 265show_sas_device_type(struct class_device *cdev, char *buf) 266{ 267 struct sas_phy *phy = transport_class_to_phy(cdev); 268 269 if (!phy->identify.device_type) 270 return snprintf(buf, 20, "none\n"); 271 return get_sas_device_type_names(phy->identify.device_type, buf); 272} 273static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 274 275static ssize_t do_sas_phy_reset(struct class_device *cdev, 276 size_t count, int hard_reset) 277{ 278 struct sas_phy *phy = transport_class_to_phy(cdev); 279 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 280 struct sas_internal *i = to_sas_internal(shost->transportt); 281 int error; 282 283 if (!phy->local_attached) 284 return -EINVAL; 285 286 error = i->f->phy_reset(phy, hard_reset); 287 if (error) 288 return error; 289 return count; 290}; 291 292static ssize_t store_sas_link_reset(struct class_device *cdev, 293 const char *buf, size_t count) 294{ 295 return do_sas_phy_reset(cdev, count, 0); 296} 297static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 298 299static ssize_t store_sas_hard_reset(struct class_device *cdev, 300 const char *buf, size_t count) 301{ 302 return do_sas_phy_reset(cdev, count, 1); 303} 304static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 305 306sas_phy_protocol_attr(identify.initiator_port_protocols, 307 initiator_port_protocols); 308sas_phy_protocol_attr(identify.target_port_protocols, 309 target_port_protocols); 310sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 311 unsigned long long); 312sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 313sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); 314sas_phy_linkspeed_attr(negotiated_linkrate); 315sas_phy_linkspeed_attr(minimum_linkrate_hw); 316sas_phy_linkspeed_attr(minimum_linkrate); 317sas_phy_linkspeed_attr(maximum_linkrate_hw); 318sas_phy_linkspeed_attr(maximum_linkrate); 319sas_phy_linkerror_attr(invalid_dword_count); 320sas_phy_linkerror_attr(running_disparity_error_count); 321sas_phy_linkerror_attr(loss_of_dword_sync_count); 322sas_phy_linkerror_attr(phy_reset_problem_count); 323 324 325static DECLARE_TRANSPORT_CLASS(sas_phy_class, 326 "sas_phy", NULL, NULL, NULL); 327 328static int sas_phy_match(struct attribute_container *cont, struct device *dev) 329{ 330 struct Scsi_Host *shost; 331 struct sas_internal *i; 332 333 if (!scsi_is_sas_phy(dev)) 334 return 0; 335 shost = dev_to_shost(dev->parent); 336 337 if (!shost->transportt) 338 return 0; 339 if (shost->transportt->host_attrs.ac.class != 340 &sas_host_class.class) 341 return 0; 342 343 i = to_sas_internal(shost->transportt); 344 return &i->phy_attr_cont.ac == cont; 345} 346 347static void sas_phy_release(struct device *dev) 348{ 349 struct sas_phy *phy = dev_to_phy(dev); 350 351 put_device(dev->parent); 352 kfree(phy); 353} 354 355/** 356 * sas_phy_alloc -- allocates and initialize a SAS PHY structure 357 * @parent: Parent device 358 * @number: Phy index 359 * 360 * Allocates an SAS PHY structure. It will be added in the device tree 361 * below the device specified by @parent, which has to be either a Scsi_Host 362 * or sas_rphy. 363 * 364 * Returns: 365 * SAS PHY allocated or %NULL if the allocation failed. 366 */ 367struct sas_phy *sas_phy_alloc(struct device *parent, int number) 368{ 369 struct Scsi_Host *shost = dev_to_shost(parent); 370 struct sas_phy *phy; 371 372 phy = kzalloc(sizeof(*phy), GFP_KERNEL); 373 if (!phy) 374 return NULL; 375 376 phy->number = number; 377 378 device_initialize(&phy->dev); 379 phy->dev.parent = get_device(parent); 380 phy->dev.release = sas_phy_release; 381 if (scsi_is_sas_expander_device(parent)) { 382 struct sas_rphy *rphy = dev_to_rphy(parent); 383 sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no, 384 rphy->scsi_target_id, number); 385 } else 386 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 387 388 transport_setup_device(&phy->dev); 389 390 return phy; 391} 392EXPORT_SYMBOL(sas_phy_alloc); 393 394/** 395 * sas_phy_add -- add a SAS PHY to the device hierachy 396 * @phy: The PHY to be added 397 * 398 * Publishes a SAS PHY to the rest of the system. 399 */ 400int sas_phy_add(struct sas_phy *phy) 401{ 402 int error; 403 404 error = device_add(&phy->dev); 405 if (!error) { 406 transport_add_device(&phy->dev); 407 transport_configure_device(&phy->dev); 408 } 409 410 return error; 411} 412EXPORT_SYMBOL(sas_phy_add); 413 414/** 415 * sas_phy_free -- free a SAS PHY 416 * @phy: SAS PHY to free 417 * 418 * Frees the specified SAS PHY. 419 * 420 * Note: 421 * This function must only be called on a PHY that has not 422 * sucessfully been added using sas_phy_add(). 423 */ 424void sas_phy_free(struct sas_phy *phy) 425{ 426 transport_destroy_device(&phy->dev); 427 put_device(&phy->dev); 428} 429EXPORT_SYMBOL(sas_phy_free); 430 431/** 432 * sas_phy_delete -- remove SAS PHY 433 * @phy: SAS PHY to remove 434 * 435 * Removes the specified SAS PHY. If the SAS PHY has an 436 * associated remote PHY it is removed before. 437 */ 438void 439sas_phy_delete(struct sas_phy *phy) 440{ 441 struct device *dev = &phy->dev; 442 443 if (phy->rphy) 444 sas_rphy_delete(phy->rphy); 445 446 transport_remove_device(dev); 447 device_del(dev); 448 transport_destroy_device(dev); 449 put_device(dev); 450} 451EXPORT_SYMBOL(sas_phy_delete); 452 453/** 454 * scsi_is_sas_phy -- check if a struct device represents a SAS PHY 455 * @dev: device to check 456 * 457 * Returns: 458 * %1 if the device represents a SAS PHY, %0 else 459 */ 460int scsi_is_sas_phy(const struct device *dev) 461{ 462 return dev->release == sas_phy_release; 463} 464EXPORT_SYMBOL(scsi_is_sas_phy); 465 466/* 467 * SAS remote PHY attributes. 468 */ 469 470#define sas_rphy_show_simple(field, name, format_string, cast) \ 471static ssize_t \ 472show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 473{ \ 474 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 475 \ 476 return snprintf(buf, 20, format_string, cast rphy->field); \ 477} 478 479#define sas_rphy_simple_attr(field, name, format_string, type) \ 480 sas_rphy_show_simple(field, name, format_string, (type)) \ 481static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 482 show_sas_rphy_##name, NULL) 483 484#define sas_rphy_show_protocol(field, name) \ 485static ssize_t \ 486show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 487{ \ 488 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 489 \ 490 if (!rphy->field) \ 491 return snprintf(buf, 20, "none\n"); \ 492 return get_sas_protocol_names(rphy->field, buf); \ 493} 494 495#define sas_rphy_protocol_attr(field, name) \ 496 sas_rphy_show_protocol(field, name) \ 497static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 498 show_sas_rphy_##name, NULL) 499 500static ssize_t 501show_sas_rphy_device_type(struct class_device *cdev, char *buf) 502{ 503 struct sas_rphy *rphy = transport_class_to_rphy(cdev); 504 505 if (!rphy->identify.device_type) 506 return snprintf(buf, 20, "none\n"); 507 return get_sas_device_type_names( 508 rphy->identify.device_type, buf); 509} 510 511static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 512 show_sas_rphy_device_type, NULL); 513 514static ssize_t 515show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf) 516{ 517 struct sas_rphy *rphy = transport_class_to_rphy(cdev); 518 struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 519 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 520 struct sas_internal *i = to_sas_internal(shost->transportt); 521 u64 identifier; 522 int error; 523 524 /* 525 * Only devices behind an expander are supported, because the 526 * enclosure identifier is a SMP feature. 527 */ 528 if (phy->local_attached) 529 return -EINVAL; 530 531 error = i->f->get_enclosure_identifier(rphy, &identifier); 532 if (error) 533 return error; 534 return sprintf(buf, "0x%llx\n", (unsigned long long)identifier); 535} 536 537static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO, 538 show_sas_rphy_enclosure_identifier, NULL); 539 540static ssize_t 541show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf) 542{ 543 struct sas_rphy *rphy = transport_class_to_rphy(cdev); 544 struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 545 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 546 struct sas_internal *i = to_sas_internal(shost->transportt); 547 int val; 548 549 if (phy->local_attached) 550 return -EINVAL; 551 552 val = i->f->get_bay_identifier(rphy); 553 if (val < 0) 554 return val; 555 return sprintf(buf, "%d\n", val); 556} 557 558static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO, 559 show_sas_rphy_bay_identifier, NULL); 560 561sas_rphy_protocol_attr(identify.initiator_port_protocols, 562 initiator_port_protocols); 563sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 564sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 565 unsigned long long); 566sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 567 568/* only need 8 bytes of data plus header (4 or 8) */ 569#define BUF_SIZE 64 570 571int sas_read_port_mode_page(struct scsi_device *sdev) 572{ 573 char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; 574 struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); 575 struct sas_end_device *rdev; 576 struct scsi_mode_data mode_data; 577 int res, error; 578 579 BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); 580 581 rdev = rphy_to_end_device(rphy); 582 583 if (!buffer) 584 return -ENOMEM; 585 586 res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3, 587 &mode_data, NULL); 588 589 error = -EINVAL; 590 if (!scsi_status_is_good(res)) 591 goto out; 592 593 msdata = buffer + mode_data.header_length + 594 mode_data.block_descriptor_length; 595 596 if (msdata - buffer > BUF_SIZE - 8) 597 goto out; 598 599 error = 0; 600 601 rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0; 602 rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5]; 603 rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7]; 604 605 out: 606 kfree(buffer); 607 return error; 608} 609EXPORT_SYMBOL(sas_read_port_mode_page); 610 611static DECLARE_TRANSPORT_CLASS(sas_end_dev_class, 612 "sas_end_device", NULL, NULL, NULL); 613 614#define sas_end_dev_show_simple(field, name, format_string, cast) \ 615static ssize_t \ 616show_sas_end_dev_##name(struct class_device *cdev, char *buf) \ 617{ \ 618 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 619 struct sas_end_device *rdev = rphy_to_end_device(rphy); \ 620 \ 621 return snprintf(buf, 20, format_string, cast rdev->field); \ 622} 623 624#define sas_end_dev_simple_attr(field, name, format_string, type) \ 625 sas_end_dev_show_simple(field, name, format_string, (type)) \ 626static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, \ 627 show_sas_end_dev_##name, NULL) 628 629sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int); 630sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, 631 "%d\n", int); 632sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, 633 "%d\n", int); 634 635static DECLARE_TRANSPORT_CLASS(sas_expander_class, 636 "sas_expander", NULL, NULL, NULL); 637 638#define sas_expander_show_simple(field, name, format_string, cast) \ 639static ssize_t \ 640show_sas_expander_##name(struct class_device *cdev, char *buf) \ 641{ \ 642 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 643 struct sas_expander_device *edev = rphy_to_expander_device(rphy); \ 644 \ 645 return snprintf(buf, 20, format_string, cast edev->field); \ 646} 647 648#define sas_expander_simple_attr(field, name, format_string, type) \ 649 sas_expander_show_simple(field, name, format_string, (type)) \ 650static SAS_CLASS_DEVICE_ATTR(expander, name, S_IRUGO, \ 651 show_sas_expander_##name, NULL) 652 653sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *); 654sas_expander_simple_attr(product_id, product_id, "%s\n", char *); 655sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *); 656sas_expander_simple_attr(component_vendor_id, component_vendor_id, 657 "%s\n", char *); 658sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int); 659sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n", 660 unsigned int); 661sas_expander_simple_attr(level, level, "%d\n", int); 662 663static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 664 "sas_device", NULL, NULL, NULL); 665 666static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 667{ 668 struct Scsi_Host *shost; 669 struct sas_internal *i; 670 671 if (!scsi_is_sas_rphy(dev)) 672 return 0; 673 shost = dev_to_shost(dev->parent->parent); 674 675 if (!shost->transportt) 676 return 0; 677 if (shost->transportt->host_attrs.ac.class != 678 &sas_host_class.class) 679 return 0; 680 681 i = to_sas_internal(shost->transportt); 682 return &i->rphy_attr_cont.ac == cont; 683} 684 685static int sas_end_dev_match(struct attribute_container *cont, 686 struct device *dev) 687{ 688 struct Scsi_Host *shost; 689 struct sas_internal *i; 690 struct sas_rphy *rphy; 691 692 if (!scsi_is_sas_rphy(dev)) 693 return 0; 694 shost = dev_to_shost(dev->parent->parent); 695 rphy = dev_to_rphy(dev); 696 697 if (!shost->transportt) 698 return 0; 699 if (shost->transportt->host_attrs.ac.class != 700 &sas_host_class.class) 701 return 0; 702 703 i = to_sas_internal(shost->transportt); 704 return &i->end_dev_attr_cont.ac == cont && 705 rphy->identify.device_type == SAS_END_DEVICE; 706} 707 708static int sas_expander_match(struct attribute_container *cont, 709 struct device *dev) 710{ 711 struct Scsi_Host *shost; 712 struct sas_internal *i; 713 struct sas_rphy *rphy; 714 715 if (!scsi_is_sas_rphy(dev)) 716 return 0; 717 shost = dev_to_shost(dev->parent->parent); 718 rphy = dev_to_rphy(dev); 719 720 if (!shost->transportt) 721 return 0; 722 if (shost->transportt->host_attrs.ac.class != 723 &sas_host_class.class) 724 return 0; 725 726 i = to_sas_internal(shost->transportt); 727 return &i->expander_attr_cont.ac == cont && 728 (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE || 729 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE); 730} 731 732static void sas_expander_release(struct device *dev) 733{ 734 struct sas_rphy *rphy = dev_to_rphy(dev); 735 struct sas_expander_device *edev = rphy_to_expander_device(rphy); 736 737 put_device(dev->parent); 738 kfree(edev); 739} 740 741static void sas_end_device_release(struct device *dev) 742{ 743 struct sas_rphy *rphy = dev_to_rphy(dev); 744 struct sas_end_device *edev = rphy_to_end_device(rphy); 745 746 put_device(dev->parent); 747 kfree(edev); 748} 749 750/** 751 * sas_end_device_alloc - allocate an rphy for an end device 752 * 753 * Allocates an SAS remote PHY structure, connected to @parent. 754 * 755 * Returns: 756 * SAS PHY allocated or %NULL if the allocation failed. 757 */ 758struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) 759{ 760 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 761 struct sas_end_device *rdev; 762 763 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 764 if (!rdev) { 765 return NULL; 766 } 767 768 device_initialize(&rdev->rphy.dev); 769 rdev->rphy.dev.parent = get_device(&parent->dev); 770 rdev->rphy.dev.release = sas_end_device_release; 771 sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d", 772 shost->host_no, parent->port_identifier, parent->number); 773 rdev->rphy.identify.device_type = SAS_END_DEVICE; 774 transport_setup_device(&rdev->rphy.dev); 775 776 return &rdev->rphy; 777} 778EXPORT_SYMBOL(sas_end_device_alloc); 779 780/** 781 * sas_expander_alloc - allocate an rphy for an end device 782 * 783 * Allocates an SAS remote PHY structure, connected to @parent. 784 * 785 * Returns: 786 * SAS PHY allocated or %NULL if the allocation failed. 787 */ 788struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, 789 enum sas_device_type type) 790{ 791 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 792 struct sas_expander_device *rdev; 793 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 794 795 BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE && 796 type != SAS_FANOUT_EXPANDER_DEVICE); 797 798 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 799 if (!rdev) { 800 return NULL; 801 } 802 803 device_initialize(&rdev->rphy.dev); 804 rdev->rphy.dev.parent = get_device(&parent->dev); 805 rdev->rphy.dev.release = sas_expander_release; 806 mutex_lock(&sas_host->lock); 807 rdev->rphy.scsi_target_id = sas_host->next_expander_id++; 808 mutex_unlock(&sas_host->lock); 809 sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d", 810 shost->host_no, rdev->rphy.scsi_target_id); 811 rdev->rphy.identify.device_type = type; 812 transport_setup_device(&rdev->rphy.dev); 813 814 return &rdev->rphy; 815} 816EXPORT_SYMBOL(sas_expander_alloc); 817 818/** 819 * sas_rphy_add -- add a SAS remote PHY to the device hierachy 820 * @rphy: The remote PHY to be added 821 * 822 * Publishes a SAS remote PHY to the rest of the system. 823 */ 824int sas_rphy_add(struct sas_rphy *rphy) 825{ 826 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 827 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 828 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 829 struct sas_identify *identify = &rphy->identify; 830 int error; 831 832 if (parent->rphy) 833 return -ENXIO; 834 parent->rphy = rphy; 835 836 error = device_add(&rphy->dev); 837 if (error) 838 return error; 839 transport_add_device(&rphy->dev); 840 transport_configure_device(&rphy->dev); 841 842 mutex_lock(&sas_host->lock); 843 list_add_tail(&rphy->list, &sas_host->rphy_list); 844 if (identify->device_type == SAS_END_DEVICE && 845 (identify->target_port_protocols & 846 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 847 rphy->scsi_target_id = sas_host->next_target_id++; 848 else if (identify->device_type == SAS_END_DEVICE) 849 rphy->scsi_target_id = -1; 850 mutex_unlock(&sas_host->lock); 851 852 if (identify->device_type == SAS_END_DEVICE && 853 rphy->scsi_target_id != -1) { 854 scsi_scan_target(&rphy->dev, parent->port_identifier, 855 rphy->scsi_target_id, ~0, 0); 856 } 857 858 return 0; 859} 860EXPORT_SYMBOL(sas_rphy_add); 861 862/** 863 * sas_rphy_free -- free a SAS remote PHY 864 * @rphy SAS remote PHY to free 865 * 866 * Frees the specified SAS remote PHY. 867 * 868 * Note: 869 * This function must only be called on a remote 870 * PHY that has not sucessfully been added using 871 * sas_rphy_add(). 872 */ 873void sas_rphy_free(struct sas_rphy *rphy) 874{ 875 struct device *dev = &rphy->dev; 876 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 877 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 878 879 mutex_lock(&sas_host->lock); 880 list_del(&rphy->list); 881 mutex_unlock(&sas_host->lock); 882 883 transport_destroy_device(dev); 884 885 put_device(dev); 886} 887EXPORT_SYMBOL(sas_rphy_free); 888 889/** 890 * sas_rphy_delete -- remove SAS remote PHY 891 * @rphy: SAS remote PHY to remove 892 * 893 * Removes the specified SAS remote PHY. 894 */ 895void 896sas_rphy_delete(struct sas_rphy *rphy) 897{ 898 struct device *dev = &rphy->dev; 899 struct sas_phy *parent = dev_to_phy(dev->parent); 900 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 901 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 902 903 switch (rphy->identify.device_type) { 904 case SAS_END_DEVICE: 905 scsi_remove_target(dev); 906 break; 907 case SAS_EDGE_EXPANDER_DEVICE: 908 case SAS_FANOUT_EXPANDER_DEVICE: 909 device_for_each_child(dev, NULL, do_sas_phy_delete); 910 break; 911 default: 912 break; 913 } 914 915 transport_remove_device(dev); 916 device_del(dev); 917 transport_destroy_device(dev); 918 919 mutex_lock(&sas_host->lock); 920 list_del(&rphy->list); 921 mutex_unlock(&sas_host->lock); 922 923 parent->rphy = NULL; 924 925 put_device(dev); 926} 927EXPORT_SYMBOL(sas_rphy_delete); 928 929/** 930 * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 931 * @dev: device to check 932 * 933 * Returns: 934 * %1 if the device represents a SAS remote PHY, %0 else 935 */ 936int scsi_is_sas_rphy(const struct device *dev) 937{ 938 return dev->release == sas_end_device_release || 939 dev->release == sas_expander_release; 940} 941EXPORT_SYMBOL(scsi_is_sas_rphy); 942 943 944/* 945 * SCSI scan helper 946 */ 947 948static int sas_user_scan(struct Scsi_Host *shost, uint channel, 949 uint id, uint lun) 950{ 951 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 952 struct sas_rphy *rphy; 953 954 mutex_lock(&sas_host->lock); 955 list_for_each_entry(rphy, &sas_host->rphy_list, list) { 956 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 957 958 if (rphy->identify.device_type != SAS_END_DEVICE || 959 rphy->scsi_target_id == -1) 960 continue; 961 962 if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) && 963 (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 964 scsi_scan_target(&rphy->dev, parent->port_identifier, 965 rphy->scsi_target_id, lun, 1); 966 } 967 } 968 mutex_unlock(&sas_host->lock); 969 970 return 0; 971} 972 973 974/* 975 * Setup / Teardown code 976 */ 977 978#define SETUP_TEMPLATE(attrb, field, perm, test) \ 979 i->private_##attrb[count] = class_device_attr_##field; \ 980 i->private_##attrb[count].attr.mode = perm; \ 981 i->attrb[count] = &i->private_##attrb[count]; \ 982 if (test) \ 983 count++ 984 985 986#define SETUP_RPORT_ATTRIBUTE(field) \ 987 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) 988 989#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 990 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) 991 992#define SETUP_PORT_ATTRIBUTE(field) \ 993 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) 994 995#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ 996 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) 997 998#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 999 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) 1000 1001#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ 1002 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) 1003 1004#define SETUP_END_DEV_ATTRIBUTE(field) \ 1005 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) 1006 1007#define SETUP_EXPANDER_ATTRIBUTE(field) \ 1008 SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1) 1009 1010/** 1011 * sas_attach_transport -- instantiate SAS transport template 1012 * @ft: SAS transport class function template 1013 */ 1014struct scsi_transport_template * 1015sas_attach_transport(struct sas_function_template *ft) 1016{ 1017 struct sas_internal *i; 1018 int count; 1019 1020 i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); 1021 if (!i) 1022 return NULL; 1023 1024 i->t.user_scan = sas_user_scan; 1025 1026 i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 1027 i->t.host_attrs.ac.class = &sas_host_class.class; 1028 i->t.host_attrs.ac.match = sas_host_match; 1029 transport_container_register(&i->t.host_attrs); 1030 i->t.host_size = sizeof(struct sas_host_attrs); 1031 1032 i->phy_attr_cont.ac.class = &sas_phy_class.class; 1033 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 1034 i->phy_attr_cont.ac.match = sas_phy_match; 1035 transport_container_register(&i->phy_attr_cont); 1036 1037 i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 1038 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 1039 i->rphy_attr_cont.ac.match = sas_rphy_match; 1040 transport_container_register(&i->rphy_attr_cont); 1041 1042 i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class; 1043 i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0]; 1044 i->end_dev_attr_cont.ac.match = sas_end_dev_match; 1045 transport_container_register(&i->end_dev_attr_cont); 1046 1047 i->expander_attr_cont.ac.class = &sas_expander_class.class; 1048 i->expander_attr_cont.ac.attrs = &i->expander_attrs[0]; 1049 i->expander_attr_cont.ac.match = sas_expander_match; 1050 transport_container_register(&i->expander_attr_cont); 1051 1052 i->f = ft; 1053 1054 count = 0; 1055 i->host_attrs[count] = NULL; 1056 1057 count = 0; 1058 SETUP_PORT_ATTRIBUTE(initiator_port_protocols); 1059 SETUP_PORT_ATTRIBUTE(target_port_protocols); 1060 SETUP_PORT_ATTRIBUTE(device_type); 1061 SETUP_PORT_ATTRIBUTE(sas_address); 1062 SETUP_PORT_ATTRIBUTE(phy_identifier); 1063 SETUP_PORT_ATTRIBUTE(port_identifier); 1064 SETUP_PORT_ATTRIBUTE(negotiated_linkrate); 1065 SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); 1066 SETUP_PORT_ATTRIBUTE(minimum_linkrate); 1067 SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); 1068 SETUP_PORT_ATTRIBUTE(maximum_linkrate); 1069 1070 SETUP_PORT_ATTRIBUTE(invalid_dword_count); 1071 SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 1072 SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 1073 SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 1074 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); 1075 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 1076 i->phy_attrs[count] = NULL; 1077 1078 count = 0; 1079 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 1080 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 1081 SETUP_RPORT_ATTRIBUTE(rphy_device_type); 1082 SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 1083 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 1084 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier, 1085 get_enclosure_identifier); 1086 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier, 1087 get_bay_identifier); 1088 i->rphy_attrs[count] = NULL; 1089 1090 count = 0; 1091 SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); 1092 SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); 1093 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); 1094 i->end_dev_attrs[count] = NULL; 1095 1096 count = 0; 1097 SETUP_EXPANDER_ATTRIBUTE(vendor_id); 1098 SETUP_EXPANDER_ATTRIBUTE(product_id); 1099 SETUP_EXPANDER_ATTRIBUTE(product_rev); 1100 SETUP_EXPANDER_ATTRIBUTE(component_vendor_id); 1101 SETUP_EXPANDER_ATTRIBUTE(component_id); 1102 SETUP_EXPANDER_ATTRIBUTE(component_revision_id); 1103 SETUP_EXPANDER_ATTRIBUTE(level); 1104 i->expander_attrs[count] = NULL; 1105 1106 return &i->t; 1107} 1108EXPORT_SYMBOL(sas_attach_transport); 1109 1110/** 1111 * sas_release_transport -- release SAS transport template instance 1112 * @t: transport template instance 1113 */ 1114void sas_release_transport(struct scsi_transport_template *t) 1115{ 1116 struct sas_internal *i = to_sas_internal(t); 1117 1118 transport_container_unregister(&i->t.host_attrs); 1119 transport_container_unregister(&i->phy_attr_cont); 1120 transport_container_unregister(&i->rphy_attr_cont); 1121 transport_container_unregister(&i->end_dev_attr_cont); 1122 transport_container_unregister(&i->expander_attr_cont); 1123 1124 kfree(i); 1125} 1126EXPORT_SYMBOL(sas_release_transport); 1127 1128static __init int sas_transport_init(void) 1129{ 1130 int error; 1131 1132 error = transport_class_register(&sas_host_class); 1133 if (error) 1134 goto out; 1135 error = transport_class_register(&sas_phy_class); 1136 if (error) 1137 goto out_unregister_transport; 1138 error = transport_class_register(&sas_rphy_class); 1139 if (error) 1140 goto out_unregister_phy; 1141 error = transport_class_register(&sas_end_dev_class); 1142 if (error) 1143 goto out_unregister_rphy; 1144 error = transport_class_register(&sas_expander_class); 1145 if (error) 1146 goto out_unregister_end_dev; 1147 1148 return 0; 1149 1150 out_unregister_end_dev: 1151 transport_class_unregister(&sas_end_dev_class); 1152 out_unregister_rphy: 1153 transport_class_unregister(&sas_rphy_class); 1154 out_unregister_phy: 1155 transport_class_unregister(&sas_phy_class); 1156 out_unregister_transport: 1157 transport_class_unregister(&sas_host_class); 1158 out: 1159 return error; 1160 1161} 1162 1163static void __exit sas_transport_exit(void) 1164{ 1165 transport_class_unregister(&sas_host_class); 1166 transport_class_unregister(&sas_phy_class); 1167 transport_class_unregister(&sas_rphy_class); 1168 transport_class_unregister(&sas_end_dev_class); 1169 transport_class_unregister(&sas_expander_class); 1170} 1171 1172MODULE_AUTHOR("Christoph Hellwig"); 1173MODULE_DESCRIPTION("SAS Transphy Attributes"); 1174MODULE_LICENSE("GPL"); 1175 1176module_init(sas_transport_init); 1177module_exit(sas_transport_exit); 1178