0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
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
0155
0156
0157 enum ibft_id {
0158 id_reserved = 0,
0159 id_control = 1,
0160 id_initiator = 2,
0161 id_nic = 3,
0162 id_target = 4,
0163 id_extensions = 5,
0164 id_end_marker,
0165 };
0166
0167
0168
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
0184 static const char nulls[16];
0185
0186
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
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
0209
0210 str += sprintf(buf, "%pI4", ip + 12);
0211 } else {
0212
0213
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
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
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
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
0468
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
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
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
0706 rc = 0;
0707 goto free_ibft_obj;
0708 }
0709
0710 if (hdr->id == id_nic) {
0711
0712
0713
0714
0715
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
0735
0736
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
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;
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
0825
0826
0827 { ACPI_SIG_IBFT },
0828 { "iBFT" },
0829 { "BIFT" },
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
0867
0868 static int __init ibft_init(void)
0869 {
0870 int rc = 0;
0871
0872
0873
0874
0875
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
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);