From 9a99425f0736a416442525ac7b15903173888b86 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 25 Feb 2016 09:56:04 -0800 Subject: iscsi_ibft: Add prefix-len attr and display netmask The iBFT table only specifies a prefix length, not a netmask. And the netmask is pretty much pointless for IPv6. So introduce a new attribute 'prefix-len'. Some older user-space code might rely on the netmask attribute being present, so we should always display it. Changes from v1: - Combined two patches into one Changes from v2: - Cleaned up/corrected wording for patch description Signed-off-by: Hannes Reinecke Signed-off-by: Lee Duncan Reviewed-by: Mike Christie Signed-off-by: Konrad Rzeszutek Wilk --- drivers/firmware/iscsi_ibft.c | 4 ++++ drivers/scsi/iscsi_boot_sysfs.c | 5 +++++ include/linux/iscsi_boot_sysfs.h | 1 + 3 files changed, 10 insertions(+) diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 72791232e46b..81037e5fe301 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -319,6 +319,9 @@ static ssize_t ibft_attr_show_nic(void *data, int type, char *buf) val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1)); str += sprintf(str, "%pI4", &val); break; + case ISCSI_BOOT_ETH_PREFIX_LEN: + str += sprintf(str, "%d\n", nic->subnet_mask_prefix); + break; case ISCSI_BOOT_ETH_ORIGIN: str += sprintf(str, "%d\n", nic->origin); break; @@ -460,6 +463,7 @@ static umode_t ibft_check_nic_for(void *data, int type) if (address_not_null(nic->ip_addr)) rc = S_IRUGO; break; + case ISCSI_BOOT_ETH_PREFIX_LEN: case ISCSI_BOOT_ETH_SUBNET_MASK: if (nic->subnet_mask_prefix) rc = S_IRUGO; diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index 680bf6f0ce76..8f0ea97cf31f 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -166,6 +166,7 @@ static struct attribute_group iscsi_boot_target_attr_group = { iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); +iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN); iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); @@ -181,6 +182,7 @@ static struct attribute *ethernet_attrs[] = { &iscsi_boot_attr_eth_index.attr, &iscsi_boot_attr_eth_flags.attr, &iscsi_boot_attr_eth_ip.attr, + &iscsi_boot_attr_eth_prefix.attr, &iscsi_boot_attr_eth_subnet.attr, &iscsi_boot_attr_eth_origin.attr, &iscsi_boot_attr_eth_gateway.attr, @@ -208,6 +210,9 @@ static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, else if (attr == &iscsi_boot_attr_eth_ip.attr) return boot_kobj->is_visible(boot_kobj->data, ISCSI_BOOT_ETH_IP_ADDR); + else if (attr == &iscsi_boot_attr_eth_prefix.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_PREFIX_LEN); else if (attr == &iscsi_boot_attr_eth_subnet.attr) return boot_kobj->is_visible(boot_kobj->data, ISCSI_BOOT_ETH_SUBNET_MASK); diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h index 2a8b1659bf35..548d55395488 100644 --- a/include/linux/iscsi_boot_sysfs.h +++ b/include/linux/iscsi_boot_sysfs.h @@ -23,6 +23,7 @@ enum iscsi_boot_eth_properties_enum { ISCSI_BOOT_ETH_INDEX, ISCSI_BOOT_ETH_FLAGS, ISCSI_BOOT_ETH_IP_ADDR, + ISCSI_BOOT_ETH_PREFIX_LEN, ISCSI_BOOT_ETH_SUBNET_MASK, ISCSI_BOOT_ETH_ORIGIN, ISCSI_BOOT_ETH_GATEWAY, -- cgit v1.2.3 From b3c8eb50383178f3a4dcf1dc867001156da6473d Mon Sep 17 00:00:00 2001 From: David Bond Date: Wed, 23 Mar 2016 21:49:26 -0400 Subject: 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 Signed-off-by: David Bond Signed-off-by: Konrad Rzeszutek Wilk --- Documentation/ABI/testing/sysfs-ibft | 10 ++++++ drivers/firmware/iscsi_ibft.c | 66 +++++++++++++++++++++++++++++++++++- drivers/scsi/iscsi_boot_sysfs.c | 62 +++++++++++++++++++++++++++++++++ include/linux/iscsi_boot_sysfs.h | 13 +++++++ 4 files changed, 150 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-ibft b/Documentation/ABI/testing/sysfs-ibft index cac3930bdb04..7d6725fe6143 100644 --- a/Documentation/ABI/testing/sysfs-ibft +++ b/Documentation/ABI/testing/sysfs-ibft @@ -21,3 +21,13 @@ Contact: Konrad Rzeszutek Description: The /sys/firmware/ibft/ethernetX directory will contain files that expose the iSCSI Boot Firmware Table NIC data. Usually this contains the IP address, MAC, and gateway of the NIC. + +What: /sys/firmware/ibft/acpi_header +Date: March 2016 +Contact: David Bond +Description: The /sys/firmware/ibft/acpi_header directory will contain files + that expose the SIGNATURE, OEM_ID, and OEM_TABLE_ID fields of the + acpi table header of the iBFT structure. This will allow for + identification of the creator of the table which is useful in + determining quirks associated with some adapters when used in + hardware vs software iscsi initiator mode. diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 81037e5fe301..14042a64bdd5 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -418,6 +418,31 @@ static ssize_t ibft_attr_show_target(void *data, int type, char *buf) return str - buf; } +static ssize_t ibft_attr_show_acpitbl(void *data, int type, char *buf) +{ + struct ibft_kobject *entry = data; + char *str = buf; + + switch (type) { + case ISCSI_BOOT_ACPITBL_SIGNATURE: + str += sprintf_string(str, ACPI_NAME_SIZE, + entry->header->header.signature); + break; + case ISCSI_BOOT_ACPITBL_OEM_ID: + str += sprintf_string(str, ACPI_OEM_ID_SIZE, + entry->header->header.oem_id); + break; + case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID: + str += sprintf_string(str, ACPI_OEM_TABLE_ID_SIZE, + entry->header->header.oem_table_id); + break; + default: + break; + } + + return str - buf; +} + static int __init ibft_check_device(void) { int len; @@ -576,6 +601,24 @@ static umode_t __init ibft_check_initiator_for(void *data, int type) return rc; } +static umode_t __init ibft_check_acpitbl_for(void *data, int type) +{ + + umode_t rc = 0; + + switch (type) { + case ISCSI_BOOT_ACPITBL_SIGNATURE: + case ISCSI_BOOT_ACPITBL_OEM_ID: + case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID: + rc = S_IRUGO; + break; + default: + break; + } + + return rc; +} + static void ibft_kobj_release(void *data) { kfree(data); @@ -699,6 +742,8 @@ free_ibft_obj: static int __init ibft_register_kobjects(struct acpi_table_ibft *header) { struct ibft_control *control = NULL; + struct iscsi_boot_kobj *boot_kobj; + struct ibft_kobject *ibft_kobj; void *ptr, *end; int rc = 0; u16 offset; @@ -726,6 +771,25 @@ static int __init ibft_register_kobjects(struct acpi_table_ibft *header) break; } } + if (rc) + return rc; + + ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL); + if (!ibft_kobj) + return -ENOMEM; + + ibft_kobj->header = header; + ibft_kobj->hdr = NULL; /*for ibft_unregister*/ + + boot_kobj = iscsi_boot_create_acpitbl(boot_kset, 0, + ibft_kobj, + ibft_attr_show_acpitbl, + ibft_check_acpitbl_for, + ibft_kobj_release); + if (!boot_kobj) { + kfree(ibft_kobj); + rc = -ENOMEM; + } return rc; } @@ -738,7 +802,7 @@ static void ibft_unregister(void) list_for_each_entry_safe(boot_kobj, tmp_kobj, &boot_kset->kobj_list, list) { ibft_kobj = boot_kobj->data; - if (ibft_kobj->hdr->id == id_nic) + if (ibft_kobj->hdr && ibft_kobj->hdr->id == id_nic) sysfs_remove_link(&boot_kobj->kobj, "device"); }; } diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index 8f0ea97cf31f..d453667612f8 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -306,6 +306,42 @@ static struct attribute_group iscsi_boot_initiator_attr_group = { .is_visible = iscsi_boot_ini_attr_is_visible, }; +/* iBFT ACPI Table attributes */ +iscsi_boot_rd_attr(acpitbl_signature, signature, ISCSI_BOOT_ACPITBL_SIGNATURE); +iscsi_boot_rd_attr(acpitbl_oem_id, oem_id, ISCSI_BOOT_ACPITBL_OEM_ID); +iscsi_boot_rd_attr(acpitbl_oem_table_id, oem_table_id, + ISCSI_BOOT_ACPITBL_OEM_TABLE_ID); + +static struct attribute *acpitbl_attrs[] = { + &iscsi_boot_attr_acpitbl_signature.attr, + &iscsi_boot_attr_acpitbl_oem_id.attr, + &iscsi_boot_attr_acpitbl_oem_table_id.attr, + NULL +}; + +static umode_t iscsi_boot_acpitbl_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_acpitbl_signature.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ACPITBL_SIGNATURE); + if (attr == &iscsi_boot_attr_acpitbl_oem_id.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ACPITBL_OEM_ID); + if (attr == &iscsi_boot_attr_acpitbl_oem_table_id.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ACPITBL_OEM_TABLE_ID); + return 0; +} + +static struct attribute_group iscsi_boot_acpitbl_attr_group = { + .attrs = acpitbl_attrs, + .is_visible = iscsi_boot_acpitbl_attr_is_visible, +}; + static struct iscsi_boot_kobj * iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, struct attribute_group *attr_group, @@ -435,6 +471,32 @@ iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, } EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); +/** + * iscsi_boot_create_acpitbl() - create boot acpi table sysfs dir + * @boot_kset: boot kset + * @index: not used + * @data: driver specific data + * @show: attr show function + * @is_visible: attr visibility function + * @release: release function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the acpitbl kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_acpitbl(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show)(void *data, int type, char *buf), + umode_t (*is_visible)(void *data, int type), + void (*release)(void *data)) +{ + return iscsi_boot_create_kobj(boot_kset, + &iscsi_boot_acpitbl_attr_group, + "acpi_header", index, data, show, + is_visible, release); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_acpitbl); + /** * iscsi_boot_create_kset() - creates root sysfs tree * @set_name: name of root dir diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h index 548d55395488..10923d730486 100644 --- a/include/linux/iscsi_boot_sysfs.h +++ b/include/linux/iscsi_boot_sysfs.h @@ -64,6 +64,12 @@ enum iscsi_boot_initiator_properties_enum { ISCSI_BOOT_INI_END_MARKER, }; +enum iscsi_boot_acpitbl_properties_enum { + ISCSI_BOOT_ACPITBL_SIGNATURE, + ISCSI_BOOT_ACPITBL_OEM_ID, + ISCSI_BOOT_ACPITBL_OEM_TABLE_ID, +}; + struct attribute_group; struct iscsi_boot_kobj { @@ -127,6 +133,13 @@ iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, umode_t (*is_visible) (void *data, int type), void (*release) (void *data)); +struct iscsi_boot_kobj * +iscsi_boot_create_acpitbl(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show)(void *data, int type, char *buf), + umode_t (*is_visible)(void *data, int type), + void (*release)(void *data)); + struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name); struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno); void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset); -- cgit v1.2.3