xref: /openbmc/linux/drivers/firmware/iscsi_ibft.c (revision 36db6e8484ed455bbb320d89a119378897ae991c)
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  
81  MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and "
82  	      "Konrad Rzeszutek <ketuzsezr@darnok.org>");
83  MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information");
84  MODULE_LICENSE("GPL");
85  MODULE_VERSION(IBFT_ISCSI_VERSION);
86  
87  static struct acpi_table_ibft *ibft_addr;
88  
89  struct ibft_hdr {
90  	u8 id;
91  	u8 version;
92  	u16 length;
93  	u8 index;
94  	u8 flags;
95  } __attribute__((__packed__));
96  
97  struct 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  
108  struct 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  
118  struct 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  
134  struct 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  */
157  enum 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  
171  struct 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  
181  static struct iscsi_boot_kset *boot_kset;
182  
183  /* fully null address */
184  static const char nulls[16];
185  
186  /* IPv4-mapped IPv6 ::ffff:0.0.0.0 */
187  static 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  
address_not_null(u8 * ip)192  static 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   */
sprintf_ipaddr(char * buf,u8 * ip)200  static 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  
sprintf_string(char * str,int len,char * buf)221  static 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   */
ibft_verify_hdr(char * t,struct ibft_hdr * hdr,int id,int length)229  static 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   */
ibft_attr_show_initiator(void * data,int type,char * buf)250  static 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  
ibft_attr_show_nic(void * data,int type,char * buf)291  static 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  		if (nic->subnet_mask_prefix > 32)
314  			val = cpu_to_be32(~0);
315  		else
316  			val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
317  		str += sprintf(str, "%pI4", &val);
318  		break;
319  	case ISCSI_BOOT_ETH_PREFIX_LEN:
320  		str += sprintf(str, "%d\n", nic->subnet_mask_prefix);
321  		break;
322  	case ISCSI_BOOT_ETH_ORIGIN:
323  		str += sprintf(str, "%d\n", nic->origin);
324  		break;
325  	case ISCSI_BOOT_ETH_GATEWAY:
326  		str += sprintf_ipaddr(str, nic->gateway);
327  		break;
328  	case ISCSI_BOOT_ETH_PRIMARY_DNS:
329  		str += sprintf_ipaddr(str, nic->primary_dns);
330  		break;
331  	case ISCSI_BOOT_ETH_SECONDARY_DNS:
332  		str += sprintf_ipaddr(str, nic->secondary_dns);
333  		break;
334  	case ISCSI_BOOT_ETH_DHCP:
335  		str += sprintf_ipaddr(str, nic->dhcp);
336  		break;
337  	case ISCSI_BOOT_ETH_VLAN:
338  		str += sprintf(str, "%d\n", nic->vlan);
339  		break;
340  	case ISCSI_BOOT_ETH_MAC:
341  		str += sprintf(str, "%pM\n", nic->mac);
342  		break;
343  	case ISCSI_BOOT_ETH_HOSTNAME:
344  		str += sprintf_string(str, nic->hostname_len,
345  				      (char *)ibft_loc + nic->hostname_off);
346  		break;
347  	default:
348  		break;
349  	}
350  
351  	return str - buf;
352  };
353  
ibft_attr_show_target(void * data,int type,char * buf)354  static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
355  {
356  	struct ibft_kobject *entry = data;
357  	struct ibft_tgt *tgt = entry->tgt;
358  	void *ibft_loc = entry->header;
359  	char *str = buf;
360  	int i;
361  
362  	if (!tgt)
363  		return 0;
364  
365  	switch (type) {
366  	case ISCSI_BOOT_TGT_INDEX:
367  		str += sprintf(str, "%d\n", tgt->hdr.index);
368  		break;
369  	case ISCSI_BOOT_TGT_FLAGS:
370  		str += sprintf(str, "%d\n", tgt->hdr.flags);
371  		break;
372  	case ISCSI_BOOT_TGT_IP_ADDR:
373  		str += sprintf_ipaddr(str, tgt->ip_addr);
374  		break;
375  	case ISCSI_BOOT_TGT_PORT:
376  		str += sprintf(str, "%d\n", tgt->port);
377  		break;
378  	case ISCSI_BOOT_TGT_LUN:
379  		for (i = 0; i < 8; i++)
380  			str += sprintf(str, "%x", (u8)tgt->lun[i]);
381  		str += sprintf(str, "\n");
382  		break;
383  	case ISCSI_BOOT_TGT_NIC_ASSOC:
384  		str += sprintf(str, "%d\n", tgt->nic_assoc);
385  		break;
386  	case ISCSI_BOOT_TGT_CHAP_TYPE:
387  		str += sprintf(str, "%d\n", tgt->chap_type);
388  		break;
389  	case ISCSI_BOOT_TGT_NAME:
390  		str += sprintf_string(str, tgt->tgt_name_len,
391  				      (char *)ibft_loc + tgt->tgt_name_off);
392  		break;
393  	case ISCSI_BOOT_TGT_CHAP_NAME:
394  		str += sprintf_string(str, tgt->chap_name_len,
395  				      (char *)ibft_loc + tgt->chap_name_off);
396  		break;
397  	case ISCSI_BOOT_TGT_CHAP_SECRET:
398  		str += sprintf_string(str, tgt->chap_secret_len,
399  				      (char *)ibft_loc + tgt->chap_secret_off);
400  		break;
401  	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
402  		str += sprintf_string(str, tgt->rev_chap_name_len,
403  				      (char *)ibft_loc +
404  				      tgt->rev_chap_name_off);
405  		break;
406  	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
407  		str += sprintf_string(str, tgt->rev_chap_secret_len,
408  				      (char *)ibft_loc +
409  				      tgt->rev_chap_secret_off);
410  		break;
411  	default:
412  		break;
413  	}
414  
415  	return str - buf;
416  }
417  
ibft_attr_show_acpitbl(void * data,int type,char * buf)418  static ssize_t ibft_attr_show_acpitbl(void *data, int type, char *buf)
419  {
420  	struct ibft_kobject *entry = data;
421  	char *str = buf;
422  
423  	switch (type) {
424  	case ISCSI_BOOT_ACPITBL_SIGNATURE:
425  		str += sprintf_string(str, ACPI_NAMESEG_SIZE,
426  				      entry->header->header.signature);
427  		break;
428  	case ISCSI_BOOT_ACPITBL_OEM_ID:
429  		str += sprintf_string(str, ACPI_OEM_ID_SIZE,
430  				      entry->header->header.oem_id);
431  		break;
432  	case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
433  		str += sprintf_string(str, ACPI_OEM_TABLE_ID_SIZE,
434  				      entry->header->header.oem_table_id);
435  		break;
436  	default:
437  		break;
438  	}
439  
440  	return str - buf;
441  }
442  
ibft_check_device(void)443  static int __init ibft_check_device(void)
444  {
445  	int len;
446  	u8 *pos;
447  	u8 csum = 0;
448  
449  	len = ibft_addr->header.length;
450  
451  	/* Sanity checking of iBFT. */
452  	if (ibft_addr->header.revision != 1) {
453  		printk(KERN_ERR "iBFT module supports only revision 1, " \
454  				"while this is %d.\n",
455  				ibft_addr->header.revision);
456  		return -ENOENT;
457  	}
458  	for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
459  		csum += *pos;
460  
461  	if (csum) {
462  		printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum);
463  		return -ENOENT;
464  	}
465  
466  	return 0;
467  }
468  
469  /*
470   * Helper routiners to check to determine if the entry is valid
471   * in the proper iBFT structure.
472   */
ibft_check_nic_for(void * data,int type)473  static umode_t ibft_check_nic_for(void *data, int type)
474  {
475  	struct ibft_kobject *entry = data;
476  	struct ibft_nic *nic = entry->nic;
477  	umode_t rc = 0;
478  
479  	switch (type) {
480  	case ISCSI_BOOT_ETH_INDEX:
481  	case ISCSI_BOOT_ETH_FLAGS:
482  		rc = S_IRUGO;
483  		break;
484  	case ISCSI_BOOT_ETH_IP_ADDR:
485  		if (address_not_null(nic->ip_addr))
486  			rc = S_IRUGO;
487  		break;
488  	case ISCSI_BOOT_ETH_PREFIX_LEN:
489  	case ISCSI_BOOT_ETH_SUBNET_MASK:
490  		if (nic->subnet_mask_prefix)
491  			rc = S_IRUGO;
492  		break;
493  	case ISCSI_BOOT_ETH_ORIGIN:
494  		rc = S_IRUGO;
495  		break;
496  	case ISCSI_BOOT_ETH_GATEWAY:
497  		if (address_not_null(nic->gateway))
498  			rc = S_IRUGO;
499  		break;
500  	case ISCSI_BOOT_ETH_PRIMARY_DNS:
501  		if (address_not_null(nic->primary_dns))
502  			rc = S_IRUGO;
503  		break;
504  	case ISCSI_BOOT_ETH_SECONDARY_DNS:
505  		if (address_not_null(nic->secondary_dns))
506  			rc = S_IRUGO;
507  		break;
508  	case ISCSI_BOOT_ETH_DHCP:
509  		if (address_not_null(nic->dhcp))
510  			rc = S_IRUGO;
511  		break;
512  	case ISCSI_BOOT_ETH_VLAN:
513  	case ISCSI_BOOT_ETH_MAC:
514  		rc = S_IRUGO;
515  		break;
516  	case ISCSI_BOOT_ETH_HOSTNAME:
517  		if (nic->hostname_off)
518  			rc = S_IRUGO;
519  		break;
520  	default:
521  		break;
522  	}
523  
524  	return rc;
525  }
526  
ibft_check_tgt_for(void * data,int type)527  static umode_t __init ibft_check_tgt_for(void *data, int type)
528  {
529  	struct ibft_kobject *entry = data;
530  	struct ibft_tgt *tgt = entry->tgt;
531  	umode_t rc = 0;
532  
533  	switch (type) {
534  	case ISCSI_BOOT_TGT_INDEX:
535  	case ISCSI_BOOT_TGT_FLAGS:
536  	case ISCSI_BOOT_TGT_IP_ADDR:
537  	case ISCSI_BOOT_TGT_PORT:
538  	case ISCSI_BOOT_TGT_LUN:
539  	case ISCSI_BOOT_TGT_NIC_ASSOC:
540  	case ISCSI_BOOT_TGT_CHAP_TYPE:
541  		rc = S_IRUGO;
542  		break;
543  	case ISCSI_BOOT_TGT_NAME:
544  		if (tgt->tgt_name_len)
545  			rc = S_IRUGO;
546  		break;
547  	case ISCSI_BOOT_TGT_CHAP_NAME:
548  	case ISCSI_BOOT_TGT_CHAP_SECRET:
549  		if (tgt->chap_name_len)
550  			rc = S_IRUGO;
551  		break;
552  	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
553  	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
554  		if (tgt->rev_chap_name_len)
555  			rc = S_IRUGO;
556  		break;
557  	default:
558  		break;
559  	}
560  
561  	return rc;
562  }
563  
ibft_check_initiator_for(void * data,int type)564  static umode_t __init ibft_check_initiator_for(void *data, int type)
565  {
566  	struct ibft_kobject *entry = data;
567  	struct ibft_initiator *init = entry->initiator;
568  	umode_t rc = 0;
569  
570  	switch (type) {
571  	case ISCSI_BOOT_INI_INDEX:
572  	case ISCSI_BOOT_INI_FLAGS:
573  		rc = S_IRUGO;
574  		break;
575  	case ISCSI_BOOT_INI_ISNS_SERVER:
576  		if (address_not_null(init->isns_server))
577  			rc = S_IRUGO;
578  		break;
579  	case ISCSI_BOOT_INI_SLP_SERVER:
580  		if (address_not_null(init->slp_server))
581  			rc = S_IRUGO;
582  		break;
583  	case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
584  		if (address_not_null(init->pri_radius_server))
585  			rc = S_IRUGO;
586  		break;
587  	case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
588  		if (address_not_null(init->sec_radius_server))
589  			rc = S_IRUGO;
590  		break;
591  	case ISCSI_BOOT_INI_INITIATOR_NAME:
592  		if (init->initiator_name_len)
593  			rc = S_IRUGO;
594  		break;
595  	default:
596  		break;
597  	}
598  
599  	return rc;
600  }
601  
ibft_check_acpitbl_for(void * data,int type)602  static umode_t __init ibft_check_acpitbl_for(void *data, int type)
603  {
604  
605  	umode_t rc = 0;
606  
607  	switch (type) {
608  	case ISCSI_BOOT_ACPITBL_SIGNATURE:
609  	case ISCSI_BOOT_ACPITBL_OEM_ID:
610  	case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
611  		rc = S_IRUGO;
612  		break;
613  	default:
614  		break;
615  	}
616  
617  	return rc;
618  }
619  
ibft_kobj_release(void * data)620  static void ibft_kobj_release(void *data)
621  {
622  	kfree(data);
623  }
624  
625  /*
626   * Helper function for ibft_register_kobjects.
627   */
ibft_create_kobject(struct acpi_table_ibft * header,struct ibft_hdr * hdr)628  static int __init ibft_create_kobject(struct acpi_table_ibft *header,
629  				      struct ibft_hdr *hdr)
630  {
631  	struct iscsi_boot_kobj *boot_kobj = NULL;
632  	struct ibft_kobject *ibft_kobj = NULL;
633  	struct ibft_nic *nic = (struct ibft_nic *)hdr;
634  	struct pci_dev *pci_dev;
635  	int rc = 0;
636  
637  	ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
638  	if (!ibft_kobj)
639  		return -ENOMEM;
640  
641  	ibft_kobj->header = header;
642  	ibft_kobj->hdr = hdr;
643  
644  	switch (hdr->id) {
645  	case id_initiator:
646  		rc = ibft_verify_hdr("initiator", hdr, id_initiator,
647  				     sizeof(*ibft_kobj->initiator));
648  		if (rc)
649  			break;
650  
651  		boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
652  						ibft_kobj,
653  						ibft_attr_show_initiator,
654  						ibft_check_initiator_for,
655  						ibft_kobj_release);
656  		if (!boot_kobj) {
657  			rc = -ENOMEM;
658  			goto free_ibft_obj;
659  		}
660  		break;
661  	case id_nic:
662  		rc = ibft_verify_hdr("ethernet", hdr, id_nic,
663  				     sizeof(*ibft_kobj->nic));
664  		if (rc)
665  			break;
666  
667  		boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
668  						       ibft_kobj,
669  						       ibft_attr_show_nic,
670  						       ibft_check_nic_for,
671  						       ibft_kobj_release);
672  		if (!boot_kobj) {
673  			rc = -ENOMEM;
674  			goto free_ibft_obj;
675  		}
676  		break;
677  	case id_target:
678  		rc = ibft_verify_hdr("target", hdr, id_target,
679  				     sizeof(*ibft_kobj->tgt));
680  		if (rc)
681  			break;
682  
683  		boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
684  						     ibft_kobj,
685  						     ibft_attr_show_target,
686  						     ibft_check_tgt_for,
687  						     ibft_kobj_release);
688  		if (!boot_kobj) {
689  			rc = -ENOMEM;
690  			goto free_ibft_obj;
691  		}
692  		break;
693  	case id_reserved:
694  	case id_control:
695  	case id_extensions:
696  		/* Fields which we don't support. Ignore them */
697  		rc = 1;
698  		break;
699  	default:
700  		printk(KERN_ERR "iBFT has unknown structure type (%d). " \
701  				"Report this bug to %.6s!\n", hdr->id,
702  				header->header.oem_id);
703  		rc = 1;
704  		break;
705  	}
706  
707  	if (rc) {
708  		/* Skip adding this kobject, but exit with non-fatal error. */
709  		rc = 0;
710  		goto free_ibft_obj;
711  	}
712  
713  	if (hdr->id == id_nic) {
714  		/*
715  		* We don't search for the device in other domains than
716  		* zero. This is because on x86 platforms the BIOS
717  		* executes only devices which are in domain 0. Furthermore, the
718  		* iBFT spec doesn't have a domain id field :-(
719  		*/
720  		pci_dev = pci_get_domain_bus_and_slot(0,
721  						(nic->pci_bdf & 0xff00) >> 8,
722  						(nic->pci_bdf & 0xff));
723  		if (pci_dev) {
724  			rc = sysfs_create_link(&boot_kobj->kobj,
725  					       &pci_dev->dev.kobj, "device");
726  			pci_dev_put(pci_dev);
727  		}
728  	}
729  	return 0;
730  
731  free_ibft_obj:
732  	kfree(ibft_kobj);
733  	return rc;
734  }
735  
736  /*
737   * Scan the IBFT table structure for the NIC and Target fields. When
738   * found add them on the passed-in list. We do not support the other
739   * fields at this point, so they are skipped.
740   */
ibft_register_kobjects(struct acpi_table_ibft * header)741  static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
742  {
743  	struct ibft_control *control = NULL;
744  	struct iscsi_boot_kobj *boot_kobj;
745  	struct ibft_kobject *ibft_kobj;
746  	void *ptr, *end;
747  	int rc = 0;
748  	u16 offset;
749  	u16 eot_offset;
750  
751  	control = (void *)header + sizeof(*header);
752  	end = (void *)control + control->hdr.length;
753  	eot_offset = (void *)header + header->header.length - (void *)control;
754  	rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, 0);
755  
756  	/* iBFT table safety checking */
757  	rc |= ((control->hdr.index) ? -ENODEV : 0);
758  	rc |= ((control->hdr.length < sizeof(*control)) ? -ENODEV : 0);
759  	if (rc) {
760  		printk(KERN_ERR "iBFT error: Control header is invalid!\n");
761  		return rc;
762  	}
763  	for (ptr = &control->initiator_off; ptr + sizeof(u16) <= end; ptr += sizeof(u16)) {
764  		offset = *(u16 *)ptr;
765  		if (offset && offset < header->header.length &&
766  						offset < eot_offset) {
767  			rc = ibft_create_kobject(header,
768  						 (void *)header + offset);
769  			if (rc)
770  				break;
771  		}
772  	}
773  	if (rc)
774  		return rc;
775  
776  	ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
777  	if (!ibft_kobj)
778  		return -ENOMEM;
779  
780  	ibft_kobj->header = header;
781  	ibft_kobj->hdr = NULL; /*for ibft_unregister*/
782  
783  	boot_kobj = iscsi_boot_create_acpitbl(boot_kset, 0,
784  					ibft_kobj,
785  					ibft_attr_show_acpitbl,
786  					ibft_check_acpitbl_for,
787  					ibft_kobj_release);
788  	if (!boot_kobj)  {
789  		kfree(ibft_kobj);
790  		rc = -ENOMEM;
791  	}
792  
793  	return rc;
794  }
795  
ibft_unregister(void)796  static void ibft_unregister(void)
797  {
798  	struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
799  	struct ibft_kobject *ibft_kobj;
800  
801  	list_for_each_entry_safe(boot_kobj, tmp_kobj,
802  				 &boot_kset->kobj_list, list) {
803  		ibft_kobj = boot_kobj->data;
804  		if (ibft_kobj->hdr && ibft_kobj->hdr->id == id_nic)
805  			sysfs_remove_link(&boot_kobj->kobj, "device");
806  	};
807  }
808  
ibft_cleanup(void)809  static void ibft_cleanup(void)
810  {
811  	if (boot_kset) {
812  		ibft_unregister();
813  		iscsi_boot_destroy_kset(boot_kset);
814  	}
815  }
816  
ibft_exit(void)817  static void __exit ibft_exit(void)
818  {
819  	ibft_cleanup();
820  }
821  
822  #ifdef CONFIG_ACPI
823  static const struct {
824  	char *sign;
825  } ibft_signs[] = {
826  	/*
827  	 * One spec says "IBFT", the other says "iBFT". We have to check
828  	 * for both.
829  	 */
830  	{ ACPI_SIG_IBFT },
831  	{ "iBFT" },
832  	{ "BIFT" },	/* Broadcom iSCSI Offload */
833  };
834  
acpi_find_ibft_region(void)835  static void __init acpi_find_ibft_region(void)
836  {
837  	int i;
838  	struct acpi_table_header *table = NULL;
839  
840  	if (acpi_disabled)
841  		return;
842  
843  	for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
844  		acpi_get_table(ibft_signs[i].sign, 0, &table);
845  		ibft_addr = (struct acpi_table_ibft *)table;
846  	}
847  }
848  #else
acpi_find_ibft_region(void)849  static void __init acpi_find_ibft_region(void)
850  {
851  }
852  #endif
853  #ifdef CONFIG_ISCSI_IBFT_FIND
acpi_find_isa_region(void)854  static int __init acpi_find_isa_region(void)
855  {
856  	if (ibft_phys_addr) {
857  		ibft_addr = isa_bus_to_virt(ibft_phys_addr);
858  		return 0;
859  	}
860  	return -ENODEV;
861  }
862  #else
acpi_find_isa_region(void)863  static int __init acpi_find_isa_region(void)
864  {
865  	return -ENODEV;
866  }
867  #endif
868  /*
869   * ibft_init() - creates sysfs tree entries for the iBFT data.
870   */
ibft_init(void)871  static int __init ibft_init(void)
872  {
873  	int rc = 0;
874  
875  	/*
876  	   As on UEFI systems the setup_arch()/reserve_ibft_region()
877  	   is called before ACPI tables are parsed and it only does
878  	   legacy finding.
879  	*/
880  	if (acpi_find_isa_region())
881  		acpi_find_ibft_region();
882  
883  	if (ibft_addr) {
884  		pr_info("iBFT detected.\n");
885  
886  		rc = ibft_check_device();
887  		if (rc)
888  			return rc;
889  
890  		boot_kset = iscsi_boot_create_kset("ibft");
891  		if (!boot_kset)
892  			return -ENOMEM;
893  
894  		/* Scan the IBFT for data and register the kobjects. */
895  		rc = ibft_register_kobjects(ibft_addr);
896  		if (rc)
897  			goto out_free;
898  	} else
899  		printk(KERN_INFO "No iBFT detected.\n");
900  
901  	return 0;
902  
903  out_free:
904  	ibft_cleanup();
905  	return rc;
906  }
907  
908  module_init(ibft_init);
909  module_exit(ibft_exit);
910