1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
87struct ibft_hdr {
88 u8 id;
89 u8 version;
90 u16 length;
91 u8 index;
92 u8 flags;
93} __attribute__((__packed__));
94
95struct ibft_control {
96 struct ibft_hdr hdr;
97 u16 extensions;
98 u16 initiator_off;
99 u16 nic0_off;
100 u16 tgt0_off;
101 u16 nic1_off;
102 u16 tgt1_off;
103} __attribute__((__packed__));
104
105struct ibft_initiator {
106 struct ibft_hdr hdr;
107 char isns_server[16];
108 char slp_server[16];
109 char pri_radius_server[16];
110 char sec_radius_server[16];
111 u16 initiator_name_len;
112 u16 initiator_name_off;
113} __attribute__((__packed__));
114
115struct ibft_nic {
116 struct ibft_hdr hdr;
117 char ip_addr[16];
118 u8 subnet_mask_prefix;
119 u8 origin;
120 char gateway[16];
121 char primary_dns[16];
122 char secondary_dns[16];
123 char dhcp[16];
124 u16 vlan;
125 char mac[6];
126 u16 pci_bdf;
127 u16 hostname_len;
128 u16 hostname_off;
129} __attribute__((__packed__));
130
131struct ibft_tgt {
132 struct ibft_hdr hdr;
133 char ip_addr[16];
134 u16 port;
135 char lun[8];
136 u8 chap_type;
137 u8 nic_assoc;
138 u16 tgt_name_len;
139 u16 tgt_name_off;
140 u16 chap_name_len;
141 u16 chap_name_off;
142 u16 chap_secret_len;
143 u16 chap_secret_off;
144 u16 rev_chap_name_len;
145 u16 rev_chap_name_off;
146 u16 rev_chap_secret_len;
147 u16 rev_chap_secret_off;
148} __attribute__((__packed__));
149
150
151
152
153
154enum ibft_id {
155 id_reserved = 0,
156 id_control = 1,
157 id_initiator = 2,
158 id_nic = 3,
159 id_target = 4,
160 id_extensions = 5,
161 id_end_marker,
162};
163
164
165
166
167
168struct ibft_kobject {
169 struct acpi_table_ibft *header;
170 union {
171 struct ibft_initiator *initiator;
172 struct ibft_nic *nic;
173 struct ibft_tgt *tgt;
174 struct ibft_hdr *hdr;
175 };
176};
177
178static struct iscsi_boot_kset *boot_kset;
179
180
181static const char nulls[16];
182
183
184static const char mapped_nulls[16] = { 0x00, 0x00, 0x00, 0x00,
185 0x00, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0xff, 0xff,
187 0x00, 0x00, 0x00, 0x00 };
188
189static int address_not_null(u8 *ip)
190{
191 return (memcmp(ip, nulls, 16) && memcmp(ip, mapped_nulls, 16));
192}
193
194
195
196
197static ssize_t sprintf_ipaddr(char *buf, u8 *ip)
198{
199 char *str = buf;
200
201 if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 &&
202 ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 &&
203 ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff) {
204
205
206
207 str += sprintf(buf, "%pI4", ip + 12);
208 } else {
209
210
211
212 str += sprintf(str, "%pI6", ip);
213 }
214 str += sprintf(str, "\n");
215 return str - buf;
216}
217
218static ssize_t sprintf_string(char *str, int len, char *buf)
219{
220 return sprintf(str, "%.*s\n", len, buf);
221}
222
223
224
225
226static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
227{
228 if (hdr->id != id) {
229 printk(KERN_ERR "iBFT error: We expected the %s " \
230 "field header.id to have %d but " \
231 "found %d instead!\n", t, id, hdr->id);
232 return -ENODEV;
233 }
234 if (hdr->length != length) {
235 printk(KERN_ERR "iBFT error: We expected the %s " \
236 "field header.length to have %d but " \
237 "found %d instead!\n", t, length, hdr->length);
238 return -ENODEV;
239 }
240
241 return 0;
242}
243
244
245
246
247static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
248{
249 struct ibft_kobject *entry = data;
250 struct ibft_initiator *initiator = entry->initiator;
251 void *ibft_loc = entry->header;
252 char *str = buf;
253
254 if (!initiator)
255 return 0;
256
257 switch (type) {
258 case ISCSI_BOOT_INI_INDEX:
259 str += sprintf(str, "%d\n", initiator->hdr.index);
260 break;
261 case ISCSI_BOOT_INI_FLAGS:
262 str += sprintf(str, "%d\n", initiator->hdr.flags);
263 break;
264 case ISCSI_BOOT_INI_ISNS_SERVER:
265 str += sprintf_ipaddr(str, initiator->isns_server);
266 break;
267 case ISCSI_BOOT_INI_SLP_SERVER:
268 str += sprintf_ipaddr(str, initiator->slp_server);
269 break;
270 case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
271 str += sprintf_ipaddr(str, initiator->pri_radius_server);
272 break;
273 case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
274 str += sprintf_ipaddr(str, initiator->sec_radius_server);
275 break;
276 case ISCSI_BOOT_INI_INITIATOR_NAME:
277 str += sprintf_string(str, initiator->initiator_name_len,
278 (char *)ibft_loc +
279 initiator->initiator_name_off);
280 break;
281 default:
282 break;
283 }
284
285 return str - buf;
286}
287
288static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
289{
290 struct ibft_kobject *entry = data;
291 struct ibft_nic *nic = entry->nic;
292 void *ibft_loc = entry->header;
293 char *str = buf;
294 __be32 val;
295
296 if (!nic)
297 return 0;
298
299 switch (type) {
300 case ISCSI_BOOT_ETH_INDEX:
301 str += sprintf(str, "%d\n", nic->hdr.index);
302 break;
303 case ISCSI_BOOT_ETH_FLAGS:
304 str += sprintf(str, "%d\n", nic->hdr.flags);
305 break;
306 case ISCSI_BOOT_ETH_IP_ADDR:
307 str += sprintf_ipaddr(str, nic->ip_addr);
308 break;
309 case ISCSI_BOOT_ETH_SUBNET_MASK:
310 val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
311 str += sprintf(str, "%pI4", &val);
312 break;
313 case ISCSI_BOOT_ETH_PREFIX_LEN:
314 str += sprintf(str, "%d\n", nic->subnet_mask_prefix);
315 break;
316 case ISCSI_BOOT_ETH_ORIGIN:
317 str += sprintf(str, "%d\n", nic->origin);
318 break;
319 case ISCSI_BOOT_ETH_GATEWAY:
320 str += sprintf_ipaddr(str, nic->gateway);
321 break;
322 case ISCSI_BOOT_ETH_PRIMARY_DNS:
323 str += sprintf_ipaddr(str, nic->primary_dns);
324 break;
325 case ISCSI_BOOT_ETH_SECONDARY_DNS:
326 str += sprintf_ipaddr(str, nic->secondary_dns);
327 break;
328 case ISCSI_BOOT_ETH_DHCP:
329 str += sprintf_ipaddr(str, nic->dhcp);
330 break;
331 case ISCSI_BOOT_ETH_VLAN:
332 str += sprintf(str, "%d\n", nic->vlan);
333 break;
334 case ISCSI_BOOT_ETH_MAC:
335 str += sprintf(str, "%pM\n", nic->mac);
336 break;
337 case ISCSI_BOOT_ETH_HOSTNAME:
338 str += sprintf_string(str, nic->hostname_len,
339 (char *)ibft_loc + nic->hostname_off);
340 break;
341 default:
342 break;
343 }
344
345 return str - buf;
346};
347
348static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
349{
350 struct ibft_kobject *entry = data;
351 struct ibft_tgt *tgt = entry->tgt;
352 void *ibft_loc = entry->header;
353 char *str = buf;
354 int i;
355
356 if (!tgt)
357 return 0;
358
359 switch (type) {
360 case ISCSI_BOOT_TGT_INDEX:
361 str += sprintf(str, "%d\n", tgt->hdr.index);
362 break;
363 case ISCSI_BOOT_TGT_FLAGS:
364 str += sprintf(str, "%d\n", tgt->hdr.flags);
365 break;
366 case ISCSI_BOOT_TGT_IP_ADDR:
367 str += sprintf_ipaddr(str, tgt->ip_addr);
368 break;
369 case ISCSI_BOOT_TGT_PORT:
370 str += sprintf(str, "%d\n", tgt->port);
371 break;
372 case ISCSI_BOOT_TGT_LUN:
373 for (i = 0; i < 8; i++)
374 str += sprintf(str, "%x", (u8)tgt->lun[i]);
375 str += sprintf(str, "\n");
376 break;
377 case ISCSI_BOOT_TGT_NIC_ASSOC:
378 str += sprintf(str, "%d\n", tgt->nic_assoc);
379 break;
380 case ISCSI_BOOT_TGT_CHAP_TYPE:
381 str += sprintf(str, "%d\n", tgt->chap_type);
382 break;
383 case ISCSI_BOOT_TGT_NAME:
384 str += sprintf_string(str, tgt->tgt_name_len,
385 (char *)ibft_loc + tgt->tgt_name_off);
386 break;
387 case ISCSI_BOOT_TGT_CHAP_NAME:
388 str += sprintf_string(str, tgt->chap_name_len,
389 (char *)ibft_loc + tgt->chap_name_off);
390 break;
391 case ISCSI_BOOT_TGT_CHAP_SECRET:
392 str += sprintf_string(str, tgt->chap_secret_len,
393 (char *)ibft_loc + tgt->chap_secret_off);
394 break;
395 case ISCSI_BOOT_TGT_REV_CHAP_NAME:
396 str += sprintf_string(str, tgt->rev_chap_name_len,
397 (char *)ibft_loc +
398 tgt->rev_chap_name_off);
399 break;
400 case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
401 str += sprintf_string(str, tgt->rev_chap_secret_len,
402 (char *)ibft_loc +
403 tgt->rev_chap_secret_off);
404 break;
405 default:
406 break;
407 }
408
409 return str - buf;
410}
411
412static ssize_t ibft_attr_show_acpitbl(void *data, int type, char *buf)
413{
414 struct ibft_kobject *entry = data;
415 char *str = buf;
416
417 switch (type) {
418 case ISCSI_BOOT_ACPITBL_SIGNATURE:
419 str += sprintf_string(str, ACPI_NAMESEG_SIZE,
420 entry->header->header.signature);
421 break;
422 case ISCSI_BOOT_ACPITBL_OEM_ID:
423 str += sprintf_string(str, ACPI_OEM_ID_SIZE,
424 entry->header->header.oem_id);
425 break;
426 case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
427 str += sprintf_string(str, ACPI_OEM_TABLE_ID_SIZE,
428 entry->header->header.oem_table_id);
429 break;
430 default:
431 break;
432 }
433
434 return str - buf;
435}
436
437static int __init ibft_check_device(void)
438{
439 int len;
440 u8 *pos;
441 u8 csum = 0;
442
443 len = ibft_addr->header.length;
444
445
446 if (ibft_addr->header.revision != 1) {
447 printk(KERN_ERR "iBFT module supports only revision 1, " \
448 "while this is %d.\n",
449 ibft_addr->header.revision);
450 return -ENOENT;
451 }
452 for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
453 csum += *pos;
454
455 if (csum) {
456 printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum);
457 return -ENOENT;
458 }
459
460 return 0;
461}
462
463
464
465
466
467static umode_t ibft_check_nic_for(void *data, int type)
468{
469 struct ibft_kobject *entry = data;
470 struct ibft_nic *nic = entry->nic;
471 umode_t rc = 0;
472
473 switch (type) {
474 case ISCSI_BOOT_ETH_INDEX:
475 case ISCSI_BOOT_ETH_FLAGS:
476 rc = S_IRUGO;
477 break;
478 case ISCSI_BOOT_ETH_IP_ADDR:
479 if (address_not_null(nic->ip_addr))
480 rc = S_IRUGO;
481 break;
482 case ISCSI_BOOT_ETH_PREFIX_LEN:
483 case ISCSI_BOOT_ETH_SUBNET_MASK:
484 if (nic->subnet_mask_prefix)
485 rc = S_IRUGO;
486 break;
487 case ISCSI_BOOT_ETH_ORIGIN:
488 rc = S_IRUGO;
489 break;
490 case ISCSI_BOOT_ETH_GATEWAY:
491 if (address_not_null(nic->gateway))
492 rc = S_IRUGO;
493 break;
494 case ISCSI_BOOT_ETH_PRIMARY_DNS:
495 if (address_not_null(nic->primary_dns))
496 rc = S_IRUGO;
497 break;
498 case ISCSI_BOOT_ETH_SECONDARY_DNS:
499 if (address_not_null(nic->secondary_dns))
500 rc = S_IRUGO;
501 break;
502 case ISCSI_BOOT_ETH_DHCP:
503 if (address_not_null(nic->dhcp))
504 rc = S_IRUGO;
505 break;
506 case ISCSI_BOOT_ETH_VLAN:
507 case ISCSI_BOOT_ETH_MAC:
508 rc = S_IRUGO;
509 break;
510 case ISCSI_BOOT_ETH_HOSTNAME:
511 if (nic->hostname_off)
512 rc = S_IRUGO;
513 break;
514 default:
515 break;
516 }
517
518 return rc;
519}
520
521static umode_t __init ibft_check_tgt_for(void *data, int type)
522{
523 struct ibft_kobject *entry = data;
524 struct ibft_tgt *tgt = entry->tgt;
525 umode_t rc = 0;
526
527 switch (type) {
528 case ISCSI_BOOT_TGT_INDEX:
529 case ISCSI_BOOT_TGT_FLAGS:
530 case ISCSI_BOOT_TGT_IP_ADDR:
531 case ISCSI_BOOT_TGT_PORT:
532 case ISCSI_BOOT_TGT_LUN:
533 case ISCSI_BOOT_TGT_NIC_ASSOC:
534 case ISCSI_BOOT_TGT_CHAP_TYPE:
535 rc = S_IRUGO;
536 break;
537 case ISCSI_BOOT_TGT_NAME:
538 if (tgt->tgt_name_len)
539 rc = S_IRUGO;
540 break;
541 case ISCSI_BOOT_TGT_CHAP_NAME:
542 case ISCSI_BOOT_TGT_CHAP_SECRET:
543 if (tgt->chap_name_len)
544 rc = S_IRUGO;
545 break;
546 case ISCSI_BOOT_TGT_REV_CHAP_NAME:
547 case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
548 if (tgt->rev_chap_name_len)
549 rc = S_IRUGO;
550 break;
551 default:
552 break;
553 }
554
555 return rc;
556}
557
558static umode_t __init ibft_check_initiator_for(void *data, int type)
559{
560 struct ibft_kobject *entry = data;
561 struct ibft_initiator *init = entry->initiator;
562 umode_t rc = 0;
563
564 switch (type) {
565 case ISCSI_BOOT_INI_INDEX:
566 case ISCSI_BOOT_INI_FLAGS:
567 rc = S_IRUGO;
568 break;
569 case ISCSI_BOOT_INI_ISNS_SERVER:
570 if (address_not_null(init->isns_server))
571 rc = S_IRUGO;
572 break;
573 case ISCSI_BOOT_INI_SLP_SERVER:
574 if (address_not_null(init->slp_server))
575 rc = S_IRUGO;
576 break;
577 case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
578 if (address_not_null(init->pri_radius_server))
579 rc = S_IRUGO;
580 break;
581 case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
582 if (address_not_null(init->sec_radius_server))
583 rc = S_IRUGO;
584 break;
585 case ISCSI_BOOT_INI_INITIATOR_NAME:
586 if (init->initiator_name_len)
587 rc = S_IRUGO;
588 break;
589 default:
590 break;
591 }
592
593 return rc;
594}
595
596static umode_t __init ibft_check_acpitbl_for(void *data, int type)
597{
598
599 umode_t rc = 0;
600
601 switch (type) {
602 case ISCSI_BOOT_ACPITBL_SIGNATURE:
603 case ISCSI_BOOT_ACPITBL_OEM_ID:
604 case ISCSI_BOOT_ACPITBL_OEM_TABLE_ID:
605 rc = S_IRUGO;
606 break;
607 default:
608 break;
609 }
610
611 return rc;
612}
613
614static void ibft_kobj_release(void *data)
615{
616 kfree(data);
617}
618
619
620
621
622static int __init ibft_create_kobject(struct acpi_table_ibft *header,
623 struct ibft_hdr *hdr)
624{
625 struct iscsi_boot_kobj *boot_kobj = NULL;
626 struct ibft_kobject *ibft_kobj = NULL;
627 struct ibft_nic *nic = (struct ibft_nic *)hdr;
628 struct pci_dev *pci_dev;
629 int rc = 0;
630
631 ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
632 if (!ibft_kobj)
633 return -ENOMEM;
634
635 ibft_kobj->header = header;
636 ibft_kobj->hdr = hdr;
637
638 switch (hdr->id) {
639 case id_initiator:
640 rc = ibft_verify_hdr("initiator", hdr, id_initiator,
641 sizeof(*ibft_kobj->initiator));
642 if (rc)
643 break;
644
645 boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
646 ibft_kobj,
647 ibft_attr_show_initiator,
648 ibft_check_initiator_for,
649 ibft_kobj_release);
650 if (!boot_kobj) {
651 rc = -ENOMEM;
652 goto free_ibft_obj;
653 }
654 break;
655 case id_nic:
656 rc = ibft_verify_hdr("ethernet", hdr, id_nic,
657 sizeof(*ibft_kobj->nic));
658 if (rc)
659 break;
660
661 boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
662 ibft_kobj,
663 ibft_attr_show_nic,
664 ibft_check_nic_for,
665 ibft_kobj_release);
666 if (!boot_kobj) {
667 rc = -ENOMEM;
668 goto free_ibft_obj;
669 }
670 break;
671 case id_target:
672 rc = ibft_verify_hdr("target", hdr, id_target,
673 sizeof(*ibft_kobj->tgt));
674 if (rc)
675 break;
676
677 boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
678 ibft_kobj,
679 ibft_attr_show_target,
680 ibft_check_tgt_for,
681 ibft_kobj_release);
682 if (!boot_kobj) {
683 rc = -ENOMEM;
684 goto free_ibft_obj;
685 }
686 break;
687 case id_reserved:
688 case id_control:
689 case id_extensions:
690
691 rc = 1;
692 break;
693 default:
694 printk(KERN_ERR "iBFT has unknown structure type (%d). " \
695 "Report this bug to %.6s!\n", hdr->id,
696 header->header.oem_id);
697 rc = 1;
698 break;
699 }
700
701 if (rc) {
702
703 rc = 0;
704 goto free_ibft_obj;
705 }
706
707 if (hdr->id == id_nic) {
708
709
710
711
712
713
714 pci_dev = pci_get_domain_bus_and_slot(0,
715 (nic->pci_bdf & 0xff00) >> 8,
716 (nic->pci_bdf & 0xff));
717 if (pci_dev) {
718 rc = sysfs_create_link(&boot_kobj->kobj,
719 &pci_dev->dev.kobj, "device");
720 pci_dev_put(pci_dev);
721 }
722 }
723 return 0;
724
725free_ibft_obj:
726 kfree(ibft_kobj);
727 return rc;
728}
729
730
731
732
733
734
735static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
736{
737 struct ibft_control *control = NULL;
738 struct iscsi_boot_kobj *boot_kobj;
739 struct ibft_kobject *ibft_kobj;
740 void *ptr, *end;
741 int rc = 0;
742 u16 offset;
743 u16 eot_offset;
744
745 control = (void *)header + sizeof(*header);
746 end = (void *)control + control->hdr.length;
747 eot_offset = (void *)header + header->header.length - (void *)control;
748 rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
749 sizeof(*control));
750
751
752 rc |= ((control->hdr.index) ? -ENODEV : 0);
753 if (rc) {
754 printk(KERN_ERR "iBFT error: Control header is invalid!\n");
755 return rc;
756 }
757 for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) {
758 offset = *(u16 *)ptr;
759 if (offset && offset < header->header.length &&
760 offset < eot_offset) {
761 rc = ibft_create_kobject(header,
762 (void *)header + offset);
763 if (rc)
764 break;
765 }
766 }
767 if (rc)
768 return rc;
769
770 ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
771 if (!ibft_kobj)
772 return -ENOMEM;
773
774 ibft_kobj->header = header;
775 ibft_kobj->hdr = NULL;
776
777 boot_kobj = iscsi_boot_create_acpitbl(boot_kset, 0,
778 ibft_kobj,
779 ibft_attr_show_acpitbl,
780 ibft_check_acpitbl_for,
781 ibft_kobj_release);
782 if (!boot_kobj) {
783 kfree(ibft_kobj);
784 rc = -ENOMEM;
785 }
786
787 return rc;
788}
789
790static void ibft_unregister(void)
791{
792 struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
793 struct ibft_kobject *ibft_kobj;
794
795 list_for_each_entry_safe(boot_kobj, tmp_kobj,
796 &boot_kset->kobj_list, list) {
797 ibft_kobj = boot_kobj->data;
798 if (ibft_kobj->hdr && ibft_kobj->hdr->id == id_nic)
799 sysfs_remove_link(&boot_kobj->kobj, "device");
800 };
801}
802
803static void ibft_cleanup(void)
804{
805 if (boot_kset) {
806 ibft_unregister();
807 iscsi_boot_destroy_kset(boot_kset);
808 }
809}
810
811static void __exit ibft_exit(void)
812{
813 ibft_cleanup();
814}
815
816#ifdef CONFIG_ACPI
817static const struct {
818 char *sign;
819} ibft_signs[] = {
820
821
822
823
824 { ACPI_SIG_IBFT },
825 { "iBFT" },
826 { "BIFT" },
827};
828
829static void __init acpi_find_ibft_region(void)
830{
831 int i;
832 struct acpi_table_header *table = NULL;
833
834 if (acpi_disabled)
835 return;
836
837 for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
838 acpi_get_table(ibft_signs[i].sign, 0, &table);
839 ibft_addr = (struct acpi_table_ibft *)table;
840 }
841}
842#else
843static void __init acpi_find_ibft_region(void)
844{
845}
846#endif
847
848
849
850
851static int __init ibft_init(void)
852{
853 int rc = 0;
854
855
856
857
858
859
860 if (!ibft_addr)
861 acpi_find_ibft_region();
862
863 if (ibft_addr) {
864 pr_info("iBFT detected.\n");
865
866 rc = ibft_check_device();
867 if (rc)
868 return rc;
869
870 boot_kset = iscsi_boot_create_kset("ibft");
871 if (!boot_kset)
872 return -ENOMEM;
873
874
875 rc = ibft_register_kobjects(ibft_addr);
876 if (rc)
877 goto out_free;
878 } else
879 printk(KERN_INFO "No iBFT detected.\n");
880
881 return 0;
882
883out_free:
884 ibft_cleanup();
885 return rc;
886}
887
888module_init(ibft_init);
889module_exit(ibft_exit);
890