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