iscsi_ibft.c revision 1afa67f5e70b4733d5b237df61e6d639af6283bb
1/* 2 * Copyright 2007 Red Hat, Inc. 3 * by Peter Jones <pjones@redhat.com> 4 * Copyright 2008 IBM, Inc. 5 * by Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 6 * Copyright 2008 7 * by Konrad Rzeszutek <ketuzsezr@darnok.org> 8 * 9 * This code exposes the iSCSI Boot Format Table to userland via sysfs. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License v2.0 as published by 13 * the Free Software Foundation 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * Changelog: 21 * 22 * 14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org> 23 * Updated comments and copyrights. (v0.4.9) 24 * 25 * 11 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 26 * Converted to using ibft_addr. (v0.4.8) 27 * 28 * 8 Feb 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 29 * Combined two functions in one: reserve_ibft_region. (v0.4.7) 30 * 31 * 30 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 32 * Added logic to handle IPv6 addresses. (v0.4.6) 33 * 34 * 25 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 35 * Added logic to handle badly not-to-spec iBFT. (v0.4.5) 36 * 37 * 4 Jan 2008 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 38 * Added __init to function declarations. (v0.4.4) 39 * 40 * 21 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 41 * Updated kobject registration, combined unregister functions in one 42 * and code and style cleanup. (v0.4.3) 43 * 44 * 5 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 45 * Added end-markers to enums and re-organized kobject registration. (v0.4.2) 46 * 47 * 4 Dec 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 48 * Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1) 49 * 50 * 28 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 51 * Added sysfs-ibft documentation, moved 'find_ibft' function to 52 * in its own file and added text attributes for every struct field. (v0.4) 53 * 54 * 21 Nov 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 55 * Added text attributes emulating OpenFirmware /proc/device-tree naming. 56 * Removed binary /sysfs interface (v0.3) 57 * 58 * 29 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 59 * Added functionality in setup.c to reserve iBFT region. (v0.2) 60 * 61 * 27 Aug 2007 - Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 62 * First version exposing iBFT data via a binary /sysfs. (v0.1) 63 * 64 */ 65 66 67#include <linux/blkdev.h> 68#include <linux/capability.h> 69#include <linux/ctype.h> 70#include <linux/device.h> 71#include <linux/err.h> 72#include <linux/init.h> 73#include <linux/iscsi_ibft.h> 74#include <linux/limits.h> 75#include <linux/module.h> 76#include <linux/pci.h> 77#include <linux/slab.h> 78#include <linux/stat.h> 79#include <linux/string.h> 80#include <linux/types.h> 81 82#define IBFT_ISCSI_VERSION "0.4.9" 83#define IBFT_ISCSI_DATE "2008-Mar-14" 84 85MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and \ 86Konrad Rzeszutek <ketuzsezr@darnok.org>"); 87MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information"); 88MODULE_LICENSE("GPL"); 89MODULE_VERSION(IBFT_ISCSI_VERSION); 90 91struct ibft_hdr { 92 u8 id; 93 u8 version; 94 u16 length; 95 u8 index; 96 u8 flags; 97} __attribute__((__packed__)); 98 99struct ibft_control { 100 struct ibft_hdr hdr; 101 u16 extensions; 102 u16 initiator_off; 103 u16 nic0_off; 104 u16 tgt0_off; 105 u16 nic1_off; 106 u16 tgt1_off; 107} __attribute__((__packed__)); 108 109struct ibft_initiator { 110 struct ibft_hdr hdr; 111 char isns_server[16]; 112 char slp_server[16]; 113 char pri_radius_server[16]; 114 char sec_radius_server[16]; 115 u16 initiator_name_len; 116 u16 initiator_name_off; 117} __attribute__((__packed__)); 118 119struct ibft_nic { 120 struct ibft_hdr hdr; 121 char ip_addr[16]; 122 u8 subnet_mask_prefix; 123 u8 origin; 124 char gateway[16]; 125 char primary_dns[16]; 126 char secondary_dns[16]; 127 char dhcp[16]; 128 u16 vlan; 129 char mac[6]; 130 u16 pci_bdf; 131 u16 hostname_len; 132 u16 hostname_off; 133} __attribute__((__packed__)); 134 135struct ibft_tgt { 136 struct ibft_hdr hdr; 137 char ip_addr[16]; 138 u16 port; 139 char lun[8]; 140 u8 chap_type; 141 u8 nic_assoc; 142 u16 tgt_name_len; 143 u16 tgt_name_off; 144 u16 chap_name_len; 145 u16 chap_name_off; 146 u16 chap_secret_len; 147 u16 chap_secret_off; 148 u16 rev_chap_name_len; 149 u16 rev_chap_name_off; 150 u16 rev_chap_secret_len; 151 u16 rev_chap_secret_off; 152} __attribute__((__packed__)); 153 154/* 155 * The kobject different types and its names. 156 * 157*/ 158enum ibft_id { 159 id_reserved = 0, /* We don't support. */ 160 id_control = 1, /* Should show up only once and is not exported. */ 161 id_initiator = 2, 162 id_nic = 3, 163 id_target = 4, 164 id_extensions = 5, /* We don't support. */ 165 id_end_marker, 166}; 167 168/* 169 * We do not support the other types, hence the usage of NULL. 170 * This maps to the enum ibft_id. 171 */ 172static const char *ibft_id_names[] = 173 {NULL, NULL, "initiator", "ethernet%d", "target%d", NULL, NULL}; 174 175/* 176 * The text attributes names for each of the kobjects. 177*/ 178enum ibft_eth_properties_enum { 179 ibft_eth_index, 180 ibft_eth_flags, 181 ibft_eth_ip_addr, 182 ibft_eth_subnet_mask, 183 ibft_eth_origin, 184 ibft_eth_gateway, 185 ibft_eth_primary_dns, 186 ibft_eth_secondary_dns, 187 ibft_eth_dhcp, 188 ibft_eth_vlan, 189 ibft_eth_mac, 190 /* ibft_eth_pci_bdf - this is replaced by link to the device itself. */ 191 ibft_eth_hostname, 192 ibft_eth_end_marker, 193}; 194 195static const char *ibft_eth_properties[] = 196 {"index", "flags", "ip-addr", "subnet-mask", "origin", "gateway", 197 "primary-dns", "secondary-dns", "dhcp", "vlan", "mac", "hostname", 198 NULL}; 199 200enum ibft_tgt_properties_enum { 201 ibft_tgt_index, 202 ibft_tgt_flags, 203 ibft_tgt_ip_addr, 204 ibft_tgt_port, 205 ibft_tgt_lun, 206 ibft_tgt_chap_type, 207 ibft_tgt_nic_assoc, 208 ibft_tgt_name, 209 ibft_tgt_chap_name, 210 ibft_tgt_chap_secret, 211 ibft_tgt_rev_chap_name, 212 ibft_tgt_rev_chap_secret, 213 ibft_tgt_end_marker, 214}; 215 216static const char *ibft_tgt_properties[] = 217 {"index", "flags", "ip-addr", "port", "lun", "chap-type", "nic-assoc", 218 "target-name", "chap-name", "chap-secret", "rev-chap-name", 219 "rev-chap-name-secret", NULL}; 220 221enum ibft_initiator_properties_enum { 222 ibft_init_index, 223 ibft_init_flags, 224 ibft_init_isns_server, 225 ibft_init_slp_server, 226 ibft_init_pri_radius_server, 227 ibft_init_sec_radius_server, 228 ibft_init_initiator_name, 229 ibft_init_end_marker, 230}; 231 232static const char *ibft_initiator_properties[] = 233 {"index", "flags", "isns-server", "slp-server", "pri-radius-server", 234 "sec-radius-server", "initiator-name", NULL}; 235 236/* 237 * The kobject and attribute structures. 238 */ 239 240struct ibft_kobject { 241 struct ibft_table_header *header; 242 union { 243 struct ibft_initiator *initiator; 244 struct ibft_nic *nic; 245 struct ibft_tgt *tgt; 246 struct ibft_hdr *hdr; 247 }; 248 struct kobject kobj; 249 struct list_head node; 250}; 251 252struct ibft_attribute { 253 struct attribute attr; 254 ssize_t (*show) (struct ibft_kobject *entry, 255 struct ibft_attribute *attr, char *buf); 256 union { 257 struct ibft_initiator *initiator; 258 struct ibft_nic *nic; 259 struct ibft_tgt *tgt; 260 struct ibft_hdr *hdr; 261 }; 262 struct kobject *kobj; 263 int type; /* The enum of the type. This can be any value of: 264 ibft_eth_properties_enum, ibft_tgt_properties_enum, 265 or ibft_initiator_properties_enum. */ 266 struct list_head node; 267}; 268 269static LIST_HEAD(ibft_attr_list); 270static LIST_HEAD(ibft_kobject_list); 271 272static const char nulls[16]; 273 274/* 275 * Helper functions to parse data properly. 276 */ 277static ssize_t sprintf_ipaddr(char *buf, u8 *ip) 278{ 279 char *str = buf; 280 281 if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && 282 ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 && 283 ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff) { 284 /* 285 * IPV4 286 */ 287 str += sprintf(buf, NIPQUAD_FMT, ip[12], 288 ip[13], ip[14], ip[15]); 289 } else { 290 /* 291 * IPv6 292 */ 293 str += sprintf(str, "%p6", ip); 294 } 295 str += sprintf(str, "\n"); 296 return str - buf; 297} 298 299static ssize_t sprintf_string(char *str, int len, char *buf) 300{ 301 return sprintf(str, "%.*s\n", len, buf); 302} 303 304/* 305 * Helper function to verify the IBFT header. 306 */ 307static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length) 308{ 309 if (hdr->id != id) { 310 printk(KERN_ERR "iBFT error: We expected the " \ 311 "field header.id to have %d but " \ 312 "found %d instead!\n", id, hdr->id); 313 return -ENODEV; 314 } 315 if (hdr->length != length) { 316 printk(KERN_ERR "iBFT error: We expected the " \ 317 "field header.length to have %d but " \ 318 "found %d instead!\n", length, hdr->length); 319 return -ENODEV; 320 } 321 322 return 0; 323} 324 325static void ibft_release(struct kobject *kobj) 326{ 327 struct ibft_kobject *ibft = 328 container_of(kobj, struct ibft_kobject, kobj); 329 kfree(ibft); 330} 331 332/* 333 * Routines for parsing the iBFT data to be human readable. 334 */ 335static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry, 336 struct ibft_attribute *attr, 337 char *buf) 338{ 339 struct ibft_initiator *initiator = entry->initiator; 340 void *ibft_loc = entry->header; 341 char *str = buf; 342 343 if (!initiator) 344 return 0; 345 346 switch (attr->type) { 347 case ibft_init_index: 348 str += sprintf(str, "%d\n", initiator->hdr.index); 349 break; 350 case ibft_init_flags: 351 str += sprintf(str, "%d\n", initiator->hdr.flags); 352 break; 353 case ibft_init_isns_server: 354 str += sprintf_ipaddr(str, initiator->isns_server); 355 break; 356 case ibft_init_slp_server: 357 str += sprintf_ipaddr(str, initiator->slp_server); 358 break; 359 case ibft_init_pri_radius_server: 360 str += sprintf_ipaddr(str, initiator->pri_radius_server); 361 break; 362 case ibft_init_sec_radius_server: 363 str += sprintf_ipaddr(str, initiator->sec_radius_server); 364 break; 365 case ibft_init_initiator_name: 366 str += sprintf_string(str, initiator->initiator_name_len, 367 (char *)ibft_loc + 368 initiator->initiator_name_off); 369 break; 370 default: 371 break; 372 } 373 374 return str - buf; 375} 376 377static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, 378 struct ibft_attribute *attr, 379 char *buf) 380{ 381 struct ibft_nic *nic = entry->nic; 382 void *ibft_loc = entry->header; 383 char *str = buf; 384 char *mac; 385 int val; 386 387 if (!nic) 388 return 0; 389 390 switch (attr->type) { 391 case ibft_eth_index: 392 str += sprintf(str, "%d\n", nic->hdr.index); 393 break; 394 case ibft_eth_flags: 395 str += sprintf(str, "%d\n", nic->hdr.flags); 396 break; 397 case ibft_eth_ip_addr: 398 str += sprintf_ipaddr(str, nic->ip_addr); 399 break; 400 case ibft_eth_subnet_mask: 401 val = ~((1 << (32-nic->subnet_mask_prefix))-1); 402 str += sprintf(str, NIPQUAD_FMT, 403 (u8)(val >> 24), (u8)(val >> 16), 404 (u8)(val >> 8), (u8)(val)); 405 break; 406 case ibft_eth_origin: 407 str += sprintf(str, "%d\n", nic->origin); 408 break; 409 case ibft_eth_gateway: 410 str += sprintf_ipaddr(str, nic->gateway); 411 break; 412 case ibft_eth_primary_dns: 413 str += sprintf_ipaddr(str, nic->primary_dns); 414 break; 415 case ibft_eth_secondary_dns: 416 str += sprintf_ipaddr(str, nic->secondary_dns); 417 break; 418 case ibft_eth_dhcp: 419 str += sprintf_ipaddr(str, nic->dhcp); 420 break; 421 case ibft_eth_vlan: 422 str += sprintf(str, "%d\n", nic->vlan); 423 break; 424 case ibft_eth_mac: 425 mac = nic->mac; 426 str += sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n", 427 (u8)mac[0], (u8)mac[1], (u8)mac[2], 428 (u8)mac[3], (u8)mac[4], (u8)mac[5]); 429 break; 430 case ibft_eth_hostname: 431 str += sprintf_string(str, nic->hostname_len, 432 (char *)ibft_loc + nic->hostname_off); 433 break; 434 default: 435 break; 436 } 437 438 return str - buf; 439}; 440 441static ssize_t ibft_attr_show_target(struct ibft_kobject *entry, 442 struct ibft_attribute *attr, 443 char *buf) 444{ 445 struct ibft_tgt *tgt = entry->tgt; 446 void *ibft_loc = entry->header; 447 char *str = buf; 448 int i; 449 450 if (!tgt) 451 return 0; 452 453 switch (attr->type) { 454 case ibft_tgt_index: 455 str += sprintf(str, "%d\n", tgt->hdr.index); 456 break; 457 case ibft_tgt_flags: 458 str += sprintf(str, "%d\n", tgt->hdr.flags); 459 break; 460 case ibft_tgt_ip_addr: 461 str += sprintf_ipaddr(str, tgt->ip_addr); 462 break; 463 case ibft_tgt_port: 464 str += sprintf(str, "%d\n", tgt->port); 465 break; 466 case ibft_tgt_lun: 467 for (i = 0; i < 8; i++) 468 str += sprintf(str, "%x", (u8)tgt->lun[i]); 469 str += sprintf(str, "\n"); 470 break; 471 case ibft_tgt_nic_assoc: 472 str += sprintf(str, "%d\n", tgt->nic_assoc); 473 break; 474 case ibft_tgt_chap_type: 475 str += sprintf(str, "%d\n", tgt->chap_type); 476 break; 477 case ibft_tgt_name: 478 str += sprintf_string(str, tgt->tgt_name_len, 479 (char *)ibft_loc + tgt->tgt_name_off); 480 break; 481 case ibft_tgt_chap_name: 482 str += sprintf_string(str, tgt->chap_name_len, 483 (char *)ibft_loc + tgt->chap_name_off); 484 break; 485 case ibft_tgt_chap_secret: 486 str += sprintf_string(str, tgt->chap_secret_len, 487 (char *)ibft_loc + tgt->chap_secret_off); 488 break; 489 case ibft_tgt_rev_chap_name: 490 str += sprintf_string(str, tgt->rev_chap_name_len, 491 (char *)ibft_loc + 492 tgt->rev_chap_name_off); 493 break; 494 case ibft_tgt_rev_chap_secret: 495 str += sprintf_string(str, tgt->rev_chap_secret_len, 496 (char *)ibft_loc + 497 tgt->rev_chap_secret_off); 498 break; 499 default: 500 break; 501 } 502 503 return str - buf; 504} 505 506/* 507 * The routine called for all sysfs attributes. 508 */ 509static ssize_t ibft_show_attribute(struct kobject *kobj, 510 struct attribute *attr, 511 char *buf) 512{ 513 struct ibft_kobject *dev = 514 container_of(kobj, struct ibft_kobject, kobj); 515 struct ibft_attribute *ibft_attr = 516 container_of(attr, struct ibft_attribute, attr); 517 ssize_t ret = -EIO; 518 char *str = buf; 519 520 if (!capable(CAP_SYS_ADMIN)) 521 return -EACCES; 522 523 if (ibft_attr->show) 524 ret = ibft_attr->show(dev, ibft_attr, str); 525 526 return ret; 527} 528 529static struct sysfs_ops ibft_attr_ops = { 530 .show = ibft_show_attribute, 531}; 532 533static struct kobj_type ibft_ktype = { 534 .release = ibft_release, 535 .sysfs_ops = &ibft_attr_ops, 536}; 537 538static struct kset *ibft_kset; 539 540static int __init ibft_check_device(void) 541{ 542 int len; 543 u8 *pos; 544 u8 csum = 0; 545 546 len = ibft_addr->length; 547 548 /* Sanity checking of iBFT. */ 549 if (ibft_addr->revision != 1) { 550 printk(KERN_ERR "iBFT module supports only revision 1, " \ 551 "while this is %d.\n", ibft_addr->revision); 552 return -ENOENT; 553 } 554 for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++) 555 csum += *pos; 556 557 if (csum) { 558 printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum); 559 return -ENOENT; 560 } 561 562 return 0; 563} 564 565/* 566 * Helper function for ibft_register_kobjects. 567 */ 568static int __init ibft_create_kobject(struct ibft_table_header *header, 569 struct ibft_hdr *hdr, 570 struct list_head *list) 571{ 572 struct ibft_kobject *ibft_kobj = NULL; 573 struct ibft_nic *nic = (struct ibft_nic *)hdr; 574 struct pci_dev *pci_dev; 575 int rc = 0; 576 577 ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL); 578 if (!ibft_kobj) 579 return -ENOMEM; 580 581 ibft_kobj->header = header; 582 ibft_kobj->hdr = hdr; 583 584 switch (hdr->id) { 585 case id_initiator: 586 rc = ibft_verify_hdr("initiator", hdr, id_initiator, 587 sizeof(*ibft_kobj->initiator)); 588 break; 589 case id_nic: 590 rc = ibft_verify_hdr("ethernet", hdr, id_nic, 591 sizeof(*ibft_kobj->nic)); 592 break; 593 case id_target: 594 rc = ibft_verify_hdr("target", hdr, id_target, 595 sizeof(*ibft_kobj->tgt)); 596 break; 597 case id_reserved: 598 case id_control: 599 case id_extensions: 600 /* Fields which we don't support. Ignore them */ 601 rc = 1; 602 break; 603 default: 604 printk(KERN_ERR "iBFT has unknown structure type (%d). " \ 605 "Report this bug to %.6s!\n", hdr->id, 606 header->oem_id); 607 rc = 1; 608 break; 609 } 610 611 if (rc) { 612 /* Skip adding this kobject, but exit with non-fatal error. */ 613 kfree(ibft_kobj); 614 goto out_invalid_struct; 615 } 616 617 ibft_kobj->kobj.kset = ibft_kset; 618 619 rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype, 620 NULL, ibft_id_names[hdr->id], hdr->index); 621 622 if (rc) { 623 kfree(ibft_kobj); 624 goto out; 625 } 626 627 kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD); 628 629 if (hdr->id == id_nic) { 630 /* 631 * We don't search for the device in other domains than 632 * zero. This is because on x86 platforms the BIOS 633 * executes only devices which are in domain 0. Furthermore, the 634 * iBFT spec doesn't have a domain id field :-( 635 */ 636 pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8, 637 (nic->pci_bdf & 0xff)); 638 if (pci_dev) { 639 rc = sysfs_create_link(&ibft_kobj->kobj, 640 &pci_dev->dev.kobj, "device"); 641 pci_dev_put(pci_dev); 642 } 643 } 644 645 /* Nothing broke so lets add it to the list. */ 646 list_add_tail(&ibft_kobj->node, list); 647out: 648 return rc; 649out_invalid_struct: 650 /* Unsupported structs are skipped. */ 651 return 0; 652} 653 654/* 655 * Scan the IBFT table structure for the NIC and Target fields. When 656 * found add them on the passed-in list. We do not support the other 657 * fields at this point, so they are skipped. 658 */ 659static int __init ibft_register_kobjects(struct ibft_table_header *header, 660 struct list_head *list) 661{ 662 struct ibft_control *control = NULL; 663 void *ptr, *end; 664 int rc = 0; 665 u16 offset; 666 u16 eot_offset; 667 668 control = (void *)header + sizeof(*header); 669 end = (void *)control + control->hdr.length; 670 eot_offset = (void *)header + header->length - (void *)control; 671 rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, 672 sizeof(*control)); 673 674 /* iBFT table safety checking */ 675 rc |= ((control->hdr.index) ? -ENODEV : 0); 676 if (rc) { 677 printk(KERN_ERR "iBFT error: Control header is invalid!\n"); 678 return rc; 679 } 680 for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) { 681 offset = *(u16 *)ptr; 682 if (offset && offset < header->length && offset < eot_offset) { 683 rc = ibft_create_kobject(header, 684 (void *)header + offset, 685 list); 686 if (rc) 687 break; 688 } 689 } 690 691 return rc; 692} 693 694static void ibft_unregister(struct list_head *attr_list, 695 struct list_head *kobj_list) 696{ 697 struct ibft_kobject *data = NULL, *n; 698 struct ibft_attribute *attr = NULL, *m; 699 700 list_for_each_entry_safe(attr, m, attr_list, node) { 701 sysfs_remove_file(attr->kobj, &attr->attr); 702 list_del(&attr->node); 703 kfree(attr); 704 }; 705 list_del_init(attr_list); 706 707 list_for_each_entry_safe(data, n, kobj_list, node) { 708 list_del(&data->node); 709 if (data->hdr->id == id_nic) 710 sysfs_remove_link(&data->kobj, "device"); 711 kobject_put(&data->kobj); 712 }; 713 list_del_init(kobj_list); 714} 715 716static int __init ibft_create_attribute(struct ibft_kobject *kobj_data, 717 int type, 718 const char *name, 719 ssize_t (*show)(struct ibft_kobject *, 720 struct ibft_attribute*, 721 char *buf), 722 struct list_head *list) 723{ 724 struct ibft_attribute *attr = NULL; 725 struct ibft_hdr *hdr = kobj_data->hdr; 726 727 attr = kmalloc(sizeof(*attr), GFP_KERNEL); 728 if (!attr) 729 return -ENOMEM; 730 731 attr->attr.name = name; 732 attr->attr.mode = S_IRUSR; 733 734 attr->hdr = hdr; 735 attr->show = show; 736 attr->kobj = &kobj_data->kobj; 737 attr->type = type; 738 739 list_add_tail(&attr->node, list); 740 741 return 0; 742} 743 744/* 745 * Helper routiners to check to determine if the entry is valid 746 * in the proper iBFT structure. 747 */ 748static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry) 749{ 750 int rc = 0; 751 752 switch (entry) { 753 case ibft_eth_index: 754 case ibft_eth_flags: 755 rc = 1; 756 break; 757 case ibft_eth_ip_addr: 758 if (!memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) 759 rc = 1; 760 break; 761 case ibft_eth_subnet_mask: 762 if (!memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) 763 rc = 1; 764 break; 765 case ibft_eth_origin: 766 rc = 1; 767 break; 768 case ibft_eth_gateway: 769 if (memcmp(nic->gateway, nulls, sizeof(nic->gateway))) 770 rc = 1; 771 break; 772 case ibft_eth_primary_dns: 773 if (memcmp(nic->primary_dns, nulls, 774 sizeof(nic->primary_dns))) 775 rc = 1; 776 break; 777 case ibft_eth_secondary_dns: 778 if (memcmp(nic->secondary_dns, nulls, 779 sizeof(nic->secondary_dns))) 780 rc = 1; 781 break; 782 case ibft_eth_dhcp: 783 if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) 784 rc = 1; 785 break; 786 case ibft_eth_vlan: 787 case ibft_eth_mac: 788 rc = 1; 789 break; 790 case ibft_eth_hostname: 791 if (nic->hostname_off) 792 rc = 1; 793 break; 794 default: 795 break; 796 } 797 798 return rc; 799} 800 801static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry) 802{ 803 int rc = 0; 804 805 switch (entry) { 806 case ibft_tgt_index: 807 case ibft_tgt_flags: 808 case ibft_tgt_ip_addr: 809 case ibft_tgt_port: 810 case ibft_tgt_lun: 811 case ibft_tgt_nic_assoc: 812 case ibft_tgt_chap_type: 813 rc = 1; 814 case ibft_tgt_name: 815 if (tgt->tgt_name_len) 816 rc = 1; 817 break; 818 case ibft_tgt_chap_name: 819 case ibft_tgt_chap_secret: 820 if (tgt->chap_name_len) 821 rc = 1; 822 break; 823 case ibft_tgt_rev_chap_name: 824 case ibft_tgt_rev_chap_secret: 825 if (tgt->rev_chap_name_len) 826 rc = 1; 827 break; 828 default: 829 break; 830 } 831 832 return rc; 833} 834 835static int __init ibft_check_initiator_for(struct ibft_initiator *init, 836 int entry) 837{ 838 int rc = 0; 839 840 switch (entry) { 841 case ibft_init_index: 842 case ibft_init_flags: 843 rc = 1; 844 break; 845 case ibft_init_isns_server: 846 if (memcmp(init->isns_server, nulls, 847 sizeof(init->isns_server))) 848 rc = 1; 849 break; 850 case ibft_init_slp_server: 851 if (memcmp(init->slp_server, nulls, 852 sizeof(init->slp_server))) 853 rc = 1; 854 break; 855 case ibft_init_pri_radius_server: 856 if (memcmp(init->pri_radius_server, nulls, 857 sizeof(init->pri_radius_server))) 858 rc = 1; 859 break; 860 case ibft_init_sec_radius_server: 861 if (memcmp(init->sec_radius_server, nulls, 862 sizeof(init->sec_radius_server))) 863 rc = 1; 864 break; 865 case ibft_init_initiator_name: 866 if (init->initiator_name_len) 867 rc = 1; 868 break; 869 default: 870 break; 871 } 872 873 return rc; 874} 875 876/* 877 * Register the attributes for all of the kobjects. 878 */ 879static int __init ibft_register_attributes(struct list_head *kobject_list, 880 struct list_head *attr_list) 881{ 882 int rc = 0, i = 0; 883 struct ibft_kobject *data = NULL; 884 struct ibft_attribute *attr = NULL, *m; 885 886 list_for_each_entry(data, kobject_list, node) { 887 switch (data->hdr->id) { 888 case id_nic: 889 for (i = 0; i < ibft_eth_end_marker && !rc; i++) 890 if (ibft_check_nic_for(data->nic, i)) 891 rc = ibft_create_attribute(data, i, 892 ibft_eth_properties[i], 893 ibft_attr_show_nic, attr_list); 894 break; 895 case id_target: 896 for (i = 0; i < ibft_tgt_end_marker && !rc; i++) 897 if (ibft_check_tgt_for(data->tgt, i)) 898 rc = ibft_create_attribute(data, i, 899 ibft_tgt_properties[i], 900 ibft_attr_show_target, 901 attr_list); 902 break; 903 case id_initiator: 904 for (i = 0; i < ibft_init_end_marker && !rc; i++) 905 if (ibft_check_initiator_for( 906 data->initiator, i)) 907 rc = ibft_create_attribute(data, i, 908 ibft_initiator_properties[i], 909 ibft_attr_show_initiator, 910 attr_list); 911 break; 912 default: 913 break; 914 } 915 if (rc) 916 break; 917 } 918 list_for_each_entry_safe(attr, m, attr_list, node) { 919 rc = sysfs_create_file(attr->kobj, &attr->attr); 920 if (rc) { 921 list_del(&attr->node); 922 kfree(attr); 923 break; 924 } 925 } 926 927 return rc; 928} 929 930/* 931 * ibft_init() - creates sysfs tree entries for the iBFT data. 932 */ 933static int __init ibft_init(void) 934{ 935 int rc = 0; 936 937 ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj); 938 if (!ibft_kset) 939 return -ENOMEM; 940 941 if (ibft_addr) { 942 printk(KERN_INFO "iBFT detected at 0x%lx.\n", 943 virt_to_phys((void *)ibft_addr)); 944 945 rc = ibft_check_device(); 946 if (rc) 947 goto out_firmware_unregister; 948 949 /* Scan the IBFT for data and register the kobjects. */ 950 rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list); 951 if (rc) 952 goto out_free; 953 954 /* Register the attributes */ 955 rc = ibft_register_attributes(&ibft_kobject_list, 956 &ibft_attr_list); 957 if (rc) 958 goto out_free; 959 } else 960 printk(KERN_INFO "No iBFT detected.\n"); 961 962 return 0; 963 964out_free: 965 ibft_unregister(&ibft_attr_list, &ibft_kobject_list); 966out_firmware_unregister: 967 kset_unregister(ibft_kset); 968 return rc; 969} 970 971static void __exit ibft_exit(void) 972{ 973 ibft_unregister(&ibft_attr_list, &ibft_kobject_list); 974 kset_unregister(ibft_kset); 975} 976 977module_init(ibft_init); 978module_exit(ibft_exit); 979