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