aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2010-08-02 13:46:12 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-08-06 11:45:07 -0400
commitaab7a8fd19d0c2f7fcac4d07616899655e326dfe (patch)
tree8fa8652375d20f664f822283ca8ee542421dc2c9 /drivers/scsi
parent787f0bd3376aedb3f9ba9bbf862d85e4b176f9b0 (diff)
[SCSI] iscsi boot: mv iscsi_boot_sysfs to drivers/scsi
iscsi_boot_sysfs does not depend on firmware. Any iscsi driver can use it. This patch moves iscsi_boot_sysfs to the scsi dir, so that it can be used on any arch with any driver. Signed-off-by: Mike Christie <mchristi@redhat.com> Acked-by: Konrad Rzeszutek Wilk <konrad@kernel.org> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/Kconfig8
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/iscsi_boot_sysfs.c481
3 files changed, 490 insertions, 0 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 158284f05732..a479b3b7ea90 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -370,6 +370,14 @@ config ISCSI_TCP
370 370
371 http://open-iscsi.org 371 http://open-iscsi.org
372 372
373config ISCSI_BOOT_SYSFS
374 tristate "iSCSI Boot Sysfs Interface"
375 default n
376 help
377 This option enables support for exposing iSCSI boot information
378 via sysfs to userspace. If you wish to export this information,
379 say Y. Otherwise, say N.
380
373source "drivers/scsi/cxgb3i/Kconfig" 381source "drivers/scsi/cxgb3i/Kconfig"
374source "drivers/scsi/bnx2i/Kconfig" 382source "drivers/scsi/bnx2i/Kconfig"
375source "drivers/scsi/be2iscsi/Kconfig" 383source "drivers/scsi/be2iscsi/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2a3fca2eca6a..2703c6ec5e36 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_FCOE) += fcoe/
42obj-$(CONFIG_FCOE_FNIC) += fnic/ 42obj-$(CONFIG_FCOE_FNIC) += fnic/
43obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o 43obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o
44obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o 44obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
45obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
45obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o 46obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
46obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o 47obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o
47obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o 48obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
new file mode 100644
index 000000000000..df6bff7366cf
--- /dev/null
+++ b/drivers/scsi/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);