brintos

brintos / linux-shallow public Read only

0
0
Text · 20.9 KiB · 6e97883 Raw
907 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 20088 *  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 one37 *   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 to47 *   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		 * IPV4209		 */210		str += sprintf(buf, "%pI4", ip + 12);211	} else {212		/*213		 * IPv6214		 */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 valid468 * 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 than713		* zero. This is because on x86 platforms the BIOS714		* executes only devices which are in domain 0. Furthermore, the715		* 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. When735 * found add them on the passed-in list. We do not support the other736 * 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_ACPI820static const struct {821	char *sign;822} ibft_signs[] = {823	/*824	 * One spec says "IBFT", the other says "iBFT". We have to check825	 * 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#else846static void __init acpi_find_ibft_region(void)847{848}849#endif850#ifdef CONFIG_ISCSI_IBFT_FIND851static 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#else860static int __init acpi_find_isa_region(void)861{862	return -ENODEV;863}864#endif865/*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 does875	   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	} else896		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);907