Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ibft: Expose iBFT acpi header via sysfs

Some ethernet adapter vendors are supplying products which support optional
(payed license) features. On some adapters this includes a hardware iscsi
initiator. The same adapters in a normal (no extra licenses) mode of
operation can be used as a software iscsi initiator. In addition, software
iscsi boot initiators are becoming a standard part of many vendors uefi
implementations. This is creating difficulties during early boot/install
determining the proper configuration method for these adapters when they
are used as a boot device.

The attached patch creates sysfs entries to expose information from the
acpi header of the ibft table. This information allows for a method to
easily determining if an ibft table was created by a ethernet card's
firmware or the system uefi/bios. In the case of a hardware initiator this
information in combination with the pci vendor and device id can be used
to ascertain any vendor specific behaviors that need to be accommodated.

Reviewed-by: Lee Duncan <lduncan@suse.com>
Signed-off-by: David Bond <dbond@suse.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

authored by

David Bond and committed by
Konrad Rzeszutek Wilk
b3c8eb50 9a99425f

+150 -1
+10
Documentation/ABI/testing/sysfs-ibft
··· 21 21 Description: The /sys/firmware/ibft/ethernetX directory will contain 22 22 files that expose the iSCSI Boot Firmware Table NIC data. 23 23 Usually this contains the IP address, MAC, and gateway of the NIC. 24 + 25 + What: /sys/firmware/ibft/acpi_header 26 + Date: March 2016 27 + Contact: David Bond <dbond@suse.com> 28 + Description: The /sys/firmware/ibft/acpi_header directory will contain files 29 + that expose the SIGNATURE, OEM_ID, and OEM_TABLE_ID fields of the 30 + acpi table header of the iBFT structure. This will allow for 31 + identification of the creator of the table which is useful in 32 + determining quirks associated with some adapters when used in 33 + hardware vs software iscsi initiator mode.
+65 -1
drivers/firmware/iscsi_ibft.c
··· 418 418 return str - buf; 419 419 } 420 420 421 + static ssize_t ibft_attr_show_acpitbl(void *data, int type, char *buf) 422 + { 423 + struct ibft_kobject *entry = data; 424 + char *str = buf; 425 + 426 + switch (type) { 427 + case ISCSI_BOOT_ACPITBL_SIGNATURE: 428 + str += sprintf_string(str, ACPI_NAME_SIZE, 429 + entry->header->header.signature); 430 + break; 431 + case ISCSI_BOOT_ACPITBL_OEM_ID: 432 + str += sprintf_string(str, ACPI_OEM_ID_SIZE, 433 + entry->header->header.oem_id); 434 + break; 435 + case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID: 436 + str += sprintf_string(str, ACPI_OEM_TABLE_ID_SIZE, 437 + entry->header->header.oem_table_id); 438 + break; 439 + default: 440 + break; 441 + } 442 + 443 + return str - buf; 444 + } 445 + 421 446 static int __init ibft_check_device(void) 422 447 { 423 448 int len; ··· 601 576 return rc; 602 577 } 603 578 579 + static umode_t __init ibft_check_acpitbl_for(void *data, int type) 580 + { 581 + 582 + umode_t rc = 0; 583 + 584 + switch (type) { 585 + case ISCSI_BOOT_ACPITBL_SIGNATURE: 586 + case ISCSI_BOOT_ACPITBL_OEM_ID: 587 + case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID: 588 + rc = S_IRUGO; 589 + break; 590 + default: 591 + break; 592 + } 593 + 594 + return rc; 595 + } 596 + 604 597 static void ibft_kobj_release(void *data) 605 598 { 606 599 kfree(data); ··· 742 699 static int __init ibft_register_kobjects(struct acpi_table_ibft *header) 743 700 { 744 701 struct ibft_control *control = NULL; 702 + struct iscsi_boot_kobj *boot_kobj; 703 + struct ibft_kobject *ibft_kobj; 745 704 void *ptr, *end; 746 705 int rc = 0; 747 706 u16 offset; ··· 771 726 break; 772 727 } 773 728 } 729 + if (rc) 730 + return rc; 731 + 732 + ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL); 733 + if (!ibft_kobj) 734 + return -ENOMEM; 735 + 736 + ibft_kobj->header = header; 737 + ibft_kobj->hdr = NULL; /*for ibft_unregister*/ 738 + 739 + boot_kobj = iscsi_boot_create_acpitbl(boot_kset, 0, 740 + ibft_kobj, 741 + ibft_attr_show_acpitbl, 742 + ibft_check_acpitbl_for, 743 + ibft_kobj_release); 744 + if (!boot_kobj) { 745 + kfree(ibft_kobj); 746 + rc = -ENOMEM; 747 + } 774 748 775 749 return rc; 776 750 } ··· 802 738 list_for_each_entry_safe(boot_kobj, tmp_kobj, 803 739 &boot_kset->kobj_list, list) { 804 740 ibft_kobj = boot_kobj->data; 805 - if (ibft_kobj->hdr->id == id_nic) 741 + if (ibft_kobj->hdr && ibft_kobj->hdr->id == id_nic) 806 742 sysfs_remove_link(&boot_kobj->kobj, "device"); 807 743 }; 808 744 }
+62
drivers/scsi/iscsi_boot_sysfs.c
··· 306 306 .is_visible = iscsi_boot_ini_attr_is_visible, 307 307 }; 308 308 309 + /* iBFT ACPI Table attributes */ 310 + iscsi_boot_rd_attr(acpitbl_signature, signature, ISCSI_BOOT_ACPITBL_SIGNATURE); 311 + iscsi_boot_rd_attr(acpitbl_oem_id, oem_id, ISCSI_BOOT_ACPITBL_OEM_ID); 312 + iscsi_boot_rd_attr(acpitbl_oem_table_id, oem_table_id, 313 + ISCSI_BOOT_ACPITBL_OEM_TABLE_ID); 314 + 315 + static struct attribute *acpitbl_attrs[] = { 316 + &iscsi_boot_attr_acpitbl_signature.attr, 317 + &iscsi_boot_attr_acpitbl_oem_id.attr, 318 + &iscsi_boot_attr_acpitbl_oem_table_id.attr, 319 + NULL 320 + }; 321 + 322 + static umode_t iscsi_boot_acpitbl_attr_is_visible(struct kobject *kobj, 323 + struct attribute *attr, int i) 324 + { 325 + struct iscsi_boot_kobj *boot_kobj = 326 + container_of(kobj, struct iscsi_boot_kobj, kobj); 327 + 328 + if (attr == &iscsi_boot_attr_acpitbl_signature.attr) 329 + return boot_kobj->is_visible(boot_kobj->data, 330 + ISCSI_BOOT_ACPITBL_SIGNATURE); 331 + if (attr == &iscsi_boot_attr_acpitbl_oem_id.attr) 332 + return boot_kobj->is_visible(boot_kobj->data, 333 + ISCSI_BOOT_ACPITBL_OEM_ID); 334 + if (attr == &iscsi_boot_attr_acpitbl_oem_table_id.attr) 335 + return boot_kobj->is_visible(boot_kobj->data, 336 + ISCSI_BOOT_ACPITBL_OEM_TABLE_ID); 337 + return 0; 338 + } 339 + 340 + static struct attribute_group iscsi_boot_acpitbl_attr_group = { 341 + .attrs = acpitbl_attrs, 342 + .is_visible = iscsi_boot_acpitbl_attr_is_visible, 343 + }; 344 + 309 345 static struct iscsi_boot_kobj * 310 346 iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, 311 347 struct attribute_group *attr_group, ··· 470 434 is_visible, release); 471 435 } 472 436 EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); 437 + 438 + /** 439 + * iscsi_boot_create_acpitbl() - create boot acpi table sysfs dir 440 + * @boot_kset: boot kset 441 + * @index: not used 442 + * @data: driver specific data 443 + * @show: attr show function 444 + * @is_visible: attr visibility function 445 + * @release: release function 446 + * 447 + * Note: The boot sysfs lib will free the data passed in for the caller 448 + * when all refs to the acpitbl kobject have been released. 449 + */ 450 + struct iscsi_boot_kobj * 451 + iscsi_boot_create_acpitbl(struct iscsi_boot_kset *boot_kset, int index, 452 + void *data, 453 + ssize_t (*show)(void *data, int type, char *buf), 454 + umode_t (*is_visible)(void *data, int type), 455 + void (*release)(void *data)) 456 + { 457 + return iscsi_boot_create_kobj(boot_kset, 458 + &iscsi_boot_acpitbl_attr_group, 459 + "acpi_header", index, data, show, 460 + is_visible, release); 461 + } 462 + EXPORT_SYMBOL_GPL(iscsi_boot_create_acpitbl); 473 463 474 464 /** 475 465 * iscsi_boot_create_kset() - creates root sysfs tree
+13
include/linux/iscsi_boot_sysfs.h
··· 64 64 ISCSI_BOOT_INI_END_MARKER, 65 65 }; 66 66 67 + enum iscsi_boot_acpitbl_properties_enum { 68 + ISCSI_BOOT_ACPITBL_SIGNATURE, 69 + ISCSI_BOOT_ACPITBL_OEM_ID, 70 + ISCSI_BOOT_ACPITBL_OEM_TABLE_ID, 71 + }; 72 + 67 73 struct attribute_group; 68 74 69 75 struct iscsi_boot_kobj { ··· 132 126 ssize_t (*show) (void *data, int type, char *buf), 133 127 umode_t (*is_visible) (void *data, int type), 134 128 void (*release) (void *data)); 129 + 130 + struct iscsi_boot_kobj * 131 + iscsi_boot_create_acpitbl(struct iscsi_boot_kset *boot_kset, int index, 132 + void *data, 133 + ssize_t (*show)(void *data, int type, char *buf), 134 + umode_t (*is_visible)(void *data, int type), 135 + void (*release)(void *data)); 135 136 136 137 struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name); 137 138 struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno);