// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2007-2010 Red Hat, Inc. * by Peter Jones <pjones@redhat.com> * Copyright 2008 IBM, Inc. * by Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Copyright 2008 * by Konrad Rzeszutek <ketuzsezr@darnok.org> * * This code exposes the iSCSI Boot Format Table to userland via sysfs. * * Changelog: * * 06 Jan 2010 - Peter Jones <pjones@redhat.com> * New changelog entries are in the git log from now on. Not here. * * 14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org> * Updated comments and copyrights. (v0.4.9) * * 11 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Converted to using ibft_addr. (v0.4.8) * * 8 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Combined two functions in one: reserve_ibft_region. (v0.4.7) * * 30 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added logic to handle IPv6 addresses. (v0.4.6) * * 25 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added logic to handle badly not-to-spec iBFT. (v0.4.5) * * 4 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added __init to function declarations. (v0.4.4) * * 21 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Updated kobject registration, combined unregister functions in one * and code and style cleanup. (v0.4.3) * * 5 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added end-markers to enums and re-organized kobject registration. (v0.4.2) * * 4 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1) * * 28 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added sysfs-ibft documentation, moved 'find_ibft' function to * in its own file and added text attributes for every struct field. (v0.4) * * 21 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added text attributes emulating OpenFirmware /proc/device-tree naming. * Removed binary /sysfs interface (v0.3) * * 29 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * Added functionality in setup.c to reserve iBFT region. (v0.2) * * 27 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> * First version exposing iBFT data via a binary /sysfs. (v0.1)
*/
/* * The kobject different types and its names. *
*/ enum ibft_id {
id_reserved = 0, /* We don't support. */
id_control = 1, /* Should show up only once and is not exported. */
id_initiator = 2,
id_nic = 3,
id_target = 4,
id_extensions = 5, /* We don't support. */
id_end_marker,
};
/* * Helper function to verify the IBFT header.
*/ staticint ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
{ if (hdr->id != id) {
printk(KERN_ERR "iBFT error: We expected the %s " \ "field header.id to have %d but " \ "found %d instead!\n", t, id, hdr->id); return -ENODEV;
} if (length && hdr->length != length) {
printk(KERN_ERR "iBFT error: We expected the %s " \ "field header.length to have %d but " \ "found %d instead!\n", t, length, hdr->length); return -ENODEV;
}
return 0;
}
/* * Routines for parsing the iBFT data to be human readable.
*/ static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
{ struct ibft_kobject *entry = data; struct ibft_initiator *initiator = entry->initiator; void *ibft_loc = entry->header; char *str = buf;
if (!initiator) return 0;
switch (type) { case ISCSI_BOOT_INI_INDEX:
str += sprintf(str, "%d\n", initiator->hdr.index); break; case ISCSI_BOOT_INI_FLAGS:
str += sprintf(str, "%d\n", initiator->hdr.flags); break; case ISCSI_BOOT_INI_ISNS_SERVER:
str += sprintf_ipaddr(str, initiator->isns_server); break; case ISCSI_BOOT_INI_SLP_SERVER:
str += sprintf_ipaddr(str, initiator->slp_server); break; case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
str += sprintf_ipaddr(str, initiator->pri_radius_server); break; case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
str += sprintf_ipaddr(str, initiator->sec_radius_server); break; case ISCSI_BOOT_INI_INITIATOR_NAME:
str += sprintf_string(str, initiator->initiator_name_len,
(char *)ibft_loc +
initiator->initiator_name_off); break; default: break;
}
/* Sanity checking of iBFT. */ if (ibft_addr->header.revision != 1) {
printk(KERN_ERR "iBFT module supports only revision 1, " \ "while this is %d.\n",
ibft_addr->header.revision); return -ENOENT;
} for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
csum += *pos;
if (csum) {
printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum); return -ENOENT;
}
return 0;
}
/* * Helper routiners to check to determine if the entry is valid * in the proper iBFT structure.
*/ static umode_t ibft_check_nic_for(void *data, int type)
{ struct ibft_kobject *entry = data; struct ibft_nic *nic = entry->nic;
umode_t rc = 0;
switch (type) { case ISCSI_BOOT_ETH_INDEX: case ISCSI_BOOT_ETH_FLAGS:
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_IP_ADDR: 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; break; case ISCSI_BOOT_ETH_ORIGIN:
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_GATEWAY: if (address_not_null(nic->gateway))
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_PRIMARY_DNS: if (address_not_null(nic->primary_dns))
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_SECONDARY_DNS: if (address_not_null(nic->secondary_dns))
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_DHCP: if (address_not_null(nic->dhcp))
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_VLAN: case ISCSI_BOOT_ETH_MAC:
rc = S_IRUGO; break; case ISCSI_BOOT_ETH_HOSTNAME: if (nic->hostname_off)
rc = S_IRUGO; break; default: break;
}
switch (type) { case ISCSI_BOOT_TGT_INDEX: case ISCSI_BOOT_TGT_FLAGS: case ISCSI_BOOT_TGT_IP_ADDR: case ISCSI_BOOT_TGT_PORT: case ISCSI_BOOT_TGT_LUN: case ISCSI_BOOT_TGT_NIC_ASSOC: case ISCSI_BOOT_TGT_CHAP_TYPE:
rc = S_IRUGO; break; case ISCSI_BOOT_TGT_NAME: if (tgt->tgt_name_len)
rc = S_IRUGO; break; case ISCSI_BOOT_TGT_CHAP_NAME: case ISCSI_BOOT_TGT_CHAP_SECRET: if (tgt->chap_name_len)
rc = S_IRUGO; break; case ISCSI_BOOT_TGT_REV_CHAP_NAME: case ISCSI_BOOT_TGT_REV_CHAP_SECRET: if (tgt->rev_chap_name_len)
rc = S_IRUGO; break; default: break;
}
switch (type) { case ISCSI_BOOT_INI_INDEX: case ISCSI_BOOT_INI_FLAGS:
rc = S_IRUGO; break; case ISCSI_BOOT_INI_ISNS_SERVER: if (address_not_null(init->isns_server))
rc = S_IRUGO; break; case ISCSI_BOOT_INI_SLP_SERVER: if (address_not_null(init->slp_server))
rc = S_IRUGO; break; case ISCSI_BOOT_INI_PRI_RADIUS_SERVER: if (address_not_null(init->pri_radius_server))
rc = S_IRUGO; break; case ISCSI_BOOT_INI_SEC_RADIUS_SERVER: if (address_not_null(init->sec_radius_server))
rc = S_IRUGO; break; case ISCSI_BOOT_INI_INITIATOR_NAME: if (init->initiator_name_len)
rc = S_IRUGO; break; default: break;
}
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;
}
ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL); if (!ibft_kobj) return -ENOMEM;
ibft_kobj->header = header;
ibft_kobj->hdr = hdr;
switch (hdr->id) { case id_initiator:
rc = ibft_verify_hdr("initiator", hdr, id_initiator, sizeof(*ibft_kobj->initiator)); if (rc) break;
boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
ibft_kobj,
ibft_attr_show_initiator,
ibft_check_initiator_for,
ibft_kobj_release); if (!boot_kobj) {
rc = -ENOMEM; goto free_ibft_obj;
} break; case id_nic:
rc = ibft_verify_hdr("ethernet", hdr, id_nic, sizeof(*ibft_kobj->nic)); if (rc) break;
boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
ibft_kobj,
ibft_attr_show_nic,
ibft_check_nic_for,
ibft_kobj_release); if (!boot_kobj) {
rc = -ENOMEM; goto free_ibft_obj;
} break; case id_target:
rc = ibft_verify_hdr("target", hdr, id_target, sizeof(*ibft_kobj->tgt)); if (rc) break;
boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
ibft_kobj,
ibft_attr_show_target,
ibft_check_tgt_for,
ibft_kobj_release); if (!boot_kobj) {
rc = -ENOMEM; goto free_ibft_obj;
} break; case id_reserved: case id_control: case id_extensions: /* Fields which we don't support. Ignore them */
rc = 1; break; default:
printk(KERN_ERR "iBFT has unknown structure type (%d). " \ "Report this bug to %.6s!\n", hdr->id,
header->header.oem_id);
rc = 1; break;
}
if (rc) { /* Skip adding this kobject, but exit with non-fatal error. */
rc = 0; goto free_ibft_obj;
}
if (hdr->id == id_nic) { /* * We don't search for the device in other domains than * zero. This is because on x86 platforms the BIOS * executes only devices which are in domain 0. Furthermore, the * iBFT spec doesn't have a domain id field :-(
*/
pci_dev = pci_get_domain_bus_and_slot(0,
(nic->pci_bdf & 0xff00) >> 8,
(nic->pci_bdf & 0xff)); if (pci_dev) {
rc = sysfs_create_link(&boot_kobj->kobj,
&pci_dev->dev.kobj, "device");
pci_dev_put(pci_dev);
}
} return 0;
free_ibft_obj:
kfree(ibft_kobj); return rc;
}
/* * Scan the IBFT table structure for the NIC and Target fields. When * found add them on the passed-in list. We do not support the other * fields at this point, so they are skipped.
*/ staticint __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;
u16 eot_offset;
for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
acpi_get_table(ibft_signs[i].sign, 0, &table);
ibft_addr = (struct acpi_table_ibft *)table;
}
} #else staticvoid __init acpi_find_ibft_region(void)
{
} #endif #ifdef CONFIG_ISCSI_IBFT_FIND staticint __init acpi_find_isa_region(void)
{ if (ibft_phys_addr) {
ibft_addr = isa_bus_to_virt(ibft_phys_addr); return 0;
} return -ENODEV;
} #else staticint __init acpi_find_isa_region(void)
{ return -ENODEV;
} #endif /* * ibft_init() - creates sysfs tree entries for the iBFT data.
*/ staticint __init ibft_init(void)
{ int rc = 0;
/* As on UEFI systems the setup_arch()/reserve_ibft_region() is called before ACPI tables are parsed and it only does legacy finding.
*/ if (acpi_find_isa_region())
acpi_find_ibft_region();
if (ibft_addr) {
pr_info("iBFT detected.\n");
rc = ibft_check_device(); if (rc) return rc;
boot_kset = iscsi_boot_create_kset("ibft"); if (!boot_kset) return -ENOMEM;
/* Scan the IBFT for data and register the kobjects. */
rc = ibft_register_kobjects(ibft_addr); if (rc) goto out_free;
} else
printk(KERN_INFO "No iBFT detected.\n");
return 0;
out_free:
ibft_cleanup(); return rc;
}
module_init(ibft_init);
module_exit(ibft_exit);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.