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>
This commit is contained in:
parent
9a99425f07
commit
b3c8eb5038
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue