cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iscsi_ibft.c (21443B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  Copyright 2007-2010 Red Hat, Inc.
      4 *  by Peter Jones <pjones@redhat.com>
      5 *  Copyright 2008 IBM, Inc.
      6 *  by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
      7 *  Copyright 2008
      8 *  by Konrad Rzeszutek <ketuzsezr@darnok.org>
      9 *
     10 * This code exposes the iSCSI Boot Format Table to userland via sysfs.
     11 *
     12 * Changelog:
     13 *
     14 *  06 Jan 2010 - Peter Jones <pjones@redhat.com>
     15 *    New changelog entries are in the git log from now on.  Not here.
     16 *
     17 *  14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org>
     18 *    Updated comments and copyrights. (v0.4.9)
     19 *
     20 *  11 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     21 *    Converted to using ibft_addr. (v0.4.8)
     22 *
     23 *   8 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     24 *    Combined two functions in one: reserve_ibft_region. (v0.4.7)
     25 *
     26 *  30 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     27 *   Added logic to handle IPv6 addresses. (v0.4.6)
     28 *
     29 *  25 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     30 *   Added logic to handle badly not-to-spec iBFT. (v0.4.5)
     31 *
     32 *   4 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     33 *   Added __init to function declarations. (v0.4.4)
     34 *
     35 *  21 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     36 *   Updated kobject registration, combined unregister functions in one
     37 *   and code and style cleanup. (v0.4.3)
     38 *
     39 *   5 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     40 *   Added end-markers to enums and re-organized kobject registration. (v0.4.2)
     41 *
     42 *   4 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     43 *   Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1)
     44 *
     45 *  28 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     46 *   Added sysfs-ibft documentation, moved 'find_ibft' function to
     47 *   in its own file and added text attributes for every struct field.  (v0.4)
     48 *
     49 *  21 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     50 *   Added text attributes emulating OpenFirmware /proc/device-tree naming.
     51 *   Removed binary /sysfs interface (v0.3)
     52 *
     53 *  29 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     54 *   Added functionality in setup.c to reserve iBFT region. (v0.2)
     55 *
     56 *  27 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
     57 *   First version exposing iBFT data via a binary /sysfs. (v0.1)
     58 */
     59
     60
     61#include <linux/blkdev.h>
     62#include <linux/capability.h>
     63#include <linux/ctype.h>
     64#include <linux/device.h>
     65#include <linux/err.h>
     66#include <linux/init.h>
     67#include <linux/iscsi_ibft.h>
     68#include <linux/limits.h>
     69#include <linux/module.h>
     70#include <linux/pci.h>
     71#include <linux/slab.h>
     72#include <linux/stat.h>
     73#include <linux/string.h>
     74#include <linux/types.h>
     75#include <linux/acpi.h>
     76#include <linux/iscsi_boot_sysfs.h>
     77
     78#define IBFT_ISCSI_VERSION "0.5.0"
     79#define IBFT_ISCSI_DATE "2010-Feb-25"
     80
     81MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and "
     82	      "Konrad Rzeszutek <ketuzsezr@darnok.org>");
     83MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information");
     84MODULE_LICENSE("GPL");
     85MODULE_VERSION(IBFT_ISCSI_VERSION);
     86
     87static struct acpi_table_ibft *ibft_addr;
     88
     89struct ibft_hdr {
     90	u8 id;
     91	u8 version;
     92	u16 length;
     93	u8 index;
     94	u8 flags;
     95} __attribute__((__packed__));
     96
     97struct ibft_control {
     98	struct ibft_hdr hdr;
     99	u16 extensions;
    100	u16 initiator_off;
    101	u16 nic0_off;
    102	u16 tgt0_off;
    103	u16 nic1_off;
    104	u16 tgt1_off;
    105	u16 expansion[];
    106} __attribute__((__packed__));
    107
    108struct ibft_initiator {
    109	struct ibft_hdr hdr;
    110	char isns_server[16];
    111	char slp_server[16];
    112	char pri_radius_server[16];
    113	char sec_radius_server[16];
    114	u16 initiator_name_len;
    115	u16 initiator_name_off;
    116} __attribute__((__packed__));
    117
    118struct ibft_nic {
    119	struct ibft_hdr hdr;
    120	char ip_addr[16];
    121	u8 subnet_mask_prefix;
    122	u8 origin;
    123	char gateway[16];
    124	char primary_dns[16];
    125	char secondary_dns[16];
    126	char dhcp[16];
    127	u16 vlan;
    128	char mac[6];
    129	u16 pci_bdf;
    130	u16 hostname_len;
    131	u16 hostname_off;
    132} __attribute__((__packed__));
    133
    134struct ibft_tgt {
    135	struct ibft_hdr hdr;
    136	char ip_addr[16];
    137	u16 port;
    138	char lun[8];
    139	u8 chap_type;
    140	u8 nic_assoc;
    141	u16 tgt_name_len;
    142	u16 tgt_name_off;
    143	u16 chap_name_len;
    144	u16 chap_name_off;
    145	u16 chap_secret_len;
    146	u16 chap_secret_off;
    147	u16 rev_chap_name_len;
    148	u16 rev_chap_name_off;
    149	u16 rev_chap_secret_len;
    150	u16 rev_chap_secret_off;
    151} __attribute__((__packed__));
    152
    153/*
    154 * The kobject different types and its names.
    155 *
    156*/
    157enum ibft_id {
    158	id_reserved = 0, /* We don't support. */
    159	id_control = 1, /* Should show up only once and is not exported. */
    160	id_initiator = 2,
    161	id_nic = 3,
    162	id_target = 4,
    163	id_extensions = 5, /* We don't support. */
    164	id_end_marker,
    165};
    166
    167/*
    168 * The kobject and attribute structures.
    169 */
    170
    171struct ibft_kobject {
    172	struct acpi_table_ibft *header;
    173	union {
    174		struct ibft_initiator *initiator;
    175		struct ibft_nic *nic;
    176		struct ibft_tgt *tgt;
    177		struct ibft_hdr *hdr;
    178	};
    179};
    180
    181static struct iscsi_boot_kset *boot_kset;
    182
    183/* fully null address */
    184static const char nulls[16];
    185
    186/* IPv4-mapped IPv6 ::ffff:0.0.0.0 */
    187static const char mapped_nulls[16] = { 0x00, 0x00, 0x00, 0x00,
    188                                       0x00, 0x00, 0x00, 0x00,
    189                                       0x00, 0x00, 0xff, 0xff,
    190                                       0x00, 0x00, 0x00, 0x00 };
    191
    192static int address_not_null(u8 *ip)
    193{
    194	return (memcmp(ip, nulls, 16) && memcmp(ip, mapped_nulls, 16));
    195}
    196
    197/*
    198 * Helper functions to parse data properly.
    199 */
    200static ssize_t sprintf_ipaddr(char *buf, u8 *ip)
    201{
    202	char *str = buf;
    203
    204	if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 &&
    205	    ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 &&
    206	    ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff) {
    207		/*
    208		 * IPV4
    209		 */
    210		str += sprintf(buf, "%pI4", ip + 12);
    211	} else {
    212		/*
    213		 * IPv6
    214		 */
    215		str += sprintf(str, "%pI6", ip);
    216	}
    217	str += sprintf(str, "\n");
    218	return str - buf;
    219}
    220
    221static ssize_t sprintf_string(char *str, int len, char *buf)
    222{
    223	return sprintf(str, "%.*s\n", len, buf);
    224}
    225
    226/*
    227 * Helper function to verify the IBFT header.
    228 */
    229static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
    230{
    231	if (hdr->id != id) {
    232		printk(KERN_ERR "iBFT error: We expected the %s " \
    233				"field header.id to have %d but " \
    234				"found %d instead!\n", t, id, hdr->id);
    235		return -ENODEV;
    236	}
    237	if (length && hdr->length != length) {
    238		printk(KERN_ERR "iBFT error: We expected the %s " \
    239				"field header.length to have %d but " \
    240				"found %d instead!\n", t, length, hdr->length);
    241		return -ENODEV;
    242	}
    243
    244	return 0;
    245}
    246
    247/*
    248 *  Routines for parsing the iBFT data to be human readable.
    249 */
    250static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
    251{
    252	struct ibft_kobject *entry = data;
    253	struct ibft_initiator *initiator = entry->initiator;
    254	void *ibft_loc = entry->header;
    255	char *str = buf;
    256
    257	if (!initiator)
    258		return 0;
    259
    260	switch (type) {
    261	case ISCSI_BOOT_INI_INDEX:
    262		str += sprintf(str, "%d\n", initiator->hdr.index);
    263		break;
    264	case ISCSI_BOOT_INI_FLAGS:
    265		str += sprintf(str, "%d\n", initiator->hdr.flags);
    266		break;
    267	case ISCSI_BOOT_INI_ISNS_SERVER:
    268		str += sprintf_ipaddr(str, initiator->isns_server);
    269		break;
    270	case ISCSI_BOOT_INI_SLP_SERVER:
    271		str += sprintf_ipaddr(str, initiator->slp_server);
    272		break;
    273	case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
    274		str += sprintf_ipaddr(str, initiator->pri_radius_server);
    275		break;
    276	case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
    277		str += sprintf_ipaddr(str, initiator->sec_radius_server);
    278		break;
    279	case ISCSI_BOOT_INI_INITIATOR_NAME:
    280		str += sprintf_string(str, initiator->initiator_name_len,
    281				      (char *)ibft_loc +
    282				      initiator->initiator_name_off);
    283		break;
    284	default:
    285		break;
    286	}
    287
    288	return str - buf;
    289}
    290
    291static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
    292{
    293	struct ibft_kobject *entry = data;
    294	struct ibft_nic *nic = entry->nic;
    295	void *ibft_loc = entry->header;
    296	char *str = buf;
    297	__be32 val;
    298
    299	if (!nic)
    300		return 0;
    301
    302	switch (type) {
    303	case ISCSI_BOOT_ETH_INDEX:
    304		str += sprintf(str, "%d\n", nic->hdr.index);
    305		break;
    306	case ISCSI_BOOT_ETH_FLAGS:
    307		str += sprintf(str, "%d\n", nic->hdr.flags);
    308		break;
    309	case ISCSI_BOOT_ETH_IP_ADDR:
    310		str += sprintf_ipaddr(str, nic->ip_addr);
    311		break;
    312	case ISCSI_BOOT_ETH_SUBNET_MASK:
    313		val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
    314		str += sprintf(str, "%pI4", &val);
    315		break;
    316	case ISCSI_BOOT_ETH_PREFIX_LEN:
    317		str += sprintf(str, "%d\n", nic->subnet_mask_prefix);
    318		break;
    319	case ISCSI_BOOT_ETH_ORIGIN:
    320		str += sprintf(str, "%d\n", nic->origin);
    321		break;
    322	case ISCSI_BOOT_ETH_GATEWAY:
    323		str += sprintf_ipaddr(str, nic->gateway);
    324		break;
    325	case ISCSI_BOOT_ETH_PRIMARY_DNS:
    326		str += sprintf_ipaddr(str, nic->primary_dns);
    327		break;
    328	case ISCSI_BOOT_ETH_SECONDARY_DNS:
    329		str += sprintf_ipaddr(str, nic->secondary_dns);
    330		break;
    331	case ISCSI_BOOT_ETH_DHCP:
    332		str += sprintf_ipaddr(str, nic->dhcp);
    333		break;
    334	case ISCSI_BOOT_ETH_VLAN:
    335		str += sprintf(str, "%d\n", nic->vlan);
    336		break;
    337	case ISCSI_BOOT_ETH_MAC:
    338		str += sprintf(str, "%pM\n", nic->mac);
    339		break;
    340	case ISCSI_BOOT_ETH_HOSTNAME:
    341		str += sprintf_string(str, nic->hostname_len,
    342				      (char *)ibft_loc + nic->hostname_off);
    343		break;
    344	default:
    345		break;
    346	}
    347
    348	return str - buf;
    349};
    350
    351static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
    352{
    353	struct ibft_kobject *entry = data;
    354	struct ibft_tgt *tgt = entry->tgt;
    355	void *ibft_loc = entry->header;
    356	char *str = buf;
    357	int i;
    358
    359	if (!tgt)
    360		return 0;
    361
    362	switch (type) {
    363	case ISCSI_BOOT_TGT_INDEX:
    364		str += sprintf(str, "%d\n", tgt->hdr.index);
    365		break;
    366	case ISCSI_BOOT_TGT_FLAGS:
    367		str += sprintf(str, "%d\n", tgt->hdr.flags);
    368		break;
    369	case ISCSI_BOOT_TGT_IP_ADDR:
    370		str += sprintf_ipaddr(str, tgt->ip_addr);
    371		break;
    372	case ISCSI_BOOT_TGT_PORT:
    373		str += sprintf(str, "%d\n", tgt->port);
    374		break;
    375	case ISCSI_BOOT_TGT_LUN:
    376		for (i = 0; i < 8; i++)
    377			str += sprintf(str, "%x", (u8)tgt->lun[i]);
    378		str += sprintf(str, "\n");
    379		break;
    380	case ISCSI_BOOT_TGT_NIC_ASSOC:
    381		str += sprintf(str, "%d\n", tgt->nic_assoc);
    382		break;
    383	case ISCSI_BOOT_TGT_CHAP_TYPE:
    384		str += sprintf(str, "%d\n", tgt->chap_type);
    385		break;
    386	case ISCSI_BOOT_TGT_NAME:
    387		str += sprintf_string(str, tgt->tgt_name_len,
    388				      (char *)ibft_loc + tgt->tgt_name_off);
    389		break;
    390	case ISCSI_BOOT_TGT_CHAP_NAME:
    391		str += sprintf_string(str, tgt->chap_name_len,
    392				      (char *)ibft_loc + tgt->chap_name_off);
    393		break;
    394	case ISCSI_BOOT_TGT_CHAP_SECRET:
    395		str += sprintf_string(str, tgt->chap_secret_len,
    396				      (char *)ibft_loc + tgt->chap_secret_off);
    397		break;
    398	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
    399		str += sprintf_string(str, tgt->rev_chap_name_len,
    400				      (char *)ibft_loc +
    401				      tgt->rev_chap_name_off);
    402		break;
    403	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
    404		str += sprintf_string(str, tgt->rev_chap_secret_len,
    405				      (char *)ibft_loc +
    406				      tgt->rev_chap_secret_off);
    407		break;
    408	default:
    409		break;
    410	}
    411
    412	return str - buf;
    413}
    414
    415static ssize_t ibft_attr_show_acpitbl(void *data, int type, char *buf)
    416{
    417	struct ibft_kobject *entry = data;
    418	char *str = buf;
    419
    420	switch (type) {
    421	case ISCSI_BOOT_ACPITBL_SIGNATURE:
    422		str += sprintf_string(str, ACPI_NAMESEG_SIZE,
    423				      entry->header->header.signature);
    424		break;
    425	case ISCSI_BOOT_ACPITBL_OEM_ID:
    426		str += sprintf_string(str, ACPI_OEM_ID_SIZE,
    427				      entry->header->header.oem_id);
    428		break;
    429	case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
    430		str += sprintf_string(str, ACPI_OEM_TABLE_ID_SIZE,
    431				      entry->header->header.oem_table_id);
    432		break;
    433	default:
    434		break;
    435	}
    436
    437	return str - buf;
    438}
    439
    440static int __init ibft_check_device(void)
    441{
    442	int len;
    443	u8 *pos;
    444	u8 csum = 0;
    445
    446	len = ibft_addr->header.length;
    447
    448	/* Sanity checking of iBFT. */
    449	if (ibft_addr->header.revision != 1) {
    450		printk(KERN_ERR "iBFT module supports only revision 1, " \
    451				"while this is %d.\n",
    452				ibft_addr->header.revision);
    453		return -ENOENT;
    454	}
    455	for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
    456		csum += *pos;
    457
    458	if (csum) {
    459		printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum);
    460		return -ENOENT;
    461	}
    462
    463	return 0;
    464}
    465
    466/*
    467 * Helper routiners to check to determine if the entry is valid
    468 * in the proper iBFT structure.
    469 */
    470static umode_t ibft_check_nic_for(void *data, int type)
    471{
    472	struct ibft_kobject *entry = data;
    473	struct ibft_nic *nic = entry->nic;
    474	umode_t rc = 0;
    475
    476	switch (type) {
    477	case ISCSI_BOOT_ETH_INDEX:
    478	case ISCSI_BOOT_ETH_FLAGS:
    479		rc = S_IRUGO;
    480		break;
    481	case ISCSI_BOOT_ETH_IP_ADDR:
    482		if (address_not_null(nic->ip_addr))
    483			rc = S_IRUGO;
    484		break;
    485	case ISCSI_BOOT_ETH_PREFIX_LEN:
    486	case ISCSI_BOOT_ETH_SUBNET_MASK:
    487		if (nic->subnet_mask_prefix)
    488			rc = S_IRUGO;
    489		break;
    490	case ISCSI_BOOT_ETH_ORIGIN:
    491		rc = S_IRUGO;
    492		break;
    493	case ISCSI_BOOT_ETH_GATEWAY:
    494		if (address_not_null(nic->gateway))
    495			rc = S_IRUGO;
    496		break;
    497	case ISCSI_BOOT_ETH_PRIMARY_DNS:
    498		if (address_not_null(nic->primary_dns))
    499			rc = S_IRUGO;
    500		break;
    501	case ISCSI_BOOT_ETH_SECONDARY_DNS:
    502		if (address_not_null(nic->secondary_dns))
    503			rc = S_IRUGO;
    504		break;
    505	case ISCSI_BOOT_ETH_DHCP:
    506		if (address_not_null(nic->dhcp))
    507			rc = S_IRUGO;
    508		break;
    509	case ISCSI_BOOT_ETH_VLAN:
    510	case ISCSI_BOOT_ETH_MAC:
    511		rc = S_IRUGO;
    512		break;
    513	case ISCSI_BOOT_ETH_HOSTNAME:
    514		if (nic->hostname_off)
    515			rc = S_IRUGO;
    516		break;
    517	default:
    518		break;
    519	}
    520
    521	return rc;
    522}
    523
    524static umode_t __init ibft_check_tgt_for(void *data, int type)
    525{
    526	struct ibft_kobject *entry = data;
    527	struct ibft_tgt *tgt = entry->tgt;
    528	umode_t rc = 0;
    529
    530	switch (type) {
    531	case ISCSI_BOOT_TGT_INDEX:
    532	case ISCSI_BOOT_TGT_FLAGS:
    533	case ISCSI_BOOT_TGT_IP_ADDR:
    534	case ISCSI_BOOT_TGT_PORT:
    535	case ISCSI_BOOT_TGT_LUN:
    536	case ISCSI_BOOT_TGT_NIC_ASSOC:
    537	case ISCSI_BOOT_TGT_CHAP_TYPE:
    538		rc = S_IRUGO;
    539		break;
    540	case ISCSI_BOOT_TGT_NAME:
    541		if (tgt->tgt_name_len)
    542			rc = S_IRUGO;
    543		break;
    544	case ISCSI_BOOT_TGT_CHAP_NAME:
    545	case ISCSI_BOOT_TGT_CHAP_SECRET:
    546		if (tgt->chap_name_len)
    547			rc = S_IRUGO;
    548		break;
    549	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
    550	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
    551		if (tgt->rev_chap_name_len)
    552			rc = S_IRUGO;
    553		break;
    554	default:
    555		break;
    556	}
    557
    558	return rc;
    559}
    560
    561static umode_t __init ibft_check_initiator_for(void *data, int type)
    562{
    563	struct ibft_kobject *entry = data;
    564	struct ibft_initiator *init = entry->initiator;
    565	umode_t rc = 0;
    566
    567	switch (type) {
    568	case ISCSI_BOOT_INI_INDEX:
    569	case ISCSI_BOOT_INI_FLAGS:
    570		rc = S_IRUGO;
    571		break;
    572	case ISCSI_BOOT_INI_ISNS_SERVER:
    573		if (address_not_null(init->isns_server))
    574			rc = S_IRUGO;
    575		break;
    576	case ISCSI_BOOT_INI_SLP_SERVER:
    577		if (address_not_null(init->slp_server))
    578			rc = S_IRUGO;
    579		break;
    580	case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
    581		if (address_not_null(init->pri_radius_server))
    582			rc = S_IRUGO;
    583		break;
    584	case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
    585		if (address_not_null(init->sec_radius_server))
    586			rc = S_IRUGO;
    587		break;
    588	case ISCSI_BOOT_INI_INITIATOR_NAME:
    589		if (init->initiator_name_len)
    590			rc = S_IRUGO;
    591		break;
    592	default:
    593		break;
    594	}
    595
    596	return rc;
    597}
    598
    599static umode_t __init ibft_check_acpitbl_for(void *data, int type)
    600{
    601
    602	umode_t rc = 0;
    603
    604	switch (type) {
    605	case ISCSI_BOOT_ACPITBL_SIGNATURE:
    606	case ISCSI_BOOT_ACPITBL_OEM_ID:
    607	case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
    608		rc = S_IRUGO;
    609		break;
    610	default:
    611		break;
    612	}
    613
    614	return rc;
    615}
    616
    617static void ibft_kobj_release(void *data)
    618{
    619	kfree(data);
    620}
    621
    622/*
    623 * Helper function for ibft_register_kobjects.
    624 */
    625static int __init ibft_create_kobject(struct acpi_table_ibft *header,
    626				      struct ibft_hdr *hdr)
    627{
    628	struct iscsi_boot_kobj *boot_kobj = NULL;
    629	struct ibft_kobject *ibft_kobj = NULL;
    630	struct ibft_nic *nic = (struct ibft_nic *)hdr;
    631	struct pci_dev *pci_dev;
    632	int rc = 0;
    633
    634	ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
    635	if (!ibft_kobj)
    636		return -ENOMEM;
    637
    638	ibft_kobj->header = header;
    639	ibft_kobj->hdr = hdr;
    640
    641	switch (hdr->id) {
    642	case id_initiator:
    643		rc = ibft_verify_hdr("initiator", hdr, id_initiator,
    644				     sizeof(*ibft_kobj->initiator));
    645		if (rc)
    646			break;
    647
    648		boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
    649						ibft_kobj,
    650						ibft_attr_show_initiator,
    651						ibft_check_initiator_for,
    652						ibft_kobj_release);
    653		if (!boot_kobj) {
    654			rc = -ENOMEM;
    655			goto free_ibft_obj;
    656		}
    657		break;
    658	case id_nic:
    659		rc = ibft_verify_hdr("ethernet", hdr, id_nic,
    660				     sizeof(*ibft_kobj->nic));
    661		if (rc)
    662			break;
    663
    664		boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
    665						       ibft_kobj,
    666						       ibft_attr_show_nic,
    667						       ibft_check_nic_for,
    668						       ibft_kobj_release);
    669		if (!boot_kobj) {
    670			rc = -ENOMEM;
    671			goto free_ibft_obj;
    672		}
    673		break;
    674	case id_target:
    675		rc = ibft_verify_hdr("target", hdr, id_target,
    676				     sizeof(*ibft_kobj->tgt));
    677		if (rc)
    678			break;
    679
    680		boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
    681						     ibft_kobj,
    682						     ibft_attr_show_target,
    683						     ibft_check_tgt_for,
    684						     ibft_kobj_release);
    685		if (!boot_kobj) {
    686			rc = -ENOMEM;
    687			goto free_ibft_obj;
    688		}
    689		break;
    690	case id_reserved:
    691	case id_control:
    692	case id_extensions:
    693		/* Fields which we don't support. Ignore them */
    694		rc = 1;
    695		break;
    696	default:
    697		printk(KERN_ERR "iBFT has unknown structure type (%d). " \
    698				"Report this bug to %.6s!\n", hdr->id,
    699				header->header.oem_id);
    700		rc = 1;
    701		break;
    702	}
    703
    704	if (rc) {
    705		/* Skip adding this kobject, but exit with non-fatal error. */
    706		rc = 0;
    707		goto free_ibft_obj;
    708	}
    709
    710	if (hdr->id == id_nic) {
    711		/*
    712		* We don't search for the device in other domains than
    713		* zero. This is because on x86 platforms the BIOS
    714		* executes only devices which are in domain 0. Furthermore, the
    715		* iBFT spec doesn't have a domain id field :-(
    716		*/
    717		pci_dev = pci_get_domain_bus_and_slot(0,
    718						(nic->pci_bdf & 0xff00) >> 8,
    719						(nic->pci_bdf & 0xff));
    720		if (pci_dev) {
    721			rc = sysfs_create_link(&boot_kobj->kobj,
    722					       &pci_dev->dev.kobj, "device");
    723			pci_dev_put(pci_dev);
    724		}
    725	}
    726	return 0;
    727
    728free_ibft_obj:
    729	kfree(ibft_kobj);
    730	return rc;
    731}
    732
    733/*
    734 * Scan the IBFT table structure for the NIC and Target fields. When
    735 * found add them on the passed-in list. We do not support the other
    736 * fields at this point, so they are skipped.
    737 */
    738static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
    739{
    740	struct ibft_control *control = NULL;
    741	struct iscsi_boot_kobj *boot_kobj;
    742	struct ibft_kobject *ibft_kobj;
    743	void *ptr, *end;
    744	int rc = 0;
    745	u16 offset;
    746	u16 eot_offset;
    747
    748	control = (void *)header + sizeof(*header);
    749	end = (void *)control + control->hdr.length;
    750	eot_offset = (void *)header + header->header.length - (void *)control;
    751	rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, 0);
    752
    753	/* iBFT table safety checking */
    754	rc |= ((control->hdr.index) ? -ENODEV : 0);
    755	rc |= ((control->hdr.length < sizeof(*control)) ? -ENODEV : 0);
    756	if (rc) {
    757		printk(KERN_ERR "iBFT error: Control header is invalid!\n");
    758		return rc;
    759	}
    760	for (ptr = &control->initiator_off; ptr + sizeof(u16) <= end; ptr += sizeof(u16)) {
    761		offset = *(u16 *)ptr;
    762		if (offset && offset < header->header.length &&
    763						offset < eot_offset) {
    764			rc = ibft_create_kobject(header,
    765						 (void *)header + offset);
    766			if (rc)
    767				break;
    768		}
    769	}
    770	if (rc)
    771		return rc;
    772
    773	ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
    774	if (!ibft_kobj)
    775		return -ENOMEM;
    776
    777	ibft_kobj->header = header;
    778	ibft_kobj->hdr = NULL; /*for ibft_unregister*/
    779
    780	boot_kobj = iscsi_boot_create_acpitbl(boot_kset, 0,
    781					ibft_kobj,
    782					ibft_attr_show_acpitbl,
    783					ibft_check_acpitbl_for,
    784					ibft_kobj_release);
    785	if (!boot_kobj)  {
    786		kfree(ibft_kobj);
    787		rc = -ENOMEM;
    788	}
    789
    790	return rc;
    791}
    792
    793static void ibft_unregister(void)
    794{
    795	struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
    796	struct ibft_kobject *ibft_kobj;
    797
    798	list_for_each_entry_safe(boot_kobj, tmp_kobj,
    799				 &boot_kset->kobj_list, list) {
    800		ibft_kobj = boot_kobj->data;
    801		if (ibft_kobj->hdr && ibft_kobj->hdr->id == id_nic)
    802			sysfs_remove_link(&boot_kobj->kobj, "device");
    803	};
    804}
    805
    806static void ibft_cleanup(void)
    807{
    808	if (boot_kset) {
    809		ibft_unregister();
    810		iscsi_boot_destroy_kset(boot_kset);
    811	}
    812}
    813
    814static void __exit ibft_exit(void)
    815{
    816	ibft_cleanup();
    817}
    818
    819#ifdef CONFIG_ACPI
    820static const struct {
    821	char *sign;
    822} ibft_signs[] = {
    823	/*
    824	 * One spec says "IBFT", the other says "iBFT". We have to check
    825	 * for both.
    826	 */
    827	{ ACPI_SIG_IBFT },
    828	{ "iBFT" },
    829	{ "BIFT" },	/* Broadcom iSCSI Offload */
    830};
    831
    832static void __init acpi_find_ibft_region(void)
    833{
    834	int i;
    835	struct acpi_table_header *table = NULL;
    836
    837	if (acpi_disabled)
    838		return;
    839
    840	for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
    841		acpi_get_table(ibft_signs[i].sign, 0, &table);
    842		ibft_addr = (struct acpi_table_ibft *)table;
    843	}
    844}
    845#else
    846static void __init acpi_find_ibft_region(void)
    847{
    848}
    849#endif
    850#ifdef CONFIG_ISCSI_IBFT_FIND
    851static int __init acpi_find_isa_region(void)
    852{
    853	if (ibft_phys_addr) {
    854		ibft_addr = isa_bus_to_virt(ibft_phys_addr);
    855		return 0;
    856	}
    857	return -ENODEV;
    858}
    859#else
    860static int __init acpi_find_isa_region(void)
    861{
    862	return -ENODEV;
    863}
    864#endif
    865/*
    866 * ibft_init() - creates sysfs tree entries for the iBFT data.
    867 */
    868static int __init ibft_init(void)
    869{
    870	int rc = 0;
    871
    872	/*
    873	   As on UEFI systems the setup_arch()/reserve_ibft_region()
    874	   is called before ACPI tables are parsed and it only does
    875	   legacy finding.
    876	*/
    877	if (acpi_find_isa_region())
    878		acpi_find_ibft_region();
    879
    880	if (ibft_addr) {
    881		pr_info("iBFT detected.\n");
    882
    883		rc = ibft_check_device();
    884		if (rc)
    885			return rc;
    886
    887		boot_kset = iscsi_boot_create_kset("ibft");
    888		if (!boot_kset)
    889			return -ENOMEM;
    890
    891		/* Scan the IBFT for data and register the kobjects. */
    892		rc = ibft_register_kobjects(ibft_addr);
    893		if (rc)
    894			goto out_free;
    895	} else
    896		printk(KERN_INFO "No iBFT detected.\n");
    897
    898	return 0;
    899
    900out_free:
    901	ibft_cleanup();
    902	return rc;
    903}
    904
    905module_init(ibft_init);
    906module_exit(ibft_exit);