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