Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/iscsi_ibft.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright 2007-2010 Red Hat, Inc.
4
* by Peter Jones <[email protected]>
5
* Copyright 2008 IBM, Inc.
6
* by Konrad Rzeszutek <[email protected]>
7
* Copyright 2008
8
* by Konrad Rzeszutek <[email protected]>
9
*
10
* This code exposes the iSCSI Boot Format Table to userland via sysfs.
11
*
12
* Changelog:
13
*
14
* 06 Jan 2010 - Peter Jones <[email protected]>
15
* New changelog entries are in the git log from now on. Not here.
16
*
17
* 14 Mar 2008 - Konrad Rzeszutek <[email protected]>
18
* Updated comments and copyrights. (v0.4.9)
19
*
20
* 11 Feb 2008 - Konrad Rzeszutek <[email protected]>
21
* Converted to using ibft_addr. (v0.4.8)
22
*
23
* 8 Feb 2008 - Konrad Rzeszutek <[email protected]>
24
* Combined two functions in one: reserve_ibft_region. (v0.4.7)
25
*
26
* 30 Jan 2008 - Konrad Rzeszutek <[email protected]>
27
* Added logic to handle IPv6 addresses. (v0.4.6)
28
*
29
* 25 Jan 2008 - Konrad Rzeszutek <[email protected]>
30
* Added logic to handle badly not-to-spec iBFT. (v0.4.5)
31
*
32
* 4 Jan 2008 - Konrad Rzeszutek <[email protected]>
33
* Added __init to function declarations. (v0.4.4)
34
*
35
* 21 Dec 2007 - Konrad Rzeszutek <[email protected]>
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 <[email protected]>
40
* Added end-markers to enums and re-organized kobject registration. (v0.4.2)
41
*
42
* 4 Dec 2007 - Konrad Rzeszutek <[email protected]>
43
* Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1)
44
*
45
* 28 Nov 2007 - Konrad Rzeszutek <[email protected]>
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 <[email protected]>
50
* Added text attributes emulating OpenFirmware /proc/device-tree naming.
51
* Removed binary /sysfs interface (v0.3)
52
*
53
* 29 Aug 2007 - Konrad Rzeszutek <[email protected]>
54
* Added functionality in setup.c to reserve iBFT region. (v0.2)
55
*
56
* 27 Aug 2007 - Konrad Rzeszutek <[email protected]>
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 <[email protected]> and "
82
"Konrad Rzeszutek <[email protected]>");
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
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
*/
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
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
*/
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
*/
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
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
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
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
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
*/
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
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
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
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
620
static void ibft_kobj_release(void *data)
621
{
622
kfree(data);
623
}
624
625
/*
626
* Helper function for ibft_register_kobjects.
627
*/
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
*/
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
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
809
static void ibft_cleanup(void)
810
{
811
if (boot_kset) {
812
ibft_unregister();
813
iscsi_boot_destroy_kset(boot_kset);
814
}
815
}
816
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
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
849
static void __init acpi_find_ibft_region(void)
850
{
851
}
852
#endif
853
#ifdef CONFIG_ISCSI_IBFT_FIND
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
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
*/
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
911