Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright 2007-2010 Red Hat, Inc.
0004  *  by Peter Jones <pjones@redhat.com>
0005  *  Copyright 2008 IBM, Inc.
0006  *  by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0007  *  Copyright 2008
0008  *  by Konrad Rzeszutek <ketuzsezr@darnok.org>
0009  *
0010  * This code exposes the iSCSI Boot Format Table to userland via sysfs.
0011  *
0012  * Changelog:
0013  *
0014  *  06 Jan 2010 - Peter Jones <pjones@redhat.com>
0015  *    New changelog entries are in the git log from now on.  Not here.
0016  *
0017  *  14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org>
0018  *    Updated comments and copyrights. (v0.4.9)
0019  *
0020  *  11 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0021  *    Converted to using ibft_addr. (v0.4.8)
0022  *
0023  *   8 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0024  *    Combined two functions in one: reserve_ibft_region. (v0.4.7)
0025  *
0026  *  30 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0027  *   Added logic to handle IPv6 addresses. (v0.4.6)
0028  *
0029  *  25 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0030  *   Added logic to handle badly not-to-spec iBFT. (v0.4.5)
0031  *
0032  *   4 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0033  *   Added __init to function declarations. (v0.4.4)
0034  *
0035  *  21 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0036  *   Updated kobject registration, combined unregister functions in one
0037  *   and code and style cleanup. (v0.4.3)
0038  *
0039  *   5 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0040  *   Added end-markers to enums and re-organized kobject registration. (v0.4.2)
0041  *
0042  *   4 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0043  *   Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1)
0044  *
0045  *  28 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0046  *   Added sysfs-ibft documentation, moved 'find_ibft' function to
0047  *   in its own file and added text attributes for every struct field.  (v0.4)
0048  *
0049  *  21 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0050  *   Added text attributes emulating OpenFirmware /proc/device-tree naming.
0051  *   Removed binary /sysfs interface (v0.3)
0052  *
0053  *  29 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0054  *   Added functionality in setup.c to reserve iBFT region. (v0.2)
0055  *
0056  *  27 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
0057  *   First version exposing iBFT data via a binary /sysfs. (v0.1)
0058  */
0059 
0060 
0061 #include <linux/blkdev.h>
0062 #include <linux/capability.h>
0063 #include <linux/ctype.h>
0064 #include <linux/device.h>
0065 #include <linux/err.h>
0066 #include <linux/init.h>
0067 #include <linux/iscsi_ibft.h>
0068 #include <linux/limits.h>
0069 #include <linux/module.h>
0070 #include <linux/pci.h>
0071 #include <linux/slab.h>
0072 #include <linux/stat.h>
0073 #include <linux/string.h>
0074 #include <linux/types.h>
0075 #include <linux/acpi.h>
0076 #include <linux/iscsi_boot_sysfs.h>
0077 
0078 #define IBFT_ISCSI_VERSION "0.5.0"
0079 #define IBFT_ISCSI_DATE "2010-Feb-25"
0080 
0081 MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and "
0082           "Konrad Rzeszutek <ketuzsezr@darnok.org>");
0083 MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information");
0084 MODULE_LICENSE("GPL");
0085 MODULE_VERSION(IBFT_ISCSI_VERSION);
0086 
0087 static struct acpi_table_ibft *ibft_addr;
0088 
0089 struct ibft_hdr {
0090     u8 id;
0091     u8 version;
0092     u16 length;
0093     u8 index;
0094     u8 flags;
0095 } __attribute__((__packed__));
0096 
0097 struct ibft_control {
0098     struct ibft_hdr hdr;
0099     u16 extensions;
0100     u16 initiator_off;
0101     u16 nic0_off;
0102     u16 tgt0_off;
0103     u16 nic1_off;
0104     u16 tgt1_off;
0105     u16 expansion[];
0106 } __attribute__((__packed__));
0107 
0108 struct ibft_initiator {
0109     struct ibft_hdr hdr;
0110     char isns_server[16];
0111     char slp_server[16];
0112     char pri_radius_server[16];
0113     char sec_radius_server[16];
0114     u16 initiator_name_len;
0115     u16 initiator_name_off;
0116 } __attribute__((__packed__));
0117 
0118 struct ibft_nic {
0119     struct ibft_hdr hdr;
0120     char ip_addr[16];
0121     u8 subnet_mask_prefix;
0122     u8 origin;
0123     char gateway[16];
0124     char primary_dns[16];
0125     char secondary_dns[16];
0126     char dhcp[16];
0127     u16 vlan;
0128     char mac[6];
0129     u16 pci_bdf;
0130     u16 hostname_len;
0131     u16 hostname_off;
0132 } __attribute__((__packed__));
0133 
0134 struct ibft_tgt {
0135     struct ibft_hdr hdr;
0136     char ip_addr[16];
0137     u16 port;
0138     char lun[8];
0139     u8 chap_type;
0140     u8 nic_assoc;
0141     u16 tgt_name_len;
0142     u16 tgt_name_off;
0143     u16 chap_name_len;
0144     u16 chap_name_off;
0145     u16 chap_secret_len;
0146     u16 chap_secret_off;
0147     u16 rev_chap_name_len;
0148     u16 rev_chap_name_off;
0149     u16 rev_chap_secret_len;
0150     u16 rev_chap_secret_off;
0151 } __attribute__((__packed__));
0152 
0153 /*
0154  * The kobject different types and its names.
0155  *
0156 */
0157 enum ibft_id {
0158     id_reserved = 0, /* We don't support. */
0159     id_control = 1, /* Should show up only once and is not exported. */
0160     id_initiator = 2,
0161     id_nic = 3,
0162     id_target = 4,
0163     id_extensions = 5, /* We don't support. */
0164     id_end_marker,
0165 };
0166 
0167 /*
0168  * The kobject and attribute structures.
0169  */
0170 
0171 struct ibft_kobject {
0172     struct acpi_table_ibft *header;
0173     union {
0174         struct ibft_initiator *initiator;
0175         struct ibft_nic *nic;
0176         struct ibft_tgt *tgt;
0177         struct ibft_hdr *hdr;
0178     };
0179 };
0180 
0181 static struct iscsi_boot_kset *boot_kset;
0182 
0183 /* fully null address */
0184 static const char nulls[16];
0185 
0186 /* IPv4-mapped IPv6 ::ffff:0.0.0.0 */
0187 static const char mapped_nulls[16] = { 0x00, 0x00, 0x00, 0x00,
0188                                        0x00, 0x00, 0x00, 0x00,
0189                                        0x00, 0x00, 0xff, 0xff,
0190                                        0x00, 0x00, 0x00, 0x00 };
0191 
0192 static int address_not_null(u8 *ip)
0193 {
0194     return (memcmp(ip, nulls, 16) && memcmp(ip, mapped_nulls, 16));
0195 }
0196 
0197 /*
0198  * Helper functions to parse data properly.
0199  */
0200 static ssize_t sprintf_ipaddr(char *buf, u8 *ip)
0201 {
0202     char *str = buf;
0203 
0204     if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 &&
0205         ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 &&
0206         ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff) {
0207         /*
0208          * IPV4
0209          */
0210         str += sprintf(buf, "%pI4", ip + 12);
0211     } else {
0212         /*
0213          * IPv6
0214          */
0215         str += sprintf(str, "%pI6", ip);
0216     }
0217     str += sprintf(str, "\n");
0218     return str - buf;
0219 }
0220 
0221 static ssize_t sprintf_string(char *str, int len, char *buf)
0222 {
0223     return sprintf(str, "%.*s\n", len, buf);
0224 }
0225 
0226 /*
0227  * Helper function to verify the IBFT header.
0228  */
0229 static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
0230 {
0231     if (hdr->id != id) {
0232         printk(KERN_ERR "iBFT error: We expected the %s " \
0233                 "field header.id to have %d but " \
0234                 "found %d instead!\n", t, id, hdr->id);
0235         return -ENODEV;
0236     }
0237     if (length && hdr->length != length) {
0238         printk(KERN_ERR "iBFT error: We expected the %s " \
0239                 "field header.length to have %d but " \
0240                 "found %d instead!\n", t, length, hdr->length);
0241         return -ENODEV;
0242     }
0243 
0244     return 0;
0245 }
0246 
0247 /*
0248  *  Routines for parsing the iBFT data to be human readable.
0249  */
0250 static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
0251 {
0252     struct ibft_kobject *entry = data;
0253     struct ibft_initiator *initiator = entry->initiator;
0254     void *ibft_loc = entry->header;
0255     char *str = buf;
0256 
0257     if (!initiator)
0258         return 0;
0259 
0260     switch (type) {
0261     case ISCSI_BOOT_INI_INDEX:
0262         str += sprintf(str, "%d\n", initiator->hdr.index);
0263         break;
0264     case ISCSI_BOOT_INI_FLAGS:
0265         str += sprintf(str, "%d\n", initiator->hdr.flags);
0266         break;
0267     case ISCSI_BOOT_INI_ISNS_SERVER:
0268         str += sprintf_ipaddr(str, initiator->isns_server);
0269         break;
0270     case ISCSI_BOOT_INI_SLP_SERVER:
0271         str += sprintf_ipaddr(str, initiator->slp_server);
0272         break;
0273     case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
0274         str += sprintf_ipaddr(str, initiator->pri_radius_server);
0275         break;
0276     case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
0277         str += sprintf_ipaddr(str, initiator->sec_radius_server);
0278         break;
0279     case ISCSI_BOOT_INI_INITIATOR_NAME:
0280         str += sprintf_string(str, initiator->initiator_name_len,
0281                       (char *)ibft_loc +
0282                       initiator->initiator_name_off);
0283         break;
0284     default:
0285         break;
0286     }
0287 
0288     return str - buf;
0289 }
0290 
0291 static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
0292 {
0293     struct ibft_kobject *entry = data;
0294     struct ibft_nic *nic = entry->nic;
0295     void *ibft_loc = entry->header;
0296     char *str = buf;
0297     __be32 val;
0298 
0299     if (!nic)
0300         return 0;
0301 
0302     switch (type) {
0303     case ISCSI_BOOT_ETH_INDEX:
0304         str += sprintf(str, "%d\n", nic->hdr.index);
0305         break;
0306     case ISCSI_BOOT_ETH_FLAGS:
0307         str += sprintf(str, "%d\n", nic->hdr.flags);
0308         break;
0309     case ISCSI_BOOT_ETH_IP_ADDR:
0310         str += sprintf_ipaddr(str, nic->ip_addr);
0311         break;
0312     case ISCSI_BOOT_ETH_SUBNET_MASK:
0313         val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
0314         str += sprintf(str, "%pI4", &val);
0315         break;
0316     case ISCSI_BOOT_ETH_PREFIX_LEN:
0317         str += sprintf(str, "%d\n", nic->subnet_mask_prefix);
0318         break;
0319     case ISCSI_BOOT_ETH_ORIGIN:
0320         str += sprintf(str, "%d\n", nic->origin);
0321         break;
0322     case ISCSI_BOOT_ETH_GATEWAY:
0323         str += sprintf_ipaddr(str, nic->gateway);
0324         break;
0325     case ISCSI_BOOT_ETH_PRIMARY_DNS:
0326         str += sprintf_ipaddr(str, nic->primary_dns);
0327         break;
0328     case ISCSI_BOOT_ETH_SECONDARY_DNS:
0329         str += sprintf_ipaddr(str, nic->secondary_dns);
0330         break;
0331     case ISCSI_BOOT_ETH_DHCP:
0332         str += sprintf_ipaddr(str, nic->dhcp);
0333         break;
0334     case ISCSI_BOOT_ETH_VLAN:
0335         str += sprintf(str, "%d\n", nic->vlan);
0336         break;
0337     case ISCSI_BOOT_ETH_MAC:
0338         str += sprintf(str, "%pM\n", nic->mac);
0339         break;
0340     case ISCSI_BOOT_ETH_HOSTNAME:
0341         str += sprintf_string(str, nic->hostname_len,
0342                       (char *)ibft_loc + nic->hostname_off);
0343         break;
0344     default:
0345         break;
0346     }
0347 
0348     return str - buf;
0349 };
0350 
0351 static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
0352 {
0353     struct ibft_kobject *entry = data;
0354     struct ibft_tgt *tgt = entry->tgt;
0355     void *ibft_loc = entry->header;
0356     char *str = buf;
0357     int i;
0358 
0359     if (!tgt)
0360         return 0;
0361 
0362     switch (type) {
0363     case ISCSI_BOOT_TGT_INDEX:
0364         str += sprintf(str, "%d\n", tgt->hdr.index);
0365         break;
0366     case ISCSI_BOOT_TGT_FLAGS:
0367         str += sprintf(str, "%d\n", tgt->hdr.flags);
0368         break;
0369     case ISCSI_BOOT_TGT_IP_ADDR:
0370         str += sprintf_ipaddr(str, tgt->ip_addr);
0371         break;
0372     case ISCSI_BOOT_TGT_PORT:
0373         str += sprintf(str, "%d\n", tgt->port);
0374         break;
0375     case ISCSI_BOOT_TGT_LUN:
0376         for (i = 0; i < 8; i++)
0377             str += sprintf(str, "%x", (u8)tgt->lun[i]);
0378         str += sprintf(str, "\n");
0379         break;
0380     case ISCSI_BOOT_TGT_NIC_ASSOC:
0381         str += sprintf(str, "%d\n", tgt->nic_assoc);
0382         break;
0383     case ISCSI_BOOT_TGT_CHAP_TYPE:
0384         str += sprintf(str, "%d\n", tgt->chap_type);
0385         break;
0386     case ISCSI_BOOT_TGT_NAME:
0387         str += sprintf_string(str, tgt->tgt_name_len,
0388                       (char *)ibft_loc + tgt->tgt_name_off);
0389         break;
0390     case ISCSI_BOOT_TGT_CHAP_NAME:
0391         str += sprintf_string(str, tgt->chap_name_len,
0392                       (char *)ibft_loc + tgt->chap_name_off);
0393         break;
0394     case ISCSI_BOOT_TGT_CHAP_SECRET:
0395         str += sprintf_string(str, tgt->chap_secret_len,
0396                       (char *)ibft_loc + tgt->chap_secret_off);
0397         break;
0398     case ISCSI_BOOT_TGT_REV_CHAP_NAME:
0399         str += sprintf_string(str, tgt->rev_chap_name_len,
0400                       (char *)ibft_loc +
0401                       tgt->rev_chap_name_off);
0402         break;
0403     case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
0404         str += sprintf_string(str, tgt->rev_chap_secret_len,
0405                       (char *)ibft_loc +
0406                       tgt->rev_chap_secret_off);
0407         break;
0408     default:
0409         break;
0410     }
0411 
0412     return str - buf;
0413 }
0414 
0415 static ssize_t ibft_attr_show_acpitbl(void *data, int type, char *buf)
0416 {
0417     struct ibft_kobject *entry = data;
0418     char *str = buf;
0419 
0420     switch (type) {
0421     case ISCSI_BOOT_ACPITBL_SIGNATURE:
0422         str += sprintf_string(str, ACPI_NAMESEG_SIZE,
0423                       entry->header->header.signature);
0424         break;
0425     case ISCSI_BOOT_ACPITBL_OEM_ID:
0426         str += sprintf_string(str, ACPI_OEM_ID_SIZE,
0427                       entry->header->header.oem_id);
0428         break;
0429     case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
0430         str += sprintf_string(str, ACPI_OEM_TABLE_ID_SIZE,
0431                       entry->header->header.oem_table_id);
0432         break;
0433     default:
0434         break;
0435     }
0436 
0437     return str - buf;
0438 }
0439 
0440 static int __init ibft_check_device(void)
0441 {
0442     int len;
0443     u8 *pos;
0444     u8 csum = 0;
0445 
0446     len = ibft_addr->header.length;
0447 
0448     /* Sanity checking of iBFT. */
0449     if (ibft_addr->header.revision != 1) {
0450         printk(KERN_ERR "iBFT module supports only revision 1, " \
0451                 "while this is %d.\n",
0452                 ibft_addr->header.revision);
0453         return -ENOENT;
0454     }
0455     for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
0456         csum += *pos;
0457 
0458     if (csum) {
0459         printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum);
0460         return -ENOENT;
0461     }
0462 
0463     return 0;
0464 }
0465 
0466 /*
0467  * Helper routiners to check to determine if the entry is valid
0468  * in the proper iBFT structure.
0469  */
0470 static umode_t ibft_check_nic_for(void *data, int type)
0471 {
0472     struct ibft_kobject *entry = data;
0473     struct ibft_nic *nic = entry->nic;
0474     umode_t rc = 0;
0475 
0476     switch (type) {
0477     case ISCSI_BOOT_ETH_INDEX:
0478     case ISCSI_BOOT_ETH_FLAGS:
0479         rc = S_IRUGO;
0480         break;
0481     case ISCSI_BOOT_ETH_IP_ADDR:
0482         if (address_not_null(nic->ip_addr))
0483             rc = S_IRUGO;
0484         break;
0485     case ISCSI_BOOT_ETH_PREFIX_LEN:
0486     case ISCSI_BOOT_ETH_SUBNET_MASK:
0487         if (nic->subnet_mask_prefix)
0488             rc = S_IRUGO;
0489         break;
0490     case ISCSI_BOOT_ETH_ORIGIN:
0491         rc = S_IRUGO;
0492         break;
0493     case ISCSI_BOOT_ETH_GATEWAY:
0494         if (address_not_null(nic->gateway))
0495             rc = S_IRUGO;
0496         break;
0497     case ISCSI_BOOT_ETH_PRIMARY_DNS:
0498         if (address_not_null(nic->primary_dns))
0499             rc = S_IRUGO;
0500         break;
0501     case ISCSI_BOOT_ETH_SECONDARY_DNS:
0502         if (address_not_null(nic->secondary_dns))
0503             rc = S_IRUGO;
0504         break;
0505     case ISCSI_BOOT_ETH_DHCP:
0506         if (address_not_null(nic->dhcp))
0507             rc = S_IRUGO;
0508         break;
0509     case ISCSI_BOOT_ETH_VLAN:
0510     case ISCSI_BOOT_ETH_MAC:
0511         rc = S_IRUGO;
0512         break;
0513     case ISCSI_BOOT_ETH_HOSTNAME:
0514         if (nic->hostname_off)
0515             rc = S_IRUGO;
0516         break;
0517     default:
0518         break;
0519     }
0520 
0521     return rc;
0522 }
0523 
0524 static umode_t __init ibft_check_tgt_for(void *data, int type)
0525 {
0526     struct ibft_kobject *entry = data;
0527     struct ibft_tgt *tgt = entry->tgt;
0528     umode_t rc = 0;
0529 
0530     switch (type) {
0531     case ISCSI_BOOT_TGT_INDEX:
0532     case ISCSI_BOOT_TGT_FLAGS:
0533     case ISCSI_BOOT_TGT_IP_ADDR:
0534     case ISCSI_BOOT_TGT_PORT:
0535     case ISCSI_BOOT_TGT_LUN:
0536     case ISCSI_BOOT_TGT_NIC_ASSOC:
0537     case ISCSI_BOOT_TGT_CHAP_TYPE:
0538         rc = S_IRUGO;
0539         break;
0540     case ISCSI_BOOT_TGT_NAME:
0541         if (tgt->tgt_name_len)
0542             rc = S_IRUGO;
0543         break;
0544     case ISCSI_BOOT_TGT_CHAP_NAME:
0545     case ISCSI_BOOT_TGT_CHAP_SECRET:
0546         if (tgt->chap_name_len)
0547             rc = S_IRUGO;
0548         break;
0549     case ISCSI_BOOT_TGT_REV_CHAP_NAME:
0550     case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
0551         if (tgt->rev_chap_name_len)
0552             rc = S_IRUGO;
0553         break;
0554     default:
0555         break;
0556     }
0557 
0558     return rc;
0559 }
0560 
0561 static umode_t __init ibft_check_initiator_for(void *data, int type)
0562 {
0563     struct ibft_kobject *entry = data;
0564     struct ibft_initiator *init = entry->initiator;
0565     umode_t rc = 0;
0566 
0567     switch (type) {
0568     case ISCSI_BOOT_INI_INDEX:
0569     case ISCSI_BOOT_INI_FLAGS:
0570         rc = S_IRUGO;
0571         break;
0572     case ISCSI_BOOT_INI_ISNS_SERVER:
0573         if (address_not_null(init->isns_server))
0574             rc = S_IRUGO;
0575         break;
0576     case ISCSI_BOOT_INI_SLP_SERVER:
0577         if (address_not_null(init->slp_server))
0578             rc = S_IRUGO;
0579         break;
0580     case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
0581         if (address_not_null(init->pri_radius_server))
0582             rc = S_IRUGO;
0583         break;
0584     case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
0585         if (address_not_null(init->sec_radius_server))
0586             rc = S_IRUGO;
0587         break;
0588     case ISCSI_BOOT_INI_INITIATOR_NAME:
0589         if (init->initiator_name_len)
0590             rc = S_IRUGO;
0591         break;
0592     default:
0593         break;
0594     }
0595 
0596     return rc;
0597 }
0598 
0599 static umode_t __init ibft_check_acpitbl_for(void *data, int type)
0600 {
0601 
0602     umode_t rc = 0;
0603 
0604     switch (type) {
0605     case ISCSI_BOOT_ACPITBL_SIGNATURE:
0606     case ISCSI_BOOT_ACPITBL_OEM_ID:
0607     case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
0608         rc = S_IRUGO;
0609         break;
0610     default:
0611         break;
0612     }
0613 
0614     return rc;
0615 }
0616 
0617 static void ibft_kobj_release(void *data)
0618 {
0619     kfree(data);
0620 }
0621 
0622 /*
0623  * Helper function for ibft_register_kobjects.
0624  */
0625 static int __init ibft_create_kobject(struct acpi_table_ibft *header,
0626                       struct ibft_hdr *hdr)
0627 {
0628     struct iscsi_boot_kobj *boot_kobj = NULL;
0629     struct ibft_kobject *ibft_kobj = NULL;
0630     struct ibft_nic *nic = (struct ibft_nic *)hdr;
0631     struct pci_dev *pci_dev;
0632     int rc = 0;
0633 
0634     ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
0635     if (!ibft_kobj)
0636         return -ENOMEM;
0637 
0638     ibft_kobj->header = header;
0639     ibft_kobj->hdr = hdr;
0640 
0641     switch (hdr->id) {
0642     case id_initiator:
0643         rc = ibft_verify_hdr("initiator", hdr, id_initiator,
0644                      sizeof(*ibft_kobj->initiator));
0645         if (rc)
0646             break;
0647 
0648         boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
0649                         ibft_kobj,
0650                         ibft_attr_show_initiator,
0651                         ibft_check_initiator_for,
0652                         ibft_kobj_release);
0653         if (!boot_kobj) {
0654             rc = -ENOMEM;
0655             goto free_ibft_obj;
0656         }
0657         break;
0658     case id_nic:
0659         rc = ibft_verify_hdr("ethernet", hdr, id_nic,
0660                      sizeof(*ibft_kobj->nic));
0661         if (rc)
0662             break;
0663 
0664         boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
0665                                ibft_kobj,
0666                                ibft_attr_show_nic,
0667                                ibft_check_nic_for,
0668                                ibft_kobj_release);
0669         if (!boot_kobj) {
0670             rc = -ENOMEM;
0671             goto free_ibft_obj;
0672         }
0673         break;
0674     case id_target:
0675         rc = ibft_verify_hdr("target", hdr, id_target,
0676                      sizeof(*ibft_kobj->tgt));
0677         if (rc)
0678             break;
0679 
0680         boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
0681                              ibft_kobj,
0682                              ibft_attr_show_target,
0683                              ibft_check_tgt_for,
0684                              ibft_kobj_release);
0685         if (!boot_kobj) {
0686             rc = -ENOMEM;
0687             goto free_ibft_obj;
0688         }
0689         break;
0690     case id_reserved:
0691     case id_control:
0692     case id_extensions:
0693         /* Fields which we don't support. Ignore them */
0694         rc = 1;
0695         break;
0696     default:
0697         printk(KERN_ERR "iBFT has unknown structure type (%d). " \
0698                 "Report this bug to %.6s!\n", hdr->id,
0699                 header->header.oem_id);
0700         rc = 1;
0701         break;
0702     }
0703 
0704     if (rc) {
0705         /* Skip adding this kobject, but exit with non-fatal error. */
0706         rc = 0;
0707         goto free_ibft_obj;
0708     }
0709 
0710     if (hdr->id == id_nic) {
0711         /*
0712         * We don't search for the device in other domains than
0713         * zero. This is because on x86 platforms the BIOS
0714         * executes only devices which are in domain 0. Furthermore, the
0715         * iBFT spec doesn't have a domain id field :-(
0716         */
0717         pci_dev = pci_get_domain_bus_and_slot(0,
0718                         (nic->pci_bdf & 0xff00) >> 8,
0719                         (nic->pci_bdf & 0xff));
0720         if (pci_dev) {
0721             rc = sysfs_create_link(&boot_kobj->kobj,
0722                            &pci_dev->dev.kobj, "device");
0723             pci_dev_put(pci_dev);
0724         }
0725     }
0726     return 0;
0727 
0728 free_ibft_obj:
0729     kfree(ibft_kobj);
0730     return rc;
0731 }
0732 
0733 /*
0734  * Scan the IBFT table structure for the NIC and Target fields. When
0735  * found add them on the passed-in list. We do not support the other
0736  * fields at this point, so they are skipped.
0737  */
0738 static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
0739 {
0740     struct ibft_control *control = NULL;
0741     struct iscsi_boot_kobj *boot_kobj;
0742     struct ibft_kobject *ibft_kobj;
0743     void *ptr, *end;
0744     int rc = 0;
0745     u16 offset;
0746     u16 eot_offset;
0747 
0748     control = (void *)header + sizeof(*header);
0749     end = (void *)control + control->hdr.length;
0750     eot_offset = (void *)header + header->header.length - (void *)control;
0751     rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, 0);
0752 
0753     /* iBFT table safety checking */
0754     rc |= ((control->hdr.index) ? -ENODEV : 0);
0755     rc |= ((control->hdr.length < sizeof(*control)) ? -ENODEV : 0);
0756     if (rc) {
0757         printk(KERN_ERR "iBFT error: Control header is invalid!\n");
0758         return rc;
0759     }
0760     for (ptr = &control->initiator_off; ptr + sizeof(u16) <= end; ptr += sizeof(u16)) {
0761         offset = *(u16 *)ptr;
0762         if (offset && offset < header->header.length &&
0763                         offset < eot_offset) {
0764             rc = ibft_create_kobject(header,
0765                          (void *)header + offset);
0766             if (rc)
0767                 break;
0768         }
0769     }
0770     if (rc)
0771         return rc;
0772 
0773     ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
0774     if (!ibft_kobj)
0775         return -ENOMEM;
0776 
0777     ibft_kobj->header = header;
0778     ibft_kobj->hdr = NULL; /*for ibft_unregister*/
0779 
0780     boot_kobj = iscsi_boot_create_acpitbl(boot_kset, 0,
0781                     ibft_kobj,
0782                     ibft_attr_show_acpitbl,
0783                     ibft_check_acpitbl_for,
0784                     ibft_kobj_release);
0785     if (!boot_kobj)  {
0786         kfree(ibft_kobj);
0787         rc = -ENOMEM;
0788     }
0789 
0790     return rc;
0791 }
0792 
0793 static void ibft_unregister(void)
0794 {
0795     struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
0796     struct ibft_kobject *ibft_kobj;
0797 
0798     list_for_each_entry_safe(boot_kobj, tmp_kobj,
0799                  &boot_kset->kobj_list, list) {
0800         ibft_kobj = boot_kobj->data;
0801         if (ibft_kobj->hdr && ibft_kobj->hdr->id == id_nic)
0802             sysfs_remove_link(&boot_kobj->kobj, "device");
0803     };
0804 }
0805 
0806 static void ibft_cleanup(void)
0807 {
0808     if (boot_kset) {
0809         ibft_unregister();
0810         iscsi_boot_destroy_kset(boot_kset);
0811     }
0812 }
0813 
0814 static void __exit ibft_exit(void)
0815 {
0816     ibft_cleanup();
0817 }
0818 
0819 #ifdef CONFIG_ACPI
0820 static const struct {
0821     char *sign;
0822 } ibft_signs[] = {
0823     /*
0824      * One spec says "IBFT", the other says "iBFT". We have to check
0825      * for both.
0826      */
0827     { ACPI_SIG_IBFT },
0828     { "iBFT" },
0829     { "BIFT" }, /* Broadcom iSCSI Offload */
0830 };
0831 
0832 static void __init acpi_find_ibft_region(void)
0833 {
0834     int i;
0835     struct acpi_table_header *table = NULL;
0836 
0837     if (acpi_disabled)
0838         return;
0839 
0840     for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
0841         acpi_get_table(ibft_signs[i].sign, 0, &table);
0842         ibft_addr = (struct acpi_table_ibft *)table;
0843     }
0844 }
0845 #else
0846 static void __init acpi_find_ibft_region(void)
0847 {
0848 }
0849 #endif
0850 #ifdef CONFIG_ISCSI_IBFT_FIND
0851 static int __init acpi_find_isa_region(void)
0852 {
0853     if (ibft_phys_addr) {
0854         ibft_addr = isa_bus_to_virt(ibft_phys_addr);
0855         return 0;
0856     }
0857     return -ENODEV;
0858 }
0859 #else
0860 static int __init acpi_find_isa_region(void)
0861 {
0862     return -ENODEV;
0863 }
0864 #endif
0865 /*
0866  * ibft_init() - creates sysfs tree entries for the iBFT data.
0867  */
0868 static int __init ibft_init(void)
0869 {
0870     int rc = 0;
0871 
0872     /*
0873        As on UEFI systems the setup_arch()/reserve_ibft_region()
0874        is called before ACPI tables are parsed and it only does
0875        legacy finding.
0876     */
0877     if (acpi_find_isa_region())
0878         acpi_find_ibft_region();
0879 
0880     if (ibft_addr) {
0881         pr_info("iBFT detected.\n");
0882 
0883         rc = ibft_check_device();
0884         if (rc)
0885             return rc;
0886 
0887         boot_kset = iscsi_boot_create_kset("ibft");
0888         if (!boot_kset)
0889             return -ENOMEM;
0890 
0891         /* Scan the IBFT for data and register the kobjects. */
0892         rc = ibft_register_kobjects(ibft_addr);
0893         if (rc)
0894             goto out_free;
0895     } else
0896         printk(KERN_INFO "No iBFT detected.\n");
0897 
0898     return 0;
0899 
0900 out_free:
0901     ibft_cleanup();
0902     return rc;
0903 }
0904 
0905 module_init(ibft_init);
0906 module_exit(ibft_exit);