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