Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iscsi_ibft.c
Go to the documentation of this file.
1 /*
2  * Copyright 2007-2010 Red Hat, Inc.
3  * by Peter Jones <[email protected]>
4  * Copyright 2008 IBM, Inc.
5  * by Konrad Rzeszutek <[email protected]>
6  * Copyright 2008
7  * by Konrad Rzeszutek <[email protected]>
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  * 06 Jan 2010 - Peter Jones <[email protected]>
23  * New changelog entries are in the git log from now on. Not here.
24  *
25  * 14 Mar 2008 - Konrad Rzeszutek <[email protected]>
26  * Updated comments and copyrights. (v0.4.9)
27  *
28  * 11 Feb 2008 - Konrad Rzeszutek <[email protected]>
29  * Converted to using ibft_addr. (v0.4.8)
30  *
31  * 8 Feb 2008 - Konrad Rzeszutek <[email protected]>
32  * Combined two functions in one: reserve_ibft_region. (v0.4.7)
33  *
34  * 30 Jan 2008 - Konrad Rzeszutek <[email protected]>
35  * Added logic to handle IPv6 addresses. (v0.4.6)
36  *
37  * 25 Jan 2008 - Konrad Rzeszutek <[email protected]>
38  * Added logic to handle badly not-to-spec iBFT. (v0.4.5)
39  *
40  * 4 Jan 2008 - Konrad Rzeszutek <[email protected]>
41  * Added __init to function declarations. (v0.4.4)
42  *
43  * 21 Dec 2007 - Konrad Rzeszutek <[email protected]>
44  * Updated kobject registration, combined unregister functions in one
45  * and code and style cleanup. (v0.4.3)
46  *
47  * 5 Dec 2007 - Konrad Rzeszutek <[email protected]>
48  * Added end-markers to enums and re-organized kobject registration. (v0.4.2)
49  *
50  * 4 Dec 2007 - Konrad Rzeszutek <[email protected]>
51  * Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1)
52  *
53  * 28 Nov 2007 - Konrad Rzeszutek <[email protected]>
54  * Added sysfs-ibft documentation, moved 'find_ibft' function to
55  * in its own file and added text attributes for every struct field. (v0.4)
56  *
57  * 21 Nov 2007 - Konrad Rzeszutek <[email protected]>
58  * Added text attributes emulating OpenFirmware /proc/device-tree naming.
59  * Removed binary /sysfs interface (v0.3)
60  *
61  * 29 Aug 2007 - Konrad Rzeszutek <[email protected]>
62  * Added functionality in setup.c to reserve iBFT region. (v0.2)
63  *
64  * 27 Aug 2007 - Konrad Rzeszutek <[email protected]>
65  * First version exposing iBFT data via a binary /sysfs. (v0.1)
66  *
67  */
68 
69 
70 #include <linux/blkdev.h>
71 #include <linux/capability.h>
72 #include <linux/ctype.h>
73 #include <linux/device.h>
74 #include <linux/err.h>
75 #include <linux/init.h>
76 #include <linux/iscsi_ibft.h>
77 #include <linux/limits.h>
78 #include <linux/module.h>
79 #include <linux/pci.h>
80 #include <linux/slab.h>
81 #include <linux/stat.h>
82 #include <linux/string.h>
83 #include <linux/types.h>
84 #include <linux/acpi.h>
85 #include <linux/iscsi_boot_sysfs.h>
86 
87 #define IBFT_ISCSI_VERSION "0.5.0"
88 #define IBFT_ISCSI_DATE "2010-Feb-25"
89 
90 MODULE_AUTHOR("Peter Jones <[email protected]> and "
91  "Konrad Rzeszutek <[email protected]>");
92 MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information");
93 MODULE_LICENSE("GPL");
95 
96 struct ibft_hdr {
97  u8 id;
102 } __attribute__((__packed__));
104 struct ibft_control {
105  struct ibft_hdr hdr;
112 } __attribute__((__packed__));
115  struct ibft_hdr hdr;
116  char isns_server[16];
117  char slp_server[16];
122 } __attribute__((__packed__));
123 
124 struct ibft_nic {
125  struct ibft_hdr hdr;
126  char ip_addr[16];
129  char gateway[16];
130  char primary_dns[16];
131  char secondary_dns[16];
132  char dhcp[16];
134  char mac[6];
138 } __attribute__((__packed__));
139 
140 struct ibft_tgt {
141  struct ibft_hdr hdr;
142  char ip_addr[16];
144  char lun[8];
157 } __attribute__((__packed__));
158 
159 /*
160  * The kobject different types and its names.
161  *
162 */
163 enum ibft_id {
164  id_reserved = 0, /* We don't support. */
165  id_control = 1, /* Should show up only once and is not exported. */
167  id_nic = 3,
169  id_extensions = 5, /* We don't support. */
171 };
173 /*
174  * The kobject and attribute structures.
175  */
176 
177 struct ibft_kobject {
179  union {
181  struct ibft_nic *nic;
182  struct ibft_tgt *tgt;
183  struct ibft_hdr *hdr;
184  };
185 };
186 
187 static struct iscsi_boot_kset *boot_kset;
188 
189 static const char nulls[16];
190 
191 /*
192  * Helper functions to parse data properly.
193  */
194 static ssize_t sprintf_ipaddr(char *buf, u8 *ip)
195 {
196  char *str = buf;
197 
198  if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 &&
199  ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 &&
200  ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff) {
201  /*
202  * IPV4
203  */
204  str += sprintf(buf, "%pI4", ip + 12);
205  } else {
206  /*
207  * IPv6
208  */
209  str += sprintf(str, "%pI6", ip);
210  }
211  str += sprintf(str, "\n");
212  return str - buf;
213 }
214 
215 static ssize_t sprintf_string(char *str, int len, char *buf)
216 {
217  return sprintf(str, "%.*s\n", len, buf);
218 }
219 
220 /*
221  * Helper function to verify the IBFT header.
222  */
223 static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
224 {
225  if (hdr->id != id) {
226  printk(KERN_ERR "iBFT error: We expected the %s " \
227  "field header.id to have %d but " \
228  "found %d instead!\n", t, id, hdr->id);
229  return -ENODEV;
230  }
231  if (hdr->length != length) {
232  printk(KERN_ERR "iBFT error: We expected the %s " \
233  "field header.length to have %d but " \
234  "found %d instead!\n", t, length, hdr->length);
235  return -ENODEV;
236  }
237 
238  return 0;
239 }
240 
241 /*
242  * Routines for parsing the iBFT data to be human readable.
243  */
244 static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
245 {
246  struct ibft_kobject *entry = data;
247  struct ibft_initiator *initiator = entry->initiator;
248  void *ibft_loc = entry->header;
249  char *str = buf;
250 
251  if (!initiator)
252  return 0;
253 
254  switch (type) {
256  str += sprintf(str, "%d\n", initiator->hdr.index);
257  break;
259  str += sprintf(str, "%d\n", initiator->hdr.flags);
260  break;
262  str += sprintf_ipaddr(str, initiator->isns_server);
263  break;
265  str += sprintf_ipaddr(str, initiator->slp_server);
266  break;
268  str += sprintf_ipaddr(str, initiator->pri_radius_server);
269  break;
271  str += sprintf_ipaddr(str, initiator->sec_radius_server);
272  break;
274  str += sprintf_string(str, initiator->initiator_name_len,
275  (char *)ibft_loc +
276  initiator->initiator_name_off);
277  break;
278  default:
279  break;
280  }
281 
282  return str - buf;
283 }
284 
285 static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
286 {
287  struct ibft_kobject *entry = data;
288  struct ibft_nic *nic = entry->nic;
289  void *ibft_loc = entry->header;
290  char *str = buf;
291  __be32 val;
292 
293  if (!nic)
294  return 0;
295 
296  switch (type) {
298  str += sprintf(str, "%d\n", nic->hdr.index);
299  break;
301  str += sprintf(str, "%d\n", nic->hdr.flags);
302  break;
304  str += sprintf_ipaddr(str, nic->ip_addr);
305  break;
307  val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
308  str += sprintf(str, "%pI4", &val);
309  break;
311  str += sprintf(str, "%d\n", nic->origin);
312  break;
314  str += sprintf_ipaddr(str, nic->gateway);
315  break;
317  str += sprintf_ipaddr(str, nic->primary_dns);
318  break;
320  str += sprintf_ipaddr(str, nic->secondary_dns);
321  break;
322  case ISCSI_BOOT_ETH_DHCP:
323  str += sprintf_ipaddr(str, nic->dhcp);
324  break;
325  case ISCSI_BOOT_ETH_VLAN:
326  str += sprintf(str, "%d\n", nic->vlan);
327  break;
328  case ISCSI_BOOT_ETH_MAC:
329  str += sprintf(str, "%pM\n", nic->mac);
330  break;
332  str += sprintf_string(str, nic->hostname_len,
333  (char *)ibft_loc + nic->hostname_off);
334  break;
335  default:
336  break;
337  }
338 
339  return str - buf;
340 };
341 
342 static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
343 {
344  struct ibft_kobject *entry = data;
345  struct ibft_tgt *tgt = entry->tgt;
346  void *ibft_loc = entry->header;
347  char *str = buf;
348  int i;
349 
350  if (!tgt)
351  return 0;
352 
353  switch (type) {
355  str += sprintf(str, "%d\n", tgt->hdr.index);
356  break;
358  str += sprintf(str, "%d\n", tgt->hdr.flags);
359  break;
361  str += sprintf_ipaddr(str, tgt->ip_addr);
362  break;
363  case ISCSI_BOOT_TGT_PORT:
364  str += sprintf(str, "%d\n", tgt->port);
365  break;
366  case ISCSI_BOOT_TGT_LUN:
367  for (i = 0; i < 8; i++)
368  str += sprintf(str, "%x", (u8)tgt->lun[i]);
369  str += sprintf(str, "\n");
370  break;
372  str += sprintf(str, "%d\n", tgt->nic_assoc);
373  break;
375  str += sprintf(str, "%d\n", tgt->chap_type);
376  break;
377  case ISCSI_BOOT_TGT_NAME:
378  str += sprintf_string(str, tgt->tgt_name_len,
379  (char *)ibft_loc + tgt->tgt_name_off);
380  break;
382  str += sprintf_string(str, tgt->chap_name_len,
383  (char *)ibft_loc + tgt->chap_name_off);
384  break;
386  str += sprintf_string(str, tgt->chap_secret_len,
387  (char *)ibft_loc + tgt->chap_secret_off);
388  break;
390  str += sprintf_string(str, tgt->rev_chap_name_len,
391  (char *)ibft_loc +
392  tgt->rev_chap_name_off);
393  break;
395  str += sprintf_string(str, tgt->rev_chap_secret_len,
396  (char *)ibft_loc +
397  tgt->rev_chap_secret_off);
398  break;
399  default:
400  break;
401  }
402 
403  return str - buf;
404 }
405 
406 static int __init ibft_check_device(void)
407 {
408  int len;
409  u8 *pos;
410  u8 csum = 0;
411 
412  len = ibft_addr->header.length;
413 
414  /* Sanity checking of iBFT. */
415  if (ibft_addr->header.revision != 1) {
416  printk(KERN_ERR "iBFT module supports only revision 1, " \
417  "while this is %d.\n",
418  ibft_addr->header.revision);
419  return -ENOENT;
420  }
421  for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
422  csum += *pos;
423 
424  if (csum) {
425  printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum);
426  return -ENOENT;
427  }
428 
429  return 0;
430 }
431 
432 /*
433  * Helper routiners to check to determine if the entry is valid
434  * in the proper iBFT structure.
435  */
436 static umode_t ibft_check_nic_for(void *data, int type)
437 {
438  struct ibft_kobject *entry = data;
439  struct ibft_nic *nic = entry->nic;
440  umode_t rc = 0;
441 
442  switch (type) {
445  rc = S_IRUGO;
446  break;
448  if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
449  rc = S_IRUGO;
450  break;
452  if (nic->subnet_mask_prefix)
453  rc = S_IRUGO;
454  break;
456  rc = S_IRUGO;
457  break;
459  if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
460  rc = S_IRUGO;
461  break;
463  if (memcmp(nic->primary_dns, nulls,
464  sizeof(nic->primary_dns)))
465  rc = S_IRUGO;
466  break;
468  if (memcmp(nic->secondary_dns, nulls,
469  sizeof(nic->secondary_dns)))
470  rc = S_IRUGO;
471  break;
472  case ISCSI_BOOT_ETH_DHCP:
473  if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
474  rc = S_IRUGO;
475  break;
476  case ISCSI_BOOT_ETH_VLAN:
477  case ISCSI_BOOT_ETH_MAC:
478  rc = S_IRUGO;
479  break;
481  if (nic->hostname_off)
482  rc = S_IRUGO;
483  break;
484  default:
485  break;
486  }
487 
488  return rc;
489 }
490 
491 static umode_t __init ibft_check_tgt_for(void *data, int type)
492 {
493  struct ibft_kobject *entry = data;
494  struct ibft_tgt *tgt = entry->tgt;
495  umode_t rc = 0;
496 
497  switch (type) {
501  case ISCSI_BOOT_TGT_PORT:
502  case ISCSI_BOOT_TGT_LUN:
505  rc = S_IRUGO;
506  case ISCSI_BOOT_TGT_NAME:
507  if (tgt->tgt_name_len)
508  rc = S_IRUGO;
509  break;
512  if (tgt->chap_name_len)
513  rc = S_IRUGO;
514  break;
517  if (tgt->rev_chap_name_len)
518  rc = S_IRUGO;
519  break;
520  default:
521  break;
522  }
523 
524  return rc;
525 }
526 
527 static umode_t __init ibft_check_initiator_for(void *data, int type)
528 {
529  struct ibft_kobject *entry = data;
530  struct ibft_initiator *init = entry->initiator;
531  umode_t rc = 0;
532 
533  switch (type) {
536  rc = S_IRUGO;
537  break;
539  if (memcmp(init->isns_server, nulls,
540  sizeof(init->isns_server)))
541  rc = S_IRUGO;
542  break;
544  if (memcmp(init->slp_server, nulls,
545  sizeof(init->slp_server)))
546  rc = S_IRUGO;
547  break;
549  if (memcmp(init->pri_radius_server, nulls,
550  sizeof(init->pri_radius_server)))
551  rc = S_IRUGO;
552  break;
554  if (memcmp(init->sec_radius_server, nulls,
555  sizeof(init->sec_radius_server)))
556  rc = S_IRUGO;
557  break;
559  if (init->initiator_name_len)
560  rc = S_IRUGO;
561  break;
562  default:
563  break;
564  }
565 
566  return rc;
567 }
568 
569 static void ibft_kobj_release(void *data)
570 {
571  kfree(data);
572 }
573 
574 /*
575  * Helper function for ibft_register_kobjects.
576  */
577 static int __init ibft_create_kobject(struct acpi_table_ibft *header,
578  struct ibft_hdr *hdr)
579 {
580  struct iscsi_boot_kobj *boot_kobj = NULL;
581  struct ibft_kobject *ibft_kobj = NULL;
582  struct ibft_nic *nic = (struct ibft_nic *)hdr;
583  struct pci_dev *pci_dev;
584  int rc = 0;
585 
586  ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL);
587  if (!ibft_kobj)
588  return -ENOMEM;
589 
590  ibft_kobj->header = header;
591  ibft_kobj->hdr = hdr;
592 
593  switch (hdr->id) {
594  case id_initiator:
595  rc = ibft_verify_hdr("initiator", hdr, id_initiator,
596  sizeof(*ibft_kobj->initiator));
597  if (rc)
598  break;
599 
600  boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
601  ibft_kobj,
602  ibft_attr_show_initiator,
603  ibft_check_initiator_for,
604  ibft_kobj_release);
605  if (!boot_kobj) {
606  rc = -ENOMEM;
607  goto free_ibft_obj;
608  }
609  break;
610  case id_nic:
611  rc = ibft_verify_hdr("ethernet", hdr, id_nic,
612  sizeof(*ibft_kobj->nic));
613  if (rc)
614  break;
615 
616  boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
617  ibft_kobj,
618  ibft_attr_show_nic,
619  ibft_check_nic_for,
620  ibft_kobj_release);
621  if (!boot_kobj) {
622  rc = -ENOMEM;
623  goto free_ibft_obj;
624  }
625  break;
626  case id_target:
627  rc = ibft_verify_hdr("target", hdr, id_target,
628  sizeof(*ibft_kobj->tgt));
629  if (rc)
630  break;
631 
632  boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
633  ibft_kobj,
634  ibft_attr_show_target,
635  ibft_check_tgt_for,
636  ibft_kobj_release);
637  if (!boot_kobj) {
638  rc = -ENOMEM;
639  goto free_ibft_obj;
640  }
641  break;
642  case id_reserved:
643  case id_control:
644  case id_extensions:
645  /* Fields which we don't support. Ignore them */
646  rc = 1;
647  break;
648  default:
649  printk(KERN_ERR "iBFT has unknown structure type (%d). " \
650  "Report this bug to %.6s!\n", hdr->id,
651  header->header.oem_id);
652  rc = 1;
653  break;
654  }
655 
656  if (rc) {
657  /* Skip adding this kobject, but exit with non-fatal error. */
658  rc = 0;
659  goto free_ibft_obj;
660  }
661 
662  if (hdr->id == id_nic) {
663  /*
664  * We don't search for the device in other domains than
665  * zero. This is because on x86 platforms the BIOS
666  * executes only devices which are in domain 0. Furthermore, the
667  * iBFT spec doesn't have a domain id field :-(
668  */
669  pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8,
670  (nic->pci_bdf & 0xff));
671  if (pci_dev) {
672  rc = sysfs_create_link(&boot_kobj->kobj,
673  &pci_dev->dev.kobj, "device");
674  pci_dev_put(pci_dev);
675  }
676  }
677  return 0;
678 
679 free_ibft_obj:
680  kfree(ibft_kobj);
681  return rc;
682 }
683 
684 /*
685  * Scan the IBFT table structure for the NIC and Target fields. When
686  * found add them on the passed-in list. We do not support the other
687  * fields at this point, so they are skipped.
688  */
689 static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
690 {
691  struct ibft_control *control = NULL;
692  void *ptr, *end;
693  int rc = 0;
694  u16 offset;
695  u16 eot_offset;
696 
697  control = (void *)header + sizeof(*header);
698  end = (void *)control + control->hdr.length;
699  eot_offset = (void *)header + header->header.length - (void *)control;
700  rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
701  sizeof(*control));
702 
703  /* iBFT table safety checking */
704  rc |= ((control->hdr.index) ? -ENODEV : 0);
705  if (rc) {
706  printk(KERN_ERR "iBFT error: Control header is invalid!\n");
707  return rc;
708  }
709  for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) {
710  offset = *(u16 *)ptr;
711  if (offset && offset < header->header.length &&
712  offset < eot_offset) {
713  rc = ibft_create_kobject(header,
714  (void *)header + offset);
715  if (rc)
716  break;
717  }
718  }
719 
720  return rc;
721 }
722 
723 static void ibft_unregister(void)
724 {
725  struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
726  struct ibft_kobject *ibft_kobj;
727 
728  list_for_each_entry_safe(boot_kobj, tmp_kobj,
729  &boot_kset->kobj_list, list) {
730  ibft_kobj = boot_kobj->data;
731  if (ibft_kobj->hdr->id == id_nic)
732  sysfs_remove_link(&boot_kobj->kobj, "device");
733  };
734 }
735 
736 static void ibft_cleanup(void)
737 {
738  if (boot_kset) {
739  ibft_unregister();
740  iscsi_boot_destroy_kset(boot_kset);
741  }
742 }
743 
744 static void __exit ibft_exit(void)
745 {
746  ibft_cleanup();
747 }
748 
749 #ifdef CONFIG_ACPI
750 static const struct {
751  char *sign;
752 } ibft_signs[] = {
753  /*
754  * One spec says "IBFT", the other says "iBFT". We have to check
755  * for both.
756  */
757  { ACPI_SIG_IBFT },
758  { "iBFT" },
759 };
760 
761 static void __init acpi_find_ibft_region(void)
762 {
763  int i;
764  struct acpi_table_header *table = NULL;
765 
766  if (acpi_disabled)
767  return;
768 
769  for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) {
770  acpi_get_table(ibft_signs[i].sign, 0, &table);
771  ibft_addr = (struct acpi_table_ibft *)table;
772  }
773 }
774 #else
775 static void __init acpi_find_ibft_region(void)
776 {
777 }
778 #endif
779 
780 /*
781  * ibft_init() - creates sysfs tree entries for the iBFT data.
782  */
783 static int __init ibft_init(void)
784 {
785  int rc = 0;
786 
787  /*
788  As on UEFI systems the setup_arch()/find_ibft_region()
789  is called before ACPI tables are parsed and it only does
790  legacy finding.
791  */
792  if (!ibft_addr)
793  acpi_find_ibft_region();
794 
795  if (ibft_addr) {
796  pr_info("iBFT detected.\n");
797 
798  rc = ibft_check_device();
799  if (rc)
800  return rc;
801 
802  boot_kset = iscsi_boot_create_kset("ibft");
803  if (!boot_kset)
804  return -ENOMEM;
805 
806  /* Scan the IBFT for data and register the kobjects. */
807  rc = ibft_register_kobjects(ibft_addr);
808  if (rc)
809  goto out_free;
810  } else
811  printk(KERN_INFO "No iBFT detected.\n");
812 
813  return 0;
814 
815 out_free:
816  ibft_cleanup();
817  return rc;
818 }
819 
820 module_init(ibft_init);
821 module_exit(ibft_exit);