Commit | Line | Data |
---|---|---|
ba4ee30c MC |
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 | ||
25 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>"); | |
26 | MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information"); | |
27 | MODULE_LICENSE("GPL"); | |
28 | /* | |
29 | * The kobject and attribute structures. | |
30 | */ | |
31 | struct 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 | */ | |
40 | static 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 | ||
58 | static const struct sysfs_ops iscsi_boot_attr_ops = { | |
59 | .show = iscsi_boot_show_attribute, | |
60 | }; | |
61 | ||
62 | static 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 | ||
f457a46f MC |
67 | if (boot_kobj->release) |
68 | boot_kobj->release(boot_kobj->data); | |
ba4ee30c MC |
69 | kfree(boot_kobj); |
70 | } | |
71 | ||
72 | static struct kobj_type iscsi_boot_ktype = { | |
73 | .release = iscsi_boot_kobj_release, | |
74 | .sysfs_ops = &iscsi_boot_attr_ops, | |
75 | }; | |
76 | ||
77 | #define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ | |
78 | static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ | |
79 | .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ | |
80 | .type = attr_type, \ | |
81 | } | |
82 | ||
83 | /* Target attrs */ | |
84 | iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); | |
85 | iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); | |
86 | iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); | |
87 | iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); | |
88 | iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); | |
89 | iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); | |
90 | iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); | |
91 | iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); | |
92 | iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); | |
93 | iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); | |
94 | iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, | |
95 | ISCSI_BOOT_TGT_REV_CHAP_NAME); | |
96 | iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, | |
97 | ISCSI_BOOT_TGT_REV_CHAP_SECRET); | |
98 | ||
99 | static struct attribute *target_attrs[] = { | |
100 | &iscsi_boot_attr_tgt_index.attr, | |
101 | &iscsi_boot_attr_tgt_flags.attr, | |
102 | &iscsi_boot_attr_tgt_ip.attr, | |
103 | &iscsi_boot_attr_tgt_port.attr, | |
104 | &iscsi_boot_attr_tgt_lun.attr, | |
105 | &iscsi_boot_attr_tgt_chap.attr, | |
106 | &iscsi_boot_attr_tgt_nic.attr, | |
107 | &iscsi_boot_attr_tgt_name.attr, | |
108 | &iscsi_boot_attr_tgt_chap_name.attr, | |
109 | &iscsi_boot_attr_tgt_chap_secret.attr, | |
110 | &iscsi_boot_attr_tgt_chap_rev_name.attr, | |
111 | &iscsi_boot_attr_tgt_chap_rev_secret.attr, | |
112 | NULL | |
113 | }; | |
114 | ||
587a1f16 | 115 | static umode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
116 | struct attribute *attr, int i) |
117 | { | |
118 | struct iscsi_boot_kobj *boot_kobj = | |
119 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
120 | ||
121 | if (attr == &iscsi_boot_attr_tgt_index.attr) | |
122 | return boot_kobj->is_visible(boot_kobj->data, | |
123 | ISCSI_BOOT_TGT_INDEX); | |
124 | else if (attr == &iscsi_boot_attr_tgt_flags.attr) | |
125 | return boot_kobj->is_visible(boot_kobj->data, | |
126 | ISCSI_BOOT_TGT_FLAGS); | |
127 | else if (attr == &iscsi_boot_attr_tgt_ip.attr) | |
128 | return boot_kobj->is_visible(boot_kobj->data, | |
129 | ISCSI_BOOT_TGT_IP_ADDR); | |
130 | else if (attr == &iscsi_boot_attr_tgt_port.attr) | |
131 | return boot_kobj->is_visible(boot_kobj->data, | |
132 | ISCSI_BOOT_TGT_PORT); | |
133 | else if (attr == &iscsi_boot_attr_tgt_lun.attr) | |
134 | return boot_kobj->is_visible(boot_kobj->data, | |
135 | ISCSI_BOOT_TGT_LUN); | |
136 | else if (attr == &iscsi_boot_attr_tgt_chap.attr) | |
137 | return boot_kobj->is_visible(boot_kobj->data, | |
138 | ISCSI_BOOT_TGT_CHAP_TYPE); | |
139 | else if (attr == &iscsi_boot_attr_tgt_nic.attr) | |
140 | return boot_kobj->is_visible(boot_kobj->data, | |
141 | ISCSI_BOOT_TGT_NIC_ASSOC); | |
142 | else if (attr == &iscsi_boot_attr_tgt_name.attr) | |
143 | return boot_kobj->is_visible(boot_kobj->data, | |
144 | ISCSI_BOOT_TGT_NAME); | |
145 | else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) | |
146 | return boot_kobj->is_visible(boot_kobj->data, | |
147 | ISCSI_BOOT_TGT_CHAP_NAME); | |
148 | else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) | |
149 | return boot_kobj->is_visible(boot_kobj->data, | |
150 | ISCSI_BOOT_TGT_CHAP_SECRET); | |
151 | else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) | |
152 | return boot_kobj->is_visible(boot_kobj->data, | |
153 | ISCSI_BOOT_TGT_REV_CHAP_NAME); | |
154 | else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) | |
155 | return boot_kobj->is_visible(boot_kobj->data, | |
156 | ISCSI_BOOT_TGT_REV_CHAP_SECRET); | |
157 | return 0; | |
158 | } | |
159 | ||
160 | static struct attribute_group iscsi_boot_target_attr_group = { | |
161 | .attrs = target_attrs, | |
162 | .is_visible = iscsi_boot_tgt_attr_is_visible, | |
163 | }; | |
164 | ||
165 | /* Ethernet attrs */ | |
166 | iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); | |
167 | iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); | |
168 | iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); | |
9a99425f | 169 | iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN); |
ba4ee30c MC |
170 | iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); |
171 | iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); | |
172 | iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); | |
173 | iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); | |
174 | iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, | |
175 | ISCSI_BOOT_ETH_SECONDARY_DNS); | |
176 | iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); | |
177 | iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); | |
178 | iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); | |
179 | iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); | |
180 | ||
181 | static struct attribute *ethernet_attrs[] = { | |
182 | &iscsi_boot_attr_eth_index.attr, | |
183 | &iscsi_boot_attr_eth_flags.attr, | |
184 | &iscsi_boot_attr_eth_ip.attr, | |
9a99425f | 185 | &iscsi_boot_attr_eth_prefix.attr, |
ba4ee30c MC |
186 | &iscsi_boot_attr_eth_subnet.attr, |
187 | &iscsi_boot_attr_eth_origin.attr, | |
188 | &iscsi_boot_attr_eth_gateway.attr, | |
189 | &iscsi_boot_attr_eth_primary_dns.attr, | |
190 | &iscsi_boot_attr_eth_secondary_dns.attr, | |
191 | &iscsi_boot_attr_eth_dhcp.attr, | |
192 | &iscsi_boot_attr_eth_vlan.attr, | |
193 | &iscsi_boot_attr_eth_mac.attr, | |
194 | &iscsi_boot_attr_eth_hostname.attr, | |
195 | NULL | |
196 | }; | |
197 | ||
587a1f16 | 198 | static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
199 | struct attribute *attr, int i) |
200 | { | |
201 | struct iscsi_boot_kobj *boot_kobj = | |
202 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
203 | ||
204 | if (attr == &iscsi_boot_attr_eth_index.attr) | |
205 | return boot_kobj->is_visible(boot_kobj->data, | |
206 | ISCSI_BOOT_ETH_INDEX); | |
207 | else if (attr == &iscsi_boot_attr_eth_flags.attr) | |
208 | return boot_kobj->is_visible(boot_kobj->data, | |
209 | ISCSI_BOOT_ETH_FLAGS); | |
210 | else if (attr == &iscsi_boot_attr_eth_ip.attr) | |
211 | return boot_kobj->is_visible(boot_kobj->data, | |
212 | ISCSI_BOOT_ETH_IP_ADDR); | |
9a99425f HR |
213 | else if (attr == &iscsi_boot_attr_eth_prefix.attr) |
214 | return boot_kobj->is_visible(boot_kobj->data, | |
215 | ISCSI_BOOT_ETH_PREFIX_LEN); | |
ba4ee30c MC |
216 | else if (attr == &iscsi_boot_attr_eth_subnet.attr) |
217 | return boot_kobj->is_visible(boot_kobj->data, | |
218 | ISCSI_BOOT_ETH_SUBNET_MASK); | |
219 | else if (attr == &iscsi_boot_attr_eth_origin.attr) | |
220 | return boot_kobj->is_visible(boot_kobj->data, | |
221 | ISCSI_BOOT_ETH_ORIGIN); | |
222 | else if (attr == &iscsi_boot_attr_eth_gateway.attr) | |
223 | return boot_kobj->is_visible(boot_kobj->data, | |
224 | ISCSI_BOOT_ETH_GATEWAY); | |
225 | else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) | |
226 | return boot_kobj->is_visible(boot_kobj->data, | |
227 | ISCSI_BOOT_ETH_PRIMARY_DNS); | |
228 | else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) | |
229 | return boot_kobj->is_visible(boot_kobj->data, | |
230 | ISCSI_BOOT_ETH_SECONDARY_DNS); | |
231 | else if (attr == &iscsi_boot_attr_eth_dhcp.attr) | |
232 | return boot_kobj->is_visible(boot_kobj->data, | |
233 | ISCSI_BOOT_ETH_DHCP); | |
234 | else if (attr == &iscsi_boot_attr_eth_vlan.attr) | |
235 | return boot_kobj->is_visible(boot_kobj->data, | |
236 | ISCSI_BOOT_ETH_VLAN); | |
237 | else if (attr == &iscsi_boot_attr_eth_mac.attr) | |
238 | return boot_kobj->is_visible(boot_kobj->data, | |
239 | ISCSI_BOOT_ETH_MAC); | |
240 | else if (attr == &iscsi_boot_attr_eth_hostname.attr) | |
241 | return boot_kobj->is_visible(boot_kobj->data, | |
242 | ISCSI_BOOT_ETH_HOSTNAME); | |
243 | return 0; | |
244 | } | |
245 | ||
246 | static struct attribute_group iscsi_boot_ethernet_attr_group = { | |
247 | .attrs = ethernet_attrs, | |
248 | .is_visible = iscsi_boot_eth_attr_is_visible, | |
249 | }; | |
250 | ||
251 | /* Initiator attrs */ | |
252 | iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); | |
253 | iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); | |
254 | iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); | |
255 | iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); | |
256 | iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, | |
257 | ISCSI_BOOT_INI_PRI_RADIUS_SERVER); | |
258 | iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, | |
259 | ISCSI_BOOT_INI_SEC_RADIUS_SERVER); | |
260 | iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); | |
261 | ||
262 | static struct attribute *initiator_attrs[] = { | |
263 | &iscsi_boot_attr_ini_index.attr, | |
264 | &iscsi_boot_attr_ini_flags.attr, | |
265 | &iscsi_boot_attr_ini_isns.attr, | |
266 | &iscsi_boot_attr_ini_slp.attr, | |
267 | &iscsi_boot_attr_ini_primary_radius.attr, | |
268 | &iscsi_boot_attr_ini_secondary_radius.attr, | |
269 | &iscsi_boot_attr_ini_name.attr, | |
270 | NULL | |
271 | }; | |
272 | ||
587a1f16 | 273 | static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
274 | struct attribute *attr, int i) |
275 | { | |
276 | struct iscsi_boot_kobj *boot_kobj = | |
277 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
278 | ||
279 | if (attr == &iscsi_boot_attr_ini_index.attr) | |
280 | return boot_kobj->is_visible(boot_kobj->data, | |
281 | ISCSI_BOOT_INI_INDEX); | |
282 | if (attr == &iscsi_boot_attr_ini_flags.attr) | |
283 | return boot_kobj->is_visible(boot_kobj->data, | |
284 | ISCSI_BOOT_INI_FLAGS); | |
285 | if (attr == &iscsi_boot_attr_ini_isns.attr) | |
286 | return boot_kobj->is_visible(boot_kobj->data, | |
287 | ISCSI_BOOT_INI_ISNS_SERVER); | |
288 | if (attr == &iscsi_boot_attr_ini_slp.attr) | |
289 | return boot_kobj->is_visible(boot_kobj->data, | |
290 | ISCSI_BOOT_INI_SLP_SERVER); | |
291 | if (attr == &iscsi_boot_attr_ini_primary_radius.attr) | |
292 | return boot_kobj->is_visible(boot_kobj->data, | |
293 | ISCSI_BOOT_INI_PRI_RADIUS_SERVER); | |
294 | if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) | |
295 | return boot_kobj->is_visible(boot_kobj->data, | |
296 | ISCSI_BOOT_INI_SEC_RADIUS_SERVER); | |
297 | if (attr == &iscsi_boot_attr_ini_name.attr) | |
298 | return boot_kobj->is_visible(boot_kobj->data, | |
299 | ISCSI_BOOT_INI_INITIATOR_NAME); | |
300 | ||
301 | return 0; | |
302 | } | |
303 | ||
304 | static struct attribute_group iscsi_boot_initiator_attr_group = { | |
305 | .attrs = initiator_attrs, | |
306 | .is_visible = iscsi_boot_ini_attr_is_visible, | |
307 | }; | |
308 | ||
b3c8eb50 DB |
309 | /* iBFT ACPI Table attributes */ |
310 | iscsi_boot_rd_attr(acpitbl_signature, signature, ISCSI_BOOT_ACPITBL_SIGNATURE); | |
311 | iscsi_boot_rd_attr(acpitbl_oem_id, oem_id, ISCSI_BOOT_ACPITBL_OEM_ID); | |
312 | iscsi_boot_rd_attr(acpitbl_oem_table_id, oem_table_id, | |
313 | ISCSI_BOOT_ACPITBL_OEM_TABLE_ID); | |
314 | ||
315 | static struct attribute *acpitbl_attrs[] = { | |
316 | &iscsi_boot_attr_acpitbl_signature.attr, | |
317 | &iscsi_boot_attr_acpitbl_oem_id.attr, | |
318 | &iscsi_boot_attr_acpitbl_oem_table_id.attr, | |
319 | NULL | |
320 | }; | |
321 | ||
322 | static umode_t iscsi_boot_acpitbl_attr_is_visible(struct kobject *kobj, | |
323 | struct attribute *attr, int i) | |
324 | { | |
325 | struct iscsi_boot_kobj *boot_kobj = | |
326 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
327 | ||
328 | if (attr == &iscsi_boot_attr_acpitbl_signature.attr) | |
329 | return boot_kobj->is_visible(boot_kobj->data, | |
330 | ISCSI_BOOT_ACPITBL_SIGNATURE); | |
331 | if (attr == &iscsi_boot_attr_acpitbl_oem_id.attr) | |
332 | return boot_kobj->is_visible(boot_kobj->data, | |
333 | ISCSI_BOOT_ACPITBL_OEM_ID); | |
334 | if (attr == &iscsi_boot_attr_acpitbl_oem_table_id.attr) | |
335 | return boot_kobj->is_visible(boot_kobj->data, | |
336 | ISCSI_BOOT_ACPITBL_OEM_TABLE_ID); | |
337 | return 0; | |
338 | } | |
339 | ||
340 | static struct attribute_group iscsi_boot_acpitbl_attr_group = { | |
341 | .attrs = acpitbl_attrs, | |
342 | .is_visible = iscsi_boot_acpitbl_attr_is_visible, | |
343 | }; | |
344 | ||
ba4ee30c MC |
345 | static struct iscsi_boot_kobj * |
346 | iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, | |
347 | struct attribute_group *attr_group, | |
348 | const char *name, int index, void *data, | |
349 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 350 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 351 | void (*release) (void *data)) |
ba4ee30c MC |
352 | { |
353 | struct iscsi_boot_kobj *boot_kobj; | |
354 | ||
355 | boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); | |
356 | if (!boot_kobj) | |
357 | return NULL; | |
358 | INIT_LIST_HEAD(&boot_kobj->list); | |
359 | ||
360 | boot_kobj->kobj.kset = boot_kset->kset; | |
361 | if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, | |
362 | NULL, name, index)) { | |
363 | kfree(boot_kobj); | |
364 | return NULL; | |
365 | } | |
366 | boot_kobj->data = data; | |
367 | boot_kobj->show = show; | |
368 | boot_kobj->is_visible = is_visible; | |
f457a46f | 369 | boot_kobj->release = release; |
ba4ee30c MC |
370 | |
371 | if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { | |
372 | /* | |
373 | * We do not want to free this because the caller | |
374 | * will assume that since the creation call failed | |
375 | * the boot kobj was not setup and the normal release | |
376 | * path is not being run. | |
377 | */ | |
f457a46f | 378 | boot_kobj->release = NULL; |
ba4ee30c MC |
379 | kobject_put(&boot_kobj->kobj); |
380 | return NULL; | |
381 | } | |
382 | boot_kobj->attr_group = attr_group; | |
383 | ||
384 | kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); | |
385 | /* Nothing broke so lets add it to the list. */ | |
386 | list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); | |
387 | return boot_kobj; | |
388 | } | |
389 | ||
390 | static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) | |
391 | { | |
392 | list_del(&boot_kobj->list); | |
393 | sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); | |
394 | kobject_put(&boot_kobj->kobj); | |
395 | } | |
396 | ||
397 | /** | |
398 | * iscsi_boot_create_target() - create boot target sysfs dir | |
399 | * @boot_kset: boot kset | |
400 | * @index: the target id | |
401 | * @data: driver specific data for target | |
402 | * @show: attr show function | |
403 | * @is_visible: attr visibility function | |
f457a46f | 404 | * @release: release function |
ba4ee30c MC |
405 | * |
406 | * Note: The boot sysfs lib will free the data passed in for the caller | |
407 | * when all refs to the target kobject have been released. | |
408 | */ | |
409 | struct iscsi_boot_kobj * | |
410 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, | |
411 | void *data, | |
412 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 413 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 414 | void (*release) (void *data)) |
ba4ee30c MC |
415 | { |
416 | return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, | |
f457a46f MC |
417 | "target%d", index, data, show, is_visible, |
418 | release); | |
ba4ee30c MC |
419 | } |
420 | EXPORT_SYMBOL_GPL(iscsi_boot_create_target); | |
421 | ||
422 | /** | |
423 | * iscsi_boot_create_initiator() - create boot initiator sysfs dir | |
424 | * @boot_kset: boot kset | |
425 | * @index: the initiator id | |
426 | * @data: driver specific data | |
427 | * @show: attr show function | |
428 | * @is_visible: attr visibility function | |
f457a46f | 429 | * @release: release function |
ba4ee30c MC |
430 | * |
431 | * Note: The boot sysfs lib will free the data passed in for the caller | |
432 | * when all refs to the initiator kobject have been released. | |
433 | */ | |
434 | struct iscsi_boot_kobj * | |
435 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, | |
436 | void *data, | |
437 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 438 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 439 | void (*release) (void *data)) |
ba4ee30c MC |
440 | { |
441 | return iscsi_boot_create_kobj(boot_kset, | |
442 | &iscsi_boot_initiator_attr_group, | |
443 | "initiator", index, data, show, | |
f457a46f | 444 | is_visible, release); |
ba4ee30c MC |
445 | } |
446 | EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); | |
447 | ||
448 | /** | |
449 | * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir | |
450 | * @boot_kset: boot kset | |
451 | * @index: the ethernet device id | |
452 | * @data: driver specific data | |
453 | * @show: attr show function | |
454 | * @is_visible: attr visibility function | |
f457a46f | 455 | * @release: release function |
ba4ee30c MC |
456 | * |
457 | * Note: The boot sysfs lib will free the data passed in for the caller | |
458 | * when all refs to the ethernet kobject have been released. | |
459 | */ | |
460 | struct iscsi_boot_kobj * | |
461 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, | |
462 | void *data, | |
463 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 464 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 465 | void (*release) (void *data)) |
ba4ee30c MC |
466 | { |
467 | return iscsi_boot_create_kobj(boot_kset, | |
468 | &iscsi_boot_ethernet_attr_group, | |
469 | "ethernet%d", index, data, show, | |
f457a46f | 470 | is_visible, release); |
ba4ee30c MC |
471 | } |
472 | EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); | |
473 | ||
b3c8eb50 DB |
474 | /** |
475 | * iscsi_boot_create_acpitbl() - create boot acpi table sysfs dir | |
476 | * @boot_kset: boot kset | |
477 | * @index: not used | |
478 | * @data: driver specific data | |
479 | * @show: attr show function | |
480 | * @is_visible: attr visibility function | |
481 | * @release: release function | |
482 | * | |
483 | * Note: The boot sysfs lib will free the data passed in for the caller | |
484 | * when all refs to the acpitbl kobject have been released. | |
485 | */ | |
486 | struct iscsi_boot_kobj * | |
487 | iscsi_boot_create_acpitbl(struct iscsi_boot_kset *boot_kset, int index, | |
488 | void *data, | |
489 | ssize_t (*show)(void *data, int type, char *buf), | |
490 | umode_t (*is_visible)(void *data, int type), | |
491 | void (*release)(void *data)) | |
492 | { | |
493 | return iscsi_boot_create_kobj(boot_kset, | |
494 | &iscsi_boot_acpitbl_attr_group, | |
495 | "acpi_header", index, data, show, | |
496 | is_visible, release); | |
497 | } | |
498 | EXPORT_SYMBOL_GPL(iscsi_boot_create_acpitbl); | |
499 | ||
ba4ee30c MC |
500 | /** |
501 | * iscsi_boot_create_kset() - creates root sysfs tree | |
502 | * @set_name: name of root dir | |
503 | */ | |
504 | struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) | |
505 | { | |
506 | struct iscsi_boot_kset *boot_kset; | |
507 | ||
508 | boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); | |
509 | if (!boot_kset) | |
510 | return NULL; | |
511 | ||
512 | boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); | |
513 | if (!boot_kset->kset) { | |
514 | kfree(boot_kset); | |
515 | return NULL; | |
516 | } | |
517 | ||
518 | INIT_LIST_HEAD(&boot_kset->kobj_list); | |
519 | return boot_kset; | |
520 | } | |
521 | EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); | |
522 | ||
523 | /** | |
524 | * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host | |
525 | * @hostno: host number of scsi host | |
526 | */ | |
527 | struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) | |
528 | { | |
529 | struct iscsi_boot_kset *boot_kset; | |
530 | char *set_name; | |
531 | ||
532 | set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); | |
533 | if (!set_name) | |
534 | return NULL; | |
535 | ||
536 | boot_kset = iscsi_boot_create_kset(set_name); | |
537 | kfree(set_name); | |
538 | return boot_kset; | |
539 | } | |
540 | EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); | |
541 | ||
542 | /** | |
543 | * iscsi_boot_destroy_kset() - destroy kset and kobjects under it | |
544 | * @boot_kset: boot kset | |
545 | * | |
546 | * This will remove the kset and kobjects and attrs under it. | |
547 | */ | |
548 | void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) | |
549 | { | |
550 | struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; | |
551 | ||
9d045163 MC |
552 | if (!boot_kset) |
553 | return; | |
554 | ||
ba4ee30c MC |
555 | list_for_each_entry_safe(boot_kobj, tmp_kobj, |
556 | &boot_kset->kobj_list, list) | |
557 | iscsi_boot_remove_kobj(boot_kobj); | |
558 | ||
559 | kset_unregister(boot_kset->kset); | |
9cb48e7b | 560 | kfree(boot_kset); |
ba4ee30c MC |
561 | } |
562 | EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); |