linux/drivers/scsi/iscsi_boot_sysfs.c
<<
>>
Prefs
   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        if (boot_kobj->release)
  68                boot_kobj->release(boot_kobj->data);
  69        kfree(boot_kobj);
  70}
  71
  72static 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)               \
  78static 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 */
  84iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
  85iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
  86iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
  87iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
  88iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
  89iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
  90iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
  91iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
  92iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
  93iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
  94iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
  95                   ISCSI_BOOT_TGT_REV_CHAP_NAME);
  96iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
  97                   ISCSI_BOOT_TGT_REV_CHAP_SECRET);
  98
  99static 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
 115static umode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
 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
 160static 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 */
 166iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
 167iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
 168iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
 169iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN);
 170iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
 171iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
 172iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
 173iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
 174iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
 175                   ISCSI_BOOT_ETH_SECONDARY_DNS);
 176iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
 177iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
 178iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
 179iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
 180
 181static 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,
 185        &iscsi_boot_attr_eth_prefix.attr,
 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
 198static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
 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);
 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);
 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
 246static 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 */
 252iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
 253iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
 254iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
 255iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
 256iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
 257                   ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
 258iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
 259                   ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
 260iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
 261
 262static 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
 273static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
 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
 304static struct attribute_group iscsi_boot_initiator_attr_group = {
 305        .attrs = initiator_attrs,
 306        .is_visible = iscsi_boot_ini_attr_is_visible,
 307};
 308
 309/* iBFT ACPI Table attributes */
 310iscsi_boot_rd_attr(acpitbl_signature, signature, ISCSI_BOOT_ACPITBL_SIGNATURE);
 311iscsi_boot_rd_attr(acpitbl_oem_id, oem_id, ISCSI_BOOT_ACPITBL_OEM_ID);
 312iscsi_boot_rd_attr(acpitbl_oem_table_id, oem_table_id,
 313                   ISCSI_BOOT_ACPITBL_OEM_TABLE_ID);
 314
 315static 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
 322static 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
 340static struct attribute_group iscsi_boot_acpitbl_attr_group = {
 341        .attrs = acpitbl_attrs,
 342        .is_visible = iscsi_boot_acpitbl_attr_is_visible,
 343};
 344
 345static struct iscsi_boot_kobj *
 346iscsi_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),
 350                       umode_t (*is_visible) (void *data, int type),
 351                       void (*release) (void *data))
 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;
 369        boot_kobj->release = release;
 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                 */
 378                boot_kobj->release = NULL;
 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
 390static 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
 404 * @release: release function
 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 */
 409struct iscsi_boot_kobj *
 410iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
 411                         void *data,
 412                         ssize_t (*show) (void *data, int type, char *buf),
 413                         umode_t (*is_visible) (void *data, int type),
 414                         void (*release) (void *data))
 415{
 416        return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
 417                                      "target%d", index, data, show, is_visible,
 418                                      release);
 419}
 420EXPORT_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
 429 * @release: release function
 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 */
 434struct iscsi_boot_kobj *
 435iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
 436                            void *data,
 437                            ssize_t (*show) (void *data, int type, char *buf),
 438                            umode_t (*is_visible) (void *data, int type),
 439                            void (*release) (void *data))
 440{
 441        return iscsi_boot_create_kobj(boot_kset,
 442                                      &iscsi_boot_initiator_attr_group,
 443                                      "initiator", index, data, show,
 444                                      is_visible, release);
 445}
 446EXPORT_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
 455 * @release: release function
 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 */
 460struct iscsi_boot_kobj *
 461iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
 462                           void *data,
 463                           ssize_t (*show) (void *data, int type, char *buf),
 464                           umode_t (*is_visible) (void *data, int type),
 465                           void (*release) (void *data))
 466{
 467        return iscsi_boot_create_kobj(boot_kset,
 468                                      &iscsi_boot_ethernet_attr_group,
 469                                      "ethernet%d", index, data, show,
 470                                      is_visible, release);
 471}
 472EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
 473
 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 */
 486struct iscsi_boot_kobj *
 487iscsi_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}
 498EXPORT_SYMBOL_GPL(iscsi_boot_create_acpitbl);
 499
 500/**
 501 * iscsi_boot_create_kset() - creates root sysfs tree
 502 * @set_name: name of root dir
 503 */
 504struct 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}
 521EXPORT_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 */
 527struct 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}
 540EXPORT_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 */
 548void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
 549{
 550        struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
 551
 552        if (!boot_kset)
 553                return;
 554
 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);
 560        kfree(boot_kset);
 561}
 562EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
 563