linux/arch/s390/hypfs/hypfs_diag.c
<<
>>
Prefs
   1/*
   2 *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
   3 *    implementation.
   4 *
   5 *    Copyright IBM Corp. 2006, 2008
   6 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
   7 */
   8
   9#define KMSG_COMPONENT "hypfs"
  10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11
  12#include <linux/types.h>
  13#include <linux/errno.h>
  14#include <linux/slab.h>
  15#include <linux/string.h>
  16#include <linux/vmalloc.h>
  17#include <linux/mm.h>
  18#include <asm/diag.h>
  19#include <asm/ebcdic.h>
  20#include "hypfs.h"
  21
  22#define TMP_SIZE 64             /* size of temporary buffers */
  23
  24#define DBFS_D204_HDR_VERSION   0
  25
  26static char *diag224_cpu_names;                 /* diag 224 name table */
  27static enum diag204_sc diag204_store_sc;        /* used subcode for store */
  28static enum diag204_format diag204_info_type;   /* used diag 204 data format */
  29
  30static void *diag204_buf;               /* 4K aligned buffer for diag204 data */
  31static void *diag204_buf_vmalloc;       /* vmalloc pointer for diag204 data */
  32static int diag204_buf_pages;           /* number of pages for diag204 data */
  33
  34static struct dentry *dbfs_d204_file;
  35
  36/*
  37 * DIAG 204 member access functions.
  38 *
  39 * Since we have two different diag 204 data formats for old and new s390
  40 * machines, we do not access the structs directly, but use getter functions for
  41 * each struct member instead. This should make the code more readable.
  42 */
  43
  44/* Time information block */
  45
  46static inline int info_blk_hdr__size(enum diag204_format type)
  47{
  48        if (type == DIAG204_INFO_SIMPLE)
  49                return sizeof(struct diag204_info_blk_hdr);
  50        else /* DIAG204_INFO_EXT */
  51                return sizeof(struct diag204_x_info_blk_hdr);
  52}
  53
  54static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
  55{
  56        if (type == DIAG204_INFO_SIMPLE)
  57                return ((struct diag204_info_blk_hdr *)hdr)->npar;
  58        else /* DIAG204_INFO_EXT */
  59                return ((struct diag204_x_info_blk_hdr *)hdr)->npar;
  60}
  61
  62static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
  63{
  64        if (type == DIAG204_INFO_SIMPLE)
  65                return ((struct diag204_info_blk_hdr *)hdr)->flags;
  66        else /* DIAG204_INFO_EXT */
  67                return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
  68}
  69
  70static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
  71{
  72        if (type == DIAG204_INFO_SIMPLE)
  73                return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
  74        else /* DIAG204_INFO_EXT */
  75                return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
  76}
  77
  78/* Partition header */
  79
  80static inline int part_hdr__size(enum diag204_format type)
  81{
  82        if (type == DIAG204_INFO_SIMPLE)
  83                return sizeof(struct diag204_part_hdr);
  84        else /* DIAG204_INFO_EXT */
  85                return sizeof(struct diag204_x_part_hdr);
  86}
  87
  88static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
  89{
  90        if (type == DIAG204_INFO_SIMPLE)
  91                return ((struct diag204_part_hdr *)hdr)->cpus;
  92        else /* DIAG204_INFO_EXT */
  93                return ((struct diag204_x_part_hdr *)hdr)->rcpus;
  94}
  95
  96static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
  97                                       char *name)
  98{
  99        if (type == DIAG204_INFO_SIMPLE)
 100                memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name,
 101                       DIAG204_LPAR_NAME_LEN);
 102        else /* DIAG204_INFO_EXT */
 103                memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name,
 104                       DIAG204_LPAR_NAME_LEN);
 105        EBCASC(name, DIAG204_LPAR_NAME_LEN);
 106        name[DIAG204_LPAR_NAME_LEN] = 0;
 107        strim(name);
 108}
 109
 110/* CPU info block */
 111
 112static inline int cpu_info__size(enum diag204_format type)
 113{
 114        if (type == DIAG204_INFO_SIMPLE)
 115                return sizeof(struct diag204_cpu_info);
 116        else /* DIAG204_INFO_EXT */
 117                return sizeof(struct diag204_x_cpu_info);
 118}
 119
 120static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
 121{
 122        if (type == DIAG204_INFO_SIMPLE)
 123                return ((struct diag204_cpu_info *)hdr)->ctidx;
 124        else /* DIAG204_INFO_EXT */
 125                return ((struct diag204_x_cpu_info *)hdr)->ctidx;
 126}
 127
 128static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
 129{
 130        if (type == DIAG204_INFO_SIMPLE)
 131                return ((struct diag204_cpu_info *)hdr)->cpu_addr;
 132        else /* DIAG204_INFO_EXT */
 133                return ((struct diag204_x_cpu_info *)hdr)->cpu_addr;
 134}
 135
 136static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
 137{
 138        if (type == DIAG204_INFO_SIMPLE)
 139                return ((struct diag204_cpu_info *)hdr)->acc_time;
 140        else /* DIAG204_INFO_EXT */
 141                return ((struct diag204_x_cpu_info *)hdr)->acc_time;
 142}
 143
 144static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
 145{
 146        if (type == DIAG204_INFO_SIMPLE)
 147                return ((struct diag204_cpu_info *)hdr)->lp_time;
 148        else /* DIAG204_INFO_EXT */
 149                return ((struct diag204_x_cpu_info *)hdr)->lp_time;
 150}
 151
 152static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
 153{
 154        if (type == DIAG204_INFO_SIMPLE)
 155                return 0;       /* online_time not available in simple info */
 156        else /* DIAG204_INFO_EXT */
 157                return ((struct diag204_x_cpu_info *)hdr)->online_time;
 158}
 159
 160/* Physical header */
 161
 162static inline int phys_hdr__size(enum diag204_format type)
 163{
 164        if (type == DIAG204_INFO_SIMPLE)
 165                return sizeof(struct diag204_phys_hdr);
 166        else /* DIAG204_INFO_EXT */
 167                return sizeof(struct diag204_x_phys_hdr);
 168}
 169
 170static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
 171{
 172        if (type == DIAG204_INFO_SIMPLE)
 173                return ((struct diag204_phys_hdr *)hdr)->cpus;
 174        else /* DIAG204_INFO_EXT */
 175                return ((struct diag204_x_phys_hdr *)hdr)->cpus;
 176}
 177
 178/* Physical CPU info block */
 179
 180static inline int phys_cpu__size(enum diag204_format type)
 181{
 182        if (type == DIAG204_INFO_SIMPLE)
 183                return sizeof(struct diag204_phys_cpu);
 184        else /* DIAG204_INFO_EXT */
 185                return sizeof(struct diag204_x_phys_cpu);
 186}
 187
 188static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
 189{
 190        if (type == DIAG204_INFO_SIMPLE)
 191                return ((struct diag204_phys_cpu *)hdr)->cpu_addr;
 192        else /* DIAG204_INFO_EXT */
 193                return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr;
 194}
 195
 196static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
 197{
 198        if (type == DIAG204_INFO_SIMPLE)
 199                return ((struct diag204_phys_cpu *)hdr)->mgm_time;
 200        else /* DIAG204_INFO_EXT */
 201                return ((struct diag204_x_phys_cpu *)hdr)->mgm_time;
 202}
 203
 204static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
 205{
 206        if (type == DIAG204_INFO_SIMPLE)
 207                return ((struct diag204_phys_cpu *)hdr)->ctidx;
 208        else /* DIAG204_INFO_EXT */
 209                return ((struct diag204_x_phys_cpu *)hdr)->ctidx;
 210}
 211
 212/* Diagnose 204 functions */
 213/*
 214 * For the old diag subcode 4 with simple data format we have to use real
 215 * memory. If we use subcode 6 or 7 with extended data format, we can (and
 216 * should) use vmalloc, since we need a lot of memory in that case. Currently
 217 * up to 93 pages!
 218 */
 219
 220static void diag204_free_buffer(void)
 221{
 222        if (!diag204_buf)
 223                return;
 224        if (diag204_buf_vmalloc) {
 225                vfree(diag204_buf_vmalloc);
 226                diag204_buf_vmalloc = NULL;
 227        } else {
 228                free_pages((unsigned long) diag204_buf, 0);
 229        }
 230        diag204_buf = NULL;
 231}
 232
 233static void *page_align_ptr(void *ptr)
 234{
 235        return (void *) PAGE_ALIGN((unsigned long) ptr);
 236}
 237
 238static void *diag204_alloc_vbuf(int pages)
 239{
 240        /* The buffer has to be page aligned! */
 241        diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
 242        if (!diag204_buf_vmalloc)
 243                return ERR_PTR(-ENOMEM);
 244        diag204_buf = page_align_ptr(diag204_buf_vmalloc);
 245        diag204_buf_pages = pages;
 246        return diag204_buf;
 247}
 248
 249static void *diag204_alloc_rbuf(void)
 250{
 251        diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
 252        if (!diag204_buf)
 253                return ERR_PTR(-ENOMEM);
 254        diag204_buf_pages = 1;
 255        return diag204_buf;
 256}
 257
 258static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
 259{
 260        if (diag204_buf) {
 261                *pages = diag204_buf_pages;
 262                return diag204_buf;
 263        }
 264        if (fmt == DIAG204_INFO_SIMPLE) {
 265                *pages = 1;
 266                return diag204_alloc_rbuf();
 267        } else {/* DIAG204_INFO_EXT */
 268                *pages = diag204((unsigned long)DIAG204_SUBC_RSI |
 269                                 (unsigned long)DIAG204_INFO_EXT, 0, NULL);
 270                if (*pages <= 0)
 271                        return ERR_PTR(-ENOSYS);
 272                else
 273                        return diag204_alloc_vbuf(*pages);
 274        }
 275}
 276
 277/*
 278 * diag204_probe() has to find out, which type of diagnose 204 implementation
 279 * we have on our machine. Currently there are three possible scanarios:
 280 *   - subcode 4   + simple data format (only one page)
 281 *   - subcode 4-6 + extended data format
 282 *   - subcode 4-7 + extended data format
 283 *
 284 * Subcode 5 is used to retrieve the size of the data, provided by subcodes
 285 * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
 286 * to subcode 6 it provides also information about secondary cpus.
 287 * In order to get as much information as possible, we first try
 288 * subcode 7, then 6 and if both fail, we use subcode 4.
 289 */
 290
 291static int diag204_probe(void)
 292{
 293        void *buf;
 294        int pages, rc;
 295
 296        buf = diag204_get_buffer(DIAG204_INFO_EXT, &pages);
 297        if (!IS_ERR(buf)) {
 298                if (diag204((unsigned long)DIAG204_SUBC_STIB7 |
 299                            (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
 300                        diag204_store_sc = DIAG204_SUBC_STIB7;
 301                        diag204_info_type = DIAG204_INFO_EXT;
 302                        goto out;
 303                }
 304                if (diag204((unsigned long)DIAG204_SUBC_STIB6 |
 305                            (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
 306                        diag204_store_sc = DIAG204_SUBC_STIB6;
 307                        diag204_info_type = DIAG204_INFO_EXT;
 308                        goto out;
 309                }
 310                diag204_free_buffer();
 311        }
 312
 313        /* subcodes 6 and 7 failed, now try subcode 4 */
 314
 315        buf = diag204_get_buffer(DIAG204_INFO_SIMPLE, &pages);
 316        if (IS_ERR(buf)) {
 317                rc = PTR_ERR(buf);
 318                goto fail_alloc;
 319        }
 320        if (diag204((unsigned long)DIAG204_SUBC_STIB4 |
 321                    (unsigned long)DIAG204_INFO_SIMPLE, pages, buf) >= 0) {
 322                diag204_store_sc = DIAG204_SUBC_STIB4;
 323                diag204_info_type = DIAG204_INFO_SIMPLE;
 324                goto out;
 325        } else {
 326                rc = -ENOSYS;
 327                goto fail_store;
 328        }
 329out:
 330        rc = 0;
 331fail_store:
 332        diag204_free_buffer();
 333fail_alloc:
 334        return rc;
 335}
 336
 337static int diag204_do_store(void *buf, int pages)
 338{
 339        int rc;
 340
 341        rc = diag204((unsigned long) diag204_store_sc |
 342                     (unsigned long) diag204_info_type, pages, buf);
 343        return rc < 0 ? -ENOSYS : 0;
 344}
 345
 346static void *diag204_store(void)
 347{
 348        void *buf;
 349        int pages, rc;
 350
 351        buf = diag204_get_buffer(diag204_info_type, &pages);
 352        if (IS_ERR(buf))
 353                goto out;
 354        rc = diag204_do_store(buf, pages);
 355        if (rc)
 356                return ERR_PTR(rc);
 357out:
 358        return buf;
 359}
 360
 361/* Diagnose 224 functions */
 362
 363static int diag224_get_name_table(void)
 364{
 365        /* memory must be below 2GB */
 366        diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
 367        if (!diag224_cpu_names)
 368                return -ENOMEM;
 369        if (diag224(diag224_cpu_names)) {
 370                kfree(diag224_cpu_names);
 371                return -EOPNOTSUPP;
 372        }
 373        EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
 374        return 0;
 375}
 376
 377static void diag224_delete_name_table(void)
 378{
 379        kfree(diag224_cpu_names);
 380}
 381
 382static int diag224_idx2name(int index, char *name)
 383{
 384        memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN),
 385               DIAG204_CPU_NAME_LEN);
 386        name[DIAG204_CPU_NAME_LEN] = 0;
 387        strim(name);
 388        return 0;
 389}
 390
 391struct dbfs_d204_hdr {
 392        u64     len;            /* Length of d204 buffer without header */
 393        u16     version;        /* Version of header */
 394        u8      sc;             /* Used subcode */
 395        char    reserved[53];
 396} __attribute__ ((packed));
 397
 398struct dbfs_d204 {
 399        struct dbfs_d204_hdr    hdr;    /* 64 byte header */
 400        char                    buf[];  /* d204 buffer */
 401} __attribute__ ((packed));
 402
 403static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
 404{
 405        struct dbfs_d204 *d204;
 406        int rc, buf_size;
 407        void *base;
 408
 409        buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
 410        base = vzalloc(buf_size);
 411        if (!base)
 412                return -ENOMEM;
 413        d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
 414        rc = diag204_do_store(d204->buf, diag204_buf_pages);
 415        if (rc) {
 416                vfree(base);
 417                return rc;
 418        }
 419        d204->hdr.version = DBFS_D204_HDR_VERSION;
 420        d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
 421        d204->hdr.sc = diag204_store_sc;
 422        *data = d204;
 423        *data_free_ptr = base;
 424        *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
 425        return 0;
 426}
 427
 428static struct hypfs_dbfs_file dbfs_file_d204 = {
 429        .name           = "diag_204",
 430        .data_create    = dbfs_d204_create,
 431        .data_free      = vfree,
 432};
 433
 434__init int hypfs_diag_init(void)
 435{
 436        int rc;
 437
 438        if (diag204_probe()) {
 439                pr_err("The hardware system does not support hypfs\n");
 440                return -ENODATA;
 441        }
 442        if (diag204_info_type == DIAG204_INFO_EXT) {
 443                rc = hypfs_dbfs_create_file(&dbfs_file_d204);
 444                if (rc)
 445                        return rc;
 446        }
 447        if (MACHINE_IS_LPAR) {
 448                rc = diag224_get_name_table();
 449                if (rc) {
 450                        pr_err("The hardware system does not provide all "
 451                               "functions required by hypfs\n");
 452                        debugfs_remove(dbfs_d204_file);
 453                        return rc;
 454                }
 455        }
 456        return 0;
 457}
 458
 459void hypfs_diag_exit(void)
 460{
 461        debugfs_remove(dbfs_d204_file);
 462        diag224_delete_name_table();
 463        diag204_free_buffer();
 464        hypfs_dbfs_remove_file(&dbfs_file_d204);
 465}
 466
 467/*
 468 * Functions to create the directory structure
 469 * *******************************************
 470 */
 471
 472static int hypfs_create_cpu_files(struct super_block *sb,
 473                                  struct dentry *cpus_dir, void *cpu_info)
 474{
 475        struct dentry *cpu_dir;
 476        char buffer[TMP_SIZE];
 477        void *rc;
 478
 479        snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
 480                                                            cpu_info));
 481        cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
 482        rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
 483                              cpu_info__acc_time(diag204_info_type, cpu_info) -
 484                              cpu_info__lp_time(diag204_info_type, cpu_info));
 485        if (IS_ERR(rc))
 486                return PTR_ERR(rc);
 487        rc = hypfs_create_u64(sb, cpu_dir, "cputime",
 488                              cpu_info__lp_time(diag204_info_type, cpu_info));
 489        if (IS_ERR(rc))
 490                return PTR_ERR(rc);
 491        if (diag204_info_type == DIAG204_INFO_EXT) {
 492                rc = hypfs_create_u64(sb, cpu_dir, "onlinetime",
 493                                      cpu_info__online_time(diag204_info_type,
 494                                                            cpu_info));
 495                if (IS_ERR(rc))
 496                        return PTR_ERR(rc);
 497        }
 498        diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
 499        rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
 500        if (IS_ERR(rc))
 501                return PTR_ERR(rc);
 502        return 0;
 503}
 504
 505static void *hypfs_create_lpar_files(struct super_block *sb,
 506                                     struct dentry *systems_dir, void *part_hdr)
 507{
 508        struct dentry *cpus_dir;
 509        struct dentry *lpar_dir;
 510        char lpar_name[DIAG204_LPAR_NAME_LEN + 1];
 511        void *cpu_info;
 512        int i;
 513
 514        part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
 515        lpar_name[DIAG204_LPAR_NAME_LEN] = 0;
 516        lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name);
 517        if (IS_ERR(lpar_dir))
 518                return lpar_dir;
 519        cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus");
 520        if (IS_ERR(cpus_dir))
 521                return cpus_dir;
 522        cpu_info = part_hdr + part_hdr__size(diag204_info_type);
 523        for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
 524                int rc;
 525                rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info);
 526                if (rc)
 527                        return ERR_PTR(rc);
 528                cpu_info += cpu_info__size(diag204_info_type);
 529        }
 530        return cpu_info;
 531}
 532
 533static int hypfs_create_phys_cpu_files(struct super_block *sb,
 534                                       struct dentry *cpus_dir, void *cpu_info)
 535{
 536        struct dentry *cpu_dir;
 537        char buffer[TMP_SIZE];
 538        void *rc;
 539
 540        snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
 541                                                            cpu_info));
 542        cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
 543        if (IS_ERR(cpu_dir))
 544                return PTR_ERR(cpu_dir);
 545        rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
 546                              phys_cpu__mgm_time(diag204_info_type, cpu_info));
 547        if (IS_ERR(rc))
 548                return PTR_ERR(rc);
 549        diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
 550        rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
 551        if (IS_ERR(rc))
 552                return PTR_ERR(rc);
 553        return 0;
 554}
 555
 556static void *hypfs_create_phys_files(struct super_block *sb,
 557                                     struct dentry *parent_dir, void *phys_hdr)
 558{
 559        int i;
 560        void *cpu_info;
 561        struct dentry *cpus_dir;
 562
 563        cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus");
 564        if (IS_ERR(cpus_dir))
 565                return cpus_dir;
 566        cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
 567        for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
 568                int rc;
 569                rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info);
 570                if (rc)
 571                        return ERR_PTR(rc);
 572                cpu_info += phys_cpu__size(diag204_info_type);
 573        }
 574        return cpu_info;
 575}
 576
 577int hypfs_diag_create_files(struct super_block *sb, struct dentry *root)
 578{
 579        struct dentry *systems_dir, *hyp_dir;
 580        void *time_hdr, *part_hdr;
 581        int i, rc;
 582        void *buffer, *ptr;
 583
 584        buffer = diag204_store();
 585        if (IS_ERR(buffer))
 586                return PTR_ERR(buffer);
 587
 588        systems_dir = hypfs_mkdir(sb, root, "systems");
 589        if (IS_ERR(systems_dir)) {
 590                rc = PTR_ERR(systems_dir);
 591                goto err_out;
 592        }
 593        time_hdr = (struct x_info_blk_hdr *)buffer;
 594        part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
 595        for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
 596                part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr);
 597                if (IS_ERR(part_hdr)) {
 598                        rc = PTR_ERR(part_hdr);
 599                        goto err_out;
 600                }
 601        }
 602        if (info_blk_hdr__flags(diag204_info_type, time_hdr) &
 603            DIAG204_LPAR_PHYS_FLG) {
 604                ptr = hypfs_create_phys_files(sb, root, part_hdr);
 605                if (IS_ERR(ptr)) {
 606                        rc = PTR_ERR(ptr);
 607                        goto err_out;
 608                }
 609        }
 610        hyp_dir = hypfs_mkdir(sb, root, "hyp");
 611        if (IS_ERR(hyp_dir)) {
 612                rc = PTR_ERR(hyp_dir);
 613                goto err_out;
 614        }
 615        ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor");
 616        if (IS_ERR(ptr)) {
 617                rc = PTR_ERR(ptr);
 618                goto err_out;
 619        }
 620        rc = 0;
 621
 622err_out:
 623        return rc;
 624}
 625