scsi_transport_sas.c revision e02f3f59225d8c3b2a0ad0dc941a09865e27da61
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#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 5 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}; 155sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 156 157 158/* 159 * SAS host attributes 160 */ 161 162static int sas_host_setup(struct transport_container *tc, struct device *dev, 163 struct class_device *cdev) 164{ 165 struct Scsi_Host *shost = dev_to_shost(dev); 166 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 167 168 INIT_LIST_HEAD(&sas_host->rphy_list); 169 mutex_init(&sas_host->lock); 170 sas_host->next_target_id = 0; 171 return 0; 172} 173 174static DECLARE_TRANSPORT_CLASS(sas_host_class, 175 "sas_host", sas_host_setup, NULL, NULL); 176 177static int sas_host_match(struct attribute_container *cont, 178 struct device *dev) 179{ 180 struct Scsi_Host *shost; 181 struct sas_internal *i; 182 183 if (!scsi_is_host_device(dev)) 184 return 0; 185 shost = dev_to_shost(dev); 186 187 if (!shost->transportt) 188 return 0; 189 if (shost->transportt->host_attrs.ac.class != 190 &sas_host_class.class) 191 return 0; 192 193 i = to_sas_internal(shost->transportt); 194 return &i->t.host_attrs.ac == cont; 195} 196 197static int do_sas_phy_delete(struct device *dev, void *data) 198{ 199 if (scsi_is_sas_phy(dev)) 200 sas_phy_delete(dev_to_phy(dev)); 201 return 0; 202} 203 204/** 205 * sas_remove_host -- tear down a Scsi_Host's SAS data structures 206 * @shost: Scsi Host that is torn down 207 * 208 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. 209 * Must be called just before scsi_remove_host for SAS HBAs. 210 */ 211void sas_remove_host(struct Scsi_Host *shost) 212{ 213 device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); 214} 215EXPORT_SYMBOL(sas_remove_host); 216 217 218/* 219 * SAS Port attributes 220 */ 221 222#define sas_phy_show_simple(field, name, format_string, cast) \ 223static ssize_t \ 224show_sas_phy_##name(struct class_device *cdev, char *buf) \ 225{ \ 226 struct sas_phy *phy = transport_class_to_phy(cdev); \ 227 \ 228 return snprintf(buf, 20, format_string, cast phy->field); \ 229} 230 231#define sas_phy_simple_attr(field, name, format_string, type) \ 232 sas_phy_show_simple(field, name, format_string, (type)) \ 233static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 234 235#define sas_phy_show_protocol(field, name) \ 236static ssize_t \ 237show_sas_phy_##name(struct class_device *cdev, char *buf) \ 238{ \ 239 struct sas_phy *phy = transport_class_to_phy(cdev); \ 240 \ 241 if (!phy->field) \ 242 return snprintf(buf, 20, "none\n"); \ 243 return get_sas_protocol_names(phy->field, buf); \ 244} 245 246#define sas_phy_protocol_attr(field, name) \ 247 sas_phy_show_protocol(field, name) \ 248static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) 249 250#define sas_phy_show_linkspeed(field) \ 251static ssize_t \ 252show_sas_phy_##field(struct class_device *cdev, char *buf) \ 253{ \ 254 struct sas_phy *phy = transport_class_to_phy(cdev); \ 255 \ 256 return get_sas_linkspeed_names(phy->field, buf); \ 257} 258 259#define sas_phy_linkspeed_attr(field) \ 260 sas_phy_show_linkspeed(field) \ 261static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 262 263#define sas_phy_show_linkerror(field) \ 264static ssize_t \ 265show_sas_phy_##field(struct class_device *cdev, char *buf) \ 266{ \ 267 struct sas_phy *phy = transport_class_to_phy(cdev); \ 268 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ 269 struct sas_internal *i = to_sas_internal(shost->transportt); \ 270 int error; \ 271 \ 272 if (!phy->local_attached) \ 273 return -EINVAL; \ 274 \ 275 error = i->f->get_linkerrors(phy); \ 276 if (error) \ 277 return error; \ 278 return snprintf(buf, 20, "%u\n", phy->field); \ 279} 280 281#define sas_phy_linkerror_attr(field) \ 282 sas_phy_show_linkerror(field) \ 283static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) 284 285 286static ssize_t 287show_sas_device_type(struct class_device *cdev, char *buf) 288{ 289 struct sas_phy *phy = transport_class_to_phy(cdev); 290 291 if (!phy->identify.device_type) 292 return snprintf(buf, 20, "none\n"); 293 return get_sas_device_type_names(phy->identify.device_type, buf); 294} 295static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 296 297static ssize_t do_sas_phy_reset(struct class_device *cdev, 298 size_t count, int hard_reset) 299{ 300 struct sas_phy *phy = transport_class_to_phy(cdev); 301 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); 302 struct sas_internal *i = to_sas_internal(shost->transportt); 303 int error; 304 305 if (!phy->local_attached) 306 return -EINVAL; 307 308 error = i->f->phy_reset(phy, hard_reset); 309 if (error) 310 return error; 311 return count; 312}; 313 314static ssize_t store_sas_link_reset(struct class_device *cdev, 315 const char *buf, size_t count) 316{ 317 return do_sas_phy_reset(cdev, count, 0); 318} 319static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); 320 321static ssize_t store_sas_hard_reset(struct class_device *cdev, 322 const char *buf, size_t count) 323{ 324 return do_sas_phy_reset(cdev, count, 1); 325} 326static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); 327 328sas_phy_protocol_attr(identify.initiator_port_protocols, 329 initiator_port_protocols); 330sas_phy_protocol_attr(identify.target_port_protocols, 331 target_port_protocols); 332sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 333 unsigned long long); 334sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 335sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); 336sas_phy_linkspeed_attr(negotiated_linkrate); 337sas_phy_linkspeed_attr(minimum_linkrate_hw); 338sas_phy_linkspeed_attr(minimum_linkrate); 339sas_phy_linkspeed_attr(maximum_linkrate_hw); 340sas_phy_linkspeed_attr(maximum_linkrate); 341sas_phy_linkerror_attr(invalid_dword_count); 342sas_phy_linkerror_attr(running_disparity_error_count); 343sas_phy_linkerror_attr(loss_of_dword_sync_count); 344sas_phy_linkerror_attr(phy_reset_problem_count); 345 346 347static DECLARE_TRANSPORT_CLASS(sas_phy_class, 348 "sas_phy", NULL, NULL, NULL); 349 350static int sas_phy_match(struct attribute_container *cont, struct device *dev) 351{ 352 struct Scsi_Host *shost; 353 struct sas_internal *i; 354 355 if (!scsi_is_sas_phy(dev)) 356 return 0; 357 shost = dev_to_shost(dev->parent); 358 359 if (!shost->transportt) 360 return 0; 361 if (shost->transportt->host_attrs.ac.class != 362 &sas_host_class.class) 363 return 0; 364 365 i = to_sas_internal(shost->transportt); 366 return &i->phy_attr_cont.ac == cont; 367} 368 369static void sas_phy_release(struct device *dev) 370{ 371 struct sas_phy *phy = dev_to_phy(dev); 372 373 put_device(dev->parent); 374 kfree(phy); 375} 376 377/** 378 * sas_phy_alloc -- allocates and initialize a SAS PHY structure 379 * @parent: Parent device 380 * @number: Port number 381 * 382 * Allocates an SAS PHY structure. It will be added in the device tree 383 * below the device specified by @parent, which has to be either a Scsi_Host 384 * or sas_rphy. 385 * 386 * Returns: 387 * SAS PHY allocated or %NULL if the allocation failed. 388 */ 389struct sas_phy *sas_phy_alloc(struct device *parent, int number) 390{ 391 struct Scsi_Host *shost = dev_to_shost(parent); 392 struct sas_phy *phy; 393 394 phy = kmalloc(sizeof(*phy), GFP_KERNEL); 395 if (!phy) 396 return NULL; 397 memset(phy, 0, sizeof(*phy)); 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 537sas_rphy_protocol_attr(identify.initiator_port_protocols, 538 initiator_port_protocols); 539sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 540sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 541 unsigned long long); 542sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 543 544static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 545 "sas_rphy", NULL, NULL, NULL); 546 547static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 548{ 549 struct Scsi_Host *shost; 550 struct sas_internal *i; 551 552 if (!scsi_is_sas_rphy(dev)) 553 return 0; 554 shost = dev_to_shost(dev->parent->parent); 555 556 if (!shost->transportt) 557 return 0; 558 if (shost->transportt->host_attrs.ac.class != 559 &sas_host_class.class) 560 return 0; 561 562 i = to_sas_internal(shost->transportt); 563 return &i->rphy_attr_cont.ac == cont; 564} 565 566static void sas_rphy_release(struct device *dev) 567{ 568 struct sas_rphy *rphy = dev_to_rphy(dev); 569 570 put_device(dev->parent); 571 kfree(rphy); 572} 573 574/** 575 * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure 576 * @parent: SAS PHY this remote PHY is conneted to 577 * 578 * Allocates an SAS remote PHY structure, connected to @parent. 579 * 580 * Returns: 581 * SAS PHY allocated or %NULL if the allocation failed. 582 */ 583struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent) 584{ 585 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 586 struct sas_rphy *rphy; 587 588 rphy = kmalloc(sizeof(*rphy), GFP_KERNEL); 589 if (!rphy) { 590 put_device(&parent->dev); 591 return NULL; 592 } 593 memset(rphy, 0, sizeof(*rphy)); 594 595 device_initialize(&rphy->dev); 596 rphy->dev.parent = get_device(&parent->dev); 597 rphy->dev.release = sas_rphy_release; 598 sprintf(rphy->dev.bus_id, "rphy-%d:%d", 599 shost->host_no, parent->number); 600 transport_setup_device(&rphy->dev); 601 602 return rphy; 603} 604EXPORT_SYMBOL(sas_rphy_alloc); 605 606/** 607 * sas_rphy_add -- add a SAS remote PHY to the device hierachy 608 * @rphy: The remote PHY to be added 609 * 610 * Publishes a SAS remote PHY to the rest of the system. 611 */ 612int sas_rphy_add(struct sas_rphy *rphy) 613{ 614 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 615 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 616 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 617 struct sas_identify *identify = &rphy->identify; 618 int error; 619 620 if (parent->rphy) 621 return -ENXIO; 622 parent->rphy = rphy; 623 624 error = device_add(&rphy->dev); 625 if (error) 626 return error; 627 transport_add_device(&rphy->dev); 628 transport_configure_device(&rphy->dev); 629 630 mutex_lock(&sas_host->lock); 631 list_add_tail(&rphy->list, &sas_host->rphy_list); 632 if (identify->device_type == SAS_END_DEVICE && 633 (identify->target_port_protocols & 634 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 635 rphy->scsi_target_id = sas_host->next_target_id++; 636 else 637 rphy->scsi_target_id = -1; 638 mutex_unlock(&sas_host->lock); 639 640 if (rphy->scsi_target_id != -1) { 641 scsi_scan_target(&rphy->dev, parent->number, 642 rphy->scsi_target_id, ~0, 0); 643 } 644 645 return 0; 646} 647EXPORT_SYMBOL(sas_rphy_add); 648 649/** 650 * sas_rphy_free -- free a SAS remote PHY 651 * @rphy SAS remote PHY to free 652 * 653 * Frees the specified SAS remote PHY. 654 * 655 * Note: 656 * This function must only be called on a remote 657 * PHY that has not sucessfully been added using 658 * sas_rphy_add(). 659 */ 660void sas_rphy_free(struct sas_rphy *rphy) 661{ 662 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); 663 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 664 665 mutex_lock(&sas_host->lock); 666 list_del(&rphy->list); 667 mutex_unlock(&sas_host->lock); 668 669 transport_destroy_device(&rphy->dev); 670 put_device(rphy->dev.parent); 671 put_device(rphy->dev.parent); 672 put_device(rphy->dev.parent); 673 kfree(rphy); 674} 675EXPORT_SYMBOL(sas_rphy_free); 676 677/** 678 * sas_rphy_delete -- remove SAS remote PHY 679 * @rphy: SAS remote PHY to remove 680 * 681 * Removes the specified SAS remote PHY. 682 */ 683void 684sas_rphy_delete(struct sas_rphy *rphy) 685{ 686 struct device *dev = &rphy->dev; 687 struct sas_phy *parent = dev_to_phy(dev->parent); 688 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 689 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 690 691 switch (rphy->identify.device_type) { 692 case SAS_END_DEVICE: 693 scsi_remove_target(dev); 694 break; 695 case SAS_EDGE_EXPANDER_DEVICE: 696 case SAS_FANOUT_EXPANDER_DEVICE: 697 device_for_each_child(dev, NULL, do_sas_phy_delete); 698 break; 699 default: 700 break; 701 } 702 703 transport_remove_device(dev); 704 device_del(dev); 705 transport_destroy_device(dev); 706 707 mutex_lock(&sas_host->lock); 708 list_del(&rphy->list); 709 mutex_unlock(&sas_host->lock); 710 711 parent->rphy = NULL; 712 713 put_device(&parent->dev); 714} 715EXPORT_SYMBOL(sas_rphy_delete); 716 717/** 718 * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY 719 * @dev: device to check 720 * 721 * Returns: 722 * %1 if the device represents a SAS remote PHY, %0 else 723 */ 724int scsi_is_sas_rphy(const struct device *dev) 725{ 726 return dev->release == sas_rphy_release; 727} 728EXPORT_SYMBOL(scsi_is_sas_rphy); 729 730 731/* 732 * SCSI scan helper 733 */ 734 735static int sas_user_scan(struct Scsi_Host *shost, uint channel, 736 uint id, uint lun) 737{ 738 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 739 struct sas_rphy *rphy; 740 741 mutex_lock(&sas_host->lock); 742 list_for_each_entry(rphy, &sas_host->rphy_list, list) { 743 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 744 745 if (rphy->scsi_target_id == -1) 746 continue; 747 748 if ((channel == SCAN_WILD_CARD || channel == parent->number) && 749 (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 750 scsi_scan_target(&rphy->dev, parent->number, 751 rphy->scsi_target_id, lun, 1); 752 } 753 } 754 mutex_unlock(&sas_host->lock); 755 756 return 0; 757} 758 759 760/* 761 * Setup / Teardown code 762 */ 763 764#define SETUP_RPORT_ATTRIBUTE(field) \ 765 i->private_rphy_attrs[count] = class_device_attr_##field; \ 766 i->private_rphy_attrs[count].attr.mode = S_IRUGO; \ 767 i->private_rphy_attrs[count].store = NULL; \ 768 i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \ 769 count++ 770 771#define SETUP_PORT_ATTRIBUTE(field) \ 772 i->private_phy_attrs[count] = class_device_attr_##field; \ 773 i->private_phy_attrs[count].attr.mode = S_IRUGO; \ 774 i->private_phy_attrs[count].store = NULL; \ 775 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 776 count++ 777 778#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 779 i->private_phy_attrs[count] = class_device_attr_##field; \ 780 i->private_phy_attrs[count].attr.mode = S_IWUGO; \ 781 i->private_phy_attrs[count].show = NULL; \ 782 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 783 count++ 784 785 786/** 787 * sas_attach_transport -- instantiate SAS transport template 788 * @ft: SAS transport class function template 789 */ 790struct scsi_transport_template * 791sas_attach_transport(struct sas_function_template *ft) 792{ 793 struct sas_internal *i; 794 int count; 795 796 i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL); 797 if (!i) 798 return NULL; 799 memset(i, 0, sizeof(struct sas_internal)); 800 801 i->t.user_scan = sas_user_scan; 802 803 i->t.host_attrs.ac.attrs = &i->host_attrs[0]; 804 i->t.host_attrs.ac.class = &sas_host_class.class; 805 i->t.host_attrs.ac.match = sas_host_match; 806 transport_container_register(&i->t.host_attrs); 807 i->t.host_size = sizeof(struct sas_host_attrs); 808 809 i->phy_attr_cont.ac.class = &sas_phy_class.class; 810 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; 811 i->phy_attr_cont.ac.match = sas_phy_match; 812 transport_container_register(&i->phy_attr_cont); 813 814 i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 815 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 816 i->rphy_attr_cont.ac.match = sas_rphy_match; 817 transport_container_register(&i->rphy_attr_cont); 818 819 i->f = ft; 820 821 count = 0; 822 i->host_attrs[count] = NULL; 823 824 count = 0; 825 SETUP_PORT_ATTRIBUTE(initiator_port_protocols); 826 SETUP_PORT_ATTRIBUTE(target_port_protocols); 827 SETUP_PORT_ATTRIBUTE(device_type); 828 SETUP_PORT_ATTRIBUTE(sas_address); 829 SETUP_PORT_ATTRIBUTE(phy_identifier); 830 SETUP_PORT_ATTRIBUTE(port_identifier); 831 SETUP_PORT_ATTRIBUTE(negotiated_linkrate); 832 SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); 833 SETUP_PORT_ATTRIBUTE(minimum_linkrate); 834 SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); 835 SETUP_PORT_ATTRIBUTE(maximum_linkrate); 836 837 SETUP_PORT_ATTRIBUTE(invalid_dword_count); 838 SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 839 SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 840 SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 841 SETUP_PORT_ATTRIBUTE_WRONLY(link_reset); 842 SETUP_PORT_ATTRIBUTE_WRONLY(hard_reset); 843 i->phy_attrs[count] = NULL; 844 845 count = 0; 846 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 847 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 848 SETUP_RPORT_ATTRIBUTE(rphy_device_type); 849 SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 850 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 851 i->rphy_attrs[count] = NULL; 852 853 return &i->t; 854} 855EXPORT_SYMBOL(sas_attach_transport); 856 857/** 858 * sas_release_transport -- release SAS transport template instance 859 * @t: transport template instance 860 */ 861void sas_release_transport(struct scsi_transport_template *t) 862{ 863 struct sas_internal *i = to_sas_internal(t); 864 865 transport_container_unregister(&i->t.host_attrs); 866 transport_container_unregister(&i->phy_attr_cont); 867 transport_container_unregister(&i->rphy_attr_cont); 868 869 kfree(i); 870} 871EXPORT_SYMBOL(sas_release_transport); 872 873static __init int sas_transport_init(void) 874{ 875 int error; 876 877 error = transport_class_register(&sas_host_class); 878 if (error) 879 goto out; 880 error = transport_class_register(&sas_phy_class); 881 if (error) 882 goto out_unregister_transport; 883 error = transport_class_register(&sas_rphy_class); 884 if (error) 885 goto out_unregister_phy; 886 887 return 0; 888 889 out_unregister_phy: 890 transport_class_unregister(&sas_phy_class); 891 out_unregister_transport: 892 transport_class_unregister(&sas_host_class); 893 out: 894 return error; 895 896} 897 898static void __exit sas_transport_exit(void) 899{ 900 transport_class_unregister(&sas_host_class); 901 transport_class_unregister(&sas_phy_class); 902 transport_class_unregister(&sas_rphy_class); 903} 904 905MODULE_AUTHOR("Christoph Hellwig"); 906MODULE_DESCRIPTION("SAS Transphy Attributes"); 907MODULE_LICENSE("GPL"); 908 909module_init(sas_transport_init); 910module_exit(sas_transport_exit); 911