aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 14:25:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 14:25:58 -0400
commit5abd9ccced7a726c817dd6b5b96bc933859138d1 (patch)
tree52b4612b5fb54f00364eadf39e0155209498e5d9 /drivers/firmware
parentd5fc1d517543857ea117fc57f23b394aa9784f06 (diff)
parent57a5f3c99c99f70f8fdfa0bbc83b98c48f56551a (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/ibft-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/ibft-2.6: ibft: Use IBFT_SIGN instead of open-coding the search string. ibft: convert iscsi_ibft module to iscsi boot lib ibft: separate ibft parsing from sysfs interface ibft: For UEFI machines actually do scan ACPI for iBFT. ibft: Update iBFT handling for v1.03 of the spec.
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/iscsi_boot_sysfs.c481
-rw-r--r--drivers/firmware/iscsi_ibft.c726
-rw-r--r--drivers/firmware/iscsi_ibft_find.c56
5 files changed, 799 insertions, 474 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1b03ba1d0834..a6c670b8ce52 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -122,8 +122,17 @@ config ISCSI_IBFT_FIND
122 is necessary for iSCSI Boot Firmware Table Attributes module to work 122 is necessary for iSCSI Boot Firmware Table Attributes module to work
123 properly. 123 properly.
124 124
125config ISCSI_BOOT_SYSFS
126 tristate "iSCSI Boot Sysfs Interface"
127 default n
128 help
129 This option enables support for exposing iSCSI boot information
130 via sysfs to userspace. If you wish to export this information,
131 say Y. Otherwise, say N.
132
125config ISCSI_IBFT 133config ISCSI_IBFT
126 tristate "iSCSI Boot Firmware Table Attributes module" 134 tristate "iSCSI Boot Firmware Table Attributes module"
135 select ISCSI_BOOT_SYSFS
127 depends on ISCSI_IBFT_FIND 136 depends on ISCSI_IBFT_FIND
128 default n 137 default n
129 help 138 help
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 1c3c17343dbe..5fe7e1662922 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,4 +10,5 @@ obj-$(CONFIG_DCDBAS) += dcdbas.o
10obj-$(CONFIG_DMIID) += dmi-id.o 10obj-$(CONFIG_DMIID) += dmi-id.o
11obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o 11obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
12obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o 12obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
13obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
13obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o 14obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
diff --git a/drivers/firmware/iscsi_boot_sysfs.c b/drivers/firmware/iscsi_boot_sysfs.c
new file mode 100644
index 000000000000..df6bff7366cf
--- /dev/null
+++ b/drivers/firmware/iscsi_boot_sysfs.c
@@ -0,0 +1,481 @@
1/*
2 * Export the iSCSI boot info to userland via sysfs.
3 *
4 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2010 Mike Christie
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License v2.0 as published by
9 * the Free Software Foundation
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/module.h>
18#include <linux/string.h>
19#include <linux/slab.h>
20#include <linux/sysfs.h>
21#include <linux/capability.h>
22#include <linux/iscsi_boot_sysfs.h>
23
24
25MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>");
26MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information");
27MODULE_LICENSE("GPL");
28/*
29 * The kobject and attribute structures.
30 */
31struct iscsi_boot_attr {
32 struct attribute attr;
33 int type;
34 ssize_t (*show) (void *data, int type, char *buf);
35};
36
37/*
38 * The routine called for all sysfs attributes.
39 */
40static ssize_t iscsi_boot_show_attribute(struct kobject *kobj,
41 struct attribute *attr, char *buf)
42{
43 struct iscsi_boot_kobj *boot_kobj =
44 container_of(kobj, struct iscsi_boot_kobj, kobj);
45 struct iscsi_boot_attr *boot_attr =
46 container_of(attr, struct iscsi_boot_attr, attr);
47 ssize_t ret = -EIO;
48 char *str = buf;
49
50 if (!capable(CAP_SYS_ADMIN))
51 return -EACCES;
52
53 if (boot_kobj->show)
54 ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str);
55 return ret;
56}
57
58static const struct sysfs_ops iscsi_boot_attr_ops = {
59 .show = iscsi_boot_show_attribute,
60};
61
62static void iscsi_boot_kobj_release(struct kobject *kobj)
63{
64 struct iscsi_boot_kobj *boot_kobj =
65 container_of(kobj, struct iscsi_boot_kobj, kobj);
66
67 kfree(boot_kobj->data);
68 kfree(boot_kobj);
69}
70
71static struct kobj_type iscsi_boot_ktype = {
72 .release = iscsi_boot_kobj_release,
73 .sysfs_ops = &iscsi_boot_attr_ops,
74};
75
76#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \
77static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \
78 .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \
79 .type = attr_type, \
80}
81
82/* Target attrs */
83iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
84iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
85iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
86iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
87iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
88iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
89iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
90iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
91iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
92iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
93iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
94 ISCSI_BOOT_TGT_REV_CHAP_NAME);
95iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
96 ISCSI_BOOT_TGT_REV_CHAP_SECRET);
97
98static struct attribute *target_attrs[] = {
99 &iscsi_boot_attr_tgt_index.attr,
100 &iscsi_boot_attr_tgt_flags.attr,
101 &iscsi_boot_attr_tgt_ip.attr,
102 &iscsi_boot_attr_tgt_port.attr,
103 &iscsi_boot_attr_tgt_lun.attr,
104 &iscsi_boot_attr_tgt_chap.attr,
105 &iscsi_boot_attr_tgt_nic.attr,
106 &iscsi_boot_attr_tgt_name.attr,
107 &iscsi_boot_attr_tgt_chap_name.attr,
108 &iscsi_boot_attr_tgt_chap_secret.attr,
109 &iscsi_boot_attr_tgt_chap_rev_name.attr,
110 &iscsi_boot_attr_tgt_chap_rev_secret.attr,
111 NULL
112};
113
114static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
115 struct attribute *attr, int i)
116{
117 struct iscsi_boot_kobj *boot_kobj =
118 container_of(kobj, struct iscsi_boot_kobj, kobj);
119
120 if (attr == &iscsi_boot_attr_tgt_index.attr)
121 return boot_kobj->is_visible(boot_kobj->data,
122 ISCSI_BOOT_TGT_INDEX);
123 else if (attr == &iscsi_boot_attr_tgt_flags.attr)
124 return boot_kobj->is_visible(boot_kobj->data,
125 ISCSI_BOOT_TGT_FLAGS);
126 else if (attr == &iscsi_boot_attr_tgt_ip.attr)
127 return boot_kobj->is_visible(boot_kobj->data,
128 ISCSI_BOOT_TGT_IP_ADDR);
129 else if (attr == &iscsi_boot_attr_tgt_port.attr)
130 return boot_kobj->is_visible(boot_kobj->data,
131 ISCSI_BOOT_TGT_PORT);
132 else if (attr == &iscsi_boot_attr_tgt_lun.attr)
133 return boot_kobj->is_visible(boot_kobj->data,
134 ISCSI_BOOT_TGT_LUN);
135 else if (attr == &iscsi_boot_attr_tgt_chap.attr)
136 return boot_kobj->is_visible(boot_kobj->data,
137 ISCSI_BOOT_TGT_CHAP_TYPE);
138 else if (attr == &iscsi_boot_attr_tgt_nic.attr)
139 return boot_kobj->is_visible(boot_kobj->data,
140 ISCSI_BOOT_TGT_NIC_ASSOC);
141 else if (attr == &iscsi_boot_attr_tgt_name.attr)
142 return boot_kobj->is_visible(boot_kobj->data,
143 ISCSI_BOOT_TGT_NAME);
144 else if (attr == &iscsi_boot_attr_tgt_chap_name.attr)
145 return boot_kobj->is_visible(boot_kobj->data,
146 ISCSI_BOOT_TGT_CHAP_NAME);
147 else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr)
148 return boot_kobj->is_visible(boot_kobj->data,
149 ISCSI_BOOT_TGT_CHAP_SECRET);
150 else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr)
151 return boot_kobj->is_visible(boot_kobj->data,
152 ISCSI_BOOT_TGT_REV_CHAP_NAME);
153 else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr)
154 return boot_kobj->is_visible(boot_kobj->data,
155 ISCSI_BOOT_TGT_REV_CHAP_SECRET);
156 return 0;
157}
158
159static struct attribute_group iscsi_boot_target_attr_group = {
160 .attrs = target_attrs,
161 .is_visible = iscsi_boot_tgt_attr_is_visible,
162};
163
164/* Ethernet attrs */
165iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
166iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
167iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
168iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
169iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
170iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
171iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
172iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
173 ISCSI_BOOT_ETH_SECONDARY_DNS);
174iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
175iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
176iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
177iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
178
179static struct attribute *ethernet_attrs[] = {
180 &iscsi_boot_attr_eth_index.attr,
181 &iscsi_boot_attr_eth_flags.attr,
182 &iscsi_boot_attr_eth_ip.attr,
183 &iscsi_boot_attr_eth_subnet.attr,
184 &iscsi_boot_attr_eth_origin.attr,
185 &iscsi_boot_attr_eth_gateway.attr,
186 &iscsi_boot_attr_eth_primary_dns.attr,
187 &iscsi_boot_attr_eth_secondary_dns.attr,
188 &iscsi_boot_attr_eth_dhcp.attr,
189 &iscsi_boot_attr_eth_vlan.attr,
190 &iscsi_boot_attr_eth_mac.attr,
191 &iscsi_boot_attr_eth_hostname.attr,
192 NULL
193};
194
195static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
196 struct attribute *attr, int i)
197{
198 struct iscsi_boot_kobj *boot_kobj =
199 container_of(kobj, struct iscsi_boot_kobj, kobj);
200
201 if (attr == &iscsi_boot_attr_eth_index.attr)
202 return boot_kobj->is_visible(boot_kobj->data,
203 ISCSI_BOOT_ETH_INDEX);
204 else if (attr == &iscsi_boot_attr_eth_flags.attr)
205 return boot_kobj->is_visible(boot_kobj->data,
206 ISCSI_BOOT_ETH_FLAGS);
207 else if (attr == &iscsi_boot_attr_eth_ip.attr)
208 return boot_kobj->is_visible(boot_kobj->data,
209 ISCSI_BOOT_ETH_IP_ADDR);
210 else if (attr == &iscsi_boot_attr_eth_subnet.attr)
211 return boot_kobj->is_visible(boot_kobj->data,
212 ISCSI_BOOT_ETH_SUBNET_MASK);
213 else if (attr == &iscsi_boot_attr_eth_origin.attr)
214 return boot_kobj->is_visible(boot_kobj->data,
215 ISCSI_BOOT_ETH_ORIGIN);
216 else if (attr == &iscsi_boot_attr_eth_gateway.attr)
217 return boot_kobj->is_visible(boot_kobj->data,
218 ISCSI_BOOT_ETH_GATEWAY);
219 else if (attr == &iscsi_boot_attr_eth_primary_dns.attr)
220 return boot_kobj->is_visible(boot_kobj->data,
221 ISCSI_BOOT_ETH_PRIMARY_DNS);
222 else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr)
223 return boot_kobj->is_visible(boot_kobj->data,
224 ISCSI_BOOT_ETH_SECONDARY_DNS);
225 else if (attr == &iscsi_boot_attr_eth_dhcp.attr)
226 return boot_kobj->is_visible(boot_kobj->data,
227 ISCSI_BOOT_ETH_DHCP);
228 else if (attr == &iscsi_boot_attr_eth_vlan.attr)
229 return boot_kobj->is_visible(boot_kobj->data,
230 ISCSI_BOOT_ETH_VLAN);
231 else if (attr == &iscsi_boot_attr_eth_mac.attr)
232 return boot_kobj->is_visible(boot_kobj->data,
233 ISCSI_BOOT_ETH_MAC);
234 else if (attr == &iscsi_boot_attr_eth_hostname.attr)
235 return boot_kobj->is_visible(boot_kobj->data,
236 ISCSI_BOOT_ETH_HOSTNAME);
237 return 0;
238}
239
240static struct attribute_group iscsi_boot_ethernet_attr_group = {
241 .attrs = ethernet_attrs,
242 .is_visible = iscsi_boot_eth_attr_is_visible,
243};
244
245/* Initiator attrs */
246iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
247iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
248iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
249iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
250iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
251 ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
252iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
253 ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
254iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
255
256static struct attribute *initiator_attrs[] = {
257 &iscsi_boot_attr_ini_index.attr,
258 &iscsi_boot_attr_ini_flags.attr,
259 &iscsi_boot_attr_ini_isns.attr,
260 &iscsi_boot_attr_ini_slp.attr,
261 &iscsi_boot_attr_ini_primary_radius.attr,
262 &iscsi_boot_attr_ini_secondary_radius.attr,
263 &iscsi_boot_attr_ini_name.attr,
264 NULL
265};
266
267static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
268 struct attribute *attr, int i)
269{
270 struct iscsi_boot_kobj *boot_kobj =
271 container_of(kobj, struct iscsi_boot_kobj, kobj);
272
273 if (attr == &iscsi_boot_attr_ini_index.attr)
274 return boot_kobj->is_visible(boot_kobj->data,
275 ISCSI_BOOT_INI_INDEX);
276 if (attr == &iscsi_boot_attr_ini_flags.attr)
277 return boot_kobj->is_visible(boot_kobj->data,
278 ISCSI_BOOT_INI_FLAGS);
279 if (attr == &iscsi_boot_attr_ini_isns.attr)
280 return boot_kobj->is_visible(boot_kobj->data,
281 ISCSI_BOOT_INI_ISNS_SERVER);
282 if (attr == &iscsi_boot_attr_ini_slp.attr)
283 return boot_kobj->is_visible(boot_kobj->data,
284 ISCSI_BOOT_INI_SLP_SERVER);
285 if (attr == &iscsi_boot_attr_ini_primary_radius.attr)
286 return boot_kobj->is_visible(boot_kobj->data,
287 ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
288 if (attr == &iscsi_boot_attr_ini_secondary_radius.attr)
289 return boot_kobj->is_visible(boot_kobj->data,
290 ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
291 if (attr == &iscsi_boot_attr_ini_name.attr)
292 return boot_kobj->is_visible(boot_kobj->data,
293 ISCSI_BOOT_INI_INITIATOR_NAME);
294
295 return 0;
296}
297
298static struct attribute_group iscsi_boot_initiator_attr_group = {
299 .attrs = initiator_attrs,
300 .is_visible = iscsi_boot_ini_attr_is_visible,
301};
302
303static struct iscsi_boot_kobj *
304iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset,
305 struct attribute_group *attr_group,
306 const char *name, int index, void *data,
307 ssize_t (*show) (void *data, int type, char *buf),
308 mode_t (*is_visible) (void *data, int type))
309{
310 struct iscsi_boot_kobj *boot_kobj;
311
312 boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL);
313 if (!boot_kobj)
314 return NULL;
315 INIT_LIST_HEAD(&boot_kobj->list);
316
317 boot_kobj->kobj.kset = boot_kset->kset;
318 if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
319 NULL, name, index)) {
320 kfree(boot_kobj);
321 return NULL;
322 }
323 boot_kobj->data = data;
324 boot_kobj->show = show;
325 boot_kobj->is_visible = is_visible;
326
327 if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
328 /*
329 * We do not want to free this because the caller
330 * will assume that since the creation call failed
331 * the boot kobj was not setup and the normal release
332 * path is not being run.
333 */
334 boot_kobj->data = NULL;
335 kobject_put(&boot_kobj->kobj);
336 return NULL;
337 }
338 boot_kobj->attr_group = attr_group;
339
340 kobject_uevent(&boot_kobj->kobj, KOBJ_ADD);
341 /* Nothing broke so lets add it to the list. */
342 list_add_tail(&boot_kobj->list, &boot_kset->kobj_list);
343 return boot_kobj;
344}
345
346static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj)
347{
348 list_del(&boot_kobj->list);
349 sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group);
350 kobject_put(&boot_kobj->kobj);
351}
352
353/**
354 * iscsi_boot_create_target() - create boot target sysfs dir
355 * @boot_kset: boot kset
356 * @index: the target id
357 * @data: driver specific data for target
358 * @show: attr show function
359 * @is_visible: attr visibility function
360 *
361 * Note: The boot sysfs lib will free the data passed in for the caller
362 * when all refs to the target kobject have been released.
363 */
364struct iscsi_boot_kobj *
365iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
366 void *data,
367 ssize_t (*show) (void *data, int type, char *buf),
368 mode_t (*is_visible) (void *data, int type))
369{
370 return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
371 "target%d", index, data, show, is_visible);
372}
373EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
374
375/**
376 * iscsi_boot_create_initiator() - create boot initiator sysfs dir
377 * @boot_kset: boot kset
378 * @index: the initiator id
379 * @data: driver specific data
380 * @show: attr show function
381 * @is_visible: attr visibility function
382 *
383 * Note: The boot sysfs lib will free the data passed in for the caller
384 * when all refs to the initiator kobject have been released.
385 */
386struct iscsi_boot_kobj *
387iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
388 void *data,
389 ssize_t (*show) (void *data, int type, char *buf),
390 mode_t (*is_visible) (void *data, int type))
391{
392 return iscsi_boot_create_kobj(boot_kset,
393 &iscsi_boot_initiator_attr_group,
394 "initiator", index, data, show,
395 is_visible);
396}
397EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
398
399/**
400 * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir
401 * @boot_kset: boot kset
402 * @index: the ethernet device id
403 * @data: driver specific data
404 * @show: attr show function
405 * @is_visible: attr visibility function
406 *
407 * Note: The boot sysfs lib will free the data passed in for the caller
408 * when all refs to the ethernet kobject have been released.
409 */
410struct iscsi_boot_kobj *
411iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
412 void *data,
413 ssize_t (*show) (void *data, int type, char *buf),
414 mode_t (*is_visible) (void *data, int type))
415{
416 return iscsi_boot_create_kobj(boot_kset,
417 &iscsi_boot_ethernet_attr_group,
418 "ethernet%d", index, data, show,
419 is_visible);
420}
421EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
422
423/**
424 * iscsi_boot_create_kset() - creates root sysfs tree
425 * @set_name: name of root dir
426 */
427struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)
428{
429 struct iscsi_boot_kset *boot_kset;
430
431 boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL);
432 if (!boot_kset)
433 return NULL;
434
435 boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj);
436 if (!boot_kset->kset) {
437 kfree(boot_kset);
438 return NULL;
439 }
440
441 INIT_LIST_HEAD(&boot_kset->kobj_list);
442 return boot_kset;
443}
444EXPORT_SYMBOL_GPL(iscsi_boot_create_kset);
445
446/**
447 * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host
448 * @hostno: host number of scsi host
449 */
450struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)
451{
452 struct iscsi_boot_kset *boot_kset;
453 char *set_name;
454
455 set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno);
456 if (!set_name)
457 return NULL;
458
459 boot_kset = iscsi_boot_create_kset(set_name);
460 kfree(set_name);
461 return boot_kset;
462}
463EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset);
464
465/**
466 * iscsi_boot_destroy_kset() - destroy kset and kobjects under it
467 * @boot_kset: boot kset
468 *
469 * This will remove the kset and kobjects and attrs under it.
470 */
471void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
472{
473 struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
474
475 list_for_each_entry_safe(boot_kobj, tmp_kobj,
476 &boot_kset->kobj_list, list)
477 iscsi_boot_remove_kobj(boot_kobj);
478
479 kset_unregister(boot_kset->kset);
480}
481EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index ed2801c378de..4f04ec0410a0 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright 2007 Red Hat, Inc. 2 * Copyright 2007-2010 Red Hat, Inc.
3 * by Peter Jones <pjones@redhat.com> 3 * by Peter Jones <pjones@redhat.com>
4 * Copyright 2008 IBM, Inc. 4 * Copyright 2008 IBM, Inc.
5 * by Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 5 * by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -19,6 +19,9 @@
19 * 19 *
20 * Changelog: 20 * Changelog:
21 * 21 *
22 * 06 Jan 2010 - Peter Jones <pjones@redhat.com>
23 * New changelog entries are in the git log from now on. Not here.
24 *
22 * 14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org> 25 * 14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org>
23 * Updated comments and copyrights. (v0.4.9) 26 * Updated comments and copyrights. (v0.4.9)
24 * 27 *
@@ -78,9 +81,11 @@
78#include <linux/stat.h> 81#include <linux/stat.h>
79#include <linux/string.h> 82#include <linux/string.h>
80#include <linux/types.h> 83#include <linux/types.h>
84#include <linux/acpi.h>
85#include <linux/iscsi_boot_sysfs.h>
81 86
82#define IBFT_ISCSI_VERSION "0.4.9" 87#define IBFT_ISCSI_VERSION "0.5.0"
83#define IBFT_ISCSI_DATE "2008-Mar-14" 88#define IBFT_ISCSI_DATE "2010-Feb-25"
84 89
85MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and \ 90MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and \
86Konrad Rzeszutek <ketuzsezr@darnok.org>"); 91Konrad Rzeszutek <ketuzsezr@darnok.org>");
@@ -166,108 +171,20 @@ enum ibft_id {
166}; 171};
167 172
168/* 173/*
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. 174 * The kobject and attribute structures.
238 */ 175 */
239 176
240struct ibft_kobject { 177struct ibft_kobject {
241 struct ibft_table_header *header; 178 struct acpi_table_ibft *header;
242 union { 179 union {
243 struct ibft_initiator *initiator; 180 struct ibft_initiator *initiator;
244 struct ibft_nic *nic; 181 struct ibft_nic *nic;
245 struct ibft_tgt *tgt; 182 struct ibft_tgt *tgt;
246 struct ibft_hdr *hdr; 183 struct ibft_hdr *hdr;
247 }; 184 };
248 struct kobject kobj;
249 struct list_head node;
250}; 185};
251 186
252struct ibft_attribute { 187static struct iscsi_boot_kset *boot_kset;
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 188
272static const char nulls[16]; 189static const char nulls[16];
273 190
@@ -306,35 +223,27 @@ static ssize_t sprintf_string(char *str, int len, char *buf)
306static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length) 223static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
307{ 224{
308 if (hdr->id != id) { 225 if (hdr->id != id) {
309 printk(KERN_ERR "iBFT error: We expected the " \ 226 printk(KERN_ERR "iBFT error: We expected the %s " \
310 "field header.id to have %d but " \ 227 "field header.id to have %d but " \
311 "found %d instead!\n", id, hdr->id); 228 "found %d instead!\n", t, id, hdr->id);
312 return -ENODEV; 229 return -ENODEV;
313 } 230 }
314 if (hdr->length != length) { 231 if (hdr->length != length) {
315 printk(KERN_ERR "iBFT error: We expected the " \ 232 printk(KERN_ERR "iBFT error: We expected the %s " \
316 "field header.length to have %d but " \ 233 "field header.length to have %d but " \
317 "found %d instead!\n", length, hdr->length); 234 "found %d instead!\n", t, length, hdr->length);
318 return -ENODEV; 235 return -ENODEV;
319 } 236 }
320 237
321 return 0; 238 return 0;
322} 239}
323 240
324static void ibft_release(struct kobject *kobj)
325{
326 struct ibft_kobject *ibft =
327 container_of(kobj, struct ibft_kobject, kobj);
328 kfree(ibft);
329}
330
331/* 241/*
332 * Routines for parsing the iBFT data to be human readable. 242 * Routines for parsing the iBFT data to be human readable.
333 */ 243 */
334static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry, 244static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
335 struct ibft_attribute *attr,
336 char *buf)
337{ 245{
246 struct ibft_kobject *entry = data;
338 struct ibft_initiator *initiator = entry->initiator; 247 struct ibft_initiator *initiator = entry->initiator;
339 void *ibft_loc = entry->header; 248 void *ibft_loc = entry->header;
340 char *str = buf; 249 char *str = buf;
@@ -342,26 +251,26 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
342 if (!initiator) 251 if (!initiator)
343 return 0; 252 return 0;
344 253
345 switch (attr->type) { 254 switch (type) {
346 case ibft_init_index: 255 case ISCSI_BOOT_INI_INDEX:
347 str += sprintf(str, "%d\n", initiator->hdr.index); 256 str += sprintf(str, "%d\n", initiator->hdr.index);
348 break; 257 break;
349 case ibft_init_flags: 258 case ISCSI_BOOT_INI_FLAGS:
350 str += sprintf(str, "%d\n", initiator->hdr.flags); 259 str += sprintf(str, "%d\n", initiator->hdr.flags);
351 break; 260 break;
352 case ibft_init_isns_server: 261 case ISCSI_BOOT_INI_ISNS_SERVER:
353 str += sprintf_ipaddr(str, initiator->isns_server); 262 str += sprintf_ipaddr(str, initiator->isns_server);
354 break; 263 break;
355 case ibft_init_slp_server: 264 case ISCSI_BOOT_INI_SLP_SERVER:
356 str += sprintf_ipaddr(str, initiator->slp_server); 265 str += sprintf_ipaddr(str, initiator->slp_server);
357 break; 266 break;
358 case ibft_init_pri_radius_server: 267 case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
359 str += sprintf_ipaddr(str, initiator->pri_radius_server); 268 str += sprintf_ipaddr(str, initiator->pri_radius_server);
360 break; 269 break;
361 case ibft_init_sec_radius_server: 270 case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
362 str += sprintf_ipaddr(str, initiator->sec_radius_server); 271 str += sprintf_ipaddr(str, initiator->sec_radius_server);
363 break; 272 break;
364 case ibft_init_initiator_name: 273 case ISCSI_BOOT_INI_INITIATOR_NAME:
365 str += sprintf_string(str, initiator->initiator_name_len, 274 str += sprintf_string(str, initiator->initiator_name_len,
366 (char *)ibft_loc + 275 (char *)ibft_loc +
367 initiator->initiator_name_off); 276 initiator->initiator_name_off);
@@ -373,10 +282,9 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
373 return str - buf; 282 return str - buf;
374} 283}
375 284
376static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, 285static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
377 struct ibft_attribute *attr,
378 char *buf)
379{ 286{
287 struct ibft_kobject *entry = data;
380 struct ibft_nic *nic = entry->nic; 288 struct ibft_nic *nic = entry->nic;
381 void *ibft_loc = entry->header; 289 void *ibft_loc = entry->header;
382 char *str = buf; 290 char *str = buf;
@@ -385,42 +293,42 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
385 if (!nic) 293 if (!nic)
386 return 0; 294 return 0;
387 295
388 switch (attr->type) { 296 switch (type) {
389 case ibft_eth_index: 297 case ISCSI_BOOT_ETH_INDEX:
390 str += sprintf(str, "%d\n", nic->hdr.index); 298 str += sprintf(str, "%d\n", nic->hdr.index);
391 break; 299 break;
392 case ibft_eth_flags: 300 case ISCSI_BOOT_ETH_FLAGS:
393 str += sprintf(str, "%d\n", nic->hdr.flags); 301 str += sprintf(str, "%d\n", nic->hdr.flags);
394 break; 302 break;
395 case ibft_eth_ip_addr: 303 case ISCSI_BOOT_ETH_IP_ADDR:
396 str += sprintf_ipaddr(str, nic->ip_addr); 304 str += sprintf_ipaddr(str, nic->ip_addr);
397 break; 305 break;
398 case ibft_eth_subnet_mask: 306 case ISCSI_BOOT_ETH_SUBNET_MASK:
399 val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1)); 307 val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
400 str += sprintf(str, "%pI4", &val); 308 str += sprintf(str, "%pI4", &val);
401 break; 309 break;
402 case ibft_eth_origin: 310 case ISCSI_BOOT_ETH_ORIGIN:
403 str += sprintf(str, "%d\n", nic->origin); 311 str += sprintf(str, "%d\n", nic->origin);
404 break; 312 break;
405 case ibft_eth_gateway: 313 case ISCSI_BOOT_ETH_GATEWAY:
406 str += sprintf_ipaddr(str, nic->gateway); 314 str += sprintf_ipaddr(str, nic->gateway);
407 break; 315 break;
408 case ibft_eth_primary_dns: 316 case ISCSI_BOOT_ETH_PRIMARY_DNS:
409 str += sprintf_ipaddr(str, nic->primary_dns); 317 str += sprintf_ipaddr(str, nic->primary_dns);
410 break; 318 break;
411 case ibft_eth_secondary_dns: 319 case ISCSI_BOOT_ETH_SECONDARY_DNS:
412 str += sprintf_ipaddr(str, nic->secondary_dns); 320 str += sprintf_ipaddr(str, nic->secondary_dns);
413 break; 321 break;
414 case ibft_eth_dhcp: 322 case ISCSI_BOOT_ETH_DHCP:
415 str += sprintf_ipaddr(str, nic->dhcp); 323 str += sprintf_ipaddr(str, nic->dhcp);
416 break; 324 break;
417 case ibft_eth_vlan: 325 case ISCSI_BOOT_ETH_VLAN:
418 str += sprintf(str, "%d\n", nic->vlan); 326 str += sprintf(str, "%d\n", nic->vlan);
419 break; 327 break;
420 case ibft_eth_mac: 328 case ISCSI_BOOT_ETH_MAC:
421 str += sprintf(str, "%pM\n", nic->mac); 329 str += sprintf(str, "%pM\n", nic->mac);
422 break; 330 break;
423 case ibft_eth_hostname: 331 case ISCSI_BOOT_ETH_HOSTNAME:
424 str += sprintf_string(str, nic->hostname_len, 332 str += sprintf_string(str, nic->hostname_len,
425 (char *)ibft_loc + nic->hostname_off); 333 (char *)ibft_loc + nic->hostname_off);
426 break; 334 break;
@@ -431,10 +339,9 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
431 return str - buf; 339 return str - buf;
432}; 340};
433 341
434static ssize_t ibft_attr_show_target(struct ibft_kobject *entry, 342static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
435 struct ibft_attribute *attr,
436 char *buf)
437{ 343{
344 struct ibft_kobject *entry = data;
438 struct ibft_tgt *tgt = entry->tgt; 345 struct ibft_tgt *tgt = entry->tgt;
439 void *ibft_loc = entry->header; 346 void *ibft_loc = entry->header;
440 char *str = buf; 347 char *str = buf;
@@ -443,48 +350,48 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
443 if (!tgt) 350 if (!tgt)
444 return 0; 351 return 0;
445 352
446 switch (attr->type) { 353 switch (type) {
447 case ibft_tgt_index: 354 case ISCSI_BOOT_TGT_INDEX:
448 str += sprintf(str, "%d\n", tgt->hdr.index); 355 str += sprintf(str, "%d\n", tgt->hdr.index);
449 break; 356 break;
450 case ibft_tgt_flags: 357 case ISCSI_BOOT_TGT_FLAGS:
451 str += sprintf(str, "%d\n", tgt->hdr.flags); 358 str += sprintf(str, "%d\n", tgt->hdr.flags);
452 break; 359 break;
453 case ibft_tgt_ip_addr: 360 case ISCSI_BOOT_TGT_IP_ADDR:
454 str += sprintf_ipaddr(str, tgt->ip_addr); 361 str += sprintf_ipaddr(str, tgt->ip_addr);
455 break; 362 break;
456 case ibft_tgt_port: 363 case ISCSI_BOOT_TGT_PORT:
457 str += sprintf(str, "%d\n", tgt->port); 364 str += sprintf(str, "%d\n", tgt->port);
458 break; 365 break;
459 case ibft_tgt_lun: 366 case ISCSI_BOOT_TGT_LUN:
460 for (i = 0; i < 8; i++) 367 for (i = 0; i < 8; i++)
461 str += sprintf(str, "%x", (u8)tgt->lun[i]); 368 str += sprintf(str, "%x", (u8)tgt->lun[i]);
462 str += sprintf(str, "\n"); 369 str += sprintf(str, "\n");
463 break; 370 break;
464 case ibft_tgt_nic_assoc: 371 case ISCSI_BOOT_TGT_NIC_ASSOC:
465 str += sprintf(str, "%d\n", tgt->nic_assoc); 372 str += sprintf(str, "%d\n", tgt->nic_assoc);
466 break; 373 break;
467 case ibft_tgt_chap_type: 374 case ISCSI_BOOT_TGT_CHAP_TYPE:
468 str += sprintf(str, "%d\n", tgt->chap_type); 375 str += sprintf(str, "%d\n", tgt->chap_type);
469 break; 376 break;
470 case ibft_tgt_name: 377 case ISCSI_BOOT_TGT_NAME:
471 str += sprintf_string(str, tgt->tgt_name_len, 378 str += sprintf_string(str, tgt->tgt_name_len,
472 (char *)ibft_loc + tgt->tgt_name_off); 379 (char *)ibft_loc + tgt->tgt_name_off);
473 break; 380 break;
474 case ibft_tgt_chap_name: 381 case ISCSI_BOOT_TGT_CHAP_NAME:
475 str += sprintf_string(str, tgt->chap_name_len, 382 str += sprintf_string(str, tgt->chap_name_len,
476 (char *)ibft_loc + tgt->chap_name_off); 383 (char *)ibft_loc + tgt->chap_name_off);
477 break; 384 break;
478 case ibft_tgt_chap_secret: 385 case ISCSI_BOOT_TGT_CHAP_SECRET:
479 str += sprintf_string(str, tgt->chap_secret_len, 386 str += sprintf_string(str, tgt->chap_secret_len,
480 (char *)ibft_loc + tgt->chap_secret_off); 387 (char *)ibft_loc + tgt->chap_secret_off);
481 break; 388 break;
482 case ibft_tgt_rev_chap_name: 389 case ISCSI_BOOT_TGT_REV_CHAP_NAME:
483 str += sprintf_string(str, tgt->rev_chap_name_len, 390 str += sprintf_string(str, tgt->rev_chap_name_len,
484 (char *)ibft_loc + 391 (char *)ibft_loc +
485 tgt->rev_chap_name_off); 392 tgt->rev_chap_name_off);
486 break; 393 break;
487 case ibft_tgt_rev_chap_secret: 394 case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
488 str += sprintf_string(str, tgt->rev_chap_secret_len, 395 str += sprintf_string(str, tgt->rev_chap_secret_len,
489 (char *)ibft_loc + 396 (char *)ibft_loc +
490 tgt->rev_chap_secret_off); 397 tgt->rev_chap_secret_off);
@@ -496,52 +403,19 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
496 return str - buf; 403 return str - buf;
497} 404}
498 405
499/*
500 * The routine called for all sysfs attributes.
501 */
502static ssize_t ibft_show_attribute(struct kobject *kobj,
503 struct attribute *attr,
504 char *buf)
505{
506 struct ibft_kobject *dev =
507 container_of(kobj, struct ibft_kobject, kobj);
508 struct ibft_attribute *ibft_attr =
509 container_of(attr, struct ibft_attribute, attr);
510 ssize_t ret = -EIO;
511 char *str = buf;
512
513 if (!capable(CAP_SYS_ADMIN))
514 return -EACCES;
515
516 if (ibft_attr->show)
517 ret = ibft_attr->show(dev, ibft_attr, str);
518
519 return ret;
520}
521
522static const struct sysfs_ops ibft_attr_ops = {
523 .show = ibft_show_attribute,
524};
525
526static struct kobj_type ibft_ktype = {
527 .release = ibft_release,
528 .sysfs_ops = &ibft_attr_ops,
529};
530
531static struct kset *ibft_kset;
532
533static int __init ibft_check_device(void) 406static int __init ibft_check_device(void)
534{ 407{
535 int len; 408 int len;
536 u8 *pos; 409 u8 *pos;
537 u8 csum = 0; 410 u8 csum = 0;
538 411
539 len = ibft_addr->length; 412 len = ibft_addr->header.length;
540 413
541 /* Sanity checking of iBFT. */ 414 /* Sanity checking of iBFT. */
542 if (ibft_addr->revision != 1) { 415 if (ibft_addr->header.revision != 1) {
543 printk(KERN_ERR "iBFT module supports only revision 1, " \ 416 printk(KERN_ERR "iBFT module supports only revision 1, " \
544 "while this is %d.\n", ibft_addr->revision); 417 "while this is %d.\n",
418 ibft_addr->header.revision);
545 return -ENOENT; 419 return -ENOENT;
546 } 420 }
547 for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++) 421 for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
@@ -556,12 +430,149 @@ static int __init ibft_check_device(void)
556} 430}
557 431
558/* 432/*
433 * Helper routiners to check to determine if the entry is valid
434 * in the proper iBFT structure.
435 */
436static mode_t ibft_check_nic_for(void *data, int type)
437{
438 struct ibft_kobject *entry = data;
439 struct ibft_nic *nic = entry->nic;
440 mode_t rc = 0;
441
442 switch (type) {
443 case ISCSI_BOOT_ETH_INDEX:
444 case ISCSI_BOOT_ETH_FLAGS:
445 rc = S_IRUGO;
446 break;
447 case ISCSI_BOOT_ETH_IP_ADDR:
448 if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
449 rc = S_IRUGO;
450 break;
451 case ISCSI_BOOT_ETH_SUBNET_MASK:
452 if (nic->subnet_mask_prefix)
453 rc = S_IRUGO;
454 break;
455 case ISCSI_BOOT_ETH_ORIGIN:
456 rc = S_IRUGO;
457 break;
458 case ISCSI_BOOT_ETH_GATEWAY:
459 if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
460 rc = S_IRUGO;
461 break;
462 case ISCSI_BOOT_ETH_PRIMARY_DNS:
463 if (memcmp(nic->primary_dns, nulls,
464 sizeof(nic->primary_dns)))
465 rc = S_IRUGO;
466 break;
467 case ISCSI_BOOT_ETH_SECONDARY_DNS:
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;
480 case ISCSI_BOOT_ETH_HOSTNAME:
481 if (nic->hostname_off)
482 rc = S_IRUGO;
483 break;
484 default:
485 break;
486 }
487
488 return rc;
489}
490
491static mode_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 mode_t rc = 0;
496
497 switch (type) {
498 case ISCSI_BOOT_TGT_INDEX:
499 case ISCSI_BOOT_TGT_FLAGS:
500 case ISCSI_BOOT_TGT_IP_ADDR:
501 case ISCSI_BOOT_TGT_PORT:
502 case ISCSI_BOOT_TGT_LUN:
503 case ISCSI_BOOT_TGT_NIC_ASSOC:
504 case ISCSI_BOOT_TGT_CHAP_TYPE:
505 rc = S_IRUGO;
506 case ISCSI_BOOT_TGT_NAME:
507 if (tgt->tgt_name_len)
508 rc = S_IRUGO;
509 break;
510 case ISCSI_BOOT_TGT_CHAP_NAME:
511 case ISCSI_BOOT_TGT_CHAP_SECRET:
512 if (tgt->chap_name_len)
513 rc = S_IRUGO;
514 break;
515 case ISCSI_BOOT_TGT_REV_CHAP_NAME:
516 case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
517 if (tgt->rev_chap_name_len)
518 rc = S_IRUGO;
519 break;
520 default:
521 break;
522 }
523
524 return rc;
525}
526
527static mode_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 mode_t rc = 0;
532
533 switch (type) {
534 case ISCSI_BOOT_INI_INDEX:
535 case ISCSI_BOOT_INI_FLAGS:
536 rc = S_IRUGO;
537 break;
538 case ISCSI_BOOT_INI_ISNS_SERVER:
539 if (memcmp(init->isns_server, nulls,
540 sizeof(init->isns_server)))
541 rc = S_IRUGO;
542 break;
543 case ISCSI_BOOT_INI_SLP_SERVER:
544 if (memcmp(init->slp_server, nulls,
545 sizeof(init->slp_server)))
546 rc = S_IRUGO;
547 break;
548 case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
549 if (memcmp(init->pri_radius_server, nulls,
550 sizeof(init->pri_radius_server)))
551 rc = S_IRUGO;
552 break;
553 case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
554 if (memcmp(init->sec_radius_server, nulls,
555 sizeof(init->sec_radius_server)))
556 rc = S_IRUGO;
557 break;
558 case ISCSI_BOOT_INI_INITIATOR_NAME:
559 if (init->initiator_name_len)
560 rc = S_IRUGO;
561 break;
562 default:
563 break;
564 }
565
566 return rc;
567}
568
569/*
559 * Helper function for ibft_register_kobjects. 570 * Helper function for ibft_register_kobjects.
560 */ 571 */
561static int __init ibft_create_kobject(struct ibft_table_header *header, 572static int __init ibft_create_kobject(struct acpi_table_ibft *header,
562 struct ibft_hdr *hdr, 573 struct ibft_hdr *hdr)
563 struct list_head *list)
564{ 574{
575 struct iscsi_boot_kobj *boot_kobj = NULL;
565 struct ibft_kobject *ibft_kobj = NULL; 576 struct ibft_kobject *ibft_kobj = NULL;
566 struct ibft_nic *nic = (struct ibft_nic *)hdr; 577 struct ibft_nic *nic = (struct ibft_nic *)hdr;
567 struct pci_dev *pci_dev; 578 struct pci_dev *pci_dev;
@@ -578,14 +589,47 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
578 case id_initiator: 589 case id_initiator:
579 rc = ibft_verify_hdr("initiator", hdr, id_initiator, 590 rc = ibft_verify_hdr("initiator", hdr, id_initiator,
580 sizeof(*ibft_kobj->initiator)); 591 sizeof(*ibft_kobj->initiator));
592 if (rc)
593 break;
594
595 boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
596 ibft_kobj,
597 ibft_attr_show_initiator,
598 ibft_check_initiator_for);
599 if (!boot_kobj) {
600 rc = -ENOMEM;
601 goto free_ibft_obj;
602 }
581 break; 603 break;
582 case id_nic: 604 case id_nic:
583 rc = ibft_verify_hdr("ethernet", hdr, id_nic, 605 rc = ibft_verify_hdr("ethernet", hdr, id_nic,
584 sizeof(*ibft_kobj->nic)); 606 sizeof(*ibft_kobj->nic));
607 if (rc)
608 break;
609
610 boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
611 ibft_kobj,
612 ibft_attr_show_nic,
613 ibft_check_nic_for);
614 if (!boot_kobj) {
615 rc = -ENOMEM;
616 goto free_ibft_obj;
617 }
585 break; 618 break;
586 case id_target: 619 case id_target:
587 rc = ibft_verify_hdr("target", hdr, id_target, 620 rc = ibft_verify_hdr("target", hdr, id_target,
588 sizeof(*ibft_kobj->tgt)); 621 sizeof(*ibft_kobj->tgt));
622 if (rc)
623 break;
624
625 boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
626 ibft_kobj,
627 ibft_attr_show_target,
628 ibft_check_tgt_for);
629 if (!boot_kobj) {
630 rc = -ENOMEM;
631 goto free_ibft_obj;
632 }
589 break; 633 break;
590 case id_reserved: 634 case id_reserved:
591 case id_control: 635 case id_control:
@@ -596,29 +640,17 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
596 default: 640 default:
597 printk(KERN_ERR "iBFT has unknown structure type (%d). " \ 641 printk(KERN_ERR "iBFT has unknown structure type (%d). " \
598 "Report this bug to %.6s!\n", hdr->id, 642 "Report this bug to %.6s!\n", hdr->id,
599 header->oem_id); 643 header->header.oem_id);
600 rc = 1; 644 rc = 1;
601 break; 645 break;
602 } 646 }
603 647
604 if (rc) { 648 if (rc) {
605 /* Skip adding this kobject, but exit with non-fatal error. */ 649 /* Skip adding this kobject, but exit with non-fatal error. */
606 kfree(ibft_kobj); 650 rc = 0;
607 goto out_invalid_struct; 651 goto free_ibft_obj;
608 } 652 }
609 653
610 ibft_kobj->kobj.kset = ibft_kset;
611
612 rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype,
613 NULL, ibft_id_names[hdr->id], hdr->index);
614
615 if (rc) {
616 kfree(ibft_kobj);
617 goto out;
618 }
619
620 kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD);
621
622 if (hdr->id == id_nic) { 654 if (hdr->id == id_nic) {
623 /* 655 /*
624 * We don't search for the device in other domains than 656 * We don't search for the device in other domains than
@@ -629,19 +661,16 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
629 pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8, 661 pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8,
630 (nic->pci_bdf & 0xff)); 662 (nic->pci_bdf & 0xff));
631 if (pci_dev) { 663 if (pci_dev) {
632 rc = sysfs_create_link(&ibft_kobj->kobj, 664 rc = sysfs_create_link(&boot_kobj->kobj,
633 &pci_dev->dev.kobj, "device"); 665 &pci_dev->dev.kobj, "device");
634 pci_dev_put(pci_dev); 666 pci_dev_put(pci_dev);
635 } 667 }
636 } 668 }
669 return 0;
637 670
638 /* Nothing broke so lets add it to the list. */ 671free_ibft_obj:
639 list_add_tail(&ibft_kobj->node, list); 672 kfree(ibft_kobj);
640out:
641 return rc; 673 return rc;
642out_invalid_struct:
643 /* Unsupported structs are skipped. */
644 return 0;
645} 674}
646 675
647/* 676/*
@@ -649,8 +678,7 @@ out_invalid_struct:
649 * found add them on the passed-in list. We do not support the other 678 * found add them on the passed-in list. We do not support the other
650 * fields at this point, so they are skipped. 679 * fields at this point, so they are skipped.
651 */ 680 */
652static int __init ibft_register_kobjects(struct ibft_table_header *header, 681static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
653 struct list_head *list)
654{ 682{
655 struct ibft_control *control = NULL; 683 struct ibft_control *control = NULL;
656 void *ptr, *end; 684 void *ptr, *end;
@@ -660,7 +688,7 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
660 688
661 control = (void *)header + sizeof(*header); 689 control = (void *)header + sizeof(*header);
662 end = (void *)control + control->hdr.length; 690 end = (void *)control + control->hdr.length;
663 eot_offset = (void *)header + header->length - (void *)control; 691 eot_offset = (void *)header + header->header.length - (void *)control;
664 rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, 692 rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
665 sizeof(*control)); 693 sizeof(*control));
666 694
@@ -672,10 +700,10 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
672 } 700 }
673 for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) { 701 for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) {
674 offset = *(u16 *)ptr; 702 offset = *(u16 *)ptr;
675 if (offset && offset < header->length && offset < eot_offset) { 703 if (offset && offset < header->header.length &&
704 offset < eot_offset) {
676 rc = ibft_create_kobject(header, 705 rc = ibft_create_kobject(header,
677 (void *)header + offset, 706 (void *)header + offset);
678 list);
679 if (rc) 707 if (rc)
680 break; 708 break;
681 } 709 }
@@ -684,240 +712,28 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
684 return rc; 712 return rc;
685} 713}
686 714
687static void ibft_unregister(struct list_head *attr_list, 715static void ibft_unregister(void)
688 struct list_head *kobj_list)
689{ 716{
690 struct ibft_kobject *data = NULL, *n; 717 struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
691 struct ibft_attribute *attr = NULL, *m; 718 struct ibft_kobject *ibft_kobj;
692 719
693 list_for_each_entry_safe(attr, m, attr_list, node) { 720 list_for_each_entry_safe(boot_kobj, tmp_kobj,
694 sysfs_remove_file(attr->kobj, &attr->attr); 721 &boot_kset->kobj_list, list) {
695 list_del(&attr->node); 722 ibft_kobj = boot_kobj->data;
696 kfree(attr); 723 if (ibft_kobj->hdr->id == id_nic)
724 sysfs_remove_link(&boot_kobj->kobj, "device");
697 }; 725 };
698 list_del_init(attr_list);
699
700 list_for_each_entry_safe(data, n, kobj_list, node) {
701 list_del(&data->node);
702 if (data->hdr->id == id_nic)
703 sysfs_remove_link(&data->kobj, "device");
704 kobject_put(&data->kobj);
705 };
706 list_del_init(kobj_list);
707} 726}
708 727
709static int __init ibft_create_attribute(struct ibft_kobject *kobj_data, 728static void ibft_cleanup(void)
710 int type,
711 const char *name,
712 ssize_t (*show)(struct ibft_kobject *,
713 struct ibft_attribute*,
714 char *buf),
715 struct list_head *list)
716{ 729{
717 struct ibft_attribute *attr = NULL; 730 ibft_unregister();
718 struct ibft_hdr *hdr = kobj_data->hdr; 731 iscsi_boot_destroy_kset(boot_kset);
719
720 attr = kmalloc(sizeof(*attr), GFP_KERNEL);
721 if (!attr)
722 return -ENOMEM;
723
724 attr->attr.name = name;
725 attr->attr.mode = S_IRUSR;
726
727 attr->hdr = hdr;
728 attr->show = show;
729 attr->kobj = &kobj_data->kobj;
730 attr->type = type;
731
732 list_add_tail(&attr->node, list);
733
734 return 0;
735}
736
737/*
738 * Helper routiners to check to determine if the entry is valid
739 * in the proper iBFT structure.
740 */
741static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry)
742{
743 int rc = 0;
744
745 switch (entry) {
746 case ibft_eth_index:
747 case ibft_eth_flags:
748 rc = 1;
749 break;
750 case ibft_eth_ip_addr:
751 if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
752 rc = 1;
753 break;
754 case ibft_eth_subnet_mask:
755 if (nic->subnet_mask_prefix)
756 rc = 1;
757 break;
758 case ibft_eth_origin:
759 rc = 1;
760 break;
761 case ibft_eth_gateway:
762 if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
763 rc = 1;
764 break;
765 case ibft_eth_primary_dns:
766 if (memcmp(nic->primary_dns, nulls,
767 sizeof(nic->primary_dns)))
768 rc = 1;
769 break;
770 case ibft_eth_secondary_dns:
771 if (memcmp(nic->secondary_dns, nulls,
772 sizeof(nic->secondary_dns)))
773 rc = 1;
774 break;
775 case ibft_eth_dhcp:
776 if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
777 rc = 1;
778 break;
779 case ibft_eth_vlan:
780 case ibft_eth_mac:
781 rc = 1;
782 break;
783 case ibft_eth_hostname:
784 if (nic->hostname_off)
785 rc = 1;
786 break;
787 default:
788 break;
789 }
790
791 return rc;
792} 732}
793 733
794static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry) 734static void __exit ibft_exit(void)
795{
796 int rc = 0;
797
798 switch (entry) {
799 case ibft_tgt_index:
800 case ibft_tgt_flags:
801 case ibft_tgt_ip_addr:
802 case ibft_tgt_port:
803 case ibft_tgt_lun:
804 case ibft_tgt_nic_assoc:
805 case ibft_tgt_chap_type:
806 rc = 1;
807 case ibft_tgt_name:
808 if (tgt->tgt_name_len)
809 rc = 1;
810 break;
811 case ibft_tgt_chap_name:
812 case ibft_tgt_chap_secret:
813 if (tgt->chap_name_len)
814 rc = 1;
815 break;
816 case ibft_tgt_rev_chap_name:
817 case ibft_tgt_rev_chap_secret:
818 if (tgt->rev_chap_name_len)
819 rc = 1;
820 break;
821 default:
822 break;
823 }
824
825 return rc;
826}
827
828static int __init ibft_check_initiator_for(struct ibft_initiator *init,
829 int entry)
830{
831 int rc = 0;
832
833 switch (entry) {
834 case ibft_init_index:
835 case ibft_init_flags:
836 rc = 1;
837 break;
838 case ibft_init_isns_server:
839 if (memcmp(init->isns_server, nulls,
840 sizeof(init->isns_server)))
841 rc = 1;
842 break;
843 case ibft_init_slp_server:
844 if (memcmp(init->slp_server, nulls,
845 sizeof(init->slp_server)))
846 rc = 1;
847 break;
848 case ibft_init_pri_radius_server:
849 if (memcmp(init->pri_radius_server, nulls,
850 sizeof(init->pri_radius_server)))
851 rc = 1;
852 break;
853 case ibft_init_sec_radius_server:
854 if (memcmp(init->sec_radius_server, nulls,
855 sizeof(init->sec_radius_server)))
856 rc = 1;
857 break;
858 case ibft_init_initiator_name:
859 if (init->initiator_name_len)
860 rc = 1;
861 break;
862 default:
863 break;
864 }
865
866 return rc;
867}
868
869/*
870 * Register the attributes for all of the kobjects.
871 */
872static int __init ibft_register_attributes(struct list_head *kobject_list,
873 struct list_head *attr_list)
874{ 735{
875 int rc = 0, i = 0; 736 ibft_cleanup();
876 struct ibft_kobject *data = NULL;
877 struct ibft_attribute *attr = NULL, *m;
878
879 list_for_each_entry(data, kobject_list, node) {
880 switch (data->hdr->id) {
881 case id_nic:
882 for (i = 0; i < ibft_eth_end_marker && !rc; i++)
883 if (ibft_check_nic_for(data->nic, i))
884 rc = ibft_create_attribute(data, i,
885 ibft_eth_properties[i],
886 ibft_attr_show_nic, attr_list);
887 break;
888 case id_target:
889 for (i = 0; i < ibft_tgt_end_marker && !rc; i++)
890 if (ibft_check_tgt_for(data->tgt, i))
891 rc = ibft_create_attribute(data, i,
892 ibft_tgt_properties[i],
893 ibft_attr_show_target,
894 attr_list);
895 break;
896 case id_initiator:
897 for (i = 0; i < ibft_init_end_marker && !rc; i++)
898 if (ibft_check_initiator_for(
899 data->initiator, i))
900 rc = ibft_create_attribute(data, i,
901 ibft_initiator_properties[i],
902 ibft_attr_show_initiator,
903 attr_list);
904 break;
905 default:
906 break;
907 }
908 if (rc)
909 break;
910 }
911 list_for_each_entry_safe(attr, m, attr_list, node) {
912 rc = sysfs_create_file(attr->kobj, &attr->attr);
913 if (rc) {
914 list_del(&attr->node);
915 kfree(attr);
916 break;
917 }
918 }
919
920 return rc;
921} 737}
922 738
923/* 739/*
@@ -927,26 +743,20 @@ static int __init ibft_init(void)
927{ 743{
928 int rc = 0; 744 int rc = 0;
929 745
930 ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj);
931 if (!ibft_kset)
932 return -ENOMEM;
933
934 if (ibft_addr) { 746 if (ibft_addr) {
935 printk(KERN_INFO "iBFT detected at 0x%llx.\n", 747 printk(KERN_INFO "iBFT detected at 0x%llx.\n",
936 (u64)isa_virt_to_bus(ibft_addr)); 748 (u64)isa_virt_to_bus(ibft_addr));
937 749
938 rc = ibft_check_device(); 750 rc = ibft_check_device();
939 if (rc) 751 if (rc)
940 goto out_firmware_unregister; 752 return rc;
941 753
942 /* Scan the IBFT for data and register the kobjects. */ 754 boot_kset = iscsi_boot_create_kset("ibft");
943 rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list); 755 if (!boot_kset)
944 if (rc) 756 return -ENOMEM;
945 goto out_free;
946 757
947 /* Register the attributes */ 758 /* Scan the IBFT for data and register the kobjects. */
948 rc = ibft_register_attributes(&ibft_kobject_list, 759 rc = ibft_register_kobjects(ibft_addr);
949 &ibft_attr_list);
950 if (rc) 760 if (rc)
951 goto out_free; 761 goto out_free;
952 } else 762 } else
@@ -955,17 +765,9 @@ static int __init ibft_init(void)
955 return 0; 765 return 0;
956 766
957out_free: 767out_free:
958 ibft_unregister(&ibft_attr_list, &ibft_kobject_list); 768 ibft_cleanup();
959out_firmware_unregister:
960 kset_unregister(ibft_kset);
961 return rc; 769 return rc;
962} 770}
963 771
964static void __exit ibft_exit(void)
965{
966 ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
967 kset_unregister(ibft_kset);
968}
969
970module_init(ibft_init); 772module_init(ibft_init);
971module_exit(ibft_exit); 773module_exit(ibft_exit);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index d6470ef36e4a..2192456dfd68 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright 2007 Red Hat, Inc. 2 * Copyright 2007-2010 Red Hat, Inc.
3 * by Peter Jones <pjones@redhat.com> 3 * by Peter Jones <pjones@redhat.com>
4 * Copyright 2007 IBM, Inc. 4 * Copyright 2007 IBM, Inc.
5 * by Konrad Rzeszutek <konradr@linux.vnet.ibm.com> 5 * by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -22,6 +22,7 @@
22#include <linux/blkdev.h> 22#include <linux/blkdev.h>
23#include <linux/ctype.h> 23#include <linux/ctype.h>
24#include <linux/device.h> 24#include <linux/device.h>
25#include <linux/efi.h>
25#include <linux/err.h> 26#include <linux/err.h>
26#include <linux/init.h> 27#include <linux/init.h>
27#include <linux/limits.h> 28#include <linux/limits.h>
@@ -30,13 +31,15 @@
30#include <linux/stat.h> 31#include <linux/stat.h>
31#include <linux/string.h> 32#include <linux/string.h>
32#include <linux/types.h> 33#include <linux/types.h>
34#include <linux/acpi.h>
35#include <linux/iscsi_ibft.h>
33 36
34#include <asm/mmzone.h> 37#include <asm/mmzone.h>
35 38
36/* 39/*
37 * Physical location of iSCSI Boot Format Table. 40 * Physical location of iSCSI Boot Format Table.
38 */ 41 */
39struct ibft_table_header *ibft_addr; 42struct acpi_table_ibft *ibft_addr;
40EXPORT_SYMBOL_GPL(ibft_addr); 43EXPORT_SYMBOL_GPL(ibft_addr);
41 44
42#define IBFT_SIGN "iBFT" 45#define IBFT_SIGN "iBFT"
@@ -46,19 +49,20 @@ EXPORT_SYMBOL_GPL(ibft_addr);
46#define VGA_MEM 0xA0000 /* VGA buffer */ 49#define VGA_MEM 0xA0000 /* VGA buffer */
47#define VGA_SIZE 0x20000 /* 128kB */ 50#define VGA_SIZE 0x20000 /* 128kB */
48 51
52#ifdef CONFIG_ACPI
53static int __init acpi_find_ibft(struct acpi_table_header *header)
54{
55 ibft_addr = (struct acpi_table_ibft *)header;
56 return 0;
57}
58#endif /* CONFIG_ACPI */
49 59
50/* 60static int __init find_ibft_in_mem(void)
51 * Routine used to find the iSCSI Boot Format Table. The logical
52 * kernel address is set in the ibft_addr global variable.
53 */
54unsigned long __init find_ibft_region(unsigned long *sizep)
55{ 61{
56 unsigned long pos; 62 unsigned long pos;
57 unsigned int len = 0; 63 unsigned int len = 0;
58 void *virt; 64 void *virt;
59 65
60 ibft_addr = NULL;
61
62 for (pos = IBFT_START; pos < IBFT_END; pos += 16) { 66 for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
63 /* The table can't be inside the VGA BIOS reserved space, 67 /* The table can't be inside the VGA BIOS reserved space,
64 * so skip that area */ 68 * so skip that area */
@@ -72,14 +76,42 @@ unsigned long __init find_ibft_region(unsigned long *sizep)
72 /* if the length of the table extends past 1M, 76 /* if the length of the table extends past 1M,
73 * the table cannot be valid. */ 77 * the table cannot be valid. */
74 if (pos + len <= (IBFT_END-1)) { 78 if (pos + len <= (IBFT_END-1)) {
75 ibft_addr = (struct ibft_table_header *)virt; 79 ibft_addr = (struct acpi_table_ibft *)virt;
76 break; 80 break;
77 } 81 }
78 } 82 }
79 } 83 }
84 return len;
85}
86/*
87 * Routine used to find the iSCSI Boot Format Table. The logical
88 * kernel address is set in the ibft_addr global variable.
89 */
90unsigned long __init find_ibft_region(unsigned long *sizep)
91{
92
93 ibft_addr = NULL;
94
95#ifdef CONFIG_ACPI
96 /*
97 * One spec says "IBFT", the other says "iBFT". We have to check
98 * for both.
99 */
100 if (!ibft_addr)
101 acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft);
102 if (!ibft_addr)
103 acpi_table_parse(IBFT_SIGN, acpi_find_ibft);
104#endif /* CONFIG_ACPI */
105
106 /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
107 * only use ACPI for this */
108
109 if (!ibft_addr && !efi_enabled)
110 find_ibft_in_mem();
111
80 if (ibft_addr) { 112 if (ibft_addr) {
81 *sizep = PAGE_ALIGN(len); 113 *sizep = PAGE_ALIGN(ibft_addr->header.length);
82 return pos; 114 return (u64)isa_virt_to_bus(ibft_addr);
83 } 115 }
84 116
85 *sizep = 0; 117 *sizep = 0;