Skip to content

Commit

Permalink
ibft: Expose iBFT acpi header via sysfs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Bond authored and Konrad Rzeszutek Wilk committed May 16, 2016
1 parent 9a99425 commit b3c8eb5
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Documentation/ABI/testing/sysfs-ibft
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ Contact: Konrad Rzeszutek <ketuzsezr@darnok.org>
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 <dbond@suse.com>
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.
66 changes: 65 additions & 1 deletion drivers/firmware/iscsi_ibft.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -699,6 +742,8 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header,
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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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");
};
}
Expand Down
62 changes: 62 additions & 0 deletions drivers/scsi/iscsi_boot_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions include/linux/iscsi_boot_sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit b3c8eb5

Please sign in to comment.