[CIFS] DFS build fixes
[pandora-kernel.git] / drivers / s390 / char / sclp_info.c
index 7bcbe64..a1136e0 100644 (file)
 #include <asm/sclp.h>
 #include "sclp.h"
 
-struct sclp_readinfo_sccb s390_readinfo_sccb;
+struct sclp_readinfo_sccb {
+       struct  sccb_header header;     /* 0-7 */
+       u16     rnmax;                  /* 8-9 */
+       u8      rnsize;                 /* 10 */
+       u8      _reserved0[24 - 11];    /* 11-23 */
+       u8      loadparm[8];            /* 24-31 */
+       u8      _reserved1[48 - 32];    /* 32-47 */
+       u64     facilities;             /* 48-55 */
+       u8      _reserved2[91 - 56];    /* 56-90 */
+       u8      flags;                  /* 91 */
+       u8      _reserved3[100 - 92];   /* 92-99 */
+       u32     rnsize2;                /* 100-103 */
+       u64     rnmax2;                 /* 104-111 */
+       u8      _reserved4[4096 - 112]; /* 112-4095 */
+} __attribute__((packed, aligned(4096)));
+
+static struct sclp_readinfo_sccb __initdata early_readinfo_sccb;
+static int __initdata early_readinfo_sccb_valid;
+
+u64 sclp_facilities;
 
 void __init sclp_readinfo_early(void)
 {
-       sclp_cmdw_t command;
-       struct sccb_header *sccb;
        int ret;
+       int i;
+       struct sclp_readinfo_sccb *sccb;
+       sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+                                 SCLP_CMDW_READ_SCP_INFO};
 
-       __ctl_set_bit(0, 9); /* enable service signal subclass mask */
-
-       sccb = &s390_readinfo_sccb.header;
-       command = SCLP_CMDW_READ_SCP_INFO_FORCED;
-       while (1) {
-               u16 response;
-
-               memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
-               sccb->length = sizeof(s390_readinfo_sccb);
-               sccb->control_mask[2] = 0x80;
-
-               ret = sclp_service_call(command, &s390_readinfo_sccb);
-
-               if (ret == -EIO)
-                       goto out;
-               if (ret == -EBUSY)
-                       continue;
+       /* Enable service signal subclass mask. */
+       __ctl_set_bit(0, 9);
+       sccb = &early_readinfo_sccb;
+       for (i = 0; i < ARRAY_SIZE(commands); i++) {
+               do {
+                       memset(sccb, 0, sizeof(*sccb));
+                       sccb->header.length = sizeof(*sccb);
+                       sccb->header.control_mask[2] = 0x80;
+                       ret = sclp_service_call(commands[i], sccb);
+               } while (ret == -EBUSY);
 
+               if (ret)
+                       break;
                __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
                                PSW_MASK_WAIT | PSW_DEFAULT_KEY);
                local_irq_disable();
+               /*
+                * Contents of the sccb might have changed
+                * therefore a barrier is needed.
+                */
                barrier();
+               if (sccb->header.response_code == 0x10) {
+                       early_readinfo_sccb_valid = 1;
+                       break;
+               }
+               if (sccb->header.response_code != 0x1f0)
+                       break;
+       }
+       /* Disable service signal subclass mask again. */
+       __ctl_clear_bit(0, 9);
+}
 
-               response = sccb->response_code;
+void __init sclp_facilities_detect(void)
+{
+       if (!early_readinfo_sccb_valid)
+               return;
+       sclp_facilities = early_readinfo_sccb.facilities;
+}
 
-               if (response == 0x10)
-                       break;
+unsigned long long __init sclp_memory_detect(void)
+{
+       unsigned long long memsize;
+       struct sclp_readinfo_sccb *sccb;
 
-               if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
-                       break;
+       if (!early_readinfo_sccb_valid)
+               return 0;
+       sccb = &early_readinfo_sccb;
+       if (sccb->rnsize)
+               memsize = sccb->rnsize << 20;
+       else
+               memsize = sccb->rnsize2 << 20;
+       if (sccb->rnmax)
+               memsize *= sccb->rnmax;
+       else
+               memsize *= sccb->rnmax2;
+       return memsize;
+}
 
-               command = SCLP_CMDW_READ_SCP_INFO;
-       }
-out:
-       __ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+/*
+ * This function will be called after sclp_memory_detect(), which gets called
+ * early from early.c code. Therefore the sccb should have valid contents.
+ */
+void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
+{
+       struct sclp_readinfo_sccb *sccb;
+
+       if (!early_readinfo_sccb_valid)
+               return;
+       sccb = &early_readinfo_sccb;
+       info->is_valid = 1;
+       if (sccb->flags & 0x2)
+               info->has_dump = 1;
+       memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
 }