scsi_transport_sas.c revision dd9fbb52134693f1394a928c05d5f3cd3fdaf6e0
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 39#define SAS_HOST_ATTRS 0 40#define SAS_PORT_ATTRS 17 41#define SAS_RPORT_ATTRS 7 42 43struct sas_internal { 44 struct scsi_transport_template t; 45 struct sas_function_template *f; 46 47 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; 48 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; 49 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 50 51 struct transport_container phy_attr_cont; 52 struct transport_container rphy_attr_cont; 53 54 /* 55 * The array of null terminated pointers to attributes 56 * needed by scsi_sysfs.c 57 */ 58 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; 59 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 60 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 61}; 62#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) 63 64struct sas_host_attrs { 65 struct list_head rphy_list; 66 struct mutex lock; 67 u32 next_target_id; 68}; 69#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 70 71 72/* 73 * Hack to allow attributes of the same name in different objects. 74 */ 75#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ 76 struct class_device_attribute class_device_attr_##_prefix##_##_name = \ 77 __ATTR(_name,_mode,_show,_store) 78 79 80/* 81 * Pretty printing helpers 82 */ 83 84#define sas_bitfield_name_match(title, table) \ 85static ssize_t \ 86get_sas_##title##_names(u32 table_key, char *buf) \ 87{ \ 88 char *prefix = ""; \ 89 ssize_t len = 0; \ 90 int i; \ 91 \ 92 for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \ 93 if (table[i].value & table_key) { \ 94 len += sprintf(buf + len, "%s%s", \ 95 prefix, table[i].name); \ 96 prefix = ", "; \ 97 } \ 98 } \ 99 len += sprintf(buf + len, "\n"); \ 100 return len; \ 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 < sizeof(table)/sizeof(table[0]); 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}; 156sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 157 158 159/* 160 * SAS host attributes 161 */ 162 163static int sas_host_setup(struct transport_container *tc, struct device *dev, 164 struct class_device *cdev) 165{ 166 struct Scsi_Host *shost = dev_to_shost(dev); 167 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 168 169 INIT_LIST_HEAD(&sas_host->rphy_list); 170 mutex_init(&sas_host->lock); 171 sas_host->next_target_id = 0; 172 return 0; 173} 174 175static DECLARE_TRANSPORT_CLASS(sas_host_class, 176 "sas_host", sas_host_setup, NULL, NULL); 177 178static int sas_host_match(struct attribute_container *cont, 179 struct device *dev) 180{ 181 struct Scsi_Host *shost; 182 struct sas_internal *i; 183 184 if (!scsi_is_host_device(dev)) 185 return 0; 186 shost = dev_to_shost(dev); 187 188 if (!shost->transportt) 189 return 0; 190 if (shost->transportt->host_attrs.ac.class != 191 &sas_host_class.class) 192 return 0; 193 194 i = to_sas_internal(shost->transportt); 195 return &i->t.host_attrs.ac == cont; 196} 197 198static int do_sas_phy_delete(struct device *dev, void *data) 199{ 200 if (scsi_is_sas_phy(dev)) 201 sas_phy_delete(dev_to_phy(dev)); 202 return 0; 203} 204 205/** 206 * sas_remove_host -- tear down a Scsi_Host's SAS data structures 207 * @shost: Scsi Host that is torn down 208 * 209 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 210 * Must be called just before scsi_remove_host for SAS HBAs. 211 */ 212void sas_remove_host(struct Scsi_Host *shost) 213{ 214 device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); 215} 216EXPORT_SYMBOL(sas_remove_host); 217 218 219/* 220 * SAS Port attributes 221 */ 222 223#define sas_phy_show_simple(field, name, format_string, cast) \ 224static ssize_t \ 225show_sas_phy_##name(struct class_device *cdev, char *buf) \ 226{ \ 227 struct sas_phy *phy = transport_class_to_phy(cdev); \ 228 \ 229 return snprintf(buf, 20, format_string, cast phy->field); \ 230} 231 232#define sas_phy_simple_attr(field, name, format_string, type) \ 233 sas_phy_show_simple(field, name, format_string, (type)) \ 234static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 235 236#define sas_phy_show_protocol(field, name) \ 237static ssize_t \ 238show_sas_phy_##name(struct class_device *cdev, char *buf) \ 239{ \ 240 struct sas_phy *phy = transport_class_to_phy(cdev); \ 241 \ 242 if (!phy->field) \ 243 return snprintf(buf, 20, "none\n"); \ 244 return get_sas_protocol_names(phy->field, buf); \ 245} 246 247#define sas_phy_protocol_attr(field, name) \ 248 sas_phy_show_protocol(field, name) \ 249static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 250 251#define sas_phy_show_linkspeed(field) \ 252static ssize_t \ 253show_sas_phy_##field(struct class_device *cdev, char *buf) \ 254{ \ 255 struct sas_phy *phy = transport_class_to_phy(cdev); \ 256 \ 257 return get_sas_linkspeed_names(phy->field, buf); \ 258} 259 260#define sas_phy_linkspeed_attr(field) \ 261 sas_phy_show_linkspeed(field) \ 262static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 263 264#define sas_phy_show_linkerror(field) \ 265static ssize_t \ 266show_sas_phy_##field(struct class_device *cdev, char *buf) \ 267{ \ 268 struct sas_phy *phy = transport_class_to_phy(cdev); \ 269 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 270 struct sas_internal *i = to_sas_internal(shost->transportt); \ 271 int error; \ 272 \ 273 if (!phy->local_attached) \ 274 return -EINVAL; \ 275 \ 276 error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ 277 if (error) \ 278 return error; \ 279 return snprintf(buf, 20, "%u\n", phy->field); \ 280} 281 282#define sas_phy_linkerror_attr(field) \ 283 sas_phy_show_linkerror(field) \ 284static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 285 286 287static ssize_t 288show_sas_device_type(struct class_device *cdev, char *buf) 289{ 290 struct sas_phy *phy = transport_class_to_phy(cdev); 291 292 if (!phy->identify.device_type) 293 return snprintf(buf, 20, "none\n"); 294 return get_sas_device_type_names(phy->identify.device_type, buf); 295} 296static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 297 298static ssize_t do_sas_phy_reset(struct class_device *cdev, 299 size_t count, int hard_reset) 300{ 301 struct sas_phy *phy = transport_class_to_phy(cdev); 302 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 303 struct sas_internal *i = to_sas_internal(shost->transportt); 304 int error; 305 306 if (!phy->local_attached) 307 return -EINVAL; 308 309 error = i->f->phy_reset(phy, hard_reset); 310 if (error) 311 return error; 312 return count; 313}; 314 315static ssize_t store_sas_link_reset(struct class_device *cdev, 316 const char *buf, size_t count) 317{ 318 return do_sas_phy_reset(cdev, count, 0); 319} 320static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 321 322static ssize_t store_sas_hard_reset(struct class_device *cdev, 323 const char *buf, size_t count) 324{ 325 return do_sas_phy_reset(cdev, count, 1); 326} 327static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 328 329sas_phy_protocol_attr(identify.initiator_port_protocols, 330 initiator_port_protocols); 331sas_phy_protocol_attr(identify.target_port_protocols, 332 target_port_protocols); 333sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 334 unsigned long long); 335sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 336sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); 337sas_phy_linkspeed_attr(negotiated_linkrate); 338sas_phy_linkspeed_attr(minimum_linkrate_hw); 339sas_phy_linkspeed_attr(minimum_linkrate); 340sas_phy_linkspeed_attr(maximum_linkrate_hw); 341sas_phy_linkspeed_attr(maximum_linkrate); 342sas_phy_linkerror_attr(invalid_dword_count); 343sas_phy_linkerror_attr(running_disparity_error_count); 344sas_phy_linkerror_attr(loss_of_dword_sync_count); 345sas_phy_linkerror_attr(phy_reset_problem_count); 346 347 348static DECLARE_TRANSPORT_CLASS(sas_phy_class, 349 "sas_phy", NULL, NULL, NULL); 350 351static int sas_phy_match(struct attribute_container *cont, struct device *dev) 352{ 353 struct Scsi_Host *shost; 354 struct sas_internal *i; 355 356 if (!scsi_is_sas_phy(dev)) 357 return 0; 358 shost = dev_to_shost(dev->parent); 359 360 if (!shost->transportt) 361 return 0; 362 if (shost->transportt->host_attrs.ac.class != 363 &sas_host_class.class) 364 return 0; 365 366 i = to_sas_internal(shost->transportt); 367 return &i->phy_attr_cont.ac == cont; 368} 369 370static void sas_phy_release(struct device *dev) 371{ 372 struct sas_phy *phy = dev_to_phy(dev); 373 374 put_device(dev->parent); 375 kfree(phy); 376} 377 378/** 379 * sas_phy_alloc -- allocates and initialize a SAS PHY structure 380 * @parent: Parent device 381 * @number: Phy index 382 * 383 * Allocates an SAS PHY structure. It will be added in the device tree 384 * below the device specified by @parent, which has to be either a Scsi_Host 385 * or sas_rphy. 386 * 387 * Returns: 388 * SAS PHY allocated or %NULL if the allocation failed. 389 */ 390struct sas_phy *sas_phy_alloc(struct device *parent, int number) 391{ 392 struct Scsi_Host *shost = dev_to_shost(parent); 393 struct sas_phy *phy; 394 395 phy = kzalloc(sizeof(*phy), GFP_KERNEL); 396 if (!phy) 397 return NULL; 398 399 get_device(parent); 400 401 phy->number = number; 402 403 device_initialize(&phy->dev); 404 phy->dev.parent = get_device(parent); 405 phy->dev.release = sas_phy_release; 406 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 407 408 transport_setup_device(&phy->dev); 409 410 return phy; 411} 412EXPORT_SYMBOL(sas_phy_alloc); 413 414/** 415 * sas_phy_add -- add a SAS PHY to the device hierachy 416 * @phy: The PHY to be added 417 * 418 * Publishes a SAS PHY to the rest of the system. 419 */ 420int sas_phy_add(struct sas_phy *phy) 421{ 422 int error; 423 424 error = device_add(&phy->dev); 425 if (!error) { 426 transport_add_device(&phy->dev); 427 transport_configure_device(&phy->dev); 428 } 429 430 return error; 431} 432EXPORT_SYMBOL(sas_phy_add); 433 434/** 435 * sas_phy_free -- free a SAS PHY 436 * @phy: SAS PHY to free 437 * 438 * Frees the specified SAS PHY. 439 * 440 * Note: 441 * This function must only be called on a PHY that has not 442 * sucessfully been added using sas_phy_add(). 443 */ 444void sas_phy_free(struct sas_phy *phy) 445{ 446 transport_destroy_device(&phy->dev); 447 put_device(phy->dev.parent); 448 put_device(phy->dev.parent); 449 put_device(phy->dev.parent); 450 kfree(phy); 451} 452EXPORT_SYMBOL(sas_phy_free); 453 454/** 455 * sas_phy_delete -- remove SAS PHY 456 * @phy: SAS PHY to remove 457 * 458 * Removes the specified SAS PHY. If the SAS PHY has an 459 * associated remote PHY it is removed before. 460 */ 461void 462sas_phy_delete(struct sas_phy *phy) 463{ 464 struct device *dev = &phy->dev; 465 466 if (phy->rphy) 467 sas_rphy_delete(phy->rphy); 468 469 transport_remove_device(dev); 470 device_del(dev); 471 transport_destroy_device(dev); 472 put_device(dev->parent); 473} 474EXPORT_SYMBOL(sas_phy_delete); 475 476/** 477 * scsi_is_sas_phy -- check if a struct device represents a SAS PHY 478 * @dev: device to check 479 * 480 * Returns: 481 * %1 if the device represents a SAS PHY, %0 else 482 */ 483int scsi_is_sas_phy(const struct device *dev) 484{ 485 return dev->release == sas_phy_release; 486} 487EXPORT_SYMBOL(scsi_is_sas_phy); 488 489/* 490 * SAS remote PHY attributes. 491 */ 492 493#define sas_rphy_show_simple(field, name, format_string, cast) \ 494static ssize_t \ 495show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 496{ \ 497 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 498 \ 499 return snprintf(buf, 20, format_string, cast rphy->field); \ 500} 501 502#define sas_rphy_simple_attr(field, name, format_string, type) \ 503 sas_rphy_show_simple(field, name, format_string, (type)) \ 504static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 505 show_sas_rphy_##name, NULL) 506 507#define sas_rphy_show_protocol(field, name) \ 508static ssize_t \ 509show_sas_rphy_##name(struct class_device *cdev, char *buf) \ 510{ \ 511 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \ 512 \ 513 if (!rphy->field) \ 514 return snprintf(buf, 20, "none\n"); \ 515 return get_sas_protocol_names(rphy->field, buf); \ 516} 517 518#define sas_rphy_protocol_attr(field, name) \ 519 sas_rphy_show_protocol(field, name) \ 520static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \ 521 show_sas_rphy_##name, NULL) 522 523static ssize_t 524show_sas_rphy_device_type(struct class_device *cdev, char *buf) 525{ 526 struct sas_rphy *rphy = transport_class_to_rphy(cdev); 527 528 if (!rphy->identify.device_type) 529 return snprintf(buf, 20, "none\n"); 530 return get_sas_device_type_names( 531 rphy->identify.device_type, buf); 532} 533 534static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 535 show_sas_rphy_device_type, NULL); 536 537static ssize_t 538show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf) 539{ 540 struct sas_rphy *rphy = transport_class_to_rphy(cdev); 541 struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 542 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 543 struct sas_internal *i = to_sas_internal(shost->transportt); 544 u64 identifier; 545 int error; 546 547 /* 548 * Only devices behind an expander are supported, because the 549 * enclosure identifier is a SMP feature. 550 */ 551 if (phy->local_attached) 552 return -EINVAL; 553 554 error = i->f->get_enclosure_identifier(rphy, &identifier); 555 if (error) 556 return error; 557 return sprintf(buf, "0x%llx\n", (unsigned long long)identifier); 558} 559 560static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO, 561 show_sas_rphy_enclosure_identifier, NULL); 562 563static ssize_t 564show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf) 565{ 566 struct sas_rphy *rphy = transport_class_to_rphy(cdev); 567 struct sas_phy *phy = dev_to_phy(rphy->dev.parent); 568 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 569 struct sas_internal *i = to_sas_internal(shost->transportt); 570 int val; 571 572 if (phy->local_attached) 573 return -EINVAL; 574 575 val = i->f->get_bay_identifier(rphy); 576 if (val < 0) 577 return val; 578 return sprintf(buf, "%d\n", val); 579} 580 581static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO, 582 show_sas_rphy_bay_identifier, NULL); 583 584sas_rphy_protocol_attr(identify.initiator_port_protocols, 585 initiator_port_protocols); 586sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 587sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 588 unsigned long long); 589sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 590 591static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 592 "sas_rphy", NULL, NULL, NULL); 593 594static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 595{ 596 struct Scsi_Host *shost; 597 struct sas_internal *i; 598 599 if (!scsi_is_sas_rphy(dev)) 600 return 0; 601 shost = dev_to_shost(dev->parent->parent); 602 603 if (!shost->transportt) 604 return 0; 605 if (shost->transportt->host_attrs.ac.class != 606 &sas_host_class.class) 607 return 0; 608 609 i = to_sas_internal(shost->transportt); 610 return &i->rphy_attr_cont.ac == cont; 611} 612 613static void sas_rphy_release(struct device *dev) 614{ 615 struct sas_rphy *rphy = dev_to_rphy(dev); 616 617 put_device(dev->parent); 618 kfree(rphy); 619} 620 621/** 622 * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure 623 * @parent: SAS PHY this remote PHY is conneted to 624 * 625 * Allocates an SAS remote PHY structure, connected to @parent. 626 * 627 * Returns: 628 * SAS PHY allocated or %NULL if the allocation failed. 629 */ 630struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent) 631{ 632 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 633 struct sas_rphy *rphy; 634 635 rphy = kzalloc(sizeof(*rphy), GFP_KERNEL); 636 if (!rphy) { 637 put_device(&parent->dev); 638 return NULL; 639 } 640 641 device_initialize(&rphy->dev); 642 rphy->dev.parent = get_device(&parent->dev); 643 rphy->dev.release = sas_rphy_release; 644 sprintf(rphy->dev.bus_id, "rphy-%d:%d-%d", 645 shost->host_no, parent->port_identifier, parent->number); 646 transport_setup_device(&rphy->dev); 647 648 return rphy; 649} 650EXPORT_SYMBOL(sas_rphy_alloc); 651 652/** 653 * sas_rphy_add -- add a SAS remote PHY to the device hierachy 654 * @rphy: The remote PHY to be added 655 * 656 * Publishes a SAS remote PHY to the rest of the system. 657 */ 658int sas_rphy_add(struct sas_rphy *rphy) 659{ 660 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 661 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 662 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 663 struct sas_identify *identify = &rphy->identify; 664 int error; 665 666 if (parent->rphy) 667 return -ENXIO; 668 parent->rphy = rphy; 669 670 error = device_add(&rphy->dev); 671 if (error) 672 return error; 673 transport_add_device(&rphy->dev); 674 transport_configure_device(&rphy->dev); 675 676 mutex_lock(&sas_host->lock); 677 list_add_tail(&rphy->list, &sas_host->rphy_list); 678 if (identify->device_type == SAS_END_DEVICE && 679 (identify->target_port_protocols & 680 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 681 rphy->scsi_target_id = sas_host->next_target_id++; 682 else 683 rphy->scsi_target_id = -1; 684 mutex_unlock(&sas_host->lock); 685 686 if (rphy->scsi_target_id != -1) { 687 scsi_scan_target(&rphy->dev, parent->port_identifier, 688 rphy->scsi_target_id, ~0, 0); 689 } 690 691 return 0; 692} 693EXPORT_SYMBOL(sas_rphy_add); 694 695/** 696 * sas_rphy_free -- free a SAS remote PHY 697 * @rphy SAS remote PHY to free 698 * 699 * Frees the specified SAS remote PHY. 700 * 701 * Note: 702 * This function must only be called on a remote 703 * PHY that has not sucessfully been added using 704 * sas_rphy_add(). 705 */ 706void sas_rphy_free(struct sas_rphy *rphy) 707{ 708 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 709 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 710 711 mutex_lock(&sas_host->lock); 712 list_del(&rphy->list); 713 mutex_unlock(&sas_host->lock); 714 715 transport_destroy_device(&rphy->dev); 716 put_device(rphy->dev.parent); 717 put_device(rphy->dev.parent); 718 put_device(rphy->dev.parent); 719 kfree(rphy); 720} 721EXPORT_SYMBOL(sas_rphy_free); 722 723/** 724 * sas_rphy_delete -- remove SAS remote PHY 725 * @rphy: SAS remote PHY to remove 726 * 727 * Removes the specified SAS remote PHY. 728 */ 729void 730sas_rphy_delete(struct sas_rphy *rphy) 731{ 732 struct device *dev = &rphy->dev; 733 struct sas_phy *parent = dev_to_phy(dev->parent); 734 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 735 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 736 737 switch (rphy->identify.device_type) { 738 case SAS_END_DEVICE: 739 scsi_remove_target(dev); 740 break; 741 case SAS_EDGE_EXPANDER_DEVICE: 742 case SAS_FANOUT_EXPANDER_DEVICE: 743 device_for_each_child(dev, NULL, do_sas_phy_delete); 744 break; 745 default: 746 break; 747 } 748 749 transport_remove_device(dev); 750 device_del(dev); 751 transport_destroy_device(dev); 752 753 mutex_lock(&sas_host->lock); 754 list_del(&rphy->list); 755 mutex_unlock(&sas_host->lock); 756 757 parent->rphy = NULL; 758 759 put_device(&parent->dev); 760} 761EXPORT_SYMBOL(sas_rphy_delete); 762 763/** 764 * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 765 * @dev: device to check 766 * 767 * Returns: 768 * %1 if the device represents a SAS remote PHY, %0 else 769 */ 770int scsi_is_sas_rphy(const struct device *dev) 771{ 772 return dev->release == sas_rphy_release; 773} 774EXPORT_SYMBOL(scsi_is_sas_rphy); 775 776 777/* 778 * SCSI scan helper 779 */ 780 781static int sas_user_scan(struct Scsi_Host *shost, uint channel, 782 uint id, uint lun) 783{ 784 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 785 struct sas_rphy *rphy; 786 787 mutex_lock(&sas_host->lock); 788 list_for_each_entry(rphy, &sas_host->rphy_list, list) { 789 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 790 791 if (rphy->scsi_target_id == -1) 792 continue; 793 794 if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) && 795 (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 796 scsi_scan_target(&rphy->dev, parent->port_identifier, 797 rphy->scsi_target_id, lun, 1); 798 } 799 } 800 mutex_unlock(&sas_host->lock); 801 802 return 0; 803} 804 805 806/* 807 * Setup / Teardown code 808 */ 809 810#define SETUP_RPORT_ATTRIBUTE(field) \ 811 i->private_rphy_attrs[count] = class_device_attr_##field; \ 812 i->private_rphy_attrs[count].attr.mode = S_IRUGO; \ 813 i->private_rphy_attrs[count].store = NULL; \ 814 i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \ 815 count++ 816 817#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 818 i->private_rphy_attrs[count] = class_device_attr_##field; \ 819 i->private_rphy_attrs[count].attr.mode = S_IRUGO; \ 820 i->private_rphy_attrs[count].store = NULL; \ 821 i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \ 822 if (i->f->func) \ 823 count++ 824 825#define SETUP_PORT_ATTRIBUTE(field) \ 826 i->private_phy_attrs[count] = class_device_attr_##field; \ 827 i->private_phy_attrs[count].attr.mode = S_IRUGO; \ 828 i->private_phy_attrs[count].store = NULL; \ 829 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 830 count++ 831 832#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ 833 i->private_phy_attrs[count] = class_device_attr_##field; \ 834 i->private_phy_attrs[count].attr.mode = S_IRUGO; \ 835 i->private_phy_attrs[count].store = NULL; \ 836 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 837 if (i->f->func) \ 838 count++ 839 840#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 841 i->private_phy_attrs[count] = class_device_attr_##field; \ 842 i->private_phy_attrs[count].attr.mode = S_IWUGO; \ 843 i->private_phy_attrs[count].show = NULL; \ 844 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 845 count++ 846 847#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ 848 i->private_phy_attrs[count] = class_device_attr_##field; \ 849 i->private_phy_attrs[count].attr.mode = S_IWUGO; \ 850 i->private_phy_attrs[count].show = NULL; \ 851 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 852 if (i->f->func) \ 853 count++ 854 855 856/** 857 * sas_attach_transport -- instantiate SAS transport template 858 * @ft: SAS transport class function template 859 */ 860struct scsi_transport_template * 861sas_attach_transport(struct sas_function_template *ft) 862{ 863 struct sas_internal *i; 864 int count; 865 866 i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); 867 if (!i) 868 return NULL; 869 870 i->t.user_scan = sas_user_scan; 871 872 i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 873 i->t.host_attrs.ac.class = &sas_host_class.class; 874 i->t.host_attrs.ac.match = sas_host_match; 875 transport_container_register(&i->t.host_attrs); 876 i->t.host_size = sizeof(struct sas_host_attrs); 877 878 i->phy_attr_cont.ac.class = &sas_phy_class.class; 879 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 880 i->phy_attr_cont.ac.match = sas_phy_match; 881 transport_container_register(&i->phy_attr_cont); 882 883 i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 884 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 885 i->rphy_attr_cont.ac.match = sas_rphy_match; 886 transport_container_register(&i->rphy_attr_cont); 887 888 i->f = ft; 889 890 count = 0; 891 i->host_attrs[count] = NULL; 892 893 count = 0; 894 SETUP_PORT_ATTRIBUTE(initiator_port_protocols); 895 SETUP_PORT_ATTRIBUTE(target_port_protocols); 896 SETUP_PORT_ATTRIBUTE(device_type); 897 SETUP_PORT_ATTRIBUTE(sas_address); 898 SETUP_PORT_ATTRIBUTE(phy_identifier); 899 SETUP_PORT_ATTRIBUTE(port_identifier); 900 SETUP_PORT_ATTRIBUTE(negotiated_linkrate); 901 SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); 902 SETUP_PORT_ATTRIBUTE(minimum_linkrate); 903 SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); 904 SETUP_PORT_ATTRIBUTE(maximum_linkrate); 905 906 SETUP_PORT_ATTRIBUTE(invalid_dword_count); 907 SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 908 SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 909 SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 910 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); 911 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 912 i->phy_attrs[count] = NULL; 913 914 count = 0; 915 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 916 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 917 SETUP_RPORT_ATTRIBUTE(rphy_device_type); 918 SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 919 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 920 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier, 921 get_enclosure_identifier); 922 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier, 923 get_bay_identifier); 924 i->rphy_attrs[count] = NULL; 925 926 return &i->t; 927} 928EXPORT_SYMBOL(sas_attach_transport); 929 930/** 931 * sas_release_transport -- release SAS transport template instance 932 * @t: transport template instance 933 */ 934void sas_release_transport(struct scsi_transport_template *t) 935{ 936 struct sas_internal *i = to_sas_internal(t); 937 938 transport_container_unregister(&i->t.host_attrs); 939 transport_container_unregister(&i->phy_attr_cont); 940 transport_container_unregister(&i->rphy_attr_cont); 941 942 kfree(i); 943} 944EXPORT_SYMBOL(sas_release_transport); 945 946static __init int sas_transport_init(void) 947{ 948 int error; 949 950 error = transport_class_register(&sas_host_class); 951 if (error) 952 goto out; 953 error = transport_class_register(&sas_phy_class); 954 if (error) 955 goto out_unregister_transport; 956 error = transport_class_register(&sas_rphy_class); 957 if (error) 958 goto out_unregister_phy; 959 960 return 0; 961 962 out_unregister_phy: 963 transport_class_unregister(&sas_phy_class); 964 out_unregister_transport: 965 transport_class_unregister(&sas_host_class); 966 out: 967 return error; 968 969} 970 971static void __exit sas_transport_exit(void) 972{ 973 transport_class_unregister(&sas_host_class); 974 transport_class_unregister(&sas_phy_class); 975 transport_class_unregister(&sas_rphy_class); 976} 977 978MODULE_AUTHOR("Christoph Hellwig"); 979MODULE_DESCRIPTION("SAS Transphy Attributes"); 980MODULE_LICENSE("GPL"); 981 982module_init(sas_transport_init); 983module_exit(sas_transport_exit); 984